fix(simulation): persist TriangleState in SaveStateV1
Triangle phase and tension were silently lost on save/load. Now serialized as triangle_states vec in SaveStateV1, sorted by triangle_id for determinism (D-010). Dedicated triangle entities are respawned on load. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -16,7 +16,7 @@ use thiserror::Error;
|
|||||||
|
|
||||||
use crate::bridge::types::SaveLoadResultWire;
|
use crate::bridge::types::SaveLoadResultWire;
|
||||||
use crate::bridge::types::SnapshotBuffer;
|
use crate::bridge::types::SnapshotBuffer;
|
||||||
use crate::content::template::TemplateReferenceMap;
|
use crate::content::template::{TemplateReferenceMap, TriangleState};
|
||||||
use crate::knowledge::graph::KnowledgeGraph;
|
use crate::knowledge::graph::KnowledgeGraph;
|
||||||
use crate::knowledge::registry::EntityRegistry;
|
use crate::knowledge::registry::EntityRegistry;
|
||||||
use crate::npc::Npc;
|
use crate::npc::Npc;
|
||||||
@@ -113,6 +113,13 @@ pub fn save_to_file(path: &Path, world: &mut World) -> Result<(), SaveLoadError>
|
|||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
// Capture TriangleState components — sorted by triangle_id for determinism (D-010).
|
||||||
|
let mut triangle_states: Vec<TriangleState> = {
|
||||||
|
let mut q = world.query::<&TriangleState>();
|
||||||
|
q.iter(world).cloned().collect()
|
||||||
|
};
|
||||||
|
triangle_states.sort_by_key(|t| t.triangle_id.0);
|
||||||
|
|
||||||
let state = SaveStateV1 {
|
let state = SaveStateV1 {
|
||||||
format_version: SAVE_FORMAT_VERSION,
|
format_version: SAVE_FORMAT_VERSION,
|
||||||
tick,
|
tick,
|
||||||
@@ -122,6 +129,7 @@ pub fn save_to_file(path: &Path, world: &mut World) -> Result<(), SaveLoadError>
|
|||||||
relationship_graph,
|
relationship_graph,
|
||||||
npc_states,
|
npc_states,
|
||||||
template_references,
|
template_references,
|
||||||
|
triangle_states,
|
||||||
};
|
};
|
||||||
|
|
||||||
let bytes = state
|
let bytes = state
|
||||||
@@ -210,6 +218,11 @@ pub fn load_from_file(path: &Path, world: &mut World) -> Result<(), SaveLoadErro
|
|||||||
// Restore simulation resources.
|
// Restore simulation resources.
|
||||||
world.insert_resource(state.relationship_graph);
|
world.insert_resource(state.relationship_graph);
|
||||||
world.insert_resource(state.template_references);
|
world.insert_resource(state.template_references);
|
||||||
|
|
||||||
|
// Restore triangle states (#250) — spawn dedicated entities for each.
|
||||||
|
for ts in &state.triangle_states {
|
||||||
|
world.spawn(ts.clone());
|
||||||
|
}
|
||||||
{
|
{
|
||||||
let mut t = world.resource_mut::<SimulationTime>();
|
let mut t = world.resource_mut::<SimulationTime>();
|
||||||
t.tick = state.tick;
|
t.tick = state.tick;
|
||||||
@@ -508,6 +521,7 @@ mod tests {
|
|||||||
relationship_graph: RelationshipGraph::new(),
|
relationship_graph: RelationshipGraph::new(),
|
||||||
npc_states: vec![],
|
npc_states: vec![],
|
||||||
template_references: TemplateReferenceMap::default(),
|
template_references: TemplateReferenceMap::default(),
|
||||||
|
triangle_states: vec![],
|
||||||
};
|
};
|
||||||
let bytes = bad_state.to_bytes().expect("serialize");
|
let bytes = bad_state.to_bytes().expect("serialize");
|
||||||
let path = temp_path();
|
let path = temp_path();
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ use bevy_ecs::entity::Entity;
|
|||||||
use bevy_ecs::world::World;
|
use bevy_ecs::world::World;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::content::template::{TemplateOwnership, TemplateReferenceMap};
|
use crate::content::template::{TemplateOwnership, TemplateReferenceMap, TriangleState};
|
||||||
use crate::knowledge::graph::KnowledgeGraph;
|
use crate::knowledge::graph::KnowledgeGraph;
|
||||||
use crate::knowledge::registry::StableEntityId;
|
use crate::knowledge::registry::StableEntityId;
|
||||||
use crate::knowledge::types::StableId;
|
use crate::knowledge::types::StableId;
|
||||||
@@ -89,6 +89,11 @@ pub struct SaveStateV1 {
|
|||||||
/// relationship metadata even when their NPCs are not in Active tier.
|
/// relationship metadata even when their NPCs are not in Active tier.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub template_references: TemplateReferenceMap,
|
pub template_references: TemplateReferenceMap,
|
||||||
|
/// Triangle escalation states (#250).
|
||||||
|
/// Persisted so tension/phase survive save/load. Sorted by triangle_id
|
||||||
|
/// for deterministic serialization (D-010).
|
||||||
|
#[serde(default)]
|
||||||
|
pub triangle_states: Vec<TriangleState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Per-NPC state snapshot for `SaveStateV1`.
|
/// Per-NPC state snapshot for `SaveStateV1`.
|
||||||
@@ -399,6 +404,7 @@ mod tests {
|
|||||||
relationship_graph: RelationshipGraph::new(),
|
relationship_graph: RelationshipGraph::new(),
|
||||||
npc_states: vec![],
|
npc_states: vec![],
|
||||||
template_references: TemplateReferenceMap::default(),
|
template_references: TemplateReferenceMap::default(),
|
||||||
|
triangle_states: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -794,6 +800,7 @@ mod tests {
|
|||||||
relationship_graph: RelationshipGraph::new(),
|
relationship_graph: RelationshipGraph::new(),
|
||||||
npc_states: vec![frozen],
|
npc_states: vec![frozen],
|
||||||
template_references: TemplateReferenceMap::default(),
|
template_references: TemplateReferenceMap::default(),
|
||||||
|
triangle_states: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
let bytes = save.to_bytes().expect("serialize");
|
let bytes = save.to_bytes().expect("serialize");
|
||||||
|
|||||||
@@ -204,6 +204,7 @@ fn save_state_npc_kg_isolation() {
|
|||||||
relationship_graph: RelationshipGraph::new(),
|
relationship_graph: RelationshipGraph::new(),
|
||||||
npc_states: vec![npc_a_state, npc_b_state],
|
npc_states: vec![npc_a_state, npc_b_state],
|
||||||
template_references: Default::default(),
|
template_references: Default::default(),
|
||||||
|
triangle_states: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
// Roundtrip: serialize → deserialize.
|
// Roundtrip: serialize → deserialize.
|
||||||
|
|||||||
Reference in New Issue
Block a user