mirror of
https://github.com/Minestom/Minestom.git
synced 2024-11-15 07:05:52 +01:00
Simplify shift click handling, fix click processor ignoring non-air slot
This commit is contained in:
parent
1daaeda63f
commit
e9b5779b24
@ -338,51 +338,21 @@ public class Inventory extends AbstractInventory implements Viewable {
|
||||
final ItemStack clicked = isInWindow ? getItemStack(slot) : playerInventory.getItemStack(clickSlot);
|
||||
final ItemStack cursor = getCursorItem(player); // Isn't used in the algorithm
|
||||
|
||||
|
||||
final InventoryClickResult clickResult;
|
||||
|
||||
if (isInWindow) {
|
||||
clickResult = clickProcessor.shiftClick(this, player, slot, clicked, cursor,
|
||||
// Player inventory loop
|
||||
new InventoryClickLoopHandler(offset, PlayerInventory.INVENTORY_SIZE + offset, 1,
|
||||
PlayerInventoryUtils::convertToPacketSlot,
|
||||
index -> isClickInWindow(index) ?
|
||||
getItemStack(index) :
|
||||
playerInventory.getItemStack(PlayerInventoryUtils.convertSlot(index, offset)),
|
||||
(index, itemStack) -> {
|
||||
if (isClickInWindow(index)) {
|
||||
setItemStack(index, itemStack);
|
||||
} else {
|
||||
playerInventory.setItemStack(PlayerInventoryUtils.convertSlot(index, offset), itemStack);
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
clickResult = clickProcessor.shiftClick(null, player, slot, clicked, cursor,
|
||||
// Window loop
|
||||
new InventoryClickLoopHandler(0, getSize(), 1,
|
||||
i -> i,
|
||||
index -> isClickInWindow(index) ?
|
||||
getItemStack(index) :
|
||||
playerInventory.getItemStack(PlayerInventoryUtils.convertSlot(index, offset)),
|
||||
(index, itemStack) -> {
|
||||
if (isClickInWindow(index)) {
|
||||
setItemStack(index, itemStack);
|
||||
} else {
|
||||
playerInventory.setItemStack(PlayerInventoryUtils.convertSlot(index, offset), itemStack);
|
||||
}
|
||||
}));
|
||||
}
|
||||
final InventoryClickResult clickResult = clickProcessor.shiftClick(
|
||||
isInWindow ? playerInventory : this,
|
||||
isInWindow ? this : null,
|
||||
player, slot, clicked, cursor);
|
||||
|
||||
if (clickResult == null)
|
||||
return false;
|
||||
|
||||
if (clickResult.doRefresh()) {
|
||||
updateFromClick(clickResult, player);
|
||||
if (isInWindow) {
|
||||
setItemStack(slot, clickResult.getClicked());
|
||||
} else {
|
||||
playerInventory.setItemStack(clickSlot, clickResult.getClicked());
|
||||
}
|
||||
|
||||
refreshPlayerCursorItem(player, clickResult.getCursor());
|
||||
playerInventory.update();
|
||||
update();
|
||||
|
||||
return !clickResult.isCancel();
|
||||
}
|
||||
|
@ -339,26 +339,17 @@ public class PlayerInventory extends AbstractInventory implements EquipmentHandl
|
||||
public boolean shiftClick(@NotNull Player player, int slot) {
|
||||
final ItemStack cursor = getCursorItem();
|
||||
final ItemStack clicked = getItemStack(slot, OFFSET);
|
||||
|
||||
final boolean hotBarClick = convertToPacketSlot(slot) < 9;
|
||||
final InventoryClickResult clickResult = clickProcessor.shiftClick(null, player, slot, clicked, cursor,
|
||||
new InventoryClickLoopHandler(0, itemStacks.length, 1,
|
||||
i -> {
|
||||
if (hotBarClick) {
|
||||
return i < 9 ? i + 9 : i - 9;
|
||||
} else {
|
||||
return convertPlayerInventorySlot(i, OFFSET);
|
||||
}
|
||||
},
|
||||
index -> getItemStack(index, OFFSET),
|
||||
(index, itemStack) -> setItemStack(index, OFFSET, itemStack)));
|
||||
final boolean hotBarClick = convertSlot(slot, OFFSET) < 9;
|
||||
final int start = hotBarClick ? 9 : 0;
|
||||
final int end = hotBarClick ? getSize() - 9 : 8;
|
||||
final InventoryClickResult clickResult = clickProcessor.shiftClick(this,
|
||||
start, end, 1,
|
||||
player, slot, clicked, cursor);
|
||||
|
||||
if (clickResult == null)
|
||||
return false;
|
||||
|
||||
if (clickResult.doRefresh())
|
||||
update();
|
||||
|
||||
setItemStack(slot, OFFSET, clickResult.getClicked());
|
||||
setCursorItem(clickResult.getCursor());
|
||||
|
||||
return !clickResult.isCancel();
|
||||
|
@ -19,13 +19,13 @@ public interface TransactionType {
|
||||
* Adds an item to the inventory.
|
||||
* Can either take an air slot or be stacked.
|
||||
*/
|
||||
TransactionType ADD = (inventory, itemStack) -> {
|
||||
TransactionType ADD = (inventory, itemStack, slotPredicate, start, end, step) -> {
|
||||
Int2ObjectMap<ItemStack> itemChangesMap = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
final StackingRule stackingRule = itemStack.getStackingRule();
|
||||
|
||||
// Check filled slot (not air)
|
||||
for (int i = 0; i < inventory.getInnerSize(); i++) {
|
||||
for (int i = start; i < end; i += step) {
|
||||
ItemStack inventoryItem = inventory.getItemStack(i);
|
||||
if (inventoryItem.isAir()) {
|
||||
continue;
|
||||
@ -34,6 +34,12 @@ public interface TransactionType {
|
||||
final int itemAmount = stackingRule.getAmount(inventoryItem);
|
||||
if (itemAmount == stackingRule.getMaxSize())
|
||||
continue;
|
||||
|
||||
if (!slotPredicate.test(i, inventoryItem)) {
|
||||
// Cancelled transaction
|
||||
continue;
|
||||
}
|
||||
|
||||
final int itemStackAmount = stackingRule.getAmount(itemStack);
|
||||
final int totalAmount = itemStackAmount + itemAmount;
|
||||
if (!stackingRule.canApply(itemStack, totalAmount)) {
|
||||
@ -50,11 +56,17 @@ public interface TransactionType {
|
||||
}
|
||||
|
||||
// Check air slot to fill
|
||||
for (int i = 0; i < inventory.getInnerSize(); i++) {
|
||||
for (int i = start; i < end; i += step) {
|
||||
ItemStack inventoryItem = inventory.getItemStack(i);
|
||||
if (!inventoryItem.isAir()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!slotPredicate.test(i, inventoryItem)) {
|
||||
// Cancelled transaction
|
||||
continue;
|
||||
}
|
||||
|
||||
// Fill the slot
|
||||
itemChangesMap.put(i, itemStack);
|
||||
itemStack = stackingRule.apply(itemStack, 0);
|
||||
@ -68,15 +80,20 @@ public interface TransactionType {
|
||||
* Takes an item from the inventory.
|
||||
* Can either transform items to air or reduce their amount.
|
||||
*/
|
||||
TransactionType TAKE = (inventory, itemStack) -> {
|
||||
TransactionType TAKE = (inventory, itemStack, slotPredicate, start, end, step) -> {
|
||||
Int2ObjectMap<ItemStack> itemChangesMap = new Int2ObjectOpenHashMap<>();
|
||||
final StackingRule stackingRule = itemStack.getStackingRule();
|
||||
for (int i = 0; i < inventory.getInnerSize(); i++) {
|
||||
for (int i = start; i < end; i += step) {
|
||||
ItemStack inventoryItem = inventory.getItemStack(i);
|
||||
if (inventoryItem.isAir()) {
|
||||
continue;
|
||||
}
|
||||
if (stackingRule.canBeStacked(itemStack, inventoryItem)) {
|
||||
if (!slotPredicate.test(i, inventoryItem)) {
|
||||
// Cancelled transaction
|
||||
continue;
|
||||
}
|
||||
|
||||
final int itemAmount = stackingRule.getAmount(inventoryItem);
|
||||
final int itemStackAmount = stackingRule.getAmount(itemStack);
|
||||
if (itemStackAmount < itemAmount) {
|
||||
@ -97,6 +114,23 @@ public interface TransactionType {
|
||||
};
|
||||
|
||||
@NotNull Pair<ItemStack, Map<Integer, ItemStack>> process(@NotNull AbstractInventory inventory,
|
||||
@NotNull ItemStack itemStack);
|
||||
@NotNull ItemStack itemStack,
|
||||
@NotNull SlotPredicate slotPredicate,
|
||||
int start, int end, int step);
|
||||
|
||||
default @NotNull Pair<ItemStack, Map<Integer, ItemStack>> process(@NotNull AbstractInventory inventory,
|
||||
@NotNull ItemStack itemStack,
|
||||
@NotNull SlotPredicate slotPredicate) {
|
||||
return process(inventory, itemStack, slotPredicate, 0, inventory.getInnerSize(), 1);
|
||||
}
|
||||
|
||||
default @NotNull Pair<ItemStack, Map<Integer, ItemStack>> process(@NotNull AbstractInventory inventory,
|
||||
@NotNull ItemStack itemStack) {
|
||||
return process(inventory, itemStack, (slot, itemStack1) -> true);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface SlotPredicate {
|
||||
boolean test(int slot, @NotNull ItemStack itemStack);
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,9 @@ import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import net.minestom.server.entity.Player;
|
||||
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.TransactionType;
|
||||
import net.minestom.server.inventory.condition.InventoryCondition;
|
||||
import net.minestom.server.inventory.condition.InventoryConditionResult;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
@ -167,9 +169,8 @@ public class InventoryClickProcessor {
|
||||
return clickResult;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public InventoryClickResult shiftClick(@Nullable Inventory inventory, @NotNull Player player, int slot,
|
||||
@NotNull ItemStack clicked, @NotNull ItemStack cursor, @NotNull InventoryClickLoopHandler... loopHandlers) {
|
||||
public @Nullable InventoryClickResult shiftClick(AbstractInventory targetInventory, @Nullable Inventory inventory, @NotNull Player player, int slot,
|
||||
@NotNull ItemStack clicked, @NotNull ItemStack cursor) {
|
||||
InventoryClickResult clickResult = startCondition(inventory, player, slot, ClickType.START_SHIFT_CLICK, clicked, cursor);
|
||||
|
||||
if (clickResult.isCancel()) {
|
||||
@ -179,72 +180,44 @@ public class InventoryClickProcessor {
|
||||
if (clicked.isAir())
|
||||
return null;
|
||||
|
||||
final StackingRule clickedRule = clicked.getStackingRule();
|
||||
var pair = TransactionType.ADD.process(targetInventory, clicked, (index, itemStack) -> {
|
||||
InventoryClickResult result = startCondition(inventory, player, index, ClickType.SHIFT_CLICK, itemStack, cursor);
|
||||
return !result.isCancel();
|
||||
});
|
||||
|
||||
boolean filled = false;
|
||||
ItemStack resultClicked = clicked;
|
||||
var itemResult = pair.left();
|
||||
var map = pair.right();
|
||||
map.forEach(targetInventory::setItemStack);
|
||||
|
||||
for (InventoryClickLoopHandler loopHandler : loopHandlers) {
|
||||
final Int2IntFunction indexModifier = loopHandler.getIndexModifier();
|
||||
final Int2ObjectFunction<ItemStack> itemGetter = loopHandler.getItemGetter();
|
||||
final BiConsumer<Integer, ItemStack> itemSetter = loopHandler.getItemSetter();
|
||||
clickResult.setClicked(itemResult);
|
||||
|
||||
for (int i = loopHandler.getStart(); i < loopHandler.getEnd(); i += loopHandler.getStep()) {
|
||||
final int index = indexModifier.apply(i);
|
||||
if (index == slot)
|
||||
continue;
|
||||
return clickResult;
|
||||
}
|
||||
|
||||
ItemStack item = itemGetter.apply(index);
|
||||
final StackingRule itemRule = item.getStackingRule();
|
||||
if (itemRule.canBeStacked(item, clicked)) {
|
||||
public @Nullable InventoryClickResult shiftClick(@NotNull AbstractInventory targetInventory, int start, int end, int step, @NotNull Player player, int slot,
|
||||
@NotNull ItemStack clicked, @NotNull ItemStack cursor) {
|
||||
InventoryClickResult clickResult = startCondition(null, player, slot, ClickType.START_SHIFT_CLICK, clicked, cursor);
|
||||
|
||||
clickResult = startCondition(inventory, player, index, ClickType.SHIFT_CLICK, item, cursor);
|
||||
if (clickResult.isCancel())
|
||||
break;
|
||||
|
||||
final int amount = itemRule.getAmount(item);
|
||||
if (!clickedRule.canApply(clicked, amount + 1))
|
||||
continue;
|
||||
|
||||
final int totalAmount = clickedRule.getAmount(resultClicked) + amount;
|
||||
if (!clickedRule.canApply(clicked, totalAmount)) {
|
||||
item = itemRule.apply(item, itemRule.getMaxSize());
|
||||
itemSetter.accept(index, item);
|
||||
|
||||
resultClicked = clickedRule.apply(resultClicked, totalAmount - clickedRule.getMaxSize());
|
||||
filled = false;
|
||||
|
||||
callClickEvent(player, inventory, index, ClickType.SHIFT_CLICK, item, cursor);
|
||||
continue;
|
||||
} else {
|
||||
resultClicked = clickedRule.apply(resultClicked, totalAmount);
|
||||
itemSetter.accept(index, resultClicked);
|
||||
|
||||
item = itemRule.apply(item, 0);
|
||||
itemSetter.accept(slot, item);
|
||||
filled = true;
|
||||
|
||||
callClickEvent(player, inventory, index, ClickType.SHIFT_CLICK, item, cursor);
|
||||
break;
|
||||
}
|
||||
} else if (item.isAir()) {
|
||||
|
||||
clickResult = startCondition(inventory, player, index, ClickType.SHIFT_CLICK, item, cursor);
|
||||
if (clickResult.isCancel())
|
||||
break;
|
||||
|
||||
// Switch
|
||||
itemSetter.accept(index, resultClicked);
|
||||
itemSetter.accept(slot, ItemStack.AIR);
|
||||
filled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!filled) {
|
||||
itemSetter.accept(slot, resultClicked);
|
||||
}
|
||||
if (clickResult.isCancel()) {
|
||||
return clickResult;
|
||||
}
|
||||
|
||||
if (clicked.isAir())
|
||||
return null;
|
||||
|
||||
var pair = TransactionType.ADD.process(targetInventory, clicked, (index, itemStack) -> {
|
||||
if (index == slot) // Prevent item lose/duplication
|
||||
return false;
|
||||
InventoryClickResult result = startCondition(null, player, index, ClickType.SHIFT_CLICK, itemStack, cursor);
|
||||
return !result.isCancel();
|
||||
}, start, end, step);
|
||||
|
||||
var itemResult = pair.left();
|
||||
var map = pair.right();
|
||||
map.forEach(targetInventory::setItemStack);
|
||||
|
||||
clickResult.setClicked(itemResult);
|
||||
|
||||
return clickResult;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user