1package com.osroyale.game.world.items.containers;
3import com.google.common.base.Preconditions;
4import com.osroyale.game.world.entity.mob.player.Player;
5import com.osroyale.game.world.items.Item;
6import com.osroyale.game.world.items.ItemDefinition;
7import com.osroyale.game.world.items.containers.pricechecker.PriceType;
8import com.osroyale.net.packet.out.SendItemOnInterface;
11import java.util.function.Consumer;
12import java.util.stream.Stream;
13import java.util.stream.StreamSupport;
15import static com.google.common.base.Preconditions.checkArgument;
16import static com.google.common.base.Preconditions.checkState;
60 private static final class ItemContainerIterator
implements Iterator<Item> {
69 private int lastIndex = -1;
73 this.container = container;
77 public boolean hasNext() {
78 return (index + 1) <= container.capacity;
83 checkState(index < container.capacity,
"no more elements left to iterate");
87 return container.items[lastIndex];
91 public void remove() {
92 checkState(lastIndex != -1,
"can only be called once after 'next'");
94 Item oldItem = container.items[lastIndex];
95 container.items[lastIndex] =
null;
129 private final List<ItemContainerListener> listeners =
new ArrayList<>();
132 private final int capacity;
138 private Item[] items;
141 private boolean firingEvents =
true;
145 this.capacity = capacity;
146 this.policy = policy;
152 this(capacity, policy,
new Item[capacity]);
161 public final void forEach(Consumer<? super Item> action) {
162 Objects.requireNonNull(action);
163 for (Item item : items) {
171 public final Spliterator<Item> spliterator() {
172 return Spliterators.spliterator(items, Spliterator.ORDERED);
176 public final Iterator<Item> iterator() {
177 return new ItemContainerIterator(
this);
185 return StreamSupport.stream(spliterator(),
false);
195 public boolean add(Item item) {
196 return add(item, -1,
true);
207 public boolean add(Item item,
int slot) {
208 return add(item, slot,
true);
219 public boolean add(
int id,
int amount) {
220 return add(
new Item(
id, amount));
223 public boolean add(Item item,
boolean refresh,
boolean stack) {
227 public boolean add(Item item,
int preferredIndex,
boolean refresh) {
228 return add(item, preferredIndex,
refresh,
false);
242 public boolean add(Item item,
int preferredIndex,
boolean refresh,
boolean stack) {
243 checkArgument(preferredIndex >= -1,
"invalid index identifier");
249 if (stackable && !stack) {
251 }
else if (preferredIndex != -1) {
252 preferredIndex = items[preferredIndex] !=
null ? -1 : preferredIndex;
255 preferredIndex = preferredIndex == -1 ?
computeFreeIndex() : preferredIndex;
257 if (preferredIndex == -1) {
263 Item current = items[preferredIndex];
264 items[preferredIndex] = (current ==
null) ? item : current.createAndIncrement(item.getAmount());
270 for (
int index = 0; index < until; index++) {
271 preferredIndex = (preferredIndex > capacity || preferredIndex < 0 || items[preferredIndex] ==
null) ? preferredIndex :
computeFreeIndex();
272 if (preferredIndex == -1) {
277 items[preferredIndex] = item;
292 public boolean addAll(Collection<? extends Item> items) {
293 if (items.size() == 1) {
294 Optional<? extends Item> item = items.stream().
295 filter(Objects::nonNull).
297 return item.isPresent() &&
add(item.get());
300 firingEvents =
false;
302 boolean added =
false;
304 for (Item item : items) {
308 if (
add(item, -1,
false)) {
327 return addAll(Arrays.asList(items));
338 return addAll(items.items);
348 public boolean remove(Item item) {
349 return remove(item, -1,
true);
362 public boolean remove(Item item,
int preferredIndex) {
363 return remove(item, preferredIndex,
true);
366 public boolean remove(
int id) {
367 return remove(
new Item(
id, 1));
370 public boolean remove(
int id,
int amount) {
371 return remove(
new Item(
id, amount));
374 public boolean remove(Item item,
int preferredIndex,
boolean refresh) {
375 return remove(item, preferredIndex,
refresh,
true);
393 checkArgument(preferredIndex >= -1,
"invalid index identifier");
407 preferredIndex = preferredIndex == -1 ?
computeIndexForId(item.getId()) : preferredIndex;
409 if (preferredIndex != -1 && items[preferredIndex] ==
null) {
415 if (preferredIndex == -1) {
420 Item current = items[preferredIndex];
421 if (current.getAmount() > item.getAmount()) {
422 items[preferredIndex] = current.createAndDecrement(item.getAmount());
425 items[preferredIndex] = current.createWithAmount(0);
427 items[preferredIndex] =
null;
434 until = (item.getAmount() > until) ? until : item.getAmount();
436 for (
int index = 0; index < until && index < capacity; index++) {
438 if (preferredIndex < 0 || preferredIndex >= capacity) {
440 }
else if (items[preferredIndex] ==
null) {
442 }
else if (items[preferredIndex].
getId() != item.getId()) {
445 if (preferredIndex == -1) {
449 Item oldItem = items[preferredIndex];
451 items[preferredIndex] = oldItem.createWithAmount(0);
453 items[preferredIndex] =
null;
468 public boolean removeAll(Collection<? extends Item> items) {
469 if (items.size() == 1) {
470 Optional<? extends Item> item = items.stream().
471 filter(Objects::nonNull).
473 return item.isPresent() &&
remove(item.get());
476 firingEvents =
false;
477 boolean removed =
false;
479 for (Item item : items) {
483 if (
remove(item, -1,
false)) {
524 for (
final Item item : items) {
529 int price = item.getValue(type);
531 if (value >= Long.MAX_VALUE - price * item.getAmount()) {
532 return Long.MAX_VALUE;
535 value += price * item.getAmount();
547 for (
int index = 0; index < capacity; index++) {
548 if (items[index] ==
null) {
563 for (
int index = 0; index < capacity; index++) {
564 if (items[index] !=
null && items[index].
getId() ==
id) {
581 for (Item item : items) {
582 if (item ==
null || item.getId() !=
id)
584 amount += item.getAmount();
596 return retrieve(index).map(Item::getId);
610 Item oldItem = items[index];
612 if (oldItem ==
null || !oldItem.matchesId(oldId))
615 Item newItem = oldItem.createWithId(newId);
635 Item oldItem = items[index];
637 if (oldItem ==
null || !oldItem.matchesId(oldId))
640 Item newItem = oldItem.createWithId(newId);
659 Item oldItem = items[index];
661 if (oldItem ==
null || !oldItem.matchesId(first.getId()))
677 boolean replaced =
false;
679 firingEvents =
false;
681 while (
replace(oldId, newId,
false)) {
700 for (Item item : forItems) {
712 Item existing = items[index];
713 if ((existing.getAmount() + item.getAmount()) <= 0) {
717 indexCount += item.getAmount();
746 container.
removeAll(Arrays.copyOf(
remove,
remove.length));
758 for (Item item : items) {
759 if (item !=
null &&
id == item.getId()) {
774 for (
int id : identifiers) {
790 for (
int id : identifiers) {
800 return item !=
null &&
contains(item.getId(), item.getAmount());
804 public final boolean contains(
int id,
int amount) {
805 for (Item item : items) {
806 if (item !=
null &&
id == item.getId()) {
807 amount -= item.getAmount();
808 if (amount <= 0)
return true;
816 for (Item item : items) {
826 for (Item item : items) {
836 for (Item item : items) {
846 for (Item item : items) {
875 public final void swap(
int oldIndex,
int newIndex) {
876 swap(
false, oldIndex, newIndex,
true);
888 public final void swap(
boolean insert,
int oldIndex,
int newIndex,
boolean refresh) {
890 insert(oldIndex, newIndex,
refresh);
896 public final void swap(
int oldIndex,
int newIndex,
boolean refresh) {
897 checkArgument(oldIndex >= 0 && oldIndex <
capacity,
"[swap] oldIndex out of range - [old=" + oldIndex +
", new=" + newIndex +
", refresh=" +
refresh +
", size=" +
size() +
", capacity=" +
capacity +
"]");
898 checkArgument(newIndex >= 0 && newIndex <
capacity,
"[swap] newIndex out of range - [old=" + oldIndex +
", new=" + newIndex +
", refresh=" +
refresh +
", size=" +
size() +
", capacity=" +
capacity +
"]");
900 Item itemOld = items[oldIndex];
901 Item itemNew = items[newIndex];
903 items[oldIndex] = itemNew;
904 items[newIndex] = itemOld;
910 public final void insert(
int oldIndex,
int newIndex,
boolean refresh) {
911 checkArgument(oldIndex >= 0 && oldIndex <
capacity,
"[insert] oldIndex out of range - [old=" + oldIndex +
", new=" + newIndex +
", refresh=" +
refresh +
", size=" +
size() +
", capacity=" +
capacity +
"]");
912 checkArgument(newIndex >= 0 && newIndex <
capacity,
"[insert] newIndex out of range - [old=" + oldIndex +
", new=" + newIndex +
", refresh=" +
refresh +
", size=" +
size() +
", capacity=" +
capacity +
"]");
914 if (newIndex > oldIndex) {
915 for (
int index = oldIndex; index < newIndex; index++) {
918 }
else if (oldIndex > newIndex) {
919 for (
int index = oldIndex; index > newIndex; index--) {
925 public final void transfer(
int firstIndex,
int secondIndex,
ItemContainer other,
boolean refresh) {
926 checkArgument(firstIndex >= 0 && firstIndex <
capacity,
"[transfer] firstIndex out of range - [first=" + firstIndex +
", second=" + secondIndex +
", refresh=" +
refresh +
"]");
927 checkArgument(secondIndex >= 0 && secondIndex < other.capacity,
"[transfer] secondIndex out of range - [first=" + firstIndex +
", second=" + secondIndex +
", refresh=" +
refresh +
"]");
928 Item first =
get(firstIndex);
929 Item second = other.get(secondIndex);
930 set(firstIndex, second,
true);
931 other.set(secondIndex, first,
true);
938 Item[] newItems =
new Item[capacity];
941 for (Item item : items) {
945 newItems[newIndex++] = item;
959 Preconditions.checkArgument(items.length <= capacity);
961 for (
int i = 0; i < items.length; i++) {
962 this.items[i] = items[i] ==
null ? null :
copy ? items[i].copy() : items[i];
967 public final void setItems(Item[] items) {
971 public final void set(Item[] toSet) {
982 return Arrays.copyOf(items, items.length);
985 public final Item[] toNonNullArray() {
990 final List<Item> items =
new ArrayList<>(
size());
1000 return items.toArray(
new Item[items.size()]);
1013 weight += item.getWeight();
1025 public void set(
int index, Item item,
boolean refresh) {
1026 Item oldItem = items[index];
1027 items[index] = item;
1039 if (index >= 0 && index < items.length)
1040 return Optional.ofNullable(items[index]);
1041 return Optional.empty();
1050 public final void ifPresent(
int index, Consumer<Item> action) {
1051 if (index >= 0 && index < items.length)
1052 action.accept(items[index]);
1061 public final Item
get(
int index) {
1062 if (index >= 0 && index < items.length)
1063 return items[index];
1074 if (items[index] ==
null) {
1077 return items[index].getId();
1088 return stream().filter(i -> i !=
null &&
id == i.getId()).findFirst();
1100 return stream().filter(i -> i !=
null && item.getId() == i.getId() && item.getAmount() == i.getAmount()).findFirst();
1107 return retrieve(index).isPresent();
1124 this.listeners.forEach(container::addListener);
1135 Arrays.fill(items,
null);
1145 public final boolean isFull() {
1156 return listeners.add(listener);
1167 return listeners.remove(listener);
1181 listeners.forEach(evt -> evt.itemUpdated(
this, Optional.ofNullable(oldItem), Optional.ofNullable(newItem), index,
refresh, login));
1191 listeners.forEach(evt -> evt.bulkItemsUpdated(
this));
1201 listeners.forEach(evt -> evt.capacityExceeded(
this));
1212 this.firingEvents = firingEvents;
1217 return capacity -
size();
1227 return (
int) Arrays.stream(items).filter(Objects::nonNull).count();
1253 for (
int i = 0; i < items.length; i++) {
1254 if (items[i] ==
null) {
1257 if (items[i].
getId() ==
id) {
final Optional< Integer > computeIdForIndex(int index)
final boolean containsAll(int... identifiers)
final boolean replace(int oldId, int newId, int index, boolean refresh)
ItemContainer(int capacity, StackPolicy policy, Item[] items)
boolean removeAll(ItemContainer items)
final boolean contains(int id, int amount)
boolean add(int id, int amount)
final Optional< Item > retrieve(int index)
long containerValue(PriceType type)
void refresh(Player player, int widget)
final boolean replace(Item first, Item second, boolean refresh)
final void fireBulkItemsUpdatedEvent()
boolean addAll(ItemContainer items)
final boolean hasCapacityFor(Item... item)
final int computeFreeIndex()
final boolean replace(int oldId, int newId, boolean refresh)
final boolean replaceAll(int oldId, int newId)
final int computeIndexCount(Item... forItems)
final int computeAmountForId(int id)
Optional< Item > search(int id)
final boolean containsAll(Item... items)
final boolean containsAny(Collection< Item > items)
final boolean hasCapacityAfter(Item[] add, Item... remove)
boolean add(Item item, int slot)
final void fireItemUpdatedEvent(Item oldItem, Item newItem, int index, boolean refresh)
void setFiringEvents(boolean firingEvents)
final void forEach(Consumer<? super Item > action)
final boolean contains(Item item)
final void swap(int oldIndex, int newIndex)
final StackPolicy policy()
final boolean indexFree(int index)
Optional< Item > search(Item item)
final boolean addListener(ItemContainerListener listener)
boolean add(Item item, int preferredIndex, boolean refresh, boolean stack)
boolean addAll(Item... items)
final Stream< Item > stream()
boolean removeAll(Item... items)
final boolean removeListener(ItemContainerListener listener)
final boolean containsAny(int... identifiers)
final void setItems(Item[] items, boolean copy)
final boolean containsAll(Collection< Item > items)
final ItemContainer copy()
boolean addAll(Collection<? extends Item > items)
final void ifPresent(int index, Consumer< Item > action)
boolean removeAll(Collection<? extends Item > items)
ItemContainer(int capacity, StackPolicy policy)
final void swap(boolean insert, int oldIndex, int newIndex, boolean refresh)
final int computeIndexForId(int id)
final boolean containsAny(Item... items)
final int getId(int index)
final boolean indexOccupied(int index)
final void fireCapacityExceededEvent()
final void clear(boolean refresh)