/* * This file is part of LanternServer, licensed under the MIT License (MIT). * * Copyright (c) LanternPowered <https://www.lanternpowered.org> * Copyright (c) SpongePowered <https://www.spongepowered.org> * Copyright (c) contributors * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the Software), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.lanternpowered.server.inventory; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import com.google.common.collect.ImmutableList; import org.lanternpowered.server.util.collect.EmptyIterator; import org.spongepowered.api.effect.Viewer; import org.spongepowered.api.item.ItemType; import org.spongepowered.api.item.inventory.EmptyInventory; import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.InventoryProperty; import org.spongepowered.api.item.inventory.ItemStack; import org.spongepowered.api.item.inventory.property.InventoryCapacity; import org.spongepowered.api.item.inventory.property.InventoryTitle; import org.spongepowered.api.item.inventory.transaction.InventoryTransactionResult; import org.spongepowered.api.item.inventory.transaction.SlotTransaction; import org.spongepowered.api.text.Text; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Optional; import java.util.function.Predicate; import javax.annotation.Nullable; public abstract class AbstractInventory implements IInventory { protected abstract LanternEmptyInventory empty(); AbstractInventory getChild(int index) { return empty(); } int getChildIndex(AbstractInventory inventory) { return -1; } @SuppressWarnings("unchecked") @Override public Iterator<Inventory> iterator() { return EmptyIterator.get(); } @Override public abstract AbstractInventory parent(); @Override public void add(ContainerViewListener listener) { } /** * Offers the {@link ItemStack} fast to this inventory, avoiding * the creation of {@link InventoryTransactionResult}s. * * @param stack The item stack * @return The fast offer result */ protected abstract FastOfferResult offerFast(ItemStack stack); protected abstract PeekOfferTransactionsResult peekOfferFastTransactions(ItemStack stack); @SuppressWarnings("unchecked") @Override public <T extends Inventory> T first() { final Inventory inventory = getChild(0); return inventory instanceof EmptyInventory ? (T) this : (T) inventory; } @SuppressWarnings("unchecked") @Override public <T extends Inventory> T next() { final AbstractInventory parent = parent(); if (parent == this) { return (T) empty(); } int index = parent.getChildIndex(this); checkState(index != -1); return (T) parent.getChild(index + 1); } @Override public Optional<ItemStack> poll() { return poll(stack -> true); } @Override public Optional<ItemStack> poll(ItemType itemType) { checkNotNull(itemType, "itemType"); return poll(stack -> stack.getItem().equals(itemType)); } @Override public Optional<ItemStack> poll(int limit) { return poll(limit, stack -> true); } @Override public Optional<ItemStack> poll(int limit, ItemType itemType) { checkNotNull(itemType, "itemType"); return poll(limit, stack -> stack.getItem().equals(itemType)); } @Override public Optional<ItemStack> peek() { return peek(stack -> true); } @Override public Optional<ItemStack> peek(ItemType itemType) { checkNotNull(itemType, "itemType"); return peek(stack -> stack.getItem().equals(itemType)); } @Override public Optional<ItemStack> peek(int limit) { return peek(limit, stack -> true); } @Override public Optional<ItemStack> peek(int limit, ItemType itemType) { checkNotNull(itemType, "itemType"); return peek(limit, stack -> stack.getItem().equals(itemType)); } protected abstract Optional<PeekPollTransactionsResult> peekPollTransactions(Predicate<ItemStack> matcher); protected abstract Optional<PeekPollTransactionsResult> peekPollTransactions(int limit, Predicate<ItemStack> matcher); /** * Peeks for the result {@link SlotTransaction}s and {@link InventoryTransactionResult} * that would occur if you try to set a item through {@link Inventory#set(ItemStack)}. * * @param itemStack The item stack to set * @return The peeked transaction results */ protected abstract PeekSetTransactionsResult peekSetTransactions(@Nullable ItemStack itemStack); @Override public boolean hasProperty(Class<? extends InventoryProperty<?, ?>> property) { checkNotNull(property, "property"); final AbstractInventory parent = parent(); //noinspection unchecked Optional<InventoryProperty<?, ?>> optProperty = tryGetProperty((Class) property, null); if (parent != this && !optProperty.isPresent()) { //noinspection unchecked optProperty = parent.tryGetProperty( this, (Class) property, null); } return optProperty.isPresent(); } @Override public boolean hasProperty(InventoryProperty<?, ?> property) { checkNotNull(property, "property"); final AbstractInventory parent = parent(); //noinspection unchecked Optional<InventoryProperty<?, ?>> optProperty = tryGetProperty((Class) property.getClass(), property.getKey()); if (parent != this && !optProperty.isPresent()) { //noinspection unchecked optProperty = parent.tryGetProperty( this, (Class) property.getClass(), property.getKey()); } return optProperty.isPresent() && optProperty.get().equals(property); } @Override public boolean hasProperty(Inventory child, InventoryProperty<?,?> property) { checkNotNull(property, "property"); //noinspection unchecked Optional<InventoryProperty<?, ?>> optProperty = tryGetProperty( child, (Class) property.getClass(), property.getKey()); if (!optProperty.isPresent()) { //noinspection unchecked optProperty = ((AbstractInventory) child).tryGetProperty((Class) property.getClass(), property.getKey()); } return optProperty.isPresent() && optProperty.get().equals(property); } @Override public final <T extends InventoryProperty<?, ?>> Collection<T> getProperties(Class<T> property) { return getPropertiesBuilder(property).build(); } <T extends InventoryProperty<?, ?>> ImmutableList.Builder<T> getPropertiesBuilder(Class<T> property) { checkNotNull(property, "property"); final AbstractInventory parent = parent(); final ImmutableList.Builder<T> properties = ImmutableList.builder(); //noinspection unchecked properties.addAll(tryGetProperties(property)); if (parent != this) { properties.addAll(parent.tryGetProperties(this, property)); } return properties; } @Override public final <T extends InventoryProperty<?, ?>> Collection<T> getProperties(Inventory child, Class<T> property) { return getPropertiesBuilder(child, property).build(); } <T extends InventoryProperty<?, ?>> ImmutableList.Builder<T> getPropertiesBuilder(Inventory child, Class<T> property) { checkNotNull(child, "child"); checkNotNull(property, "property"); final ImmutableList.Builder<T> properties = ImmutableList.builder(); //noinspection unchecked properties.addAll(tryGetProperties(child, property)); properties.addAll(((AbstractInventory) child).tryGetProperties(property)); return properties; } @Override public <T extends InventoryProperty<?, ?>> Optional<T> getProperty(Class<T> property, @Nullable Object key) { checkNotNull(property, "property"); final AbstractInventory parent = parent(); if (parent != this) { final Optional<T> optProperty = parent.tryGetProperty(this, property, key); if (optProperty.isPresent()) { return optProperty; } } return tryGetProperty(property, key); } @Override public <T extends InventoryProperty<?, ?>> Optional<T> getProperty(Inventory child, Class<T> property, @Nullable Object key) { checkNotNull(child, "child"); checkNotNull(property, "property"); Optional<T> optProperty = tryGetProperty(child, property, key); if (!optProperty.isPresent()) { //noinspection unchecked optProperty = ((AbstractInventory) child).tryGetProperty(property, key); } return optProperty; } protected <T extends InventoryProperty<?, ?>> Optional<T> tryGetProperty(Class<T> property, @Nullable Object key) { if (property == InventoryTitle.class) { //noinspection unchecked return Optional.of((T) new InventoryTitle(Text.of(this.getName()))); } else if (property == InventoryCapacity.class) { //noinspection unchecked return Optional.of((T) new InventoryCapacity(this.capacity())); } return Optional.empty(); } protected <T extends InventoryProperty<?, ?>> List<T> tryGetProperties(Class<T> property) { final List<T> properties = new ArrayList<>(); if (property == InventoryTitle.class) { //noinspection unchecked properties.add((T) new InventoryTitle(Text.of(this.getName()))); } else if (property == InventoryCapacity.class) { //noinspection unchecked properties.add((T) new InventoryCapacity(this.capacity())); } return properties; } protected <T extends InventoryProperty<?, ?>> Optional<T> tryGetProperty(Inventory child, Class<T> property, @Nullable Object key) { return Optional.empty(); } protected <T extends InventoryProperty<?, ?>> List<T> tryGetProperties(Inventory child, Class<T> property) { return new ArrayList<>(); } void addViewer(Viewer viewer, LanternContainer container) { } void removeViewer(Viewer viewer, LanternContainer container) { } }