Added item attributes

This commit is contained in:
Felix Cravic 2020-05-28 23:43:12 +02:00
parent 068a0889c8
commit 619c680f1b
7 changed files with 219 additions and 8 deletions

View File

@ -37,4 +37,12 @@ public enum Attribute {
public float getMaxVanillaValue() {
return maxVanillaValue;
}
public static Attribute fromKey(String key) {
for (Attribute attribute : values()) {
if (attribute.getKey().equals(key))
return attribute;
}
return null;
}
}

View File

@ -2,6 +2,7 @@ package net.minestom.server.item;
import net.minestom.server.data.Data;
import net.minestom.server.data.DataContainer;
import net.minestom.server.item.attribute.ItemAttribute;
import net.minestom.server.item.rule.VanillaStackingRule;
import net.minestom.server.potion.PotionType;
import net.minestom.server.utils.validate.Check;
@ -19,7 +20,6 @@ public class ItemStack implements DataContainer {
private static StackingRule defaultStackingRule;
private short materialId;
private Set<PotionType> potionTypes;
private byte amount;
private short damage;
@ -29,6 +29,8 @@ public class ItemStack implements DataContainer {
private ArrayList<String> lore;
private Map<Enchantment, Short> enchantmentMap;
private List<ItemAttribute> attributes;
private Set<PotionType> potionTypes;
{
if (defaultStackingRule == null)
@ -47,6 +49,7 @@ public class ItemStack implements DataContainer {
this.lore = new ArrayList<>();
this.enchantmentMap = new HashMap<>();
this.attributes = new ArrayList<>();
this.potionTypes = new HashSet<>();
this.stackingRule = defaultStackingRule;
@ -150,6 +153,14 @@ public class ItemStack implements DataContainer {
return this.enchantmentMap.getOrDefault(enchantment, (short) 0);
}
public List<ItemAttribute> getAttributes() {
return Collections.unmodifiableList(attributes);
}
public void addAttribute(ItemAttribute itemAttribute) {
this.attributes.add(itemAttribute);
}
public Set<PotionType> getPotionTypes() {
return Collections.unmodifiableSet(potionTypes);
}
@ -200,7 +211,8 @@ public class ItemStack implements DataContainer {
}
public boolean hasNbtTag() {
return hasDisplayName() || hasLore() || isUnbreakable() || !getEnchantmentMap().isEmpty() || !potionTypes.isEmpty();
return hasDisplayName() || hasLore() || isUnbreakable() ||
!getEnchantmentMap().isEmpty() || !attributes.isEmpty() || !potionTypes.isEmpty();
}
public ItemStack clone() {

View File

@ -0,0 +1,26 @@
package net.minestom.server.item.attribute;
public enum AttributeOperation {
ADDITION(0),
MULTIPLY_BASE(1),
MULTIPLY_TOTAL(2);
private static final AttributeOperation[] VALUES = new AttributeOperation[]{ADDITION, MULTIPLY_BASE, MULTIPLY_TOTAL};
private final int id;
AttributeOperation(int id) {
this.id = id;
}
public static AttributeOperation byId(int id) {
if (id >= 0 && id < VALUES.length) {
return VALUES[id];
} else {
throw new IllegalArgumentException("No operation with value " + id);
}
}
public int getId() {
return this.id;
}
}

View File

@ -0,0 +1,10 @@
package net.minestom.server.item.attribute;
public enum AttributeSlot {
MAINHAND,
OFFHAND,
FEET,
LEGS,
CHEST,
HEAD
}

View File

@ -0,0 +1,48 @@
package net.minestom.server.item.attribute;
import net.minestom.server.entity.property.Attribute;
import java.util.UUID;
public class ItemAttribute {
private UUID uuid;
private String internalName;
private Attribute attribute;
private AttributeOperation operation;
private double value;
private AttributeSlot slot;
public ItemAttribute(UUID uuid, String internalName, Attribute attribute, AttributeOperation operation, double value, AttributeSlot slot) {
this.uuid = uuid;
this.internalName = internalName;
this.attribute = attribute;
this.operation = operation;
this.value = value;
this.slot = slot;
}
public UUID getUuid() {
return uuid;
}
public String getInternalName() {
return internalName;
}
public Attribute getAttribute() {
return attribute;
}
public AttributeOperation getOperation() {
return operation;
}
public double getValue() {
return value;
}
public AttributeSlot getSlot() {
return slot;
}
}

View File

@ -5,15 +5,14 @@ import net.minestom.server.chat.Chat;
import net.minestom.server.instance.Chunk;
import net.minestom.server.item.Enchantment;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.attribute.ItemAttribute;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.potion.PotionType;
import net.minestom.server.utils.buffer.BufferWrapper;
import net.minestom.server.utils.item.NbtReaderUtils;
import java.util.ArrayList;
import java.util.Map;
import java.util.Set;
import java.util.*;
public class Utils {
@ -184,6 +183,52 @@ public class Utils {
}
// End enchantment
// Start attribute
{
List<ItemAttribute> itemAttributes = itemStack.getAttributes();
if (!itemAttributes.isEmpty()) {
packet.writeByte((byte) 0x09); // Type id (list)
packet.writeShortSizedString("AttributeModifiers");
packet.writeByte((byte) 0x0A); // Compound
packet.writeInt(itemAttributes.size());
for (ItemAttribute itemAttribute : itemAttributes) {
UUID uuid = itemAttribute.getUuid();
packet.writeByte((byte) 0x04); // Type id (long)
packet.writeShortSizedString("UUIDMost");
packet.writeLong(uuid.getMostSignificantBits());
packet.writeByte((byte) 0x04); // Type id (long)
packet.writeShortSizedString("UUIDLeast");
packet.writeLong(uuid.getLeastSignificantBits());
packet.writeByte((byte) 0x06); // Type id (double)
packet.writeShortSizedString("Amount");
packet.writeDouble(itemAttribute.getValue());
packet.writeByte((byte) 0x08); // Type id (string)
packet.writeShortSizedString("Slot");
packet.writeShortSizedString(itemAttribute.getSlot().name().toLowerCase());
packet.writeByte((byte) 0x08); // Type id (string)
packet.writeShortSizedString("AttributeName");
packet.writeShortSizedString(itemAttribute.getAttribute().getKey());
packet.writeByte((byte) 0x03); // Type id (int)
packet.writeShortSizedString("Operation");
packet.writeInt(itemAttribute.getOperation().getId());
packet.writeByte((byte) 0x08); // Type id (string)
packet.writeShortSizedString("Name");
packet.writeShortSizedString(itemAttribute.getInternalName());
}
packet.writeByte((byte) 0x00); // End compound
}
}
// End attribute
// Start potion
{
Set<PotionType> potionTypes = itemStack.getPotionTypes();

View File

@ -2,12 +2,17 @@ package net.minestom.server.utils.item;
import net.kyori.text.Component;
import net.minestom.server.chat.Chat;
import net.minestom.server.entity.property.Attribute;
import net.minestom.server.item.Enchantment;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.attribute.AttributeOperation;
import net.minestom.server.item.attribute.AttributeSlot;
import net.minestom.server.item.attribute.ItemAttribute;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.potion.PotionType;
import java.util.ArrayList;
import java.util.UUID;
public class NbtReaderUtils {
@ -15,7 +20,7 @@ public class NbtReaderUtils {
byte typeId = reader.readByte();
//System.out.println("DEBUG TYPE: " + typeId);
System.out.println("DEBUG TYPE: " + typeId);
switch (typeId) {
case 0x00: // TAG_End
// End of item NBT
@ -82,9 +87,9 @@ public class NbtReaderUtils {
if (listName.equals("StoredEnchantments")) {
reader.readByte(); // Should be a compound (0x0A)
int size = reader.readInteger(); // Enchants count
int size = reader.readInteger(); // Enchantments count
for (int ench = 0; ench < size; ench++) {
for (int i = 0; i < size; i++) {
reader.readByte(); // Type id (short)
reader.readShortSizedString(); // Constant "lvl"
short lvl = reader.readShort();
@ -102,6 +107,63 @@ public class NbtReaderUtils {
reader.readByte(); // Compound end
readItemStackNBT(reader, item);
} else if (listName.equals("AttributeModifiers")) {
reader.readByte(); // Should be a compound (0x0A);
int size = reader.readInteger(); // Attributes count
for (int i = 0; i < size; i++) {
reader.readByte(); // Type id (long)
reader.readShortSizedString(); // Constant "UUIDMost"
long uuidMost = reader.readLong();
reader.readByte(); // Type id (long)
reader.readShortSizedString(); // Constant "UUIDLeast"
long uuidLeast = reader.readLong();
final UUID uuid = new UUID(uuidMost, uuidLeast);
reader.readByte(); // Type id (double)
reader.readShortSizedString(); // Constant "Amount"
final double value = reader.readDouble();
reader.readByte(); // Type id (string)
reader.readShortSizedString(); // Constant "Slot"
final String slot = reader.readShortSizedString();
reader.readByte(); // Type id (string)
reader.readShortSizedString(); // Constant "AttributeName"
final String attributeName = reader.readShortSizedString();
reader.readByte(); // Type id (int)
reader.readShortSizedString(); // Constant "Operation"
final int operation = reader.readInteger();
reader.readByte(); // Type id (string)
reader.readShortSizedString(); // Constant "Name"
final String name = reader.readShortSizedString();
final Attribute attribute = Attribute.fromKey(attributeName);
// Wrong attribute name, stop here
if (attribute == null)
break;
final AttributeOperation attributeOperation = AttributeOperation.byId(operation);
// Wrong attribute operation, stop here
if (attributeOperation == null)
break;
final AttributeSlot attributeSlot = AttributeSlot.valueOf(slot.toUpperCase());
// Wrong attribute slot, stop here
if (attributeSlot == null)
break;
// Add attribute
final ItemAttribute itemAttribute =
new ItemAttribute(uuid, name, attribute, attributeOperation, value, attributeSlot);
item.addAttribute(itemAttribute);
}
reader.readByte(); // Compound end
readItemStackNBT(reader, item);
}