mirror of https://github.com/Minestom/Minestom.git
WIP FillOption
This commit is contained in:
parent
c7cd8c332a
commit
d86a733b79
|
@ -52,13 +52,11 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an {@link ItemStack} to the inventory and sends relevant update to the viewer(s).
|
* Adds an {@link ItemStack} to the inventory and sends relevant update to the viewer(s).
|
||||||
* <p>
|
|
||||||
* Does nothing if the item cannot be fully added.
|
|
||||||
*
|
*
|
||||||
* @param itemStack the item to add
|
* @param itemStack the item to add
|
||||||
* @return true if the item has been successfully added, false otherwise
|
* @return true if the item has been successfully added, false otherwise
|
||||||
*/
|
*/
|
||||||
public synchronized boolean addItemStack(@NotNull ItemStack itemStack) {
|
public synchronized <T> T addItemStack(@NotNull ItemStack itemStack, FillOption<T> fillOption) {
|
||||||
Int2ObjectMap<ItemStack> itemChangesMap = new Int2ObjectOpenHashMap<>();
|
Int2ObjectMap<ItemStack> itemChangesMap = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
final StackingRule stackingRule = itemStack.getStackingRule();
|
final StackingRule stackingRule = itemStack.getStackingRule();
|
||||||
|
@ -96,81 +94,35 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemStack.isAir()) {
|
return fillOption.fill(this, itemStack, itemChangesMap);
|
||||||
// Item can be fully placed inside the inventory, do so
|
}
|
||||||
itemChangesMap.forEach(this::safeItemInsert);
|
|
||||||
return true;
|
public synchronized boolean addItemStack(@NotNull ItemStack itemStack) {
|
||||||
} else {
|
return addItemStack(itemStack, FillOption.ALL_OR_NOTHING);
|
||||||
// Inventory cannot accept the item fully
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds {@link ItemStack}s to the inventory and sends relevant updates to the viewer(s).
|
* Adds {@link ItemStack}s to the inventory and sends relevant updates to the viewer(s).
|
||||||
* <p>
|
|
||||||
* Does nothing if the item cannot be fully added.
|
|
||||||
*
|
*
|
||||||
* @param itemStacks items to add
|
* @param itemStacks items to add
|
||||||
* @return list of items that could not be successfully added, empty list otherwise
|
* @return the operation results
|
||||||
*/
|
*/
|
||||||
public @NotNull List<ItemStack> addItemStacks(@NotNull List<ItemStack> itemStacks) {
|
public <T> @NotNull List<T> addItemStacks(@NotNull List<ItemStack> itemStacks, @NotNull FillOption<T> fillOption) {
|
||||||
List<ItemStack> result = new ArrayList<>();
|
List<T> result = new ArrayList<>(itemStacks.size());
|
||||||
itemStacks.forEach(itemStack -> {
|
itemStacks.forEach(itemStack -> {
|
||||||
if (!addItemStack(itemStack)) {
|
T fillResult = addItemStack(itemStack, fillOption);
|
||||||
result.add(itemStack);
|
result.add(fillResult);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether {@link ItemStack} can be fully added to the inventory.
|
|
||||||
*
|
|
||||||
* @param itemStack the item to be checked
|
|
||||||
* @return true if the item can be fully added to the inventory, false otherwise
|
|
||||||
*/
|
|
||||||
public boolean canAddItemStack(@NotNull ItemStack itemStack) {
|
|
||||||
final StackingRule stackingRule = itemStack.getStackingRule();
|
|
||||||
int amountLeft = stackingRule.getAmount(itemStack);
|
|
||||||
for (int i = 0; i < getInnerSize(); i++) {
|
|
||||||
ItemStack inventoryItem = getItemStack(i);
|
|
||||||
if (stackingRule.canBeStacked(itemStack, inventoryItem)) {
|
|
||||||
final int itemAmount = stackingRule.getAmount(inventoryItem);
|
|
||||||
if (itemAmount == stackingRule.getMaxSize())
|
|
||||||
continue;
|
|
||||||
if (!stackingRule.canApply(itemStack, amountLeft + itemAmount)) {
|
|
||||||
// Slot cannot accept the whole item, reduce amount to 'itemStack'
|
|
||||||
amountLeft -= stackingRule.getMaxSize() - itemAmount;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else if (inventoryItem.isAir()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether {@link ItemStack}s can be fully added to the inventory.
|
|
||||||
*
|
|
||||||
* @param itemStacks items to be checked
|
|
||||||
* @return true if all the items can be fully added to the inventory, false otherwise
|
|
||||||
*/
|
|
||||||
public boolean canAddItemStacks(@NotNull List<ItemStack> itemStacks) {
|
|
||||||
return itemStacks.stream().allMatch(this::canAddItemStack);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes an {@link ItemStack} from the inventory and sends relevant update to the viewer(s).
|
* Takes an {@link ItemStack} from the inventory and sends relevant update to the viewer(s).
|
||||||
* <p>
|
|
||||||
* Even the item cannot be fully taken, the amount of {@code itemStack} will be updated.
|
|
||||||
*
|
*
|
||||||
* @param itemStack the item to take
|
* @param itemStack the item to take
|
||||||
* @return true if the item has been successfully fully taken, false otherwise
|
* @return true if the item has been successfully fully taken, false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean takeItemStack(@NotNull ItemStack itemStack) {
|
public <T> T takeItemStack(@NotNull ItemStack itemStack, @NotNull FillOption<T> fillOption) {
|
||||||
Int2ObjectMap<ItemStack> itemChangesMap = new Int2ObjectOpenHashMap<>();
|
Int2ObjectMap<ItemStack> itemChangesMap = new Int2ObjectOpenHashMap<>();
|
||||||
final StackingRule stackingRule = itemStack.getStackingRule();
|
final StackingRule stackingRule = itemStack.getStackingRule();
|
||||||
for (int i = 0; i < getInnerSize(); i++) {
|
for (int i = 0; i < getInnerSize(); i++) {
|
||||||
|
@ -195,68 +147,24 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemStack.isAir()) {
|
return fillOption.fill(this, itemStack, itemChangesMap);
|
||||||
// Item can be fully taken from the inventory, do so
|
|
||||||
itemChangesMap.forEach(this::safeItemInsert);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes {@link ItemStack}s from the inventory and sends relevant updates to the viewer(s).
|
* Takes {@link ItemStack}s from the inventory and sends relevant updates to the viewer(s).
|
||||||
* <p>
|
|
||||||
* Even items cannot be fully taken, the amount of {@code itemStack}s will be updated.
|
|
||||||
*
|
*
|
||||||
* @param itemStacks items to take
|
* @param itemStacks items to take
|
||||||
* @return list of itemstacks that could not be successfully fully taken, empty list otherwise
|
* @return the operation results
|
||||||
*/
|
*/
|
||||||
public @NotNull List<ItemStack> takeItemStacks(@NotNull List<ItemStack> itemStacks) {
|
public <T> @NotNull List<T> takeItemStacks(@NotNull List<ItemStack> itemStacks, @NotNull FillOption<T> fillOption) {
|
||||||
List<ItemStack> result = new ArrayList<>();
|
List<T> result = new ArrayList<>(itemStacks.size());
|
||||||
itemStacks.forEach(itemStack -> {
|
itemStacks.forEach(itemStack -> {
|
||||||
if (!takeItemStack(itemStack)) {
|
T fillResult = takeItemStack(itemStack, fillOption);
|
||||||
result.add(itemStack);
|
result.add(fillResult);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether {@link ItemStack} can be fully taken from the inventory.
|
|
||||||
*
|
|
||||||
* @param itemStack the item to be checked
|
|
||||||
* @return true if the item can be fully taken from the inventory, false otherwise
|
|
||||||
*/
|
|
||||||
public boolean canTakeItemStack(@NotNull ItemStack itemStack) {
|
|
||||||
final StackingRule stackingRule = itemStack.getStackingRule();
|
|
||||||
int amountLeft = stackingRule.getAmount(itemStack);
|
|
||||||
for (int i = 0; i < getInnerSize(); i++) {
|
|
||||||
ItemStack inventoryItem = getItemStack(i);
|
|
||||||
if (inventoryItem.isAir()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (stackingRule.canBeStacked(itemStack, inventoryItem)) {
|
|
||||||
final int itemAmount = stackingRule.getAmount(inventoryItem);
|
|
||||||
if (amountLeft <= itemAmount) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
amountLeft -= itemAmount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether {@link ItemStack}s can be fully taken from the inventory.
|
|
||||||
*
|
|
||||||
* @param itemStacks items to be checked
|
|
||||||
* @return true if all the items can be fully taken from the inventory, false otherwise
|
|
||||||
*/
|
|
||||||
public boolean canTakeItemStacks(@NotNull List<ItemStack> itemStacks) {
|
|
||||||
return itemStacks.stream().allMatch(this::canTakeItemStack);
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) {
|
public synchronized void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) {
|
||||||
var currentItem = getItemStack(slot);
|
var currentItem = getItemStack(slot);
|
||||||
setItemStack(slot, operator.apply(currentItem));
|
setItemStack(slot, operator.apply(currentItem));
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
package net.minestom.server.inventory;
|
||||||
|
|
||||||
|
import net.minestom.server.item.ItemStack;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface FillOption<T> {
|
||||||
|
|
||||||
|
FillOption<ItemStack> ALL = (inventory, result, itemChangesMap) -> {
|
||||||
|
itemChangesMap.forEach(inventory::safeItemInsert);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
FillOption<Boolean> ALL_OR_NOTHING = (inventory, result, itemChangesMap) -> {
|
||||||
|
if (result.isAir()) {
|
||||||
|
// Item can be fully placed inside the inventory, do so
|
||||||
|
itemChangesMap.forEach(inventory::safeItemInsert);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// Inventory cannot accept the item fully
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
FillOption<Boolean> DRY_RUN = (inventory, result, itemChangesMap) -> !result.isAir();
|
||||||
|
|
||||||
|
T fill(@NotNull AbstractInventory inventory,
|
||||||
|
@NotNull ItemStack result,
|
||||||
|
@NotNull Map<@NotNull Integer, @NotNull ItemStack> itemChangesMap);
|
||||||
|
}
|
|
@ -49,6 +49,7 @@ public class Main {
|
||||||
commandManager.register(new EchoCommand());
|
commandManager.register(new EchoCommand());
|
||||||
commandManager.register(new SummonCommand());
|
commandManager.register(new SummonCommand());
|
||||||
commandManager.register(new RemoveCommand());
|
commandManager.register(new RemoveCommand());
|
||||||
|
commandManager.register(new GiveCommand());
|
||||||
|
|
||||||
commandManager.setUnknownCommandCallback((sender, command) -> sender.sendMessage(Component.text("Unknown command", NamedTextColor.RED)));
|
commandManager.setUnknownCommandCallback((sender, command) -> sender.sendMessage(Component.text("Unknown command", NamedTextColor.RED)));
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
package demo.commands;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.minestom.server.command.builder.Command;
|
||||||
|
import net.minestom.server.entity.Entity;
|
||||||
|
import net.minestom.server.entity.Player;
|
||||||
|
import net.minestom.server.inventory.FillOption;
|
||||||
|
import net.minestom.server.item.ItemStack;
|
||||||
|
import net.minestom.server.utils.entity.EntityFinder;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static net.minestom.server.command.builder.arguments.ArgumentType.Integer;
|
||||||
|
import static net.minestom.server.command.builder.arguments.ArgumentType.*;
|
||||||
|
|
||||||
|
public class GiveCommand extends Command {
|
||||||
|
public GiveCommand() {
|
||||||
|
super("give");
|
||||||
|
|
||||||
|
setDefaultExecutor((sender, context) ->
|
||||||
|
sender.sendMessage(Component.text("Usage: /give <target> <item> [<count>]")));
|
||||||
|
|
||||||
|
addSyntax((sender, context) -> {
|
||||||
|
final EntityFinder entityFinder = context.get("target");
|
||||||
|
int count = context.get("count");
|
||||||
|
ItemStack itemStack = context.get("item");
|
||||||
|
|
||||||
|
List<ItemStack> itemStacks;
|
||||||
|
if (count <= 64) {
|
||||||
|
itemStack = itemStack.withAmount(count);
|
||||||
|
itemStacks = Collections.singletonList(itemStack);
|
||||||
|
} else {
|
||||||
|
itemStacks = new ArrayList<>();
|
||||||
|
while (count > 64) {
|
||||||
|
itemStacks.add(itemStack.withAmount(64));
|
||||||
|
count -= 64;
|
||||||
|
}
|
||||||
|
itemStacks.add(itemStack.withAmount(count));
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<Entity> targets = entityFinder.find(sender);
|
||||||
|
for (Entity target : targets) {
|
||||||
|
if (target instanceof Player) {
|
||||||
|
Player player = (Player) target;
|
||||||
|
player.getInventory().addItemStacks(itemStacks, FillOption.ALL_OR_NOTHING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sender.sendMessage(Component.text("Items have been given successfully!"));
|
||||||
|
|
||||||
|
}, Entity("target").onlyPlayers(true), ItemStack("item"), Integer("count").setDefaultValue(() -> 1));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue