1 /*
2 * Entreri, an entity-component framework in Java
3 *
4 * Copyright (c) 2013, Michael Ludwig
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without modification,
8 * are permitted provided that the following conditions are met:
9 *
10 * Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
23 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 package com.lhkbob.entreri.impl;
28
29 import com.lhkbob.entreri.Component;
30 import com.lhkbob.entreri.ComponentIterator;
31
32 import java.util.Arrays;
33
34 /**
35 * Implementation of ComponentIterator used by EntitySystemImpl.
36 *
37 * @author Michael Ludwig
38 */
39 public class ComponentIteratorImpl implements ComponentIterator {
40 private final EntitySystemImpl system;
41
42 private int index;
43
44 private AbstractComponent<?>[] required; // all required except primary
45 private AbstractComponent<?>[] optional;
46
47 private AbstractComponent<?> primary;
48
49 /**
50 * Create a new ComponentIterator that will iterate over components within the given
51 * EntitySystem. It is initialized with no required or optional components, but at
52 * least one required component must be added before it can be iterated over.
53 *
54 * @param system The EntitySystem of the iterator
55 *
56 * @throws NullPointerException if system is null
57 */
58 public ComponentIteratorImpl(EntitySystemImpl system) {
59 if (system == null) {
60 throw new NullPointerException("System cannot be null");
61 }
62 this.system = system;
63 required = new AbstractComponent<?>[0];
64 optional = new AbstractComponent<?>[0];
65 primary = null;
66 index = 0;
67 }
68
69 @Override
70 @SuppressWarnings("unchecked")
71 public <T extends Component> T addRequired(Class<T> type) {
72 if (type == null) {
73 throw new NullPointerException("Component type cannot be null");
74 }
75 AbstractComponent<T> data = system.getRepository(type).createDataInstance();
76
77 // check to see if the data should be the new primary
78 if (primary == null) {
79 // no other required components, so just set it
80 primary = data;
81 } else {
82 // check if the new data is shorter, but we will definitely
83 // putting one data into the required array
84 required = Arrays.copyOf(required, required.length + 1);
85
86 if (data.owner.getMaxComponentIndex() <
87 primary.owner.getMaxComponentIndex()) {
88 // new primary
89 required[required.length - 1] = primary;
90 primary = data;
91 } else {
92 // not short enough so store it in the array
93 required[required.length - 1] = data;
94 }
95 }
96
97 return (T) data;
98 }
99
100 @Override
101 @SuppressWarnings("unchecked")
102 public <T extends Component> T addOptional(Class<T> type) {
103 if (type == null) {
104 throw new NullPointerException("Component type cannot be null");
105 }
106
107 AbstractComponent<T> data = system.getRepository(type).createDataInstance();
108
109 // add the data to the optional array
110 optional = Arrays.copyOf(optional, optional.length + 1);
111 optional[optional.length - 1] = data;
112
113 return (T) data;
114 }
115
116 @Override
117 public boolean next() {
118 if (primary == null) {
119 return false;
120 }
121
122 boolean found;
123 int entity;
124 int component;
125 int count = primary.owner.getMaxComponentIndex();
126 while (index < count - 1) {
127 index++; // always increment one
128
129 found = true;
130 entity = primary.owner.getEntityIndex(index);
131 if (entity != 0) {
132 // we have a possible entity candidate
133 primary.setIndex(index);
134 for (int i = 0; i < required.length; i++) {
135 component = required[i].owner.getComponentIndex(entity);
136 if (component == 0) {
137 found = false;
138 break;
139 } else {
140 required[i].setIndex(component);
141 }
142 }
143
144 if (found) {
145 // we have satisfied all required components,
146 // so now set all optional requirements as well
147 for (int i = 0; i < optional.length; i++) {
148 component = optional[i].owner.getComponentIndex(entity);
149 optional[i].setIndex(component);
150 }
151
152 return true;
153 }
154 }
155 }
156
157 return false;
158 }
159
160 @Override
161 public void reset() {
162 index = 0;
163 }
164 }