mirror of
https://github.com/Minestom/Minestom.git
synced 2025-03-13 07:09:51 +01:00
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).
|
||||
* <p>
|
||||
* Does nothing if the item cannot be fully added.
|
||||
*
|
||||
* @param itemStack the item to add
|
||||
* @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<>();
|
||||
|
||||
final StackingRule stackingRule = itemStack.getStackingRule();
|
||||
@ -96,81 +94,35 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo
|
||||
break;
|
||||
}
|
||||
|
||||
if (itemStack.isAir()) {
|
||||
// Item can be fully placed inside the inventory, do so
|
||||
itemChangesMap.forEach(this::safeItemInsert);
|
||||
return true;
|
||||
} else {
|
||||
// Inventory cannot accept the item fully
|
||||
return false;
|
||||
}
|
||||
return fillOption.fill(this, itemStack, itemChangesMap);
|
||||
}
|
||||
|
||||
public synchronized boolean addItemStack(@NotNull ItemStack itemStack) {
|
||||
return addItemStack(itemStack, FillOption.ALL_OR_NOTHING);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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) {
|
||||
List<ItemStack> result = new ArrayList<>();
|
||||
public <T> @NotNull List<T> addItemStacks(@NotNull List<ItemStack> itemStacks, @NotNull FillOption<T> fillOption) {
|
||||
List<T> result = new ArrayList<>(itemStacks.size());
|
||||
itemStacks.forEach(itemStack -> {
|
||||
if (!addItemStack(itemStack)) {
|
||||
result.add(itemStack);
|
||||
}
|
||||
T fillResult = addItemStack(itemStack, fillOption);
|
||||
result.add(fillResult);
|
||||
});
|
||||
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).
|
||||
* <p>
|
||||
* Even the item cannot be fully taken, the amount of {@code itemStack} will be updated.
|
||||
*
|
||||
* @param itemStack the item to take
|
||||
* @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<>();
|
||||
final StackingRule stackingRule = itemStack.getStackingRule();
|
||||
for (int i = 0; i < getInnerSize(); i++) {
|
||||
@ -195,68 +147,24 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo
|
||||
}
|
||||
}
|
||||
|
||||
if (itemStack.isAir()) {
|
||||
// Item can be fully taken from the inventory, do so
|
||||
itemChangesMap.forEach(this::safeItemInsert);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return fillOption.fill(this, itemStack, itemChangesMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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) {
|
||||
List<ItemStack> result = new ArrayList<>();
|
||||
public <T> @NotNull List<T> takeItemStacks(@NotNull List<ItemStack> itemStacks, @NotNull FillOption<T> fillOption) {
|
||||
List<T> result = new ArrayList<>(itemStacks.size());
|
||||
itemStacks.forEach(itemStack -> {
|
||||
if (!takeItemStack(itemStack)) {
|
||||
result.add(itemStack);
|
||||
}
|
||||
T fillResult = takeItemStack(itemStack, fillOption);
|
||||
result.add(fillResult);
|
||||
});
|
||||
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) {
|
||||
var currentItem = getItemStack(slot);
|
||||
setItemStack(slot, operator.apply(currentItem));
|
||||
|
32
src/main/java/net/minestom/server/inventory/FillOption.java
Normal file
32
src/main/java/net/minestom/server/inventory/FillOption.java
Normal file
@ -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 SummonCommand());
|
||||
commandManager.register(new RemoveCommand());
|
||||
commandManager.register(new GiveCommand());
|
||||
|
||||
commandManager.setUnknownCommandCallback((sender, command) -> sender.sendMessage(Component.text("Unknown command", NamedTextColor.RED)));
|
||||
|
||||
|
56
src/test/java/demo/commands/GiveCommand.java
Normal file
56
src/test/java/demo/commands/GiveCommand.java
Normal file
@ -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
Block a user