Drag click cleanup, fix cursor item not being updated (thanks 1.17.1)

This commit is contained in:
TheMode 2021-08-12 20:49:03 +02:00
parent c17f07e1d0
commit 70c757e8b5
2 changed files with 106 additions and 143 deletions

View File

@ -146,155 +146,121 @@ public final class InventoryClickProcessor {
@NotNull Int2ObjectFunction<ItemStack> itemGetter, @NotNull Int2ObjectFunction<ItemStack> itemGetter,
@NotNull BiConsumer<Integer, ItemStack> itemSetter) { @NotNull BiConsumer<Integer, ItemStack> itemSetter) {
InventoryClickResult clickResult = null; InventoryClickResult clickResult = null;
final StackingRule stackingRule = cursor.getStackingRule(); final StackingRule stackingRule = cursor.getStackingRule();
if (slot != -999) {
if (slot == -999) { // Add slot
// Start or end left/right drag if (button == 1) {
// Add left
IntSet left = leftDraggingMap.get(player);
if (left == null) return null;
left.add(slot);
} else if (button == 5) {
// Add right
IntSet right = rightDraggingMap.get(player);
if (right == null) return null;
right.add(slot);
} else if (button == 9) {
// Add middle
// TODO
}
} else {
// Drag instruction
if (button == 0) { if (button == 0) {
// Start left // Start left
clickResult = startCondition(player, inventory, slot, ClickType.START_LEFT_DRAGGING, clicked, cursor); clickResult = startCondition(player, inventory, slot, ClickType.START_LEFT_DRAGGING, clicked, cursor);
if (!clickResult.isCancel()) if (!clickResult.isCancel()) this.leftDraggingMap.put(player, new IntOpenHashSet());
this.leftDraggingMap.put(player, new IntOpenHashSet()); } else if (button == 2) {
// End left
final IntSet slots = leftDraggingMap.remove(player);
if (slots == null) return null;
final int slotCount = slots.size();
final int cursorAmount = stackingRule.getAmount(cursor);
if (slotCount > cursorAmount) return null;
for (int s : slots) {
// Apply each drag element
final ItemStack slotItem = itemGetter.apply(s);
clickResult = startCondition(player, inventory, s, ClickType.LEFT_DRAGGING, slotItem, cursor);
if (clickResult.isCancel()) {
return clickResult;
}
}
clickResult = startCondition(player, inventory, slot, ClickType.END_LEFT_DRAGGING, clicked, cursor);
if (clickResult.isCancel()) return clickResult;
// Should be size of each defined slot (if not full)
final int slotSize = (int) ((float) cursorAmount / (float) slotCount);
// Place all waiting drag action
int finalCursorAmount = cursorAmount;
for (int s : slots) {
ItemStack slotItem = itemGetter.apply(s);
final StackingRule slotItemRule = slotItem.getStackingRule();
final int amount = slotItemRule.getAmount(slotItem);
if (stackingRule.canBeStacked(cursor, slotItem)) {
if (stackingRule.canApply(slotItem, amount + slotSize)) {
// Append divided amount to slot
slotItem = stackingRule.apply(slotItem, a -> a + slotSize);
finalCursorAmount -= slotSize;
} else {
// Amount too big, fill as much as possible
final int maxSize = stackingRule.getMaxSize(cursor);
final int removedAmount = maxSize - amount;
slotItem = stackingRule.apply(slotItem, maxSize);
finalCursorAmount -= removedAmount;
}
} else if (slotItem.isAir()) {
// Slot is empty, add divided amount
slotItem = stackingRule.apply(cursor, slotSize);
finalCursorAmount -= slotSize;
}
itemSetter.accept(s, slotItem);
callClickEvent(player, inventory, s, ClickType.LEFT_DRAGGING, slotItem, cursor);
}
// Update the cursor
clickResult.setCursor(stackingRule.apply(cursor, finalCursorAmount));
} else if (button == 4) { } else if (button == 4) {
// Start right // Start right
clickResult = startCondition(player, inventory, slot, ClickType.START_RIGHT_DRAGGING, clicked, cursor); clickResult = startCondition(player, inventory, slot, ClickType.START_RIGHT_DRAGGING, clicked, cursor);
if (!clickResult.isCancel()) if (!clickResult.isCancel()) this.rightDraggingMap.put(player, new IntOpenHashSet());
this.rightDraggingMap.put(player, new IntOpenHashSet());
} else if (button == 2) {
// End left
if (!leftDraggingMap.containsKey(player))
return null;
final IntSet slots = leftDraggingMap.get(player);
final int slotCount = slots.size();
final int cursorAmount = stackingRule.getAmount(cursor);
if (slotCount > cursorAmount)
return null;
boolean cancel = false;
for (int s : slots) {
ItemStack slotItem = itemGetter.apply(s);
clickResult = startCondition(player, inventory, s, ClickType.LEFT_DRAGGING, slotItem, cursor);
if (clickResult.isCancel()) {
cancel = true;
break;
}
}
cancel |= startCondition(player, inventory, slot, ClickType.END_LEFT_DRAGGING, clicked, cursor).isCancel();
// Should be size of each defined slot (if not full)
final int slotSize = (int) ((float) cursorAmount / (float) slotCount);
int finalCursorAmount = cursorAmount;
if (!cancel) {
for (int s : slots) {
ItemStack slotItem = itemGetter.apply(s);
StackingRule slotItemRule = slotItem.getStackingRule();
final int maxSize = stackingRule.getMaxSize(cursor);
if (stackingRule.canBeStacked(cursor, slotItem)) {
final int amount = slotItemRule.getAmount(slotItem);
if (stackingRule.canApply(slotItem, amount + slotSize)) {
slotItem = stackingRule.apply(slotItem, a -> a + slotSize);
finalCursorAmount -= slotSize;
} else {
final int removedAmount = maxSize - amount;
slotItem = stackingRule.apply(slotItem, maxSize);
finalCursorAmount -= removedAmount;
}
} else if (slotItem.isAir()) {
slotItem = stackingRule.apply(cursor, slotSize);
finalCursorAmount -= slotSize;
}
itemSetter.accept(s, slotItem);
callClickEvent(player, inventory, s, ClickType.LEFT_DRAGGING, slotItem, cursor);
}
// If no slots were dragged over, no need to apply any kind of stacking rules
if (clickResult != null) {
cursor = stackingRule.apply(cursor, finalCursorAmount);
clickResult.setCursor(cursor);
}
}
leftDraggingMap.remove(player);
} else if (button == 6) { } else if (button == 6) {
// End right // End right
if (!rightDraggingMap.containsKey(player)) final IntSet slots = rightDraggingMap.remove(player);
return null; if (slots == null) return null;
final IntSet slots = rightDraggingMap.get(player);
final int size = slots.size(); final int size = slots.size();
int cursorAmount = stackingRule.getAmount(cursor); int cursorAmount = stackingRule.getAmount(cursor);
if (size > cursorAmount) if (size > cursorAmount) return null;
return null; // Verify if each slot can be modified (or cancel the whole drag)
boolean cancel = false;
for (int s : slots) { for (int s : slots) {
ItemStack slotItem = itemGetter.apply(s); ItemStack slotItem = itemGetter.apply(s);
clickResult = startCondition(player, inventory, s, ClickType.RIGHT_DRAGGING, slotItem, cursor); clickResult = startCondition(player, inventory, s, ClickType.RIGHT_DRAGGING, slotItem, cursor);
if (clickResult.isCancel()) { if (clickResult.isCancel()) {
cancel = true; return clickResult;
break;
} }
} }
clickResult = startCondition(player, inventory, slot, ClickType.END_RIGHT_DRAGGING, clicked, cursor);
cancel |= startCondition(player, inventory, slot, ClickType.END_RIGHT_DRAGGING, clicked, cursor).isCancel(); if (clickResult.isCancel()) return clickResult;
// Place all waiting drag action
if (!cancel) { int finalCursorAmount = cursorAmount;
for (int s : slots) { for (int s : slots) {
ItemStack draggedItem = cursor; ItemStack slotItem = itemGetter.apply(s);
ItemStack slotItem = itemGetter.apply(s); StackingRule slotItemRule = slotItem.getStackingRule();
if (stackingRule.canBeStacked(cursor, slotItem)) {
StackingRule slotItemRule = slotItem.getStackingRule(); // Compatible item in the slot, increment by 1
if (stackingRule.canBeStacked(draggedItem, slotItem)) { final int amount = slotItemRule.getAmount(slotItem) + 1;
final int amount = slotItemRule.getAmount(slotItem) + 1; if (stackingRule.canApply(slotItem, amount)) {
if (stackingRule.canApply(slotItem, amount)) { slotItem = stackingRule.apply(slotItem, amount);
slotItem = stackingRule.apply(slotItem, amount); finalCursorAmount -= 1;
itemSetter.accept(s, slotItem);
cursorAmount -= 1;
}
} else if (slotItem.isAir()) {
draggedItem = stackingRule.apply(draggedItem, 1);
itemSetter.accept(s, draggedItem);
cursorAmount -= 1;
} }
} else if (slotItem.isAir()) {
callClickEvent(player, inventory, s, ClickType.RIGHT_DRAGGING, draggedItem, cursor); // No item at the slot, place one
} slotItem = stackingRule.apply(cursor, 1);
finalCursorAmount -= 1;
// If no slots were dragged over, no need to apply any kind of stacking rules
if (clickResult != null) {
cursor = stackingRule.apply(cursor, cursorAmount);
clickResult.setCursor(cursor);
} }
itemSetter.accept(s, slotItem);
callClickEvent(player, inventory, s, ClickType.RIGHT_DRAGGING, slotItem, cursor);
} }
// Update the cursor
rightDraggingMap.remove(player); clickResult.setCursor(stackingRule.apply(cursor, finalCursorAmount));
}
} else {
// Add slot
if (button == 1) {
// Add left slot
if (!leftDraggingMap.containsKey(player))
return null;
leftDraggingMap.get(player).add(slot);
} else if (button == 5) {
// Add right slot
if (!rightDraggingMap.containsKey(player))
return null;
rightDraggingMap.get(player).add(slot);
} }
} }
return clickResult; return clickResult;
} }

