@@ -36,8 +36,7 @@ public final class GameStatsHud
3636 private static final float PADDING = 4F ;
3737 private static final float LINE_GAP = 2F ;
3838 private static final long SAMPLE_INTERVAL_MS = 1000L ;
39- private static final long SPEED_WINDOW_MS = 600L ;
40- private static final double SPEED_EMA_ALPHA = 0.5 ;
39+ private static final long SPEED_WINDOW_MS = 3000L ;
4140 private static final double SPEED_MAX_PLAUSIBLE_BPS = 5000.0 ;
4241 private static final float GRAPH_GAP = 4F ;
4342 private static final float GRAPH_TO_TEXT_GAP = 2F ;
@@ -71,11 +70,7 @@ public final class GameStatsHud
7170 private double lastY ;
7271 private double lastZ ;
7372 private long lastMovementSampleMs ;
74- private final ArrayDeque <MovementSample > movementSamples =
75- new ArrayDeque <>();
76- private long movementWindowDurationMs ;
77- private double movementWindowDistance ;
78- private double liveSpeedBps ;
73+ private final ArrayDeque <MovementPoint > movementPoints = new ArrayDeque <>();
7974 private double smoothedSpeedBps ;
8075 private int mobKillsBaseline = -1 ;
8176 private int playerKillsBaseline = -1 ;
@@ -313,9 +308,7 @@ private void updateSessionTracking()
313308 if (Double .isFinite (delta ) && delta >= 0 )
314309 {
315310 distanceTravelledMeters += delta ;
316- long dtMs = Math .max (1L , now - lastMovementSampleMs );
317- double horizontalDelta = Math .hypot (dx , dz );
318- pushMovementSample (horizontalDelta , dtMs );
311+ pushMovementSample (x , z , now );
319312 }
320313 }
321314
@@ -424,41 +417,38 @@ private static String formatDistance(double meters)
424417
425418 private void resetMovementSpeed ()
426419 {
427- movementSamples .clear ();
428- movementWindowDurationMs = 0L ;
429- movementWindowDistance = 0 ;
430- liveSpeedBps = 0 ;
420+ movementPoints .clear ();
431421 smoothedSpeedBps = 0 ;
432422 }
433423
434- private void pushMovementSample (double distance , long dtMs )
424+ private void pushMovementSample (double x , double z , long nowMs )
435425 {
436- if (dtMs <= 0L || !Double .isFinite (distance ) || distance < 0 )
426+ if (!Double .isFinite (x ) || ! Double . isFinite ( z ) )
437427 return ;
438428
439- double dtSec = dtMs / 1000D ;
440- double maxDistance = SPEED_MAX_PLAUSIBLE_BPS * dtSec ;
441- distance = Math .min (distance , maxDistance );
442-
443- movementSamples .addLast (new MovementSample (distance , dtMs ));
444- movementWindowDistance += distance ;
445- movementWindowDurationMs += dtMs ;
429+ movementPoints .addLast (new MovementPoint (x , z , nowMs ));
430+ long minTime = nowMs - SPEED_WINDOW_MS ;
431+ while (movementPoints .size () > 2
432+ && movementPoints .peekFirst ().timestampMs < minTime )
433+ movementPoints .removeFirst ();
446434
447- while (movementWindowDurationMs > SPEED_WINDOW_MS
448- && !movementSamples .isEmpty ())
449- {
450- MovementSample oldest = movementSamples .removeFirst ();
451- movementWindowDistance -= oldest .distance ;
452- movementWindowDurationMs -= oldest .durationMs ;
453- }
435+ MovementPoint oldest = movementPoints .peekFirst ();
436+ MovementPoint newest = movementPoints .peekLast ();
437+ if (oldest == null || newest == null )
438+ return ;
454439
455- if (movementWindowDurationMs <= 0L )
456- liveSpeedBps = 0 ;
457- else
458- liveSpeedBps =
459- movementWindowDistance / (movementWindowDurationMs / 1000D );
440+ long dtMs = newest .timestampMs - oldest .timestampMs ;
441+ if (dtMs <= 0L )
442+ return ;
460443
461- smoothedSpeedBps += SPEED_EMA_ALPHA * (liveSpeedBps - smoothedSpeedBps );
444+ double dx = newest .x - oldest .x ;
445+ double dz = newest .z - oldest .z ;
446+ double netDistance = Math .hypot (dx , dz );
447+ double dtSec = dtMs / 1000D ;
448+ double speed = netDistance / dtSec ;
449+ double maxDistance = SPEED_MAX_PLAUSIBLE_BPS * dtSec ;
450+ speed = Math .min (speed , maxDistance / dtSec );
451+ smoothedSpeedBps = speed ;
462452 }
463453
464454 private static String getWorldTime24h ()
@@ -1028,15 +1018,17 @@ private static int withAlpha(int rgb, int alpha)
10281018 return (Math .max (0 , Math .min (255 , alpha )) << 24 ) | (rgb & 0x00FFFFFF );
10291019 }
10301020
1031- private static final class MovementSample
1021+ private static final class MovementPoint
10321022 {
1033- private final double distance ;
1034- private final long durationMs ;
1023+ private final double x ;
1024+ private final double z ;
1025+ private final long timestampMs ;
10351026
1036- private MovementSample (double distance , long durationMs )
1027+ private MovementPoint (double x , double z , long timestampMs )
10371028 {
1038- this .distance = distance ;
1039- this .durationMs = durationMs ;
1029+ this .x = x ;
1030+ this .z = z ;
1031+ this .timestampMs = timestampMs ;
10401032 }
10411033 }
10421034}
0 commit comments