mirror of https://github.com/Minestom/Minestom.git
Style change
This commit is contained in:
parent
84ead9b25c
commit
a0c915a5c9
|
@ -22,19 +22,35 @@ public final class Click {
|
|||
* The inventory used should be known from context.
|
||||
*/
|
||||
public sealed interface Info {
|
||||
|
||||
record Left(int slot) implements Info {}
|
||||
record Right(int slot) implements Info {}
|
||||
record Middle(int slot) implements Info {} // Creative only
|
||||
record Middle(int slot) implements Info {
|
||||
// Creative only
|
||||
}
|
||||
|
||||
record LeftShift(int slot) implements Info {}
|
||||
record RightShift(int slot) implements Info {}
|
||||
|
||||
record Double(int slot) implements Info {}
|
||||
|
||||
record LeftDrag(List<Integer> slots) implements Info {}
|
||||
record RightDrag(List<Integer> slots) implements Info {}
|
||||
record MiddleDrag(List<Integer> slots) implements Info {} // Creative only
|
||||
record LeftDrag(List<Integer> slots) implements Info {
|
||||
public LeftDrag {
|
||||
slots = List.copyOf(slots);
|
||||
}
|
||||
}
|
||||
|
||||
record RightDrag(List<Integer> slots) implements Info {
|
||||
public RightDrag {
|
||||
slots = List.copyOf(slots);
|
||||
}
|
||||
}
|
||||
|
||||
record MiddleDrag(List<Integer> slots) implements Info {
|
||||
// Creative only
|
||||
public MiddleDrag {
|
||||
slots = List.copyOf(slots);
|
||||
}
|
||||
}
|
||||
|
||||
record LeftDropCursor() implements Info {}
|
||||
record RightDropCursor() implements Info {}
|
||||
|
@ -47,14 +63,12 @@ public final class Click {
|
|||
|
||||
record CreativeSetItem(int slot, @NotNull ItemStack item) implements Info {}
|
||||
record CreativeDropItem(@NotNull ItemStack item) implements Info {}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Preprocesses click packets, turning them into {@link Info} instances for further processing.
|
||||
*/
|
||||
public static final class Preprocessor {
|
||||
|
||||
private final List<Integer> leftDrag = new ArrayList<>();
|
||||
private final List<Integer> rightDrag = new ArrayList<>();
|
||||
private final List<Integer> middleDrag = new ArrayList<>();
|
||||
|
@ -69,8 +83,8 @@ public final class Click {
|
|||
* Processes the provided click packet, turning it into a {@link Info}.
|
||||
* This will do simple verification of the packet before sending it to {@link #process(ClientClickWindowPacket.ClickType, int, byte, boolean)}.
|
||||
*
|
||||
* @param packet the raw click packet
|
||||
* @param isCreative whether or not the player is in creative mode (used for ignoring some actions)
|
||||
* @param packet the raw click packet
|
||||
* @param isCreative whether the player is in creative mode (used for ignoring some actions)
|
||||
* @return the information about the click, or nothing if there was no immediately usable information
|
||||
*/
|
||||
public @Nullable Click.Info process(@NotNull ClientClickWindowPacket packet, @NotNull Inventory inventory, boolean isCreative) {
|
||||
|
@ -81,25 +95,24 @@ public final class Click {
|
|||
int slot = inventory instanceof PlayerInventory ? PlayerInventoryUtils.protocolToMinestom(originalSlot) : originalSlot;
|
||||
if (originalSlot == -999) slot = -999;
|
||||
|
||||
boolean creativeRequired = switch (type) {
|
||||
final boolean creativeRequired = switch (type) {
|
||||
case CLONE -> true;
|
||||
case QUICK_CRAFT -> button == 8 || button == 9 || button == 10;
|
||||
default -> false;
|
||||
};
|
||||
|
||||
if (creativeRequired && !isCreative) return null;
|
||||
|
||||
int maxSize = inventory.getSize() + (inventory instanceof PlayerInventory ? 0 : PlayerInventoryUtils.INNER_SIZE);
|
||||
final int maxSize = inventory.getSize() + (inventory instanceof PlayerInventory ? 0 : PlayerInventoryUtils.INNER_SIZE);
|
||||
return process(type, slot, button, slot >= 0 && slot < maxSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a packet into click info.
|
||||
*
|
||||
* @param type the type of the click
|
||||
* @param slot the clicked slot
|
||||
* @param button the sent button
|
||||
* @param valid whether or not {@code slot} fits within the inventory (may be unused, depending on click)
|
||||
* @param type the type of the click
|
||||
* @param slot the clicked slot
|
||||
* @param button the sent button
|
||||
* @param valid whether {@code slot} fits within the inventory (may be unused, depending on click)
|
||||
* @return the information about the click, or nothing if there was no immediately usable information
|
||||
*/
|
||||
public @Nullable Click.Info process(@NotNull ClientClickWindowPacket.ClickType type,
|
||||
|
@ -182,7 +195,6 @@ public final class Click {
|
|||
|
||||
public record Getter(@NotNull IntFunction<ItemStack> main, @NotNull IntFunction<ItemStack> player,
|
||||
@NotNull ItemStack cursor, int mainSize) {
|
||||
|
||||
public @NotNull ItemStack get(int slot) {
|
||||
if (slot < mainSize()) {
|
||||
return main.apply(slot);
|
||||
|
@ -196,8 +208,7 @@ public final class Click {
|
|||
}
|
||||
}
|
||||
|
||||
public static class Setter {
|
||||
|
||||
public static final class Setter {
|
||||
private final Map<Integer, ItemStack> main = new HashMap<>();
|
||||
private final Map<Integer, ItemStack> player = new HashMap<>();
|
||||
private @Nullable ItemStack cursor;
|
||||
|
@ -237,37 +248,32 @@ public final class Click {
|
|||
public @NotNull Click.Result build() {
|
||||
return new Result(main, player, cursor, sideEffect);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores changes that occurred or will occur as the result of a click.
|
||||
* @param changes the map of changes that will occur to the inventory
|
||||
*
|
||||
* @param changes the map of changes that will occur to the inventory
|
||||
* @param playerInventoryChanges the map of changes that will occur to the player inventory
|
||||
* @param newCursorItem the player's cursor item after this click. Null indicates no change
|
||||
* @param sideEffects the side effects of this click
|
||||
* @param newCursorItem the player's cursor item after this click. Null indicates no change
|
||||
* @param sideEffects the side effects of this click
|
||||
*/
|
||||
public record Result(@NotNull Map<Integer, ItemStack> changes, @NotNull Map<Integer, ItemStack> playerInventoryChanges,
|
||||
public record Result(@NotNull Map<Integer, ItemStack> changes,
|
||||
@NotNull Map<Integer, ItemStack> playerInventoryChanges,
|
||||
@Nullable ItemStack newCursorItem, @Nullable Click.SideEffect sideEffects) {
|
||||
|
||||
public static @NotNull Result nothing() {
|
||||
return new Result(Map.of(), Map.of(), null, null);
|
||||
}
|
||||
public static final Result NOTHING = new Result(Map.of(), Map.of(), null, null);
|
||||
|
||||
public Result {
|
||||
changes = Map.copyOf(changes);
|
||||
playerInventoryChanges = Map.copyOf(playerInventoryChanges);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents side effects that may occur as the result of an inventory click.
|
||||
*/
|
||||
public sealed interface SideEffect {
|
||||
|
||||
record DropFromPlayer(@NotNull List<ItemStack> items) implements SideEffect {
|
||||
|
||||
record DropFromPlayer(@NotNull List<@NotNull ItemStack> items) implements SideEffect {
|
||||
public DropFromPlayer {
|
||||
items = List.copyOf(items);
|
||||
}
|
||||
|
|
|
@ -18,12 +18,11 @@ import java.util.stream.IntStream;
|
|||
* Provides standard implementations of most click functions.
|
||||
*/
|
||||
public final class ClickProcessors {
|
||||
|
||||
private static final @NotNull StackingRule RULE = StackingRule.get();
|
||||
|
||||
public static @NotNull Click.Result leftClick(int slot, @NotNull Click.Getter getter) {
|
||||
ItemStack cursor = getter.cursor();
|
||||
ItemStack clickedItem = getter.get(slot);
|
||||
final ItemStack cursor = getter.cursor();
|
||||
final ItemStack clickedItem = getter.get(slot);
|
||||
|
||||
Pair<ItemStack, ItemStack> pair = TransactionOperator.STACK_LEFT.apply(clickedItem, cursor);
|
||||
if (pair != null) { // Stackable items, combine their counts
|
||||
|
@ -31,24 +30,23 @@ public final class ClickProcessors {
|
|||
} else if (!RULE.canBeStacked(cursor, clickedItem)) { // If they're unstackable, switch them
|
||||
return getter.setter().set(slot, cursor).cursor(clickedItem).build();
|
||||
} else {
|
||||
return Click.Result.nothing();
|
||||
return Click.Result.NOTHING;
|
||||
}
|
||||
}
|
||||
|
||||
public static @NotNull Click.Result rightClick(int slot, @NotNull Click.Getter getter) {
|
||||
ItemStack cursor = getter.cursor();
|
||||
ItemStack clickedItem = getter.get(slot);
|
||||
|
||||
if (cursor.isAir() && clickedItem.isAir()) return Click.Result.nothing(); // Both are air, no changes
|
||||
final ItemStack cursor = getter.cursor();
|
||||
final ItemStack clickedItem = getter.get(slot);
|
||||
if (cursor.isAir() && clickedItem.isAir()) return Click.Result.NOTHING; // Both are air, no changes
|
||||
|
||||
if (cursor.isAir()) { // Take half (rounded up) of the clicked item
|
||||
int newAmount = (int) Math.ceil(RULE.getAmount(clickedItem) / 2d);
|
||||
Pair<ItemStack, ItemStack> cursorSlot = TransactionOperator.stackLeftN(newAmount).apply(cursor, clickedItem);
|
||||
return cursorSlot == null ? Click.Result.nothing() :
|
||||
return cursorSlot == null ? Click.Result.NOTHING :
|
||||
getter.setter().cursor(cursorSlot.left()).set(slot, cursorSlot.right()).build();
|
||||
} else if (clickedItem.isAir() || RULE.canBeStacked(clickedItem, cursor)) { // Can add, transfer one over
|
||||
Pair<ItemStack, ItemStack> slotCursor = TransactionOperator.stackLeftN(1).apply(clickedItem, cursor);
|
||||
return slotCursor == null ? Click.Result.nothing() :
|
||||
return slotCursor == null ? Click.Result.NOTHING :
|
||||
getter.setter().set(slot, slotCursor.left()).cursor(slotCursor.right()).build();
|
||||
} else { // Two existing of items of different types, so switch
|
||||
return getter.setter().cursor(clickedItem).set(slot, cursor).build();
|
||||
|
@ -60,12 +58,12 @@ public final class ClickProcessors {
|
|||
if (getter.cursor().isAir() && !item.isAir()) {
|
||||
return getter.setter().cursor(RULE.apply(item, RULE.getMaxSize(item))).build();
|
||||
} else {
|
||||
return Click.Result.nothing();
|
||||
return Click.Result.NOTHING;
|
||||
}
|
||||
}
|
||||
|
||||
public static @NotNull Click.Result shiftClick(int slot, @NotNull List<Integer> slots, @NotNull Click.Getter getter) {
|
||||
ItemStack clicked = getter.get(slot);
|
||||
final ItemStack clicked = getter.get(slot);
|
||||
|
||||
slots = new ArrayList<>(slots);
|
||||
slots.removeIf(i -> i == slot);
|
||||
|
@ -80,8 +78,8 @@ public final class ClickProcessors {
|
|||
}
|
||||
|
||||
public static @NotNull Click.Result doubleClick(@NotNull List<Integer> slots, @NotNull Click.Getter getter) {
|
||||
var cursor = getter.cursor();
|
||||
if (cursor.isAir()) Click.Result.nothing();
|
||||
final ItemStack cursor = getter.cursor();
|
||||
if (cursor.isAir()) return Click.Result.NOTHING;
|
||||
|
||||
var unstacked = TransactionType.general(TransactionOperator.filter(TransactionOperator.STACK_RIGHT, (left, right) -> RULE.getAmount(left) < RULE.getMaxSize(left)), slots);
|
||||
var stacked = TransactionType.general(TransactionOperator.filter(TransactionOperator.STACK_RIGHT, (left, right) -> RULE.getAmount(left) == RULE.getMaxSize(left)), slots);
|
||||
|
@ -96,8 +94,8 @@ public final class ClickProcessors {
|
|||
}
|
||||
|
||||
public static @NotNull Click.Result dragClick(int countPerSlot, @NotNull List<Integer> slots, @NotNull Click.Getter getter) {
|
||||
var cursor = getter.cursor();
|
||||
if (cursor.isAir()) return Click.Result.nothing();
|
||||
final ItemStack cursor = getter.cursor();
|
||||
if (cursor.isAir()) return Click.Result.NOTHING;
|
||||
|
||||
Pair<ItemStack, Map<Integer, ItemStack>> result = TransactionType.general(TransactionOperator.stackLeftN(countPerSlot), slots).process(cursor, getter::get);
|
||||
Click.Setter setter = getter.setter();
|
||||
|
@ -109,25 +107,22 @@ public final class ClickProcessors {
|
|||
}
|
||||
|
||||
public static @NotNull Click.Result middleDragClick(@NotNull List<Integer> slots, @NotNull Click.Getter getter) {
|
||||
var cursor = getter.cursor();
|
||||
|
||||
final ItemStack cursor = getter.cursor();
|
||||
Click.Setter setter = getter.setter();
|
||||
|
||||
for (int slot : slots) {
|
||||
if (getter.get(slot).isAir()) {
|
||||
setter.set(slot, cursor);
|
||||
}
|
||||
}
|
||||
|
||||
return setter.build();
|
||||
}
|
||||
|
||||
public static @NotNull Click.Result dropFromCursor(int amount, @NotNull Click.Getter getter) {
|
||||
var cursor = getter.cursor();
|
||||
if (cursor.isAir()) Click.Result.nothing(); // Do nothing
|
||||
final ItemStack cursor = getter.cursor();
|
||||
if (cursor.isAir()) return Click.Result.NOTHING; // Do nothing
|
||||
|
||||
var pair = TransactionOperator.stackLeftN(amount).apply(ItemStack.AIR, cursor);
|
||||
if (pair == null) return Click.Result.nothing();
|
||||
if (pair == null) return Click.Result.NOTHING;
|
||||
|
||||
return getter.setter().cursor(pair.right())
|
||||
.sideEffects(new Click.SideEffect.DropFromPlayer(pair.left()))
|
||||
|
@ -135,11 +130,11 @@ public final class ClickProcessors {
|
|||
}
|
||||
|
||||
public static @NotNull Click.Result dropFromSlot(int slot, int amount, @NotNull Click.Getter getter) {
|
||||
var item = getter.get(slot);
|
||||
if (item.isAir()) return Click.Result.nothing(); // Do nothing
|
||||
final ItemStack item = getter.get(slot);
|
||||
if (item.isAir()) return Click.Result.NOTHING; // Do nothing
|
||||
|
||||
var pair = TransactionOperator.stackLeftN(amount).apply(ItemStack.AIR, item);
|
||||
if (pair == null) return Click.Result.nothing();
|
||||
if (pair == null) return Click.Result.NOTHING;
|
||||
|
||||
return getter.setter().set(slot, pair.right())
|
||||
.sideEffects(new Click.SideEffect.DropFromPlayer(pair.left()))
|
||||
|
@ -150,9 +145,10 @@ public final class ClickProcessors {
|
|||
* Handles clicks, given a shift click provider and a double click provider.<br>
|
||||
* When shift clicks or double clicks need to be handled, the slots provided from the relevant handler will be
|
||||
* checked in their given order.<br>
|
||||
* For example, double clicking will collect items of the same type as the cursor; the slots provided by the double
|
||||
* For example, double-clicking will collect items of the same type as the cursor; the slots provided by the double
|
||||
* click slot provider will be checked sequentially and used if they have the same type as
|
||||
* @param shiftClickSlots the shift click slot supplier
|
||||
*
|
||||
* @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) {
|
||||
|
@ -173,18 +169,18 @@ public final class ClickProcessors {
|
|||
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();
|
||||
case Click.Info.MiddleDropCursor() -> Click.Result.NOTHING;
|
||||
case Click.Info.HotbarSwap(int hotbarSlot, int clickedSlot) -> {
|
||||
var hotbarItem = getter.player().apply(hotbarSlot);
|
||||
var selectedItem = getter.get(clickedSlot);
|
||||
if (hotbarItem.equals(selectedItem)) yield Click.Result.nothing();
|
||||
if (hotbarItem.equals(selectedItem)) yield Click.Result.NOTHING;
|
||||
|
||||
yield getter.setter().setPlayer(hotbarSlot, selectedItem).set(clickedSlot, hotbarItem).build();
|
||||
}
|
||||
case Click.Info.OffhandSwap(int slot) -> {
|
||||
var offhandItem = getter.player().apply(PlayerInventoryUtils.OFF_HAND_SLOT);
|
||||
var selectedItem = getter.get(slot);
|
||||
if (offhandItem.equals(selectedItem)) yield Click.Result.nothing();
|
||||
if (offhandItem.equals(selectedItem)) yield Click.Result.NOTHING;
|
||||
|
||||
yield getter.setter().setPlayer(PlayerInventoryUtils.OFF_HAND_SLOT, selectedItem).set(slot, offhandItem).build();
|
||||
}
|
||||
|
@ -204,16 +200,17 @@ public final class ClickProcessors {
|
|||
|
||||
/**
|
||||
* Suggests slots to be used for this operation.
|
||||
*
|
||||
* @param builder the result builder
|
||||
* @param item the item clicked
|
||||
* @param slot the slot of the clicked item
|
||||
* @param item the item clicked
|
||||
* @param slot the slot of the clicked item
|
||||
* @return the list of slots, in order of priority, to be used for this operation
|
||||
*/
|
||||
@NotNull IntStream get(@NotNull Click.Getter builder, @NotNull ItemStack item, int slot);
|
||||
@NotNull
|
||||
IntStream get(@NotNull Click.Getter builder, @NotNull ItemStack item, int slot);
|
||||
|
||||
default @NotNull List<Integer> getList(@NotNull Click.Getter builder, @NotNull ItemStack item, int slot) {
|
||||
return get(builder, item, slot).boxed().toList();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,11 +5,10 @@ package net.minestom.server.utils.inventory;
|
|||
* Minestom uses different slot IDs for player inventories as the Minecraft protocol uses a strange system (e.g. the
|
||||
* crafting result is the first slot).<br>
|
||||
* These can be mapped 1:1 to and from protocol slots using {@link #minestomToProtocol(int)} and {@link #protocolToMinestom(int)}.<br>
|
||||
*
|
||||
* <p>
|
||||
* Read about protocol slot IDs <a href="https://wiki.vg/Inventory">here</a>.
|
||||
*/
|
||||
public final class PlayerInventoryUtils {
|
||||
|
||||
public static final int INVENTORY_SIZE = 46;
|
||||
public static final int INNER_SIZE = 36;
|
||||
|
||||
|
@ -28,12 +27,12 @@ public final class PlayerInventoryUtils {
|
|||
public static final int OFF_HAND_SLOT = 45;
|
||||
|
||||
private PlayerInventoryUtils() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Minestom slot ID to a Minecraft protocol slot ID.<br>
|
||||
* This is the inverse of {@link #protocolToMinestom(int)}.
|
||||
*
|
||||
* @param slot the internal slot ID to convert
|
||||
* @return the protocol slot ID, or -1 if the given slot could not be converted
|
||||
*/
|
||||
|
@ -64,6 +63,7 @@ public final class PlayerInventoryUtils {
|
|||
/**
|
||||
* Converts a Minecraft protocol slot ID to a Minestom slot ID.<br>
|
||||
* This is the inverse of {@link #minestomToProtocol(int)}.
|
||||
*
|
||||
* @param slot the protocol slot ID to convert
|
||||
* @return the Minestom slot ID, or -1 if the given slot could not be converted
|
||||
*/
|
||||
|
@ -97,7 +97,7 @@ public final class PlayerInventoryUtils {
|
|||
* open.<br>
|
||||
* This is the inverse of {@link #protocolToMinestom(int, int)}.
|
||||
*
|
||||
* @param slot the player slot that was interacted with
|
||||
* @param slot the player slot that was interacted with
|
||||
* @param openInventorySize the size of the inventory opened by the player (not the player's inventory)
|
||||
* @return the protocol slot ID
|
||||
*/
|
||||
|
@ -111,14 +111,12 @@ public final class PlayerInventoryUtils {
|
|||
* open.<br>
|
||||
* This is the inverse of {@link #minestomToProtocol(int, int)}.
|
||||
*
|
||||
* @param slot the protocol slot ID, situated directly after the slot IDs for the open inventory
|
||||
* @param slot the protocol slot ID, situated directly after the slot IDs for the open inventory
|
||||
* @param openInventorySize the size of the inventory opened by the player (not the player's inventory)
|
||||
* @return the player slot ID
|
||||
*/
|
||||
public static int protocolToMinestom(int slot, int openInventorySize) {
|
||||
if (slot < openInventorySize) return -1;
|
||||
|
||||
return PlayerInventoryUtils.protocolToMinestom(slot - openInventorySize + PROTOCOL_OFFSET);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue