1mod indexing;
2#[cfg(test)]
3mod tests;
4
5use crate::component::{ComponentStorage, ComponentTrait};
6use soroban_sdk::{contracttype, Bytes, Env, Map, Symbol, Vec};
7
8pub type EntityId = u32;
10
11#[contracttype]
45#[derive(Clone, Debug)]
46pub struct SimpleWorld {
47 pub(crate) next_entity_id: u32,
48 pub(crate) components: Map<(u32, Symbol), Bytes>,
50 pub(crate) sparse_components: Map<(u32, Symbol), Bytes>,
52 pub(crate) entity_components: Map<u32, Vec<Symbol>>,
54 pub(crate) table_index: Map<Symbol, Vec<u32>>,
56 pub(crate) all_index: Map<Symbol, Vec<u32>>,
58 pub(crate) version: u64,
61}
62
63impl SimpleWorld {
64 pub fn new(env: &Env) -> Self {
65 Self {
66 next_entity_id: 1,
67 components: Map::new(env),
68 sparse_components: Map::new(env),
69 entity_components: Map::new(env),
70 table_index: Map::new(env),
71 all_index: Map::new(env),
72 version: 0,
73 }
74 }
75
76 pub fn version(&self) -> u64 {
78 self.version
79 }
80
81 pub fn next_entity_id(&self) -> EntityId {
83 self.next_entity_id
84 }
85
86 pub fn env(&self) -> &Env {
88 self.components.env()
89 }
90
91 pub fn spawn_entity(&mut self) -> EntityId {
92 let id = self.next_entity_id;
93 self.next_entity_id += 1;
94 id
95 }
96
97 fn has_component_in_table(&self, entity_id: EntityId, component_type: &Symbol) -> bool {
98 self.components
99 .contains_key((entity_id, component_type.clone()))
100 }
101
102 fn has_component_in_sparse(&self, entity_id: EntityId, component_type: &Symbol) -> bool {
103 self.sparse_components
104 .contains_key((entity_id, component_type.clone()))
105 }
106
107 pub fn add_component(&mut self, entity_id: EntityId, component_type: Symbol, data: Bytes) {
109 self.add_component_with_storage(entity_id, component_type, data, ComponentStorage::Table);
110 }
111
112 pub fn add_component_with_storage(
114 &mut self,
115 entity_id: EntityId,
116 component_type: Symbol,
117 data: Bytes,
118 storage: ComponentStorage,
119 ) {
120 self.version += 1;
121 let was_in_table = self.has_component_in_table(entity_id, &component_type);
122 let was_in_sparse = self.has_component_in_sparse(entity_id, &component_type);
123
124 match storage {
125 ComponentStorage::Table => {
126 self.components
127 .set((entity_id, component_type.clone()), data);
128 if was_in_sparse {
129 self.sparse_components
130 .remove((entity_id, component_type.clone()));
131 }
132 }
133 ComponentStorage::Sparse => {
134 self.sparse_components
135 .set((entity_id, component_type.clone()), data);
136 if was_in_table {
137 self.components.remove((entity_id, component_type.clone()));
138 }
139 }
140 }
141
142 let mut types = self
143 .entity_components
144 .get(entity_id)
145 .unwrap_or_else(|| Vec::new(self.components.env()));
146
147 let mut found = false;
148 for i in 0..types.len() {
149 if let Some(t) = types.get(i) {
150 if t == component_type {
151 found = true;
152 break;
153 }
154 }
155 }
156 if !found {
157 types.push_back(component_type.clone());
158 }
159 self.entity_components.set(entity_id, types);
160
161 indexing::push_index(&mut self.all_index, &component_type, entity_id);
162 match storage {
163 ComponentStorage::Table => {
164 indexing::push_index(&mut self.table_index, &component_type, entity_id);
165 }
166 ComponentStorage::Sparse => {
167 indexing::remove_from_index(&mut self.table_index, &component_type, entity_id);
168 }
169 }
170 }
171
172 pub fn get_component(&self, entity_id: EntityId, component_type: &Symbol) -> Option<Bytes> {
174 self.components
175 .get((entity_id, component_type.clone()))
176 .or_else(|| {
177 self.sparse_components
178 .get((entity_id, component_type.clone()))
179 })
180 }
181
182 pub fn remove_component(&mut self, entity_id: EntityId, component_type: &Symbol) -> bool {
184 self.version += 1;
185 let removed = self
186 .components
187 .remove((entity_id, component_type.clone()))
188 .or_else(|| {
189 self.sparse_components
190 .remove((entity_id, component_type.clone()))
191 });
192
193 if removed.is_some() {
194 if let Some(types) = self.entity_components.get(entity_id) {
195 let env = self.components.env();
196 let mut new_types = Vec::new(env);
197 for i in 0..types.len() {
198 if let Some(t) = types.get(i) {
199 if &t != component_type {
200 new_types.push_back(t);
201 }
202 }
203 }
204 if new_types.is_empty() {
205 self.entity_components.remove(entity_id);
206 } else {
207 self.entity_components.set(entity_id, new_types);
208 }
209 }
210 indexing::remove_from_index(&mut self.all_index, component_type, entity_id);
211 indexing::remove_from_index(&mut self.table_index, component_type, entity_id);
212 true
213 } else {
214 false
215 }
216 }
217
218 pub fn has_component(&self, entity_id: EntityId, component_type: &Symbol) -> bool {
220 self.has_component_in_table(entity_id, component_type)
221 || self.has_component_in_sparse(entity_id, component_type)
222 }
223
224 pub fn get_entities_with_component(&self, component_type: &Symbol, env: &Env) -> Vec<EntityId> {
225 self.table_index
226 .get(component_type.clone())
227 .unwrap_or_else(|| Vec::new(env))
228 }
229
230 pub fn get_table_entities_with_component(
233 &self,
234 component_type: &Symbol,
235 env: &Env,
236 ) -> Vec<EntityId> {
237 self.table_index
238 .get(component_type.clone())
239 .unwrap_or_else(|| Vec::new(env))
240 }
241
242 pub fn get_all_entities_with_component(
244 &self,
245 component_type: &Symbol,
246 env: &Env,
247 ) -> Vec<EntityId> {
248 self.all_index
249 .get(component_type.clone())
250 .unwrap_or_else(|| Vec::new(env))
251 }
252
253 pub fn table_component_count(&self, component_type: &Symbol) -> usize {
255 self.table_index
256 .get(component_type.clone())
257 .map(|entities| entities.len())
258 .unwrap_or(0)
259 .try_into()
260 .unwrap()
261 }
262
263 pub fn component_count(&self, component_type: &Symbol) -> usize {
265 self.all_index
266 .get(component_type.clone())
267 .map(|entities| entities.len())
268 .unwrap_or(0)
269 .try_into()
270 .unwrap()
271 }
272
273 pub fn get_typed<T: ComponentTrait>(&self, env: &Env, entity_id: EntityId) -> Option<T> {
289 let bytes = self.get_component(entity_id, &T::component_type())?;
290 T::deserialize(env, &bytes)
291 }
292
293 pub fn set_typed<T: ComponentTrait>(&mut self, env: &Env, entity_id: EntityId, component: &T) {
308 let symbol = T::component_type();
309 let data = component.serialize(env);
310 let storage = T::default_storage();
311 self.add_component_with_storage(entity_id, symbol, data, storage);
312 }
313
314 pub fn has_typed<T: ComponentTrait>(&self, entity_id: EntityId) -> bool {
316 self.has_component(entity_id, &T::component_type())
317 }
318
319 pub fn remove_typed<T: ComponentTrait>(&mut self, entity_id: EntityId) -> bool {
321 self.remove_component(entity_id, &T::component_type())
322 }
323
324 pub fn despawn_entity(&mut self, entity_id: EntityId) {
325 self.version += 1;
326 if let Some(types) = self.entity_components.get(entity_id) {
327 for i in 0..types.len() {
328 if let Some(t) = types.get(i) {
329 self.components.remove((entity_id, t.clone()));
330 self.sparse_components.remove((entity_id, t.clone()));
331 indexing::remove_from_index(&mut self.all_index, &t, entity_id);
332 indexing::remove_from_index(&mut self.table_index, &t, entity_id);
333 }
334 }
335 }
336 self.entity_components.remove(entity_id);
337 }
338}