use gizmo_core::World;
#[derive(Clone)]
pub struct EntitySnapshot {
pub entity_id: u32,
pub name: Option<String>,
pub components: std::collections::BTreeMap<String, ron::Value>,
}
#[derive(Clone)]
pub struct SceneSnapshot {
pub entities: Vec<EntitySnapshot>,
pub timestamp: std::time::Instant,
}
impl SceneSnapshot {
pub fn capture(
world: &World,
registry: &crate::registry::SceneRegistry,
protected_ids: &std::collections::HashSet<u32>,
) -> Self {
let mut entities = Vec::new();
let names = world.borrow::<gizmo_core::EntityName>();
for ent in world.iter_alive_entities() {
let id = ent.id();
if protected_ids.contains(&id) {
continue;
}
if let Some(name) = names.get(id) {
if name.0.starts_with("Editor ") || name.0 == "Highlight Box" {
continue;
}
}
let name = names.get(id).map(|n| n.0.clone());
let mut components = std::collections::BTreeMap::new();
for comp_name in registry.all_components() {
if let Some(serializer) = registry.get_serializer(comp_name) {
if let Some(comp_value) = serializer(world, id) {
components.insert(comp_name.clone(), comp_value);
}
}
}
if name.is_some() || !components.is_empty() {
entities.push(EntitySnapshot {
entity_id: id,
name,
components,
});
}
}
Self {
entities,
timestamp: std::time::Instant::now(),
}
}
pub fn restore(
&self,
world: &mut World,
registry: &crate::registry::SceneRegistry,
protected_ids: &std::collections::HashSet<u32>,
) -> RestoreResult {
let start = std::time::Instant::now();
let mut restored_count = 0u32;
let mut despawned_count = 0u32;
let alive = world.iter_alive_entities();
let mut to_despawn = Vec::new();
{
let names = world.borrow::<gizmo_core::EntityName>();
for ent in &alive {
let id = ent.id();
if protected_ids.contains(&id) {
continue;
}
if let Some(name) = names.get(id) {
if name.0.starts_with("Editor ") || name.0 == "Highlight Box" {
continue;
}
}
to_despawn.push(*ent);
}
}
for ent in to_despawn {
world.despawn(ent);
despawned_count += 1;
}
for snap_entity in &self.entities {
let ent = world.spawn();
if let Some(ref name) = snap_entity.name {
world.add_component(ent, gizmo_core::EntityName::new(name));
}
for (comp_name, comp_val) in &snap_entity.components {
if let Some(deserializer) = registry.get_deserializer(comp_name) {
deserializer(world, ent.id(), comp_val);
}
}
restored_count += 1;
}
RestoreResult {
despawned: despawned_count,
restored: restored_count,
duration: start.elapsed(),
}
}
pub fn entity_count(&self) -> usize {
self.entities.len()
}
pub fn age(&self) -> std::time::Duration {
self.timestamp.elapsed()
}
}
#[derive(Debug, Clone)]
pub struct RestoreResult {
pub despawned: u32,
pub restored: u32,
pub duration: std::time::Duration,
}
impl std::fmt::Display for RestoreResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Restore: {} entity silindi, {} entity geri yüklendi ({:.2}ms)",
self.despawned,
self.restored,
self.duration.as_secs_f64() * 1000.0,
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_scene_snapshot_capture_empty_world() {
let world = World::new();
let registry = crate::registry::SceneRegistry::new();
let protected = std::collections::HashSet::new();
let snapshot = SceneSnapshot::capture(&world, ®istry, &protected);
assert_eq!(snapshot.entity_count(), 0);
}
#[test]
fn test_scene_snapshot_round_trip() {
let mut world = World::new();
let registry = crate::registry::SceneRegistry::with_core_components();
let protected = std::collections::HashSet::new();
let ent = world.spawn();
world.add_component(ent, gizmo_core::EntityName::new("TestCube"));
world.add_component(
ent,
gizmo_physics::components::Transform::new(gizmo_math::Vec3::new(1.0, 2.0, 3.0)),
);
let snapshot = SceneSnapshot::capture(&world, ®istry, &protected);
assert_eq!(snapshot.entity_count(), 1);
assert_eq!(snapshot.entities[0].name.as_deref(), Some("TestCube"));
assert!(snapshot.entities[0].components.contains_key("Transform"));
world.despawn(ent);
assert_eq!(world.iter_alive_entities().len(), 0);
let result = snapshot.restore(&mut world, ®istry, &protected);
assert_eq!(result.restored, 1);
let names = world.borrow::<gizmo_core::EntityName>();
let alive = world.iter_alive_entities();
assert_eq!(alive.len(), 1);
let restored_name = names.get(alive[0].id());
assert!(restored_name.is_some());
assert_eq!(restored_name.unwrap().0, "TestCube");
}
}