WIP Item rework implementation

This commit is contained in:
themode 2021-04-02 18:13:02 +02:00
parent a70870d261
commit a128d30b6b
56 changed files with 388 additions and 1399 deletions

View File

@ -33,7 +33,7 @@ public class EntityTypeContainer implements Comparable<EntityTypeContainer> {
String metaClassName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name.getPath());
// special cases
switch (metaClassName) {
case "Item":
case "ItemStack":
metaClassName = "ItemEntity";
break;
case "Tnt":

View File

@ -6,7 +6,6 @@ import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.type.decoration.EntityItemFrame;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceManager;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.item.metadata.MapMeta;
import net.minestom.server.map.Framebuffer;

View File

@ -60,7 +60,7 @@ public class Advancement {
public Advancement(@NotNull JsonMessage title, @NotNull JsonMessage description,
@NotNull Material icon, @NotNull FrameType frameType,
float x, float y) {
this(title, description, new ItemStack(icon, (byte) 1), frameType, x, y);
this(title, description, ItemStack.of(icon, 1), frameType, x, y);
}
public Advancement(@NotNull Component title, Component description,
@ -77,7 +77,7 @@ public class Advancement {
public Advancement(@NotNull Component title, @NotNull Component description,
@NotNull Material icon, @NotNull FrameType frameType,
float x, float y) {
this(title, description, new ItemStack(icon, (byte) 1), frameType, x, y);
this(title, description, ItemStack.of(icon, 1), frameType, x, y);
}
/**

View File

@ -1,7 +1,6 @@
package net.minestom.server.advancements;
import net.kyori.adventure.text.Component;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.chat.JsonMessage;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;

View File

@ -33,7 +33,7 @@ public class Notification {
}
public Notification(@NotNull Component title, @NotNull FrameType frameType, @NotNull Material icon) {
this(title, frameType, new ItemStack(icon, (byte) 1));
this(title, frameType, ItemStack.of(icon));
}
public Notification(@NotNull Component title, @NotNull FrameType frameType, @NotNull ItemStack icon) {
@ -46,7 +46,6 @@ public class Notification {
* Gets the title of the notification.
*
* @return the notification title
*
* @deprecated Use {@link #getTitle()}
*/
@NotNull

View File

@ -1,6 +1,5 @@
package net.minestom.server.chat;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import net.kyori.adventure.text.Component;
@ -93,11 +92,8 @@ public class ChatHoverEvent {
JsonObject obj = GsonComponentSerializer.gson().serializer().toJsonTree(Component.empty().hoverEvent(event)).getAsJsonObject();
obj = obj.get("hoverEvent").getAsJsonObject().get("contents").getAsJsonObject();
if (itemStack.getItemMeta() != null) {
NBTCompound compound = new NBTCompound();
itemStack.getItemMeta().write(compound);
obj.add("tag", new JsonPrimitive(compound.toSNBT()));
}
NBTCompound compound = itemStack.getMeta().toNBT();
obj.add("tag", new JsonPrimitive(compound.toSNBT()));
return new ChatHoverEvent("show_item", obj);
}

View File

@ -42,12 +42,12 @@ public class ArgumentItemStack extends Argument<ItemStack> {
if (nbtIndex == -1) {
// Only item name
final Material material = Registries.getMaterial(input);
return new ItemStack(material, (byte) 1);
return ItemStack.of(material);
} else {
final String materialName = input.substring(0, nbtIndex);
final Material material = Registries.getMaterial(materialName);
ItemStack itemStack = new ItemStack(material, (byte) 1);
ItemStack itemStack = ItemStack.of(material);
final String sNBT = input.substring(nbtIndex).replace("\\\"", "\"");

View File

@ -109,7 +109,7 @@ public class ItemEntity extends ObjectEntity {
if (!canApply)
continue;
final ItemStack result = stackingRule.apply(itemStack.clone(), totalAmount);
final ItemStack result = stackingRule.apply(itemStack, totalAmount);
EntityItemMergeEvent entityItemMergeEvent = new EntityItemMergeEvent(this, itemEntity, result);
callCancellableEvent(EntityItemMergeEvent.class, entityItemMergeEvent, () -> {

View File

@ -37,7 +37,7 @@ import java.util.concurrent.ConcurrentHashMap;
//TODO: Default attributes registration (and limitation ?)
public class LivingEntity extends Entity implements EquipmentHandler {
// Item pickup
// ItemStack pickup
protected boolean canPickupItem;
protected UpdateOption itemPickupCooldown = new UpdateOption(5, TimeUnit.TICK);
private long lastItemPickupCheckTime;
@ -112,13 +112,13 @@ public class LivingEntity extends Entity implements EquipmentHandler {
}
private void initEquipments() {
this.mainHandItem = ItemStack.getAirItem();
this.offHandItem = ItemStack.getAirItem();
this.mainHandItem = ItemStack.AIR;
this.offHandItem = ItemStack.AIR;
this.helmet = ItemStack.getAirItem();
this.chestplate = ItemStack.getAirItem();
this.leggings = ItemStack.getAirItem();
this.boots = ItemStack.getAirItem();
this.helmet = ItemStack.AIR;
this.chestplate = ItemStack.AIR;
this.leggings = ItemStack.AIR;
this.boots = ItemStack.AIR;
}
@NotNull
@ -551,7 +551,7 @@ public class LivingEntity extends Entity implements EquipmentHandler {
playerConnection.sendPacket(getEquipmentsPacket());
playerConnection.sendPacket(getPropertiesPacket());
if (getTeam() != null){
if (getTeam() != null) {
playerConnection.sendPacket(getTeam().createTeamsCreationPacket());
}

View File

@ -1,15 +1,14 @@
package net.minestom.server.entity;
import net.kyori.adventure.text.Component;
import net.minestom.server.adventure.AdventureSerializer;
import net.minestom.server.MinecraftServer;
import net.minestom.server.adventure.AdventureSerializer;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.chat.JsonMessage;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.server.play.EntityMetaDataPacket;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.Direction;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.Vector;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
@ -21,8 +20,8 @@ import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTEnd;
import org.jglrxavpok.hephaistos.nbt.NBTException;
import java.util.*;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Function;
@ -61,14 +60,14 @@ public class Metadata {
writer.writeSizedString(value.toString());
}
},
reader -> {
boolean present = reader.readBoolean();
if(present) {
return reader.readJsonMessage(Integer.MAX_VALUE);
} else {
return null;
}
});
reader -> {
boolean present = reader.readBoolean();
if (present) {
return reader.readJsonMessage(Integer.MAX_VALUE);
} else {
return null;
}
});
}
public static Value<Component> Chat(@NotNull Component value) {
@ -84,7 +83,7 @@ public class Metadata {
}
}, reader -> {
boolean present = reader.readBoolean();
if(present) {
if (present) {
return reader.readComponent(Integer.MAX_VALUE);
}
return null;
@ -120,7 +119,7 @@ public class Metadata {
}
}, reader -> {
boolean present = reader.readBoolean();
if(present) {
if (present) {
return reader.readBlockPosition();
} else {
return null;
@ -141,7 +140,7 @@ public class Metadata {
}
}, reader -> {
boolean present = reader.readBoolean();
if(present) {
if (present) {
return reader.readUuid();
} else {
return null;
@ -155,7 +154,7 @@ public class Metadata {
writer.writeVarInt(present ? value : 0);
}, reader -> {
boolean present = reader.readBoolean();
if(present) {
if (present) {
return reader.readVarInt();
} else {
return null;
@ -183,7 +182,7 @@ public class Metadata {
writer.writeVarInt(villagerType);
writer.writeVarInt(villagerProfession);
writer.writeVarInt(level);
}, reader -> new int[] {
}, reader -> new int[]{
reader.readVarInt(),
reader.readVarInt(),
reader.readVarInt()
@ -196,7 +195,7 @@ public class Metadata {
writer.writeVarInt(present ? value + 1 : 0);
}, reader -> {
boolean present = reader.readBoolean();
if(present) {
if (present) {
return reader.readVarInt();
} else {
return null;
@ -331,7 +330,7 @@ public class Metadata {
}
private static <T> Value<T> getCorrespondingNewEmptyValue(int type) {
switch(type) {
switch (type) {
case TYPE_BYTE:
return (Value<T>) Byte((byte) 0);
case TYPE_VARINT:
@ -345,13 +344,13 @@ public class Metadata {
case TYPE_OPTCHAT:
return (Value<T>) OptChat((Component) null);
case TYPE_SLOT:
return (Value<T>) Slot(ItemStack.getAirItem());
return (Value<T>) Slot(ItemStack.AIR);
case TYPE_BOOLEAN:
return (Value<T>) Boolean(false);
case TYPE_ROTATION:
return (Value<T>) Rotation(new Vector());
case TYPE_POSITION:
return (Value<T>) Position(new BlockPosition(0,0,0));
return (Value<T>) Position(new BlockPosition(0, 0, 0));
case TYPE_OPTPOSITION:
return (Value<T>) OptPosition(null);
case TYPE_DIRECTION:
@ -365,7 +364,7 @@ public class Metadata {
case TYPE_PARTICLE:
throw new UnsupportedOperationException();
case TYPE_VILLAGERDATA:
return (Value<T>) VillagerData(0,0,0);
return (Value<T>) VillagerData(0, 0, 0);
case TYPE_OPTVARINT:
return (Value<T>) OptVarInt(null);
case TYPE_POSE:

View File

@ -78,7 +78,6 @@ import org.jetbrains.annotations.Nullable;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.UnaryOperator;
@ -591,11 +590,12 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
}
}
// Item ownership cache
// ItemStack ownership cache
{
ItemStack[] itemStacks = inventory.getItemStacks();
for (ItemStack itemStack : itemStacks) {
ItemStack.DATA_OWNERSHIP.clearCache(itemStack.getIdentifier());
// FIXME: item data
//ItemStack.DATA_OWNERSHIP.clearCache(itemStack.getIdentifier());
}
}
@ -1109,37 +1109,12 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
MinecraftServer.getBossBarManager().removeBossBar(this, bar);
}
/**
* Opens a book ui for the player with the given book metadata.
*
* @param bookMeta The metadata of the book to open
* @deprecated Use {@link #openBook(Book)}
*/
@Deprecated
public void openBook(@NotNull WrittenBookMeta bookMeta) {
// Set book in offhand
final ItemStack writtenBook = new ItemStack(Material.WRITTEN_BOOK, (byte) 1);
writtenBook.setItemMeta(bookMeta);
final SetSlotPacket setSlotPacket = new SetSlotPacket();
setSlotPacket.windowId = 0;
setSlotPacket.slot = 45;
setSlotPacket.itemStack = writtenBook;
this.playerConnection.sendPacket(setSlotPacket);
// Open the book
final OpenBookPacket openBookPacket = new OpenBookPacket();
openBookPacket.hand = Hand.OFF;
this.playerConnection.sendPacket(openBookPacket);
// Update inventory to remove book (which the actual inventory does not have)
this.inventory.update();
}
@Override
public void openBook(@NotNull Book book) {
// make the book
ItemStack writtenBook = new ItemStack(Material.WRITTEN_BOOK, (byte) 1);
writtenBook.setItemMeta(WrittenBookMeta.fromAdventure(book, this));
ItemStack writtenBook = ItemStack.of(Material.WRITTEN_BOOK);
// TODO: WRITTEN_BOOK meta
//writtenBook.setItemMeta(WrittenBookMeta.fromAdventure(book, this));
// Set book in offhand
SetSlotPacket setBookPacket = new SetSlotPacket();
@ -2009,10 +1984,10 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
ItemStack cursorItem;
if (openInventory == null) {
cursorItem = getInventory().getCursorItem();
getInventory().setCursorItem(ItemStack.getAirItem());
getInventory().setCursorItem(ItemStack.AIR);
} else {
cursorItem = openInventory.getCursorItem(this);
openInventory.setCursorItem(this, ItemStack.getAirItem());
openInventory.setCursorItem(this, ItemStack.AIR);
}
if (!cursorItem.isAir()) {
// Add item to inventory if he hasn't been able to drop it

View File

@ -13,7 +13,7 @@ class ItemContainingMeta extends EntityMeta {
protected ItemContainingMeta(@NotNull Entity entity, @NotNull Metadata metadata, @NotNull Material defaultItemMaterial) {
super(entity, metadata);
this.defaultItem = new ItemStack(defaultItemMaterial, (byte) 1);
this.defaultItem = ItemStack.of(defaultItemMaterial, 1);
}
@NotNull

View File

@ -18,7 +18,7 @@ public class FireworkRocketMeta extends EntityMeta implements ProjectileMeta {
@NotNull
public ItemStack getFireworkInfo() {
return super.metadata.getIndex((byte) 7, ItemStack.getAirItem());
return super.metadata.getIndex((byte) 7, ItemStack.AIR);
}
public void setFireworkInfo(@NotNull ItemStack value) {

View File

@ -19,7 +19,7 @@ public class ItemFrameMeta extends EntityMeta implements ObjectDataProvider {
@NotNull
public ItemStack getItem() {
return super.metadata.getIndex((byte) 7, ItemStack.getAirItem());
return super.metadata.getIndex((byte) 7, ItemStack.AIR);
}
public void setItem(@NotNull ItemStack value) {

View File

@ -41,13 +41,13 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler {
setLeftLegRotation(new Vector(-1f, 0, -1f));
setRightLegRotation(new Vector(1, 0, 1));
this.mainHandItem = ItemStack.getAirItem();
this.offHandItem = ItemStack.getAirItem();
this.mainHandItem = ItemStack.AIR;
this.offHandItem = ItemStack.AIR;
this.helmet = ItemStack.getAirItem();
this.chestplate = ItemStack.getAirItem();
this.leggings = ItemStack.getAirItem();
this.boots = ItemStack.getAirItem();
this.helmet = ItemStack.AIR;
this.chestplate = ItemStack.AIR;
this.leggings = ItemStack.AIR;
this.boots = ItemStack.AIR;
}

View File

@ -10,6 +10,7 @@ import org.jetbrains.annotations.NotNull;
// FIXME: https://wiki.vg/Object_Data#Item_Frame_.28id_71.29
// "You have to set both Orientation and Yaw/Pitch accordingly, otherwise it will not work."
/**
* @deprecated Use {@link net.minestom.server.entity.metadata.other.ItemFrameMeta} instead.
*/
@ -37,7 +38,7 @@ public class EntityItemFrame extends ObjectEntity {
*/
@NotNull
public ItemStack getItemStack() {
return metadata.getIndex((byte) 7, ItemStack.getAirItem());
return metadata.getIndex((byte) 7, ItemStack.AIR);
}
/**

View File

@ -26,7 +26,7 @@ public class EntityEyeOfEnder extends Entity {
* @return the item
*/
public ItemStack getItemStack() {
return metadata.getIndex((byte) 7, ItemStack.getAirItem());
return metadata.getIndex((byte) 7, ItemStack.AIR);
}
/**

View File

@ -22,7 +22,7 @@ public class EntityPotion extends Entity {
@NotNull
public ItemStack getPotion() {
return metadata.getIndex((byte) 7, ItemStack.getAirItem());
return metadata.getIndex((byte) 7, ItemStack.AIR);
}
public void setPotion(@NotNull ItemStack potion) {

View File

@ -22,7 +22,7 @@ public class ConditionedFunctionWrapper implements LootTableFunction {
@Override
public ItemStack apply(ItemStack stack, Data data) {
for (Condition c : conditions) {
if(!c.test(data))
if (!c.test(data))
return stack;
}
return baseFunction.apply(stack, data);

View File

@ -31,10 +31,10 @@ public class LootTable {
}
public List<ItemStack> generate(Data arguments) {
if(arguments == null)
if (arguments == null)
arguments = Data.EMPTY;
List<ItemStack> output = new LinkedList<>();
for(Pool p : pools) {
for (Pool p : pools) {
p.generate(output, arguments);
}
return output;
@ -74,18 +74,18 @@ public class LootTable {
}
public void generate(List<ItemStack> output, Data arguments) {
for(Condition c : conditions) {
if(!c.test(arguments))
for (Condition c : conditions) {
if (!c.test(arguments))
return;
}
Random rng = new Random();
int luck = arguments.getOrDefault(LUCK_KEY, 0);
int rollCount = rng.nextInt(maxRollCount - minRollCount +1 /*inclusive*/) + minRollCount;
int bonusRollCount = rng.nextInt(bonusMaxRollCount - bonusMinRollCount +1 /*inclusive*/) + bonusMinRollCount;
int rollCount = rng.nextInt(maxRollCount - minRollCount + 1 /*inclusive*/) + minRollCount;
int bonusRollCount = rng.nextInt(bonusMaxRollCount - bonusMinRollCount + 1 /*inclusive*/) + bonusMinRollCount;
bonusRollCount *= luck;
// TODO: implement luck (quality/weight) weight=floor( weight + (quality * generic.luck))
WeightedRandom<Entry> weightedRandom = new WeightedRandom<>(entries);
for (int i = 0; i < rollCount+bonusRollCount; i++) {
for (int i = 0; i < rollCount + bonusRollCount; i++) {
Entry entry = weightedRandom.get(rng);
entry.generateStacks(output, arguments);
}
@ -122,8 +122,8 @@ public class LootTable {
}
public final void generateStacks(List<ItemStack> output, Data arguments) {
for(Condition c : conditions) {
if(!c.test(arguments))
for (Condition c : conditions) {
if (!c.test(arguments))
return;
}
generate(output, arguments);

View File

@ -17,11 +17,11 @@ public class AlternativesEntry extends LootTable.Entry {
@Override
public void generate(List<ItemStack> output, Data arguments) {
for(LootTable.Entry c : children) {
for (LootTable.Entry c : children) {
int previousSize = output.size();
c.generateStacks(output, arguments);
int newSize = output.size();
if(newSize != previousSize) { // an entry managed to generate, stop here
if (newSize != previousSize) { // an entry managed to generate, stop here
return;
}
}

View File

@ -23,11 +23,11 @@ public class ItemEntry extends LootTable.Entry {
@Override
public void generate(List<ItemStack> output, Data arguments) {
ItemStack stack = new ItemStack(item, (byte)1);
ItemStack stack = ItemStack.of(item);
for (LootTableFunction function : functions) {
stack = function.apply(stack, arguments);
}
if(!stack.isAir()) {
if (!stack.isAir()) {
output.add(stack);
}
}

View File

@ -17,11 +17,11 @@ public class SequenceEntry extends LootTable.Entry {
@Override
public void generate(List<ItemStack> output, Data arguments) {
for(LootTable.Entry c : children) {
for (LootTable.Entry c : children) {
int previousSize = output.size();
c.generateStacks(output, arguments);
int newSize = output.size();
if(newSize == previousSize) { // an entry failed to generate, stop here
if (newSize == previousSize) { // an entry failed to generate, stop here
return;
}
}

View File

@ -27,19 +27,19 @@ public class TagEntry extends LootTable.Entry {
@Override
public void generate(List<ItemStack> output, Data arguments) {
Set<NamespaceID> values = tag.getValues();
if(values.isEmpty())
if (values.isEmpty())
return;
Material[] asArrayOfItems = new Material[values.size()];
int ptr = 0;
for (NamespaceID id : values) {
asArrayOfItems[ptr++] = Registries.getMaterial(id);
}
if(expand) {
Material selectedItem = asArrayOfItems[rng.nextInt(asArrayOfItems.length)];
output.add(new ItemStack(selectedItem, (byte) 1));
if (expand) {
Material selectedMaterial = asArrayOfItems[rng.nextInt(asArrayOfItems.length)];
output.add(ItemStack.of(selectedMaterial));
} else {
for(Material item : asArrayOfItems) {
output.add(new ItemStack(item, (byte) 1));
for (Material material : asArrayOfItems) {
output.add(ItemStack.of(material));
}
}
}

View File

@ -16,13 +16,13 @@ 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.player.PlayerConnection;
import net.minestom.server.utils.ArrayUtils;
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;
@ -79,8 +79,7 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View
this.offset = size;
this.itemStacks = new ItemStack[size];
ArrayUtils.fill(itemStacks, ItemStack::getAirItem);
Arrays.fill(itemStacks, ItemStack.AIR);
}
private static byte generateId() {
@ -162,12 +161,10 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View
final int totalAmount = itemStackAmount + itemAmount;
if (!stackingRule.canApply(itemStack, totalAmount)) {
item = itemStackingRule.apply(item, itemStackingRule.getMaxSize());
sendSlotRefresh((short) i, item);
setItemStack(i, item);
itemStack = stackingRule.apply(itemStack, totalAmount - stackingRule.getMaxSize());
} else {
item.setAmount((byte) totalAmount);
sendSlotRefresh((short) i, item);
setItemStack(i, item.withAmount(totalAmount));
return true;
}
} else if (item.isAir()) {
@ -182,7 +179,7 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View
public void clear() {
// Clear the item array
for (int i = 0; i < getSize(); i++) {
setItemStackInternal(i, ItemStack.getAirItem());
setItemStackInternal(i, ItemStack.AIR);
}
// Send the cleared inventory to viewers
update();
@ -289,7 +286,7 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View
*/
@NotNull
public ItemStack getCursorItem(@NotNull Player player) {
return cursorPlayersItem.getOrDefault(player, ItemStack.getAirItem());
return cursorPlayersItem.getOrDefault(player, ItemStack.AIR);
}
/**
@ -543,7 +540,7 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View
final boolean outsideDrop = slot == -999;
final int clickSlot = isInWindow ? slot : PlayerInventoryUtils.convertSlot(slot, offset);
final ItemStack clicked = outsideDrop ?
ItemStack.getAirItem() : (isInWindow ? getItemStack(slot) : playerInventory.getItemStack(clickSlot));
ItemStack.AIR : (isInWindow ? getItemStack(slot) : playerInventory.getItemStack(clickSlot));
final ItemStack cursor = getCursorItem(player);
final InventoryClickResult clickResult = clickProcessor.drop(this, player,
@ -574,7 +571,7 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View
final int clickSlot = isInWindow ? slot : PlayerInventoryUtils.convertSlot(slot, offset);
final ItemStack clicked = slot != -999 ?
(isInWindow ? getItemStack(slot) : playerInventory.getItemStack(clickSlot)) :
ItemStack.getAirItem();
ItemStack.AIR;
final ItemStack cursor = getCursorItem(player);
final InventoryClickResult clickResult = clickProcessor.dragging(this, player,

View File

@ -16,12 +16,12 @@ import net.minestom.server.item.StackingRule;
import net.minestom.server.network.packet.server.play.EntityEquipmentPacket;
import net.minestom.server.network.packet.server.play.SetSlotPacket;
import net.minestom.server.network.packet.server.play.WindowItemsPacket;
import net.minestom.server.utils.ArrayUtils;
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;
@ -36,7 +36,7 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler
protected final Player player;
protected final ItemStack[] items = new ItemStack[INVENTORY_SIZE];
private ItemStack cursorItem = ItemStack.getAirItem();
private ItemStack cursorItem = ItemStack.AIR;
private final List<InventoryCondition> inventoryConditions = new CopyOnWriteArrayList<>();
private final InventoryClickProcessor clickProcessor = new InventoryClickProcessor();
@ -45,8 +45,7 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler
public PlayerInventory(@NotNull Player player) {
this.player = player;
ArrayUtils.fill(items, ItemStack::getAirItem);
Arrays.fill(items, ItemStack.AIR);
}
@NotNull
@ -110,12 +109,10 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler
final int totalAmount = itemStackAmount + itemAmount;
if (!stackingRule.canApply(itemStack, totalAmount)) {
item = itemStackingRule.apply(item, itemStackingRule.getMaxSize());
sendSlotRefresh((short) convertToPacketSlot(i), item);
setItemStack(i, item);
itemStack = stackingRule.apply(itemStack, totalAmount - stackingRule.getMaxSize());
} else {
item.setAmount((byte) totalAmount);
sendSlotRefresh((short) convertToPacketSlot(i), item);
setItemStack(i, item.withAmount(totalAmount));
return true;
}
} else if (item.isAir()) {
@ -130,7 +127,7 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler
public void clear() {
// Clear the item array
for (int i = 0; i < getSize(); i++) {
setItemStackInternal(i, ItemStack.getAirItem());
setItemStackInternal(i, ItemStack.AIR);
}
// Send the cleared inventory to the inventory's owner
update();
@ -418,7 +415,7 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler
public boolean drop(@NotNull Player player, int mode, int slot, int button) {
final ItemStack cursor = getCursorItem();
final boolean outsideDrop = slot == -999;
final ItemStack clicked = outsideDrop ? ItemStack.getAirItem() : getItemStack(slot, OFFSET);
final ItemStack clicked = outsideDrop ? ItemStack.AIR : getItemStack(slot, OFFSET);
final InventoryClickResult clickResult = clickProcessor.drop(null, player,
mode, slot, button, clicked, cursor);
@ -492,7 +489,7 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler
@Override
public boolean dragging(@NotNull Player player, int slot, int button) {
final ItemStack cursor = getCursorItem();
final ItemStack clicked = slot != -999 ? getItemStack(slot, OFFSET) : ItemStack.getAirItem();
final ItemStack clicked = slot != -999 ? getItemStack(slot, OFFSET) : ItemStack.AIR;
final InventoryClickResult clickResult = clickProcessor.dragging(null, player,
slot, button,

View File

@ -101,19 +101,13 @@ public class InventoryClickProcessor {
} else {
if (cursor.isAir()) {
final int amount = (int) Math.ceil((double) clicked.getAmount() / 2d);
resultCursor = clicked.clone();
resultCursor = cursorRule.apply(resultCursor, amount);
resultClicked = clicked.clone();
resultClicked = clickedRule.apply(resultClicked, clicked.getAmount() / 2);
resultCursor = cursorRule.apply(clicked, amount);
resultClicked = clickedRule.apply(clicked, clicked.getAmount() / 2);
} else {
if (clicked.isAir()) {
final int amount = cursor.getAmount();
resultCursor = cursor.clone();
resultCursor = cursorRule.apply(resultCursor, amount - 1);
resultClicked = cursor.clone();
resultClicked = clickedRule.apply(resultClicked, 1);
resultCursor = cursorRule.apply(cursor, amount - 1);
resultClicked = clickedRule.apply(cursor, 1);
} else {
resultCursor = clicked;
resultClicked = cursor;
@ -155,11 +149,11 @@ public class InventoryClickProcessor {
if (clicked.isAir()) {
// Set held item [key] to slot
resultClicked = cursor;
resultHeld = ItemStack.getAirItem();
resultHeld = ItemStack.AIR;
} else {
if (cursor.isAir()) {
// if held item [key] is air then set clicked to held
resultClicked = ItemStack.getAirItem();
resultClicked = ItemStack.AIR;
} else {
// Otherwise replace held item and held
resultClicked = cursor;
@ -189,7 +183,7 @@ public class InventoryClickProcessor {
final StackingRule clickedRule = clicked.getStackingRule();
boolean filled = false;
ItemStack resultClicked = clicked.clone();
ItemStack resultClicked = clicked;
for (InventoryClickLoopHandler loopHandler : loopHandlers) {
final Int2IntFunction indexModifier = loopHandler.getIndexModifier();
@ -242,7 +236,7 @@ public class InventoryClickProcessor {
// Switch
itemSetter.accept(index, resultClicked);
itemSetter.accept(slot, ItemStack.getAirItem());
itemSetter.accept(slot, ItemStack.AIR);
filled = true;
break;
}
@ -287,7 +281,7 @@ public class InventoryClickProcessor {
int finalCursorAmount = cursorAmount;
for (int s : slots) {
final ItemStack draggedItem = cursor.clone();
final ItemStack draggedItem = cursor;
ItemStack slotItem = itemGetter.apply(s);
clickResult = startCondition(inventory, player, s, ClickType.DRAGGING, slotItem, cursor);
@ -327,7 +321,7 @@ public class InventoryClickProcessor {
if (size > cursorAmount)
return null;
for (int s : slots) {
ItemStack draggedItem = cursor.clone();
ItemStack draggedItem = cursor;
ItemStack slotItem = itemGetter.apply(s);
clickResult = startCondition(inventory, player, s, ClickType.DRAGGING, slotItem, cursor);
@ -377,7 +371,7 @@ public class InventoryClickProcessor {
@Nullable
public InventoryClickResult doubleClick(@Nullable Inventory inventory, @NotNull Player player, int slot,
@NotNull ItemStack cursor, @NotNull InventoryClickLoopHandler... loopHandlers) {
InventoryClickResult clickResult = startCondition(inventory, player, slot, ClickType.START_DOUBLE_CLICK, ItemStack.getAirItem(), cursor);
InventoryClickResult clickResult = startCondition(inventory, player, slot, ClickType.START_DOUBLE_CLICK, ItemStack.AIR, cursor);
if (clickResult.isCancel()) {
return clickResult;
@ -446,8 +440,8 @@ public class InventoryClickProcessor {
final StackingRule clickedRule = clicked.getStackingRule();
final StackingRule cursorRule = cursor.getStackingRule();
ItemStack resultClicked = clicked.clone();
ItemStack resultCursor = cursor.clone();
ItemStack resultClicked = clicked;
ItemStack resultCursor = cursor;
if (slot == -999) {
@ -455,7 +449,7 @@ public class InventoryClickProcessor {
if (button == 0) {
// Left (drop all)
final int amount = cursorRule.getAmount(resultCursor);
final ItemStack dropItem = cursorRule.apply(resultCursor.clone(), amount);
final ItemStack dropItem = cursorRule.apply(resultCursor, amount);
final boolean dropResult = player.dropItem(dropItem);
clickResult.setCancel(!dropResult);
if (dropResult) {
@ -463,7 +457,7 @@ public class InventoryClickProcessor {
}
} else if (button == 1) {
// Right (drop 1)
final ItemStack dropItem = cursorRule.apply(resultCursor.clone(), 1);
final ItemStack dropItem = cursorRule.apply(resultCursor, 1);
final boolean dropResult = player.dropItem(dropItem);
clickResult.setCancel(!dropResult);
if (dropResult) {
@ -476,7 +470,7 @@ public class InventoryClickProcessor {
} else if (mode == 4) {
if (button == 0) {
// Drop key Q (drop 1)
final ItemStack dropItem = cursorRule.apply(resultClicked.clone(), 1);
final ItemStack dropItem = cursorRule.apply(resultClicked, 1);
final boolean dropResult = player.dropItem(dropItem);
clickResult.setCancel(!dropResult);
if (dropResult) {
@ -487,7 +481,7 @@ public class InventoryClickProcessor {
} else if (button == 1) {
// Ctrl + Drop key Q (drop all)
final int amount = cursorRule.getAmount(resultClicked);
final ItemStack dropItem = clickedRule.apply(resultClicked.clone(), amount);
final ItemStack dropItem = clickedRule.apply(resultClicked, amount);
final boolean dropResult = player.dropItem(dropItem);
clickResult.setCancel(!dropResult);
if (dropResult) {
@ -517,7 +511,7 @@ public class InventoryClickProcessor {
// Call ItemStack#onInventoryClick
{
clickResult.getClicked().onInventoryClick(player, clickType, slot, isPlayerInventory);
//clickResult.getClicked().onInventoryClick(player, clickType, slot, isPlayerInventory);
}
// Reset the didCloseInventory field

View File

@ -1,104 +0,0 @@
package net.minestom.server.item;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.IntUnaryOperator;
import java.util.function.UnaryOperator;
public class Item {
private final UUID uuid = UUID.randomUUID();
private final Material material;
private final int amount;
private final ItemMeta meta;
protected Item(@NotNull Material material, int amount, ItemMeta meta) {
this.material = material;
this.amount = amount;
this.meta = meta;
}
@Contract(value = "_ -> new", pure = true)
public static @NotNull ItemBuilder builder(@NotNull Material material) {
return new ItemBuilder(material);
}
@Contract(pure = true)
public @NotNull UUID getUuid() {
return uuid;
}
@Contract(pure = true)
public @NotNull Material getMaterial() {
return material;
}
@Contract(value = "_, -> new", pure = true)
public @NotNull Item with(@NotNull Consumer<@NotNull ItemBuilder> builderConsumer) {
var builder = builder();
builderConsumer.accept(builder);
return builder.build();
}
@Contract(pure = true)
public int getAmount() {
return amount;
}
@Contract(value = "_, -> new", pure = true)
public @NotNull Item withAmount(int amount) {
return builder().amount(amount).build();
}
@Contract(value = "_, -> new", pure = true)
public @NotNull Item withAmount(@NotNull IntUnaryOperator intUnaryOperator) {
return withAmount(intUnaryOperator.applyAsInt(amount));
}
@Contract(value = "_, _ -> new", pure = true)
public <T extends ItemMetaBuilder, U extends ItemMetaBuilder.Provider<T>> @NotNull Item withMeta(Class<U> metaType, Consumer<T> metaConsumer) {
return builder().meta(metaType, metaConsumer).build();
}
@Contract(pure = true)
public @Nullable Component getDisplayName() {
return meta.getDisplayName();
}
@Contract(value = "_, -> new", pure = true)
public @NotNull Item withDisplayName(@Nullable Component displayName) {
return builder().displayName(displayName).build();
}
@Contract(value = "_, -> new", pure = true)
public @NotNull Item withDisplayName(@NotNull UnaryOperator<@Nullable Component> componentUnaryOperator) {
return withDisplayName(componentUnaryOperator.apply(getDisplayName()));
}
@Contract(pure = true)
public @Nullable List<@NotNull Component> getLore() {
return meta.getLore();
}
@Contract(value = "_, -> new", pure = true)
public @NotNull Item withLore(@Nullable List<@NotNull Component> lore) {
return builder().lore(lore).build();
}
@Contract(value = "_, -> new", pure = true)
public @NotNull Item withLore(@NotNull UnaryOperator<@Nullable List<@NotNull Component>> loreUnaryOperator) {
return withLore(loreUnaryOperator.apply(getLore()));
}
@Contract(value = "-> new", pure = true)
protected @NotNull ItemBuilder builder() {
return new ItemBuilder(material, meta.builder())
.amount(amount);
}
}

View File

@ -17,7 +17,7 @@ public class ItemBuilder {
protected ItemBuilder(@NotNull Material material, @NotNull ItemMetaBuilder metaBuilder) {
this.material = material;
this.amount = 0;
this.amount = 1;
this.metaBuilder = metaBuilder;
}
@ -63,8 +63,8 @@ public class ItemBuilder {
}
@Contract(value = "-> new", pure = true)
public @NotNull Item build() {
return new Item(material, amount, metaBuilder.build());
public @NotNull ItemStack build() {
return new ItemStack(material, amount, metaBuilder.build());
}
}

View File

@ -1,24 +1,46 @@
package net.minestom.server.item;
import net.kyori.adventure.text.Component;
import net.minestom.server.item.attribute.ItemAttribute;
import net.minestom.server.utils.NBTUtils;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
public class ItemMeta implements Cloneable {
private final ItemMetaBuilder builder;
private final int damage;
private final boolean unbreakable;
private final int hideFlag;
private final Component displayName;
private final List<Component> lore;
private final Map<Enchantment, Short> enchantmentMap;
private final List<ItemAttribute> attributes;
private final int customModelData;
private NBTCompound cache = null;
protected ItemMeta(@NotNull ItemMetaBuilder metaBuilder) {
this.builder = metaBuilder.clone();
this.damage = 0;
this.unbreakable = false;
this.hideFlag = 0;
this.displayName = metaBuilder.displayName;
this.lore = Collections.unmodifiableList(metaBuilder.lore);
this.enchantmentMap = Collections.unmodifiableMap(metaBuilder.enchantmentMap);
this.attributes = new ArrayList<>();
this.customModelData = 0;
}
@Contract(value = "_, -> new", pure = true)
@ -28,6 +50,18 @@ public class ItemMeta implements Cloneable {
return builder.build();
}
public int getDamage() {
return damage;
}
public boolean isUnbreakable() {
return unbreakable;
}
public int getHideFlag() {
return hideFlag;
}
@Contract(pure = true)
public @Nullable Component getDisplayName() {
return displayName;
@ -38,6 +72,25 @@ public class ItemMeta implements Cloneable {
return lore;
}
public Map<Enchantment, Short> getEnchantmentMap() {
return enchantmentMap;
}
public List<ItemAttribute> getAttributes() {
return attributes;
}
public int getCustomModelData() {
return customModelData;
}
public NBTCompound toNBT() {
if (cache == null) {
this.cache = NBTUtils.metaToNBT(this);
}
return cache;
}
protected @NotNull ItemMetaBuilder builder() {
return builder.clone();
}

View File

@ -9,7 +9,7 @@ import java.util.*;
public abstract class ItemMetaBuilder implements Cloneable {
protected Component displayName;
protected List<Component> lore;
protected List<Component> lore = new ArrayList<>();
protected Map<Enchantment, Short> enchantmentMap = new HashMap<>();
protected ItemMetaBuilder() {

View File

@ -1,912 +1,136 @@
package net.minestom.server.item;
import it.unimi.dsi.fastutil.objects.Object2ShortMap;
import it.unimi.dsi.fastutil.objects.Object2ShortOpenHashMap;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.event.HoverEvent.ShowItem;
import net.kyori.adventure.text.event.HoverEventSource;
import net.minestom.server.MinecraftServer;
import net.minestom.server.chat.JsonMessage;
import net.minestom.server.data.Data;
import net.minestom.server.data.DataContainer;
import net.minestom.server.entity.ItemEntity;
import net.minestom.server.entity.Player;
import net.minestom.server.inventory.Inventory;
import net.minestom.server.inventory.PlayerInventory;
import net.minestom.server.inventory.click.ClickType;
import net.minestom.server.item.attribute.ItemAttribute;
import net.minestom.server.item.metadata.*;
import net.minestom.server.item.rule.VanillaStackingRule;
import net.minestom.server.network.packet.server.play.SetSlotPacket;
import net.minestom.server.registry.Registries;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.Direction;
import net.minestom.server.utils.NBTUtils;
import net.minestom.server.utils.clone.PublicCloneable;
import net.minestom.server.utils.ownership.OwnershipHandler;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.*;
import java.util.List;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.IntUnaryOperator;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
// TODO should we cache a ByteBuf of this item for faster packet write
public class ItemStack {
/**
* Represents an item in an inventory ({@link PlayerInventory}, {@link Inventory}) or on the ground ({@link ItemEntity}).
* <p>
* An item stack cannot be null, you can however use {@link #getAirItem()} instead.
* <p>
* WARNING: all setters will not update the item automatically, it will need to be refreshed manually.
* Here a non-exhaustive list of what you can do to update the item:
* {@link PlayerInventory#refreshSlot(short)}, {@link Inventory#refreshSlot(short)} or a raw {@link SetSlotPacket}.
*/
public class ItemStack implements DataContainer, PublicCloneable<ItemStack>, HoverEventSource<ShowItem> {
public static final ItemStack AIR = ItemStack.builder(Material.AIR).build();
public static final OwnershipHandler<Data> DATA_OWNERSHIP = new OwnershipHandler<>();
public static final String OWNERSHIP_DATA_KEY = "ownership_identifier";
private static final StackingRule VANILLA_STACKING_RULE = new VanillaStackingRule(64);
private final UUID uuid = UUID.randomUUID();
private final StackingRule stackingRule = new VanillaStackingRule(64);
private final UUID identifier;
private final Material material;
private final int amount;
private final ItemMeta meta;
private Material material;
private static StackingRule defaultStackingRule;
private ItemMeta itemMeta;
private byte amount;
private int damage;
private Component displayName;
private boolean unbreakable;
private List<Component> lore;
private Object2ShortMap<Enchantment> enchantmentMap;
private List<ItemAttribute> attributes;
private int hideFlag;
private int customModelData;
private StackingRule stackingRule;
private Data data;
private Set<String> canDestroy;
private Set<String> canPlaceOn;
{
if (defaultStackingRule == null)
defaultStackingRule = VANILLA_STACKING_RULE;
this.stackingRule = defaultStackingRule;
}
public ItemStack(@NotNull Material material, byte amount, int damage) {
this.identifier = DATA_OWNERSHIP.generateIdentifier();
protected ItemStack(@NotNull Material material, int amount, ItemMeta meta) {
this.material = material;
this.amount = amount;
this.damage = damage;
this.lore = new ArrayList<>();
this.enchantmentMap = new Object2ShortOpenHashMap<>();
this.attributes = new ArrayList<>();
this.canDestroy = new HashSet<>();
this.canPlaceOn = new HashSet<>();
this.itemMeta = findMeta();
this.meta = meta;
}
public ItemStack(@NotNull Material material, byte amount) {
this(material, amount, (short) 0);
@Contract(value = "_ -> new", pure = true)
public static @NotNull ItemBuilder builder(@NotNull Material material) {
return new ItemBuilder(material);
}
public ItemStack(@NotNull Material material) {
this(material, (byte) 1, (short) 0);
@Contract(value = "_ -> new", pure = true)
public static @NotNull ItemStack of(@NotNull Material material, int amount) {
return builder(material).amount(amount).build();
}
/**
* Gets a new {@link ItemStack} with the material sets to {@link Material#AIR}.
* <p>
* Used when you require a "null item".
*
* @return an air item
*/
@NotNull
public static ItemStack getAirItem() {
return new ItemStack(Material.AIR, (byte) 0);
@Contract(value = "_ -> new", pure = true)
public static @NotNull ItemStack of(@NotNull Material material) {
return of(material, 1);
}
/**
* Gets the default {@link StackingRule} for newly created {@link ItemStack}.
*
* @return the default stacking rule
*/
@NotNull
public static StackingRule getDefaultStackingRule() {
return defaultStackingRule;
@Contract(pure = true)
public @NotNull UUID getUuid() {
return uuid;
}
/**
* Changes the default stacking rule for created item stack.
*
* @param defaultStackingRule the default item stack
* @throws NullPointerException if {@code defaultStackingRule} is null
*/
public static void setDefaultStackingRule(@NotNull StackingRule defaultStackingRule) {
ItemStack.defaultStackingRule = defaultStackingRule;
}
/**
* Loads an {@link ItemStack} from nbt.
*
* @param nbt the nbt compound containing the item
* @return the parsed item stack
*/
@NotNull
public static ItemStack fromNBT(@NotNull NBTCompound nbt) {
if (!nbt.containsKey("id") || !nbt.containsKey("Count"))
throw new IllegalArgumentException("Invalid item NBT, must at least contain 'id' and 'Count' tags");
final Material material = Registries.getMaterial(nbt.getString("id"));
final byte count = nbt.getAsByte("Count");
ItemStack s = new ItemStack(material, count);
NBTCompound tag = nbt.getCompound("tag");
if (tag != null) {
NBTUtils.loadDataIntoItem(s, tag);
}
return s;
}
/**
* Gets if the item material is {@link Material#AIR}.
*
* @return true if the material is air, false otherwise
*/
public boolean isAir() {
return material == Material.AIR;
}
/**
* Gets if two items are similar.
* It does not take {@link #getAmount()} and {@link #getStackingRule()} in consideration.
*
* @param itemStack The ItemStack to compare to
* @return true if both items are similar
*/
public boolean isSimilar(@NotNull ItemStack itemStack) {
synchronized (ItemStack.class) {
if (itemStack.getIdentifier().equals(identifier)) {
return true;
}
final boolean displayNameCheck = Objects.equals(displayName, itemStack.displayName);
final boolean loreCheck = Objects.equals(lore, itemStack.lore);
final Data itemData = itemStack.getData();
final boolean dataCheck = (data == null && itemData == null) ||
(data != null && data.equals(itemData));
final boolean sameMeta = (itemStack.itemMeta == null && itemMeta == null) ||
(itemStack.itemMeta != null && itemMeta != null && (itemStack.itemMeta.isSimilar(itemMeta)));
return itemStack.getMaterial() == material &&
displayNameCheck &&
loreCheck &&
itemStack.isUnbreakable() == unbreakable &&
itemStack.getDamage() == damage &&
itemStack.enchantmentMap.equals(enchantmentMap) &&
itemStack.attributes.equals(attributes) &&
itemStack.hideFlag == hideFlag &&
sameMeta &&
dataCheck &&
itemStack.canPlaceOn.equals(canPlaceOn) &&
itemStack.canDestroy.equals(canDestroy);
}
}
@Override
public boolean equals(Object o) {
return o instanceof ItemStack &&
isSimilar((ItemStack) o) && ((ItemStack) o).getAmount() == getAmount();
}
/**
* Checks if this item can be placed on the block.
* This should be enforced only for adventure mode players.
*
* @param block the block's namespaceID
* @return <code>true</code> if it can be placed, <code>false</code> otherwise
*/
public boolean canPlaceOn(String block) {
return canPlaceOn.contains(block);
}
/**
* Gets the blocks that this item can be placed on
*
* @return the {@link Set} of blocks
*/
public Set<String> getCanPlaceOn() {
return canPlaceOn;
}
/**
* Checks if this item is allowed to break the provided block.
* This should be enforced only for adventure mode players.
*
* @param block the block's namespaceID
* @return <code>true</code> if this item can destroy it, otherwise <code>false</code>
*/
public boolean canDestroy(String block) {
return canDestroy.contains(block);
}
/**
* Gets the blocks that this item can destroy
*
* @return the {@link Set} of blocks
*/
public Set<String> getCanDestroy() {
return canDestroy;
}
/**
* Gets the item damage (durability).
*
* @return the item damage
*/
public int getDamage() {
return damage;
}
/**
* Sets the item damage (durability).
*
* @param damage the item damage
*/
public void setDamage(int damage) {
this.damage = damage;
}
/**
* Gets the item amount.
* <p>
* WARNING: for amount computation it would be better to use {@link StackingRule#getAmount(ItemStack)}
* to support all stacking implementation.
*
* @return the item amount
*/
public byte getAmount() {
return amount;
}
/**
* Changes the item amount.
* <p>
* WARNING: for amount computation it would be better to use {@link StackingRule#getAmount(ItemStack)}
* to support all stacking implementation.
*
* @param amount the new item amount
*/
public void setAmount(byte amount) {
this.amount = amount;
}
/**
* Gets the special meta object for this item.
* <p>
* Can be null if not any.
*
* @return the item meta
*/
@Nullable
public ItemMeta getItemMeta() {
return itemMeta;
}
/**
* Changes the item meta linked to this item.
* <p>
* WARNING: be sure to have nbt data useful for this item, items should automatically get the appropriate
* item meta.
*
* @param itemMeta the new item meta
*/
public void setItemMeta(@Nullable ItemMeta itemMeta) {
this.itemMeta = itemMeta;
}
/**
* Gets the item display name.
*
* @return the item display name, can be null if not present
* @deprecated Use {@link #getDisplayName()}
*/
@Deprecated
@Nullable
public JsonMessage getDisplayNameJson() {
return JsonMessage.fromComponent(displayName);
}
/**
* Gets the item display name.
*
* @return the item display name, can be null if not present
*/
@Nullable
public Component getDisplayName() {
return displayName;
}
/**
* Sets the item display name.
*
* @param displayName the item display name
* @deprecated Use {@link #setDisplayName(Component)}
*/
@Deprecated
public void setDisplayName(@Nullable JsonMessage displayName) {
this.setDisplayName(displayName == null ? null : displayName.asComponent());
}
/**
* Sets the item display name.
*
* @param displayName the item display name
*/
public void setDisplayName(@Nullable Component displayName) {
this.displayName = displayName;
}
/**
* Gets if the item has a display name.
*
* @return the item display name
*/
public boolean hasDisplayName() {
return displayName != null;
}
/**
* Gets the item lore.
*
* @return a modifiable list containing the item lore, can be empty if not present
* @deprecated Use {@link #getLore()}
*/
@Deprecated
@NotNull
public List<JsonMessage> getLoreJson() {
return lore.stream().map(JsonMessage::fromComponent).collect(Collectors.toList());
}
/**
* Gets the item lore.
*
* @return a modifiable list containing the item lore, can be empty if not present
*/
@NotNull
public List<Component> getLore() {
return lore;
}
/**
* Sets the item lore.
*
* @param lore the item lore, can be empty to remove
* @deprecated Use {@link #setLore}
*/
@Deprecated
public void setLoreJson(@NotNull List<JsonMessage> lore) {
this.lore = lore.stream().map(JsonMessage::asComponent).collect(Collectors.toList());
}
/**
* Sets the item lore.
*
* @param lore the item lore, can be empty to remove
*/
@NotNull
public void setLore(List<Component> lore) {
this.lore = lore;
}
/**
* Gets if the item has a lore.
*
* @return true if the item has lore, false otherwise
*/
public boolean hasLore() {
return lore != null && !lore.isEmpty();
}
/**
* Gets the item enchantment map.
*
* @return an unmodifiable map containing the item enchantments
*/
@NotNull
public Map<Enchantment, Short> getEnchantmentMap() {
return Collections.unmodifiableMap(enchantmentMap);
}
/**
* Sets an enchantment level.
*
* @param enchantment the enchantment type
* @param level the enchantment level
*/
public void setEnchantment(@NotNull Enchantment enchantment, short level) {
if (level < 1) {
removeEnchantment(enchantment);
return;
}
this.enchantmentMap.put(enchantment, level);
}
/**
* Removes an enchantment.
*
* @param enchantment the enchantment type
*/
public void removeEnchantment(@NotNull Enchantment enchantment) {
this.enchantmentMap.removeShort(enchantment);
}
/**
* Gets an enchantment level.
*
* @param enchantment the enchantment type
* @return the stored enchantment level, 0 if not present
*/
public int getEnchantmentLevel(@NotNull Enchantment enchantment) {
return this.enchantmentMap.getOrDefault(enchantment, (short) 0);
}
/**
* Gets the item attributes.
*
* @return an unmodifiable {@link List} containing the item attributes
*/
@NotNull
public List<ItemAttribute> getAttributes() {
return Collections.unmodifiableList(attributes);
}
/**
* Gets the {@link ItemAttribute} with the specified internal name.
*
* @param internalName the internal name of the attribute
* @return the {@link ItemAttribute} with the internal name, null if not found
*/
public ItemAttribute getAttribute(@NotNull String internalName) {
for (ItemAttribute itemAttribute : attributes) {
if (itemAttribute.getInternalName().equals(internalName))
return itemAttribute;
}
return null;
}
/**
* Adds an attribute to the item.
*
* @param itemAttribute the attribute to add
*/
public void addAttribute(@NotNull ItemAttribute itemAttribute) {
this.attributes.add(itemAttribute);
}
/**
* Removes an attribute to the item.
*
* @param itemAttribute the attribute to remove
*/
public void removeAttribute(@NotNull ItemAttribute itemAttribute) {
this.attributes.remove(itemAttribute);
}
/**
* Gets the item hide flag.
*
* @return the item hide flag
*/
public int getHideFlag() {
return hideFlag;
}
/**
* Changes the item hide flag. This is the integer sent when updating the item hide flag.
*
* @param hideFlag the new item hide flag
*/
public void setHideFlag(int hideFlag) {
this.hideFlag = hideFlag;
}
/**
* Gets the item custom model data.
*
* @return the item custom model data
*/
public int getCustomModelData() {
return customModelData;
}
/**
* Changes the item custom model data.
*
* @param customModelData the new item custom data model
*/
public void setCustomModelData(int customModelData) {
this.customModelData = customModelData;
}
/**
* Adds flags to the item.
*
* @param flags the flags to add
*/
public void addItemFlags(@NotNull ItemFlag... flags) {
for (ItemFlag f : flags) {
this.hideFlag |= getBitModifier(f);
}
}
/**
* Removes flags from the item.
*
* @param flags the flags to remove
*/
public void removeItemFlags(@NotNull ItemFlag... flags) {
for (ItemFlag f : flags) {
this.hideFlag &= ~getBitModifier(f);
}
}
/**
* Gets the item flags.
*
* @return an unmodifiable {@link Set} containing the item flags
*/
@NotNull
public Set<ItemFlag> getItemFlags() {
Set<ItemFlag> currentFlags = EnumSet.noneOf(ItemFlag.class);
for (ItemFlag f : ItemFlag.values()) {
if (hasItemFlag(f)) {
currentFlags.add(f);
}
}
return Collections.unmodifiableSet(currentFlags);
}
/**
* Gets if the item has an item flag.
*
* @param flag the item flag
* @return true if the item has the flag {@code flag}, false otherwise
*/
public boolean hasItemFlag(@NotNull ItemFlag flag) {
final int bitModifier = getBitModifier(flag);
return (this.hideFlag & bitModifier) == bitModifier;
}
/**
* Gets if the item is unbreakable.
*
* @return true if the item is unbreakable, false otherwise
*/
public boolean isUnbreakable() {
return unbreakable;
}
/**
* Makes the item unbreakable.
*
* @param unbreakable true to make the item unbreakable, false otherwise
*/
public void setUnbreakable(boolean unbreakable) {
this.unbreakable = unbreakable;
}
/**
* Gets the unique identifier of this object.
* <p>
* This value is non persistent and will be randomized once this item is separated with a right-click,
* when copied and when the server restart. It is used internally by the data ownership system.
*
* @return this item unique identifier
*/
@NotNull
public UUID getIdentifier() {
return identifier;
}
/**
* Gets the item {@link Material}.
*
* @return the item material
*/
@NotNull
public Material getMaterial() {
@Contract(pure = true)
public @NotNull Material getMaterial() {
return material;
}
/**
* Changes the item {@link Material}.
*
* @param material the new material
*/
public void setMaterial(@NotNull Material material) {
this.material = material;
@Contract(value = "_, -> new", pure = true)
public @NotNull ItemStack with(@NotNull Consumer<@NotNull ItemBuilder> builderConsumer) {
var builder = builder();
builderConsumer.accept(builder);
return builder.build();
}
/**
* Gets if the item has any nbt tag.
*
* @return true if the item has nbt tag, false otherwise
*/
public boolean hasNbtTag() {
return hasDisplayName() ||
hasLore() ||
damage != 0 ||
isUnbreakable() ||
!enchantmentMap.isEmpty() ||
!attributes.isEmpty() ||
hideFlag != 0 ||
customModelData != 0 ||
(itemMeta != null && itemMeta.hasNbt()) ||
(data != null && !data.isEmpty()) ||
!canDestroy.isEmpty() ||
!canPlaceOn.isEmpty();
@Contract(pure = true)
public int getAmount() {
return amount;
}
/**
* @deprecated use {@link #clone()}
*/
@Deprecated
@NotNull
public synchronized ItemStack copy() {
return clone();
@Contract(value = "_, -> new", pure = true)
public @NotNull ItemStack withAmount(int amount) {
return builder().amount(amount).build();
}
/**
* Clones this item stack.
* <p>
* Be aware that the identifier ({@link #getIdentifier()}) will change.
*
* @return a cloned item stack with a different identifier
*/
@NotNull
@Override
public ItemStack clone() {
try {
ItemStack itemStack = (ItemStack) super.clone();
itemStack.setDisplayName(displayName);
itemStack.setUnbreakable(unbreakable);
if (lore != null) {
itemStack.setLore(new ArrayList<>(lore));
}
if (stackingRule != null) {
itemStack.setStackingRule(stackingRule);
}
itemStack.enchantmentMap = new Object2ShortOpenHashMap<>(enchantmentMap);
itemStack.attributes = new ArrayList<>(attributes);
itemStack.hideFlag = hideFlag;
itemStack.customModelData = customModelData;
itemStack.canPlaceOn = new HashSet<>(canPlaceOn);
itemStack.canDestroy = new HashSet<>(canDestroy);
if (itemMeta != null)
itemStack.itemMeta = itemMeta.clone();
final Data data = getData();
if (data != null)
itemStack.setData(data.clone());
return itemStack;
} catch (CloneNotSupportedException e) {
MinecraftServer.getExceptionManager().handleException(e);
return null;
}
@Contract(value = "_, -> new", pure = true)
public @NotNull ItemStack withAmount(@NotNull IntUnaryOperator intUnaryOperator) {
return withAmount(intUnaryOperator.applyAsInt(amount));
}
@Nullable
@Override
public Data getData() {
return data;
@Contract(value = "_, _ -> new", pure = true)
public <T extends ItemMetaBuilder, U extends ItemMetaBuilder.Provider<T>> @NotNull ItemStack withMeta(Class<U> metaType, Consumer<T> metaConsumer) {
return builder().meta(metaType, metaConsumer).build();
}
/**
* Sets the data of this item.
*
* @param data the new {@link Data} of this container, null to remove it
*/
@Override
public void setData(@Nullable Data data) {
DATA_OWNERSHIP.saveOwnObject(getIdentifier(), data);
this.data = data;
@Contract(pure = true)
public @Nullable Component getDisplayName() {
return meta.getDisplayName();
}
/**
* Gets the item {@link StackingRule}.
*
* @return the item stacking rule
*/
@NotNull
public StackingRule getStackingRule() {
@Contract(value = "_, -> new", pure = true)
public @NotNull ItemStack withDisplayName(@Nullable Component displayName) {
return builder().displayName(displayName).build();
}
@Contract(value = "_, -> new", pure = true)
public @NotNull ItemStack withDisplayName(@NotNull UnaryOperator<@Nullable Component> componentUnaryOperator) {
return withDisplayName(componentUnaryOperator.apply(getDisplayName()));
}
@Contract(pure = true)
public @Nullable List<@NotNull Component> getLore() {
return meta.getLore();
}
@Contract(value = "_, -> new", pure = true)
public @NotNull ItemStack withLore(@Nullable List<@NotNull Component> lore) {
return builder().lore(lore).build();
}
@Contract(value = "_, -> new", pure = true)
public @NotNull ItemStack withLore(@NotNull UnaryOperator<@Nullable List<@NotNull Component>> loreUnaryOperator) {
return withLore(loreUnaryOperator.apply(getLore()));
}
public @NotNull StackingRule getStackingRule() {
return stackingRule;
}
/**
* Changes the {@link StackingRule} of the item.
*
* @param stackingRule the new item stacking rule
* @throws NullPointerException if {@code stackingRule} is null
*/
public void setStackingRule(@NotNull StackingRule stackingRule) {
this.stackingRule = stackingRule;
public @NotNull ItemMeta getMeta() {
return meta;
}
/**
* Consumes this item by a specific amount.
* <p>
* Will return null if the amount's amount isn't enough.
*
* @param amount the quantity to consume
* @return the new item with the updated amount, null if the item cannot be consumed by this much
*/
@Nullable
public ItemStack consume(int amount) {
final int currentAmount = stackingRule.getAmount(this);
if (currentAmount < amount)
return null;
return stackingRule.apply(this, currentAmount - amount);
public boolean isSimilar(@NotNull ItemStack itemStack) {
return material.equals(itemStack.material) &&
meta.equals(itemStack.meta);
}
private byte getBitModifier(@NotNull ItemFlag hideFlag) {
return (byte) (1 << hideFlag.ordinal());
public boolean isAir() {
return equals(AIR);
}
/**
* Finds the {@link ItemMeta} based on the material type.
*
* @return the item meta, null if none found
*/
@Nullable
private ItemMeta findMeta() {
if (material == Material.POTION ||
material == Material.LINGERING_POTION ||
material == Material.SPLASH_POTION ||
material == Material.TIPPED_ARROW)
return new PotionMeta();
if (material == Material.FILLED_MAP)
return new MapMeta();
if (material == Material.COMPASS)
return new CompassMeta();
if (material == Material.ENCHANTED_BOOK)
return new EnchantedBookMeta();
if (material == Material.CROSSBOW)
return new CrossbowMeta();
if (material == Material.WRITABLE_BOOK)
return new WritableBookMeta();
if (material == Material.WRITTEN_BOOK)
return new WrittenBookMeta();
if (material == Material.FIREWORK_STAR)
return new FireworkEffectMeta();
if (material == Material.FIREWORK_ROCKET)
return new FireworkMeta();
if (material == Material.PLAYER_HEAD)
return new PlayerHeadMeta();
if (material == Material.LEATHER_HELMET ||
material == Material.LEATHER_CHESTPLATE ||
material == Material.LEATHER_LEGGINGS ||
material == Material.LEATHER_BOOTS)
return new LeatherArmorMeta();
return null;
}
/**
* Creates a {@link NBTCompound} containing the data of this item.
* <p>
* WARNING: modifying the returned nbt will not affect the item.
*
* @return this item nbt
*/
@NotNull
public NBTCompound toNBT() {
NBTCompound compound = new NBTCompound()
.setByte("Count", amount)
.setString("id", material.getName());
if (hasNbtTag()) {
NBTCompound additionalTag = new NBTCompound();
NBTUtils.saveDataIntoNBT(this, additionalTag);
compound.set("tag", additionalTag);
}
return compound;
}
/**
* WARNING: not implemented yet.
* <p>
* This is be called each time an item is serialized to be send to a player,
* can be used to customize the display of the item based on player data.
*
* @param player the player
* @return the custom {@link ItemDisplay} for {@code player},
* null to use the normal item display name &amp; lore
*/
public ItemDisplay getCustomDisplay(Player player) {
throw new UnsupportedOperationException("Not implemented yet");
}
@Override
public @NotNull HoverEvent<ShowItem> asHoverEvent(@NotNull UnaryOperator<ShowItem> op) {
return HoverEvent.showItem(op.apply(ShowItem.of(this.material, this.amount, NBTUtils.asBinaryTagHolder(this.toNBT().getCompound("tag")))));
}
// Callback events
/**
* Called when the player right clicks with this item.
*
* @param player the player who used the item
* @param hand the hand used
*/
public void onRightClick(@NotNull Player player, @NotNull Player.Hand hand) {
}
/**
* Called when the player left clicks with this item.
*
* @param player the player who used the item
* @param hand the hand used
*/
public void onLeftClick(@NotNull Player player, @NotNull Player.Hand hand) {
}
/**
* Called when the player right clicks with this item on a block.
*
* @param player the player who used the item
* @param hand the hand used
* @param position the position of the interacted block
* @param blockFace the block face
* @return true if it prevents normal item use (placing blocks for instance)
*/
public boolean onUseOnBlock(@NotNull Player player, @NotNull Player.Hand hand, @NotNull BlockPosition position, @NotNull Direction blockFace) {
return false;
}
/**
* Called when the player click on this item on an inventory.
* <p>
* Executed before any events.
*
* @param player the player who clicked on the item
* @param clickType the click type
* @param slot the slot clicked
* @param playerInventory true if the click is in the player inventory
*/
public void onInventoryClick(@NotNull Player player, @NotNull ClickType clickType, int slot, boolean playerInventory) {
@Contract(value = "-> new", pure = true)
protected @NotNull ItemBuilder builder() {
return new ItemBuilder(material, meta.builder())
.amount(amount);
}
}

View File

@ -4,7 +4,6 @@ import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.registry.Registries;
import net.minestom.server.utils.NBTUtils;
import net.minestom.server.utils.clone.CloneUtils;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
@ -137,7 +136,7 @@ public class CrossbowMeta extends ItemMeta {
final NBTCompound tagsCompound = projectileCompound.getCompound("tag");
ItemStack itemStack = new ItemStack(material, count);
ItemStack itemStack = ItemStack.of(material, count);
NBTUtils.loadDataIntoItem(itemStack, tagsCompound);
index++;
@ -184,9 +183,9 @@ public class CrossbowMeta extends ItemMeta {
public ItemMeta clone() {
CrossbowMeta crossbowMeta = (CrossbowMeta) super.clone();
crossbowMeta.triple = triple;
crossbowMeta.projectile1 = CloneUtils.optionalClone(projectile1);
crossbowMeta.projectile2 = CloneUtils.optionalClone(projectile2);
crossbowMeta.projectile3 = CloneUtils.optionalClone(projectile3);
crossbowMeta.projectile1 = projectile1;
crossbowMeta.projectile2 = projectile2;
crossbowMeta.projectile3 = projectile3;
crossbowMeta.charged = charged;
@ -195,12 +194,9 @@ public class CrossbowMeta extends ItemMeta {
@NotNull
private NBTCompound getItemCompound(@NotNull ItemStack itemStack) {
NBTCompound compound = new NBTCompound();
compound.setByte("Count", itemStack.getAmount());
NBTCompound compound = NBTUtils.metaToNBT(itemStack.getMeta());
compound.setByte("Count", (byte) itemStack.getAmount());
compound.setString("id", itemStack.getMaterial().getName());
NBTUtils.saveDataIntoNBT(itemStack, compound);
return compound;
}
}

View File

@ -1,7 +1,6 @@
package net.minestom.server.item.metadata;
import net.minestom.server.MinecraftServer;
import net.minestom.server.item.ItemStack;
import net.minestom.server.utils.clone.PublicCloneable;
import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;

View File

@ -18,7 +18,7 @@ import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Item meta for
* ItemStack meta for
* {@link net.minestom.server.item.Material#POTION},
* {@link net.minestom.server.item.Material#LINGERING_POTION},
* {@link net.minestom.server.item.Material#SPLASH_POTION},

View File

@ -25,10 +25,9 @@ public class VanillaStackingRule extends StackingRule {
@Override
public ItemStack apply(@NotNull ItemStack item, int newAmount) {
if (newAmount <= 0)
return ItemStack.getAirItem();
return ItemStack.AIR;
item.setAmount((byte) newAmount);
return item;
return item.withAmount(newAmount);
}
@Override

View File

@ -10,7 +10,7 @@ public class AnimationListener {
public static void animationListener(ClientAnimationPacket packet, Player player) {
final Player.Hand hand = packet.hand;
final ItemStack itemStack = player.getItemInHand(hand);
itemStack.onLeftClick(player, hand);
//itemStack.onLeftClick(player, hand);
PlayerHandAnimationEvent handAnimationEvent = new PlayerHandAnimationEvent(player, hand);
player.callCancellableEvent(PlayerHandAnimationEvent.class, handAnimationEvent, () -> {
switch (hand) {

View File

@ -52,7 +52,8 @@ public class BlockPlacementListener {
final ItemStack usedItem = player.getItemInHand(hand);
// Interact at block
final boolean cancel = usedItem.onUseOnBlock(player, hand, blockPosition, direction);
// FIXME: onUseOnBlock
final boolean cancel = false;//usedItem.onUseOnBlock(player, hand, blockPosition, direction);
PlayerBlockInteractEvent playerBlockInteractEvent = new PlayerBlockInteractEvent(player, blockPosition, hand, blockFace);
playerBlockInteractEvent.setCancelled(cancel);
playerBlockInteractEvent.setBlockingItemUse(cancel);
@ -85,7 +86,8 @@ public class BlockPlacementListener {
canPlaceBlock = false; //Spectators can't place blocks
} else if (player.getGameMode() == GameMode.ADVENTURE) {
//Check if the block can placed on the block
canPlaceBlock = usedItem.canPlaceOn(instance.getBlock(blockPosition).getName());
// FIXME: canPlaceOn
canPlaceBlock = true;//usedItem.canPlaceOn(instance.getBlock(blockPosition).getName());
}
}
@ -166,11 +168,8 @@ public class BlockPlacementListener {
// Block consuming
if (playerBlockPlaceEvent.doesConsumeBlock()) {
// Consume the block in the player's hand
final ItemStack newUsedItem = usedItem.consume(1);
if (newUsedItem != null) {
playerInventory.setItemInHand(hand, newUsedItem);
}
final ItemStack newUsedItem = usedItem.getStackingRule().apply(usedItem, usedItem.getAmount() - 1);
playerInventory.setItemInHand(hand, newUsedItem);
}
} else {
refreshChunk = true;

View File

@ -47,11 +47,12 @@ public class PlayerDiggingListener {
} else if (player.getGameMode() == GameMode.ADVENTURE) {
//Check if the item can break the block with the current item
ItemStack itemInMainHand = player.getItemInMainHand();
if (!itemInMainHand.canDestroy(instance.getBlock(blockPosition).getName())) {
// FIXME: canDestroy
/*if (!itemInMainHand.canDestroy(instance.getBlock(blockPosition).getName())) {
sendAcknowledgePacket(player, blockPosition, blockStateId,
ClientPlayerDiggingPacket.Status.STARTED_DIGGING, false);
return;
}
}*/
}
final boolean instantBreak = player.isCreative() ||
@ -111,7 +112,7 @@ public class PlayerDiggingListener {
} else if (status == ClientPlayerDiggingPacket.Status.DROP_ITEM_STACK) {
final ItemStack droppedItemStack = player.getInventory().getItemInMainHand();
dropItem(player, droppedItemStack, ItemStack.getAirItem());
dropItem(player, droppedItemStack, ItemStack.AIR);
} else if (status == ClientPlayerDiggingPacket.Status.DROP_ITEM) {
@ -123,14 +124,11 @@ public class PlayerDiggingListener {
if (handAmount <= dropAmount) {
// Drop the whole item without copy
dropItem(player, handItem, ItemStack.getAirItem());
dropItem(player, handItem, ItemStack.AIR);
} else {
// Drop a single item, need a copy
ItemStack droppedItemStack2 = handItem.clone();
ItemStack droppedItemStack2 = stackingRule.apply(handItem, dropAmount);
droppedItemStack2 = stackingRule.apply(droppedItemStack2, dropAmount);
handItem = handItem.clone(); // Force the copy
handItem = stackingRule.apply(handItem, handAmount - dropAmount);
dropItem(player, droppedItemStack2, handItem);

View File

@ -1,7 +1,6 @@
package net.minestom.server.listener;
import net.minestom.server.entity.Player;
import net.minestom.server.event.item.ArmorEquipEvent;
import net.minestom.server.event.player.PlayerItemAnimationEvent;
import net.minestom.server.event.player.PlayerPreEatEvent;
import net.minestom.server.event.player.PlayerUseItemEvent;
@ -16,7 +15,7 @@ public class UseItemListener {
final PlayerInventory inventory = player.getInventory();
final Player.Hand hand = packet.hand;
ItemStack itemStack = hand == Player.Hand.MAIN ? inventory.getItemInMainHand() : inventory.getItemInOffHand();
itemStack.onRightClick(player, hand);
//itemStack.onRightClick(player, hand);
PlayerUseItemEvent useItemEvent = new PlayerUseItemEvent(player, hand, itemStack);
player.callEvent(PlayerUseItemEvent.class, useItemEvent);

View File

@ -13,7 +13,7 @@ public class ClientClickWindowPacket extends ClientPlayPacket {
public byte button;
public short actionNumber;
public int mode;
public ItemStack item = ItemStack.getAirItem();
public ItemStack item = ItemStack.AIR;
@Override
public void read(@NotNull BinaryReader reader) {

View File

@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull;
public class ClientCreativeInventoryActionPacket extends ClientPlayPacket {
public short slot;
public ItemStack item = ItemStack.getAirItem();
public ItemStack item = ItemStack.AIR;
@Override
public void read(@NotNull BinaryReader reader) {

View File

@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull;
public class ClientEditBookPacket extends ClientPlayPacket {
public ItemStack book = ItemStack.getAirItem();
public ItemStack book = ItemStack.AIR;
public boolean isSigning;
public Player.Hand hand = Player.Hand.MAIN;

View File

@ -17,7 +17,7 @@ public class ClientNameItemPacket extends ClientPlayPacket {
@Override
public void write(@NotNull BinaryWriter writer) {
if(itemName.length() > Short.MAX_VALUE) {
throw new IllegalArgumentException("Item name cannot be longer than Short.MAX_VALUE characters!");
throw new IllegalArgumentException("ItemStack name cannot be longer than Short.MAX_VALUE characters!");
}
writer.writeSizedString(itemName);
}

View File

@ -2,8 +2,6 @@ package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.text.Component;
import net.minestom.server.advancements.FrameType;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.chat.JsonMessage;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
import net.minestom.server.network.packet.server.ServerPacket;
@ -27,7 +25,8 @@ public class AdvancementsPacket implements ComponentHoldingServerPacket {
public String[] identifiersToRemove = new String[0];
public ProgressMapping[] progressMappings = new ProgressMapping[0];
public AdvancementsPacket() {}
public AdvancementsPacket() {
}
@Override
public void write(@NotNull BinaryWriter writer) {
@ -151,14 +150,14 @@ public class AdvancementsPacket implements ComponentHoldingServerPacket {
@Override
public void read(@NotNull BinaryReader reader) {
boolean hasParent = reader.readBoolean();
if(hasParent) {
if (hasParent) {
parentIdentifier = reader.readSizedString(Integer.MAX_VALUE);
} else {
parentIdentifier = null;
}
boolean hasDisplay = reader.readBoolean();
if(hasDisplay) {
if (hasDisplay) {
displayData = new DisplayData();
displayData.read(reader);
} else {
@ -179,7 +178,7 @@ public class AdvancementsPacket implements ComponentHoldingServerPacket {
public static class DisplayData implements Writeable, Readable {
public Component title = Component.empty(); // Only text
public Component description = Component.empty(); // Only text
public ItemStack icon = ItemStack.getAirItem();
public ItemStack icon = ItemStack.AIR;
public FrameType frameType = FrameType.TASK;
public int flags;
public String backgroundTexture = "";
@ -207,7 +206,7 @@ public class AdvancementsPacket implements ComponentHoldingServerPacket {
icon = reader.readItemStack();
frameType = FrameType.values()[reader.readVarInt()];
flags = reader.readInt();
if((flags & 0x1) != 0) {
if ((flags & 0x1) != 0) {
backgroundTexture = reader.readSizedString(Integer.MAX_VALUE);
} else {
backgroundTexture = null;
@ -304,7 +303,7 @@ public class AdvancementsPacket implements ComponentHoldingServerPacket {
@Override
public void read(@NotNull BinaryReader reader) {
achieved = reader.readBoolean();
if(achieved) {
if (achieved) {
dateOfAchieving = reader.readLong();
}
}

View File

@ -14,7 +14,8 @@ public class DeclareRecipesPacket implements ServerPacket {
public DeclaredRecipe[] recipes = new DeclaredRecipe[0];
public DeclareRecipesPacket() {}
public DeclareRecipesPacket() {
}
@Override
public void write(@NotNull BinaryWriter writer) {
@ -68,7 +69,7 @@ public class DeclareRecipesPacket implements ServerPacket {
break;
default:
throw new UnsupportedOperationException("Unrecognized type: "+type+" (id is "+id+")");
throw new UnsupportedOperationException("Unrecognized type: " + type + " (id is " + id + ")");
}
}
}
@ -193,7 +194,7 @@ public class DeclareRecipesPacket implements ServerPacket {
width = reader.readVarInt();
height = reader.readVarInt();
group = reader.readSizedString(Integer.MAX_VALUE);
ingredients = new Ingredient[width*height];
ingredients = new Ingredient[width * height];
for (int i = 0; i < width * height; i++) {
ingredients[i] = new Ingredient();
ingredients[i].read(reader);
@ -442,7 +443,7 @@ public class DeclareRecipesPacket implements ServerPacket {
public void read(@NotNull BinaryReader reader) {
group = reader.readSizedString(Integer.MAX_VALUE);
ingredient = new Ingredient();
ingredient.read( reader);
ingredient.read(reader);
result = reader.readItemStack();
}
}

View File

@ -17,7 +17,8 @@ public class EntityEquipmentPacket implements ServerPacket {
public Slot[] slots;
public ItemStack[] itemStacks;
public EntityEquipmentPacket() {}
public EntityEquipmentPacket() {
}
@Override
public void write(@NotNull BinaryWriter writer) {
@ -53,7 +54,7 @@ public class EntityEquipmentPacket implements ServerPacket {
boolean hasRemaining = true;
List<Slot> slots = new LinkedList<>();
List<ItemStack> stacks = new LinkedList<>();
while(hasRemaining) {
while (hasRemaining) {
byte slotEnum = reader.readByte();
hasRemaining = (slotEnum & 0x80) == 0x80;

View File

@ -14,7 +14,7 @@ public class SetSlotPacket implements ServerPacket {
public ItemStack itemStack;
public SetSlotPacket() {
itemStack = ItemStack.getAirItem();
itemStack = ItemStack.AIR;
}
@Override

View File

@ -96,7 +96,7 @@ public class TradeListPacket implements ServerPacket {
result = reader.readItemStack();
boolean hasSecondItem = reader.readBoolean();
if(hasSecondItem) {
if (hasSecondItem) {
inputItem2 = reader.readItemStack();
} else {
inputItem2 = null;

View File

@ -17,11 +17,11 @@ public abstract class ShapedRecipe extends Recipe {
private ItemStack result;
protected ShapedRecipe(@NotNull String recipeId,
int width,
int height,
@NotNull String group,
@Nullable List<DeclareRecipesPacket.Ingredient> ingredients,
@NotNull ItemStack result) {
int width,
int height,
@NotNull String group,
@Nullable List<DeclareRecipesPacket.Ingredient> ingredients,
@NotNull ItemStack result) {
super(RecipeType.SHAPED, recipeId);
this.width = width;
this.height = height;

View File

@ -9,18 +9,16 @@ import net.minestom.server.adventure.AdventureSerializer;
import net.minestom.server.attribute.Attribute;
import net.minestom.server.attribute.AttributeOperation;
import net.minestom.server.data.Data;
import net.minestom.server.data.DataType;
import net.minestom.server.inventory.Inventory;
import net.minestom.server.item.Enchantment;
import net.minestom.server.item.ItemMeta;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.item.attribute.AttributeSlot;
import net.minestom.server.item.attribute.ItemAttribute;
import net.minestom.server.item.metadata.ItemMeta;
import net.minestom.server.registry.Registries;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -30,7 +28,10 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.StringReader;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
// for lack of a better name
public final class NBTUtils {
@ -48,6 +49,7 @@ public final class NBTUtils {
/**
* Turns an {@link NBTCompound} into an Adventure {@link BinaryTagHolder}.
*
* @param tag the tag, if any
* @return the binary tag holder, or {@code null} if the tag was null
*/
@ -73,7 +75,7 @@ public final class NBTUtils {
if (item == Material.AIR) {
item = Material.STONE;
}
ItemStack stack = new ItemStack(item, tag.getByte("Count"));
ItemStack stack = ItemStack.of(item, tag.getByte("Count"));
if (tag.containsKey("tag")) {
loadDataIntoItem(stack, tag.getCompound("tag"));
}
@ -86,12 +88,11 @@ public final class NBTUtils {
final ItemStack stack = inventory.getItemStack(i);
NBTCompound nbt = new NBTCompound();
NBTCompound tag = new NBTCompound();
saveDataIntoNBT(stack, tag);
NBTCompound tag = metaToNBT(stack.getMeta());
nbt.set("tag", tag);
nbt.setByte("Slot", (byte) i);
nbt.setByte("Count", stack.getAmount());
nbt.setByte("Count", (byte) stack.getAmount());
nbt.setString("id", stack.getMaterial().getName());
list.add(nbt);
@ -113,23 +114,23 @@ public final class NBTUtils {
nbt.set(listName, enchantList);
}
@Nullable
@NotNull
public static ItemStack readItemStack(@NotNull BinaryReader reader) {
final boolean present = reader.readBoolean();
if (!present) {
return ItemStack.getAirItem();
return ItemStack.AIR;
}
final int id = reader.readVarInt();
if (id == -1) {
// Drop mode
return ItemStack.getAirItem();
return ItemStack.AIR;
}
final Material material = Material.fromId((short) id);
final byte count = reader.readByte();
ItemStack item = new ItemStack(material, count);
ItemStack item = ItemStack.of(material, count);
try {
final NBT itemNBT = reader.readTag();
@ -146,7 +147,7 @@ public final class NBTUtils {
@SuppressWarnings("ConstantConditions")
public static void loadDataIntoItem(@NotNull ItemStack item, @NotNull NBTCompound nbt) {
if (nbt.containsKey("Damage")) item.setDamage(nbt.getInt("Damage"));
/*if (nbt.containsKey("Damage")) item.setDamage(nbt.getInt("Damage"));
if (nbt.containsKey("Unbreakable")) item.setUnbreakable(nbt.getAsByte("Unbreakable") == 1);
if (nbt.containsKey("HideFlags")) item.setHideFlag(nbt.getInt("HideFlags"));
if (nbt.containsKey("display")) {
@ -257,7 +258,7 @@ public final class NBTUtils {
NBTList<NBTString> canPlaceOn = nbt.getList("CanDestroy");
canPlaceOn.forEach(x -> item.getCanDestroy().add(x.getValue()));
}
}
}*/
}
public static void loadEnchantments(NBTList<NBTCompound> enchantments, EnchantmentSetter setter) {
@ -273,85 +274,74 @@ public final class NBTUtils {
}
}
public static void writeItemStack(BinaryWriter packet, ItemStack itemStack) {
if (itemStack == null || itemStack.isAir()) {
public static void writeItemStack(BinaryWriter packet, @NotNull ItemStack itemStack) {
if (itemStack.isAir()) {
packet.writeBoolean(false);
} else {
packet.writeBoolean(true);
packet.writeVarInt(itemStack.getMaterial().getId());
packet.writeByte(itemStack.getAmount());
packet.writeByte((byte) itemStack.getAmount());
if (!itemStack.hasNbtTag()) {
packet.writeByte((byte) NBTTypes.TAG_End); // No nbt
return;
}
NBTCompound itemNBT = new NBTCompound();
// Vanilla compound
saveDataIntoNBT(itemStack, itemNBT);
// End custom model data
packet.writeNBT("", itemNBT);
packet.writeNBT("", itemStack.getMeta().toNBT());
}
}
public static void saveDataIntoNBT(@NotNull ItemStack itemStack, @NotNull NBTCompound itemNBT) {
public static NBTCompound metaToNBT(@NotNull ItemMeta itemMeta) {
final NBTCompound itemNBT = new NBTCompound();
// Unbreakable
if (itemStack.isUnbreakable()) {
if (itemMeta.isUnbreakable()) {
itemNBT.setInt("Unbreakable", 1);
}
// Start damage
// Damage
{
final int damage = itemStack.getDamage();
final int damage = itemMeta.getDamage();
if (damage > 0) {
itemNBT.setInt("Damage", damage);
}
}
// End damage
// Display
final boolean hasDisplayName = itemStack.hasDisplayName();
final boolean hasLore = itemStack.hasLore();
if (hasDisplayName || hasLore) {
NBTCompound displayNBT = new NBTCompound();
if (hasDisplayName) {
final String name = AdventureSerializer.serialize(itemStack.getDisplayName());
displayNBT.setString("Name", name);
}
if (hasLore) {
final List<Component> lore = itemStack.getLore();
final NBTList<NBTString> loreNBT = new NBTList<>(NBTTypes.TAG_String);
for (Component line : lore) {
loreNBT.add(new NBTString(GsonComponentSerializer.gson().serialize(line)));
}
displayNBT.set("Lore", loreNBT);
}
itemNBT.set("display", displayNBT);
}
// End display
// Start enchantment
{
final Map<Enchantment, Short> enchantmentMap = itemStack.getEnchantmentMap();
if (!enchantmentMap.isEmpty()) {
writeEnchant(itemNBT, "Enchantments", enchantmentMap);
final var displayName = itemMeta.getDisplayName();
final var lore = itemMeta.getLore();
final boolean hasDisplayName = displayName != null;
final boolean hasLore = !lore.isEmpty();
if (hasDisplayName || hasLore) {
NBTCompound displayNBT = new NBTCompound();
if (hasDisplayName) {
final String name = AdventureSerializer.serialize(displayName);
displayNBT.setString("Name", name);
}
if (hasLore) {
final NBTList<NBTString> loreNBT = new NBTList<>(NBTTypes.TAG_String);
for (Component line : lore) {
loreNBT.add(new NBTString(GsonComponentSerializer.gson().serialize(line)));
}
displayNBT.set("Lore", loreNBT);
}
itemNBT.set("display", displayNBT);
}
}
// Enchantment
{
final var enchantmentMap = itemMeta.getEnchantmentMap();
if (!enchantmentMap.isEmpty()) {
NBTUtils.writeEnchant(itemNBT, "Enchantments", enchantmentMap);
}
}
// End enchantment
// Start attribute
{
final List<ItemAttribute> itemAttributes = itemStack.getAttributes();
if (!itemAttributes.isEmpty()) {
final var attributes = itemMeta.getAttributes();
if (!attributes.isEmpty()) {
NBTList<NBTCompound> attributesNBT = new NBTList<>(NBTTypes.TAG_Compound);
for (ItemAttribute itemAttribute : itemAttributes) {
for (ItemAttribute itemAttribute : attributes) {
final UUID uuid = itemAttribute.getUuid();
attributesNBT.add(
new NBTCompound()
@ -370,7 +360,7 @@ public final class NBTUtils {
// Start hide flags
{
final int hideFlag = itemStack.getHideFlag();
final int hideFlag = itemMeta.getHideFlag();
if (hideFlag != 0) {
itemNBT.setInt("HideFlags", hideFlag);
}
@ -379,135 +369,14 @@ public final class NBTUtils {
// Start custom model data
{
final int customModelData = itemStack.getCustomModelData();
final int customModelData = itemMeta.getCustomModelData();
if (customModelData != 0) {
itemNBT.setInt("CustomModelData", customModelData);
}
}
// End custom model data
// Start custom meta
{
final ItemMeta itemMeta = itemStack.getItemMeta();
if (itemMeta != null) {
itemMeta.write(itemNBT);
}
}
// End custom meta
// Start ownership
{
final Data data = itemStack.getData();
if (data != null && !data.isEmpty()) {
final UUID identifier = itemStack.getIdentifier();
itemNBT.setString(ItemStack.OWNERSHIP_DATA_KEY, identifier.toString());
}
}
// End ownership
//CanDestroy
{
Set<String> canDestroy = itemStack.getCanDestroy();
if (canDestroy.size() > 0) {
NBTList<NBTString> list = new NBTList<>(NBTTypes.TAG_String);
canDestroy.forEach(x -> list.add(new NBTString(x)));
itemNBT.set("CanDestroy", list);
}
}
//CanDestroy
{
Set<String> canPlaceOn = itemStack.getCanPlaceOn();
if (canPlaceOn.size() > 0) {
NBTList<NBTString> list = new NBTList<>(NBTTypes.TAG_String);
canPlaceOn.forEach(x -> list.add(new NBTString(x)));
itemNBT.set("CanPlaceOn", list);
}
}
}
/**
* Converts an object into its {@link NBT} equivalent.
* <p>
* If {@code type} is not a primitive type or primitive array and {@code supportDataType} is true,
* the data will be encoded with the appropriate {@link DataType} into a byte array.
*
* @param value the value to convert
* @param type the type of the value, used to know which {@link DataType} to use if {@code value} is not a primitive type
* @param supportDataType true to allow using a {@link DataType} to encode {@code value} into a byte array if not a primitive type
* @return the converted value, null if {@code type} is not a primitive type and {@code supportDataType} is false
*/
@Nullable
public static NBT toNBT(@NotNull Object value, @NotNull Class type, boolean supportDataType) {
type = PrimitiveConversion.getObjectClass(type);
if (type.equals(Boolean.class)) {
// No boolean type in NBT
return new NBTByte((byte) (((boolean) value) ? 1 : 0));
} else if (type.equals(Byte.class)) {
return new NBTByte((byte) value);
} else if (type.equals(Character.class)) {
// No char type in NBT
return new NBTShort((short) value);
} else if (type.equals(Short.class)) {
return new NBTShort((short) value);
} else if (type.equals(Integer.class)) {
return new NBTInt((int) value);
} else if (type.equals(Long.class)) {
return new NBTLong((long) value);
} else if (type.equals(Float.class)) {
return new NBTFloat((float) value);
} else if (type.equals(Double.class)) {
return new NBTDouble((double) value);
} else if (type.equals(String.class)) {
return new NBTString((String) value);
} else if (type.equals(Byte[].class)) {
return new NBTByteArray((byte[]) value);
} else if (type.equals(Integer[].class)) {
return new NBTIntArray((int[]) value);
} else if (type.equals(Long[].class)) {
return new NBTLongArray((long[]) value);
} else {
if (supportDataType) {
// Custom NBT type, try to encode using the data manager
DataType dataType = MinecraftServer.getDataManager().getDataType(type);
Check.notNull(dataType, "The type '" + type + "' is not registered in DataManager and not a primitive type.");
BinaryWriter writer = new BinaryWriter();
dataType.encode(writer, value);
final byte[] encodedValue = writer.toByteArray();
return new NBTByteArray(encodedValue);
} else {
return null;
}
}
}
/**
* Converts a nbt object to its raw value.
* <p>
* Currently support number, string, byte/int/long array.
*
* @param nbt the nbt tag to convert
* @return the value representation of a tag
* @throws UnsupportedOperationException if the tag type is not supported
*/
@NotNull
public static Object fromNBT(@NotNull NBT nbt) {
if (nbt instanceof NBTNumber) {
return ((NBTNumber) nbt).getValue();
} else if (nbt instanceof NBTString) {
return ((NBTString) nbt).getValue();
} else if (nbt instanceof NBTByteArray) {
return ((NBTByteArray) nbt).getValue();
} else if (nbt instanceof NBTIntArray) {
return ((NBTIntArray) nbt).getValue();
} else if (nbt instanceof NBTLongArray) {
return ((NBTLongArray) nbt).getValue();
}
throw new UnsupportedOperationException("NBT type " + nbt.getClass() + " is not handled properly.");
return itemNBT;
}
@FunctionalInterface

View File

@ -20,7 +20,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
/**
@ -197,6 +196,7 @@ public class BinaryReader extends InputStream {
/**
* Creates a new object from the given supplier and calls its {@link Readable#read(BinaryReader)} method with this reader
*
* @param supplier supplier to create new instances of your object
* @param <T>
* @return the read object
@ -210,6 +210,7 @@ public class BinaryReader extends InputStream {
/**
* Reads the length of the array to read as a varint, creates the array to contain the readable objects and call
* their respective {@link Readable#read(BinaryReader)} methods.
*
* @param supplier supplier to create new instances of your object
* @param <T>
* @return the read objects
@ -245,13 +246,14 @@ public class BinaryReader extends InputStream {
* Records the current position, runs the given Runnable, and then returns the bytes between the position before
* running the runnable and the position after.
* Can be used to extract a subsection of this reader's buffer with complex data
*
* @param extractor the extraction code, simply call the reader's read* methods here.
*/
public byte[] extractBytes(Runnable extractor) {
int startingPosition = getBuffer().readerIndex();
extractor.run();
int endingPosition = getBuffer().readerIndex();
byte[] output = new byte[endingPosition-startingPosition];
byte[] output = new byte[endingPosition - startingPosition];
getBuffer().getBytes(startingPosition, output);
return output;
}

View File

@ -180,6 +180,7 @@ public class BinaryWriter extends OutputStream {
/**
* Writes a JsonMessage to the buffer.
* Simply a writeSizedString with message.toString()
*
* @param message
*/
public void writeJsonMessage(JsonMessage message) {
@ -277,6 +278,7 @@ public class BinaryWriter extends OutputStream {
/**
* Writes the given writeable object into this writer.
*
* @param writeable the object to write
*/
public void write(Writeable writeable) {
@ -286,11 +288,12 @@ public class BinaryWriter extends OutputStream {
/**
* Writes an array of writeable objects to this writer. Will prepend the binary stream with a var int to denote the
* length of the array.
*
* @param writeables the array of writeables to write
*/
public void writeArray(Writeable[] writeables) {
writeVarInt(writeables.length);
for(Writeable w : writeables) {
for (Writeable w : writeables) {
write(w);
}
}

View File

@ -100,7 +100,7 @@ public class BiomeParticles {
@Override
public NBTCompound toNbt() {
//todo test count might be wrong type
NBTCompound nbtCompound = item.toNBT();
NBTCompound nbtCompound = item.getMeta().toNBT();
nbtCompound.setString("type", type);
return nbtCompound;
}

View File

@ -27,7 +27,6 @@ import net.minestom.server.inventory.Inventory;
import net.minestom.server.inventory.InventoryType;
import net.minestom.server.inventory.PlayerInventory;
import net.minestom.server.item.Enchantment;
import net.minestom.server.item.Item;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.item.meta.CompassMeta;
@ -35,7 +34,6 @@ import net.minestom.server.network.ConnectionManager;
import net.minestom.server.ping.ResponseDataConsumer;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.Vector;
import net.minestom.server.utils.inventory.PlayerInventoryUtils;
import net.minestom.server.utils.time.TimeUnit;
import net.minestom.server.world.DimensionType;
@ -73,7 +71,7 @@ public class PlayerInit {
.enchantments(Map.of(Enchantment.KNOCKBACK, (short) 5, Enchantment.EFFICIENCY, (short) 10))
.build();
Item item = Item.builder(Material.COMPASS)
ItemStack itemStack = ItemStack.builder(Material.COMPASS)
.amount(5)
.meta(compassMeta)
.meta(CompassMeta.class, builder -> {
@ -82,7 +80,7 @@ public class PlayerInit {
.displayName(Component.text("displayName"))
.build();
item = item.with(itemBuilder -> itemBuilder
itemStack = itemStack.with(itemBuilder -> itemBuilder
.amount(10)
.meta(CompassMeta.class, builder -> {
builder.lodestonePosition(new Position(5, 0, 0));
@ -224,21 +222,19 @@ public class PlayerInit {
globalEventHandler.addEventCallback(PlayerSpawnEvent.class, event -> {
final Player player = event.getPlayer();
player.setGameMode(GameMode.CREATIVE);
player.setGameMode(GameMode.SURVIVAL);
player.setPermissionLevel(4);
PlayerInventory inventory = player.getInventory();
ItemStack itemStack = new ItemStack(Material.STONE, (byte) 64);
ItemStack itemStack = ItemStack.of(Material.STONE, 64);
inventory.addItemStack(itemStack);
{
ItemStack item = new ItemStack(Material.DIAMOND_CHESTPLATE, (byte) 1);
ItemStack item = ItemStack.builder(Material.DIAMOND_CHESTPLATE)
.displayName(Component.text("test"))
.build();
inventory.setChestplate(item);
item.setDisplayName(ColoredText.of("test"));
inventory.refreshSlot((short) PlayerInventoryUtils.CHESTPLATE_SLOT);
}
//player.getInventory().addItemStack(new ItemStack(Material.STONE, (byte) 32));

View File

@ -47,13 +47,13 @@ public class ReadWritePackets {
private <T extends Readable & Writeable> Collection<DynamicTest> checkImplementationPresence(Class<T> packetClass) throws IOException {
ClassPath cp = ClassPath.from(ClassLoader.getSystemClassLoader());
List<DynamicTest> allTests = new LinkedList<>();
for(ClassPath.ClassInfo classInfo : cp.getAllClasses()) {
if(!classInfo.getPackageName().startsWith("net.minestom.server.network.packet"))
for (ClassPath.ClassInfo classInfo : cp.getAllClasses()) {
if (!classInfo.getPackageName().startsWith("net.minestom.server.network.packet"))
continue;
try {
Class<?> clazz = classInfo.load();
if(packetClass.isAssignableFrom(clazz) && !clazz.isInterface() && ((clazz.getModifiers() & Modifier.ABSTRACT) != Modifier.ABSTRACT)) {
allTests.add(DynamicTest.dynamicTest("WriteThenRead "+clazz.getSimpleName(), () -> {
if (packetClass.isAssignableFrom(clazz) && !clazz.isInterface() && ((clazz.getModifiers() & Modifier.ABSTRACT) != Modifier.ABSTRACT)) {
allTests.add(DynamicTest.dynamicTest("WriteThenRead " + clazz.getSimpleName(), () -> {
// required for managers to be loaded
MinecraftServer.init();
@ -63,14 +63,13 @@ public class ReadWritePackets {
T packet;
// exceptions
if(clazz.getSimpleName().equals("EntityEquipmentPacket")) {
if (clazz.getSimpleName().equals("EntityEquipmentPacket")) {
// requires at least one slot and one item
EntityEquipmentPacket p = new EntityEquipmentPacket();
p.itemStacks = new ItemStack[] { ItemStack.getAirItem() };
p.slots = new EntityEquipmentPacket.Slot[] { EntityEquipmentPacket.Slot.MAIN_HAND };
p.itemStacks = new ItemStack[]{ItemStack.AIR};
p.slots = new EntityEquipmentPacket.Slot[]{EntityEquipmentPacket.Slot.MAIN_HAND};
packet = (T) p;
}
else {
} else {
packet = (T) constructor.newInstance();
}