use super::snapshot::{apply_snapshot_to_entity, recreate_hierarchy_with_mapping};
use super::{UndoResult, UndoableOperation, entity_exists};
use crate::prelude::*;
pub trait Reversible {
type Context;
type Result;
fn reverse(&self, context: &mut Self::Context) -> (Self, Self::Result)
where
Self: Sized;
}
impl Reversible for UndoableOperation {
type Context = World;
type Result = UndoResult;
fn reverse(&self, context: &mut Self::Context) -> (Self, Self::Result)
where
Self: Sized,
{
match self {
UndoableOperation::EntityCreated {
hierarchy,
current_entity,
} => {
despawn_recursive_immediate(context, *current_entity);
(
UndoableOperation::EntityDeleted {
hierarchy: hierarchy.clone(),
deleted_entity: *current_entity,
},
UndoResult {
select_entity: None,
entity_mapping: None,
},
)
}
UndoableOperation::EntityDeleted { hierarchy, .. } => {
let original_parent = hierarchy
.snapshot
.parent_entity
.filter(|&parent| entity_exists(context, parent));
let (new_entity, id_mapping) =
recreate_hierarchy_with_mapping(context, hierarchy, original_parent);
context.resources.children_cache_valid = false;
(
UndoableOperation::EntityCreated {
hierarchy: hierarchy.clone(),
current_entity: new_entity,
},
UndoResult {
select_entity: Some(new_entity),
entity_mapping: Some(id_mapping),
},
)
}
UndoableOperation::TransformChanged {
entity,
old_transform,
new_transform,
} => {
let exists = entity_exists(context, *entity);
if exists {
context.set_local_transform(*entity, *old_transform);
mark_local_transform_dirty(context, *entity);
}
(
UndoableOperation::TransformChanged {
entity: *entity,
old_transform: *new_transform,
new_transform: *old_transform,
},
UndoResult {
select_entity: if exists { Some(*entity) } else { None },
entity_mapping: None,
},
)
}
UndoableOperation::BulkTransformChanged { transforms } => {
let mut first_entity = None;
let reversed_transforms: Vec<_> = transforms
.iter()
.map(|(entity, old_transform, new_transform)| {
let exists = entity_exists(context, *entity);
if exists {
context.set_local_transform(*entity, *old_transform);
mark_local_transform_dirty(context, *entity);
if first_entity.is_none() {
first_entity = Some(*entity);
}
}
(*entity, *new_transform, *old_transform)
})
.collect();
(
UndoableOperation::BulkTransformChanged {
transforms: reversed_transforms,
},
UndoResult {
select_entity: first_entity,
entity_mapping: None,
},
)
}
UndoableOperation::BulkEntitiesCreated {
hierarchies,
entities,
} => {
for entity in entities {
despawn_recursive_immediate(context, *entity);
}
(
UndoableOperation::BulkEntitiesDeleted {
hierarchies: hierarchies.clone(),
deleted_entities: entities.clone(),
},
UndoResult {
select_entity: None,
entity_mapping: None,
},
)
}
UndoableOperation::BulkEntitiesDeleted {
hierarchies,
deleted_entities: _,
} => {
let mut new_entities = Vec::new();
let mut all_mappings = std::collections::HashMap::new();
for hierarchy in hierarchies {
let original_parent = hierarchy
.snapshot
.parent_entity
.filter(|&parent| entity_exists(context, parent));
let (new_entity, id_mapping) =
recreate_hierarchy_with_mapping(context, hierarchy, original_parent);
new_entities.push(new_entity);
all_mappings.extend(id_mapping);
}
context.resources.children_cache_valid = false;
let first_entity = new_entities.first().copied();
(
UndoableOperation::BulkEntitiesCreated {
hierarchies: hierarchies.clone(),
entities: new_entities,
},
UndoResult {
select_entity: first_entity,
entity_mapping: Some(all_mappings),
},
)
}
UndoableOperation::ComponentChanged {
entity,
snapshot_before,
snapshot_after,
} => {
let exists = entity_exists(context, *entity);
if exists {
apply_snapshot_to_entity(context, *entity, snapshot_before);
}
(
UndoableOperation::ComponentChanged {
entity: *entity,
snapshot_before: snapshot_after.clone(),
snapshot_after: snapshot_before.clone(),
},
UndoResult {
select_entity: if exists { Some(*entity) } else { None },
entity_mapping: None,
},
)
}
}
}
}