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.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.item.ItemStack;
import net.minestom.server.item.StackingRule;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.UnaryOperator;
/**
* 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).
@ -35,7 +58,7 @@ public abstract class AbstractInventory {
* @param itemStack the item to add
* @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<>();
final StackingRule stackingRule = itemStack.getStackingRule();
@ -235,7 +258,7 @@ public abstract class AbstractInventory {
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);
setItemStack(slot, operator.apply(currentItem));
}
@ -243,7 +266,14 @@ public abstract class AbstractInventory {
/**
* 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.
@ -252,7 +282,9 @@ public abstract class AbstractInventory {
* @return the item in the slot {@code slot}
*/
@NotNull
public abstract ItemStack getItemStack(int slot);
public ItemStack getItemStack(int slot) {
return itemStacks[slot];
}
/**
* 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
*/
@NotNull
public abstract ItemStack[] getItemStacks();
public ItemStack[] getItemStacks() {
return itemStacks.clone();
}
/**
* Gets the size of the inventory.
*
* @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).
@ -287,14 +323,18 @@ public abstract class AbstractInventory {
* @return a modifiable {@link List} containing all the inventory conditions
*/
@NotNull
public abstract List<InventoryCondition> getInventoryConditions();
public List<InventoryCondition> getInventoryConditions() {
return inventoryConditions;
}
/**
* Adds a new {@link InventoryCondition} to this inventory.
*
* @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.
@ -313,4 +353,15 @@ public abstract class AbstractInventory {
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;
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.inventory.click.ClickType;
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.condition.InventoryCondition;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.server.play.OpenWindowPacket;
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.validate.Check;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.UnaryOperator;
/**
* 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.
* 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)
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)
private String title;
// the size based on the inventory type
private final int size;
private final int offset;
// the items in this inventory
private final ItemStack[] itemStacks;
// the players currently viewing this inventory
private final Set<Player> viewers = new CopyOnWriteArraySet<>();
private final Set<Player> unmodifiableViewers = Collections.unmodifiableSet(viewers);
// (player -> cursor item) map, used by the click listeners
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) {
super(inventoryType.getSize());
this.id = generateId();
this.inventoryType = inventoryType;
this.title = title;
this.size = inventoryType.getSize();
this.offset = size;
this.itemStacks = new ItemStack[size];
Arrays.fill(itemStacks, ItemStack.AIR);
this.offset = getSize();
}
private static byte generateId() {
@ -147,58 +122,10 @@ public class Inventory extends AbstractInventory implements InventoryClickHandle
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.
*/
@Override
public void update() {
sendPacketToViewers(createNewWindowItemsPacket());
}
@ -604,15 +531,4 @@ public class Inventory extends AbstractInventory implements InventoryClickHandle
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;
import net.minestom.server.data.Data;
import net.minestom.server.data.DataContainer;
import net.minestom.server.entity.Player;
import net.minestom.server.event.item.ArmorEquipEvent;
import net.minestom.server.event.player.PlayerAddItemStackEvent;
import net.minestom.server.event.player.PlayerSetItemStackEvent;
import net.minestom.server.inventory.click.ClickType;
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.condition.InventoryCondition;
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.validate.Check;
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.*;
/**
* 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 INNER_INVENTORY_SIZE = 36;
protected final Player player;
protected final ItemStack[] itemStacks = new ItemStack[INVENTORY_SIZE];
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) {
super(INVENTORY_SIZE);
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
public void addInventoryCondition(@NotNull InventoryCondition inventoryCondition) {
// fix packet slot to inventory slot conversion
InventoryCondition condition = (p, slot, clickType, inventoryConditionResult) -> {
final int convertedSlot = convertPlayerInventorySlot(slot, OFFSET);
inventoryCondition.accept(p, convertedSlot, clickType, inventoryConditionResult);
};
this.inventoryConditions.add(condition);
super.addInventoryCondition(condition);
}
@Override
@ -97,29 +68,13 @@ public class PlayerInventory extends AbstractInventory implements InventoryClick
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 the inventory's owner
update();
super.clear();
// Update equipments
this.player.sendPacketToViewersAndSelf(player.getEquipmentsPacket());
}
@Override
public int getSize() {
return INVENTORY_SIZE;
}
@Override
public int getInnerSize() {
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.
* the inventory items
*/
@Override
public void update() {
player.getPlayerConnection().sendPacket(createWindowItemsPacket());
}
@ -499,15 +455,4 @@ public class PlayerInventory extends AbstractInventory implements InventoryClick
return !clickResult.isCancel();
}
@Nullable
@Override
public Data getData() {
return data;
}
@Override
public void setData(@Nullable Data data) {
this.data = data;
}
}