Persist active fire spread state

This commit is contained in:
2026-05-19 12:25:41 -07:00
parent 6b43a234cf
commit dbb911038a
4 changed files with 80 additions and 1 deletions
+1 -1
View File
@@ -843,7 +843,7 @@ Target deliverable: A small group can join a server, spawn into one biome, gathe
- [x] Add server-authoritative fire spread rules for grass, brush, trees, shelters, and other burnable actors, including fuel, distance, wind, weather, and suppression hooks. Added replicated grass, forest, and structure fire intensities plus active spread radius that grow only on the server from nearby fuel, ignition distance, wind/weather, and a suppression-pressure hook for later rain, carried water, dirt/sand, firebreaks, and tools. - [x] Add server-authoritative fire spread rules for grass, brush, trees, shelters, and other burnable actors, including fuel, distance, wind, weather, and suppression hooks. Added replicated grass, forest, and structure fire intensities plus active spread radius that grow only on the server from nearby fuel, ignition distance, wind/weather, and a suppression-pressure hook for later rain, carried water, dirt/sand, firebreaks, and tools.
- [x] Add fire maintenance gameplay so watched, cleared, contained, or extinguished fires are safe, while neglected fires can become dangerous. Updated lit campfire interaction to maintain the fire, added watch, clear-area, and contain-fire hooks, and made maintenance reduce campfire, vegetation, forest, and structure ignition risks while extinguishing resets active risk state. - [x] Add fire maintenance gameplay so watched, cleared, contained, or extinguished fires are safe, while neglected fires can become dangerous. Updated lit campfire interaction to maintain the fire, added watch, clear-area, and contain-fire hooks, and made maintenance reduce campfire, vegetation, forest, and structure ignition risks while extinguishing resets active risk state.
- [x] Add fire suppression hooks for rain, water carrying, dirt/sand, cleared firebreaks, and future firefighting tools. Added shared server-side suppression hooks plus water, dirt/sand, firebreak, and tool wrappers that raise suppression pressure, reduce ignition risks, reduce active fire intensity, shrink spread radius, and let rain/water drain fuel. - [x] Add fire suppression hooks for rain, water carrying, dirt/sand, cleared firebreaks, and future firefighting tools. Added shared server-side suppression hooks plus water, dirt/sand, firebreak, and tool wrappers that raise suppression pressure, reduce ignition risks, reduce active fire intensity, shrink spread radius, and let rain/water drain fuel.
- [ ] Persist active grass, forest, and structure fires across save/load without corrupting world state. - [x] Persist active grass, forest, and structure fires across save/load without corrupting world state. Extended campfire persistence coverage for ignition flags, ignition risk scores, active grass/forest/structure fire intensities, spread radius, and suppression pressure so save/load recovery preserves active and partially suppressed fire state.
- [ ] Add QA coverage for safe campfires, unsafe campfires, vegetation spread, shelter ignition, suppression, and save/load recovery. - [ ] Add QA coverage for safe campfires, unsafe campfires, vegetation spread, shelter ignition, suppression, and save/load recovery.
- [ ] Add weather sounds. - [ ] Add weather sounds.
- [ ] Add wildlife sounds. - [ ] Add wildlife sounds.
+7
View File
@@ -384,6 +384,13 @@ shrinks spread radius, and lets water/rain also drain fuel. Wet weather
contributes passive suppression pressure so rain and storms naturally slow contributes passive suppression pressure so rain and storms naturally slow
dangerous fires before later UI and inventory actions call the same hooks. dangerous fires before later UI and inventory actions call the same hooks.
Active grass, forest, and structure fire state persists with campfires through
the existing `UAgrarianPersistentActorComponent` provider path. Save records now
carry ignition flags, ignition risk scores, fire intensities, spread radius, and
suppression pressure so save/load recovery can restore active or partially
suppressed fires without resetting the world to a safe state or corrupting the
campfire's fuel, cooking, weather, and maintenance state.
Campfires expose native extinguish logic through `AAgrarianCampfire::Extinguish`. Campfires expose native extinguish logic through `AAgrarianCampfire::Extinguish`.
Extinguishing clears remaining fuel, turns off replicated lit state, and reuses Extinguishing clears remaining fuel, turns off replicated lit state, and reuses
the same visual update path as natural fuel depletion. the same visual update path as natural fuel depletion.
+65
View File
@@ -0,0 +1,65 @@
#!/usr/bin/env python3
"""Verify active grass, forest, and structure fire state persists."""
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
FIRE_CPP = ROOT / "Source" / "AgrarianGame" / "AgrarianCampfire.cpp"
TDD = ROOT / "Docs" / "TechnicalDesignDocument.md"
ROADMAP = ROOT / "AGRARIAN_DEVELOPMENT_ROADMAP.md"
PERSISTED_KEYS = [
"grass_ignition_risk_score",
"forest_ignition_risk_score",
"structure_ignition_risk_score",
"grass_or_brush_ignited",
"forest_fuel_ignited",
"structure_ignited",
"grass_fire_intensity",
"forest_fire_intensity",
"structure_fire_intensity",
"active_fire_spread_radius",
"fire_suppression_pressure",
]
def require(condition: bool, message: str) -> None:
if not condition:
raise SystemExit(f"FAILED: {message}")
def main() -> None:
fire_cpp = FIRE_CPP.read_text(encoding="utf-8")
tdd = TDD.read_text(encoding="utf-8")
roadmap = ROADMAP.read_text(encoding="utf-8")
for key in PERSISTED_KEYS:
require(
f'NumberState.Add(TEXT("{key}")' in fire_cpp,
f"campfire capture missing persisted key {key}",
)
require(
f'NumberState.Find(TEXT("{key}")' in fire_cpp,
f"campfire apply missing persisted key {key}",
)
for token in [
"Active grass, forest, and structure fire state persists",
"ignition flags",
"fire intensities",
"spread radius",
"suppression pressure",
]:
require(token in tdd, f"technical design document missing {token!r}")
require(
"[x] Persist active grass, forest, and structure fires across save/load" in roadmap,
"roadmap item is not checked off",
)
print("OK: active fire state persists across save/load.")
if __name__ == "__main__":
main()
+7
View File
@@ -231,6 +231,7 @@ void AAgrarianCampfire::CapturePersistentState_Implementation(UAgrarianPersisten
PersistentComponent->NumberState.Add(TEXT("forest_fire_intensity"), ForestFireIntensity); PersistentComponent->NumberState.Add(TEXT("forest_fire_intensity"), ForestFireIntensity);
PersistentComponent->NumberState.Add(TEXT("structure_fire_intensity"), StructureFireIntensity); PersistentComponent->NumberState.Add(TEXT("structure_fire_intensity"), StructureFireIntensity);
PersistentComponent->NumberState.Add(TEXT("active_fire_spread_radius"), ActiveFireSpreadRadius); PersistentComponent->NumberState.Add(TEXT("active_fire_spread_radius"), ActiveFireSpreadRadius);
PersistentComponent->NumberState.Add(TEXT("fire_suppression_pressure"), FireSuppressionPressure);
} }
void AAgrarianCampfire::ApplyPersistentState_Implementation(UAgrarianPersistentActorComponent* PersistentComponent) void AAgrarianCampfire::ApplyPersistentState_Implementation(UAgrarianPersistentActorComponent* PersistentComponent)
@@ -260,6 +261,7 @@ void AAgrarianCampfire::ApplyPersistentState_Implementation(UAgrarianPersistentA
const float* SavedForestFireIntensity = PersistentComponent->NumberState.Find(TEXT("forest_fire_intensity")); const float* SavedForestFireIntensity = PersistentComponent->NumberState.Find(TEXT("forest_fire_intensity"));
const float* SavedStructureFireIntensity = PersistentComponent->NumberState.Find(TEXT("structure_fire_intensity")); const float* SavedStructureFireIntensity = PersistentComponent->NumberState.Find(TEXT("structure_fire_intensity"));
const float* SavedActiveFireSpreadRadius = PersistentComponent->NumberState.Find(TEXT("active_fire_spread_radius")); const float* SavedActiveFireSpreadRadius = PersistentComponent->NumberState.Find(TEXT("active_fire_spread_radius"));
const float* SavedFireSuppressionPressure = PersistentComponent->NumberState.Find(TEXT("fire_suppression_pressure"));
if (SavedFuelSeconds) if (SavedFuelSeconds)
{ {
@@ -356,6 +358,11 @@ void AAgrarianCampfire::ApplyPersistentState_Implementation(UAgrarianPersistentA
ActiveFireSpreadRadius = FMath::Clamp(*SavedActiveFireSpreadRadius, 0.0f, MaxFireSpreadRadius); ActiveFireSpreadRadius = FMath::Clamp(*SavedActiveFireSpreadRadius, 0.0f, MaxFireSpreadRadius);
} }
if (SavedFireSuppressionPressure)
{
FireSuppressionPressure = FMath::Clamp(*SavedFireSuppressionPressure, 0.0f, 1.0f);
}
SetLit(SavedLit && *SavedLit > 0.5f && FuelSeconds > 0.0f); SetLit(SavedLit && *SavedLit > 0.5f && FuelSeconds > 0.0f);
} }