View File

@ -13,8 +13,6 @@ import net.minestom.server.network.packet.client.play.ClientPongPacket;
import net.minestom.server.network.packet.server.play.PingPacket; import net.minestom.server.network.packet.server.play.PingPacket;
import net.minestom.server.network.packet.server.play.SetSlotPacket; import net.minestom.server.network.packet.server.play.SetSlotPacket;
import java.util.Objects;
public class WindowListener { public class WindowListener {
public static void clickWindowListener(ClientClickWindowPacket packet, Player player) { public static void clickWindowListener(ClientClickWindowPacket packet, Player player) {
@ -33,11 +31,10 @@ public class WindowListener {
boolean successful = false; boolean successful = false;
// prevent click in a non interactive slot (why does it exist?) // prevent click in a non-interactive slot (why does it exist?)
if (slot == -1) { if (slot == -1) {
return; return;
} }
if (clickType == ClientClickWindowPacket.ClickType.PICKUP) { if (clickType == ClientClickWindowPacket.ClickType.PICKUP) {
if (button == 0) { if (button == 0) {
if (slot != -999) { if (slot != -999) {
@ -70,11 +67,7 @@ public class WindowListener {
} }
// Prevent the player from picking a ghost item in cursor // Prevent the player from picking a ghost item in cursor
if (Objects.equals(player.getOpenInventory(), inventory)) { refreshCursorItem(player, inventory);
assert inventory instanceof Inventory;
refreshCursorItem(player, (Inventory) inventory);
}
// Prevent ghost item when the click is cancelled // Prevent ghost item when the click is cancelled
if (!successful) { if (!successful) {
player.getInventory().update(); player.getInventory().update();
@ -82,7 +75,7 @@ public class WindowListener {
((Inventory) inventory).update(player); ((Inventory) inventory).update(player);
} }
} }
// (Why is the ping packet necessary?)
PingPacket pingPacket = new PingPacket(); PingPacket pingPacket = new PingPacket();
pingPacket.id = (1 << 30) | (windowId << 16); pingPacket.id = (1 << 30) | (windowId << 16);
player.getPlayerConnection().sendPacket(pingPacket); player.getPlayerConnection().sendPacket(pingPacket);
@ -108,9 +101,15 @@ public class WindowListener {
* @param player the player to refresh the cursor item * @param player the player to refresh the cursor item
* @param inventory the player open inventory, null if not any (could be player inventory) * @param inventory the player open inventory, null if not any (could be player inventory)
*/ */
private static void refreshCursorItem(Player player, Inventory inventory) { private static void refreshCursorItem(Player player, AbstractInventory inventory) {
ItemStack cursorItem = inventory != null ? ItemStack cursorItem;
inventory.getCursorItem(player) : player.getInventory().getCursorItem(); if (inventory instanceof PlayerInventory) {
cursorItem = ((PlayerInventory) inventory).getCursorItem();
} else if (inventory instanceof Inventory) {
cursorItem = ((Inventory) inventory).getCursorItem(player);
} else {
throw new RuntimeException("Invalid inventory: " + inventory.getClass());
}
final SetSlotPacket setSlotPacket = SetSlotPacket.createCursorPacket(cursorItem); final SetSlotPacket setSlotPacket = SetSlotPacket.createCursorPacket(cursorItem);
player.getPlayerConnection().sendPacket(setSlotPacket); player.getPlayerConnection().sendPacket(setSlotPacket);
} }
@ -120,9 +119,7 @@ public class WindowListener {
((PlayerInventory) inventory).setCursorItem(itemStack); ((PlayerInventory) inventory).setCursorItem(itemStack);
} else if (inventory instanceof Inventory) { } else if (inventory instanceof Inventory) {
((Inventory) inventory).setCursorItem(player, itemStack); ((Inventory) inventory).setCursorItem(player, itemStack);
} else {
System.err.println("Invalid inventory: " + inventory.getClass());
} }
throw new RuntimeException("Invalid inventory: " + inventory.getClass());
} }
} }