Handle nbt directly inside builders instead of lazily

This commit is contained in:
TheMode 2021-04-09 23:57:05 +02:00
parent 4f5fd125c4
commit d6e7c9a635
7 changed files with 150 additions and 180 deletions

View File

@ -2,7 +2,6 @@ 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;
@ -11,7 +10,6 @@ import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
public class ItemMeta {
@ -40,13 +38,8 @@ public class ItemMeta {
this.attributes = Collections.unmodifiableList(metaBuilder.attributes);
this.customModelData = metaBuilder.customModelData;
// nbt
{
this.nbt = Objects.requireNonNullElseGet(metaBuilder.originalNBT, NBTCompound::new);
NBTUtils.writeMetaNBT(this, nbt);
this.emptyBuilder = metaBuilder.getSupplier().get();
}
this.nbt = metaBuilder.nbt;
this.emptyBuilder = metaBuilder.getSupplier().get();
}
@Contract(value = "_, -> new", pure = true)

View File

@ -1,18 +1,24 @@
package net.minestom.server.item;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.minestom.server.adventure.AdventureSerializer;
import net.minestom.server.item.attribute.ItemAttribute;
import net.minestom.server.utils.NBTUtils;
import net.minestom.server.utils.Utils;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.*;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Supplier;
public abstract class ItemMetaBuilder {
protected NBTCompound nbt = new NBTCompound();
protected int damage;
protected boolean unbreakable;
protected int hideFlag;
@ -22,23 +28,24 @@ public abstract class ItemMetaBuilder {
protected List<ItemAttribute> attributes = new ArrayList<>();
protected int customModelData;
protected NBTCompound originalNBT;
@Contract("_ -> this")
public @NotNull ItemMetaBuilder damage(int damage) {
this.damage = damage;
this.nbt.setInt("Damage", damage);
return this;
}
@Contract("_ -> this")
public @NotNull ItemMetaBuilder unbreakable(boolean unbreakable) {
this.unbreakable = unbreakable;
this.nbt.setByte("Unbreakable", (byte) (unbreakable ? 1 : 0));
return this;
}
@Contract("_ -> this")
public @NotNull ItemMetaBuilder hideFlag(int hideFlag) {
this.hideFlag = hideFlag;
this.nbt.setInt("HideFlags", hideFlag);
return this;
}
@ -54,12 +61,31 @@ public abstract class ItemMetaBuilder {
@Contract("_ -> this")
public @NotNull ItemMetaBuilder displayName(@Nullable Component displayName) {
this.displayName = displayName;
handleCompound("display", nbtCompound -> {
if (displayName != null) {
final String name = AdventureSerializer.serialize(displayName);
nbtCompound.setString("Name", name);
} else {
nbtCompound.removeTag("Name");
}
});
return this;
}
@Contract("_ -> this")
public @NotNull ItemMetaBuilder lore(@NotNull List<@NotNull Component> lore) {
this.lore = lore;
handleCompound("display", nbtCompound -> {
final NBTList<NBTString> loreNBT = new NBTList<>(NBTTypes.TAG_String);
for (Component line : lore) {
loreNBT.add(new NBTString(GsonComponentSerializer.gson().serialize(line)));
}
nbtCompound.set("Lore", loreNBT);
});
return this;
}
@ -71,13 +97,21 @@ public abstract class ItemMetaBuilder {
@Contract("_ -> this")
public @NotNull ItemMetaBuilder enchantments(@NotNull Map<Enchantment, Short> enchantments) {
this.enchantmentMap.putAll(enchantments);
this.enchantmentMap = enchantments;
if (!enchantmentMap.isEmpty()) {
NBTUtils.writeEnchant(nbt, "Enchantments", enchantmentMap);
} else {
this.nbt.removeTag("Enchantments");
}
return this;
}
@Contract("_, _ -> this")
public @NotNull ItemMetaBuilder enchantment(@NotNull Enchantment enchantment, short level) {
this.enchantmentMap.put(enchantment, level);
enchantments(enchantmentMap);
return this;
}
@ -90,29 +124,45 @@ public abstract class ItemMetaBuilder {
@Contract("_ -> this")
public @NotNull ItemMetaBuilder attributes(@NotNull List<@NotNull ItemAttribute> attributes) {
this.attributes = attributes;
if (!attributes.isEmpty()) {
NBTList<NBTCompound> attributesNBT = new NBTList<>(NBTTypes.TAG_Compound);
for (ItemAttribute itemAttribute : attributes) {
final UUID uuid = itemAttribute.getUuid();
attributesNBT.add(
new NBTCompound()
.setIntArray("UUID", Utils.uuidToIntArray(uuid))
.setDouble("Amount", itemAttribute.getValue())
.setString("Slot", itemAttribute.getSlot().name().toLowerCase())
.setString("AttributeName", itemAttribute.getAttribute().getKey())
.setInt("Operation", itemAttribute.getOperation().getId())
.setString("Name", itemAttribute.getInternalName())
);
}
this.nbt.set("AttributeModifiers", attributesNBT);
} else {
this.nbt.removeTag("AttributeModifiers");
}
return this;
}
@Contract("_ -> this")
public @NotNull ItemMetaBuilder customModelData(int customModelData) {
this.customModelData = customModelData;
this.nbt.setInt("CustomModelData", customModelData);
return this;
}
public <T> @NotNull ItemMetaBuilder set(@NotNull ItemTag<T> tag, @Nullable T value) {
if (originalNBT != null) {
// Item is from nbt
if (value != null) {
tag.write(originalNBT, value);
} else {
this.originalNBT.removeTag(tag.getKey());
}
return this;
if (value != null) {
tag.write(nbt, value);
} else {
// Create item meta based on nbt
var currentNbt = build().nbt();
return fromNBT(this, currentNbt).set(tag, value);
this.nbt.removeTag(tag.getKey());
}
return this;
}
@Contract("-> new")
@ -120,15 +170,38 @@ public abstract class ItemMetaBuilder {
public abstract void read(@NotNull NBTCompound nbtCompound);
public abstract void write(@NotNull NBTCompound nbtCompound);
protected abstract @NotNull Supplier<@NotNull ItemMetaBuilder> getSupplier();
protected void handleCompound(@NotNull String key,
@NotNull Consumer<@NotNull NBTCompound> consumer) {
NBTCompound compound = null;
boolean newNbt = false;
if (nbt.containsKey(key)) {
NBT dNbt = nbt.get(key);
if (dNbt instanceof NBTCompound) {
compound = (NBTCompound) dNbt;
}
} else {
compound = new NBTCompound();
newNbt = true;
}
if (compound != null) {
consumer.accept(compound);
if (newNbt && compound.getSize() > 0) {
this.nbt.set(key, compound);
} else if (!newNbt && compound.getSize() == 0) {
this.nbt.removeTag(key);
}
}
}
@Contract(value = "_, _ -> new", pure = true)
public static @NotNull ItemMetaBuilder fromNBT(@NotNull ItemMetaBuilder src, @NotNull NBTCompound nbtCompound) {
ItemMetaBuilder dest = src.getSupplier().get();
NBTUtils.loadDataIntoMeta(dest, nbtCompound);
dest.originalNBT = nbtCompound;
return dest;
}

View File

@ -45,16 +45,35 @@ public class CompassMeta extends ItemMeta implements ItemMetaBuilder.Provider<Co
public Builder lodestoneTracked(boolean lodestoneTracked) {
this.lodestoneTracked = lodestoneTracked;
this.nbt.setByte("LodestoneTracked", (byte) (lodestoneTracked ? 1 : 0));
return this;
}
public Builder lodestoneDimension(@Nullable String lodestoneDimension) {
this.lodestoneDimension = lodestoneDimension;
if (lodestoneDimension != null) {
this.nbt.setString("LodestoneDimension", lodestoneDimension);
} else {
this.nbt.removeTag("LodestoneDimension");
}
return this;
}
public Builder lodestonePosition(@Nullable Position lodestonePosition) {
this.lodestonePosition = lodestonePosition;
if (lodestonePosition != null) {
NBTCompound posCompound = new NBTCompound();
posCompound.setInt("X", (int) lodestonePosition.getX());
posCompound.setInt("Y", (int) lodestonePosition.getY());
posCompound.setInt("Z", (int) lodestonePosition.getZ());
this.nbt.set("LodestonePos", posCompound);
} else {
this.nbt.removeTag("LodestonePos");
}
return this;
}
@ -81,22 +100,6 @@ public class CompassMeta extends ItemMeta implements ItemMetaBuilder.Provider<Co
}
}
@Override
public void write(@NotNull NBTCompound nbtCompound) {
nbtCompound.setByte("LodestoneTracked", (byte) (lodestoneTracked ? 1 : 0));
if (lodestoneDimension != null) {
nbtCompound.setString("LodestoneDimension", lodestoneDimension);
}
if (lodestonePosition != null) {
NBTCompound posCompound = new NBTCompound();
posCompound.setInt("X", (int) lodestonePosition.getX());
posCompound.setInt("Y", (int) lodestonePosition.getY());
posCompound.setInt("Z", (int) lodestonePosition.getZ());
nbtCompound.set("LodestonePos", posCompound);
}
}
@Override
protected @NotNull Supplier<ItemMetaBuilder> getSupplier() {
return Builder::new;

View File

@ -90,21 +90,47 @@ public class MapMeta extends ItemMeta {
public Builder mapId(int value) {
this.mapId = value;
this.nbt.setInt("map", mapId);
return this;
}
public Builder mapScaleDirection(int value) {
this.mapScaleDirection = value;
this.nbt.setInt("map_scale_direction", value);
return this;
}
public Builder decorations(List<MapDecoration> value) {
this.decorations = value;
NBTList<NBTCompound> decorationsList = new NBTList<>(NBTTypes.TAG_Compound);
for (MapDecoration decoration : decorations) {
NBTCompound decorationCompound = new NBTCompound();
decorationCompound.setString("id", decoration.getId());
decorationCompound.setByte("type", decoration.getType());
decorationCompound.setByte("x", decoration.getX());
decorationCompound.setByte("z", decoration.getZ());
decorationCompound.setDouble("rot", decoration.getRotation());
decorationsList.add(decorationCompound);
}
this.nbt.set("Decorations", decorationsList);
return this;
}
public Builder mapColor(Color value) {
this.mapColor = value;
NBTCompound displayCompound;
if (nbt.containsKey("display")) {
displayCompound = nbt.getCompound("display");
} else {
displayCompound = new NBTCompound();
this.nbt.set("display", displayCompound);
}
displayCompound.setInt("MapColor", mapColor.asRGB());
return this;
}
@ -116,11 +142,11 @@ public class MapMeta extends ItemMeta {
@Override
public void read(@NotNull NBTCompound compound) {
if (compound.containsKey("map")) {
this.mapId = compound.getAsInt("map");
mapId(compound.getAsInt("map"));
}
if (compound.containsKey("map_scale_direction")) {
this.mapScaleDirection = compound.getAsInt("map_scale_direction");
mapScaleDirection(compound.getAsInt("map_scale_direction"));
}
if (compound.containsKey("Decorations")) {
@ -156,38 +182,6 @@ public class MapMeta extends ItemMeta {
}
}
@Override
public void write(@NotNull NBTCompound compound) {
compound.setInt("map", mapId);
compound.setInt("map_scale_direction", mapScaleDirection);
if (!decorations.isEmpty()) {
NBTList<NBTCompound> decorationsList = new NBTList<>(NBTTypes.TAG_Compound);
for (MapDecoration decoration : decorations) {
NBTCompound decorationCompound = new NBTCompound();
decorationCompound.setString("id", decoration.getId());
decorationCompound.setByte("type", decoration.getType());
decorationCompound.setByte("x", decoration.getX());
decorationCompound.setByte("z", decoration.getZ());
decorationCompound.setDouble("rot", decoration.getRotation());
decorationsList.add(decorationCompound);
}
compound.set("Decorations", decorationsList);
}
{
NBTCompound displayCompound;
if (compound.containsKey("display")) {
displayCompound = compound.getCompound("display");
} else {
displayCompound = new NBTCompound();
}
displayCompound.setInt("MapColor", mapColor.asRGB());
}
}
@Override
protected @NotNull Supplier<@NotNull ItemMetaBuilder> getSupplier() {
return Builder::new;

View File

@ -193,7 +193,7 @@ public class CrossbowMeta extends ItemMeta {
@NotNull
private NBTCompound getItemCompound(@NotNull ItemStack itemStack) {
NBTCompound compound = NBTUtils.getMetaNBT(itemStack.getMeta());
NBTCompound compound = itemStack.getMeta().nbt();
compound.setByte("Count", (byte) itemStack.getAmount());
compound.setString("id", itemStack.getMaterial().getName());
return compound;

View File

@ -5,11 +5,13 @@ import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.util.Codec;
import net.minestom.server.MinecraftServer;
import net.minestom.server.adventure.AdventureSerializer;
import net.minestom.server.attribute.Attribute;
import net.minestom.server.attribute.AttributeOperation;
import net.minestom.server.inventory.Inventory;
import net.minestom.server.item.*;
import net.minestom.server.item.Enchantment;
import net.minestom.server.item.ItemMetaBuilder;
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.registry.Registries;
@ -86,7 +88,7 @@ public final class NBTUtils {
final ItemStack stack = inventory.getItemStack(i);
NBTCompound nbt = new NBTCompound();
NBTCompound tag = getMetaNBT(stack.getMeta());
NBTCompound tag = stack.getMeta().nbt();
nbt.set("tag", tag);
nbt.setByte("Slot", (byte) i);
@ -290,103 +292,6 @@ public final class NBTUtils {
}
}
public static void writeMetaNBT(@NotNull ItemMeta itemMeta, @NotNull NBTCompound itemNBT) {
// Unbreakable
if (itemMeta.isUnbreakable()) {
itemNBT.setInt("Unbreakable", 1);
}
// Damage
{
final int damage = itemMeta.getDamage();
if (damage > 0) {
itemNBT.setInt("Damage", damage);
}
}
// Start display
{
final var displayName = itemMeta.getDisplayName();
final var lore = itemMeta.getLore();
final boolean hasDisplayName = displayName != null;
final boolean hasLore = !lore.isEmpty();
if (hasDisplayName || hasLore) {
NBTCompound displayNBT = new NBTCompound();
if (hasDisplayName) {
final String name = AdventureSerializer.serialize(displayName);
displayNBT.setString("Name", name);
}
if (hasLore) {
final NBTList<NBTString> loreNBT = new NBTList<>(NBTTypes.TAG_String);
for (Component line : lore) {
loreNBT.add(new NBTString(GsonComponentSerializer.gson().serialize(line)));
}
displayNBT.set("Lore", loreNBT);
}
itemNBT.set("display", displayNBT);
}
}
// End display
// Start enchantment
{
final var enchantmentMap = itemMeta.getEnchantmentMap();
if (!enchantmentMap.isEmpty()) {
NBTUtils.writeEnchant(itemNBT, "Enchantments", enchantmentMap);
}
}
// End enchantment
// Start attribute
{
final var attributes = itemMeta.getAttributes();
if (!attributes.isEmpty()) {
NBTList<NBTCompound> attributesNBT = new NBTList<>(NBTTypes.TAG_Compound);
for (ItemAttribute itemAttribute : attributes) {
final UUID uuid = itemAttribute.getUuid();
attributesNBT.add(
new NBTCompound()
.setIntArray("UUID", Utils.uuidToIntArray(uuid))
.setDouble("Amount", itemAttribute.getValue())
.setString("Slot", itemAttribute.getSlot().name().toLowerCase())
.setString("AttributeName", itemAttribute.getAttribute().getKey())
.setInt("Operation", itemAttribute.getOperation().getId())
.setString("Name", itemAttribute.getInternalName())
);
}
itemNBT.set("AttributeModifiers", attributesNBT);
}
}
// End attribute
// Start hide flag
{
final int hideFlag = itemMeta.getHideFlag();
if (hideFlag != 0) {
itemNBT.setInt("HideFlags", hideFlag);
}
}
// End hide flag
// Start custom model data
{
final int customModelData = itemMeta.getCustomModelData();
if (customModelData != 0) {
itemNBT.setInt("CustomModelData", customModelData);
}
}
// End custom model data
}
public static @NotNull NBTCompound getMetaNBT(@NotNull ItemMeta itemMeta) {
var nbt = new NBTCompound();
writeMetaNBT(itemMeta, nbt);
return nbt;
}
@FunctionalInterface
public interface EnchantmentSetter {
void applyEnchantment(Enchantment name, short level);

View File

@ -243,9 +243,11 @@ public class PlayerInit {
.displayName(Component.text("test"))
.lore(Component.text("lore"))
.build();
//inventory.setChestplate(item);
inventory.setChestplate(item.with(itemStackBuilder -> {
itemStackBuilder.lore(Collections.emptyList())
.displayName(null);
itemStackBuilder.lore(Collections.emptyList());
}));
}
});