Simplify double click handling

This commit is contained in:
TheMode 2021-04-20 07:29:01 +02:00
parent e9b5779b24
commit 5390cd14f0
5 changed files with 49 additions and 59 deletions

View File

@ -55,8 +55,7 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo
public synchronized <T> @NotNull T processItemStack(@NotNull ItemStack itemStack,
@NotNull TransactionType type,
@NotNull TransactionOption<T> option) {
var pair = type.process(this, itemStack);
return option.fill(this, pair.left(), pair.right());
return option.fill(type, this, itemStack);
}
public synchronized <T> @NotNull List<@NotNull T> processItemStacks(@NotNull List<@NotNull ItemStack> itemStacks,

View File

@ -4,7 +4,6 @@ import net.kyori.adventure.text.Component;
import net.minestom.server.Viewable;
import net.minestom.server.entity.Player;
import net.minestom.server.inventory.click.ClickType;
import net.minestom.server.inventory.click.InventoryClickLoopHandler;
import net.minestom.server.inventory.click.InventoryClickResult;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.server.play.OpenWindowPacket;
@ -468,17 +467,8 @@ public class Inventory extends AbstractInventory implements Viewable {
final ItemStack cursor = getCursorItem(player);
final boolean isInWindow = isClickInWindow(slot);
final InventoryClickResult clickResult = clickProcessor.doubleClick(isInWindow ? this : null, player, slot, cursor,
// Start by looping through the opened inventory
new InventoryClickLoopHandler(0, getSize(), 1,
i -> i,
this::getItemStack,
this::setItemStack),
// Looping through player inventory
new InventoryClickLoopHandler(0, PlayerInventory.INVENTORY_SIZE, 1,
PlayerInventoryUtils::convertToPacketSlot,
index -> playerInventory.getItemStack(index, PlayerInventoryUtils.OFFSET),
(index, itemStack) -> playerInventory.setItemStack(index, PlayerInventoryUtils.OFFSET, itemStack)));
final InventoryClickResult clickResult = clickProcessor.doubleClick(isInWindow ? this : playerInventory,
this, player, slot, cursor);
if (clickResult == null)
return false;

View File

@ -3,7 +3,6 @@ package net.minestom.server.inventory;
import net.minestom.server.entity.Player;
import net.minestom.server.event.item.ArmorEquipEvent;
import net.minestom.server.inventory.click.ClickType;
import net.minestom.server.inventory.click.InventoryClickLoopHandler;
import net.minestom.server.inventory.click.InventoryClickResult;
import net.minestom.server.inventory.condition.InventoryCondition;
import net.minestom.server.item.ItemStack;
@ -406,12 +405,7 @@ public class PlayerInventory extends AbstractInventory implements EquipmentHandl
@Override
public boolean doubleClick(@NotNull Player player, int slot) {
final ItemStack cursor = getCursorItem();
final InventoryClickResult clickResult = clickProcessor.doubleClick(null, player, slot, cursor,
new InventoryClickLoopHandler(0, itemStacks.length, 1,
i -> i < 9 ? i + 9 : i - 9,
index -> itemStacks[index],
this::setItemStack));
final InventoryClickResult clickResult = clickProcessor.doubleClick(this, null, player, slot, cursor);
if (clickResult == null)
return false;
@ -419,6 +413,7 @@ public class PlayerInventory extends AbstractInventory implements EquipmentHandl
if (clickResult.doRefresh())
update();
setItemStack(slot, OFFSET, clickResult.getClicked());
setCursorItem(clickResult.getCursor());
return !clickResult.isCancel();

View File

@ -44,4 +44,11 @@ public interface TransactionOption<T> {
@NotNull T fill(@NotNull AbstractInventory inventory,
@NotNull ItemStack result,
@NotNull Map<@NotNull Integer, @NotNull ItemStack> itemChangesMap);
default @NotNull T fill(@NotNull TransactionType type,
@NotNull AbstractInventory inventory,
@NotNull ItemStack itemStack) {
var pair = type.process(inventory, itemStack);
return fill(inventory, pair.left(), pair.right());
}
}

View File

@ -1,6 +1,5 @@
package net.minestom.server.inventory.click;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
import it.unimi.dsi.fastutil.ints.Int2ObjectFunction;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
@ -9,6 +8,7 @@ import net.minestom.server.event.inventory.InventoryClickEvent;
import net.minestom.server.event.inventory.InventoryPreClickEvent;
import net.minestom.server.inventory.AbstractInventory;
import net.minestom.server.inventory.Inventory;
import net.minestom.server.inventory.TransactionOption;
import net.minestom.server.inventory.TransactionType;
import net.minestom.server.inventory.condition.InventoryCondition;
import net.minestom.server.inventory.condition.InventoryConditionResult;
@ -21,7 +21,9 @@ import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
public class InventoryClickProcessor {
@ -342,8 +344,8 @@ public class InventoryClickProcessor {
}
@Nullable
public InventoryClickResult doubleClick(@Nullable Inventory inventory, @NotNull Player player, int slot,
@NotNull ItemStack cursor, @NotNull InventoryClickLoopHandler... loopHandlers) {
public InventoryClickResult doubleClick(@NotNull AbstractInventory clickedInventory, @Nullable Inventory inventory, @NotNull Player player, int slot,
@NotNull final ItemStack cursor) {
InventoryClickResult clickResult = startCondition(inventory, player, slot, ClickType.START_DOUBLE_CLICK, ItemStack.AIR, cursor);
if (clickResult.isCancel()) {
@ -354,49 +356,46 @@ public class InventoryClickProcessor {
return null;
final StackingRule cursorRule = cursor.getStackingRule();
int amount = cursorRule.getAmount(cursor);
final int amount = cursorRule.getAmount(cursor);
final int remainingAmount = cursorRule.getMaxSize() - amount;
if (!cursorRule.canApply(cursor, amount + 1))
return null;
ItemStack remain = cursorRule.apply(cursor, remainingAmount);
for (InventoryClickLoopHandler loopHandler : loopHandlers) {
final Int2IntFunction indexModifier = loopHandler.getIndexModifier();
final Int2ObjectFunction<ItemStack> itemGetter = loopHandler.getItemGetter();
final BiConsumer<Integer, ItemStack> itemSetter = loopHandler.getItemSetter();
BiFunction<AbstractInventory, ItemStack, ItemStack> func = (inv, rest) -> {
var pair = TransactionType.TAKE.process(inv, rest, (index, itemStack) -> {
if (index == slot) // Prevent item lose/duplication
return false;
InventoryClickResult result = startCondition(inventory, player, index, ClickType.DOUBLE_CLICK, itemStack, cursor);
return !result.isCancel();
});
var itemResult = pair.left();
var map = pair.right();
return TransactionOption.ALL.fill(inv, itemResult, map);
};
for (int i = loopHandler.getStart(); i < loopHandler.getEnd(); i += loopHandler.getStep()) {
final int index = indexModifier.apply(i);
if (index == slot)
continue;
var playerInventory = player.getInventory();
ItemStack item = itemGetter.apply(index);
final StackingRule itemRule = item.getStackingRule();
if (!cursorRule.canApply(cursor, amount + 1))
break;
if (cursorRule.canBeStacked(cursor, item)) {
clickResult = startCondition(inventory, player, index, ClickType.DOUBLE_CLICK, item, cursor);
if (clickResult.isCancel())
break;
final int totalAmount = amount + cursorRule.getAmount(item);
if (!cursorRule.canApply(cursor, totalAmount)) {
cursor = cursorRule.apply(cursor, cursorRule.getMaxSize());
item = itemRule.apply(item, totalAmount - itemRule.getMaxSize());
} else {
cursor = cursorRule.apply(cursor, totalAmount);
item = itemRule.apply(item, 0);
}
itemSetter.accept(index, item);
amount = cursorRule.getAmount(cursor);
callClickEvent(player, inventory, index, ClickType.DOUBLE_CLICK, item, cursor);
}
if (Objects.equals(clickedInventory, inventory)) {
// Clicked inside inventory
remain = func.apply(inventory, remain);
if (!remain.isAir()) {
remain = func.apply(playerInventory, remain);
}
} else if (inventory != null && clickedInventory == playerInventory) {
// Clicked inside player inventory, but with another inventory open
remain = func.apply(playerInventory, remain);
if (!remain.isAir()) {
remain = func.apply(inventory, remain);
}
} else {
// Clicked inside player inventory
remain = func.apply(playerInventory, remain);
}
clickResult.setCursor(cursor);
final int tookAmount = remainingAmount - cursorRule.getAmount(remain);
ItemStack resultCursor = cursorRule.apply(cursor, amount + tookAmount);
clickResult.setCursor(resultCursor);
return clickResult;
}