Refactor and fix multiple required items

This commit is contained in:
filoghost 2020-08-06 18:43:10 +02:00
parent 134e996c6c
commit 4a5c06398f
6 changed files with 150 additions and 71 deletions

View File

@ -20,11 +20,11 @@ import me.filoghost.chestcommands.action.OpenMenuAction;
import me.filoghost.chestcommands.api.ClickResult;
import me.filoghost.chestcommands.api.MenuInventory;
import me.filoghost.chestcommands.icon.requirement.RequiredExpLevel;
import me.filoghost.chestcommands.icon.requirement.RequiredItem;
import me.filoghost.chestcommands.icon.requirement.RequiredItems;
import me.filoghost.chestcommands.icon.requirement.RequiredMoney;
import me.filoghost.chestcommands.icon.requirement.RequiredPermission;
import me.filoghost.chestcommands.icon.requirement.Requirement;
import me.filoghost.chestcommands.icon.requirement.item.RequiredItem;
import me.filoghost.chestcommands.icon.requirement.item.RequiredItems;
import me.filoghost.chestcommands.util.Preconditions;
import me.filoghost.chestcommands.util.collection.CollectionUtils;
import org.bukkit.Material;

View File

@ -0,0 +1,79 @@
package me.filoghost.chestcommands.icon.requirement.item;
import me.filoghost.chestcommands.util.MaterialsHelper;
import me.filoghost.chestcommands.util.Preconditions;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
public class InventoryTakeHelper {
private final PlayerInventory inventory;
private final List<RemainingItem> remainingItems;
private boolean success;
public InventoryTakeHelper(PlayerInventory inventory) {
this.inventory = inventory;
this.remainingItems = new ArrayList<>();
for (int slotIndex = 0; slotIndex < inventory.getSize(); slotIndex++) {
ItemStack item = inventory.getItem(slotIndex);
if (item != null && !MaterialsHelper.isAir(item.getType())) {
remainingItems.add(new RemainingItem(slotIndex, item));
}
}
}
public List<RequiredItem> prepareTakeItems(List<RequiredItem> requiredItems) {
List<RequiredItem> missingItems = new ArrayList<>();
// Sort required items: check required items with a restrictive durability first
List<RequiredItem> sortedRequiredItems = requiredItems.stream()
.sorted(Comparator.comparing(RequiredItem::hasRestrictiveDurability).reversed())
.collect(Collectors.toList());
for (RequiredItem requiredItem : sortedRequiredItems) {
int remainingRequiredAmount = requiredItem.getAmount();
for (RemainingItem remainingItem : remainingItems) {
if (remainingItem.getAmount() > 0 && requiredItem.isMatchingType(remainingItem)) {
int takenAmount = remainingItem.subtract(remainingRequiredAmount);
remainingRequiredAmount -= takenAmount;
if (remainingRequiredAmount == 0) {
break;
}
}
}
// Couldn't take the required amount of an item
if (remainingRequiredAmount > 0) {
missingItems.add(requiredItem);
}
}
success = missingItems.isEmpty();
return missingItems;
}
public void applyTakeItems() {
Preconditions.checkState(success, "items take preparation was not run or successful");
for (RemainingItem remainingItem : remainingItems) {
int slotIndex = remainingItem.getSlotIndex();
ItemStack inventoryItem = inventory.getItem(slotIndex);
if (remainingItem.getAmount() != inventoryItem.getAmount()) {
if (remainingItem.getAmount() > 0) {
inventoryItem.setAmount(remainingItem.getAmount());
} else {
inventory.setItem(slotIndex, null);
}
}
}
}
}

View File

@ -0,0 +1,43 @@
package me.filoghost.chestcommands.icon.requirement.item;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
public class RemainingItem {
private final int slotIndex;
private final Material material;
private final short durability;
private int amount;
public RemainingItem(int slotIndex, ItemStack item) {
this.slotIndex = slotIndex;
this.material = item.getType();
this.durability = item.getDurability();
this.amount = item.getAmount();
}
public int getSlotIndex() {
return slotIndex;
}
public Material getMaterial() {
return material;
}
public short getDurability() {
return durability;
}
public int getAmount() {
return amount;
}
public int subtract(int minusAmount) {
int subtractedAmount = Math.min(minusAmount, this.amount);
this.amount -= subtractedAmount;
return subtractedAmount;
}
}

View File

