specs/world/mod.rs
1//! Entities, resources, components, and general world management.
2
3pub use shred::World;
4
5pub use self::{
6 comp::Component,
7 entity::{
8 CreateIterAtomic, Entities, EntitiesRes, Entity, EntityResBuilder, Generation, Index,
9 },
10 lazy::{LazyBuilder, LazyUpdate},
11 world_ext::WorldExt,
12};
13
14use shred::{FetchMut, SystemData};
15
16use crate::storage::WriteStorage;
17
18mod comp;
19mod entity;
20mod lazy;
21#[cfg(test)]
22mod tests;
23mod world_ext;
24
25/// An iterator for entity creation.
26/// Please note that you have to consume
27/// it because iterators are lazy.
28///
29/// Returned from `World::create_iter`.
30pub struct CreateIter<'a>(FetchMut<'a, EntitiesRes>);
31
32impl<'a> Iterator for CreateIter<'a> {
33 type Item = Entity;
34
35 fn next(&mut self) -> Option<Entity> {
36 Some(self.0.alloc.allocate())
37 }
38}
39
40/// A common trait for `EntityBuilder` and `LazyBuilder`, allowing either to be
41/// used. Entity is definitely alive, but the components may or may not exist
42/// before a call to `World::maintain`.
43pub trait Builder {
44 /// Appends a component and associates it with the entity.
45 ///
46 /// If a component was already associated with the entity, it should
47 /// overwrite the previous component.
48 ///
49 /// # Panics
50 ///
51 /// Panics if the component hasn't been `register()`ed in the
52 /// `World`.
53 #[cfg(feature = "parallel")]
54 fn with<C: Component + Send + Sync>(self, c: C) -> Self;
55
56 /// Appends a component and associates it with the entity.
57 ///
58 /// If a component was already associated with the entity, it should
59 /// overwrite the previous component.
60 ///
61 /// # Panics
62 ///
63 /// Panics if the component hasn't been `register()`ed in the
64 /// `World`.
65 #[cfg(not(feature = "parallel"))]
66 fn with<C: Component>(self, c: C) -> Self;
67
68 /// Convenience method that calls `self.with(component)` if
69 /// `Some(component)` is provided
70 ///
71 /// # Panics
72 ///
73 /// Panics if the component hasn't been `register()`ed in the
74 /// `World`.
75 #[cfg(feature = "parallel")]
76 fn maybe_with<C: Component + Send + Sync>(self, c: Option<C>) -> Self
77 where
78 Self: Sized,
79 {
80 match c {
81 Some(c) => self.with(c),
82 None => self,
83 }
84 }
85
86 /// Convenience method that calls `self.with(component)` if
87 /// `Some(component)` is provided
88 ///
89 /// # Panics
90 ///
91 /// Panics if the component hasn't been `register()`ed in the
92 /// `World`.
93 #[cfg(not(feature = "parallel"))]
94 fn maybe_with<C: Component>(self, c: Option<C>) -> Self
95 where
96 Self: Sized,
97 {
98 match c {
99 Some(c) => self.with(c),
100 None => self,
101 }
102 }
103
104 /// Finishes the building and returns the entity.
105 fn build(self) -> Entity;
106}
107
108/// The entity builder, allowing to
109/// build an entity together with its components.
110///
111/// ## Examples
112///
113/// ```
114/// use specs::{prelude::*, storage::HashMapStorage};
115///
116/// struct Health(f32);
117///
118/// impl Component for Health {
119/// type Storage = HashMapStorage<Self>;
120/// }
121///
122/// struct Pos {
123/// x: f32,
124/// y: f32,
125/// }
126///
127/// impl Component for Pos {
128/// type Storage = DenseVecStorage<Self>;
129/// }
130///
131/// let mut world = World::new();
132/// world.register::<Health>();
133/// world.register::<Pos>();
134///
135/// let entity = world
136/// .create_entity() // This call returns `EntityBuilder`
137/// .with(Health(4.0))
138/// .with(Pos { x: 1.0, y: 3.0 })
139/// .build(); // Returns the `Entity`
140/// ```
141///
142/// ### Distinguishing Mandatory Components from Optional Components
143///
144/// ```
145/// use specs::{prelude::*, storage::HashMapStorage};
146///
147/// struct MandatoryHealth(f32);
148///
149/// impl Component for MandatoryHealth {
150/// type Storage = HashMapStorage<Self>;
151/// }
152///
153/// struct OptionalPos {
154/// x: f32,
155/// y: f32,
156/// }
157///
158/// impl Component for OptionalPos {
159/// type Storage = DenseVecStorage<Self>;
160/// }
161///
162/// let mut world = World::new();
163/// world.register::<MandatoryHealth>();
164/// world.register::<OptionalPos>();
165///
166/// let mut entitybuilder = world.create_entity().with(MandatoryHealth(4.0));
167///
168/// // something trivial to serve as our conditional
169/// let include_optional = true;
170///
171/// if include_optional == true {
172/// entitybuilder = entitybuilder.with(OptionalPos { x: 1.0, y: 3.0 })
173/// }
174///
175/// let entity = entitybuilder.build();
176/// ```
177#[must_use = "Please call .build() on this to finish building it."]
178pub struct EntityBuilder<'a> {
179 /// The (already created) entity for which components will be inserted.
180 pub entity: Entity,
181 /// A reference to the `World` for component insertions.
182 pub world: &'a World,
183 built: bool,
184}
185
186impl<'a> Builder for EntityBuilder<'a> {
187 /// Inserts a component for this entity.
188 ///
189 /// If a component was already associated with the entity, it will
190 /// overwrite the previous component.
191 #[inline]
192 fn with<T: Component>(self, c: T) -> Self {
193 {
194 let mut storage: WriteStorage<T> = SystemData::fetch(self.world);
195 // This can't fail. This is guaranteed by the lifetime 'a
196 // in the EntityBuilder.
197 storage.insert(self.entity, c).unwrap();
198 }
199
200 self
201 }
202
203 /// Finishes the building and returns the entity. As opposed to
204 /// `LazyBuilder`, the components are available immediately.
205 #[inline]
206 fn build(mut self) -> Entity {
207 self.built = true;
208 self.entity
209 }
210}
211
212impl<'a> Drop for EntityBuilder<'a> {
213 fn drop(&mut self) {
214 if !self.built {
215 self.world
216 .read_resource::<EntitiesRes>()
217 .delete(self.entity)
218 .unwrap();
219 }
220 }
221}