1use crate::{
2 app::{AppBuilder, AppLifeCycle},
3 assets::{asset::AssetId, database::AssetsDatabase, protocols::prefab::PrefabAsset},
4 ecs::{
5 components::{Name, NonPersistent, NonPersistentPrefabProxy, Tag},
6 hierarchy::{Parent, ParentPrefabProxy},
7 life_cycle::EntityChanges,
8 pipeline::{PipelineBuilder, PipelineBuilderError},
9 Universe,
10 },
11 state::StateToken,
12};
13use hecs::*;
14use serde::{de::DeserializeOwned, Deserialize, Serialize};
15use std::collections::HashMap;
16
17pub use serde_json::Value as PrefabValue;
18
19type ComponentFactory = Box<
20 dyn Fn(
21 &mut EntityBuilder,
22 &PrefabValue,
23 &HashMap<String, Entity>,
24 StateToken,
25 ) -> Result<(), PrefabError>
26 + Send
27 + Sync,
28>;
29
30#[derive(Debug)]
31pub enum PrefabError {
32 CouldNotSerialize(String),
33 CouldNotDeserialize(String),
34 Custom(String),
35}
36
37pub trait Prefab: Serialize + DeserializeOwned + Sized {
38 fn from_prefab(data: &PrefabValue) -> Result<Self, PrefabError> {
39 match serde_json::from_value(data.clone()) {
40 Ok(result) => {
41 let mut result: Self = result;
42 result.post_from_prefab();
43 Ok(result)
44 }
45 Err(error) => Err(PrefabError::CouldNotDeserialize(error.to_string())),
46 }
47 }
48
49 fn from_prefab_with_extras(
50 data: &PrefabValue,
51 _named_entities: &HashMap<String, Entity>,
52 _state_token: StateToken,
53 ) -> Result<Self, PrefabError> {
54 Self::from_prefab(data)
55 }
56
57 fn to_prefab(&self) -> Result<PrefabValue, PrefabError> {
58 match serde_json::to_value(self) {
59 Ok(result) => Ok(result),
60 Err(error) => Err(PrefabError::CouldNotDeserialize(error.to_string())),
61 }
62 }
63
64 fn from_prefab_str(data: &str) -> Result<Self, PrefabError> {
65 match serde_json::from_str(data) {
66 Ok(result) => {
67 let mut result: Self = result;
68 result.post_from_prefab();
69 Ok(result)
70 }
71 Err(error) => Err(PrefabError::CouldNotDeserialize(error.to_string())),
72 }
73 }
74
75 fn to_prefab_string(&self) -> Result<String, PrefabError> {
76 match serde_json::to_string_pretty(self) {
77 Ok(result) => Ok(result),
78 Err(error) => Err(PrefabError::CouldNotSerialize(error.to_string())),
79 }
80 }
81
82 fn post_from_prefab(&mut self) {}
83}
84
85pub trait PrefabProxy<P>: Component + Sized
86where
87 P: Prefab,
88{
89 fn from_proxy_with_extras(
90 proxy: P,
91 named_entities: &HashMap<String, Entity>,
92 state_token: StateToken,
93 ) -> Result<Self, PrefabError>;
94}
95
96impl Prefab for PrefabValue {}
97pub trait PrefabComponent: Prefab + Component {}
98
99#[derive(Debug, Default, Clone, Serialize, Deserialize)]
100pub struct PrefabScene {
101 #[serde(default)]
102 pub template_name: Option<String>,
103 #[serde(default)]
104 pub dependencies: Vec<String>,
105 #[serde(default)]
106 pub entities: Vec<PrefabSceneEntity>,
107}
108
109#[derive(Debug, Clone, Serialize, Deserialize)]
110pub enum PrefabSceneEntity {
111 Data(PrefabSceneEntityData),
112 Template(String),
113}
114
115impl Default for PrefabSceneEntity {
116 fn default() -> Self {
117 Self::Data(Default::default())
118 }
119}
120
121impl Prefab for PrefabScene {}
122impl Prefab for PrefabSceneEntity {}
123
124#[derive(Debug, Default, Clone, Serialize, Deserialize)]
125pub struct PrefabSceneEntityData {
126 #[serde(default)]
127 pub uid: Option<String>,
128 #[serde(default)]
129 pub components: HashMap<String, PrefabValue>,
130}
131
132impl Prefab for PrefabSceneEntityData {}
133
134#[derive(Default)]
135pub struct PrefabManager {
136 component_factory: HashMap<String, ComponentFactory>,
137 templates: HashMap<String, PrefabScene>,
138}
139
140impl PrefabManager {
141 pub fn register_component_factory<T>(&mut self, name: &str)
142 where
143 T: PrefabComponent,
144 {
145 self.component_factory.insert(
146 name.to_owned(),
147 Box::new(|builder, prefab, named_entities, state_token| {
148 builder.add(T::from_prefab_with_extras(
149 prefab,
150 named_entities,
151 state_token,
152 )?);
153 Ok(())
154 }),
155 );
156 }
157
158 pub fn register_component_factory_proxy<T, P>(&mut self, name: &str)
159 where
160 P: Prefab,
161 T: PrefabProxy<P>,
162 {
163 self.component_factory.insert(
164 name.to_owned(),
165 Box::new(|builder, prefab, named_entities, state_token| {
166 let p = P::from_prefab(prefab)?;
167 builder.add(T::from_proxy_with_extras(p, named_entities, state_token)?);
168 Ok(())
169 }),
170 );
171 }
172
173 pub fn unregister_component_factory(&mut self, name: &str) {
174 self.component_factory.remove(name);
175 }
176
177 pub fn register_scene_template(&mut self, prefab: PrefabScene) -> Result<(), PrefabError> {
178 if let Some(name) = &prefab.template_name {
179 if self.templates.contains_key(name) {
180 Err(PrefabError::Custom(format!(
181 "There is already registered template: {}",
182 name
183 )))
184 } else {
185 self.templates.insert(name.to_owned(), prefab);
186 Ok(())
187 }
188 } else {
189 Err(PrefabError::Custom(
190 "Template prefabs must have set template name".to_owned(),
191 ))
192 }
193 }
194
195 pub fn unregister_scene_template(&mut self, name: &str) {
196 self.templates.remove(name);
197 }
198
199 pub fn find_template(&self, name: &str) -> Option<&PrefabScene> {
200 self.templates.get(name)
201 }
202
203 pub fn instantiate(
204 &mut self,
205 name: &str,
206 universe: &mut Universe,
207 ) -> Result<Vec<Entity>, PrefabError> {
208 let state_token = universe
209 .expect_resource::<AppLifeCycle>()
210 .current_state_token();
211 let mut world = universe.world_mut();
212 let mut changes = universe.expect_resource_mut::<EntityChanges>();
213 self.instantiate_direct(name, &mut world, &mut changes, state_token)
214 }
215
216 pub fn instantiate_direct(
217 &mut self,
218 name: &str,
219 world: &mut World,
220 changes: &mut EntityChanges,
221 state_token: StateToken,
222 ) -> Result<Vec<Entity>, PrefabError> {
223 Ok(self
224 .build_template(name, world, changes, state_token, &Default::default())?
225 .0)
226 }
227
228 pub fn load_scene_from_prefab(
229 &mut self,
230 prefab: &PrefabScene,
231 universe: &mut Universe,
232 ) -> Result<Vec<Entity>, PrefabError> {
233 let state_token = universe
234 .expect_resource::<AppLifeCycle>()
235 .current_state_token();
236 self.load_scene_from_prefab_direct(
237 prefab,
238 &mut universe.world_mut(),
239 &mut universe.expect_resource_mut::<EntityChanges>(),
240 state_token,
241 )
242 }
243
244 pub fn load_scene_from_prefab_direct(
245 &mut self,
246 prefab: &PrefabScene,
247 world: &mut World,
248 changes: &mut EntityChanges,
249 state_token: StateToken,
250 ) -> Result<Vec<Entity>, PrefabError> {
251 Ok(self
252 .load_scene_from_prefab_inner(prefab, world, changes, state_token, &Default::default())?
253 .0)
254 }
255
256 fn load_scene_from_prefab_inner(
257 &mut self,
258 prefab: &PrefabScene,
259 world: &mut World,
260 changes: &mut EntityChanges,
261 state_token: StateToken,
262 named_entities: &HashMap<String, Entity>,
263 ) -> Result<(Vec<Entity>, HashMap<String, Entity>), PrefabError> {
264 let mut named_entities = named_entities.clone();
265 let mut result_entities = vec![];
266 for entity_meta in &prefab.entities {
267 match entity_meta {
268 PrefabSceneEntity::Data(data) => {
269 let entity = self.build_entity(
270 &data.components,
271 world,
272 changes,
273 state_token,
274 &named_entities,
275 )?;
276 if let Some(uid) = &data.uid {
277 named_entities.insert(uid.to_owned(), entity);
278 }
279 result_entities.push(entity);
280 }
281 PrefabSceneEntity::Template(name) => {
282 let (entities, uids) =
283 self.build_template(name, world, changes, state_token, &named_entities)?;
284 for (uid, entity) in uids {
285 named_entities.insert(uid.to_owned(), entity);
286 }
287 result_entities.extend(entities);
288 }
289 }
290 }
291 Ok((result_entities, named_entities))
292 }
293
294 fn build_entity(
295 &mut self,
296 components: &HashMap<String, PrefabValue>,
297 world: &mut World,
298 changes: &mut EntityChanges,
299 state_token: StateToken,
300 named_entities: &HashMap<String, Entity>,
301 ) -> Result<Entity, PrefabError> {
302 let mut entity_builder = EntityBuilder::new();
303 for (key, component_meta) in components {
304 if let Some(factory) = self.component_factory.get_mut(key) {
305 factory(
306 &mut entity_builder,
307 component_meta,
308 named_entities,
309 state_token,
310 )?;
311 } else {
312 return Err(PrefabError::CouldNotDeserialize(format!(
313 "Could not find component factory: {}",
314 key
315 )));
316 }
317 }
318 let entity = world.reserve_entity();
319 let components = entity_builder.build();
320 world.spawn_at(entity, components);
321 changes.spawned.insert(entity);
322 let components = changes.added_components.entry(entity).or_default();
323 components.extend(entity_builder.component_types());
324 Ok(entity)
325 }
326
327 fn build_template(
328 &mut self,
329 name: &str,
330 world: &mut World,
331 changes: &mut EntityChanges,
332 state_token: StateToken,
333 named_entities: &HashMap<String, Entity>,
334 ) -> Result<(Vec<Entity>, HashMap<String, Entity>), PrefabError> {
335 if let Some(prefab) = self.templates.get(name).cloned() {
336 self.load_scene_from_prefab_inner(&prefab, world, changes, state_token, named_entities)
337 } else {
338 Err(PrefabError::Custom(format!(
339 "There is no template registered: {}",
340 name
341 )))
342 }
343 }
344}
345
346#[derive(Default)]
347pub struct PrefabSystemCache {
348 templates_table: HashMap<AssetId, String>,
349}
350pub type PrefabSystemResources<'a> = (
351 &'a AssetsDatabase,
352 &'a mut PrefabManager,
353 &'a mut PrefabSystemCache,
354);
355
356pub fn prefab_system(universe: &mut Universe) {
357 let (assets, mut prefabs, mut cache) = universe.query_resources::<PrefabSystemResources>();
358
359 for id in assets.lately_loaded_protocol("prefab") {
360 let id = *id;
361 let asset = assets
362 .asset_by_id(id)
363 .expect("trying to use not loaded prefab asset");
364 let asset = asset
365 .get::<PrefabAsset>()
366 .expect("trying to use non-prefab asset");
367 if let Some(name) = &asset.get().template_name {
368 if prefabs.register_scene_template(asset.get().clone()).is_ok() {
369 cache.templates_table.insert(id, name.to_owned());
370 }
371 }
372 }
373 for id in assets.lately_unloaded_protocol("prefab") {
374 if let Some(name) = cache.templates_table.remove(id) {
375 prefabs.unregister_scene_template(&name);
376 }
377 }
378}
379
380pub fn bundle_installer<PB, PMS>(
381 builder: &mut AppBuilder<PB>,
382 mut prefab_manager_setup: PMS,
383) -> Result<(), PipelineBuilderError>
384where
385 PB: PipelineBuilder,
386 PMS: FnMut(&mut PrefabManager),
387{
388 let mut manager = PrefabManager::default();
389 manager.register_component_factory_proxy::<Parent, ParentPrefabProxy>("Parent");
390 manager.register_component_factory::<Tag>("Tag");
391 manager.register_component_factory::<Name>("Name");
392 manager.register_component_factory_proxy::<NonPersistent, NonPersistentPrefabProxy>(
393 "NonPersistent",
394 );
395 prefab_manager_setup(&mut manager);
396 builder.install_resource(manager);
397 builder.install_resource(PrefabSystemCache::default());
398 builder.install_system::<PrefabSystemResources>("prefab", prefab_system, &[])?;
399 Ok(())
400}