mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-24 09:01:54 +01:00
WIP Item rework implementation
This commit is contained in:
parent
a70870d261
commit
a128d30b6b
@ -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":
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
NBTCompound compound = itemStack.getMeta().toNBT();
|
||||
obj.add("tag", new JsonPrimitive(compound.toSNBT()));
|
||||
}
|
||||
|
||||
return new ChatHoverEvent("show_item", obj);
|
||||
}
|
||||
|
@ -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("\\\"", "\"");
|
||||
|
||||
|
@ -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, () -> {
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
@ -63,7 +62,7 @@ public class Metadata {
|
||||
},
|
||||
reader -> {
|
||||
boolean present = reader.readBoolean();
|
||||
if(present) {
|
||||
if (present) {
|
||||
return reader.readJsonMessage(Integer.MAX_VALUE);
|
||||
} else {
|
||||
return null;
|
||||
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
@Contract(value = "_, -> new", pure = true)
|
||||
public @NotNull ItemStack withAmount(@NotNull IntUnaryOperator intUnaryOperator) {
|
||||
return withAmount(intUnaryOperator.applyAsInt(amount));
|
||||
}
|
||||
|
||||
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 <T extends ItemMetaBuilder, U extends ItemMetaBuilder.Provider<T>> @NotNull ItemStack withMeta(Class<U> metaType, Consumer<T> metaConsumer) {
|
||||
return builder().meta(metaType, metaConsumer).build();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Data getData() {
|
||||
return data;
|
||||
@Contract(pure = true)
|
||||
public @Nullable Component getDisplayName() {
|
||||
return meta.getDisplayName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(value = "_, -> new", pure = true)
|
||||
public @NotNull ItemStack withDisplayName(@Nullable Component displayName) {
|
||||
return builder().displayName(displayName).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the item {@link StackingRule}.
|
||||
*
|
||||
* @return the item stacking rule
|
||||
*/
|
||||
@NotNull
|
||||
public StackingRule getStackingRule() {
|
||||
@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 & 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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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},
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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,12 +168,9 @@ 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) {
|
||||
final ItemStack newUsedItem = usedItem.getStackingRule().apply(usedItem, usedItem.getAmount() - 1);
|
||||
playerInventory.setItemInHand(hand, newUsedItem);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
refreshChunk = true;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -14,7 +14,7 @@ public class SetSlotPacket implements ServerPacket {
|
||||
public ItemStack itemStack;
|
||||
|
||||
public SetSlotPacket() {
|
||||
itemStack = ItemStack.getAirItem();
|
||||
itemStack = ItemStack.AIR;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -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;
|
||||
|
@ -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,58 +274,48 @@ 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();
|
||||
|
||||
{
|
||||
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(itemStack.getDisplayName());
|
||||
final String name = AdventureSerializer.serialize(displayName);
|
||||
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)));
|
||||
@ -334,24 +325,23 @@ public final class NBTUtils {
|
||||
|
||||
itemNBT.set("display", displayNBT);
|
||||
}
|
||||
// End display
|
||||
}
|
||||
|
||||
// Start enchantment
|
||||
// Enchantment
|
||||
{
|
||||
final Map<Enchantment, Short> enchantmentMap = itemStack.getEnchantmentMap();
|
||||
final var enchantmentMap = itemMeta.getEnchantmentMap();
|
||||
if (!enchantmentMap.isEmpty()) {
|
||||
writeEnchant(itemNBT, "Enchantments", enchantmentMap);
|
||||
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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user