diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/inventory/BWInventory.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/inventory/BWInventory.java index ee9e28e69..cc912866f 100644 --- a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/inventory/BWInventory.java +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/inventory/BWInventory.java @@ -25,7 +25,6 @@ import nova.core.component.inventory.Inventory; import nova.core.item.Item; import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.ItemConverter; -import nova.internal.core.Game; import java.util.Optional; @@ -43,8 +42,9 @@ public Optional get(int slot) { @Override public boolean set(int slot, Item item) { + Optional orig = get(slot); wrapped.setInventorySlotContents(slot, ItemConverter.instance().toNative(item)); - return true; + return !orig.equals(get(slot)); } @Override @@ -54,6 +54,21 @@ public Optional remove(int slot) { return item; } + @Override + public Optional remove(int slot, int amount) { + ItemStack stack = wrapped.getStackInSlot(slot); + if (stack != null) { + Item item = ItemConverter.instance().toNova(stack); + item.setCount(item.count() - amount); + if (item.count() <= 0) { + return remove(slot); + } + ItemConverter.instance().updateMCItemStack(stack, item); + return Optional.of(item.withAmount(amount)); + } + return Optional.empty(); + } + @Override public int size() { return wrapped.getSizeInventory(); diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/inventory/FWInventory.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/inventory/FWInventory.java index 5dc81b61d..1e3e08194 100644 --- a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/inventory/FWInventory.java +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/inventory/FWInventory.java @@ -52,7 +52,8 @@ public boolean isEmpty() { @Override public ItemStack getStackInSlot(int slot) { - return ItemConverter.instance().toNative(wrapped.get(slot).orElse(null)); + if (slot < 0 || slot >= wrapped.size()) return null; + return wrapped.get(slot).map(ItemConverter.instance()::toNative).orElse(null); } @Override @@ -82,7 +83,8 @@ public ItemStack removeStackFromSlot(int slot) { @Override public void setInventorySlotContents(int slot, ItemStack stack) { - wrapped.set(slot, stack != null ? ItemConverter.instance().getNovaItem(stack) : null); + if (slot < 0 || slot >= wrapped.size()) return; + wrapped.set(slot, stack != null ? ItemConverter.instance().toNova(stack) : null); } @Override @@ -113,23 +115,19 @@ public void markDirty() { @Override public boolean isUsableByPlayer(EntityPlayer player) { - // TODO Auto-generated method stub return true; } @Override public void openInventory(EntityPlayer playerIn) { - } @Override public void closeInventory(EntityPlayer playerIn) { - } @Override public boolean isItemValidForSlot(int slot, ItemStack stack) { - // TODO Auto-generated method stub return true; } diff --git a/minecraft/1.7.10/src/main/java/nova/core/wrapper/mc/forge/v1_7_10/wrapper/inventory/BWInventory.java b/minecraft/1.7.10/src/main/java/nova/core/wrapper/mc/forge/v1_7_10/wrapper/inventory/BWInventory.java index 07a51612e..e5464250c 100644 --- a/minecraft/1.7.10/src/main/java/nova/core/wrapper/mc/forge/v1_7_10/wrapper/inventory/BWInventory.java +++ b/minecraft/1.7.10/src/main/java/nova/core/wrapper/mc/forge/v1_7_10/wrapper/inventory/BWInventory.java @@ -25,7 +25,6 @@ import nova.core.component.inventory.Inventory; import nova.core.item.Item; import nova.core.wrapper.mc.forge.v1_7_10.wrapper.item.ItemConverter; -import nova.internal.core.Game; import java.util.Optional; @@ -37,14 +36,15 @@ public BWInventory(IInventory mcInventory) { } @Override - public Optional get(int i) { - return Optional.ofNullable(wrapped.getStackInSlot(i)).map(ItemConverter.instance()::toNova); + public Optional get(int slot) { + return Optional.ofNullable(wrapped.getStackInSlot(slot)).map(ItemConverter.instance()::toNova); } @Override - public boolean set(int i, Item item) { - wrapped.setInventorySlotContents(i, ItemConverter.instance().toNative(item)); - return true; + public boolean set(int slot, Item item) { + Optional orig = get(slot); + wrapped.setInventorySlotContents(slot, ItemConverter.instance().toNative(item)); + return !orig.equals(get(slot)); } @Override @@ -54,6 +54,21 @@ public Optional remove(int slot) { return item; } + @Override + public Optional remove(int slot, int amount) { + ItemStack stack = wrapped.getStackInSlot(slot); + if (stack != null) { + Item item = ItemConverter.instance().toNova(stack); + item.setCount(item.count() - amount); + if (item.count() <= 0) { + return remove(slot); + } + ItemConverter.instance().updateMCItemStack(stack, item); + return Optional.of(item.withAmount(amount)); + } + return Optional.empty(); + } + @Override public int size() { return wrapped.getSizeInventory(); diff --git a/minecraft/1.7.10/src/main/java/nova/core/wrapper/mc/forge/v1_7_10/wrapper/inventory/FWInventory.java b/minecraft/1.7.10/src/main/java/nova/core/wrapper/mc/forge/v1_7_10/wrapper/inventory/FWInventory.java index e4508f6da..979e44a46 100644 --- a/minecraft/1.7.10/src/main/java/nova/core/wrapper/mc/forge/v1_7_10/wrapper/inventory/FWInventory.java +++ b/minecraft/1.7.10/src/main/java/nova/core/wrapper/mc/forge/v1_7_10/wrapper/inventory/FWInventory.java @@ -41,7 +41,8 @@ public int getSizeInventory() { @Override public ItemStack getStackInSlot(int slot) { - return ItemConverter.instance().toNative(wrapped.get(slot).orElse(null)); + if (slot < 0 || slot >= wrapped.size()) return null; + return wrapped.get(slot).map(ItemConverter.instance()::toNative).orElse(null); } @Override @@ -65,7 +66,8 @@ public ItemStack getStackInSlotOnClosing(int slot) { @Override public void setInventorySlotContents(int slot, ItemStack stack) { - wrapped.set(slot, stack != null ? ItemConverter.instance().getNovaItem(stack) : null); + if (slot < 0 || slot >= wrapped.size()) return; + wrapped.set(slot, stack != null ? ItemConverter.instance().toNova(stack) : null); } @Override @@ -91,23 +93,19 @@ public void markDirty() { @Override public boolean isUseableByPlayer(EntityPlayer player) { - // TODO Auto-generated method stub return true; } @Override public void openInventory() { - } @Override public void closeInventory() { - } @Override public boolean isItemValidForSlot(int slot, ItemStack stack) { - // TODO Auto-generated method stub return true; } diff --git a/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v1_8/wrapper/inventory/BWInventory.java b/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v1_8/wrapper/inventory/BWInventory.java index 719b6a631..f34cb3075 100644 --- a/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v1_8/wrapper/inventory/BWInventory.java +++ b/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v1_8/wrapper/inventory/BWInventory.java @@ -25,7 +25,6 @@ import nova.core.component.inventory.Inventory; import nova.core.item.Item; import nova.core.wrapper.mc.forge.v1_8.wrapper.item.ItemConverter; -import nova.internal.core.Game; import java.util.Optional; @@ -37,14 +36,15 @@ public BWInventory(IInventory mcInventory) { } @Override - public Optional get(int i) { - return Optional.ofNullable(wrapped.getStackInSlot(i)).map(ItemConverter.instance()::toNova); + public Optional get(int slot) { + return Optional.ofNullable(wrapped.getStackInSlot(slot)).map(ItemConverter.instance()::toNova); } @Override - public boolean set(int i, Item item) { - wrapped.setInventorySlotContents(i, ItemConverter.instance().toNative(item)); - return true; + public boolean set(int slot, Item item) { + Optional orig = get(slot); + wrapped.setInventorySlotContents(slot, ItemConverter.instance().toNative(item)); + return !orig.equals(get(slot)); } @Override @@ -54,6 +54,21 @@ public Optional remove(int slot) { return item; } + @Override + public Optional remove(int slot, int amount) { + ItemStack stack = wrapped.getStackInSlot(slot); + if (stack != null) { + Item item = ItemConverter.instance().toNova(stack); + item.setCount(item.count() - amount); + if (item.count() <= 0) { + return remove(slot); + } + ItemConverter.instance().updateMCItemStack(stack, item); + return Optional.of(item.withAmount(amount)); + } + return Optional.empty(); + } + @Override public int size() { return wrapped.getSizeInventory(); diff --git a/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v1_8/wrapper/inventory/FWInventory.java b/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v1_8/wrapper/inventory/FWInventory.java index 0ebd67776..469aae0ef 100644 --- a/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v1_8/wrapper/inventory/FWInventory.java +++ b/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v1_8/wrapper/inventory/FWInventory.java @@ -42,11 +42,13 @@ public int getSizeInventory() { @Override public ItemStack getStackInSlot(int slot) { - return ItemConverter.instance().toNative(wrapped.get(slot).orElse(null)); + if (slot < 0 || slot >= wrapped.size()) return null; + return wrapped.get(slot).map(ItemConverter.instance()::toNative).orElse(null); } @Override public ItemStack decrStackSize(int slot, int amount) { + if (slot < 0 || slot >= wrapped.size()) return null; ItemStack stack = getStackInSlot(slot); ItemStack ret = stack.copy(); ret.stackSize = Math.min(ret.stackSize, amount); @@ -61,12 +63,14 @@ public ItemStack decrStackSize(int slot, int amount) { @Override public ItemStack getStackInSlotOnClosing(int slot) { + if (slot < 0 || slot >= wrapped.size()) return null; return getStackInSlot(slot); } @Override public void setInventorySlotContents(int slot, ItemStack stack) { - wrapped.set(slot, stack != null ? ItemConverter.instance().getNovaItem(stack) : null); + if (slot < 0 || slot >= wrapped.size()) return; + wrapped.set(slot, stack != null ? ItemConverter.instance().toNova(stack) : null); } @Override @@ -97,23 +101,19 @@ public void markDirty() { @Override public boolean isUseableByPlayer(EntityPlayer player) { - // TODO Auto-generated method stub return true; } @Override public void openInventory(EntityPlayer playerIn) { - } @Override public void closeInventory(EntityPlayer playerIn) { - } @Override public boolean isItemValidForSlot(int slot, ItemStack stack) { - // TODO Auto-generated method stub return true; } @@ -124,7 +124,6 @@ public int getField(int id) { @Override public void setField(int id, int value) { - } @Override diff --git a/src/main/java/nova/core/component/inventory/Inventory.java b/src/main/java/nova/core/component/inventory/Inventory.java index bd524be6f..71fdebfaa 100644 --- a/src/main/java/nova/core/component/inventory/Inventory.java +++ b/src/main/java/nova/core/component/inventory/Inventory.java @@ -39,15 +39,25 @@ * @see InventoryView */ public interface Inventory extends Iterable { - Optional get(int slot); + + /** + * @param slot Slot number + * @return The item in the slot or an {@link Optional#empty empty optional} + * if there is no item in the slot + * @throws IndexOutOfBoundsException if the slot is out of range + * (index < 0 || index >= size()) + */ + Optional get(int slot) throws IndexOutOfBoundsException; /** * Sets {@link Item} in slot * @param slot Slot number - * @param stack Stack to insert - * @return Whether succeed + * @param item Item to insert + * @return Whether the operation succeeded or not + * @throws IndexOutOfBoundsException if the slot is out of range + * (index < 0 || index >= size()) */ - boolean set(int slot, Item stack); + boolean set(int slot, Item item) throws IndexOutOfBoundsException; /** * Gets count of slots @@ -63,66 +73,80 @@ public interface Inventory extends Iterable { /** * Adds items to this inventory at specified slot * @param slot Slot to add items into - * @param stack {@link Item} containing items + * @param item Item to add * @return Amount of items left(did not fit inside this inventory) + * @throws IndexOutOfBoundsException if the slot is out of range + * (index < 0 || index >= size()) */ - default int add(int slot, Item stack) { + default Optional add(int slot, Item item) throws IndexOutOfBoundsException { Optional o = get(slot); + if (item == null) { + return Optional.empty(); + } if (o.isPresent()) { - if (stack.sameItemType(o.get())) { - return stack.count() - o.get().addCount(stack.count()); + if (item.sameItemType(o.get())) { + return Optional.of(item.withAmount(item.count() - o.get().addCount(item.count()))); } else { - return stack.count(); + return Optional.of(item); } } else { - set(slot, stack); - return 0; + set(slot, item); + return Optional.empty(); } } /** * Adds items to this inventory - * @param stack {@link Item} containing items + * @param item {@link Item} containing items * @return Amount of items left(did not fit inside this inventory) */ - default int add(Item stack) { - int itemsLeft = stack.count(); + default Optional add(Item item) { + if (item == null) { + return Optional.empty(); + } + int itemsLeft = item.count(); for (int i = 0; i < size(); i++) { - itemsLeft = add(i, stack.withAmount(itemsLeft)); + itemsLeft = add(i, item.withAmount(itemsLeft)).map(Item::count).orElse(0); if (itemsLeft == 0) break; } - if (itemsLeft != stack.count()) { + if (itemsLeft != item.count()) { markChanged(); } - return itemsLeft; + final int il = itemsLeft; + return Optional.of(item) + .filter(i -> il > 0) + .map(i -> i.withAmount(il)); } /** * Removes a one count of the item from a slot. * @param slot The slot index to remove * @return The items removed + * @throws IndexOutOfBoundsException if the slot is out of range + * (index < 0 || index >= size()) */ - Optional remove(int slot); + Optional remove(int slot) throws IndexOutOfBoundsException; /** * Removes a certain amount of items from a slot. * @param slot The slot index to remove * @param amount The amount of items to remove * @return The items removed + * @throws IndexOutOfBoundsException if the slot is out of range + * (index < 0 || index >= size()) */ - default Optional remove(int slot, int amount) { + default Optional remove(int slot, int amount) throws IndexOutOfBoundsException { Optional o = get(slot); if (o.isPresent()) { Item item = o.get(); item.setCount(item.count() - amount); if (item.count() <= 0) { - remove(slot); + return remove(slot); } - return Optional.of(item.withAmount(amount)); } return Optional.empty(); @@ -130,18 +154,19 @@ default Optional remove(int slot, int amount) { /** * Removes a certain item from a slot. - * @param check The item type to check with + * @param item The item type to check with * @return The items removed */ - default Optional remove(Item check) { - - int left = check.count(); - + default Optional remove(Item item) { + if (item == null) { + return Optional.empty(); + } + int left = item.count(); for (int i = 0; i < size(); i++) { Optional opItem = get(i); - if (opItem.isPresent()) { - Optional removed = remove(i, check.count()); + if (opItem.isPresent() && item.sameItemType(opItem.get())) { + Optional removed = remove(i, left); if (removed.isPresent()) { left -= removed.get().count(); @@ -149,12 +174,10 @@ default Optional remove(Item check) { } } - int removed = check.count() - left; - + int removed = item.count() - left; if (removed > 0) { - return Optional.of(check.withAmount(removed)); + return Optional.of(item.withAmount(removed)); } - return Optional.empty(); } @@ -163,7 +186,7 @@ default Optional remove(Item check) { * @return This inventory as list of {@link Item Items} */ default List toList() { - ArrayList list = new ArrayList<>(); + List list = new ArrayList<>(); for (Item i : this) { list.add(i); } @@ -189,8 +212,8 @@ default Spliterator spliterator() { } /** - * Represents this inventory as {@link Item} {@link Stream} - * @return This inventory as {@link Item} {@link Stream} + * Represents this inventory as an {@link Item} {@link Stream} + * @return This inventory as an {@link Item} {@link Stream} */ default Stream stream() { return StreamSupport.stream(spliterator(), false); diff --git a/src/main/java/nova/core/component/inventory/InventoryIterator.java b/src/main/java/nova/core/component/inventory/InventoryIterator.java index 177cd2ecc..d4ff2cdb8 100644 --- a/src/main/java/nova/core/component/inventory/InventoryIterator.java +++ b/src/main/java/nova/core/component/inventory/InventoryIterator.java @@ -23,6 +23,8 @@ import nova.core.item.Item; import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Objects; import java.util.Optional; class InventoryIterator implements Iterator { @@ -30,9 +32,10 @@ class InventoryIterator implements Iterator { private int nextPos; private int currentPos; private Item next = null; + private boolean initialized = false; InventoryIterator(Inventory inv) { - this.inv = inv; + this.inv = Objects.requireNonNull(inv, "`inv` can't be null"); findNext(); } @@ -54,7 +57,11 @@ public boolean hasNext() { } @Override - public Item next() { + public Item next() throws NoSuchElementException { + if (next == null) { + throw new NoSuchElementException(); + } + initialized = true; Item current = next; findNext(); return current; @@ -62,6 +69,8 @@ public Item next() { @Override public void remove() { - inv.remove(currentPos); + if (!initialized || !inv.remove(currentPos).isPresent()) { + throw new IllegalStateException(); + } } } diff --git a/src/main/java/nova/core/component/inventory/InventorySimple.java b/src/main/java/nova/core/component/inventory/InventorySimple.java index 9a6e51bff..6121ba084 100644 --- a/src/main/java/nova/core/component/inventory/InventorySimple.java +++ b/src/main/java/nova/core/component/inventory/InventorySimple.java @@ -77,33 +77,42 @@ public int size() { } @Override - public Optional get(int slot) { + public Optional get(int slot) throws IndexOutOfBoundsException { if (slot < 0 || slot >= items.length) { - return Optional.empty(); + throw new IndexOutOfBoundsException(); } else { return Optional.ofNullable(items[slot]); } } @Override - public boolean set(int slot, Item item) { - if (slot < 0 || slot >= items.length || !isItemValidForSlot.apply(slot, item)) { + public boolean set(int slot, Item item) throws IndexOutOfBoundsException { + if (slot < 0 || slot >= items.length) { + throw new IndexOutOfBoundsException(); + } else if (isItemValidForSlot.apply(slot, item)) { return false; } else { + boolean result = (items[slot] != item); + changed |= result; items[slot] = item; - changed = true; - return true; + return result; } } @Override - public Optional remove(int slot) { + public Optional remove(int slot) throws IndexOutOfBoundsException { + if (slot < 0 || slot >= items.length) { + throw new IndexOutOfBoundsException(); + } Item item = items[slot]; items[slot] = null; return Optional.ofNullable(item); } - public Optional swap(int slot, Item item) { + public Optional swap(int slot, Item item) throws IndexOutOfBoundsException { + if (slot < 0 || slot >= items.length) { + throw new IndexOutOfBoundsException(); + } Optional current = get(slot); set(slot, item); return current; diff --git a/src/main/java/nova/core/component/inventory/InventoryView.java b/src/main/java/nova/core/component/inventory/InventoryView.java index 9b42f37cb..e32947c85 100644 --- a/src/main/java/nova/core/component/inventory/InventoryView.java +++ b/src/main/java/nova/core/component/inventory/InventoryView.java @@ -41,26 +41,30 @@ public InventoryView(Inventory parent, int[] slots) { } @Override - public Optional get(int slot) { + public Optional get(int slot) throws IndexOutOfBoundsException { if (slot < 0 || slot >= slots.length) { - return null; + throw new IndexOutOfBoundsException(); } else { return parent.get(slots[slot]); } } @Override - public boolean set(int slot, Item stack) { + public boolean set(int slot, Item stack) throws IndexOutOfBoundsException { if (slot < 0 || slot >= slots.length) { - return false; + throw new IndexOutOfBoundsException(); } else { return parent.set(slots[slot], stack); } } @Override - public Optional remove(int slot) { - return parent.remove(slot); + public Optional remove(int slot) throws IndexOutOfBoundsException { + if (slot < 0 || slot >= slots.length) { + throw new IndexOutOfBoundsException(); + } else { + return parent.remove(slots[slot]); + } } @Override diff --git a/src/main/java/nova/core/item/Item.java b/src/main/java/nova/core/item/Item.java index 5fe194840..da7bffe0a 100644 --- a/src/main/java/nova/core/item/Item.java +++ b/src/main/java/nova/core/item/Item.java @@ -31,6 +31,7 @@ import nova.core.retention.Storable; import nova.core.util.Direction; import nova.core.util.Identifiable; +import nova.core.util.math.MathUtil; import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; import java.util.List; @@ -45,8 +46,8 @@ public class Item extends ComponentProvider implements Identifiabl private int count = 1; /** - * Called to get the ItemFactory that refers to this Block class. - * @return The {@link nova.core.item.ItemFactory} that refers to this Block class. + * Called to get the ItemFactory that refers to this Item class. + * @return The {@link ItemFactory} that refers to this Item class. */ public final ItemFactory getFactory() { return (ItemFactory) components.get(FactoryProvider.class).factory; @@ -84,7 +85,7 @@ public int count() { * @return {@code this} instance */ public Item setCount(int size) { - count = Math.max(Math.min(getMaxCount(), size), 0); + count = MathUtil.clamp(size, 0, getMaxCount()); return this; } diff --git a/src/test/java/nova/core/component/inventory/InventoryIteratorTest.java b/src/test/java/nova/core/component/inventory/InventoryIteratorTest.java new file mode 100644 index 000000000..72c00ef68 --- /dev/null +++ b/src/test/java/nova/core/component/inventory/InventoryIteratorTest.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with NOVA. If not, see . + */ + +package nova.core.component.inventory; + +import org.junit.Test; + +import static org.assertj.core.api.Assertions.*; + +/** + * @author ExE Boss + */ +public class InventoryIteratorTest { + + public InventoryIteratorTest() { + } + + @Test + public void testConstructorThrowsNPE() { + assertThatCode(() -> new InventoryIterator(null)) + .isInstanceOf(NullPointerException.class); + } +}