RuneHive-Game
Loading...
Searching...
No Matches
MobList.java
Go to the documentation of this file.
1package com.runehive.game.world.entity;
2
3import com.runehive.game.world.entity.mob.Mob;
4import com.runehive.util.RandomUtils;
5
6import java.util.*;
7import java.util.function.Consumer;
8import java.util.function.Predicate;
9import java.util.stream.Collectors;
10import java.util.stream.IntStream;
11import java.util.stream.Stream;
12import java.util.stream.StreamSupport;
13
14import static com.google.common.base.Preconditions.*;
15
16/**
17 * An {@link Iterable} implementation acting as a repository that holds
18 * instances of {@link Entity}s. Indexes are cached to avoid expensive lookups
19 * whenever a new entity is added.
20 *
21 * @param <E> The specific type of {@code EntityNode} being managed within this
22 * list.
23 * @author Artem Batutin <artembatutin@gmail.com>
24 * @author lare96 <http://github.org/lare96>
25 */
26public final class MobList<E extends Mob> implements Iterable<E> {
27
28 /**
29 * An {@link Iterator} implementation designed specifically {@link
30 * MobList}s.
31 *
32 * @param <E> The specific type of {@link Entity} being managed within this
33 * {@code Iterator}.
34 * @author lare96 <http://github.org/lare96>
35 */
36 public static final class EntityListIterator<E extends Mob> implements Iterator<E> {
37
38 /** The {@link MobList} this {@link Iterator} is dedicated to. */
39 private final MobList<E> list;
40
41 /** The current index. */
42 private int curr;
43
44 /** The previous index. */
45 private int prev = -1;
46
47 /**
48 * Creates a new {@link EntityListIterator}.
49 *
50 * @param list The {@link MobList} this {@link Iterator} is dedicated
51 * to.
52 */
54 this.list = list;
55 }
56
57 @Override
58 public boolean hasNext() {
59 return curr < list.capacity() && skipNullIndexes();
60 }
61
62 @Override
63 public E next() {
65 checkPositionIndex(curr, list.capacity(), "No elements left");
66 E entity = list.element(curr);
67 prev = curr++;
68 return entity;
69 }
70
71 @Override
72 public void remove() {
73 checkState(prev != -1, "remove() can only be called once after each call to next()");
74
75 list.remove(list.get(prev));
76 prev = -1;
77 }
78
79 /**
80 * Forwards the {@code curr} marker until a {@code non-null} element is
81 * found.
82 *
83 * @return {@code true} if a non-null element is found, {@code false}
84 * otherwise.
85 */
86 private boolean skipNullIndexes() {
87 while (list.get(curr) == null) {
88 if (++curr >= list.capacity()) {
89 return false;
90 }
91 }
92 return true;
93 }
94 }
95
96 /** The entities contained within this list. */
97 private final E[] entities;
98
99 /** A queue that acts as a fs for indices. */
100 private final TreeSet<Integer> indices;
101
102 /** The internal size of this list. */
103 private int size;
104
105 /** The largest used index. */
106 private int largestIndex;
107
108 /**
109 * Creates a new {@link MobList}.
110 *
111 * @param capacity The length of the backing array plus {@code 1}.
112 */
113 @SuppressWarnings("unchecked")
114 public MobList(int capacity) {
115 entities = (E[]) new Mob[++capacity];
116 Stream<Integer> indexStream = IntStream.rangeClosed(1, capacity).boxed();
117 indices = new TreeSet<>(indexStream.collect(Collectors.toList()));
118 }
119
120 @Override
121 public Iterator<E> iterator() {
122 return new EntityListIterator<>(this);
123 }
124
125 /** Shuffles this collections list of entities. */
126 public void shuffle() {
127 if (size < 2) {
128 return;
129 }
130
131 for (int index = largestIndex; index > 1; index--) {
132 int first = index - 1;
133 int second = RandomUtils.inclusive(1, index);
134 if (first == second) continue;
135
136 E tmp = entities[first];
137 entities[first] = entities[second];
138 entities[second] = tmp;
139
140 if (entities[first] != null) {
141 entities[first].setListIndex(first);
142 }
143
144 if (entities[second] != null) {
145 entities[second].setListIndex(second);
146 }
147
148 }
149 }
150
151 /**
152 * {@inheritDoc}
153 * <p>
154 * This implementation will exclude all elements with a value of {@code
155 * null} to avoid {@link NullPointerException}s.
156 * <p>
157 * UPDATED: Now uses a shuffle_list to battle PID. This means that all
158 * entities are always processed in an random order instead of having higher
159 * priority than other entities because of a higher PID.
160 */
161 @Override
162 public void forEach(Consumer<? super E> action) {
163 int index = 0;
164 for (E e : entities) {
165 if (e == null) continue;
166 action.accept(e);
167 if (++index >= size) return;
168 }
169 }
170
171 /**
172 * Finds the first element that matches {@code filter}.
173 *
174 * @param filter The filter to apply to the elements of this sequence.
175 * @return An {@link Optional} containing the element, or an empty {@code
176 * Optional} if no element was found.
177 */
178 public Optional<E> findFirst(Predicate<? super E> filter) {
179 for (E e : this) {
180 if (filter.test(e)) {
181 return Optional.of(e);
182 }
183 }
184 return Optional.empty();
185 }
186
187 /**
188 * Finds the last element that matches {@code filter}.
189 *
190 * @param filter The filter to apply to the elements of this sequence.
191 * @return An {@link Optional} containing the element, or an empty {@code
192 * Optional} if no element was found.
193 */
194 public Optional<E> findLast(Predicate<? super E> filter) {
195 for (int index = capacity(); index > 1; index--) {
196 E entity = entities[index];
197 if (entity == null) {
198 continue;
199 }
200 if (filter.test(entity)) {
201 return Optional.of(entity);
202 }
203 }
204 return Optional.empty();
205 }
206
207 /**
208 * Finds all elements that match {@code filter}.
209 *
210 * @param filter The filter to apply to the elements of this sequence.
211 * @return An {@link ArrayList} containing the elements.
212 */
213 public List<E> findAll(Predicate<? super E> filter) {
214 List<E> list = new ArrayList<>();
215 for (E e : this) {
216 if (filter.test(e)) {
217 list.add(e);
218 }
219 }
220 return list;
221 }
222
223 /**
224 * {@inheritDoc}
225 * <p>
226 * As a rule of thumb, {@code stream()} and {@code parallelStream()} should
227 * always be used instead unless absolutely needed.
228 */
229 @Override
230 public Spliterator<E> spliterator() {
231 return Spliterators.spliterator(entities, Spliterator.ORDERED | Spliterator.DISTINCT);
232 }
233
234 /**
235 * Adds {@code entity} to this list. Will throw an exception if this list is
236 * full, or if the entity being added has a state of {@code ACTIVE}.
237 *
238 * @param entity The entity to deposit to this list.
239 */
240 public boolean add(E entity) {
241 Integer index = indices.pollFirst();
242
243 if (index == null || index == capacity()) {
244 return false;
245 }
246
247 if (index > largestIndex) {
248 largestIndex = index;
249 }
250
251 entities[index] = entity;
252 entity.setIndex(index);
253 entity.setListIndex(index);
254 size++;
255 return true;
256 }
257
258 /**
259 * Removes {@code entity} from this list. Will throw an exception if the
260 * entity being removed does not have a state of {@code ACTIVE}.
261 *
262 * @param entity The entity to withdraw from this list.
263 */
264 public boolean remove(E entity) {
265 checkArgument(entity.getListIndex() != -1, "index == -1");
266 indices.add(entity.getListIndex());
267 entities[entity.getListIndex()] = null;
268 size--;
269 return true;
270 }
271
272 /**
273 * Removes a {@link Entity} from this list at {@code index}. Will throw an
274 * exception if the entity being removed does not have a state of {@code
275 * ACTIVE}.
276 *
277 * @param index The index to withdraw the {@link Entity} at.
278 */
279 public void remove(int index) {
280 remove(entities[index]);
281 }
282
283 /**
284 * Retrieves the element on {@code index}.
285 *
286 * @param index The index.
287 * @return The retrieved element, possibly {@code null}.
288 */
289 public E get(int index) {
290 return entities[index];
291 }
292
293 /**
294 * Retrieves the element on {@code index}, the only difference between this
295 * and {@code get(int)} is that this method throws an exception if no entity
296 * is found on {@code index}.
297 *
298 * @param index The index.
299 * @return The retrieved element, will never be {@code null}.
300 */
301 public E element(int index) {
302 E entity = get(index);
303 checkArgument(entity != null, "index -> null EntityNode");
304 return entity;
305 }
306
307 /**
308 * Determines if this list contains {@code entity}.
309 *
310 * @param entity The entity to check for.
311 * @return {@code true} if {@code entity} is contained, {@code false}
312 * otherwise.
313 */
314 public boolean contains(E entity) {
315 return entity != null && entity.equals(get(entity.getListIndex()));
316 }
317
318 /**
319 * @return {@code true} if this list is full, {@code false} otherwise.
320 */
321 public boolean isFull() {
322 return size() == capacity();
323 }
324
325 /**
326 * @return {@code true} if this list is empty, {@code false} otherwise.
327 */
328 public boolean isEmpty() {
329 return size() == 0;
330 }
331
332 /**
333 * @return The amount of entities in this list.
334 */
335 public int size() {
336 return size;
337 }
338
339 /**
340 * @return The amount of free spaces remaining in this list.
341 */
342 public int remaining() {
343 return capacity() - size();
344 }
345
346 /**
347 * @return The length of the backing array.
348 */
349 public int capacity() {
350 return entities.length;
351 }
352
353 /**
354 * <strong>Please note that this function does not give direct access to the
355 * backing array but instead creates a shallow copy.</strong>
356 *
357 * @return The shallow copy of the backing array.
358 */
359 public E[] toArray() {
360 return Arrays.copyOf(entities, entities.length);
361 }
362
363 /**
364 * Calls {@code withdraw()} on every single {@link Entity} in this list.
365 */
366 public void clear() {
367 forEach(this::remove);
368 }
369
370 /**
371 * @return The {@link Stream} that will traverse over this list.
372 * Automatically excludes {@code null} values.
373 */
374 public Stream<E> stream() {
375 return StreamSupport.stream(spliterator(), false).filter(Objects::nonNull);
376 }
377
378 /**
379 * @return The {@link Stream} that will traverse over this list in parallel.
380 * Automatically excludes {@code null} values.
381 */
382 public Stream<E> parallelStream() {
383 Spliterator<E> split = Spliterators.spliterator(entities, spliterator().characteristics() | Spliterator.IMMUTABLE);
384 return StreamSupport.stream(split, true).filter(Objects::nonNull);
385 }
386}
An Iterator implementation designed specifically MobLists.
Definition MobList.java:36
final MobList< E > list
The MobList this Iterator is dedicated to.
Definition MobList.java:39
boolean skipNullIndexes()
Forwards the curr marker until a non-null element is found.
Definition MobList.java:86
EntityListIterator(MobList< E > list)
Creates a new EntityListIterator.
Definition MobList.java:53
Optional< E > findFirst(Predicate<? super E > filter)
Finds the first element that matches filter.
Definition MobList.java:178
MobList(int capacity)
Creates a new MobList.
Definition MobList.java:114
int size
The internal size of this list.
Definition MobList.java:103
List< E > findAll(Predicate<? super E > filter)
Finds all elements that match filter.
Definition MobList.java:213
final E[] entities
The entities contained within this list.
Definition MobList.java:97
final TreeSet< Integer > indices
A queue that acts as a fs for indices.
Definition MobList.java:100
void shuffle()
Shuffles this collections list of entities.
Definition MobList.java:126
E[] toArray()
Please note that this function does not give direct access to the backing array but instead creates a...
Definition MobList.java:359
boolean add(E entity)
Adds entity to this list.
Definition MobList.java:240
int largestIndex
The largest used index.
Definition MobList.java:106
boolean contains(E entity)
Determines if this list contains entity.
Definition MobList.java:314
Optional< E > findLast(Predicate<? super E > filter)
Finds the last element that matches filter.
Definition MobList.java:194
void clear()
Calls withdraw() on every single Entity in this list.
Definition MobList.java:366
void forEach(Consumer<? super E > action)
Definition MobList.java:162
E element(int index)
Retrieves the element on index, the only difference between this and get(int) is that this method thr...
Definition MobList.java:301
Handles the mob class.
Definition Mob.java:66
A static-util class that provides additional functionality for generating pseudo-random numbers.
static int inclusive(int min, int max)
Returns a pseudo-random int value between inclusive min and inclusive max.