mirror of
https://github.com/Minestom/Minestom.git
synced 2024-10-31 15:59:35 +01:00
Store all processors in ClickProcessors
This commit is contained in:
parent
17d907305f
commit
447475c44e
@ -7,6 +7,7 @@ import net.minestom.server.event.inventory.InventoryClickEvent;
|
||||
import net.minestom.server.event.inventory.InventoryPostClickEvent;
|
||||
import net.minestom.server.event.inventory.InventoryPreClickEvent;
|
||||
import net.minestom.server.inventory.click.Click;
|
||||
import net.minestom.server.inventory.click.ClickProcessors;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.network.packet.server.play.OpenWindowPacket;
|
||||
import net.minestom.server.network.packet.server.play.WindowPropertyPacket;
|
||||
@ -14,7 +15,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
/**
|
||||
* Represents an inventory which can be viewed by a collection of {@link Player}.
|
||||
@ -26,12 +26,14 @@ public non-sealed class ContainerInventory extends InventoryImpl {
|
||||
|
||||
/**
|
||||
* Processes a click, returning a result. This will call events for the click.
|
||||
*
|
||||
* @param inventory the clicked inventory (could be a player inventory)
|
||||
* @param player the player who clicked
|
||||
* @param info the click info describing the click
|
||||
* @param player the player who clicked
|
||||
* @param info the click info describing the click
|
||||
* @return the click result, or null if the click did not occur
|
||||
*/
|
||||
public static @Nullable Click.Result handleClick(@NotNull Inventory inventory, @NotNull Player player, @NotNull Click.Info info, @NotNull BiFunction<Click.@NotNull Info, Click.@NotNull Getter, Click.@NotNull Result> processor) {
|
||||
public static @Nullable Click.Result handleClick(@NotNull Inventory inventory, @NotNull Player player, @NotNull Click.Info info,
|
||||
@NotNull ClickProcessors.InventoryProcessor processor) {
|
||||
PlayerInventory playerInventory = player.getInventory();
|
||||
|
||||
InventoryPreClickEvent preClickEvent = new InventoryPreClickEvent(playerInventory, inventory, player, info);
|
||||
@ -141,6 +143,12 @@ public non-sealed class ContainerInventory extends InventoryImpl {
|
||||
update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Click.Result handleClick(@NotNull Player player, Click.@NotNull Info info) {
|
||||
return ContainerInventory.handleClick(this, player, info,
|
||||
ClickProcessors.PROCESSORS_MAP.getOrDefault(inventoryType, ClickProcessors.GENERIC_PROCESSOR));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getWindowId() {
|
||||
return id;
|
||||
|
@ -3,8 +3,6 @@ package net.minestom.server.inventory;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.event.EventDispatcher;
|
||||
import net.minestom.server.event.inventory.InventoryItemChangeEvent;
|
||||
import net.minestom.server.inventory.click.Click;
|
||||
import net.minestom.server.inventory.click.ClickProcessors;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.network.packet.server.play.CloseWindowPacket;
|
||||
import net.minestom.server.network.packet.server.play.SetSlotPacket;
|
||||
@ -13,7 +11,6 @@ import net.minestom.server.tag.TagHandler;
|
||||
import net.minestom.server.utils.MathUtils;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
@ -110,19 +107,6 @@ sealed abstract class InventoryImpl implements Inventory permits ContainerInvent
|
||||
player.sendPacket(new WindowItemsPacket(getWindowId(), 0, List.of(itemStacks), player.getInventory().getCursorItem()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Click.Result handleClick(@NotNull Player player, @NotNull Click.Info info) {
|
||||
var processor = ClickProcessors.standard(
|
||||
(builder, item, slot) -> slot >= getSize() ?
|
||||
IntStream.range(0, getSize()) :
|
||||
PlayerInventory.getInnerShiftClickSlots(getSize()),
|
||||
(builder, item, slot) -> IntStream.concat(
|
||||
IntStream.range(0, getSize()),
|
||||
PlayerInventory.getInnerDoubleClickSlots(getSize())
|
||||
));
|
||||
return ContainerInventory.handleClick(this, player, info, processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack getItemStack(int slot) {
|
||||
return (ItemStack) ITEM_UPDATER.getVolatile(itemStacks, slot);
|
||||
@ -168,7 +152,6 @@ sealed abstract class InventoryImpl implements Inventory permits ContainerInvent
|
||||
*/
|
||||
protected final void safeItemInsert(int slot, @NotNull ItemStack itemStack, boolean sendPacket) {
|
||||
lock.lock();
|
||||
|
||||
try {
|
||||
ItemStack previous = itemStacks[slot];
|
||||
if (itemStack.equals(previous)) return; // Avoid sending updates if the item has not changed
|
||||
@ -189,7 +172,6 @@ sealed abstract class InventoryImpl implements Inventory permits ContainerInvent
|
||||
@Override
|
||||
public void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) {
|
||||
lock.lock();
|
||||
|
||||
try {
|
||||
var currentItem = getItemStack(slot);
|
||||
setItemStack(slot, operator.apply(currentItem));
|
||||
@ -201,12 +183,10 @@ sealed abstract class InventoryImpl implements Inventory permits ContainerInvent
|
||||
@Override
|
||||
public void clear() {
|
||||
lock.lock();
|
||||
|
||||
try {
|
||||
for (Player viewer : getViewers()) {
|
||||
viewer.getInventory().setCursorItem(ItemStack.AIR, false);
|
||||
}
|
||||
|
||||
// Clear the item array
|
||||
for (int i = 0; i < size; i++) {
|
||||
safeItemInsert(i, ItemStack.AIR, false);
|
||||
@ -294,5 +274,4 @@ sealed abstract class InventoryImpl implements Inventory permits ContainerInvent
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,15 +7,12 @@ import net.minestom.server.event.item.EntityEquipEvent;
|
||||
import net.minestom.server.inventory.click.Click;
|
||||
import net.minestom.server.inventory.click.ClickProcessors;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.network.packet.server.play.SetSlotPacket;
|
||||
import net.minestom.server.network.packet.server.play.WindowItemsPacket;
|
||||
import net.minestom.server.utils.inventory.PlayerInventoryUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
@ -171,42 +168,7 @@ public non-sealed class PlayerInventory extends InventoryImpl {
|
||||
|
||||
@Override
|
||||
public @Nullable Click.Result handleClick(@NotNull Player player, @NotNull Click.Info info) {
|
||||
var processor = ClickProcessors.standard(
|
||||
(getter, item, slot) -> {
|
||||
List<Integer> slots = new ArrayList<>();
|
||||
|
||||
final EquipmentSlot equipmentSlot = item.material().registry().equipmentSlot();
|
||||
if (equipmentSlot != null && slot != equipmentSlot.armorSlot()) {
|
||||
slots.add(equipmentSlot.armorSlot());
|
||||
}
|
||||
|
||||
if (item.material() == Material.SHIELD && slot != OFF_HAND_SLOT) {
|
||||
slots.add(OFF_HAND_SLOT);
|
||||
}
|
||||
|
||||
if (slot < 9 || slot > 35) {
|
||||
IntStream.range(9, 36).forEach(slots::add);
|
||||
}
|
||||
|
||||
if (slot < 0 || slot > 8) {
|
||||
IntStream.range(0, 9).forEach(slots::add);
|
||||
}
|
||||
|
||||
if (slot == CRAFT_RESULT) {
|
||||
Collections.reverse(slots);
|
||||
}
|
||||
|
||||
return slots.stream().mapToInt(i -> i);
|
||||
},
|
||||
(getter, item, slot) -> Stream.of(
|
||||
IntStream.range(CRAFT_SLOT_1, CRAFT_SLOT_4 + 1), // 1-4
|
||||
IntStream.range(HELMET_SLOT, BOOTS_SLOT + 1), // 5-8
|
||||
IntStream.range(9, 36), // 9-35
|
||||
IntStream.range(0, 9), // 36-44
|
||||
IntStream.of(OFF_HAND_SLOT) // 45
|
||||
).flatMapToInt(i -> i)
|
||||
);
|
||||
return ContainerInventory.handleClick(this, player, info, processor);
|
||||
return ContainerInventory.handleClick(this, player, info, ClickProcessors.PLAYER_PROCESSOR);
|
||||
}
|
||||
|
||||
public @NotNull ItemStack getEquipment(@NotNull EquipmentSlot slot, int heldSlot) {
|
||||
|
@ -1,18 +1,27 @@
|
||||
package net.minestom.server.inventory.click;
|
||||
|
||||
import it.unimi.dsi.fastutil.Pair;
|
||||
import net.minestom.server.entity.EquipmentSlot;
|
||||
import net.minestom.server.inventory.InventoryType;
|
||||
import net.minestom.server.inventory.PlayerInventory;
|
||||
import net.minestom.server.inventory.TransactionOperator;
|
||||
import net.minestom.server.inventory.TransactionType;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.item.StackingRule;
|
||||
import net.minestom.server.utils.inventory.PlayerInventoryUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.Map.entry;
|
||||
import static net.minestom.server.utils.inventory.PlayerInventoryUtils.*;
|
||||
|
||||
/**
|
||||
* Provides standard implementations of most click functions.
|
||||
@ -151,14 +160,17 @@ public final class ClickProcessors {
|
||||
* @param shiftClickSlots the shift click slot supplier
|
||||
* @param doubleClickSlots the double click slot supplier
|
||||
*/
|
||||
public static @NotNull BiFunction<Click.@NotNull Info, Click.@NotNull Getter, Click.@NotNull Result> standard(@NotNull SlotSuggestor shiftClickSlots, @NotNull SlotSuggestor doubleClickSlots) {
|
||||
public static ClickProcessors.@NotNull InventoryProcessor standard(@NotNull SlotSuggestor shiftClickSlots, @NotNull SlotSuggestor doubleClickSlots) {
|
||||
return (info, getter) -> switch (info) {
|
||||
case Click.Info.Left(int slot) -> leftClick(slot, getter);
|
||||
case Click.Info.Right(int slot) -> rightClick(slot, getter);
|
||||
case Click.Info.Middle(int slot) -> middleClick(slot, getter);
|
||||
case Click.Info.LeftShift(int slot) -> shiftClick(slot, shiftClickSlots.getList(getter, getter.get(slot), slot), getter);
|
||||
case Click.Info.RightShift(int slot) -> shiftClick(slot, shiftClickSlots.getList(getter, getter.get(slot), slot), getter);
|
||||
case Click.Info.Double(int slot) -> doubleClick(doubleClickSlots.getList(getter, getter.get(slot), slot), getter);
|
||||
case Click.Info.LeftShift(int slot) ->
|
||||
shiftClick(slot, shiftClickSlots.getList(getter, getter.get(slot), slot), getter);
|
||||
case Click.Info.RightShift(int slot) ->
|
||||
shiftClick(slot, shiftClickSlots.getList(getter, getter.get(slot), slot), getter);
|
||||
case Click.Info.Double(int slot) ->
|
||||
doubleClick(doubleClickSlots.getList(getter, getter.get(slot), slot), getter);
|
||||
case Click.Info.LeftDrag(List<Integer> slots) -> {
|
||||
int cursorAmount = RULE.getAmount(getter.cursor());
|
||||
int amount = (int) Math.floor(cursorAmount / (double) slots.size());
|
||||
@ -166,7 +178,8 @@ public final class ClickProcessors {
|
||||
}
|
||||
case Click.Info.RightDrag(List<Integer> slots) -> dragClick(1, slots, getter);
|
||||
case Click.Info.MiddleDrag(List<Integer> slots) -> middleDragClick(slots, getter);
|
||||
case Click.Info.DropSlot(int slot, boolean all) -> dropFromSlot(slot, all ? RULE.getAmount(getter.get(slot)) : 1, getter);
|
||||
case Click.Info.DropSlot(int slot, boolean all) ->
|
||||
dropFromSlot(slot, all ? RULE.getAmount(getter.get(slot)) : 1, getter);
|
||||
case Click.Info.LeftDropCursor() -> dropFromCursor(getter.cursor().amount(), getter);
|
||||
case Click.Info.RightDropCursor() -> dropFromCursor(1, getter);
|
||||
case Click.Info.MiddleDropCursor() -> Click.Result.NOTHING;
|
||||
@ -185,10 +198,14 @@ public final class ClickProcessors {
|
||||
yield getter.setter().setPlayer(PlayerInventoryUtils.OFF_HAND_SLOT, selectedItem).set(slot, offhandItem).build();
|
||||
}
|
||||
case Click.Info.CreativeSetItem(int slot, ItemStack item) -> getter.setter().set(slot, item).build();
|
||||
case Click.Info.CreativeDropItem(ItemStack item) -> getter.setter().sideEffects(new Click.SideEffect.DropFromPlayer(item)).build();
|
||||
case Click.Info.CreativeDropItem(ItemStack item) ->
|
||||
getter.setter().sideEffects(new Click.SideEffect.DropFromPlayer(item)).build();
|
||||
};
|
||||
}
|
||||
|
||||
public interface InventoryProcessor extends BiFunction<Click.Info, Click.Getter, Click.Result> {
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic interface for providing options for clicks like shift clicks and double clicks.<br>
|
||||
* This addresses the issue of certain click operations only being able to interact with certain slots: for example,
|
||||
@ -213,4 +230,89 @@ public final class ClickProcessors {
|
||||
return get(builder, item, slot).boxed().toList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle player inventory (without any container open).
|
||||
*/
|
||||
public static final InventoryProcessor PLAYER_PROCESSOR = ClickProcessors.standard(
|
||||
(getter, item, slot) -> {
|
||||
List<Integer> slots = new ArrayList<>();
|
||||
|
||||
final EquipmentSlot equipmentSlot = item.material().registry().equipmentSlot();
|
||||
if (equipmentSlot != null && slot != equipmentSlot.armorSlot()) {
|
||||
slots.add(equipmentSlot.armorSlot());
|
||||
}
|
||||
|
||||
if (item.material() == Material.SHIELD && slot != OFF_HAND_SLOT) {
|
||||
slots.add(OFF_HAND_SLOT);
|
||||
}
|
||||
|
||||
if (slot < 9 || slot > 35) IntStream.range(9, 36).forEach(slots::add);
|
||||
if (slot < 0 || slot > 8) IntStream.range(0, 9).forEach(slots::add);
|
||||
|
||||
if (slot == CRAFT_RESULT) {
|
||||
Collections.reverse(slots);
|
||||
}
|
||||
|
||||
return slots.stream().mapToInt(i -> i);
|
||||
},
|
||||
(getter, item, slot) -> Stream.of(
|
||||
IntStream.range(CRAFT_SLOT_1, CRAFT_SLOT_4 + 1), // 1-4
|
||||
IntStream.range(HELMET_SLOT, BOOTS_SLOT + 1), // 5-8
|
||||
IntStream.range(9, 36), // 9-35
|
||||
IntStream.range(0, 9), // 36-44
|
||||
IntStream.of(OFF_HAND_SLOT) // 45
|
||||
).flatMapToInt(i -> i)
|
||||
);
|
||||
|
||||
/**
|
||||
* Assumes all the container's slots to be accessible.
|
||||
*/
|
||||
public static final InventoryProcessor GENERIC_PROCESSOR = ClickProcessors.standard(
|
||||
(builder, item, slot) -> {
|
||||
final int size = builder.mainSize();
|
||||
return slot >= size ?
|
||||
IntStream.range(0, size) :
|
||||
PlayerInventory.getInnerShiftClickSlots(size);
|
||||
},
|
||||
(builder, item, slot) -> {
|
||||
final int size = builder.mainSize();
|
||||
return IntStream.concat(
|
||||
IntStream.range(0, size),
|
||||
PlayerInventory.getInnerDoubleClickSlots(size)
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
// SPECIALIZED PROCESSORS DEFINITIONS
|
||||
|
||||
/**
|
||||
* Client prediction appears to disallow shift clicking into furnace inventories.<br>
|
||||
* Instead:
|
||||
* - Shift clicks in the inventory go to the player inventory like normal
|
||||
* - Shift clicks in the hotbar go to the storage
|
||||
* - Shift clicks in the storage go to the hotbar
|
||||
*/
|
||||
public static final InventoryProcessor FURNACE_PROCESSOR = ClickProcessors.standard(
|
||||
(builder, item, slot) -> {
|
||||
final int size = builder.mainSize();
|
||||
if (slot < size) {
|
||||
return PlayerInventory.getInnerShiftClickSlots(size);
|
||||
} else if (slot < size + 27) {
|
||||
return IntStream.range(27, 36).map(i -> i + size);
|
||||
} else {
|
||||
return IntStream.range(0, 27).map(i -> i + size);
|
||||
}
|
||||
},
|
||||
(builder, item, slot) -> {
|
||||
final int size = builder.mainSize();
|
||||
return IntStream.concat(
|
||||
IntStream.range(0, size),
|
||||
PlayerInventory.getInnerDoubleClickSlots(size)
|
||||
);
|
||||
});
|
||||
|
||||
public static final Map<InventoryType, InventoryProcessor> PROCESSORS_MAP = Map.ofEntries(
|
||||
entry(InventoryType.FURNACE, FURNACE_PROCESSOR)
|
||||
);
|
||||
}
|
||||
|
@ -1,16 +1,10 @@
|
||||
package net.minestom.server.inventory.type;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.inventory.ContainerInventory;
|
||||
import net.minestom.server.inventory.InventoryProperty;
|
||||
import net.minestom.server.inventory.InventoryType;
|
||||
import net.minestom.server.inventory.PlayerInventory;
|
||||
import net.minestom.server.inventory.click.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class FurnaceInventory extends ContainerInventory {
|
||||
|
||||
@ -27,32 +21,6 @@ public class FurnaceInventory extends ContainerInventory {
|
||||
super(InventoryType.FURNACE, title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Client prediction appears to disallow shift clicking into furnace inventories.<br>
|
||||
* Instead:
|
||||
* - Shift clicks in the inventory go to the player inventory like normal
|
||||
* - Shift clicks in the hotbar go to the storage
|
||||
* - Shift clicks in the storage go to the hotbar
|
||||
*/
|
||||
@Override
|
||||
public @Nullable Click.Result handleClick(@NotNull Player player, @NotNull Click.Info info) {
|
||||
var processor = ClickProcessors.standard(
|
||||
(builder, item, slot) -> {
|
||||
if (slot < getSize()) {
|
||||
return PlayerInventory.getInnerShiftClickSlots(getSize());
|
||||
} else if (slot < getSize() + 27) {
|
||||
return IntStream.range(27, 36).map(i -> i + getSize());
|
||||
} else {
|
||||
return IntStream.range(0, 27).map(i -> i + getSize());
|
||||
}
|
||||
},
|
||||
(builder, item, slot) -> IntStream.concat(
|
||||
IntStream.range(0, getSize()),
|
||||
PlayerInventory.getInnerDoubleClickSlots(getSize())
|
||||
));
|
||||
return ContainerInventory.handleClick(this, player, info, processor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the amount of tick until the fire icon come empty.
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user