use super::HierarchyNode;
use nightshade::ecs::bounding_volume::components::BoundingVolume;
use nightshade::ecs::grass::{GrassInteractor, GrassRegion};
use nightshade::ecs::navmesh::NavMeshAgent;
use nightshade::ecs::particles::components::ParticleEmitter;
use nightshade::ecs::physics::components::CharacterControllerComponent;
use nightshade::ecs::transform::components::IgnoreParentScale;
use nightshade::ecs::world::CASTS_SHADOW;
use nightshade::prelude::*;
#[derive(Clone, serde::Serialize, serde::Deserialize)]
#[serde(crate = "serde")]
pub struct EntitySnapshot {
pub name: Option<Name>,
pub local_transform: Option<LocalTransform>,
#[serde(skip)]
pub global_transform: Option<GlobalTransform>,
#[serde(skip)]
pub parent_entity: Option<Entity>,
pub camera: Option<Camera>,
pub light: Option<Light>,
pub visibility: Option<Visibility>,
pub render_mesh: Option<RenderMesh>,
pub instanced_mesh: Option<InstancedMesh>,
pub material_ref: Option<MaterialRef>,
pub render_layer: Option<RenderLayer>,
pub script: Option<Script>,
pub text: Option<Text>,
pub lines: Option<Lines>,
pub sprite: Option<Sprite>,
pub sprite_animator: Option<SpriteAnimator>,
pub decal: Option<Decal>,
pub water: Option<Water>,
pub animation_player: Option<AnimationPlayer>,
pub bounding_volume: Option<BoundingVolume>,
pub casts_shadow: bool,
pub ignore_parent_scale: bool,
#[serde(skip)]
pub particle_emitter: Option<ParticleEmitter>,
#[serde(skip)]
pub grass_region: Option<GrassRegion>,
#[serde(skip)]
pub grass_interactor: Option<GrassInteractor>,
#[serde(skip)]
pub character_controller: Option<CharacterControllerComponent>,
#[serde(skip)]
pub navmesh_agent: Option<NavMeshAgent>,
}
impl EntitySnapshot {
pub fn capture(world: &World, entity: Entity) -> Self {
let parent_entity = world.core.get_parent(entity).and_then(|p| p.0);
Self {
name: world.core.get_name(entity).cloned(),
local_transform: world.core.get_local_transform(entity).cloned(),
global_transform: world.core.get_global_transform(entity).cloned(),
parent_entity,
camera: world.core.get_camera(entity).cloned(),
light: world.core.get_light(entity).cloned(),
visibility: world.core.get_visibility(entity).cloned(),
render_mesh: world.core.get_render_mesh(entity).cloned(),
instanced_mesh: world.core.get_instanced_mesh(entity).cloned(),
material_ref: world.core.get_material_ref(entity).cloned(),
render_layer: world.core.get_render_layer(entity).cloned(),
script: world.core.get_script(entity).cloned(),
text: world.core.get_text(entity).cloned(),
lines: world.core.get_lines(entity).cloned(),
sprite: world.sprite2d.get_sprite(entity).cloned(),
sprite_animator: world.sprite2d.get_sprite_animator(entity).cloned(),
decal: world.core.get_decal(entity).cloned(),
water: world.core.get_water(entity).cloned(),
animation_player: world.core.get_animation_player(entity).cloned(),
bounding_volume: world.core.get_bounding_volume(entity).cloned(),
casts_shadow: world.core.entity_has_casts_shadow(entity),
ignore_parent_scale: world.core.entity_has_ignore_parent_scale(entity),
particle_emitter: world.core.get_particle_emitter(entity).cloned(),
grass_region: world.core.get_grass_region(entity).cloned(),
grass_interactor: world.core.get_grass_interactor(entity).cloned(),
character_controller: world.core.get_character_controller(entity).cloned(),
navmesh_agent: world.core.get_navmesh_agent(entity).cloned(),
}
}
}
pub fn capture_hierarchy(world: &World, entity: Entity) -> HierarchyNode {
let snapshot = EntitySnapshot::capture(world, entity);
let children = query_children(world, entity)
.into_iter()
.map(|child| capture_hierarchy(world, child))
.collect();
HierarchyNode {
entity,
snapshot,
children,
}
}
pub fn recreate_hierarchy_with_mapping(
world: &mut World,
node: &HierarchyNode,
parent: Option<Entity>,
) -> (Entity, std::collections::HashMap<Entity, Entity>) {
let mut mapping = std::collections::HashMap::new();
let root_entity = recreate_hierarchy_internal_with_mapping(world, node, parent, &mut mapping);
(root_entity, mapping)
}
fn recreate_hierarchy_internal_with_mapping(
world: &mut World,
node: &HierarchyNode,
parent: Option<Entity>,
mapping: &mut std::collections::HashMap<Entity, Entity>,
) -> Entity {
let new_entity = recreate_entity(world, &node.snapshot, parent);
mapping.insert(node.entity, new_entity);
for child_node in &node.children {
recreate_hierarchy_internal_with_mapping(world, child_node, Some(new_entity), mapping);
}
new_entity
}
pub fn recreate_entity(
world: &mut World,
snapshot: &EntitySnapshot,
parent: Option<Entity>,
) -> Entity {
let entities = EntityBuilder::new()
.with_local_transform(snapshot.local_transform.unwrap_or_default())
.with_global_transform(snapshot.global_transform.unwrap_or_default())
.spawn(world, 1);
let entity = entities[0];
if let Some(name) = &snapshot.name {
world.core.set_name(entity, name.clone());
}
if let Some(parent_entity) = parent
&& world.core.get_local_transform(parent_entity).is_some()
{
world.core.set_parent(entity, Parent(Some(parent_entity)));
}
if let Some(camera) = &snapshot.camera {
world.core.set_camera(entity, *camera);
}
if let Some(light) = &snapshot.light {
world.core.set_light(entity, light.clone());
}
if let Some(visibility) = &snapshot.visibility {
world.core.set_visibility(entity, visibility.clone());
}
if let Some(render_mesh) = &snapshot.render_mesh {
world.core.set_render_mesh(entity, render_mesh.clone());
world.resources.mesh_render_state.mark_entity_added(entity);
if let Some(&index) = world
.resources
.mesh_cache
.registry
.name_to_index
.get(&render_mesh.name)
{
world.resources.mesh_cache.registry.add_reference(index);
}
}
if let Some(material_ref) = &snapshot.material_ref {
world.core.set_material_ref(entity, material_ref.clone());
if let Some(&index) = world
.resources
.material_registry
.registry
.name_to_index
.get(&material_ref.name)
{
world
.resources
.material_registry
.registry
.add_reference(index);
}
}
if let Some(instanced_mesh) = &snapshot.instanced_mesh {
world
.core
.set_instanced_mesh(entity, instanced_mesh.clone());
}
if let Some(render_layer) = &snapshot.render_layer {
world.core.set_render_layer(entity, *render_layer);
}
if let Some(script) = &snapshot.script {
world.core.set_script(entity, script.clone());
}
if let Some(text) = &snapshot.text {
world.core.set_text(entity, text.clone());
}
if let Some(lines) = &snapshot.lines {
world.core.set_lines(entity, lines.clone());
}
if let Some(sprite) = &snapshot.sprite {
world.sprite2d.set_sprite(entity, sprite.clone());
}
if let Some(sprite_animator) = &snapshot.sprite_animator {
world
.sprite2d
.set_sprite_animator(entity, sprite_animator.clone());
}
if let Some(decal) = &snapshot.decal {
world.core.set_decal(entity, decal.clone());
}
if let Some(water) = &snapshot.water {
world.core.set_water(entity, water.clone());
}
if let Some(animation_player) = &snapshot.animation_player {
world
.core
.set_animation_player(entity, animation_player.clone());
}
if let Some(bounding_volume) = &snapshot.bounding_volume {
world.core.set_bounding_volume(entity, *bounding_volume);
}
if snapshot.casts_shadow {
world.core.add_components(entity, CASTS_SHADOW);
}
if snapshot.ignore_parent_scale {
world
.core
.set_ignore_parent_scale(entity, IgnoreParentScale);
}
if let Some(particle_emitter) = &snapshot.particle_emitter {
world
.core
.set_particle_emitter(entity, particle_emitter.clone());
}
if let Some(grass_region) = &snapshot.grass_region {
world.core.set_grass_region(entity, grass_region.clone());
}
if let Some(grass_interactor) = &snapshot.grass_interactor {
world
.core
.set_grass_interactor(entity, grass_interactor.clone());
}
if let Some(character_controller) = &snapshot.character_controller {
world
.core
.set_character_controller(entity, character_controller.clone());
}
if let Some(navmesh_agent) = &snapshot.navmesh_agent {
world.core.set_navmesh_agent(entity, navmesh_agent.clone());
}
entity
}