@ -12,12 +12,10 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package me.filoghost.chestcommands.icon.requirement;
package me.filoghost.chestcommands.icon.requirement.item;
import me.filoghost.chestcommands.util.Preconditions;
import org.bukkit.Material;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
public class RequiredItem {
@ -56,55 +54,16 @@ public class RequiredItem {
return isDurabilityRestrictive;
}
public boolean isItemContainedIn(Inventory inventory) {
int amountFound = 0;
for (ItemStack item : inventory.getContents()) {
if (isMatchingType(item)) {
amountFound += item.getAmount();
}
}
return amountFound >= amount;
}
public boolean takeItemFrom(Inventory inventory) {
if (amount <= 0) {
return true;
}
int itemsToTake = amount; // Start from amount and decrease
ItemStack[] contents = inventory.getContents();
for (int i = 0; i < contents.length; i++) {
ItemStack current = contents[i];
if (isMatchingType(current)) {
if (current.getAmount() > itemsToTake) {
current.setAmount(current.getAmount() - itemsToTake);
return true;
} else {
itemsToTake -= current.getAmount();
inventory.setItem(i, new ItemStack(Material.AIR));
}
}
// The end
if (itemsToTake <= 0) return true;
}
return false;
}
private boolean isMatchingType(ItemStack item) {
return item != null && item.getType() == material && isMatchingDurability(item.getDurability());
public boolean isMatchingType(RemainingItem item) {
return item != null && item.getMaterial() == material && isMatchingDurability(item.getDurability());
}
private boolean isMatchingDurability(short durability) {
if (!isDurabilityRestrictive) {
if (isDurabilityRestrictive) {
return this.durability == durability;
} else {
return true;
}
return this.durability == durability;
}
}

View File

@ -12,10 +12,11 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package me.filoghost.chestcommands.icon.requirement;
package me.filoghost.chestcommands.icon.requirement.item;
import com.google.common.collect.ImmutableList;
import me.filoghost.chestcommands.ChestCommands;
import me.filoghost.chestcommands.icon.requirement.Requirement;
import me.filoghost.chestcommands.util.Utils;
import org.bukkit.entity.Player;
@ -31,34 +32,31 @@ public class RequiredItems implements Requirement {
@Override
public boolean hasCost(Player player) {
boolean missingItems = false;
for (RequiredItem item : items) {
if (!item.isItemContainedIn(player.getInventory())) {
missingItems = true;
player.sendMessage(ChestCommands.getLang().no_required_item
.replace("{material}", Utils.formatEnum(item.getMaterial()))
.replace("{amount}", Integer.toString(item.getAmount()))
.replace("{durability}", item.hasRestrictiveDurability() ? Short.toString(item.getDurability()) : ChestCommands.getLang().any)
);
}
InventoryTakeHelper inventoryTakeHelper = new InventoryTakeHelper(player.getInventory());
List<RequiredItem> missingItems = inventoryTakeHelper.prepareTakeItems(items);
for (RequiredItem item : missingItems) {
player.sendMessage(ChestCommands.getLang().no_required_item
.replace("{material}", Utils.formatEnum(item.getMaterial()))
.replace("{amount}", Integer.toString(item.getAmount()))
.replace("{durability}", item.hasRestrictiveDurability() ? Short.toString(item.getDurability()) : ChestCommands.getLang().any)
);
}
return !missingItems;
return missingItems.isEmpty();
}
@Override
public boolean takeCost(Player player) {
boolean missingItems = false;
for (RequiredItem item : items) {
boolean success = item.takeItemFrom(player.getInventory());
if (!success) {
missingItems = true;
}
InventoryTakeHelper inventoryTakeHelper = new InventoryTakeHelper(player.getInventory());
List<RequiredItem> missingItems = inventoryTakeHelper.prepareTakeItems(items);
if (!missingItems.isEmpty()) {
return false;
}
return !missingItems;
inventoryTakeHelper.applyTakeItems();
return true;
}
}

View File

@ -15,7 +15,7 @@
package me.filoghost.chestcommands.parsing.attribute;
import me.filoghost.chestcommands.icon.InternalConfigurableIcon;
import me.filoghost.chestcommands.icon.requirement.RequiredItem;
import me.filoghost.chestcommands.icon.requirement.item.RequiredItem;
import me.filoghost.chestcommands.parsing.ItemStackParser;
import me.filoghost.chestcommands.parsing.ParseException;