mirror of
https://github.com/Minestom/Minestom.git
synced 2024-12-30 13:08:19 +01:00
Fix inventory click
This commit is contained in:
parent
a63c16892c
commit
56eead948a
@ -3,8 +3,8 @@ package net.minestom.server.entity.fakeplayer;
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.instance.block.BlockFace;
|
||||
import net.minestom.server.inventory.Inventory;
|
||||
import net.minestom.server.inventory.AbstractInventory;
|
||||
import net.minestom.server.inventory.Inventory;
|
||||
import net.minestom.server.inventory.PlayerInventory;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.network.packet.client.ClientPlayPacket;
|
||||
@ -43,10 +43,9 @@ public class FakePlayerController {
|
||||
* @param playerInventory {@code true} if the window a {@link PlayerInventory}, otherwise {@code false}.
|
||||
* @param slot The slot where the fake player should click on.
|
||||
* @param button The mouse button that the fake player should used.
|
||||
* @param action The action that the fake player should perform.
|
||||
* @param mode The inventory operation mode that the fake player should used.
|
||||
* @param clickType The click type
|
||||
*/
|
||||
public void clickWindow(boolean playerInventory, short slot, byte button, short action, int mode) {
|
||||
public void clickWindow(boolean playerInventory, short slot, byte button, ClientClickWindowPacket.ClickType clickType) {
|
||||
Inventory inventory = playerInventory ? null : fakePlayer.getOpenInventory();
|
||||
AbstractInventory abstractInventory = inventory == null ? fakePlayer.getInventory() : inventory;
|
||||
playerInventory = abstractInventory instanceof PlayerInventory;
|
||||
@ -59,8 +58,7 @@ public class FakePlayerController {
|
||||
clickWindowPacket.windowId = playerInventory ? 0 : inventory.getWindowId();
|
||||
clickWindowPacket.slot = slot;
|
||||
clickWindowPacket.button = button;
|
||||
clickWindowPacket.actionNumber = action;
|
||||
clickWindowPacket.mode = mode;
|
||||
clickWindowPacket.clickType = clickType;
|
||||
clickWindowPacket.item = itemStack;
|
||||
addToQueue(clickWindowPacket);
|
||||
}
|
||||
|
@ -398,7 +398,7 @@ public class Inventory extends AbstractInventory implements Viewable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean drop(@NotNull Player player, int mode, int slot, int button) {
|
||||
public boolean drop(@NotNull Player player, boolean all, int slot, int button) {
|
||||
final PlayerInventory playerInventory = player.getInventory();
|
||||
final boolean isInWindow = isClickInWindow(slot);
|
||||
final boolean outsideDrop = slot == -999;
|
||||
@ -408,7 +408,7 @@ public class Inventory extends AbstractInventory implements Viewable {
|
||||
final ItemStack cursor = getCursorItem(player);
|
||||
|
||||
final InventoryClickResult clickResult = clickProcessor.drop(isInWindow ? this : null, player,
|
||||
mode, slot, button, clicked, cursor);
|
||||
all, slot, button, clicked, cursor);
|
||||
|
||||
if (clickResult.doRefresh()) {
|
||||
updateFromClick(clickResult, player);
|
||||
|
@ -57,12 +57,12 @@ public interface InventoryClickHandler {
|
||||
* Called when a {@link Player} press the drop button
|
||||
*
|
||||
* @param player the player who clicked
|
||||
* @param mode
|
||||
* @param all
|
||||
* @param slot the slot number
|
||||
* @param button -999 if clicking outside, normal if he is not
|
||||
* @return true if the drop hasn't been cancelled, false otherwise
|
||||
*/
|
||||
boolean drop(@NotNull Player player, int mode, int slot, int button);
|
||||
boolean drop(@NotNull Player player, boolean all, int slot, int button);
|
||||
|
||||
boolean dragging(@NotNull Player player, int slot, int button);
|
||||
|
||||
|
@ -311,13 +311,13 @@ public class PlayerInventory extends AbstractInventory implements EquipmentHandl
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean drop(@NotNull Player player, int mode, int slot, int button) {
|
||||
public boolean drop(@NotNull Player player, boolean all, int slot, int button) {
|
||||
final ItemStack cursor = getCursorItem();
|
||||
final boolean outsideDrop = slot == -999;
|
||||
final ItemStack clicked = outsideDrop ? ItemStack.AIR : getItemStack(slot, OFFSET);
|
||||
|
||||
final InventoryClickResult clickResult = clickProcessor.drop(null, player,
|
||||
mode, slot, button, clicked, cursor);
|
||||
all, slot, button, clicked, cursor);
|
||||
|
||||
if (clickResult.doRefresh())
|
||||
sendSlotRefresh((short) slot, clicked);
|
||||
|
@ -416,7 +416,7 @@ public class InventoryClickProcessor {
|
||||
|
||||
@NotNull
|
||||
public InventoryClickResult drop(@Nullable Inventory inventory, @NotNull Player player,
|
||||
int mode, int slot, int button,
|
||||
boolean all, int slot, int button,
|
||||
@NotNull ItemStack clicked, @NotNull ItemStack cursor) {
|
||||
final InventoryClickResult clickResult = startCondition(inventory, player, slot, ClickType.DROP, clicked, cursor);
|
||||
|
||||
@ -454,7 +454,7 @@ public class InventoryClickProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
} else if (mode == 4) {
|
||||
} else if (!all) {
|
||||
if (button == 0) {
|
||||
// Drop key Q (drop 1)
|
||||
final ItemStack dropItem = cursorRule.apply(resultClicked, 1);
|
||||
|
@ -2,12 +2,14 @@ package net.minestom.server.listener;
|
||||
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.event.inventory.InventoryCloseEvent;
|
||||
import net.minestom.server.inventory.AbstractInventory;
|
||||
import net.minestom.server.inventory.Inventory;
|
||||
import net.minestom.server.inventory.InventoryClickHandler;
|
||||
import net.minestom.server.inventory.PlayerInventory;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.network.packet.client.play.ClientClickWindowPacket;
|
||||
import net.minestom.server.network.packet.client.play.ClientCloseWindowPacket;
|
||||
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.SetSlotPacket;
|
||||
|
||||
import java.util.Objects;
|
||||
@ -15,23 +17,18 @@ import java.util.Objects;
|
||||
public class WindowListener {
|
||||
|
||||
public static void clickWindowListener(ClientClickWindowPacket packet, Player player) {
|
||||
final Inventory inventory;
|
||||
final byte windowId = packet.windowId;
|
||||
if (windowId == 0) {
|
||||
inventory = null;
|
||||
} else {
|
||||
inventory = player.getOpenInventory();
|
||||
final AbstractInventory inventory = windowId == 0 ? player.getInventory() : player.getOpenInventory();
|
||||
if (inventory == null) {
|
||||
// Invalid packet
|
||||
return;
|
||||
}
|
||||
|
||||
InventoryClickHandler clickHandler = inventory == null ?
|
||||
player.getInventory() : player.getOpenInventory();
|
||||
|
||||
final short slot = packet.slot;
|
||||
final byte button = packet.button;
|
||||
final short actionNumber = packet.actionNumber;
|
||||
final int mode = packet.mode;
|
||||
final ClientClickWindowPacket.ClickType clickType = packet.clickType;
|
||||
|
||||
// System.out.println("Window id: " + windowId + " | slot: " + slot + " | button: " + button + " | mode: " + mode);
|
||||
//System.out.println("Window id: " + windowId + " | slot: " + slot + " | button: " + button + " | clickType: " + clickType);
|
||||
|
||||
boolean successful = false;
|
||||
|
||||
@ -40,63 +37,50 @@ public class WindowListener {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case 0:
|
||||
switch (button) {
|
||||
case 0:
|
||||
if (slot != -999) {
|
||||
// Left click
|
||||
successful = clickHandler.leftClick(player, slot);
|
||||
} else {
|
||||
// DROP
|
||||
successful = clickHandler.drop(player, mode, slot, button);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (slot != -999) {
|
||||
// Right click
|
||||
successful = clickHandler.rightClick(player, slot);
|
||||
} else {
|
||||
// DROP
|
||||
successful = clickHandler.drop(player, mode, slot, button);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
successful = clickHandler.shiftClick(player, slot); // Shift + left/right have identical behavior
|
||||
break;
|
||||
case 2:
|
||||
successful = clickHandler.changeHeld(player, slot, button);
|
||||
break;
|
||||
case 3:
|
||||
// Middle click (only creative players in non-player inventories)
|
||||
break;
|
||||
case 4:
|
||||
// Dropping functions
|
||||
successful = clickHandler.drop(player, mode, slot, button);
|
||||
break;
|
||||
case 5:
|
||||
// Dragging
|
||||
successful = clickHandler.dragging(player, slot, button);
|
||||
break;
|
||||
case 6:
|
||||
successful = clickHandler.doubleClick(player, slot);
|
||||
break;
|
||||
if (clickType == ClientClickWindowPacket.ClickType.PICKUP) {
|
||||
if (button == 0) {
|
||||
successful = inventory.leftClick(player, slot);
|
||||
} else if (button == 1) {
|
||||
successful = inventory.rightClick(player, slot);
|
||||
}
|
||||
} else if (clickType == ClientClickWindowPacket.ClickType.QUICK_MOVE) {
|
||||
successful = inventory.shiftClick(player, slot);
|
||||
} else if (clickType == ClientClickWindowPacket.ClickType.SWAP) {
|
||||
successful = inventory.changeHeld(player, slot, button);
|
||||
} else if (clickType == ClientClickWindowPacket.ClickType.CLONE) {
|
||||
successful = player.isCreative();
|
||||
if (successful) {
|
||||
setCursor(player, inventory, packet.item);
|
||||
}
|
||||
} else if (clickType == ClientClickWindowPacket.ClickType.THROW) {
|
||||
successful = inventory.drop(player, false, slot, button);
|
||||
} else if (clickType == ClientClickWindowPacket.ClickType.QUICK_CRAFT) {
|
||||
successful = inventory.dragging(player, slot, button);
|
||||
} else if (clickType == ClientClickWindowPacket.ClickType.PICKUP_ALL) {
|
||||
successful = inventory.doubleClick(player, slot);
|
||||
}
|
||||
|
||||
// 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
|
||||
if (!successful) {
|
||||
player.getInventory().update();
|
||||
if (inventory != null) {
|
||||
inventory.update(player);
|
||||
if (inventory instanceof Inventory) {
|
||||
((Inventory) inventory).update(player);
|
||||
}
|
||||
}
|
||||
|
||||
PingPacket pingPacket = new PingPacket();
|
||||
pingPacket.id = (1 << 30) | (windowId << 16);
|
||||
player.getPlayerConnection().sendPacket(pingPacket);
|
||||
}
|
||||
|
||||
public static void pong(ClientPongPacket packet, Player player) {
|
||||
// Empty
|
||||
}
|
||||
|
||||
public static void closeWindowListener(ClientCloseWindowPacket packet, Player player) {
|
||||
@ -116,23 +100,20 @@ public class WindowListener {
|
||||
* @param inventory the player open inventory, null if not any (could be player inventory)
|
||||
*/
|
||||
private static void refreshCursorItem(Player player, Inventory inventory) {
|
||||
PlayerInventory playerInventory = player.getInventory();
|
||||
|
||||
ItemStack cursorItem;
|
||||
if (inventory != null) {
|
||||
cursorItem = inventory.getCursorItem(player);
|
||||
} else {
|
||||
cursorItem = playerInventory.getCursorItem();
|
||||
}
|
||||
|
||||
// Error occurred while retrieving the cursor item, stop here
|
||||
if (cursorItem == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack cursorItem = inventory != null ?
|
||||
inventory.getCursorItem(player) : player.getInventory().getCursorItem();
|
||||
final SetSlotPacket setSlotPacket = SetSlotPacket.createCursorPacket(cursorItem);
|
||||
|
||||
player.getPlayerConnection().sendPacket(setSlotPacket);
|
||||
}
|
||||
|
||||
private static void setCursor(Player player, AbstractInventory inventory, ItemStack itemStack) {
|
||||
if (inventory instanceof PlayerInventory) {
|
||||
((PlayerInventory) inventory).setCursorItem(itemStack);
|
||||
} else if (inventory instanceof Inventory) {
|
||||
((Inventory) inventory).setCursorItem(player, itemStack);
|
||||
} else {
|
||||
System.err.println("Invalid inventory: " + inventory.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ public final class PacketListenerManager {
|
||||
setListener(ClientChatMessagePacket.class, ChatMessageListener::listener);
|
||||
setListener(ClientClickWindowPacket.class, WindowListener::clickWindowListener);
|
||||
setListener(ClientCloseWindowPacket.class, WindowListener::closeWindowListener);
|
||||
setListener(ClientPongPacket.class, WindowListener::pong);
|
||||
setListener(ClientEntityActionPacket.class, EntityActionListener::listener);
|
||||
setListener(ClientHeldItemChangePacket.class, PlayerHeldListener::heldListener);
|
||||
setListener(ClientPlayerBlockPlacementPacket.class, BlockPlacementListener::listener);
|
||||
|
@ -34,7 +34,7 @@ public class ClientPlayPacketsHandler extends ClientPacketsHandler {
|
||||
register(0x1A, ClientPlayerDiggingPacket::new);
|
||||
register(0x1B, ClientEntityActionPacket::new);
|
||||
register(0x1C, ClientSteerVehiclePacket::new);
|
||||
//register(0x1D, PONG); // TODO pong packet
|
||||
register(0x1D, ClientPongPacket::new);
|
||||
register(0x1E, ClientSetRecipeBookStatePacket::new);
|
||||
register(0x1F, ClientSetDisplayedRecipePacket::new);
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
package net.minestom.server.network.packet.client.play;
|
||||
|
||||
import it.unimi.dsi.fastutil.shorts.Short2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.network.packet.client.ClientPlayPacket;
|
||||
import net.minestom.server.utils.binary.BinaryReader;
|
||||
@ -11,8 +13,8 @@ public class ClientClickWindowPacket extends ClientPlayPacket {
|
||||
public byte windowId;
|
||||
public short slot;
|
||||
public byte button;
|
||||
public short actionNumber;
|
||||
public int mode;
|
||||
public ClickType clickType;
|
||||
public Short2ObjectMap<ItemStack> changedSlots = new Short2ObjectOpenHashMap<>();
|
||||
public ItemStack item = ItemStack.AIR;
|
||||
|
||||
@Override
|
||||
@ -20,8 +22,15 @@ public class ClientClickWindowPacket extends ClientPlayPacket {
|
||||
this.windowId = reader.readByte();
|
||||
this.slot = reader.readShort();
|
||||
this.button = reader.readByte();
|
||||
this.actionNumber = reader.readShort();
|
||||
this.mode = reader.readVarInt();
|
||||
this.clickType = ClickType.values()[reader.readVarInt()];
|
||||
|
||||
final int length = reader.readVarInt();
|
||||
this.changedSlots = new Short2ObjectOpenHashMap<>(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
short slot = reader.readShort();
|
||||
ItemStack item = reader.readItemStack();
|
||||
changedSlots.put(slot, item);
|
||||
}
|
||||
this.item = reader.readItemStack();
|
||||
}
|
||||
|
||||
@ -30,8 +39,23 @@ public class ClientClickWindowPacket extends ClientPlayPacket {
|
||||
writer.writeByte(windowId);
|
||||
writer.writeShort(slot);
|
||||
writer.writeByte(button);
|
||||
writer.writeShort(actionNumber);
|
||||
writer.writeVarInt(mode);
|
||||
writer.writeVarInt(clickType.ordinal());
|
||||
|
||||
writer.writeVarInt(changedSlots.size());
|
||||
changedSlots.forEach((slot, itemStack) -> {
|
||||
writer.writeShort(slot);
|
||||
writer.writeItemStack(itemStack);
|
||||
});
|
||||
writer.writeItemStack(item);
|
||||
}
|
||||
|
||||
public enum ClickType {
|
||||
PICKUP,
|
||||
QUICK_MOVE,
|
||||
SWAP,
|
||||
CLONE,
|
||||
THROW,
|
||||
QUICK_CRAFT,
|
||||
PICKUP_ALL
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,21 @@
|
||||
package net.minestom.server.network.packet.client.play;
|
||||
|
||||
import net.minestom.server.network.packet.client.ClientPlayPacket;
|
||||
import net.minestom.server.utils.binary.BinaryReader;
|
||||
import net.minestom.server.utils.binary.BinaryWriter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ClientPongPacket extends ClientPlayPacket {
|
||||
|
||||
public int id;
|
||||
|
||||
@Override
|
||||
public void read(@NotNull BinaryReader reader) {
|
||||
this.id = reader.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull BinaryWriter writer) {
|
||||
writer.writeInt(id);
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package net.minestom.server.network.packet.server.play;
|
||||
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||
import net.minestom.server.utils.binary.BinaryReader;
|
||||
import net.minestom.server.utils.binary.BinaryWriter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class PingPacket implements ServerPacket {
|
||||
|
||||
public int id;
|
||||
|
||||
@Override
|
||||
public void read(@NotNull BinaryReader reader) {
|
||||
this.id = reader.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull BinaryWriter writer) {
|
||||
writer.writeInt(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return ServerPacketIdentifier.PING;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user