nightshade_api/
hierarchy.rs1use nightshade::ecs::transform::queries::query_descendants;
7use nightshade::ecs::world::{GLOBAL_TRANSFORM, LOCAL_TRANSFORM};
8use nightshade::prelude::*;
9use serde::{Deserialize, Serialize};
10use std::collections::{HashMap, HashSet};
11
12pub fn name(world: &World, entity: Entity) -> String {
14 world
15 .get::<nightshade::ecs::primitives::Name>(entity)
16 .map(|name| name.0.clone())
17 .filter(|name| !name.is_empty())
18 .unwrap_or_else(|| format!("Entity {}", entity.id))
19}
20
21pub fn set_name(world: &mut World, entity: Entity, name: &str) {
23 world.set(entity, Name(name.to_string()));
24}
25
26pub fn children(world: &World, entity: Entity) -> Vec<Entity> {
28 let mut found: Vec<Entity> = Vec::new();
29 for candidate in world.ecs.worlds[CORE].query_entities(LOCAL_TRANSFORM) {
30 if world
31 .get::<freecs::dynamic::ChildOf>(candidate)
32 .map(|child_of| child_of.0)
33 == Some(entity)
34 {
35 found.push(candidate);
36 }
37 }
38 found.sort_by_key(|entity| entity.id);
39 found
40}
41
42pub fn descendants(world: &World, entity: Entity) -> Vec<Entity> {
44 query_descendants(world, entity)
45}
46
47pub fn roots(world: &World) -> Vec<Entity> {
49 let mut found: Vec<Entity> = Vec::new();
50 for entity in world.ecs.worlds[CORE].query_entities(LOCAL_TRANSFORM | GLOBAL_TRANSFORM) {
51 if world
52 .get::<freecs::dynamic::ChildOf>(entity)
53 .map(|child_of| child_of.0)
54 .is_none()
55 {
56 found.push(entity);
57 }
58 }
59 found.sort_by_key(|entity| entity.id);
60 found
61}
62
63#[derive(Clone, PartialEq, Serialize, Deserialize)]
65pub struct SceneRow {
66 pub id: u32,
67 pub name: String,
68 pub depth: u32,
69 pub has_children: bool,
70 pub camera: bool,
71 pub light: bool,
72 pub mesh: bool,
73}
74
75pub fn scene_tree(world: &World) -> Vec<SceneRow> {
78 let all: HashSet<Entity> = world.ecs.worlds[CORE]
79 .query_entities(LOCAL_TRANSFORM | GLOBAL_TRANSFORM)
80 .collect();
81
82 let mut children_map: HashMap<Entity, Vec<Entity>> = HashMap::new();
83 let mut root_entities: Vec<Entity> = Vec::new();
84 for &entity in &all {
85 let parent = world
86 .get::<freecs::dynamic::ChildOf>(entity)
87 .map(|child_of| child_of.0)
88 .filter(|parent| all.contains(parent));
89 match parent {
90 Some(parent) => children_map.entry(parent).or_default().push(entity),
91 None => root_entities.push(entity),
92 }
93 }
94 root_entities.sort_by_key(|entity| entity.id);
95 for list in children_map.values_mut() {
96 list.sort_by_key(|entity| entity.id);
97 }
98
99 let mut rows = Vec::new();
100 let mut visited: HashSet<Entity> = HashSet::new();
101 let mut stack: Vec<(Entity, u32)> = root_entities
102 .iter()
103 .rev()
104 .map(|entity| (*entity, 0))
105 .collect();
106 while let Some((entity, depth)) = stack.pop() {
107 if !visited.insert(entity) {
108 continue;
109 }
110 let has_children = children_map
111 .get(&entity)
112 .is_some_and(|list| !list.is_empty());
113 rows.push(SceneRow {
114 id: entity.id,
115 name: name(world, entity),
116 depth,
117 has_children,
118 camera: world.has::<nightshade::ecs::camera::components::Camera>(entity),
119 light: world.has::<nightshade::ecs::light::components::Light>(entity),
120 mesh: world.has::<nightshade::ecs::mesh::components::RenderMesh>(entity),
121 });
122 if let Some(list) = children_map.get(&entity) {
123 for child in list.iter().rev() {
124 if !visited.contains(child) {
125 stack.push((*child, depth + 1));
126 }
127 }
128 }
129 }
130 rows
131}