Burn blocks in place with a fire overlay - #20
Conversation
Flammable blocks enter a burning state instead of being replaced by a fire block: the block keeps its texture and collision while a new FireOverlay draws animated flame and smoke billboards over it. Burning creeps into flammable neighbours a few blocks a second and the block crumbles to air when its burn timer expires. BLOCK_FIRE remains only the standalone flame flint-and-steel lights on a non-flammable face.
📋 Review of PR #20 — Burn blocks in place with a fire overlay📌 Review Metadata
Summary: This PR replaces the old "fire swaps the block" behavior with a three-state burn lifecycle: flammable blocks burn in place (voxel untouched, collision intact) with a new 🔴 Critical Issues (Must Fix - Blocks Merge)None identified. Worker-thread safety is clean (all fire state is touched only from
|
| Principle | Score | Notes |
|---|---|---|
| Single Responsibility | 6 | FireOverlay, shaders, and the registry flag are cleanly separated, but voxel_world.gd absorbs another ~330 lines of simulation (now 1608 lines) beside water/explosives; a FireSim helper would match the water-tick scale better |
| Open/Closed | 8 | New FLAG_FLAMMABLE extends the def-table instead of branching on ids; shader gains a disabled-by-default fire_layer uniform; existing blocks unaffected |
| Liskov Substitution | 8 | FireOverlay extends Node3D with no contract violations; registry helpers are pure additions |
| Interface Segregation | 6 | use_flint_and_steel reuses the stringly-typed Dictionary payload of trigger_explosive — consistent with the codebase, though "ignited" is only meaningful on one branch |
| Dependency Inversion | 7 | Main stays decoupled via the existing item_used signal and the world-facing API; Player.target_normal reuse keeps the signal contract intact |
| Average | 7.0 |
🎯 Final Assessment
Overall Confidence Score: 78%
Confidence Breakdown:
- Code Quality: 88% — idiomatic, well-commented, mirrors the water-tick batching and edit-persistence invariants precisely
- Completeness: 85% — roadmap item genuinely fulfilled (spread, decay, ignition, chain detonation, persistence reseeding, assets, docs, CI)
- Risk Level: 82% — no worker-thread, determinism, or data-loss exposure found; the water-interaction gap is the main correctness residue
- Verification: 65% —
tools/fire_verify.tscncoverage is strong and CI-wired, but it could not be run on this runner (engine unavailable per instructions); residual risk also noted for the visual overlay (needs a display run, e.g.redot -path . res://tools/fire_verify.tscnplus an in-game check)
Merge Readiness:
- All critical issues resolved
- SOLID average score >= 6.0
- Overall confidence >= 60%
- No security concerns
- No unresolved worker-thread, determinism, or data-loss risk
Verdict:
MERGE WITH FIXES — Solid, convention-following implementation with no blocking risks; address the water/fire interplay gap (underwater ignition + missing _seed_water on burn-out) either in this PR or an immediate follow-up, and confirm by running tools/fire_verify.tscn and the parse check once the engine is available.
{
"reviewed_sha": "08b295f5964cfaa5aa3e7b7a0373529e9e7b5f33",
"critical_issues": 0,
"high_priority_issues": 0,
"medium_priority_issues": 1,
"overall_confidence_score": 78,
"recommendation": "MERGE WITH FIXES"
}- Refuse to ignite a flooded cell and seed adjacent water when a fire or a burnt block leaves air, matching break_block()/carve_sphere(). - Keep the burning cells nearest the camera when the overlay hits its cap. - Report a submerged/already-burning block instead of the wrong face hint, and treat any non-air, non-water neighbour as fire support. - Bail if a chain blast carved a burning block mid-tick.
|
All previous findings are addressed, and the fixes check out against the full-file invariants. The local checkout is exactly the PR head 📋 SummaryNo linked issues in the PR body (no "Fixes/Closes #" found). Commit 📌 Review Metadata
🔴 Critical Issues (Must Fix - Blocks Merge)✅ All previously reported critical issues have been resolved (none were reported). None identified. Re-verified on the new commit: fire state remains main-thread-only (
|
| Principle | Score | Notes |
|---|---|---|
| Single Responsibility | 6 | Overlay/shaders/registry stay separated, but voxel_world.gd grows to 1630 lines with fire beside water and explosives; a FireSim helper remains the natural next refactor |
| Open/Closed | 8 | Fix extends behavior through existing seams (flag table, edit/water-seed pipeline, payload dictionary) without branching on block ids |
| Lishov Substitution | 8 | FireOverlay extends Node3D unchanged; new _is_submerged is a pure query |
| Interface Segregation | 7 | The blocked string disambiguates the flint-and-steel payload without breaking the existing Dictionary contract Main already consumes |
| Dependency Inversion | 7 | Main stays decoupled via the item_used signal; refresh() now takes a camera dependency implicitly via the viewport, acceptable for a presentation node |
| Average | 7.2 |
🎯 Final Assessment
Overall Confidence Score: 86%
Confidence Breakdown:
- Code Quality: 88% — fixes are minimal, idiomatic, and mirror the
break_block()/carve_sphere()conventions they align with - Completeness: 92% — all four review findings addressed with dedicated test coverage; only the lateral-water nuance remains (cosmetic)
- Risk Level: 85% — no worker-thread, determinism, or data-loss exposure; new water seeding routes through the existing
_water_tickqueue - Verification: 78% —
tools/fire_verify.tscn(incl. the new_check_submerged_and_support) could not be run on this runner (engine unavailable); the author reports local passes, and I traced the test's expectations through_seed_water/_queue_watermanually — run the parse check plusredot --headless --path . res://tools/fire_verify.tscnwhere the engine is available to confirm
Merge Readiness:
- All critical issues resolved
- SOLID average score >= 6.0
- Overall confidence >= 60%
- No security concerns
- No unresolved worker-thread, determinism, or data-loss risk
Verdict:
MERGE — All previously reported issues are fixed with test coverage, and no new blocking concerns were introduced; the one remaining LOW (lateral-water ignition) is cosmetic and self-healing.
{
"reviewed_sha": "4704e2a2335e50f2e478885557a5ab65fe5aa7cf",
"critical_issues": 0,
"high_priority_issues": 0,
"medium_priority_issues": 0,
"overall_confidence_score": 86,
"recommendation": "MERGE"
}|
All previous findings verified fixed on the new head 📋 SummaryNo linked issues in the PR body (no "Fixes/Closes #" found). Commit 📌 Review Metadata
🔴 Critical Issues (Must Fix - Blocks Merge)✅ All previously reported critical issues have been resolved (none were reported). None identified. Re-verified on this head: fire state remains main-thread-only (
|
| Principle | Score | Notes |
|---|---|---|
| Single Responsibility | 6 | Overlay/shaders/registry stay separated, but voxel_world.gd is now 1634 lines with fire beside water and explosives; a FireSim helper remains the natural next refactor |
| Open/Closed | 8 | _is_submerged broadens behavior through the existing offset table without branching on block ids; no existing semantics broken |
| Liskov Substitution | 8 | FireOverlay extends Node3D unchanged; _is_submerged remains a pure query |
| Interface Segregation | 7 | The blocked string disambiguates the flint-and-steel Dictionary payload without breaking the contract Main consumes |
| Dependency Inversion | 7 | Main stays decoupled via item_used; the overlay takes its camera dependency implicitly via the viewport |
| Average | 7.2 |
🎯 Final Assessment
Overall Confidence Score: 88%
Confidence Breakdown:
- Code Quality: 88% — the incremental fix is minimal, idiomatic, comment-updated, and matches the previously suggested remedy exactly
- Completeness: 95% — every finding across both prior reviews is now addressed with dedicated verifier coverage; only the wet-while-burning nuance remains (cosmetic, self-healing)
- Risk Level: 87% — no worker-thread, determinism, or data-loss exposure; the broadened check adds at most six lookups per ignition attempt, none in per-frame paths
- Verification: 78% —
tools/fire_verify.tscn(including the new shoreline case) could not be run on this runner (engine unavailable); expectations were traced manually through_is_submerged/use_flint_and_steeland are consistent — run the parse check plusredot --headless --path . res://tools/fire_verify.tscnwhere the engine is available to confirm
Merge Readiness:
- All critical issues resolved
- SOLID average score >= 6.0
- Overall confidence >= 60%
- No security concerns
- No unresolved worker-thread, determinism, or data-loss risk
Verdict:
MERGE — The final remaining finding is fixed with test coverage and no new issues were introduced; the one residual LOW (water not dousing an already-burning block) is cosmetic and a natural follow-up.
{
"reviewed_sha": "16000117f465a44da551f6fc9a601de524f256ad",
"critical_issues": 0,
"high_priority_issues": 0,
"medium_priority_issues": 0,
"overall_confidence_score": 88,
"recommendation": "MERGE"
}


Summary
Fire no longer swaps a flammable block for a fire block. Burning is now a three-state lifecycle:
_burningstate forFUEL_BURN_TICKSwith its texture and collision intact. A newFireOverlay(world/fire_overlay.gd+fire_overlay.gdshader/smoke_overlay.gdshader) clusters animated flame and smoke billboards on it (one MultiMesh per effect, animated in-shader from per-instance phase/progress, refreshed only on the 4 Hz fire tick). While burning it spreads into flammable neighbours one at a time._record_edit(), so the settled result survives chunk regeneration.Spreading is paced so a tree burns gradually (~2 blocks/s): a per-block
FIRE_IGNITION_DELAY_TICKS(4) before a new block can spread,FIRE_SPREAD_PER_TICK(1) on everyFIRE_SPREAD_PERIOD_TICKS(2), plus a per-cellFIRE_SPREAD_INTERVAL_TICKScooldown. Burning can chain-detonate adjacent TNT/nukes.BLOCK_FIRE(70) is now only the standalone flame flint-and-steel leaves on a non-flammable face (e.g. stone); clicking a log/leaf starts that block burning instead of replacing it.BlockRegistry.FLAG_FLAMMABLEstill marks logs, leaves, dry plants, and mushrooms as fuel.Assets
assets/placeholders/fire/adds a generated flame sheet and a smoke puff (tools/gen_fire_texture.gd, deterministic), with a README noting provenance.Tests
tools/fire_verify.tscncovers flammability flags, burn-in-place, spread pacing, burn-out to persistent air, decay, chain detonation, flint-and-steel routing, persistence reseeding, and the shader/overlay wiring.Verified locally (rebased on current
main): parse check clean;fire_verify,explosives_verify,player_target_verify, allworldgen_*+stream_full_verify, and the audio/weather/ui/input/photo/frame-pacing verifiers pass.