mirror of
https://github.com/Minestom/Minestom.git
synced 2024-11-05 18:32:28 +01:00
Force volatile read for inventory contents
This commit is contained in:
parent
3ffe37591b
commit
f0cf2d946c
@ -1,5 +1,8 @@
|
||||
package net.minestom.server.inventory;
|
||||
|
||||
import net.minestom.server.event.GlobalHandles;
|
||||
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.condition.InventoryCondition;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
@ -9,9 +12,10 @@ import net.minestom.server.utils.MathUtils;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@ -24,6 +28,8 @@ import java.util.function.UnaryOperator;
|
||||
public sealed abstract class AbstractInventory implements InventoryClickHandler, TagHandler
|
||||
permits Inventory, PlayerInventory {
|
||||
|
||||
private static final VarHandle ITEM_UPDATER = MethodHandles.arrayElementVarHandle(ItemStack[].class);
|
||||
|
||||
private final int size;
|
||||
protected final ItemStack[] itemStacks;
|
||||
|
||||
@ -38,7 +44,6 @@ public sealed abstract class AbstractInventory implements InventoryClickHandler,
|
||||
protected AbstractInventory(int size) {
|
||||
this.size = size;
|
||||
this.itemStacks = new ItemStack[getSize()];
|
||||
|
||||
Arrays.fill(itemStacks, ItemStack.AIR);
|
||||
}
|
||||
|
||||
@ -62,7 +67,6 @@ public sealed abstract class AbstractInventory implements InventoryClickHandler,
|
||||
*
|
||||
* @param slot the internal slot id
|
||||
* @param itemStack the item to insert (use air instead of null)
|
||||
*
|
||||
* @throws IllegalArgumentException if the slot {@code slot} does not exist
|
||||
*/
|
||||
protected final void safeItemInsert(int slot, @NotNull ItemStack itemStack) {
|
||||
@ -76,13 +80,15 @@ public sealed abstract class AbstractInventory implements InventoryClickHandler,
|
||||
previous = itemStacks[slot];
|
||||
UNSAFE_itemInsert(slot, itemStack);
|
||||
}
|
||||
callItemChangeEvent(slot, previous, itemStack);
|
||||
if (this instanceof PlayerInventory inv) {
|
||||
GlobalHandles.PLAYER_INVENTORY_ITEM_CHANGE_EVENT.call(new PlayerInventoryItemChangeEvent(inv.player, slot, previous, itemStack));
|
||||
} else if (this instanceof Inventory inv) {
|
||||
GlobalHandles.INVENTORY_ITEM_CHANGE_EVENT.call(new InventoryItemChangeEvent(inv, slot, previous, itemStack));
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void UNSAFE_itemInsert(int slot, @NotNull ItemStack itemStack);
|
||||
|
||||
protected abstract void callItemChangeEvent(int slot, @NotNull ItemStack previous, @NotNull ItemStack current);
|
||||
|
||||
public synchronized <T> @NotNull T processItemStack(@NotNull ItemStack itemStack,
|
||||
@NotNull TransactionType type,
|
||||
@NotNull TransactionOption<T> option) {
|
||||
@ -172,7 +178,7 @@ public sealed abstract class AbstractInventory implements InventoryClickHandler,
|
||||
* @return the item in the slot {@code slot}
|
||||
*/
|
||||
public @NotNull ItemStack getItemStack(int slot) {
|
||||
return itemStacks[slot];
|
||||
return (ItemStack) ITEM_UPDATER.getVolatile(itemStacks, slot);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3,8 +3,6 @@ package net.minestom.server.inventory;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.Viewable;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.event.GlobalHandles;
|
||||
import net.minestom.server.event.inventory.InventoryItemChangeEvent;
|
||||
import net.minestom.server.inventory.click.ClickType;
|
||||
import net.minestom.server.inventory.click.InventoryClickResult;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
@ -72,8 +70,7 @@ public non-sealed class Inventory extends AbstractInventory implements Viewable
|
||||
*
|
||||
* @return the inventory type
|
||||
*/
|
||||
@NotNull
|
||||
public InventoryType getInventoryType() {
|
||||
public @NotNull InventoryType getInventoryType() {
|
||||
return inventoryType;
|
||||
}
|
||||
|
||||
@ -82,8 +79,7 @@ public non-sealed class Inventory extends AbstractInventory implements Viewable
|
||||
*
|
||||
* @return the inventory title
|
||||
*/
|
||||
@NotNull
|
||||
public Component getTitle() {
|
||||
public @NotNull Component getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
@ -124,9 +120,7 @@ public non-sealed class Inventory extends AbstractInventory implements Viewable
|
||||
*/
|
||||
@Override
|
||||
public void update() {
|
||||
for (Player player : viewers) {
|
||||
player.sendPacket(createNewWindowItemsPacket(player));
|
||||
}
|
||||
this.viewers.forEach(p -> p.sendPacket(createNewWindowItemsPacket(p)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -141,9 +135,8 @@ public non-sealed class Inventory extends AbstractInventory implements Viewable
|
||||
player.sendPacket(createNewWindowItemsPacket(player));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Player> getViewers() {
|
||||
public @NotNull Set<Player> getViewers() {
|
||||
return unmodifiableViewers;
|
||||
}
|
||||
|
||||
@ -180,8 +173,7 @@ public non-sealed class Inventory extends AbstractInventory implements Viewable
|
||||
* @param player the player to get the cursor item from
|
||||
* @return the player cursor item, air item if the player is not a viewer
|
||||
*/
|
||||
@NotNull
|
||||
public ItemStack getCursorItem(@NotNull Player player) {
|
||||
public @NotNull ItemStack getCursorItem(@NotNull Player player) {
|
||||
return cursorPlayersItem.getOrDefault(player, ItemStack.AIR);
|
||||
}
|
||||
|
||||
@ -210,16 +202,6 @@ public non-sealed class Inventory extends AbstractInventory implements Viewable
|
||||
sendPacketToViewers(new SetSlotPacket(getWindowId(), 0, (short) slot, itemStack));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void callItemChangeEvent(int slot, @NotNull ItemStack previous, @NotNull ItemStack current) {
|
||||
GlobalHandles.INVENTORY_ITEM_CHANGE_EVENT.call(new InventoryItemChangeEvent(this, slot, previous, current));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a complete new {@link WindowItemsPacket}.
|
||||
*
|
||||
* @return a new {@link WindowItemsPacket} packet
|
||||
*/
|
||||
private @NotNull WindowItemsPacket createNewWindowItemsPacket(Player player) {
|
||||
return new WindowItemsPacket(getWindowId(), 0, List.of(getItemStacks()), cursorPlayersItem.getOrDefault(player, ItemStack.AIR));
|
||||
}
|
||||
@ -235,22 +217,6 @@ public non-sealed class Inventory extends AbstractInventory implements Viewable
|
||||
sendPacketToViewers(new WindowPropertyPacket(getWindowId(), property.getProperty(), value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the internal player's cursor item
|
||||
* <p>
|
||||
* WARNING: the player will not be notified by the change
|
||||
*
|
||||
* @param player the player to change the cursor item
|
||||
* @param itemStack the cursor item
|
||||
*/
|
||||
private void refreshPlayerCursorItem(@NotNull Player player, @NotNull ItemStack itemStack) {
|
||||
this.cursorPlayersItem.put(player, itemStack);
|
||||
}
|
||||
|
||||
private boolean isClickInWindow(int slot) {
|
||||
return slot < getSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean leftClick(@NotNull Player player, int slot) {
|
||||
final PlayerInventory playerInventory = player.getInventory();
|
||||
@ -269,7 +235,7 @@ public non-sealed class Inventory extends AbstractInventory implements Viewable
|
||||
} else {
|
||||
playerInventory.setItemStack(clickSlot, clickResult.getClicked());
|
||||
}
|
||||
refreshPlayerCursorItem(player, clickResult.getCursor());
|
||||
this.cursorPlayersItem.put(player, clickResult.getCursor());
|
||||
callClickEvent(player, isInWindow ? this : null, slot, ClickType.LEFT_CLICK, clicked, cursor);
|
||||
return true;
|
||||
}
|
||||
@ -292,7 +258,7 @@ public non-sealed class Inventory extends AbstractInventory implements Viewable
|
||||
} else {
|
||||
playerInventory.setItemStack(clickSlot, clickResult.getClicked());
|
||||
}
|
||||
refreshPlayerCursorItem(player, clickResult.getCursor());
|
||||
this.cursorPlayersItem.put(player, clickResult.getCursor());
|
||||
callClickEvent(player, isInWindow ? this : null, slot, ClickType.RIGHT_CLICK, clicked, cursor);
|
||||
return true;
|
||||
}
|
||||
@ -319,7 +285,7 @@ public non-sealed class Inventory extends AbstractInventory implements Viewable
|
||||
playerInventory.setItemStack(clickSlot, clickResult.getClicked());
|
||||
}
|
||||
updateAll(player); // FIXME: currently not properly client-predicted
|
||||
refreshPlayerCursorItem(player, clickResult.getCursor());
|
||||
this.cursorPlayersItem.put(player, clickResult.getCursor());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -376,7 +342,7 @@ public non-sealed class Inventory extends AbstractInventory implements Viewable
|
||||
playerInventory.setItemStack(clickSlot, resultClicked);
|
||||
}
|
||||
}
|
||||
refreshPlayerCursorItem(player, clickResult.getCursor());
|
||||
this.cursorPlayersItem.put(player, clickResult.getCursor());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -397,7 +363,7 @@ public non-sealed class Inventory extends AbstractInventory implements Viewable
|
||||
updateAll(player);
|
||||
return false;
|
||||
}
|
||||
refreshPlayerCursorItem(player, clickResult.getCursor());
|
||||
this.cursorPlayersItem.put(player, clickResult.getCursor());
|
||||
updateAll(player); // FIXME: currently not properly client-predicted
|
||||
return true;
|
||||
}
|
||||
@ -417,11 +383,15 @@ public non-sealed class Inventory extends AbstractInventory implements Viewable
|
||||
updateAll(player);
|
||||
return false;
|
||||
}
|
||||
refreshPlayerCursorItem(player, clickResult.getCursor());
|
||||
this.cursorPlayersItem.put(player, clickResult.getCursor());
|
||||
updateAll(player); // FIXME: currently not properly client-predicted
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isClickInWindow(int slot) {
|
||||
return slot < getSize();
|
||||
}
|
||||
|
||||
private void updateAll(Player player) {
|
||||
player.getInventory().update();
|
||||
update(player);
|
||||
|
@ -3,8 +3,6 @@ package net.minestom.server.inventory;
|
||||
import net.minestom.server.entity.EquipmentSlot;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.event.EventDispatcher;
|
||||
import net.minestom.server.event.GlobalHandles;
|
||||
import net.minestom.server.event.inventory.PlayerInventoryItemChangeEvent;
|
||||
import net.minestom.server.event.item.EntityEquipEvent;
|
||||
import net.minestom.server.inventory.click.ClickType;
|
||||
import net.minestom.server.inventory.click.InventoryClickResult;
|
||||
@ -169,11 +167,6 @@ public non-sealed class PlayerInventory extends AbstractInventory implements Equ
|
||||
sendSlotRefresh((short) convertToPacketSlot(slot), itemStack);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void callItemChangeEvent(int slot, @NotNull ItemStack previous, @NotNull ItemStack current) {
|
||||
GlobalHandles.PLAYER_INVENTORY_ITEM_CHANGE_EVENT.call(new PlayerInventoryItemChangeEvent(player, slot, previous, current));
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes an inventory slot.
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user