mirror of
https://github.com/Minestom/Minestom.git
synced 2025-04-08 13:16:43 +02:00
Integrate PlayerInventory (#2332)
* Integrate player inventory and normal inventory * Fix errors and broken tests (drop before adding, wrong order, etc) * Refactor slot refreshing * Fix viewer logic error * Fix incorrect merge * Move inventory update * Minor simplifications * More minor simplifications
This commit is contained in:
parent
41738bb62a
commit
e0939f089b
@ -48,6 +48,7 @@ import net.minestom.server.instance.EntityTracker;
|
|||||||
import net.minestom.server.instance.Instance;
|
import net.minestom.server.instance.Instance;
|
||||||
import net.minestom.server.instance.SharedInstance;
|
import net.minestom.server.instance.SharedInstance;
|
||||||
import net.minestom.server.instance.block.Block;
|
import net.minestom.server.instance.block.Block;
|
||||||
|
import net.minestom.server.inventory.AbstractInventory;
|
||||||
import net.minestom.server.inventory.Inventory;
|
import net.minestom.server.inventory.Inventory;
|
||||||
import net.minestom.server.inventory.PlayerInventory;
|
import net.minestom.server.inventory.PlayerInventory;
|
||||||
import net.minestom.server.item.ItemComponent;
|
import net.minestom.server.item.ItemComponent;
|
||||||
@ -175,7 +176,7 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou
|
|||||||
private int portalCooldown = 0;
|
private int portalCooldown = 0;
|
||||||
|
|
||||||
protected PlayerInventory inventory;
|
protected PlayerInventory inventory;
|
||||||
private Inventory openInventory;
|
private AbstractInventory openInventory;
|
||||||
// Used internally to allow the closing of inventory within the inventory listener
|
// Used internally to allow the closing of inventory within the inventory listener
|
||||||
private boolean didCloseInventory;
|
private boolean didCloseInventory;
|
||||||
|
|
||||||
@ -236,7 +237,7 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou
|
|||||||
|
|
||||||
setRespawnPoint(Pos.ZERO);
|
setRespawnPoint(Pos.ZERO);
|
||||||
|
|
||||||
this.inventory = new PlayerInventory(this);
|
this.inventory = new PlayerInventory();
|
||||||
|
|
||||||
setCanPickupItem(true); // By default
|
setCanPickupItem(true); // By default
|
||||||
|
|
||||||
@ -295,6 +296,9 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou
|
|||||||
true);
|
true);
|
||||||
sendPacket(joinGamePacket);
|
sendPacket(joinGamePacket);
|
||||||
|
|
||||||
|
// Start sending inventory updates
|
||||||
|
inventory.addViewer(this);
|
||||||
|
|
||||||
// Difficulty
|
// Difficulty
|
||||||
sendPacket(new ServerDifficultyPacket(MinecraftServer.getDifficulty(), true));
|
sendPacket(new ServerDifficultyPacket(MinecraftServer.getDifficulty(), true));
|
||||||
|
|
||||||
@ -573,8 +577,9 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou
|
|||||||
|
|
||||||
super.remove(permanent);
|
super.remove(permanent);
|
||||||
|
|
||||||
final Inventory currentInventory = getOpenInventory();
|
final AbstractInventory currentInventory = getOpenInventory();
|
||||||
if (currentInventory != null) currentInventory.removeViewer(this);
|
if (currentInventory != null) currentInventory.removeViewer(this);
|
||||||
|
|
||||||
MinecraftServer.getBossBarManager().removeAllBossBars(this);
|
MinecraftServer.getBossBarManager().removeAllBossBars(this);
|
||||||
// Advancement tabs cache
|
// Advancement tabs cache
|
||||||
{
|
{
|
||||||
@ -1724,7 +1729,7 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou
|
|||||||
*
|
*
|
||||||
* @return the currently open inventory, null if there is not (player inventory is not detected)
|
* @return the currently open inventory, null if there is not (player inventory is not detected)
|
||||||
*/
|
*/
|
||||||
public @Nullable Inventory getOpenInventory() {
|
public @Nullable AbstractInventory getOpenInventory() {
|
||||||
return openInventory;
|
return openInventory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1738,19 +1743,13 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou
|
|||||||
InventoryOpenEvent inventoryOpenEvent = new InventoryOpenEvent(inventory, this);
|
InventoryOpenEvent inventoryOpenEvent = new InventoryOpenEvent(inventory, this);
|
||||||
|
|
||||||
EventDispatcher.callCancellable(inventoryOpenEvent, () -> {
|
EventDispatcher.callCancellable(inventoryOpenEvent, () -> {
|
||||||
Inventory openInventory = getOpenInventory();
|
AbstractInventory openInventory = getOpenInventory();
|
||||||
if (openInventory != null) {
|
if (openInventory != null) {
|
||||||
openInventory.removeViewer(this);
|
openInventory.removeViewer(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Inventory newInventory = inventoryOpenEvent.getInventory();
|
AbstractInventory newInventory = inventoryOpenEvent.getInventory();
|
||||||
if (newInventory == null) {
|
|
||||||
// just close the inventory
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sendPacket(new OpenWindowPacket(newInventory.getWindowId(),
|
|
||||||
newInventory.getInventoryType().getWindowType(), newInventory.getTitle()));
|
|
||||||
newInventory.addViewer(this);
|
newInventory.addViewer(this);
|
||||||
this.openInventory = newInventory;
|
this.openInventory = newInventory;
|
||||||
});
|
});
|
||||||
@ -1767,31 +1766,15 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou
|
|||||||
|
|
||||||
@ApiStatus.Internal
|
@ApiStatus.Internal
|
||||||
public void closeInventory(boolean fromClient) {
|
public void closeInventory(boolean fromClient) {
|
||||||
Inventory openInventory = getOpenInventory();
|
AbstractInventory openInventory = getOpenInventory();
|
||||||
|
if (openInventory == null) return;
|
||||||
|
|
||||||
// Drop cursor item when closing inventory
|
this.openInventory = null;
|
||||||
ItemStack cursorItem = getInventory().getCursorItem();
|
openInventory.removeViewer(this);
|
||||||
getInventory().setCursorItem(ItemStack.AIR);
|
inventory.update();
|
||||||
|
|
||||||
if (!cursorItem.isAir()) {
|
if (!fromClient) {
|
||||||
// Add item to inventory if he hasn't been able to drop it
|
didCloseInventory = true;
|
||||||
if (!dropItem(cursorItem)) {
|
|
||||||
getInventory().addItemStack(cursorItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (openInventory == getOpenInventory()) {
|
|
||||||
CloseWindowPacket closeWindowPacket;
|
|
||||||
if (openInventory == null) {
|
|
||||||
closeWindowPacket = new CloseWindowPacket((byte) 0);
|
|
||||||
} else {
|
|
||||||
closeWindowPacket = new CloseWindowPacket(openInventory.getWindowId());
|
|
||||||
openInventory.removeViewer(this); // Clear cache
|
|
||||||
this.openInventory = null;
|
|
||||||
}
|
|
||||||
if (!fromClient) sendPacket(closeWindowPacket);
|
|
||||||
inventory.update();
|
|
||||||
this.didCloseInventory = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2276,12 +2259,12 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull ItemStack getEquipment(@NotNull EquipmentSlot slot) {
|
public @NotNull ItemStack getEquipment(@NotNull EquipmentSlot slot) {
|
||||||
return inventory.getEquipment(slot);
|
return inventory.getEquipment(slot, heldSlot);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setEquipment(@NotNull EquipmentSlot slot, @NotNull ItemStack itemStack) {
|
public void setEquipment(@NotNull EquipmentSlot slot, @NotNull ItemStack itemStack) {
|
||||||
inventory.setEquipment(slot, itemStack);
|
inventory.setEquipment(slot, heldSlot, itemStack);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -5,7 +5,7 @@ import net.minestom.server.entity.Player;
|
|||||||
import net.minestom.server.event.trait.*;
|
import net.minestom.server.event.trait.*;
|
||||||
import net.minestom.server.instance.Instance;
|
import net.minestom.server.instance.Instance;
|
||||||
import net.minestom.server.instance.block.Block;
|
import net.minestom.server.instance.block.Block;
|
||||||
import net.minestom.server.inventory.Inventory;
|
import net.minestom.server.inventory.AbstractInventory;
|
||||||
import net.minestom.server.item.ItemStack;
|
import net.minestom.server.item.ItemStack;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -34,7 +34,7 @@ public interface EventFilter<E extends Event, H> {
|
|||||||
EventFilter<PlayerEvent, Player> PLAYER = from(PlayerEvent.class, Player.class, PlayerEvent::getPlayer);
|
EventFilter<PlayerEvent, Player> PLAYER = from(PlayerEvent.class, Player.class, PlayerEvent::getPlayer);
|
||||||
EventFilter<ItemEvent, ItemStack> ITEM = from(ItemEvent.class, ItemStack.class, ItemEvent::getItemStack);
|
EventFilter<ItemEvent, ItemStack> ITEM = from(ItemEvent.class, ItemStack.class, ItemEvent::getItemStack);
|
||||||
EventFilter<InstanceEvent, Instance> INSTANCE = from(InstanceEvent.class, Instance.class, InstanceEvent::getInstance);
|
EventFilter<InstanceEvent, Instance> INSTANCE = from(InstanceEvent.class, Instance.class, InstanceEvent::getInstance);
|
||||||
EventFilter<InventoryEvent, Inventory> INVENTORY = from(InventoryEvent.class, Inventory.class, InventoryEvent::getInventory);
|
EventFilter<InventoryEvent, AbstractInventory> INVENTORY = from(InventoryEvent.class, AbstractInventory.class, InventoryEvent::getInventory);
|
||||||
EventFilter<BlockEvent, Block> BLOCK = from(BlockEvent.class, Block.class, BlockEvent::getBlock);
|
EventFilter<BlockEvent, Block> BLOCK = from(BlockEvent.class, Block.class, BlockEvent::getBlock);
|
||||||
|
|
||||||
static <E extends Event, H> EventFilter<E, H> from(@NotNull Class<E> eventType,
|
static <E extends Event, H> EventFilter<E, H> from(@NotNull Class<E> eventType,
|
||||||
|
@ -3,11 +3,10 @@ package net.minestom.server.event.inventory;
|
|||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.event.trait.InventoryEvent;
|
import net.minestom.server.event.trait.InventoryEvent;
|
||||||
import net.minestom.server.event.trait.PlayerInstanceEvent;
|
import net.minestom.server.event.trait.PlayerInstanceEvent;
|
||||||
import net.minestom.server.inventory.Inventory;
|
import net.minestom.server.inventory.AbstractInventory;
|
||||||
import net.minestom.server.inventory.click.ClickType;
|
import net.minestom.server.inventory.click.ClickType;
|
||||||
import net.minestom.server.item.ItemStack;
|
import net.minestom.server.item.ItemStack;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called after {@link InventoryPreClickEvent}, this event cannot be cancelled and items related to the click
|
* Called after {@link InventoryPreClickEvent}, this event cannot be cancelled and items related to the click
|
||||||
@ -15,14 +14,14 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
*/
|
*/
|
||||||
public class InventoryClickEvent implements InventoryEvent, PlayerInstanceEvent {
|
public class InventoryClickEvent implements InventoryEvent, PlayerInstanceEvent {
|
||||||
|
|
||||||
private final Inventory inventory;
|
private final AbstractInventory inventory;
|
||||||
private final Player player;
|
private final Player player;
|
||||||
private final int slot;
|
private final int slot;
|
||||||
private final ClickType clickType;
|
private final ClickType clickType;
|
||||||
private final ItemStack clickedItem;
|
private final ItemStack clickedItem;
|
||||||
private final ItemStack cursorItem;
|
private final ItemStack cursorItem;
|
||||||
|
|
||||||
public InventoryClickEvent(@Nullable Inventory inventory, @NotNull Player player,
|
public InventoryClickEvent(@NotNull AbstractInventory inventory, @NotNull Player player,
|
||||||
int slot, @NotNull ClickType clickType,
|
int slot, @NotNull ClickType clickType,
|
||||||
@NotNull ItemStack clicked, @NotNull ItemStack cursor) {
|
@NotNull ItemStack clicked, @NotNull ItemStack cursor) {
|
||||||
this.inventory = inventory;
|
this.inventory = inventory;
|
||||||
@ -83,7 +82,7 @@ public class InventoryClickEvent implements InventoryEvent, PlayerInstanceEvent
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable Inventory getInventory() {
|
public @NotNull AbstractInventory getInventory() {
|
||||||
return inventory;
|
return inventory;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,20 +3,21 @@ package net.minestom.server.event.inventory;
|
|||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.event.trait.InventoryEvent;
|
import net.minestom.server.event.trait.InventoryEvent;
|
||||||
import net.minestom.server.event.trait.PlayerInstanceEvent;
|
import net.minestom.server.event.trait.PlayerInstanceEvent;
|
||||||
|
import net.minestom.server.inventory.AbstractInventory;
|
||||||
import net.minestom.server.inventory.Inventory;
|
import net.minestom.server.inventory.Inventory;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when an {@link Inventory} is closed by a player.
|
* Called when an {@link AbstractInventory} is closed by a player.
|
||||||
*/
|
*/
|
||||||
public class InventoryCloseEvent implements InventoryEvent, PlayerInstanceEvent {
|
public class InventoryCloseEvent implements InventoryEvent, PlayerInstanceEvent {
|
||||||
|
|
||||||
private final Inventory inventory;
|
private final AbstractInventory inventory;
|
||||||
private final Player player;
|
private final Player player;
|
||||||
private Inventory newInventory;
|
private Inventory newInventory;
|
||||||
|
|
||||||
public InventoryCloseEvent(@Nullable Inventory inventory, @NotNull Player player) {
|
public InventoryCloseEvent(@NotNull AbstractInventory inventory, @NotNull Player player) {
|
||||||
this.inventory = inventory;
|
this.inventory = inventory;
|
||||||
this.player = player;
|
this.player = player;
|
||||||
}
|
}
|
||||||
@ -51,7 +52,7 @@ public class InventoryCloseEvent implements InventoryEvent, PlayerInstanceEvent
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable Inventory getInventory() {
|
public @NotNull AbstractInventory getInventory() {
|
||||||
return inventory;
|
return inventory;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,8 @@ package net.minestom.server.event.inventory;
|
|||||||
import net.minestom.server.event.trait.InventoryEvent;
|
import net.minestom.server.event.trait.InventoryEvent;
|
||||||
import net.minestom.server.event.trait.RecursiveEvent;
|
import net.minestom.server.event.trait.RecursiveEvent;
|
||||||
import net.minestom.server.inventory.AbstractInventory;
|
import net.minestom.server.inventory.AbstractInventory;
|
||||||
import net.minestom.server.inventory.Inventory;
|
|
||||||
import net.minestom.server.item.ItemStack;
|
import net.minestom.server.item.ItemStack;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when {@link AbstractInventory#safeItemInsert(int, ItemStack)} is being invoked.
|
* Called when {@link AbstractInventory#safeItemInsert(int, ItemStack)} is being invoked.
|
||||||
@ -17,12 +15,12 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
@SuppressWarnings("JavadocReference")
|
@SuppressWarnings("JavadocReference")
|
||||||
public class InventoryItemChangeEvent implements InventoryEvent, RecursiveEvent {
|
public class InventoryItemChangeEvent implements InventoryEvent, RecursiveEvent {
|
||||||
|
|
||||||
private final Inventory inventory;
|
private final AbstractInventory inventory;
|
||||||
private final int slot;
|
private final int slot;
|
||||||
private final ItemStack previousItem;
|
private final ItemStack previousItem;
|
||||||
private final ItemStack newItem;
|
private final ItemStack newItem;
|
||||||
|
|
||||||
public InventoryItemChangeEvent(@Nullable Inventory inventory, int slot,
|
public InventoryItemChangeEvent(@NotNull AbstractInventory inventory, int slot,
|
||||||
@NotNull ItemStack previousItem, @NotNull ItemStack newItem) {
|
@NotNull ItemStack previousItem, @NotNull ItemStack newItem) {
|
||||||
this.inventory = inventory;
|
this.inventory = inventory;
|
||||||
this.slot = slot;
|
this.slot = slot;
|
||||||
@ -58,7 +56,7 @@ public class InventoryItemChangeEvent implements InventoryEvent, RecursiveEvent
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable Inventory getInventory() {
|
public @NotNull AbstractInventory getInventory() {
|
||||||
return inventory;
|
return inventory;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,23 +4,23 @@ import net.minestom.server.entity.Player;
|
|||||||
import net.minestom.server.event.trait.CancellableEvent;
|
import net.minestom.server.event.trait.CancellableEvent;
|
||||||
import net.minestom.server.event.trait.InventoryEvent;
|
import net.minestom.server.event.trait.InventoryEvent;
|
||||||
import net.minestom.server.event.trait.PlayerInstanceEvent;
|
import net.minestom.server.event.trait.PlayerInstanceEvent;
|
||||||
|
import net.minestom.server.inventory.AbstractInventory;
|
||||||
import net.minestom.server.inventory.Inventory;
|
import net.minestom.server.inventory.Inventory;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a player open an {@link Inventory}.
|
* Called when a player open an {@link AbstractInventory}.
|
||||||
* <p>
|
* <p>
|
||||||
* Executed by {@link Player#openInventory(Inventory)}.
|
* Executed by {@link Player#openInventory(Inventory)}.
|
||||||
*/
|
*/
|
||||||
public class InventoryOpenEvent implements InventoryEvent, PlayerInstanceEvent, CancellableEvent {
|
public class InventoryOpenEvent implements InventoryEvent, PlayerInstanceEvent, CancellableEvent {
|
||||||
|
|
||||||
private Inventory inventory;
|
private AbstractInventory inventory;
|
||||||
private final Player player;
|
private final Player player;
|
||||||
|
|
||||||
private boolean cancelled;
|
private boolean cancelled;
|
||||||
|
|
||||||
public InventoryOpenEvent(@Nullable Inventory inventory, @NotNull Player player) {
|
public InventoryOpenEvent(@NotNull AbstractInventory inventory, @NotNull Player player) {
|
||||||
this.inventory = inventory;
|
this.inventory = inventory;
|
||||||
this.player = player;
|
this.player = player;
|
||||||
}
|
}
|
||||||
@ -36,13 +36,12 @@ public class InventoryOpenEvent implements InventoryEvent, PlayerInstanceEvent,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the inventory to open, this could have been change by the {@link #setInventory(Inventory)}.
|
* Gets the inventory to open, this could have been change by the {@link #setInventory(AbstractInventory)}.
|
||||||
*
|
*
|
||||||
* @return the inventory to open, null to just close the current inventory if any
|
* @return the inventory to open, null to just close the current inventory if any
|
||||||
*/
|
*/
|
||||||
@Nullable
|
|
||||||
@Override
|
@Override
|
||||||
public Inventory getInventory() {
|
public @NotNull AbstractInventory getInventory() {
|
||||||
return inventory;
|
return inventory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +52,7 @@ public class InventoryOpenEvent implements InventoryEvent, PlayerInstanceEvent,
|
|||||||
*
|
*
|
||||||
* @param inventory the inventory to open
|
* @param inventory the inventory to open
|
||||||
*/
|
*/
|
||||||
public void setInventory(@Nullable Inventory inventory) {
|
public void setInventory(@NotNull AbstractInventory inventory) {
|
||||||
this.inventory = inventory;
|
this.inventory = inventory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,18 +4,17 @@ import net.minestom.server.entity.Player;
|
|||||||
import net.minestom.server.event.trait.CancellableEvent;
|
import net.minestom.server.event.trait.CancellableEvent;
|
||||||
import net.minestom.server.event.trait.InventoryEvent;
|
import net.minestom.server.event.trait.InventoryEvent;
|
||||||
import net.minestom.server.event.trait.PlayerInstanceEvent;
|
import net.minestom.server.event.trait.PlayerInstanceEvent;
|
||||||
import net.minestom.server.inventory.Inventory;
|
import net.minestom.server.inventory.AbstractInventory;
|
||||||
import net.minestom.server.inventory.click.ClickType;
|
import net.minestom.server.inventory.click.ClickType;
|
||||||
import net.minestom.server.item.ItemStack;
|
import net.minestom.server.item.ItemStack;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called before {@link InventoryClickEvent}, used to potentially cancel the click.
|
* Called before {@link InventoryClickEvent}, used to potentially cancel the click.
|
||||||
*/
|
*/
|
||||||
public class InventoryPreClickEvent implements InventoryEvent, PlayerInstanceEvent, CancellableEvent {
|
public class InventoryPreClickEvent implements InventoryEvent, PlayerInstanceEvent, CancellableEvent {
|
||||||
|
|
||||||
private final Inventory inventory;
|
private final AbstractInventory inventory;
|
||||||
private final Player player;
|
private final Player player;
|
||||||
private final int slot;
|
private final int slot;
|
||||||
private final ClickType clickType;
|
private final ClickType clickType;
|
||||||
@ -24,7 +23,7 @@ public class InventoryPreClickEvent implements InventoryEvent, PlayerInstanceEve
|
|||||||
|
|
||||||
private boolean cancelled;
|
private boolean cancelled;
|
||||||
|
|
||||||
public InventoryPreClickEvent(@Nullable Inventory inventory,
|
public InventoryPreClickEvent(@NotNull AbstractInventory inventory,
|
||||||
@NotNull Player player,
|
@NotNull Player player,
|
||||||
int slot, @NotNull ClickType clickType,
|
int slot, @NotNull ClickType clickType,
|
||||||
@NotNull ItemStack clicked, @NotNull ItemStack cursor) {
|
@NotNull ItemStack clicked, @NotNull ItemStack cursor) {
|
||||||
@ -114,7 +113,7 @@ public class InventoryPreClickEvent implements InventoryEvent, PlayerInstanceEve
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable Inventory getInventory() {
|
public @NotNull AbstractInventory getInventory() {
|
||||||
return inventory;
|
return inventory;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
package net.minestom.server.event.inventory;
|
|
||||||
|
|
||||||
import net.minestom.server.entity.Player;
|
|
||||||
import net.minestom.server.event.trait.PlayerInstanceEvent;
|
|
||||||
import net.minestom.server.inventory.AbstractInventory;
|
|
||||||
import net.minestom.server.inventory.PlayerInventory;
|
|
||||||
import net.minestom.server.item.ItemStack;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when {@link AbstractInventory#safeItemInsert(int, ItemStack)} is being invoked on a {@link PlayerInventory}.
|
|
||||||
* This event cannot be cancelled and items related to the change are already moved.
|
|
||||||
* <p>
|
|
||||||
* When this event is being called, {@link InventoryItemChangeEvent} listeners will also be triggered, so you can
|
|
||||||
* listen only for an ancestor event and check whether it is an instance of that class.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("JavadocReference")
|
|
||||||
public class PlayerInventoryItemChangeEvent extends InventoryItemChangeEvent implements PlayerInstanceEvent {
|
|
||||||
|
|
||||||
private final Player player;
|
|
||||||
|
|
||||||
public PlayerInventoryItemChangeEvent(@NotNull Player player, int slot, @NotNull ItemStack previousItem, @NotNull ItemStack newItem) {
|
|
||||||
super(null, slot, previousItem, newItem);
|
|
||||||
this.player = player;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NotNull Player getPlayer() {
|
|
||||||
return player;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +1,16 @@
|
|||||||
package net.minestom.server.event.trait;
|
package net.minestom.server.event.trait;
|
||||||
|
|
||||||
import net.minestom.server.event.Event;
|
import net.minestom.server.event.Event;
|
||||||
import net.minestom.server.inventory.Inventory;
|
import net.minestom.server.inventory.AbstractInventory;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents any event inside an {@link Inventory}.
|
* Represents any event inside an {@link AbstractInventory}.
|
||||||
*/
|
*/
|
||||||
public interface InventoryEvent extends Event {
|
public interface InventoryEvent extends Event {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the inventory.
|
* Gets the inventory that was clicked.
|
||||||
*
|
|
||||||
* @return the inventory, null if this is a player's inventory
|
|
||||||
*/
|
*/
|
||||||
@Nullable Inventory getInventory();
|
@NotNull AbstractInventory getInventory();
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
package net.minestom.server.inventory;
|
package net.minestom.server.inventory;
|
||||||
|
|
||||||
|
import net.minestom.server.Viewable;
|
||||||
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.event.EventDispatcher;
|
import net.minestom.server.event.EventDispatcher;
|
||||||
import net.minestom.server.event.inventory.InventoryItemChangeEvent;
|
import net.minestom.server.event.inventory.InventoryItemChangeEvent;
|
||||||
import net.minestom.server.event.inventory.PlayerInventoryItemChangeEvent;
|
|
||||||
import net.minestom.server.inventory.click.InventoryClickProcessor;
|
import net.minestom.server.inventory.click.InventoryClickProcessor;
|
||||||
import net.minestom.server.inventory.condition.InventoryCondition;
|
import net.minestom.server.inventory.condition.InventoryCondition;
|
||||||
import net.minestom.server.item.ItemStack;
|
import net.minestom.server.item.ItemStack;
|
||||||
|
import net.minestom.server.network.packet.server.play.CloseWindowPacket;
|
||||||
|
import net.minestom.server.network.packet.server.play.SetSlotPacket;
|
||||||
|
import net.minestom.server.network.packet.server.play.WindowItemsPacket;
|
||||||
import net.minestom.server.tag.TagHandler;
|
import net.minestom.server.tag.TagHandler;
|
||||||
import net.minestom.server.tag.Taggable;
|
import net.minestom.server.tag.Taggable;
|
||||||
import net.minestom.server.utils.MathUtils;
|
import net.minestom.server.utils.MathUtils;
|
||||||
@ -14,16 +18,15 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
|
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.lang.invoke.VarHandle;
|
import java.lang.invoke.VarHandle;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
import java.util.function.UnaryOperator;
|
import java.util.function.UnaryOperator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an inventory where items can be modified/retrieved.
|
* Represents an inventory where items can be modified/retrieved.
|
||||||
*/
|
*/
|
||||||
public sealed abstract class AbstractInventory implements InventoryClickHandler, Taggable
|
public sealed abstract class AbstractInventory implements InventoryClickHandler, Taggable, Viewable
|
||||||
permits Inventory, PlayerInventory {
|
permits Inventory, PlayerInventory {
|
||||||
|
|
||||||
private static final VarHandle ITEM_UPDATER = MethodHandles.arrayElementVarHandle(ItemStack[].class);
|
private static final VarHandle ITEM_UPDATER = MethodHandles.arrayElementVarHandle(ItemStack[].class);
|
||||||
@ -38,58 +41,97 @@ public sealed abstract class AbstractInventory implements InventoryClickHandler,
|
|||||||
|
|
||||||
private final TagHandler tagHandler = TagHandler.newHandler();
|
private final TagHandler tagHandler = TagHandler.newHandler();
|
||||||
|
|
||||||
|
// the players currently viewing this inventory
|
||||||
|
protected final Set<Player> viewers = new CopyOnWriteArraySet<>();
|
||||||
|
protected final Set<Player> unmodifiableViewers = Collections.unmodifiableSet(viewers);
|
||||||
|
|
||||||
protected AbstractInventory(int size) {
|
protected AbstractInventory(int size) {
|
||||||
this.size = size;
|
this.size = size;
|
||||||
this.itemStacks = new ItemStack[getSize()];
|
this.itemStacks = new ItemStack[getSize()];
|
||||||
Arrays.fill(itemStacks, ItemStack.AIR);
|
Arrays.fill(itemStacks, ItemStack.AIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets this window id.
|
||||||
|
* <p>
|
||||||
|
* This is the id that the client will send to identify the affected inventory, mostly used by packets.
|
||||||
|
*
|
||||||
|
* @return the window id
|
||||||
|
*/
|
||||||
|
public abstract byte getWindowId();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Set<Player> getViewers() {
|
||||||
|
return unmodifiableViewers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addViewer(@NotNull Player player) {
|
||||||
|
if (!this.viewers.add(player)) return false;
|
||||||
|
|
||||||
|
update(player);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeViewer(@NotNull Player player) {
|
||||||
|
if (!this.viewers.remove(player)) return false;
|
||||||
|
|
||||||
|
// Drop cursor item when closing inventory
|
||||||
|
ItemStack cursorItem = player.getInventory().getCursorItem();
|
||||||
|
player.getInventory().setCursorItem(ItemStack.AIR);
|
||||||
|
|
||||||
|
if (!cursorItem.isAir()) {
|
||||||
|
if (!player.dropItem(cursorItem)) {
|
||||||
|
player.getInventory().addItemStack(cursorItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player.didCloseInventory()) {
|
||||||
|
player.sendPacket(new CloseWindowPacket(getWindowId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets an {@link ItemStack} at the specified slot and send relevant update to the viewer(s).
|
* Sets an {@link ItemStack} at the specified slot and send relevant update to the viewer(s).
|
||||||
*
|
*
|
||||||
* @param slot the slot to set the item
|
* @param slot the slot to set the item
|
||||||
* @param itemStack the item to set
|
* @param itemStack the item to set
|
||||||
*/
|
*/
|
||||||
public synchronized void setItemStack(int slot, @NotNull ItemStack itemStack) {
|
public void setItemStack(int slot, @NotNull ItemStack itemStack) {
|
||||||
Check.argCondition(!MathUtils.isBetween(slot, 0, getSize()),
|
setItemStack(slot, itemStack, true);
|
||||||
"Inventory does not have the slot " + slot);
|
|
||||||
safeItemInsert(slot, itemStack);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts safely an item into the inventory.
|
* Sets an {@link ItemStack} at the specified slot and send relevant update to the viewer(s).
|
||||||
* <p>
|
|
||||||
* This will update the slot for all viewers and warn the inventory that
|
|
||||||
* the window items packet is not up-to-date.
|
|
||||||
*
|
*
|
||||||
* @param slot the internal slot id
|
* @param slot the slot to set the item
|
||||||
* @param itemStack the item to insert (use air instead of null)
|
* @param itemStack the item to set
|
||||||
* @throws IllegalArgumentException if the slot {@code slot} does not exist
|
* @param sendPacket whether or not to send packets
|
||||||
*/
|
*/
|
||||||
protected final void safeItemInsert(int slot, @NotNull ItemStack itemStack, boolean sendPacket) {
|
public void setItemStack(int slot, @NotNull ItemStack itemStack, boolean sendPacket) {
|
||||||
|
Check.argCondition(!MathUtils.isBetween(slot, 0, getSize()),
|
||||||
|
"Inventory does not have the slot " + slot);
|
||||||
|
|
||||||
ItemStack previous;
|
ItemStack previous;
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
Check.argCondition(
|
|
||||||
!MathUtils.isBetween(slot, 0, getSize()),
|
|
||||||
"The slot {0} does not exist in this inventory",
|
|
||||||
slot
|
|
||||||
);
|
|
||||||
previous = itemStacks[slot];
|
previous = itemStacks[slot];
|
||||||
if (itemStack.equals(previous)) return; // Avoid sending updates if the item has not changed
|
if (itemStack.equals(previous)) return; // Avoid sending updates if the item has not changed
|
||||||
UNSAFE_itemInsert(slot, itemStack, sendPacket);
|
UNSAFE_itemInsert(slot, itemStack, previous, sendPacket);
|
||||||
}
|
|
||||||
if (this instanceof PlayerInventory inv) {
|
|
||||||
EventDispatcher.call(new PlayerInventoryItemChangeEvent(inv.player, slot, previous, itemStack));
|
|
||||||
} else if (this instanceof Inventory inv) {
|
|
||||||
EventDispatcher.call(new InventoryItemChangeEvent(inv, slot, previous, itemStack));
|
|
||||||
}
|
}
|
||||||
|
EventDispatcher.call(new InventoryItemChangeEvent(this, slot, previous, itemStack));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final void safeItemInsert(int slot, @NotNull ItemStack itemStack) {
|
protected void UNSAFE_itemInsert(int slot, @NotNull ItemStack item, @NotNull ItemStack previous, boolean sendPacket) {
|
||||||
safeItemInsert(slot, itemStack, true);
|
itemStacks[slot] = item;
|
||||||
|
if (sendPacket) sendSlotRefresh(slot, item, previous);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void UNSAFE_itemInsert(int slot, @NotNull ItemStack itemStack, boolean sendPacket);
|
public void sendSlotRefresh(int slot, @NotNull ItemStack item, @NotNull ItemStack previous) {
|
||||||
|
sendPacketToViewers(new SetSlotPacket(getWindowId(), 0, (short) slot, item));
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized <T> @NotNull T processItemStack(@NotNull ItemStack itemStack,
|
public synchronized <T> @NotNull T processItemStack(@NotNull ItemStack itemStack,
|
||||||
@NotNull TransactionType type,
|
@NotNull TransactionType type,
|
||||||
@ -167,13 +209,27 @@ public sealed abstract class AbstractInventory implements InventoryClickHandler,
|
|||||||
public synchronized void clear() {
|
public synchronized void clear() {
|
||||||
// Clear the item array
|
// Clear the item array
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
safeItemInsert(i, ItemStack.AIR, false);
|
setItemStack(i, ItemStack.AIR, false);
|
||||||
}
|
}
|
||||||
// Send the cleared inventory to viewers
|
// Send the cleared inventory to viewers
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void update();
|
/**
|
||||||
|
* Refreshes the inventory for all viewers.
|
||||||
|
*/
|
||||||
|
public void update() {
|
||||||
|
this.viewers.forEach(this::update);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refreshes the inventory for a specific viewer.
|
||||||
|
*
|
||||||
|
* @param player the player to update the inventory for
|
||||||
|
*/
|
||||||
|
public void update(@NotNull Player player) {
|
||||||
|
player.sendPacket(new WindowItemsPacket(getWindowId(), 0, List.of(itemStacks), player.getInventory().getCursorItem()));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the {@link ItemStack} at the specified slot.
|
* Gets the {@link ItemStack} at the specified slot.
|
||||||
|
@ -1,22 +1,16 @@
|
|||||||
package net.minestom.server.inventory;
|
package net.minestom.server.inventory;
|
||||||
|
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.minestom.server.Viewable;
|
|
||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.inventory.click.ClickType;
|
import net.minestom.server.inventory.click.ClickType;
|
||||||
import net.minestom.server.inventory.click.InventoryClickResult;
|
import net.minestom.server.inventory.click.InventoryClickResult;
|
||||||
import net.minestom.server.item.ItemStack;
|
import net.minestom.server.item.ItemStack;
|
||||||
import net.minestom.server.network.packet.server.play.OpenWindowPacket;
|
import net.minestom.server.network.packet.server.play.OpenWindowPacket;
|
||||||
import net.minestom.server.network.packet.server.play.SetSlotPacket;
|
import net.minestom.server.network.packet.server.play.SetSlotPacket;
|
||||||
import net.minestom.server.network.packet.server.play.WindowItemsPacket;
|
|
||||||
import net.minestom.server.network.packet.server.play.WindowPropertyPacket;
|
import net.minestom.server.network.packet.server.play.WindowPropertyPacket;
|
||||||
import net.minestom.server.utils.inventory.PlayerInventoryUtils;
|
import net.minestom.server.utils.inventory.PlayerInventoryUtils;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,22 +19,15 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
* You can create one with {@link Inventory#Inventory(InventoryType, String)} or by making your own subclass.
|
* You can create one with {@link Inventory#Inventory(InventoryType, String)} or by making your own subclass.
|
||||||
* It can then be opened using {@link Player#openInventory(Inventory)}.
|
* It can then be opened using {@link Player#openInventory(Inventory)}.
|
||||||
*/
|
*/
|
||||||
public non-sealed class Inventory extends AbstractInventory implements Viewable {
|
public non-sealed class Inventory extends AbstractInventory {
|
||||||
private static final AtomicInteger ID_COUNTER = new AtomicInteger();
|
private static final AtomicInteger ID_COUNTER = new AtomicInteger();
|
||||||
|
|
||||||
// the id of this inventory
|
|
||||||
private final byte id;
|
private final byte id;
|
||||||
// the type of this inventory
|
|
||||||
private final InventoryType inventoryType;
|
private final InventoryType inventoryType;
|
||||||
// the title of this inventory
|
|
||||||
private Component title;
|
private Component title;
|
||||||
|
|
||||||
private final int offset;
|
private final int offset;
|
||||||
|
|
||||||
// the players currently viewing this inventory
|
|
||||||
private final Set<Player> viewers = new CopyOnWriteArraySet<>();
|
|
||||||
private final Set<Player> unmodifiableViewers = Collections.unmodifiableSet(viewers);
|
|
||||||
|
|
||||||
public Inventory(@NotNull InventoryType inventoryType, @NotNull Component title) {
|
public Inventory(@NotNull InventoryType inventoryType, @NotNull Component title) {
|
||||||
super(inventoryType.getSize());
|
super(inventoryType.getSize());
|
||||||
this.id = generateId();
|
this.id = generateId();
|
||||||
@ -89,42 +76,11 @@ public non-sealed class Inventory extends AbstractInventory implements Viewable
|
|||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Gets this window id.
|
|
||||||
* <p>
|
|
||||||
* This is the id that the client will send to identify the affected inventory, mostly used by packets.
|
|
||||||
*
|
|
||||||
* @return the window id
|
|
||||||
*/
|
|
||||||
public byte getWindowId() {
|
public byte getWindowId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Refreshes the inventory for all viewers.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void update() {
|
|
||||||
this.viewers.forEach(p -> p.sendPacket(createNewWindowItemsPacket(p)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Refreshes the inventory for a specific viewer.
|
|
||||||
* <p>
|
|
||||||
* The player needs to be a viewer, otherwise nothing is sent.
|
|
||||||
*
|
|
||||||
* @param player the player to update the inventory
|
|
||||||
*/
|
|
||||||
public void update(@NotNull Player player) {
|
|
||||||
if (!isViewer(player)) return;
|
|
||||||
player.sendPacket(createNewWindowItemsPacket(player));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NotNull Set<Player> getViewers() {
|
|
||||||
return unmodifiableViewers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This will not open the inventory for {@code player}, use {@link Player#openInventory(Inventory)}.
|
* This will not open the inventory for {@code player}, use {@link Player#openInventory(Inventory)}.
|
||||||
*
|
*
|
||||||
@ -133,9 +89,12 @@ public non-sealed class Inventory extends AbstractInventory implements Viewable
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean addViewer(@NotNull Player player) {
|
public boolean addViewer(@NotNull Player player) {
|
||||||
final boolean result = this.viewers.add(player);
|
if (!this.viewers.add(player)) return false;
|
||||||
|
|
||||||
|
// Also send the open window packet
|
||||||
|
player.sendPacket(new OpenWindowPacket(id, inventoryType.getWindowType(), title));
|
||||||
update(player);
|
update(player);
|
||||||
return result;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -146,9 +105,10 @@ public non-sealed class Inventory extends AbstractInventory implements Viewable
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean removeViewer(@NotNull Player player) {
|
public boolean removeViewer(@NotNull Player player) {
|
||||||
final boolean result = this.viewers.remove(player);
|
if (!super.removeViewer(player)) return false;
|
||||||
|
|
||||||
this.clickProcessor.clearCache(player);
|
this.clickProcessor.clearCache(player);
|
||||||
return result;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -173,16 +133,6 @@ public non-sealed class Inventory extends AbstractInventory implements Viewable
|
|||||||
player.getInventory().setCursorItem(cursorItem);
|
player.getInventory().setCursorItem(cursorItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void UNSAFE_itemInsert(int slot, @NotNull ItemStack itemStack, boolean sendPacket) {
|
|
||||||
itemStacks[slot] = itemStack;
|
|
||||||
if (sendPacket) sendPacketToViewers(new SetSlotPacket(getWindowId(), 0, (short) slot, itemStack));
|
|
||||||
}
|
|
||||||
|
|
||||||
private @NotNull WindowItemsPacket createNewWindowItemsPacket(Player player) {
|
|
||||||
return new WindowItemsPacket(getWindowId(), 0, List.of(getItemStacks()), player.getInventory().getCursorItem());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a window property to all viewers.
|
* Sends a window property to all viewers.
|
||||||
*
|
*
|
||||||
@ -200,9 +150,9 @@ public non-sealed class Inventory extends AbstractInventory implements Viewable
|
|||||||
final ItemStack cursor = playerInventory.getCursorItem();
|
final ItemStack cursor = playerInventory.getCursorItem();
|
||||||
final boolean isInWindow = isClickInWindow(slot);
|
final boolean isInWindow = isClickInWindow(slot);
|
||||||
final int clickSlot = isInWindow ? slot : PlayerInventoryUtils.convertSlot(slot, offset);
|
final int clickSlot = isInWindow ? slot : PlayerInventoryUtils.convertSlot(slot, offset);
|
||||||
|
final AbstractInventory clickedInventory = isInWindow ? this : playerInventory;
|
||||||
final ItemStack clicked = isInWindow ? getItemStack(slot) : playerInventory.getItemStack(clickSlot);
|
final ItemStack clicked = isInWindow ? getItemStack(slot) : playerInventory.getItemStack(clickSlot);
|
||||||
final InventoryClickResult clickResult = clickProcessor.leftClick(player,
|
final InventoryClickResult clickResult = clickProcessor.leftClick(player, clickedInventory, clickSlot, clicked, cursor);
|
||||||
isInWindow ? this : playerInventory, clickSlot, clicked, cursor);
|
|
||||||
if (clickResult.isCancel()) {
|
if (clickResult.isCancel()) {
|
||||||
updateAll(player);
|
updateAll(player);
|
||||||
return false;
|
return false;
|
||||||
@ -213,7 +163,7 @@ public non-sealed class Inventory extends AbstractInventory implements Viewable
|
|||||||
playerInventory.setItemStack(clickSlot, clickResult.getClicked());
|
playerInventory.setItemStack(clickSlot, clickResult.getClicked());
|
||||||
}
|
}
|
||||||
playerInventory.setCursorItem(clickResult.getCursor());
|
playerInventory.setCursorItem(clickResult.getCursor());
|
||||||
callClickEvent(player, isInWindow ? this : null, slot, ClickType.LEFT_CLICK, clicked, cursor);
|
callClickEvent(player, clickedInventory, slot, ClickType.LEFT_CLICK, clicked, cursor);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,8 +174,8 @@ public non-sealed class Inventory extends AbstractInventory implements Viewable
|
|||||||
final boolean isInWindow = isClickInWindow(slot);
|
final boolean isInWindow = isClickInWindow(slot);
|
||||||
final int clickSlot = isInWindow ? slot : PlayerInventoryUtils.convertSlot(slot, offset);
|
final int clickSlot = isInWindow ? slot : PlayerInventoryUtils.convertSlot(slot, offset);
|
||||||
final ItemStack clicked = isInWindow ? getItemStack(slot) : playerInventory.getItemStack(clickSlot);
|
final ItemStack clicked = isInWindow ? getItemStack(slot) : playerInventory.getItemStack(clickSlot);
|
||||||
final InventoryClickResult clickResult = clickProcessor.rightClick(player,
|
final AbstractInventory clickedInventory = isInWindow ? this : playerInventory;
|
||||||
isInWindow ? this : playerInventory, clickSlot, clicked, cursor);
|
final InventoryClickResult clickResult = clickProcessor.rightClick(player, clickedInventory, clickSlot, clicked, cursor);
|
||||||
if (clickResult.isCancel()) {
|
if (clickResult.isCancel()) {
|
||||||
updateAll(player);
|
updateAll(player);
|
||||||
return false;
|
return false;
|
||||||
@ -236,7 +186,7 @@ public non-sealed class Inventory extends AbstractInventory implements Viewable
|
|||||||
playerInventory.setItemStack(clickSlot, clickResult.getClicked());
|
playerInventory.setItemStack(clickSlot, clickResult.getClicked());
|
||||||
}
|
}
|
||||||
playerInventory.setCursorItem(clickResult.getCursor());
|
playerInventory.setCursorItem(clickResult.getCursor());
|
||||||
callClickEvent(player, isInWindow ? this : null, slot, ClickType.RIGHT_CLICK, clicked, cursor);
|
callClickEvent(player, clickedInventory, slot, ClickType.RIGHT_CLICK, clicked, cursor);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,8 +224,8 @@ public non-sealed class Inventory extends AbstractInventory implements Viewable
|
|||||||
final int clickSlot = isInWindow ? slot : PlayerInventoryUtils.convertSlot(slot, offset);
|
final int clickSlot = isInWindow ? slot : PlayerInventoryUtils.convertSlot(slot, offset);
|
||||||
final ItemStack clicked = isInWindow ? getItemStack(slot) : playerInventory.getItemStack(clickSlot);
|
final ItemStack clicked = isInWindow ? getItemStack(slot) : playerInventory.getItemStack(clickSlot);
|
||||||
final ItemStack heldItem = playerInventory.getItemStack(convertedKey);
|
final ItemStack heldItem = playerInventory.getItemStack(convertedKey);
|
||||||
final InventoryClickResult clickResult = clickProcessor.changeHeld(player,
|
final AbstractInventory clickedInventory = isInWindow ? this : playerInventory;
|
||||||
isInWindow ? this : playerInventory, clickSlot, convertedKey, clicked, heldItem);
|
final InventoryClickResult clickResult = clickProcessor.changeHeld(player, clickedInventory, clickSlot, convertedKey, clicked, heldItem);
|
||||||
if (clickResult.isCancel()) {
|
if (clickResult.isCancel()) {
|
||||||
updateAll(player);
|
updateAll(player);
|
||||||
return false;
|
return false;
|
||||||
@ -286,7 +236,7 @@ public non-sealed class Inventory extends AbstractInventory implements Viewable
|
|||||||
playerInventory.setItemStack(clickSlot, clickResult.getClicked());
|
playerInventory.setItemStack(clickSlot, clickResult.getClicked());
|
||||||
}
|
}
|
||||||
playerInventory.setItemStack(convertedKey, clickResult.getCursor());
|
playerInventory.setItemStack(convertedKey, clickResult.getCursor());
|
||||||
callClickEvent(player, isInWindow ? this : null, slot, ClickType.CHANGE_HELD, clicked, playerInventory.getCursorItem());
|
callClickEvent(player, clickedInventory, slot, ClickType.CHANGE_HELD, clicked, playerInventory.getCursorItem());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ public sealed interface InventoryClickHandler permits AbstractInventory {
|
|||||||
*/
|
*/
|
||||||
boolean doubleClick(@NotNull Player player, int slot);
|
boolean doubleClick(@NotNull Player player, int slot);
|
||||||
|
|
||||||
default void callClickEvent(@NotNull Player player, Inventory inventory, int slot,
|
default void callClickEvent(@NotNull Player player, @NotNull AbstractInventory inventory, int slot,
|
||||||
@NotNull ClickType clickType, @NotNull ItemStack clicked, @NotNull ItemStack cursor) {
|
@NotNull ClickType clickType, @NotNull ItemStack clicked, @NotNull ItemStack cursor) {
|
||||||
EventDispatcher.call(new InventoryClickEvent(inventory, player, slot, clickType, clicked, cursor));
|
EventDispatcher.call(new InventoryClickEvent(inventory, player, slot, clickType, clicked, cursor));
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package net.minestom.server.inventory;
|
package net.minestom.server.inventory;
|
||||||
|
|
||||||
import net.minestom.server.entity.EquipmentSlot;
|
import net.minestom.server.entity.EquipmentSlot;
|
||||||
import net.minestom.server.entity.GameMode;
|
|
||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.event.EventDispatcher;
|
import net.minestom.server.event.EventDispatcher;
|
||||||
import net.minestom.server.event.item.EntityEquipEvent;
|
import net.minestom.server.event.item.EntityEquipEvent;
|
||||||
@ -12,6 +11,7 @@ import net.minestom.server.network.packet.server.play.SetSlotPacket;
|
|||||||
import net.minestom.server.network.packet.server.play.WindowItemsPacket;
|
import net.minestom.server.network.packet.server.play.WindowItemsPacket;
|
||||||
import net.minestom.server.utils.validate.Check;
|
import net.minestom.server.utils.validate.Check;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -20,24 +20,23 @@ import static net.minestom.server.utils.inventory.PlayerInventoryUtils.*;
|
|||||||
/**
|
/**
|
||||||
* Represents the inventory of a {@link Player}, retrieved with {@link Player#getInventory()}.
|
* Represents the inventory of a {@link Player}, retrieved with {@link Player#getInventory()}.
|
||||||
*/
|
*/
|
||||||
public non-sealed class PlayerInventory extends AbstractInventory implements EquipmentHandler {
|
public non-sealed class PlayerInventory extends AbstractInventory {
|
||||||
public static final int INVENTORY_SIZE = 46;
|
public static final int INVENTORY_SIZE = 46;
|
||||||
public static final int INNER_INVENTORY_SIZE = 36;
|
public static final int INNER_INVENTORY_SIZE = 36;
|
||||||
|
|
||||||
protected final Player player;
|
|
||||||
private ItemStack cursorItem = ItemStack.AIR;
|
private ItemStack cursorItem = ItemStack.AIR;
|
||||||
|
|
||||||
public PlayerInventory(@NotNull Player player) {
|
public PlayerInventory() {
|
||||||
super(INVENTORY_SIZE);
|
super(INVENTORY_SIZE);
|
||||||
this.player = player;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void clear() {
|
public synchronized void clear() {
|
||||||
cursorItem = ItemStack.AIR;
|
cursorItem = ItemStack.AIR;
|
||||||
super.clear();
|
super.clear();
|
||||||
|
|
||||||
// Update equipments
|
// Update equipments
|
||||||
this.player.sendPacketToViewersAndSelf(player.getEquipmentsPacket());
|
viewers.forEach(viewer -> viewer.sendPacketToViewersAndSelf(viewer.getEquipmentsPacket()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -45,35 +44,45 @@ public non-sealed class PlayerInventory extends AbstractInventory implements Equ
|
|||||||
return INNER_INVENTORY_SIZE;
|
return INNER_INVENTORY_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getSlotId(@NotNull EquipmentSlot slot) {
|
@Override
|
||||||
|
public byte getWindowId() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getSlotId(@NotNull EquipmentSlot slot, byte heldSlot) {
|
||||||
return switch (slot) {
|
return switch (slot) {
|
||||||
case MAIN_HAND -> player.getHeldSlot();
|
case MAIN_HAND -> heldSlot;
|
||||||
case OFF_HAND -> OFFHAND_SLOT;
|
case OFF_HAND -> OFFHAND_SLOT;
|
||||||
default -> slot.armorSlot();
|
default -> slot.armorSlot();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private @Nullable EquipmentSlot getEquipmentSlot(int slot, byte heldSlot) {
|
||||||
public @NotNull ItemStack getEquipment(@NotNull EquipmentSlot slot) {
|
return switch (slot) {
|
||||||
if (slot == EquipmentSlot.BODY) return ItemStack.AIR;
|
case OFFHAND_SLOT -> EquipmentSlot.OFF_HAND;
|
||||||
return getItemStack(getSlotId(slot));
|
case HELMET_SLOT -> EquipmentSlot.HELMET;
|
||||||
|
case CHESTPLATE_SLOT -> EquipmentSlot.CHESTPLATE;
|
||||||
|
case LEGGINGS_SLOT -> EquipmentSlot.LEGGINGS;
|
||||||
|
case BOOTS_SLOT -> EquipmentSlot.BOOTS;
|
||||||
|
default -> slot == heldSlot ? EquipmentSlot.MAIN_HAND : null;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public @NotNull ItemStack getEquipment(@NotNull EquipmentSlot slot, byte heldSlot) {
|
||||||
public void setEquipment(@NotNull EquipmentSlot slot, @NotNull ItemStack itemStack) {
|
if (slot == EquipmentSlot.BODY) return ItemStack.AIR;
|
||||||
|
return getItemStack(getSlotId(slot, heldSlot));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEquipment(@NotNull EquipmentSlot slot, byte heldSlot, @NotNull ItemStack itemStack) {
|
||||||
if (slot == EquipmentSlot.BODY)
|
if (slot == EquipmentSlot.BODY)
|
||||||
Check.fail("PlayerInventory does not support body equipment");
|
Check.fail("PlayerInventory does not support body equipment");
|
||||||
|
|
||||||
safeItemInsert(getSlotId(slot), itemStack);
|
setItemStack(getSlotId(slot, heldSlot), itemStack);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Refreshes the player inventory by sending a {@link WindowItemsPacket} containing all.
|
|
||||||
* the inventory items
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void update() {
|
public void update(@NotNull Player player) {
|
||||||
this.player.sendPacket(createWindowItemsPacket());
|
player.sendPacket(createWindowItemsPacket());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -93,49 +102,42 @@ public non-sealed class PlayerInventory extends AbstractInventory implements Equ
|
|||||||
public void setCursorItem(@NotNull ItemStack cursorItem) {
|
public void setCursorItem(@NotNull ItemStack cursorItem) {
|
||||||
if (this.cursorItem.equals(cursorItem)) return;
|
if (this.cursorItem.equals(cursorItem)) return;
|
||||||
this.cursorItem = cursorItem;
|
this.cursorItem = cursorItem;
|
||||||
final SetSlotPacket setSlotPacket = SetSlotPacket.createCursorPacket(cursorItem);
|
sendPacketToViewers(SetSlotPacket.createCursorPacket(cursorItem));
|
||||||
this.player.sendPacket(setSlotPacket);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void UNSAFE_itemInsert(int slot, @NotNull ItemStack itemStack, boolean sendPacket) {
|
protected void UNSAFE_itemInsert(int slot, @NotNull ItemStack item, @NotNull ItemStack previous, boolean sendPacket) {
|
||||||
final EquipmentSlot equipmentSlot = switch (slot) {
|
for (Player player : getViewers()) {
|
||||||
case HELMET_SLOT -> EquipmentSlot.HELMET;
|
final EquipmentSlot equipmentSlot = getEquipmentSlot(slot, player.getHeldSlot());
|
||||||
case CHESTPLATE_SLOT -> EquipmentSlot.CHESTPLATE;
|
if (equipmentSlot == null) continue;
|
||||||
case LEGGINGS_SLOT -> EquipmentSlot.LEGGINGS;
|
|
||||||
case BOOTS_SLOT -> EquipmentSlot.BOOTS;
|
|
||||||
case OFFHAND_SLOT -> EquipmentSlot.OFF_HAND;
|
|
||||||
default -> slot == player.getHeldSlot() ? EquipmentSlot.MAIN_HAND : null;
|
|
||||||
};
|
|
||||||
if (equipmentSlot != null) {
|
|
||||||
EntityEquipEvent entityEquipEvent = new EntityEquipEvent(player, itemStack, equipmentSlot);
|
|
||||||
EventDispatcher.call(entityEquipEvent);
|
|
||||||
itemStack = entityEquipEvent.getEquippedItem();
|
|
||||||
this.player.updateEquipmentAttributes(this.itemStacks[slot], itemStack, equipmentSlot);
|
|
||||||
}
|
|
||||||
this.itemStacks[slot] = itemStack;
|
|
||||||
|
|
||||||
if (sendPacket) {
|
EntityEquipEvent entityEquipEvent = new EntityEquipEvent(player, item, equipmentSlot);
|
||||||
// Sync equipment
|
EventDispatcher.call(entityEquipEvent);
|
||||||
if (equipmentSlot != null) this.player.syncEquipment(equipmentSlot);
|
item = entityEquipEvent.getEquippedItem();
|
||||||
// Refresh slot
|
|
||||||
sendSlotRefresh((short) convertToPacketSlot(slot), itemStack);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
super.UNSAFE_itemInsert(slot, item, previous, sendPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Refreshes an inventory slot.
|
public void sendSlotRefresh(int slot, @NotNull ItemStack item, @NotNull ItemStack previous) {
|
||||||
*
|
SetSlotPacket defaultPacket = new SetSlotPacket(getWindowId(), 0, (byte) slot, item);
|
||||||
* @param slot the packet slot,
|
|
||||||
* see {@link net.minestom.server.utils.inventory.PlayerInventoryUtils#convertToPacketSlot(int)}
|
for (Player player : getViewers()) {
|
||||||
* @param itemStack the item stack in the slot
|
// Equipment handling
|
||||||
*/
|
final EquipmentSlot equipmentSlot = getEquipmentSlot(slot, player.getHeldSlot());
|
||||||
protected void sendSlotRefresh(short slot, ItemStack itemStack) {
|
if (equipmentSlot != null) {
|
||||||
var openInventory = player.getOpenInventory();
|
player.updateEquipmentAttributes(previous, item, equipmentSlot);
|
||||||
if (openInventory != null && slot >= OFFSET && slot < OFFSET + INNER_INVENTORY_SIZE) {
|
player.syncEquipment(equipmentSlot);
|
||||||
this.player.sendPacket(new SetSlotPacket(openInventory.getWindowId(), 0, (short) (slot + openInventory.getSize() - OFFSET), itemStack));
|
}
|
||||||
} else if (openInventory == null || slot == OFFHAND_SLOT) {
|
|
||||||
this.player.sendPacket(new SetSlotPacket((byte) 0, 0, slot, itemStack));
|
// Slot handling
|
||||||
|
AbstractInventory openInventory = player.getOpenInventory();
|
||||||
|
if (openInventory != null && slot >= OFFSET && slot < OFFSET + INNER_INVENTORY_SIZE) {
|
||||||
|
player.sendPacket(new SetSlotPacket(openInventory.getWindowId(), 0, (short) (slot + openInventory.getSize() - OFFSET), item));
|
||||||
|
} else if (openInventory == null || slot == OFFHAND_SLOT) {
|
||||||
|
player.sendPacket(defaultPacket);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ public interface TransactionOption<T> {
|
|||||||
* The remaining, can be air.
|
* The remaining, can be air.
|
||||||
*/
|
*/
|
||||||
TransactionOption<ItemStack> ALL = (inventory, result, itemChangesMap) -> {
|
TransactionOption<ItemStack> ALL = (inventory, result, itemChangesMap) -> {
|
||||||
itemChangesMap.forEach(inventory::safeItemInsert);
|
itemChangesMap.forEach(inventory::setItemStack);
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ public interface TransactionOption<T> {
|
|||||||
TransactionOption<Boolean> ALL_OR_NOTHING = (inventory, result, itemChangesMap) -> {
|
TransactionOption<Boolean> ALL_OR_NOTHING = (inventory, result, itemChangesMap) -> {
|
||||||
if (result.isAir()) {
|
if (result.isAir()) {
|
||||||
// Item can be fully placed inside the inventory, do so
|
// Item can be fully placed inside the inventory, do so
|
||||||
itemChangesMap.forEach(inventory::safeItemInsert);
|
itemChangesMap.forEach(inventory::setItemStack);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
// Inventory cannot accept the item fully
|
// Inventory cannot accept the item fully
|
||||||
|
@ -454,10 +454,9 @@ public final class InventoryClickProcessor {
|
|||||||
return clickResult;
|
return clickResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void callClickEvent(@NotNull Player player, @Nullable AbstractInventory inventory, int slot,
|
private void callClickEvent(@NotNull Player player, @NotNull AbstractInventory inventory, int slot,
|
||||||
@NotNull ClickType clickType, @NotNull ItemStack clicked, @NotNull ItemStack cursor) {
|
@NotNull ClickType clickType, @NotNull ItemStack clicked, @NotNull ItemStack cursor) {
|
||||||
final Inventory eventInventory = inventory instanceof Inventory ? (Inventory) inventory : null;
|
EventDispatcher.call(new InventoryClickEvent(inventory, player, slot, clickType, clicked, cursor));
|
||||||
EventDispatcher.call(new InventoryClickEvent(eventInventory, player, slot, clickType, clicked, cursor));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearCache(@NotNull Player player) {
|
public void clearCache(@NotNull Player player) {
|
||||||
|
@ -37,7 +37,6 @@ public class BlockPlacementListener {
|
|||||||
private static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager();
|
private static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager();
|
||||||
|
|
||||||
public static void listener(ClientPlayerBlockPlacementPacket packet, Player player) {
|
public static void listener(ClientPlayerBlockPlacementPacket packet, Player player) {
|
||||||
final PlayerInventory playerInventory = player.getInventory();
|
|
||||||
final PlayerHand hand = packet.hand();
|
final PlayerHand hand = packet.hand();
|
||||||
final BlockFace blockFace = packet.blockFace();
|
final BlockFace blockFace = packet.blockFace();
|
||||||
Point blockPosition = packet.blockPosition();
|
Point blockPosition = packet.blockPosition();
|
||||||
@ -179,10 +178,10 @@ public class BlockPlacementListener {
|
|||||||
if (playerBlockPlaceEvent.doesConsumeBlock()) {
|
if (playerBlockPlaceEvent.doesConsumeBlock()) {
|
||||||
// Consume the block in the player's hand
|
// Consume the block in the player's hand
|
||||||
final ItemStack newUsedItem = usedItem.consume(1);
|
final ItemStack newUsedItem = usedItem.consume(1);
|
||||||
playerInventory.setItemInHand(hand, newUsedItem);
|
player.setItemInHand(hand, newUsedItem);
|
||||||
} else {
|
} else {
|
||||||
// Prevent invisible item on client
|
// Prevent invisible item on client
|
||||||
playerInventory.update();
|
player.getInventory().update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@ import net.minestom.server.event.player.PlayerSwapItemEvent;
|
|||||||
import net.minestom.server.instance.Instance;
|
import net.minestom.server.instance.Instance;
|
||||||
import net.minestom.server.instance.block.Block;
|
import net.minestom.server.instance.block.Block;
|
||||||
import net.minestom.server.instance.block.BlockFace;
|
import net.minestom.server.instance.block.BlockFace;
|
||||||
import net.minestom.server.inventory.PlayerInventory;
|
|
||||||
import net.minestom.server.item.ItemComponent;
|
import net.minestom.server.item.ItemComponent;
|
||||||
import net.minestom.server.item.ItemStack;
|
import net.minestom.server.item.ItemStack;
|
||||||
import net.minestom.server.item.component.BlockPredicates;
|
import net.minestom.server.item.component.BlockPredicates;
|
||||||
@ -128,12 +127,12 @@ public final class PlayerDiggingListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void dropStack(Player player) {
|
private static void dropStack(Player player) {
|
||||||
final ItemStack droppedItemStack = player.getInventory().getItemInMainHand();
|
final ItemStack droppedItemStack = player.getItemInMainHand();
|
||||||
dropItem(player, droppedItemStack, ItemStack.AIR);
|
dropItem(player, droppedItemStack, ItemStack.AIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void dropSingle(Player player) {
|
private static void dropSingle(Player player) {
|
||||||
final ItemStack handItem = player.getInventory().getItemInMainHand();
|
final ItemStack handItem = player.getItemInMainHand();
|
||||||
final int handAmount = handItem.amount();
|
final int handAmount = handItem.amount();
|
||||||
if (handAmount <= 1) {
|
if (handAmount <= 1) {
|
||||||
// Drop the whole item without copy
|
// Drop the whole item without copy
|
||||||
@ -162,13 +161,12 @@ public final class PlayerDiggingListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void swapItemHand(Player player) {
|
private static void swapItemHand(Player player) {
|
||||||
final PlayerInventory inventory = player.getInventory();
|
final ItemStack mainHand = player.getItemInMainHand();
|
||||||
final ItemStack mainHand = inventory.getItemInMainHand();
|
final ItemStack offHand = player.getItemInOffHand();
|
||||||
final ItemStack offHand = inventory.getItemInOffHand();
|
|
||||||
PlayerSwapItemEvent swapItemEvent = new PlayerSwapItemEvent(player, offHand, mainHand);
|
PlayerSwapItemEvent swapItemEvent = new PlayerSwapItemEvent(player, offHand, mainHand);
|
||||||
EventDispatcher.callCancellable(swapItemEvent, () -> {
|
EventDispatcher.callCancellable(swapItemEvent, () -> {
|
||||||
inventory.setItemInMainHand(swapItemEvent.getMainHandItem());
|
player.setItemInMainHand(swapItemEvent.getMainHandItem());
|
||||||
inventory.setItemInOffHand(swapItemEvent.getOffHandItem());
|
player.setItemInOffHand(swapItemEvent.getOffHandItem());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,11 +190,10 @@ public final class PlayerDiggingListener {
|
|||||||
|
|
||||||
private static void dropItem(@NotNull Player player,
|
private static void dropItem(@NotNull Player player,
|
||||||
@NotNull ItemStack droppedItem, @NotNull ItemStack handItem) {
|
@NotNull ItemStack droppedItem, @NotNull ItemStack handItem) {
|
||||||
final PlayerInventory playerInventory = player.getInventory();
|
|
||||||
if (player.dropItem(droppedItem)) {
|
if (player.dropItem(droppedItem)) {
|
||||||
playerInventory.setItemInMainHand(handItem);
|
player.setItemInMainHand(handItem);
|
||||||
} else {
|
} else {
|
||||||
playerInventory.update();
|
player.getInventory().update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ public class UseItemListener {
|
|||||||
|
|
||||||
public static void useItemListener(ClientUseItemPacket packet, Player player) {
|
public static void useItemListener(ClientUseItemPacket packet, Player player) {
|
||||||
final PlayerHand hand = packet.hand();
|
final PlayerHand hand = packet.hand();
|
||||||
final ItemStack itemStack = player.getInventory().getItemInHand(hand);
|
final ItemStack itemStack = player.getItemInHand(hand);
|
||||||
final Material material = itemStack.material();
|
final Material material = itemStack.material();
|
||||||
|
|
||||||
boolean usingMainHand = player.getItemUseHand() == Player.Hand.MAIN && hand == Player.Hand.OFF;
|
boolean usingMainHand = player.getItemUseHand() == Player.Hand.MAIN && hand == Player.Hand.OFF;
|
||||||
|
@ -27,7 +27,7 @@ public class PlayerCreativeSlotTest {
|
|||||||
player.setGameMode(GameMode.CREATIVE);
|
player.setGameMode(GameMode.CREATIVE);
|
||||||
player.addPacketToQueue(new ClientCreativeInventoryActionPacket((short) PlayerInventoryUtils.OFFHAND_SLOT, ItemStack.of(Material.STICK)));
|
player.addPacketToQueue(new ClientCreativeInventoryActionPacket((short) PlayerInventoryUtils.OFFHAND_SLOT, ItemStack.of(Material.STICK)));
|
||||||
player.interpretPacketQueue();
|
player.interpretPacketQueue();
|
||||||
assertEquals(Material.STICK, player.getInventory().getItemInOffHand().material());
|
assertEquals(Material.STICK, player.getItemInOffHand().material());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -118,19 +118,19 @@ public class PlayerInventoryIntegrationTest {
|
|||||||
var equipmentTracker = connectionViewer.trackIncoming(EntityEquipmentPacket.class);
|
var equipmentTracker = connectionViewer.trackIncoming(EntityEquipmentPacket.class);
|
||||||
|
|
||||||
// Setting to an item should send EntityEquipmentPacket to viewer
|
// Setting to an item should send EntityEquipmentPacket to viewer
|
||||||
playerArmored.getInventory().setEquipment(EquipmentSlot.HELMET, MAGIC_STACK);
|
playerArmored.setEquipment(EquipmentSlot.HELMET, MAGIC_STACK);
|
||||||
equipmentTracker.assertSingle(entityEquipmentPacket -> {
|
equipmentTracker.assertSingle(entityEquipmentPacket -> {
|
||||||
assertEquals(MAGIC_STACK, entityEquipmentPacket.equipments().get(EquipmentSlot.HELMET));
|
assertEquals(MAGIC_STACK, entityEquipmentPacket.equipments().get(EquipmentSlot.HELMET));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Setting to the same item shouldn't send packet
|
// Setting to the same item shouldn't send packet
|
||||||
equipmentTracker = connectionViewer.trackIncoming(EntityEquipmentPacket.class);
|
equipmentTracker = connectionViewer.trackIncoming(EntityEquipmentPacket.class);
|
||||||
playerArmored.getInventory().setEquipment(EquipmentSlot.HELMET, MAGIC_STACK);
|
playerArmored.setEquipment(EquipmentSlot.HELMET, MAGIC_STACK);
|
||||||
equipmentTracker.assertEmpty();
|
equipmentTracker.assertEmpty();
|
||||||
|
|
||||||
// Setting to air should send packet
|
// Setting to air should send packet
|
||||||
equipmentTracker = connectionViewer.trackIncoming(EntityEquipmentPacket.class);
|
equipmentTracker = connectionViewer.trackIncoming(EntityEquipmentPacket.class);
|
||||||
playerArmored.getInventory().setEquipment(EquipmentSlot.HELMET, ItemStack.AIR);
|
playerArmored.setEquipment(EquipmentSlot.HELMET, ItemStack.AIR);
|
||||||
equipmentTracker.assertSingle(entityEquipmentPacket -> {
|
equipmentTracker.assertSingle(entityEquipmentPacket -> {
|
||||||
assertEquals(ItemStack.AIR, entityEquipmentPacket.equipments().get(EquipmentSlot.HELMET));
|
assertEquals(ItemStack.AIR, entityEquipmentPacket.equipments().get(EquipmentSlot.HELMET));
|
||||||
});
|
});
|
||||||
|
@ -3,6 +3,7 @@ package net.minestom.server.inventory.click.integration;
|
|||||||
import net.minestom.server.coordinate.Pos;
|
import net.minestom.server.coordinate.Pos;
|
||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.event.inventory.InventoryPreClickEvent;
|
import net.minestom.server.event.inventory.InventoryPreClickEvent;
|
||||||
|
import net.minestom.server.inventory.AbstractInventory;
|
||||||
import net.minestom.server.inventory.Inventory;
|
import net.minestom.server.inventory.Inventory;
|
||||||
import net.minestom.server.inventory.InventoryType;
|
import net.minestom.server.inventory.InventoryType;
|
||||||
import net.minestom.server.inventory.click.ClickType;
|
import net.minestom.server.inventory.click.ClickType;
|
||||||
@ -82,7 +83,7 @@ public class HeldClickIntegrationTest {
|
|||||||
});
|
});
|
||||||
heldClick(player, 3, 40);
|
heldClick(player, 3, 40);
|
||||||
assertEquals(ItemStack.AIR, inventory.getItemStack(3));
|
assertEquals(ItemStack.AIR, inventory.getItemStack(3));
|
||||||
assertEquals(ItemStack.of(Material.EGG), inventory.getItemInOffHand());
|
assertEquals(ItemStack.of(Material.EGG), player.getItemInOffHand());
|
||||||
}
|
}
|
||||||
// Cancel event
|
// Cancel event
|
||||||
{
|
{
|
||||||
@ -151,7 +152,7 @@ public class HeldClickIntegrationTest {
|
|||||||
});
|
});
|
||||||
heldClickOpenInventory(player, 3, 40);
|
heldClickOpenInventory(player, 3, 40);
|
||||||
assertEquals(ItemStack.AIR, inventory.getItemStack(3));
|
assertEquals(ItemStack.AIR, inventory.getItemStack(3));
|
||||||
assertEquals(ItemStack.of(Material.EGG), playerInv.getItemInOffHand());
|
assertEquals(ItemStack.of(Material.EGG), player.getItemInOffHand());
|
||||||
}
|
}
|
||||||
// Cancel event
|
// Cancel event
|
||||||
{
|
{
|
||||||
@ -171,7 +172,7 @@ public class HeldClickIntegrationTest {
|
|||||||
_heldClick(player.getOpenInventory(), false, player, slot, target);
|
_heldClick(player.getOpenInventory(), false, player, slot, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void _heldClick(Inventory openInventory, boolean clickOpenInventory, Player player, int slot, int target) {
|
private void _heldClick(AbstractInventory openInventory, boolean clickOpenInventory, Player player, int slot, int target) {
|
||||||
final byte windowId = openInventory != null ? openInventory.getWindowId() : 0;
|
final byte windowId = openInventory != null ? openInventory.getWindowId() : 0;
|
||||||
if (clickOpenInventory) {
|
if (clickOpenInventory) {
|
||||||
assert openInventory != null;
|
assert openInventory != null;
|
||||||
|
@ -4,6 +4,7 @@ package net.minestom.server.inventory.click.integration;
|
|||||||
import net.minestom.server.coordinate.Pos;
|
import net.minestom.server.coordinate.Pos;
|
||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.event.inventory.InventoryPreClickEvent;
|
import net.minestom.server.event.inventory.InventoryPreClickEvent;
|
||||||
|
import net.minestom.server.inventory.AbstractInventory;
|
||||||
import net.minestom.server.inventory.Inventory;
|
import net.minestom.server.inventory.Inventory;
|
||||||
import net.minestom.server.inventory.InventoryType;
|
import net.minestom.server.inventory.InventoryType;
|
||||||
import net.minestom.server.inventory.click.ClickType;
|
import net.minestom.server.inventory.click.ClickType;
|
||||||
@ -154,7 +155,7 @@ public class LeftClickIntegrationTest {
|
|||||||
_leftClick(player.getOpenInventory(), false, player, slot);
|
_leftClick(player.getOpenInventory(), false, player, slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void _leftClick(Inventory openInventory, boolean clickOpenInventory, Player player, int slot) {
|
private void _leftClick(AbstractInventory openInventory, boolean clickOpenInventory, Player player, int slot) {
|
||||||
final byte windowId = openInventory != null ? openInventory.getWindowId() : 0;
|
final byte windowId = openInventory != null ? openInventory.getWindowId() : 0;
|
||||||
if (clickOpenInventory) {
|
if (clickOpenInventory) {
|
||||||
assert openInventory != null;
|
assert openInventory != null;
|
||||||
|
@ -3,6 +3,7 @@ package net.minestom.server.inventory.click.integration;
|
|||||||
import net.minestom.server.coordinate.Pos;
|
import net.minestom.server.coordinate.Pos;
|
||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.event.inventory.InventoryPreClickEvent;
|
import net.minestom.server.event.inventory.InventoryPreClickEvent;
|
||||||
|
import net.minestom.server.inventory.AbstractInventory;
|
||||||
import net.minestom.server.inventory.Inventory;
|
import net.minestom.server.inventory.Inventory;
|
||||||
import net.minestom.server.inventory.InventoryType;
|
import net.minestom.server.inventory.InventoryType;
|
||||||
import net.minestom.server.inventory.click.ClickType;
|
import net.minestom.server.inventory.click.ClickType;
|
||||||
@ -175,7 +176,7 @@ public class RightClickIntegrationTest {
|
|||||||
_rightClick(player.getOpenInventory(), false, player, slot);
|
_rightClick(player.getOpenInventory(), false, player, slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void _rightClick(Inventory openInventory, boolean clickOpenInventory, Player player, int slot) {
|
private void _rightClick(AbstractInventory openInventory, boolean clickOpenInventory, Player player, int slot) {
|
||||||
final byte windowId = openInventory != null ? openInventory.getWindowId() : 0;
|
final byte windowId = openInventory != null ? openInventory.getWindowId() : 0;
|
||||||
if (clickOpenInventory) {
|
if (clickOpenInventory) {
|
||||||
assert openInventory != null;
|
assert openInventory != null;
|
||||||
|
Loading…
Reference in New Issue
Block a user