Share more data between PlayerInventory & Inventory

Signed-off-by: TheMode <themode@outlook.fr>
This commit is contained in:
TheMode 2021-04-04 03:36:31 +02:00
parent 1c9528908c
commit 51d290cae9
3 changed files with 70 additions and 158 deletions

View File

@ -2,20 +2,43 @@ package net.minestom.server.inventory;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minestom.server.data.Data;
import net.minestom.server.data.DataContainer;
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.item.StackingRule; import net.minestom.server.item.StackingRule;
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.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
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 abstract class AbstractInventory { public abstract class AbstractInventory implements DataContainer {
private final int size;
protected final ItemStack[] itemStacks;
// list of conditions/callbacks assigned to this inventory
protected final List<InventoryCondition> inventoryConditions = new CopyOnWriteArrayList<>();
// the click processor which process all the clicks in the inventory
protected final InventoryClickProcessor clickProcessor = new InventoryClickProcessor();
private Data data;
protected AbstractInventory(int size) {
this.size = size;
this.itemStacks = new ItemStack[getSize()];
Arrays.fill(itemStacks, ItemStack.AIR);
}
/** /**
* 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).
@ -35,7 +58,7 @@ public abstract class AbstractInventory {
* @param itemStack the item to add * @param itemStack the item to add
* @return true if the item has been successfully fully added, false otherwise * @return true if the item has been successfully fully added, false otherwise
*/ */
public boolean addItemStack(@NotNull ItemStack itemStack) { public synchronized boolean addItemStack(@NotNull ItemStack itemStack) {
Int2ObjectMap<ItemStack> itemChangesMap = new Int2ObjectOpenHashMap<>(); Int2ObjectMap<ItemStack> itemChangesMap = new Int2ObjectOpenHashMap<>();
final StackingRule stackingRule = itemStack.getStackingRule(); final StackingRule stackingRule = itemStack.getStackingRule();
@ -235,7 +258,7 @@ public abstract class AbstractInventory {
return itemStacks.stream().allMatch(this::canTakeItemStack); return itemStacks.stream().allMatch(this::canTakeItemStack);
} }
public void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) { public synchronized void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) {
var currentItem = getItemStack(slot); var currentItem = getItemStack(slot);
setItemStack(slot, operator.apply(currentItem)); setItemStack(slot, operator.apply(currentItem));
} }
@ -243,7 +266,14 @@ public abstract class AbstractInventory {
/** /**
* Clears the inventory and send relevant update to the viewer(s). * Clears the inventory and send relevant update to the viewer(s).
*/ */
public abstract void clear(); public synchronized void clear() {
// Clear the item array
Arrays.fill(itemStacks, ItemStack.AIR);
// Send the cleared inventory to viewers
update();
}
public abstract void update();
/** /**
* Gets the {@link ItemStack} at the specified slot. * Gets the {@link ItemStack} at the specified slot.
@ -252,7 +282,9 @@ public abstract class AbstractInventory {
* @return the item in the slot {@code slot} * @return the item in the slot {@code slot}
*/ */
@NotNull @NotNull
public abstract ItemStack getItemStack(int slot); public ItemStack getItemStack(int slot) {
return itemStacks[slot];
}
/** /**
* Gets all the {@link ItemStack} in the inventory. * Gets all the {@link ItemStack} in the inventory.
@ -263,14 +295,18 @@ public abstract class AbstractInventory {
* @return an array containing all the inventory's items * @return an array containing all the inventory's items
*/ */
@NotNull @NotNull
public abstract ItemStack[] getItemStacks(); public ItemStack[] getItemStacks() {
return itemStacks.clone();
}
/** /**
* Gets the size of the inventory. * Gets the size of the inventory.
* *
* @return the inventory's size * @return the inventory's size
*/ */
public abstract int getSize(); public int getSize() {
return size;
}
/** /**
* Gets the size of the "inner inventory" (which includes only "usable" slots). * Gets the size of the "inner inventory" (which includes only "usable" slots).
@ -287,14 +323,18 @@ public abstract class AbstractInventory {
* @return a modifiable {@link List} containing all the inventory conditions * @return a modifiable {@link List} containing all the inventory conditions
*/ */
@NotNull @NotNull
public abstract List<InventoryCondition> getInventoryConditions(); public List<InventoryCondition> getInventoryConditions() {
return inventoryConditions;
}
/** /**
* Adds a new {@link InventoryCondition} to this inventory. * Adds a new {@link InventoryCondition} to this inventory.
* *
* @param inventoryCondition the inventory condition to add * @param inventoryCondition the inventory condition to add
*/ */
public abstract void addInventoryCondition(@NotNull InventoryCondition inventoryCondition); public void addInventoryCondition(@NotNull InventoryCondition inventoryCondition) {
this.inventoryConditions.add(inventoryCondition);
}
/** /**
* Places all the items of {@code itemStacks} into the internal array. * Places all the items of {@code itemStacks} into the internal array.
@ -313,4 +353,15 @@ public abstract class AbstractInventory {
setItemStack(i, itemStack); setItemStack(i, itemStack);
} }
} }
@Nullable
@Override
public Data getData() {
return data;
}
@Override
public void setData(@Nullable Data data) {
this.data = data;
}
} }

View File

@ -1,14 +1,10 @@
package net.minestom.server.inventory; package net.minestom.server.inventory;
import net.minestom.server.Viewable; import net.minestom.server.Viewable;
import net.minestom.server.data.Data;
import net.minestom.server.data.DataContainer;
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.InventoryClickLoopHandler; import net.minestom.server.inventory.click.InventoryClickLoopHandler;
import net.minestom.server.inventory.click.InventoryClickProcessor;
import net.minestom.server.inventory.click.InventoryClickResult; import net.minestom.server.inventory.click.InventoryClickResult;
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.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;
@ -19,17 +15,12 @@ import net.minestom.server.utils.MathUtils;
import net.minestom.server.utils.inventory.PlayerInventoryUtils; import net.minestom.server.utils.inventory.PlayerInventoryUtils;
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.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.UnaryOperator;
/** /**
* Represents an inventory which can be viewed by a collection of {@link Player}. * Represents an inventory which can be viewed by a collection of {@link Player}.
@ -37,7 +28,7 @@ import java.util.function.UnaryOperator;
* 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 class Inventory extends AbstractInventory implements InventoryClickHandler, Viewable, DataContainer { public class Inventory extends AbstractInventory implements InventoryClickHandler, Viewable {
// incremented each time an inventory is created (used in the window packets) // incremented each time an inventory is created (used in the window packets)
private static final AtomicInteger LAST_INVENTORY_ID = new AtomicInteger(); private static final AtomicInteger LAST_INVENTORY_ID = new AtomicInteger();
@ -49,37 +40,21 @@ public class Inventory extends AbstractInventory implements InventoryClickHandle
// the title of this inventory) // the title of this inventory)
private String title; private String title;
// the size based on the inventory type
private final int size;
private final int offset; private final int offset;
// the items in this inventory
private final ItemStack[] itemStacks;
// the players currently viewing this inventory // the players currently viewing this inventory
private final Set<Player> viewers = new CopyOnWriteArraySet<>(); private final Set<Player> viewers = new CopyOnWriteArraySet<>();
private final Set<Player> unmodifiableViewers = Collections.unmodifiableSet(viewers); private final Set<Player> unmodifiableViewers = Collections.unmodifiableSet(viewers);
// (player -> cursor item) map, used by the click listeners // (player -> cursor item) map, used by the click listeners
private final ConcurrentHashMap<Player, ItemStack> cursorPlayersItem = new ConcurrentHashMap<>(); private final ConcurrentHashMap<Player, ItemStack> cursorPlayersItem = new ConcurrentHashMap<>();
// list of conditions/callbacks assigned to this inventory
private final List<InventoryCondition> inventoryConditions = new CopyOnWriteArrayList<>();
// the click processor which process all the clicks in the inventory
private final InventoryClickProcessor clickProcessor = new InventoryClickProcessor();
private Data data;
public Inventory(@NotNull InventoryType inventoryType, @NotNull String title) { public Inventory(@NotNull InventoryType inventoryType, @NotNull String title) {
super(inventoryType.getSize());
this.id = generateId(); this.id = generateId();
this.inventoryType = inventoryType; this.inventoryType = inventoryType;
this.title = title; this.title = title;
this.size = inventoryType.getSize(); this.offset = getSize();
this.offset = size;
this.itemStacks = new ItemStack[size];
Arrays.fill(itemStacks, ItemStack.AIR);
} }
private static byte generateId() { private static byte generateId() {
@ -147,58 +122,10 @@ public class Inventory extends AbstractInventory implements InventoryClickHandle
safeItemInsert(slot, itemStack); safeItemInsert(slot, itemStack);
} }
@Override
public synchronized boolean addItemStack(@NotNull ItemStack itemStack) {
// Make the method synchronized
return super.addItemStack(itemStack);
}
@Override
public synchronized void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) {
// Make the method synchronized
super.replaceItemStack(slot, operator);
}
@Override
public synchronized void clear() {
// Clear the item array
Arrays.fill(itemStacks, ItemStack.AIR);
// Send the cleared inventory to viewers
update();
}
@NotNull
@Override
public ItemStack getItemStack(int slot) {
return itemStacks[slot];
}
@NotNull
@Override
public ItemStack[] getItemStacks() {
return itemStacks.clone();
}
@Override
public int getSize() {
return size;
}
@NotNull
@Override
public List<InventoryCondition> getInventoryConditions() {
return inventoryConditions;
}
@Override
public void addInventoryCondition(@NotNull InventoryCondition inventoryCondition) {
this.inventoryConditions.add(inventoryCondition);
}
/** /**
* Refreshes the inventory for all viewers. * Refreshes the inventory for all viewers.
*/ */
@Override
public void update() { public void update() {
sendPacketToViewers(createNewWindowItemsPacket()); sendPacketToViewers(createNewWindowItemsPacket());
} }
@ -604,15 +531,4 @@ public class Inventory extends AbstractInventory implements InventoryClickHandle
update(player); update(player);
} }
} }
@Nullable
@Override
public Data getData() {
return data;
}
@Override
public void setData(@Nullable Data data) {
this.data = data;
}
} }

