From 01a350aebd4f0e9c9d1d514a4e2ea498cb7f9853 Mon Sep 17 00:00:00 2001 From: Emil Date: Mon, 22 Jun 2026 16:35:17 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20fire=20chain=20reaction=20=E2=80=94=20ne?= =?UTF-8?q?wly=20ignited=20cells=20now=20have=20updated=5Fthis=5Ftick=3Dtr?= =?UTF-8?q?ue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause: when update_fire ignited a neighbor via grid.set(), the new Fire cell had updated_this_tick=false. If the dirty rect iteration hadn't reached that cell yet, it was processed in the same tick, igniting ITS neighbors, creating exponential spread within a single tick. Fix: set updated_this_tick=true on all newly created Fire cells so they wait until the next tick before spreading. Applied to: - update_fire: igniting flammable neighbors - lava_interact: lava igniting wood/grass/flesh - update_flesh: flesh turning to fire from heat - update_grass: grass turning to fire from heat - update_water: water turning to steam from heat - projectile.rs: fireball impact igniting cells Result: fire spreads 1 cell per tick (linear, not exponential). 171 FPS avg, p99 14ms — no lag when spamming fireballs. --- benchmark_results.json | 22 +++++++++++----------- src/physics/projectile.rs | 5 ++++- src/world/cellular.rs | 13 +++++++++++-- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/benchmark_results.json b/benchmark_results.json index 7206d18..40a972c 100644 --- a/benchmark_results.json +++ b/benchmark_results.json @@ -1,17 +1,17 @@ { "mode": "graphics", "ticks": 600, - "total_time_ms": 3483.9, - "avg_fps": 172.2, - "avg_frame_time_ms": 5.78, - "p99_frame_time_ms": 14.20, - "min_frame_time_ms": 4.20, + "total_time_ms": 3437.1, + "avg_fps": 174.6, + "avg_frame_time_ms": 5.70, + "p99_frame_time_ms": 13.96, + "min_frame_time_ms": 4.45, "subsystems": { - "ca_step_avg_us": 1397, - "ca_step_p99_us": 10172, - "ca_step_min_us": 303, - "render_avg_us": 3668, - "render_p99_us": 5514, - "render_min_us": 3259 + "ca_step_avg_us": 1259, + "ca_step_p99_us": 8885, + "ca_step_min_us": 670, + "render_avg_us": 3737, + "render_p99_us": 5483, + "render_min_us": 3221 } } \ No newline at end of file diff --git a/src/physics/projectile.rs b/src/physics/projectile.rs index 4d8764d..07a5bf7 100644 --- a/src/physics/projectile.rs +++ b/src/physics/projectile.rs @@ -136,13 +136,16 @@ impl Projectile { } let cell = grid.get(x, y); if cell.is_empty() { - grid.set(x, y, Cell::new(MaterialId::Fire)); + let mut fire = Cell::new(MaterialId::Fire); + fire.updated_this_tick = true; + grid.set(x, y, fire); } else if cell.material == MaterialId::Wood || cell.material == MaterialId::Grass || cell.material == MaterialId::Flesh { let mut ignited = cell; ignited.material = MaterialId::Fire; + ignited.updated_this_tick = true; grid.set(x, y, ignited); grid.set_temp(x, y, 400.0); } diff --git a/src/world/cellular.rs b/src/world/cellular.rs index f5cef0f..d403db6 100644 --- a/src/world/cellular.rs +++ b/src/world/cellular.rs @@ -243,6 +243,7 @@ impl CellularAutomaton { if temp > 100.0 { let mut new = grid.get(x, y); new.material = MaterialId::Steam; + new.updated_this_tick = true; grid.set(x, y, new); grid.set_temp(x, y, 110.0); } @@ -301,7 +302,10 @@ impl CellularAutomaton { grid.set_temp(x, y, lava_temp - 50.0); } MaterialId::Wood | MaterialId::Grass | MaterialId::Flesh if n_temp < 300.0 => { - grid.set(nx, ny, Cell::new(MaterialId::Fire)); + let mut new_n = neighbor; + new_n.material = MaterialId::Fire; + new_n.updated_this_tick = true; + grid.set(nx, ny, new_n); grid.set_temp(nx, ny, 400.0); } MaterialId::Sand if n_temp > 1700.0 => { @@ -377,6 +381,7 @@ impl CellularAutomaton { if mat.flammable && n_temp < mat.ignition_temp { let mut new_n = neighbor; new_n.material = MaterialId::Fire; + new_n.updated_this_tick = true; grid.set(nx, ny, new_n); grid.set_temp(nx, ny, 400.0); } @@ -473,6 +478,7 @@ impl CellularAutomaton { if temp > 200.0 { let mut new = grid.get(x, y); new.material = MaterialId::Fire; + new.updated_this_tick = true; grid.set(x, y, new); grid.set_temp(x, y, 400.0); } @@ -481,7 +487,10 @@ impl CellularAutomaton { fn update_grass(&mut self, grid: &mut ChunkedGrid, x: i32, y: i32) { let temp = grid.get_temp(x, y); if temp > 250.0 { - grid.set(x, y, Cell::new(MaterialId::Fire)); + let mut new = grid.get(x, y); + new.material = MaterialId::Fire; + new.updated_this_tick = true; + grid.set(x, y, new); grid.set_temp(x, y, 400.0); } }