1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package com.lhkbob.entreri.impl;
28
29 import com.lhkbob.entreri.Component;
30 import com.lhkbob.entreri.ComponentIterator;
31 import com.lhkbob.entreri.Entity;
32 import com.lhkbob.entreri.EntitySystem;
33 import com.lhkbob.entreri.property.Property;
34 import com.lhkbob.entreri.property.PropertyFactory;
35 import com.lhkbob.entreri.task.Scheduler;
36
37 import java.util.*;
38
39
40
41
42
43
44 public final class EntitySystemImpl implements EntitySystem {
45
46 private final Map<Class<? extends Component>, Integer> typeIndexMap;
47 private int typeIdSeq;
48
49 private ComponentRepository<?>[] componentRepositories;
50
51 private EntityImpl[] entities;
52
53 private int entityInsert;
54 private int entityIdSeq;
55
56 private final Scheduler manager;
57
58
59
60
61 public EntitySystemImpl() {
62 typeIndexMap = new HashMap<>();
63 typeIdSeq = 0;
64
65 manager = new Scheduler(this);
66 entities = new EntityImpl[1];
67 componentRepositories = new ComponentRepository[0];
68
69 entityIdSeq = 1;
70 entityInsert = 1;
71 }
72
73 @Override
74 @SuppressWarnings({ "rawtypes", "unchecked" })
75 public <T extends Component> Collection<Class<? extends T>> getComponentTypes(
76 Class<T> type) {
77 if (type == null) {
78 throw new NullPointerException("Type cannot be null");
79 }
80
81 List<Class<? extends T>> ids = new ArrayList<>();
82 for (int i = 0; i < componentRepositories.length; i++) {
83 if (componentRepositories[i] != null) {
84
85 if (type.isAssignableFrom(componentRepositories[i].getType())) {
86
87 ids.add((Class) componentRepositories[i].getType());
88 }
89 }
90 }
91 return ids;
92 }
93
94 @Override
95 public Collection<Class<? extends Component>> getComponentTypes() {
96 List<Class<? extends Component>> ids = new ArrayList<>();
97 for (int i = 0; i < componentRepositories.length; i++) {
98 if (componentRepositories[i] != null) {
99 ids.add(componentRepositories[i].getType());
100 }
101 }
102 return ids;
103 }
104
105 @Override
106 public Scheduler getScheduler() {
107 return manager;
108 }
109
110 @Override
111 public Iterator<Entity> iterator() {
112 return new EntityIterator();
113 }
114
115 @Override
116 public <T extends Component> Iterator<T> iterator(Class<T> type) {
117 return new ComponentIteratorWrapper<>(type);
118 }
119
120 @Override
121 public void compact() {
122
123 int startRemove = -1;
124 for (int i = 1; i < entityInsert; i++) {
125 if (entities[i] == null) {
126
127 if (startRemove < 0) {
128 startRemove = i;
129 }
130 } else {
131
132 if (startRemove >= 0) {
133
134 System.arraycopy(entities, i, entities, startRemove,
135 entityInsert - i);
136
137
138 entityInsert = entityInsert - i + startRemove;
139
140
141 i = startRemove;
142 startRemove = -1;
143 }
144 }
145 }
146
147 if (startRemove >= 0) {
148
149
150 entityInsert = startRemove;
151 }
152
153
154 int[] oldToNew = new int[entities.length];
155 for (int i = 1; i < entityInsert; i++) {
156 oldToNew[entities[i].index] = i;
157 entities[i].index = i;
158 }
159
160 if (entityInsert < .6f * entities.length) {
161
162 int newSize = (int) (1.2f * entityInsert) + 1;
163 entities = Arrays.copyOf(entities, newSize);
164 }
165
166
167 for (int i = 0; i < componentRepositories.length; i++) {
168 if (componentRepositories[i] != null) {
169 componentRepositories[i].compact(oldToNew, entityInsert);
170 }
171 }
172 }
173
174 @Override
175 public Entity addEntity() {
176 return addEntity(null);
177 }
178
179 @Override
180 public Entity addEntity(Entity template) {
181 if (template != null) {
182
183 if (!template.isAlive()) {
184 throw new IllegalStateException("Entity template is not live");
185 }
186 }
187
188 int entityIndex = entityInsert++;
189 if (entityIndex >= entities.length) {
190 entities = Arrays.copyOf(entities, (int) (entityIndex * 1.5f) + 1);
191 }
192
193 for (int i = 0; i < componentRepositories.length; i++) {
194 if (componentRepositories[i] != null) {
195 componentRepositories[i].expandEntityIndex(entityIndex + 1);
196 }
197 }
198
199 EntityImpl newEntity = new EntityImpl(this, entityIndex, entityIdSeq++);
200 entities[entityIndex] = newEntity;
201
202 if (template != null) {
203 for (Component c : template) {
204 addFromTemplate(entityIndex, c.getType(), c);
205 }
206 }
207
208 return newEntity;
209 }
210
211 @Override
212 public void removeEntity(Entity e) {
213 if (e == null) {
214 throw new NullPointerException("Cannot remove a null entity");
215 }
216 if (e.getEntitySystem() != this) {
217 throw new IllegalArgumentException("Entity is not from this EntitySystem");
218 }
219
220 EntityImpl ei = (EntityImpl) e;
221 if (ei.index == 0) {
222 throw new IllegalArgumentException("Entity has already been removed");
223 }
224
225
226 ei.setOwner(null);
227 ei.delegate.disownAndRemoveChildren();
228
229
230
231 for (int i = 0; i < componentRepositories.length; i++) {
232 if (componentRepositories[i] != null) {
233 componentRepositories[i].removeComponent(ei.index);
234 }
235 }
236
237
238 entities[ei.index] = null;
239 ei.index = 0;
240 }
241
242 @Override
243 public <T extends Component, P extends Property> P decorate(Class<T> type,
244 PropertyFactory<P> factory) {
245 ComponentRepository<?> index = getRepository(type);
246 return index.decorate(factory);
247 }
248
249 @Override
250 public ComponentIterator fastIterator() {
251 return new ComponentIteratorImpl(this);
252 }
253
254
255
256
257
258
259
260
261
262
263 @SuppressWarnings("unchecked")
264 <T extends Component> ComponentRepository<T> getRepository(Class<T> type) {
265 int index = getTypeIndex(type);
266 if (index >= componentRepositories.length) {
267
268 componentRepositories = Arrays.copyOf(componentRepositories, index + 1);
269 }
270
271 ComponentRepository<T> i = (ComponentRepository<T>) componentRepositories[index];
272 if (i == null) {
273
274 i = new ComponentRepository<>(this, type);
275 i.expandEntityIndex(entities.length);
276 componentRepositories[index] = i;
277 }
278
279 return i;
280 }
281
282 private int getTypeIndex(Class<? extends Component> type) {
283 Integer id = typeIndexMap.get(type);
284 if (id == null) {
285 id = typeIdSeq++;
286 typeIndexMap.put(type, id);
287 }
288 return id;
289 }
290
291
292
293
294 Iterator<ComponentRepository<?>> indexIterator() {
295 return new ComponentRepositoryIterator();
296 }
297
298
299
300
301
302
303
304
305
306 Entity getEntityByIndex(int entityIndex) {
307 return entities[entityIndex];
308 }
309
310 @SuppressWarnings({ "rawtypes", "unchecked" })
311 private <T extends Component> void addFromTemplate(int entityIndex, Class type, T c) {
312 ComponentRepository index = getRepository(type);
313 index.addComponent(entityIndex, c);
314 }
315
316 private class ComponentRepositoryIterator
317 implements Iterator<ComponentRepository<?>> {
318 private int index;
319 private boolean advanced;
320
321 public ComponentRepositoryIterator() {
322 index = -1;
323 advanced = false;
324 }
325
326 @Override
327 public boolean hasNext() {
328 if (!advanced) {
329 advance();
330 }
331 return index < componentRepositories.length;
332 }
333
334 @Override
335 public ComponentRepository<?> next() {
336 if (!hasNext()) {
337 throw new NoSuchElementException();
338 }
339 advanced = false;
340 return componentRepositories[index];
341 }
342
343 @Override
344 public void remove() {
345 throw new UnsupportedOperationException();
346 }
347
348 private void advance() {
349 do {
350 index++;
351 } while (index < componentRepositories.length &&
352 componentRepositories[index] == null);
353 advanced = true;
354 }
355 }
356
357 private class ComponentIteratorWrapper<T extends Component> implements Iterator<T> {
358 private final T data;
359 private final ComponentIterator it;
360
361 private boolean nextCalled;
362 private boolean hasNext;
363
364 public ComponentIteratorWrapper(Class<T> type) {
365 it = fastIterator();
366 data = it.addRequired(type);
367
368 nextCalled = false;
369 hasNext = false;
370 }
371
372 @Override
373 public boolean hasNext() {
374 if (!nextCalled) {
375 hasNext = it.next();
376 nextCalled = true;
377 }
378 return hasNext;
379 }
380
381 @Override
382 public T next() {
383 if (!hasNext()) {
384 throw new NoSuchElementException();
385 }
386 nextCalled = false;
387 return data;
388 }
389
390 @Override
391 public void remove() {
392 throw new UnsupportedOperationException();
393 }
394 }
395
396 private class EntityIterator implements Iterator<Entity> {
397 private int index;
398 private boolean advanced;
399
400 public EntityIterator() {
401 index = 0;
402 advanced = false;
403 }
404
405 @Override
406 public boolean hasNext() {
407 if (!advanced) {
408 advance();
409 }
410 return index < entityInsert;
411 }
412
413 @Override
414 public Entity next() {
415 if (!hasNext()) {
416 throw new NoSuchElementException();
417 }
418 advanced = false;
419 return entities[index];
420 }
421
422 @Override
423 public void remove() {
424 if (advanced || index == 0) {
425 throw new IllegalStateException("Must call next() before remove()");
426 }
427 if (entities[index] == null) {
428 throw new IllegalStateException("Entity already removed");
429 }
430 removeEntity(entities[index]);
431 }
432
433 private void advance() {
434 do {
435 index++;
436 } while (index < entities.length && entities[index] == null);
437 advanced = true;
438 }
439 }
440 }