View File

@ -1,14 +1,11 @@
package net.minestom.server.inventory; package net.minestom.server.inventory;
import net.minestom.server.data.Data;
import net.minestom.server.data.DataContainer;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.event.item.ArmorEquipEvent; import net.minestom.server.event.item.ArmorEquipEvent;
import net.minestom.server.event.player.PlayerAddItemStackEvent; import net.minestom.server.event.player.PlayerAddItemStackEvent;
import net.minestom.server.event.player.PlayerSetItemStackEvent; import net.minestom.server.event.player.PlayerSetItemStackEvent;
import net.minestom.server.inventory.click.ClickType; import net.minestom.server.inventory.click.ClickType;
import net.minestom.server.inventory.click.InventoryClickLoopHandler; import net.minestom.server.inventory.click.InventoryClickLoopHandler;
import net.minestom.server.inventory.click.InventoryClickProcessor;
import net.minestom.server.inventory.click.InventoryClickResult; import net.minestom.server.inventory.click.InventoryClickResult;
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;
@ -18,60 +15,34 @@ import net.minestom.server.network.packet.server.play.WindowItemsPacket;
import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.MathUtils;
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.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.UnaryOperator;
import static net.minestom.server.utils.inventory.PlayerInventoryUtils.*; 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 class PlayerInventory extends AbstractInventory implements InventoryClickHandler, EquipmentHandler, DataContainer { public class PlayerInventory extends AbstractInventory implements InventoryClickHandler, EquipmentHandler {
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; protected final Player player;
protected final ItemStack[] itemStacks = new ItemStack[INVENTORY_SIZE];
private ItemStack cursorItem = ItemStack.AIR; private ItemStack cursorItem = ItemStack.AIR;
private final List<InventoryCondition> inventoryConditions = new CopyOnWriteArrayList<>();
private final InventoryClickProcessor clickProcessor = new InventoryClickProcessor();
private Data data;
public PlayerInventory(@NotNull Player player) { public PlayerInventory(@NotNull Player player) {
super(INVENTORY_SIZE);
this.player = player; this.player = player;
Arrays.fill(itemStacks, ItemStack.AIR);
}
@Override
public @NotNull ItemStack getItemStack(int slot) {
return this.itemStacks[slot];
}
@Override
public @NotNull ItemStack[] getItemStacks() {
return itemStacks.clone();
}
@Override
public @NotNull List<InventoryCondition> getInventoryConditions() {
return inventoryConditions;
} }
@Override @Override
public void addInventoryCondition(@NotNull InventoryCondition inventoryCondition) { public void addInventoryCondition(@NotNull InventoryCondition inventoryCondition) {
// fix packet slot to inventory slot conversion
InventoryCondition condition = (p, slot, clickType, inventoryConditionResult) -> { InventoryCondition condition = (p, slot, clickType, inventoryConditionResult) -> {
final int convertedSlot = convertPlayerInventorySlot(slot, OFFSET); final int convertedSlot = convertPlayerInventorySlot(slot, OFFSET);
inventoryCondition.accept(p, convertedSlot, clickType, inventoryConditionResult); inventoryCondition.accept(p, convertedSlot, clickType, inventoryConditionResult);
}; };
this.inventoryConditions.add(condition); super.addInventoryCondition(condition);
} }
@Override @Override
@ -97,29 +68,13 @@ public class PlayerInventory extends AbstractInventory implements InventoryClick
return super.addItemStack(itemStack); return super.addItemStack(itemStack);
} }
@Override
public synchronized void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) {
// Make the method synchronized
super.replaceItemStack(slot, operator);
}
@Override @Override
public synchronized void clear() { public synchronized void clear() {
// Clear the item array super.clear();
Arrays.fill(itemStacks, ItemStack.AIR);
// Send the cleared inventory to the inventory's owner
update();
// Update equipments // Update equipments
this.player.sendPacketToViewersAndSelf(player.getEquipmentsPacket()); this.player.sendPacketToViewersAndSelf(player.getEquipmentsPacket());
} }
@Override
public int getSize() {
return INVENTORY_SIZE;
}
@Override @Override
public int getInnerSize() { public int getInnerSize() {
return INNER_INVENTORY_SIZE; return INNER_INVENTORY_SIZE;
@ -195,6 +150,7 @@ public class PlayerInventory extends AbstractInventory implements InventoryClick
* Refreshes the player inventory by sending a {@link WindowItemsPacket} containing all. * Refreshes the player inventory by sending a {@link WindowItemsPacket} containing all.
* the inventory items * the inventory items
*/ */
@Override
public void update() { public void update() {
player.getPlayerConnection().sendPacket(createWindowItemsPacket()); player.getPlayerConnection().sendPacket(createWindowItemsPacket());
} }
@ -499,15 +455,4 @@ public class PlayerInventory extends AbstractInventory implements InventoryClick
return !clickResult.isCancel(); return !clickResult.isCancel();
} }
@Nullable
@Override
public Data getData() {
return data;
}
@Override
public void setData(@Nullable Data data) {
this.data = data;
}
} }