Skip to main content

steel_core/player/
health_sync.rs

1//! Delta-tracking state for `CSetHealth` packet deduplication.
2//!
3//! Tracks the last health/food/saturation values sent to the client so we only
4//! send `CSetHealth` when something actually changes.
5//!
6//! Vanilla: `ServerPlayer.lastSentHealth`, `lastSentFood`, `lastFoodSaturationZero`.
7
8use crate::player::Player;
9
10/// Tracks the last health/food/saturation values sent to the client.
11pub struct HealthSyncState {
12    /// Last health value sent to the client.
13    pub last_health: f32,
14    /// Last food level sent to the client.
15    pub last_food: i32,
16    /// Whether saturation was zero last time we sent health.
17    pub saturation_zero: bool,
18}
19
20impl HealthSyncState {
21    /// Creates a new state that will trigger a send on the first tick.
22    #[must_use]
23    pub const fn new() -> Self {
24        Self {
25            last_health: -1.0,
26            last_food: -1,
27            saturation_zero: true,
28        }
29    }
30
31    /// Returns true if the given values differ from what was last sent.
32    #[expect(
33        clippy::float_cmp,
34        reason = "intentional exact comparison: we only want to send updates when the value changes from what we last sent"
35    )]
36    #[must_use]
37    pub fn needs_update(&self, health: f32, food: i32, saturation_zero: bool) -> bool {
38        self.last_health != health
39            || self.last_food != food
40            || self.saturation_zero != saturation_zero
41    }
42
43    /// Records that we just sent the given values to the client.
44    pub const fn record_sent(&mut self, health: f32, food: i32, saturation_zero: bool) {
45        self.last_health = health;
46        self.last_food = food;
47        self.saturation_zero = saturation_zero;
48    }
49
50    /// Invalidates the state so the next tick will re-send.
51    ///
52    /// Vanilla: `resetSentInfo`.
53    pub const fn invalidate(&mut self) {
54        self.last_health = -1.0e8;
55    }
56
57    /// Resets to respawn defaults (forces re-send on next tick).
58    pub const fn reset_for_respawn(&mut self) {
59        self.last_health = -1.0;
60        self.last_food = -1;
61    }
62}
63
64impl Player {
65    /// Invalidates the delta-tracking state so that the next `tick()` will send
66    /// `CSetHealth` to the client (vanilla: `resetSentInfo`).
67    pub fn reset_sent_info(&self) {
68        self.health_sync.lock().invalidate();
69    }
70}