refactor(server): address PR #16 review feedback
Hoshe + Tyre review items: - Use StableId consistently for wire entity_id (H4) across observer, observation, interpretation, and interaction systems - Make NearbyInteractionBuffer.interactions private with take() (H1/H20) - Add system ordering constraint for compute_nearby_interactions (H5) - Panic on missing PlayerCharacter in input processing (H2) - Remove redundant paused field from GameTime (Tyre8) - Remove #[serde(default)] from nearby_interactions (H3) - Change NearbyInteraction.distance from f32 to u32 (H8) - Add sort stability for equal verb priorities (H6) - Scope constants to pub(crate) (H7) - Add debug_assert for last_observed_tick ordering (H10) - Strengthen unregistered entity handling to debug_assert + error (H11) - Document fractional tick accumulation (Tyre9) - Extract collect_remembered_entities helper (Tyre2/H17) - Add half_rate_no_drift_over_10000_frames test (H14) - Add mid-range and deterministic sort tests (H15) - Add fixture version assertion (H16) - Regenerate msgpack fixtures for wire format changes 146 unit + 19 integration tests pass, zero clippy warnings. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -92,6 +92,11 @@ impl SimulationTime {
|
||||
|
||||
/// Advance the simulation tick based on current tick rate.
|
||||
/// Full: +1 every frame. Half: +1 every 2 frames. Paused: no advance.
|
||||
///
|
||||
/// Uses fractional accumulation: each frame adds `tick_rate.scale()` to an
|
||||
/// internal accumulator. When it reaches 1.0, a tick fires and the accumulator
|
||||
/// subtracts 1.0. This ensures Half rate produces exactly N/2 ticks over N
|
||||
/// frames with no floating-point drift (0.5 is exactly representable in f32).
|
||||
pub fn advance_tick(mut time: ResMut<SimulationTime>) {
|
||||
let scale = time.tick_rate.scale();
|
||||
if scale <= 0.0 {
|
||||
@@ -193,4 +198,19 @@ mod tests {
|
||||
let time = SimulationTime { tick: 3 * MINUTES_PER_DAY * TICKS_PER_GAME_MINUTE + 100, ..Default::default() };
|
||||
assert_eq!(time.day(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn half_rate_no_drift_over_10000_frames() {
|
||||
let mut world = bevy_ecs::world::World::new();
|
||||
world.insert_resource(SimulationTime { tick_rate: TickRate::Half, ..Default::default() });
|
||||
let mut schedule = bevy_ecs::schedule::Schedule::default();
|
||||
schedule.add_systems(advance_tick);
|
||||
|
||||
for _ in 0..10_000 {
|
||||
schedule.run(&mut world);
|
||||
}
|
||||
|
||||
// 10,000 frames at Half rate (0.5) should yield exactly 5,000 ticks
|
||||
assert_eq!(world.resource::<SimulationTime>().tick, 5_000);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user