use crate::editor_scene::EditorScene;
use crate::project::ProjectState;
use nightshade::ecs::scene::{
AssetUuid, SceneEntity, SceneHdrSkybox, capture_scene_settings,
entity_to_scene_entity_with_uuids,
};
use nightshade::ecs::world::LOCAL_TRANSFORM;
use nightshade::prelude::{Entity, World};
use std::collections::HashSet;
#[derive(Default)]
pub struct WritebackState {
pub last_world_entity_count: usize,
pub needs_full_resync: bool,
}
impl WritebackState {
pub fn mark_full_resync(&mut self) {
self.needs_full_resync = true;
}
}
pub fn sync_entity(
project: &mut ProjectState,
editor_scene: &EditorScene,
world: &World,
entity: Entity,
) {
let Some(uuid) = editor_scene.uuid_for(entity) else {
return;
};
let parent_uuid = parent_uuid_for(world, editor_scene, entity);
let mut scene_entity = entity_to_scene_entity_with_uuids(
world,
entity,
uuid,
parent_uuid,
&editor_scene.entity_to_uuid,
);
scene_entity.layer = editor_scene.entity_layer(entity);
scene_entity.chunk_id = editor_scene.entity_chunk(entity);
write_scene_entity(project, scene_entity);
}
pub fn sync_all_known_entities(
project: &mut ProjectState,
editor_scene: &EditorScene,
world: &World,
) {
let entities: Vec<Entity> = editor_scene.known_entities().collect();
for entity in entities {
sync_entity(project, editor_scene, world, entity);
}
}
pub fn add_entity(
project: &mut ProjectState,
editor_scene: &mut EditorScene,
world: &World,
entity: Entity,
) {
if editor_scene.is_scaffolding(entity) {
return;
}
if editor_scene.uuid_for(entity).is_some() {
sync_entity(project, editor_scene, world, entity);
return;
}
let parent_uuid = parent_uuid_for(world, editor_scene, entity);
let uuid = AssetUuid::random();
editor_scene.insert(uuid, entity);
let mut scene_entity = entity_to_scene_entity_with_uuids(
world,
entity,
uuid,
parent_uuid,
&editor_scene.entity_to_uuid,
);
scene_entity.layer = editor_scene.entity_layer(entity);
scene_entity.chunk_id = editor_scene.entity_chunk(entity);
write_scene_entity(project, scene_entity);
}
pub fn register_subtree(
project: &mut ProjectState,
editor_scene: &mut EditorScene,
world: &World,
root: Entity,
) {
let mut entities = vec![root];
entities.extend(nightshade::ecs::transform::queries::query_descendants(
world, root,
));
for entity in &entities {
if editor_scene.is_scaffolding(*entity) {
continue;
}
if editor_scene.uuid_for(*entity).is_none() {
let uuid = AssetUuid::random();
editor_scene.insert(uuid, *entity);
}
}
for entity in &entities {
if editor_scene.is_scaffolding(*entity) {
continue;
}
sync_entity(project, editor_scene, world, *entity);
}
}
pub fn remove_entity(project: &mut ProjectState, editor_scene: &mut EditorScene, entity: Entity) {
let Some(uuid) = editor_scene.remove_entity(entity) else {
return;
};
project.scene.remove_entity(uuid);
project.mark_modified();
}
pub fn reconcile(
project: &mut ProjectState,
editor_scene: &mut EditorScene,
writeback_state: &mut WritebackState,
world: &mut World,
force: bool,
) {
if !force {
let count = world_entity_count(world);
if count == writeback_state.last_world_entity_count {
return;
}
writeback_state.last_world_entity_count = count;
}
let mut world_entities: HashSet<Entity> = HashSet::new();
world
.core
.query()
.with(LOCAL_TRANSFORM)
.iter(|entity, _, _| {
if !editor_scene.is_scaffolding(entity) {
world_entities.insert(entity);
}
});
let known: HashSet<Entity> = editor_scene.known_entities().collect();
for entity in &known {
if !world_entities.contains(entity) {
remove_entity(project, editor_scene, *entity);
}
}
for entity in &world_entities {
if !known.contains(entity) {
add_entity(project, editor_scene, world, *entity);
}
}
if force {
sync_all_known_entities(project, editor_scene, world);
}
writeback_state.last_world_entity_count = world_entity_count(world);
}
pub fn sync_settings(project: &mut ProjectState, world: &World) {
project.scene.atmosphere = world.resources.graphics.atmosphere;
project.scene.settings = capture_scene_settings(world);
}
pub fn sync_hdr_skybox(project: &mut ProjectState, hdr: Option<SceneHdrSkybox>) {
project.scene.hdr_skybox = hdr;
project.mark_modified();
}
fn world_entity_count(world: &World) -> usize {
world.core.get_all_entities().len()
}
fn parent_uuid_for(world: &World, scene: &EditorScene, entity: Entity) -> Option<AssetUuid> {
world
.core
.get_parent(entity)
.and_then(|parent| parent.0)
.and_then(|parent_entity| scene.uuid_for(parent_entity))
}
fn write_scene_entity(project: &mut ProjectState, scene_entity: SceneEntity) {
let scene = &mut project.scene;
let uuid = scene_entity.uuid;
if let Some(existing) = scene.find_entity_mut(uuid) {
*existing = scene_entity;
} else {
scene.add_entity(scene_entity);
}
project.mark_modified();
}