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.Entity;
31 import com.lhkbob.entreri.Requires;
32 import com.lhkbob.entreri.property.IntProperty;
33 import com.lhkbob.entreri.property.ObjectProperty;
34 import com.lhkbob.entreri.property.Property;
35 import com.lhkbob.entreri.property.PropertyFactory;
36
37 import java.lang.ref.WeakReference;
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.Iterator;
41 import java.util.List;
42
43
44
45
46
47
48
49
50
51
52 @SuppressWarnings({ "unchecked", "rawtypes" })
53 public final class ComponentRepository<T extends Component> {
54 private final EntitySystemImpl system;
55 private final Class<T> type;
56
57 private final ComponentFactoryProvider.Factory<T> factory;
58 private final Class<? extends Component>[] requiredTypes;
59
60
61
62
63 private int[] entityIndexToComponentRepository;
64 private int[] componentIndexToEntityIndex;
65 private T[] components;
66 private int componentInsert;
67
68 private final List<DeclaredPropertyStore<?>> declaredProperties;
69 private final List<DecoratedPropertyStore<?>> decoratedProperties;
70
71
72 private final IntProperty componentIdProperty;
73 private final IntProperty componentVersionProperty;
74
75 private final ObjectProperty ownerDelegatesProperty;
76
77 private int idSeq;
78 private int versionSeq;
79
80
81
82
83
84
85
86
87
88
89 public ComponentRepository(EntitySystemImpl system, Class<T> type) {
90 if (system == null || type == null) {
91 throw new NullPointerException("Arguments cannot be null");
92 }
93
94 this.system = system;
95 this.factory = ComponentFactoryProvider.getInstance().getFactory(type);
96 this.type = type;
97
98 if (type.getAnnotation(Requires.class) != null) {
99 requiredTypes = type.getAnnotation(Requires.class).value();
100 } else {
101 requiredTypes = new Class[0];
102 }
103
104 declaredProperties = new ArrayList<>();
105 decoratedProperties = new ArrayList<>();
106 for (PropertyDeclaration p : factory.getSpecification().getProperties()) {
107 DeclaredPropertyStore store = new DeclaredPropertyStore(
108 p.getPropertyFactory(), p.getName());
109 declaredProperties.add(store);
110 }
111
112 entityIndexToComponentRepository = new int[1];
113 componentIndexToEntityIndex = new int[1];
114 components = (T[]) new Component[1];
115
116 componentInsert = 1;
117
118
119 resizePropertyStores(declaredProperties, 1);
120
121
122
123 componentIdProperty = decorate(new IntProperty.Factory(0));
124 componentVersionProperty = decorate(new IntProperty.Factory(0));
125 ownerDelegatesProperty = decorate(ObjectProperty.<OwnerSupport>factory(null));
126
127 idSeq = 1;
128
129
130 componentVersionProperty.set(0, -1);
131 }
132
133
134
135
136 public Class<T> getType() {
137 return type;
138 }
139
140
141
142
143 public int getMaxComponentIndex() {
144 return componentInsert;
145 }
146
147
148
149
150 public EntitySystemImpl getEntitySystem() {
151 return system;
152 }
153
154
155
156
157
158
159
160
161
162
163
164 public int getEntityIndex(int componentIndex) {
165 return componentIndexToEntityIndex[componentIndex];
166 }
167
168
169
170
171
172
173
174
175
176
177
178 public int getComponentIndex(int entityIndex) {
179 return entityIndexToComponentRepository[entityIndex];
180 }
181
182
183
184
185
186
187
188 public void expandEntityIndex(int numEntities) {
189 if (entityIndexToComponentRepository.length < numEntities) {
190 entityIndexToComponentRepository = Arrays
191 .copyOf(entityIndexToComponentRepository,
192 (int) (numEntities * 1.5) + 1);
193 }
194 }
195
196
197
198
199
200
201 public int getId(int componentIndex) {
202 return componentIdProperty.get(componentIndex);
203 }
204
205
206
207
208
209
210 public int getVersion(int componentIndex) {
211 return componentVersionProperty.get(componentIndex);
212 }
213
214
215
216
217
218
219
220
221 public void incrementVersion(int componentIndex) {
222 if (componentIndex != 0) {
223
224 int newVersion = (0xefffffff & (versionSeq++));
225 componentVersionProperty.set(componentIndex, newVersion);
226 }
227 }
228
229
230
231
232
233
234 public OwnerSupport getOwnerDelegate(int componentIndex) {
235 return (OwnerSupport) ownerDelegatesProperty.get(componentIndex);
236 }
237
238
239
240
241
242
243
244 public Property getProperty(int propertyIndex) {
245 return declaredProperties.get(propertyIndex).getProperty();
246 }
247
248
249
250
251
252
253 public String getDeclaredPropertyName(int propertyIndex) {
254 return declaredProperties.get(propertyIndex).key;
255 }
256
257
258
259
260 public int getDeclaredPropertyCount() {
261 return declaredProperties.size();
262 }
263
264
265
266
267
268 private void expandComponentRepository(int numComponents) {
269 if (numComponents < components.length) {
270 return;
271 }
272
273 int size = (int) (numComponents * 1.5) + 1;
274
275
276 resizePropertyStores(declaredProperties, size);
277 resizePropertyStores(decoratedProperties, size);
278
279
280 components = Arrays.copyOf(components, size);
281
282
283 componentIndexToEntityIndex = Arrays.copyOf(componentIndexToEntityIndex, size);
284 }
285
286
287
288
289
290 private void resizePropertyStores(List<? extends PropertyStore<?>> properties,
291 int size) {
292 int ct = properties.size();
293 for (int i = 0; i < ct; i++) {
294 properties.get(i).resize(size);
295 }
296 }
297
298
299
300
301
302
303 public T getComponent(int componentIndex) {
304 return components[componentIndex];
305 }
306
307
308
309
310
311
312
313
314
315
316
317
318
319 public T addComponent(int entityIndex, T fromTemplate) {
320 if (!type.isInstance(fromTemplate)) {
321 throw new IllegalArgumentException(
322 "Component not of expected type, expected: " + type + ", but was: " +
323 fromTemplate.getClass());
324 }
325 if (!fromTemplate.isAlive()) {
326 throw new IllegalStateException("Template component is not live");
327 }
328
329 T instance = addComponent(entityIndex);
330
331
332
333 for (int i = 0; i < declaredProperties.size(); i++) {
334 DeclaredPropertyStore dstStore = declaredProperties.get(i);
335 DeclaredPropertyStore templateStore = ((AbstractComponent<T>) fromTemplate)
336 .owner.declaredProperties.get(i);
337
338 templateStore.creator
339 .clone(templateStore.getProperty(), fromTemplate.getIndex(),
340 dstStore.property, instance.getIndex());
341 }
342
343 return instance;
344 }
345
346
347
348
349
350
351
352
353
354
355
356 public T addComponent(int entityIndex) {
357 if (entityIndexToComponentRepository[entityIndex] != 0) {
358 removeComponent(entityIndex);
359 }
360
361 int componentIndex = componentInsert++;
362 if (componentIndex >= components.length) {
363 expandComponentRepository(componentIndex + 1);
364 }
365
366 AbstractComponent<T> instance = factory.newInstance(this);
367 components[componentIndex] = (T) instance;
368 componentIndexToEntityIndex[componentIndex] = entityIndex;
369 entityIndexToComponentRepository[entityIndex] = componentIndex;
370
371
372
373
374 for (int i = 0; i < declaredProperties.size(); i++) {
375 declaredProperties.get(i).setDefaultValue(componentIndex);
376 }
377 for (int i = 0; i < decoratedProperties.size(); i++) {
378 decoratedProperties.get(i).setDefaultValue(componentIndex);
379 }
380
381
382
383 componentIdProperty.set(componentIndex, idSeq++);
384
385 ownerDelegatesProperty.set(componentIndex, new OwnerSupport(instance));
386
387
388 incrementVersion(componentIndex);
389
390
391 instance.setIndex(componentIndex);
392
393
394 Entity entity = system.getEntityByIndex(entityIndex);
395 for (int i = 0; i < requiredTypes.length; i++) {
396 if (entity.get((Class) requiredTypes[i]) == null) {
397 Component added = entity.add((Class) requiredTypes[i]);
398 added.setOwner(instance);
399 }
400 }
401
402 return (T) instance;
403 }
404
405
406
407
408
409
410
411 public AbstractComponent<T> createDataInstance() {
412 AbstractComponent<T> t = factory.newInstance(this);
413 t.setIndex(0);
414 return t;
415 }
416
417
418
419
420
421
422
423
424
425 public boolean removeComponent(int entityIndex) {
426 int componentIndex = entityIndexToComponentRepository[entityIndex];
427
428
429 T oldComponent = components[componentIndex];
430 AbstractComponent<T> casted = (AbstractComponent<T>) oldComponent;
431 if (oldComponent != null) {
432 oldComponent.setOwner(null);
433 getOwnerDelegate(componentIndex).disownAndRemoveChildren();
434 casted.setIndex(0);
435 }
436
437 components[componentIndex] = null;
438 entityIndexToComponentRepository[entityIndex] = 0;
439 componentIndexToEntityIndex[componentIndex] = 0;
440 componentIdProperty.set(componentIndex, 0);
441 ownerDelegatesProperty.set(componentIndex, null);
442
443 return oldComponent != null;
444 }
445
446 private void sort() {
447
448
449
450 for (int i = 1; i < componentInsert; i++) {
451 int vi = componentIndexToEntityIndex[i];
452 for (int j = i - 1; j >= 1; j--) {
453 int vj = componentIndexToEntityIndex[j];
454
455
456
457 if (vi > 0 && (vi < vj || vj == 0)) {
458
459 componentIndexToEntityIndex[j] = vi;
460 componentIndexToEntityIndex[j + 1] = vj;
461
462 T t = components[j];
463 components[j] = components[j + 1];
464 components[j + 1] = t;
465
466
467 swap(declaredProperties, j + 1, j);
468 swap(decoratedProperties, j + 1, j);
469 } else {
470
471 break;
472 }
473 }
474 }
475 }
476
477 private void swap(List<? extends PropertyStore<?>> store, int a, int b) {
478 for (int i = 0; i < store.size(); i++) {
479 store.get(i).swap(a, b);
480 }
481 }
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496 public void compact(int[] entityOldToNewMap, int numEntities) {
497
498 Iterator<DecoratedPropertyStore<?>> it = decoratedProperties.iterator();
499 while (it.hasNext()) {
500 if (it.next().getProperty() == null) {
501 it.remove();
502 }
503 }
504
505
506
507 sort();
508
509
510 componentInsert = 1;
511 for (int i = 1; i < components.length; i++) {
512 if (components[i] != null) {
513 componentIndexToEntityIndex[i] = entityOldToNewMap[componentIndexToEntityIndex[i]];
514 ((AbstractComponent<T>) components[i]).setIndex(i);
515 componentInsert = i + 1;
516 } else {
517
518
519 break;
520 }
521 }
522
523
524 if (componentInsert < .6 * components.length) {
525 int newSize = (int) (1.2 * componentInsert) + 1;
526 components = Arrays.copyOf(components, newSize);
527 componentIndexToEntityIndex = Arrays
528 .copyOf(componentIndexToEntityIndex, newSize);
529 resizePropertyStores(declaredProperties, newSize);
530 resizePropertyStores(decoratedProperties, newSize);
531 }
532
533
534
535 if (numEntities < .6 * entityIndexToComponentRepository.length) {
536 entityIndexToComponentRepository = new int[(int) (1.2 * numEntities) + 1];
537 } else {
538 Arrays.fill(entityIndexToComponentRepository, 0);
539 }
540
541 for (int i = 1; i < componentInsert; i++) {
542 entityIndexToComponentRepository[componentIndexToEntityIndex[i]] = i;
543 }
544 }
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559 public <P extends Property> P decorate(PropertyFactory<P> factory) {
560 int size = (declaredProperties.isEmpty() ? componentInsert
561 : declaredProperties.get(0).property
562 .getCapacity());
563 P prop = factory.create();
564 DecoratedPropertyStore<P> pstore = new DecoratedPropertyStore<>(factory, prop);
565
566
567 prop.setCapacity(size);
568 for (int i = 1; i < size; i++) {
569 pstore.setDefaultValue(i);
570 }
571
572 decoratedProperties.add(pstore);
573 return prop;
574 }
575
576
577
578
579
580 private static abstract class PropertyStore<P extends Property> {
581 final PropertyFactory<P> creator;
582
583 PropertyStore(PropertyFactory<P> creator) {
584 this.creator = creator;
585 }
586
587 void setDefaultValue(int index) {
588 P prop = getProperty();
589 if (prop != null) {
590 creator.setDefaultValue(prop, index);
591 }
592 }
593
594 void resize(int size) {
595 P property = getProperty();
596 if (property != null) {
597 property.setCapacity(size);
598 }
599 }
600
601 void swap(int a, int b) {
602 P property = getProperty();
603 if (property != null) {
604 property.swap(a, b);
605 }
606 }
607
608 abstract P getProperty();
609 }
610
611 private static class DeclaredPropertyStore<P extends Property>
612 extends PropertyStore<P>
613
614 {
615 final String key;
616 final P property;
617
618 public DeclaredPropertyStore(PropertyFactory<P> creator, String key) {
619 super(creator);
620 this.key = key;
621 property = creator.create();
622 }
623
624 @Override
625 P getProperty() {
626 return property;
627 }
628 }
629
630 private static class DecoratedPropertyStore<P extends Property>
631 extends PropertyStore<P> {
632 final WeakReference<P> property;
633
634 public DecoratedPropertyStore(PropertyFactory<P> creator, P property) {
635 super(creator);
636 this.property = new WeakReference<>(property);
637 }
638
639 @Override
640 P getProperty() {
641 return property.get();
642 }
643 }
644 }