mirror of
https://github.com/Minestom/Minestom.git
synced 2025-02-14 03:11:25 +01:00
feat: first version of a bunch of components
This commit is contained in:
parent
e857a290e2
commit
6300d7660c
@ -42,7 +42,6 @@ public final class ServerFlag {
|
||||
public static final @NotNull String AUTH_URL = System.getProperty("minestom.auth.url", "https://sessionserver.mojang.com/session/minecraft/hasJoined");
|
||||
|
||||
// World
|
||||
public static final @Nullable String STACKING_RULE = System.getProperty("minestom.stacking-rule");
|
||||
public static final int WORLD_BORDER_SIZE = Integer.getInteger("minestom.world-border-size", 29999984);
|
||||
|
||||
// Maps
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.minestom.server.entity.attribute;
|
||||
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.UUID;
|
||||
@ -7,12 +8,12 @@ import java.util.UUID;
|
||||
/**
|
||||
* Represent an attribute modifier.
|
||||
*/
|
||||
public class AttributeModifier {
|
||||
|
||||
private final double amount;
|
||||
private final String name;
|
||||
private final AttributeOperation operation;
|
||||
private final UUID id;
|
||||
public record AttributeModifier(
|
||||
@NotNull UUID id,
|
||||
@NotNull String name,
|
||||
double amount,
|
||||
@NotNull AttributeOperation operation
|
||||
) implements NetworkBuffer.Writer {
|
||||
|
||||
/**
|
||||
* Creates a new modifier with a random id.
|
||||
@ -25,19 +26,17 @@ public class AttributeModifier {
|
||||
this(UUID.randomUUID(), name, amount, operation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new modifier.
|
||||
*
|
||||
* @param id the id of this modifier
|
||||
* @param name the name of this modifier
|
||||
* @param amount the value of this modifier
|
||||
* @param operation the operation to apply this modifier with
|
||||
*/
|
||||
public AttributeModifier(@NotNull UUID id, @NotNull String name, double amount, @NotNull AttributeOperation operation) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.amount = amount;
|
||||
this.operation = operation;
|
||||
public AttributeModifier(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(NetworkBuffer.UUID), reader.read(NetworkBuffer.STRING),
|
||||
reader.read(NetworkBuffer.DOUBLE), reader.readEnum(AttributeOperation.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(NetworkBuffer.UUID, id);
|
||||
writer.write(NetworkBuffer.STRING, name);
|
||||
writer.write(NetworkBuffer.DOUBLE, amount);
|
||||
writer.writeEnum(AttributeOperation.class, operation);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -45,8 +44,8 @@ public class AttributeModifier {
|
||||
*
|
||||
* @return the id of this modifier
|
||||
*/
|
||||
@NotNull
|
||||
public UUID getId() {
|
||||
@Deprecated
|
||||
public @NotNull UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@ -55,8 +54,8 @@ public class AttributeModifier {
|
||||
*
|
||||
* @return the name of this modifier
|
||||
*/
|
||||
@NotNull
|
||||
public String getName() {
|
||||
@Deprecated
|
||||
public @NotNull String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@ -65,6 +64,7 @@ public class AttributeModifier {
|
||||
*
|
||||
* @return the value of this modifier
|
||||
*/
|
||||
@Deprecated
|
||||
public double getAmount() {
|
||||
return amount;
|
||||
}
|
||||
@ -74,8 +74,8 @@ public class AttributeModifier {
|
||||
*
|
||||
* @return the operation of this modifier
|
||||
*/
|
||||
@NotNull
|
||||
public AttributeOperation getOperation() {
|
||||
@Deprecated
|
||||
public @NotNull AttributeOperation getOperation() {
|
||||
return operation;
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package net.minestom.server.item;
|
||||
/**
|
||||
* Represents a hide flag which can be applied to an {@link ItemStack} using {@link ItemMeta.Builder#hideFlag(int)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public enum ItemHideFlag {
|
||||
HIDE_ENCHANTS,
|
||||
HIDE_ATTRIBUTES,
|
||||
|
@ -4,8 +4,7 @@ import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.item.attribute.ItemAttribute;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.registry.StaticProtocolObject;
|
||||
import net.minestom.server.item.component.ItemComponentPatch;
|
||||
import net.minestom.server.tag.Tag;
|
||||
import net.minestom.server.tag.TagReadable;
|
||||
import net.minestom.server.tag.Taggable;
|
||||
@ -17,8 +16,10 @@ import org.jetbrains.annotations.UnknownNullability;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public sealed interface ItemMeta extends TagReadable, NetworkBuffer.Writer
|
||||
permits ItemMetaImpl {
|
||||
@Deprecated
|
||||
public sealed interface ItemMeta extends TagReadable permits ItemMetaImpl {
|
||||
|
||||
@NotNull ItemComponentPatch components();
|
||||
|
||||
@Override
|
||||
<T> @UnknownNullability T getTag(@NotNull Tag<T> tag);
|
||||
@ -31,69 +32,48 @@ public sealed interface ItemMeta extends TagReadable, NetworkBuffer.Writer
|
||||
@NotNull String toSNBT();
|
||||
|
||||
@Contract(pure = true)
|
||||
default int getDamage() {
|
||||
return getTag(ItemTags.DAMAGE);
|
||||
}
|
||||
int getDamage();
|
||||
|
||||
@Contract(pure = true)
|
||||
default boolean isUnbreakable() {
|
||||
return getTag(ItemTags.UNBREAKABLE);
|
||||
}
|
||||
boolean isUnbreakable();
|
||||
|
||||
@Contract(pure = true)
|
||||
default int getHideFlag() {
|
||||
return getTag(ItemTags.HIDE_FLAGS);
|
||||
}
|
||||
int getHideFlag();
|
||||
|
||||
@Contract(pure = true)
|
||||
default @Nullable Component getDisplayName() {
|
||||
return getTag(ItemTags.NAME);
|
||||
}
|
||||
@Nullable Component getDisplayName();
|
||||
|
||||
@Contract(pure = true)
|
||||
default @NotNull List<@NotNull Component> getLore() {
|
||||
return getTag(ItemTags.LORE);
|
||||
}
|
||||
@NotNull List<@NotNull Component> getLore();
|
||||
|
||||
@Contract(pure = true)
|
||||
default @NotNull Map<Enchantment, Short> getEnchantmentMap() {
|
||||
return getTag(ItemTags.ENCHANTMENTS);
|
||||
}
|
||||
@NotNull Map<Enchantment, Short> getEnchantmentMap();
|
||||
|
||||
@Contract(pure = true)
|
||||
default @NotNull List<@NotNull ItemAttribute> getAttributes() {
|
||||
return getTag(ItemTags.ATTRIBUTES);
|
||||
}
|
||||
@NotNull List<@NotNull ItemAttribute> getAttributes();
|
||||
|
||||
@Contract(pure = true)
|
||||
default int getCustomModelData() {
|
||||
return getTag(ItemTags.CUSTOM_MODEL_DATA);
|
||||
}
|
||||
int getCustomModelData();
|
||||
|
||||
@Contract(pure = true)
|
||||
default @NotNull Set<@NotNull String> getCanDestroy() {
|
||||
return Set.copyOf(getTag(ItemTags.CAN_DESTROY));
|
||||
}
|
||||
@NotNull Set<@NotNull String> getCanDestroy();
|
||||
|
||||
@Contract(pure = true)
|
||||
default boolean canDestroy(@NotNull Block block) {
|
||||
return getCanDestroy().contains(block.name());
|
||||
}
|
||||
boolean canDestroy(@NotNull Block block);
|
||||
|
||||
@Contract(pure = true)
|
||||
default @NotNull Set<@NotNull String> getCanPlaceOn() {
|
||||
return Set.copyOf(getTag(ItemTags.CAN_PLACE_ON));
|
||||
}
|
||||
@NotNull Set<@NotNull String> getCanPlaceOn();
|
||||
|
||||
@Contract(pure = true)
|
||||
default boolean canPlaceOn(@NotNull Block block) {
|
||||
return getCanPlaceOn().contains(block.name());
|
||||
}
|
||||
boolean canPlaceOn(@NotNull Block block);
|
||||
|
||||
@Deprecated
|
||||
sealed interface Builder extends Taggable
|
||||
permits ItemMetaImpl.Builder, ItemMetaView.Builder {
|
||||
@NotNull ItemMeta build();
|
||||
|
||||
@NotNull ItemComponentPatch.Builder components();
|
||||
|
||||
default <T> @NotNull Builder set(@NotNull Tag<T> tag, @Nullable T value) {
|
||||
setTag(tag, value);
|
||||
return this;
|
||||
|
@ -2,36 +2,38 @@ package net.minestom.server.item;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.TagStringIO;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.item.attribute.ItemAttribute;
|
||||
import net.minestom.server.item.component.*;
|
||||
import net.minestom.server.tag.Tag;
|
||||
import net.minestom.server.tag.TagHandler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.NBT;
|
||||
|
||||
record ItemMetaImpl(TagHandler tagHandler) implements ItemMeta {
|
||||
static final ItemMetaImpl EMPTY = new ItemMetaImpl(TagHandler.newHandler());
|
||||
@Deprecated
|
||||
record ItemMetaImpl(ItemComponentPatch components) implements ItemMeta {
|
||||
|
||||
@Override
|
||||
public <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) {
|
||||
return tagHandler.getTag(tag);
|
||||
return components.get(ItemComponent.CUSTOM_DATA, CustomData.EMPTY).getTag(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemMeta with(@NotNull Consumer<ItemMeta.@NotNull Builder> builderConsumer) {
|
||||
Builder builder = new Builder(tagHandler.copy());
|
||||
Builder builder = new Builder(components.builder());
|
||||
builderConsumer.accept(builder);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CompoundBinaryTag toNBT() {
|
||||
return tagHandler.asCompound();
|
||||
return components.asCompound();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -44,20 +46,81 @@ record ItemMetaImpl(TagHandler tagHandler) implements ItemMeta {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(NBT, toNBT());
|
||||
public int getDamage() {
|
||||
return components.get(ItemComponent.DAMAGE, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnbreakable() {
|
||||
return components.has(ItemComponent.UNBREAKABLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHideFlag() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Component getDisplayName() {
|
||||
return components.get(ItemComponent.CUSTOM_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<@NotNull Component> getLore() {
|
||||
return components.get(ItemComponent.LORE, List.of());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Map<Enchantment, Short> getEnchantmentMap() {
|
||||
EnchantmentList enchantments = components.get(ItemComponent.ENCHANTMENTS);
|
||||
if (enchantments == null) return Map.of();
|
||||
Map<Enchantment, Short> map = new HashMap<>(enchantments.enchantments().size());
|
||||
for (Map.Entry<Enchantment, Integer> entry : enchantments.enchantments().entrySet()) {
|
||||
map.put(entry.getKey(), entry.getValue().shortValue());
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<@NotNull ItemAttribute> getAttributes() {
|
||||
//todo
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCustomModelData() {
|
||||
return components.get(ItemComponent.CUSTOM_MODEL_DATA, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Set<@NotNull String> getCanDestroy() {
|
||||
//todo
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDestroy(@NotNull Block block) {
|
||||
//todo
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Set<@NotNull String> getCanPlaceOn() {
|
||||
//todo
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlaceOn(@NotNull Block block) {
|
||||
//todo
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof ItemMetaImpl itemMeta)) return false;
|
||||
return toNBT().equals(itemMeta.toNBT());
|
||||
return components.equals(itemMeta.components);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(toNBT());
|
||||
return Objects.hash(components);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -65,10 +128,107 @@ record ItemMetaImpl(TagHandler tagHandler) implements ItemMeta {
|
||||
return toSNBT();
|
||||
}
|
||||
|
||||
record Builder(TagHandler tagHandler) implements ItemMeta.Builder {
|
||||
static final class Builder implements ItemMeta.Builder {
|
||||
private final ItemComponentPatch.Builder components;
|
||||
private TagHandler tagHandler = null;
|
||||
|
||||
Builder(ItemComponentPatch.Builder components) {
|
||||
this.components = components;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemMeta.@NotNull Builder damage(int damage) {
|
||||
components.set(ItemComponent.DAMAGE, damage);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemMeta.@NotNull Builder unbreakable(boolean unbreakable) {
|
||||
if (unbreakable) {
|
||||
components.set(ItemComponent.UNBREAKABLE, new Unbreakable(
|
||||
components.get(ItemComponent.UNBREAKABLE, Unbreakable.DEFAULT).showInTooltip()));
|
||||
} else {
|
||||
components.remove(ItemComponent.UNBREAKABLE);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemMeta.@NotNull Builder hideFlag(int hideFlag) {
|
||||
return this; //todo
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemMeta.@NotNull Builder displayName(@Nullable Component displayName) {
|
||||
if (displayName == null) {
|
||||
components.remove(ItemComponent.CUSTOM_NAME);
|
||||
} else {
|
||||
components.set(ItemComponent.CUSTOM_NAME, displayName);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemMeta.@NotNull Builder lore(@NotNull List<? extends Component> lore) {
|
||||
components.set(ItemComponent.LORE, new ArrayList<>(lore));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemMeta.@NotNull Builder enchantments(@NotNull Map<Enchantment, Short> enchantments) {
|
||||
EnchantmentList existing = components.get(ItemComponent.ENCHANTMENTS, EnchantmentList.EMPTY);
|
||||
Map<Enchantment, Integer> map = new HashMap<>(enchantments.size());
|
||||
for (Map.Entry<Enchantment, Short> entry : enchantments.entrySet()) {
|
||||
map.put(entry.getKey(), (int) entry.getValue());
|
||||
}
|
||||
components.set(ItemComponent.ENCHANTMENTS, new EnchantmentList(map, existing.showInTooltip()));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemMeta.@NotNull Builder enchantment(@NotNull Enchantment enchantment, short level) {
|
||||
components.set(ItemComponent.ENCHANTMENTS, components.get(ItemComponent.ENCHANTMENTS, EnchantmentList.EMPTY)
|
||||
.with(enchantment, level));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemMeta.@NotNull Builder attributes(@NotNull List<@NotNull ItemAttribute> attributes) {
|
||||
return this; //todo
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemMeta.@NotNull Builder customModelData(int customModelData) {
|
||||
components.set(ItemComponent.CUSTOM_MODEL_DATA, customModelData);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemMeta.@NotNull Builder canPlaceOn(@NotNull Set<@NotNull Block> blocks) {
|
||||
//todo
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemMeta.@NotNull Builder canDestroy(@NotNull Set<@NotNull Block> blocks) {
|
||||
//todo
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull TagHandler tagHandler() {
|
||||
this.tagHandler = TagHandler.fromCompound(components.get(ItemComponent.CUSTOM_DATA, CustomData.EMPTY).nbt());
|
||||
return tagHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemMetaImpl build() {
|
||||
return new ItemMetaImpl(tagHandler.copy());
|
||||
if (tagHandler != null) {
|
||||
// If tagHandler was called then a tag was probably changed so update custom data.
|
||||
components.set(ItemComponent.CUSTOM_DATA, new CustomData(tagHandler.asCompound()));
|
||||
}
|
||||
return new ItemMetaImpl(components.build());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,15 @@
|
||||
package net.minestom.server.item;
|
||||
|
||||
import net.minestom.server.tag.TagReadable;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@SuppressWarnings("ALL")
|
||||
@ApiStatus.Experimental
|
||||
@Deprecated
|
||||
public interface ItemMetaView<T extends ItemMetaView.Builder> extends TagReadable {
|
||||
@ApiStatus.Experimental
|
||||
|
||||
@Deprecated
|
||||
non-sealed interface Builder extends ItemMeta.Builder {
|
||||
default @NotNull ItemMeta build() {
|
||||
return new ItemMetaImpl(tagHandler().copy());
|
||||
return new ItemMetaImpl(components().build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,34 +1,34 @@
|
||||
package net.minestom.server.item;
|
||||
|
||||
import net.minestom.server.tag.TagHandler;
|
||||
import net.minestom.server.tag.TagReadable;
|
||||
import net.minestom.server.item.component.ItemComponentPatch;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
@Deprecated
|
||||
final class ItemMetaViewImpl {
|
||||
static <V extends ItemMetaView.Builder, T extends ItemMetaView<V>> Class<V> viewType(Class<T> metaClass) {
|
||||
final Type type = metaClass.getGenericInterfaces()[0];
|
||||
return (Class<V>) ((ParameterizedType) type).getActualTypeArguments()[0];
|
||||
}
|
||||
|
||||
static <T extends ItemMetaView<?>> T construct(Class<T> metaClass, TagReadable tagReadable) {
|
||||
static <T extends ItemMetaView<?>> T construct(Class<T> metaClass, ItemComponentPatch components) {
|
||||
try {
|
||||
final Constructor<T> cons = metaClass.getDeclaredConstructor(TagReadable.class);
|
||||
return cons.newInstance(tagReadable);
|
||||
final Constructor<T> cons = metaClass.getDeclaredConstructor(ItemComponentPatch.class);
|
||||
return cons.newInstance(components);
|
||||
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException |
|
||||
IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
static <V extends ItemMetaView.Builder, T extends ItemMetaView<V>> V constructBuilder(Class<T> metaClass, TagHandler tagHandler) {
|
||||
static <V extends ItemMetaView.Builder, T extends ItemMetaView<V>> V constructBuilder(Class<T> metaClass, ItemComponentPatch.Builder components) {
|
||||
final Class<V> clazz = viewType(metaClass);
|
||||
try {
|
||||
final Constructor<V> cons = clazz.getDeclaredConstructor(TagHandler.class);
|
||||
return cons.newInstance(tagHandler);
|
||||
final Constructor<V> cons = clazz.getDeclaredConstructor(ItemComponentPatch.Builder.class);
|
||||
return cons.newInstance(components);
|
||||
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException |
|
||||
IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
|
@ -15,6 +15,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
@Deprecated
|
||||
@ApiStatus.Internal
|
||||
public final class ItemSerializers {
|
||||
public static final TagSerializer<EnchantmentEntry> ENCHANTMENT_SERIALIZER = new TagSerializer<>() {
|
||||
|
@ -6,11 +6,14 @@ import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.event.HoverEventSource;
|
||||
import net.minestom.server.adventure.MinestomAdventure;
|
||||
import net.minestom.server.item.component.CustomData;
|
||||
import net.minestom.server.item.component.ItemComponent;
|
||||
import net.minestom.server.item.component.ItemComponentMap;
|
||||
import net.minestom.server.inventory.ContainerInventory;
|
||||
import net.minestom.server.tag.Tag;
|
||||
import net.minestom.server.tag.TagHandler;
|
||||
import net.minestom.server.tag.TagReadable;
|
||||
import net.minestom.server.tag.TagWritable;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -25,7 +28,7 @@ import java.util.function.UnaryOperator;
|
||||
* <p>
|
||||
* An item stack cannot be null, {@link ItemStack#AIR} should be used instead.
|
||||
*/
|
||||
public sealed interface ItemStack extends TagReadable, HoverEventSource<HoverEvent.ShowItem>
|
||||
public sealed interface ItemStack extends TagReadable, ItemComponentMap, HoverEventSource<HoverEvent.ShowItem>
|
||||
permits ItemStackImpl {
|
||||
/**
|
||||
* Constant AIR item. Should be used instead of 'null'.
|
||||
@ -47,12 +50,14 @@ public sealed interface ItemStack extends TagReadable, HoverEventSource<HoverEve
|
||||
return of(material, 1);
|
||||
}
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@Contract(value = "_, _, _ -> new", pure = true)
|
||||
static @NotNull ItemStack fromNBT(@NotNull Material material, @Nullable CompoundBinaryTag nbtCompound, int amount) {
|
||||
if (nbtCompound == null) return of(material, amount);
|
||||
return builder(material).amount(amount).meta(nbtCompound).build();
|
||||
}
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@Contract(value = "_, _ -> new", pure = true)
|
||||
static @NotNull ItemStack fromNBT(@NotNull Material material, @Nullable CompoundBinaryTag nbtCompound) {
|
||||
return fromNBT(material, nbtCompound, 1);
|
||||
@ -63,17 +68,16 @@ public sealed interface ItemStack extends TagReadable, HoverEventSource<HoverEve
|
||||
*
|
||||
* @param nbtCompound The nbt representation of the item
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
static @NotNull ItemStack fromItemNBT(@NotNull CompoundBinaryTag nbtCompound) {
|
||||
String id = nbtCompound.getString("id");
|
||||
Check.notNull(id, "Item NBT must contain an id field.");
|
||||
Material material = Material.fromNamespaceId(id);
|
||||
Check.notNull(material, "Unknown material: {0}", id);
|
||||
|
||||
Byte amount = nbtCompound.getByte("Count");
|
||||
if (amount == null) amount = 1;
|
||||
final CompoundBinaryTag tag = nbtCompound.getCompound("tag");
|
||||
return tag != null ? fromNBT(material, tag, amount) : of(material, amount);
|
||||
// String id = nbtCompound.getString("id");
|
||||
// Check.notNull(id, "Item NBT must contain an id field.");
|
||||
// Material material = Material.fromNamespaceId(id);
|
||||
// Check.notNull(material, "Unknown material: {0}", id);
|
||||
//
|
||||
// Byte amount = nbtCompound.getByte("Count");
|
||||
// if (amount == null) amount = 1;
|
||||
// final CompoundBinaryTag tag = nbtCompound.getCompound("tag");
|
||||
// return tag != null ? fromNBT(material, tag, amount) : of(material, amount);
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
@ -82,24 +86,9 @@ public sealed interface ItemStack extends TagReadable, HoverEventSource<HoverEve
|
||||
@Contract(pure = true)
|
||||
int amount();
|
||||
|
||||
@Contract(pure = true)
|
||||
@NotNull ItemMeta meta();
|
||||
|
||||
@Contract(pure = true)
|
||||
@ApiStatus.Experimental
|
||||
<T extends ItemMetaView<?>> @NotNull T meta(@NotNull Class<T> metaClass);
|
||||
|
||||
@Contract(value = "_, -> new", pure = true)
|
||||
@NotNull ItemStack with(@NotNull Consumer<@NotNull Builder> consumer);
|
||||
|
||||
@Contract(value = "_, _ -> new", pure = true)
|
||||
@ApiStatus.Experimental
|
||||
<V extends ItemMetaView.Builder, T extends ItemMetaView<V>> @NotNull ItemStack withMeta(@NotNull Class<T> metaType,
|
||||
@NotNull Consumer<V> consumer);
|
||||
|
||||
@Contract(value = "_ -> new", pure = true)
|
||||
@NotNull ItemStack withMeta(@NotNull Consumer<ItemMeta.@NotNull Builder> consumer);
|
||||
|
||||
@Contract(value = "_, -> new", pure = true)
|
||||
@NotNull ItemStack withMaterial(@NotNull Material material);
|
||||
|
||||
@ -111,44 +100,26 @@ public sealed interface ItemStack extends TagReadable, HoverEventSource<HoverEve
|
||||
return withAmount(intUnaryOperator.applyAsInt(amount()));
|
||||
}
|
||||
|
||||
@ApiStatus.Experimental
|
||||
@Contract(value = "_, _ -> new", pure = true)
|
||||
<T> @NotNull ItemStack with(@NotNull ItemComponent<T> component, T value);
|
||||
|
||||
@Contract(value = "_, -> new", pure = true)
|
||||
@NotNull ItemStack without(@NotNull ItemComponent<?> component);
|
||||
|
||||
@Contract(value = "_, _ -> new", pure = true)
|
||||
default <T> @NotNull ItemStack withTag(@NotNull Tag<T> tag, @Nullable T value) {
|
||||
return withMeta(builder -> builder.set(tag, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Contract(pure = true)
|
||||
default <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) {
|
||||
return getOrDefault(ItemComponent.CUSTOM_DATA, CustomData.EMPTY).getTag(tag);
|
||||
}
|
||||
|
||||
@Contract(value = "_, -> new", pure = true)
|
||||
@NotNull ItemStack consume(int amount);
|
||||
|
||||
@Contract(pure = true)
|
||||
default @Nullable Component getDisplayName() {
|
||||
return meta().getDisplayName();
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
default @NotNull List<@NotNull Component> getLore() {
|
||||
return meta().getLore();
|
||||
}
|
||||
|
||||
@ApiStatus.Experimental
|
||||
@Contract(value = "_ -> new", pure = true)
|
||||
@NotNull ItemStack withMeta(@NotNull ItemMeta meta);
|
||||
|
||||
@Contract(value = "_, -> new", pure = true)
|
||||
default @NotNull ItemStack withDisplayName(@Nullable Component displayName) {
|
||||
return withMeta(builder -> builder.displayName(displayName));
|
||||
}
|
||||
|
||||
@Contract(value = "_, -> new", pure = true)
|
||||
default @NotNull ItemStack withDisplayName(@NotNull UnaryOperator<@Nullable Component> componentUnaryOperator) {
|
||||
return withDisplayName(componentUnaryOperator.apply(getDisplayName()));
|
||||
}
|
||||
|
||||
@Contract(value = "_, -> new", pure = true)
|
||||
default @NotNull ItemStack withLore(@NotNull List<? extends Component> lore) {
|
||||
return withMeta(builder -> builder.lore(lore));
|
||||
}
|
||||
|
||||
@Contract(value = "_, -> new", pure = true)
|
||||
default @NotNull ItemStack withLore(@NotNull UnaryOperator<@NotNull List<@NotNull Component>> loreUnaryOperator) {
|
||||
return withLore(loreUnaryOperator.apply(getLore()));
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
default boolean isAir() {
|
||||
return material() == Material.AIR;
|
||||
@ -157,16 +128,76 @@ public sealed interface ItemStack extends TagReadable, HoverEventSource<HoverEve
|
||||
@Contract(pure = true)
|
||||
boolean isSimilar(@NotNull ItemStack itemStack);
|
||||
|
||||
/**
|
||||
* Converts this item to an NBT tag containing the id (material), count (amount), and components (diff)
|
||||
*
|
||||
* @return The nbt representation of the item
|
||||
*/
|
||||
@NotNull CompoundBinaryTag toItemNBT();
|
||||
|
||||
// BEGIN DEPRECATED PRE-COMPONENT METHODS
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@Contract(pure = true)
|
||||
@NotNull ItemMeta meta();
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@Contract(pure = true)
|
||||
@ApiStatus.Experimental
|
||||
<T extends ItemMetaView<?>> @NotNull T meta(@NotNull Class<T> metaClass);
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@Contract(value = "_, _ -> new", pure = true)
|
||||
default <T> @NotNull ItemStack withTag(@NotNull Tag<T> tag, @Nullable T value) {
|
||||
return withMeta(builder -> builder.set(tag, value));
|
||||
@ApiStatus.Experimental
|
||||
<V extends ItemMetaView.Builder, T extends ItemMetaView<V>> @NotNull ItemStack withMeta(@NotNull Class<T> metaType,
|
||||
@NotNull Consumer<V> consumer);
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@Contract(value = "_ -> new", pure = true)
|
||||
@NotNull ItemStack withMeta(@NotNull Consumer<ItemMeta.@NotNull Builder> consumer);
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@Contract(pure = true)
|
||||
default @Nullable Component getDisplayName() {
|
||||
return meta().getDisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
default <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) {
|
||||
return meta().getTag(tag);
|
||||
@Deprecated(forRemoval = true)
|
||||
@Contract(pure = true)
|
||||
default @NotNull List<@NotNull Component> getLore() {
|
||||
return meta().getLore();
|
||||
}
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@Contract(value = "_ -> new", pure = true)
|
||||
@NotNull ItemStack withMeta(@NotNull ItemMeta meta);
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@Contract(value = "_, -> new", pure = true)
|
||||
default @NotNull ItemStack withDisplayName(@Nullable Component displayName) {
|
||||
return withMeta(builder -> builder.displayName(displayName));
|
||||
}
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@Contract(value = "_, -> new", pure = true)
|
||||
default @NotNull ItemStack withDisplayName(@NotNull UnaryOperator<@Nullable Component> componentUnaryOperator) {
|
||||
return withDisplayName(componentUnaryOperator.apply(getDisplayName()));
|
||||
}
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@Contract(value = "_, -> new", pure = true)
|
||||
default @NotNull ItemStack withLore(@NotNull List<? extends Component> lore) {
|
||||
return withMeta(builder -> builder.lore(lore));
|
||||
}
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@Contract(value = "_, -> new", pure = true)
|
||||
default @NotNull ItemStack withLore(@NotNull UnaryOperator<@NotNull List<@NotNull Component>> loreUnaryOperator) {
|
||||
return withLore(loreUnaryOperator.apply(getLore()));
|
||||
}
|
||||
|
||||
// END DEPRECATED PRE-COMPONENT METHODS
|
||||
|
||||
@Override
|
||||
default @NotNull HoverEvent<HoverEvent.ShowItem> asHoverEvent(@NotNull UnaryOperator<HoverEvent.ShowItem> op) {
|
||||
try {
|
||||
@ -178,56 +209,17 @@ public sealed interface ItemStack extends TagReadable, HoverEventSource<HoverEve
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this item to an NBT tag containing the id (material), count (amount), and tag (meta)
|
||||
*
|
||||
* @return The nbt representation of the item
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
@NotNull CompoundBinaryTag toItemNBT();
|
||||
|
||||
|
||||
@Deprecated
|
||||
@Contract(pure = true)
|
||||
default @NotNull Material getMaterial() {
|
||||
return material();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Contract(pure = true)
|
||||
default int getAmount() {
|
||||
return amount();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Contract(pure = true)
|
||||
default @NotNull ItemMeta getMeta() {
|
||||
return meta();
|
||||
}
|
||||
|
||||
sealed interface Builder extends TagWritable
|
||||
permits ItemStackImpl.Builder {
|
||||
|
||||
@Contract(value = "_ -> this")
|
||||
@NotNull Builder amount(int amount);
|
||||
|
||||
@Contract(value = "_ -> this")
|
||||
@NotNull Builder meta(@NotNull TagHandler tagHandler);
|
||||
|
||||
@Contract(value = "_ -> this")
|
||||
@NotNull Builder meta(@NotNull CompoundBinaryTag compound);
|
||||
|
||||
@Contract(value = "_ -> this")
|
||||
@NotNull Builder meta(@NotNull ItemMeta itemMeta);
|
||||
|
||||
@Contract(value = "_ -> this")
|
||||
@NotNull Builder meta(@NotNull Consumer<ItemMeta.@NotNull Builder> consumer);
|
||||
|
||||
@Contract(value = "_, _ -> this")
|
||||
<V extends ItemMetaView.Builder, T extends ItemMetaView<V>> @NotNull Builder meta(@NotNull Class<T> metaType,
|
||||
@NotNull Consumer<@NotNull V> itemMetaConsumer);
|
||||
<T> @NotNull Builder set(@NotNull ItemComponent<T> component, T value);
|
||||
|
||||
@Contract(value = "-> new", pure = true)
|
||||
@NotNull ItemStack build();
|
||||
@Contract(value = "_ -> this")
|
||||
@NotNull Builder remove(@NotNull ItemComponent<?> component);
|
||||
|
||||
@Contract(value = "_, _ -> this")
|
||||
default <T> @NotNull Builder set(@NotNull Tag<T> tag, @Nullable T value) {
|
||||
@ -235,16 +227,45 @@ public sealed interface ItemStack extends TagReadable, HoverEventSource<HoverEve
|
||||
return this;
|
||||
}
|
||||
|
||||
@Contract(value = "-> new", pure = true)
|
||||
@NotNull ItemStack build();
|
||||
|
||||
// BEGIN DEPRECATED PRE-COMPONENT METHODS
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@Contract(value = "_ -> this")
|
||||
@NotNull Builder meta(@NotNull TagHandler tagHandler);
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@Contract(value = "_ -> this")
|
||||
@NotNull Builder meta(@NotNull CompoundBinaryTag compound);
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@Contract(value = "_ -> this")
|
||||
@NotNull Builder meta(@NotNull ItemMeta itemMeta);
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@Contract(value = "_ -> this")
|
||||
@NotNull Builder meta(@NotNull Consumer<ItemMeta.@NotNull Builder> consumer);
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@Contract(value = "_, _ -> this")
|
||||
<V extends ItemMetaView.Builder, T extends ItemMetaView<V>> @NotNull Builder meta(@NotNull Class<T> metaType,
|
||||
@NotNull Consumer<@NotNull V> itemMetaConsumer);
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@Contract(value = "_ -> this")
|
||||
default @NotNull Builder displayName(@Nullable Component displayName) {
|
||||
return meta(builder -> builder.displayName(displayName));
|
||||
}
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@Contract(value = "_ -> this")
|
||||
default @NotNull Builder lore(@NotNull List<? extends Component> lore) {
|
||||
return meta(builder -> builder.lore(lore));
|
||||
}
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
@Contract(value = "_ -> this")
|
||||
default @NotNull Builder lore(Component... lore) {
|
||||
return meta(builder -> builder.lore(lore));
|
||||
|
@ -1,8 +1,9 @@
|
||||
package net.minestom.server.item;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.ServerFlag;
|
||||
import net.minestom.server.item.rule.VanillaStackingRule;
|
||||
import net.minestom.server.item.component.CustomData;
|
||||
import net.minestom.server.item.component.ItemComponent;
|
||||
import net.minestom.server.item.component.ItemComponentPatch;
|
||||
import net.minestom.server.tag.Tag;
|
||||
import net.minestom.server.tag.TagHandler;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
@ -11,34 +12,25 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
record ItemStackImpl(Material material, int amount, ItemMetaImpl meta) implements ItemStack {
|
||||
static final @NotNull StackingRule DEFAULT_STACKING_RULE;
|
||||
record ItemStackImpl(Material material, int amount, ItemComponentPatch components) implements ItemStack {
|
||||
|
||||
static {
|
||||
if (ServerFlag.STACKING_RULE == null) {
|
||||
DEFAULT_STACKING_RULE = new VanillaStackingRule();
|
||||
} else {
|
||||
try {
|
||||
DEFAULT_STACKING_RULE = (StackingRule) ClassLoader.getSystemClassLoader()
|
||||
.loadClass(ServerFlag.STACKING_RULE).getConstructor().newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Could not instantiate default stacking rule", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ItemStack create(Material material, int amount, ItemMetaImpl meta) {
|
||||
static ItemStack create(Material material, int amount, ItemComponentPatch components) {
|
||||
if (amount <= 0) return AIR;
|
||||
return new ItemStackImpl(material, amount, meta);
|
||||
return new ItemStackImpl(material, amount, components);
|
||||
}
|
||||
|
||||
static ItemStack create(Material material, int amount) {
|
||||
return create(material, amount, ItemMetaImpl.EMPTY);
|
||||
return create(material, amount, ItemComponentPatch.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends ItemMetaView<?>> @NotNull T meta(@NotNull Class<T> metaClass) {
|
||||
return ItemMetaViewImpl.construct(metaClass, meta);
|
||||
public <T> @Nullable T get(@NotNull ItemComponent<T> component) {
|
||||
return components.get(component);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean has(@NotNull ItemComponent<?> component) {
|
||||
return components.has(component);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -48,6 +40,65 @@ record ItemStackImpl(Material material, int amount, ItemMetaImpl meta) implement
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack withMaterial(@NotNull Material material) {
|
||||
return new ItemStackImpl(material, amount, components);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack withAmount(int amount) {
|
||||
return create(material, amount, components);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull <T> ItemStack with(@NotNull ItemComponent<T> component, T value) {
|
||||
return new ItemStackImpl(material, amount, components.with(component, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack without(@NotNull ItemComponent<?> component) {
|
||||
return new ItemStackImpl(material, amount, components.without(component));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack consume(int amount) {
|
||||
int newAmount = amount() - amount;
|
||||
if (newAmount <= 0) return AIR;
|
||||
return withAmount(newAmount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSimilar(@NotNull ItemStack itemStack) {
|
||||
return material == itemStack.material() && components.equals(((ItemStackImpl) itemStack).components);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CompoundBinaryTag toItemNBT() {
|
||||
// CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder()
|
||||
// .putString("id", material.name())
|
||||
// .putByte("Count", (byte) amount);
|
||||
// CompoundBinaryTag nbt = meta.toNBT();
|
||||
// if (nbt.size() > 0) builder.put("tag", nbt);
|
||||
// return builder.build();
|
||||
//todo
|
||||
}
|
||||
|
||||
@Contract(value = "-> new", pure = true)
|
||||
private @NotNull ItemStack.Builder builder() {
|
||||
return new Builder(material, amount, new ItemMetaImpl.Builder(meta.tagHandler().copy()));
|
||||
}
|
||||
|
||||
// BEGIN DEPRECATED PRE-COMPONENT METHODS
|
||||
|
||||
@Override public @NotNull ItemMeta meta() {
|
||||
return new ItemMetaImpl(components);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends ItemMetaView<?>> @NotNull T meta(@NotNull Class<T> metaClass) {
|
||||
return ItemMetaViewImpl.construct(metaClass, meta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull <V extends ItemMetaView.Builder, T extends ItemMetaView<V>> ItemStack withMeta(@NotNull Class<T> metaType,
|
||||
@NotNull Consumer<V> consumer) {
|
||||
@ -59,59 +110,20 @@ record ItemStackImpl(Material material, int amount, ItemMetaImpl meta) implement
|
||||
return builder().meta(consumer).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack withMaterial(@NotNull Material material) {
|
||||
return new ItemStackImpl(material, amount, meta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack withAmount(int amount) {
|
||||
return create(material, amount, meta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack consume(int amount) {
|
||||
return DEFAULT_STACKING_RULE.apply(this, currentAmount -> currentAmount - amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack withMeta(@NotNull ItemMeta meta) {
|
||||
return new ItemStackImpl(material, amount, (ItemMetaImpl) meta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSimilar(@NotNull ItemStack itemStack) {
|
||||
return material == itemStack.material() && meta.equals(itemStack.meta());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CompoundBinaryTag toItemNBT() {
|
||||
CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder()
|
||||
.putString("id", material.name())
|
||||
.putByte("Count", (byte) amount);
|
||||
CompoundBinaryTag nbt = meta.toNBT();
|
||||
if (nbt.size() > 0) builder.put("tag", nbt);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Contract(value = "-> new", pure = true)
|
||||
private @NotNull ItemStack.Builder builder() {
|
||||
return new Builder(material, amount, new ItemMetaImpl.Builder(meta.tagHandler().copy()));
|
||||
}
|
||||
|
||||
static final class Builder implements ItemStack.Builder {
|
||||
final Material material;
|
||||
int amount;
|
||||
ItemMetaImpl.Builder metaBuilder;
|
||||
ItemComponentPatch.Builder components;
|
||||
|
||||
Builder(Material material, int amount, ItemMetaImpl.Builder metaBuilder) {
|
||||
Builder(Material material, int amount, ItemComponentPatch.Builder components) {
|
||||
this.material = material;
|
||||
this.amount = amount;
|
||||
this.metaBuilder = metaBuilder;
|
||||
}
|
||||
|
||||
Builder(Material material, int amount) {
|
||||
this(material, amount, new ItemMetaImpl.Builder(TagHandler.newHandler()));
|
||||
this.components = components;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -120,49 +132,57 @@ record ItemStackImpl(Material material, int amount, ItemMetaImpl meta) implement
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ItemStack.@NotNull Builder set(@NotNull ItemComponent<T> component, T value) {
|
||||
components.set(component, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack.@NotNull Builder remove(@NotNull ItemComponent<?> component) {
|
||||
components.remove(component);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void setTag(@NotNull Tag<T> tag, @Nullable T value) {
|
||||
components.set(ItemComponent.CUSTOM_DATA, components.get(ItemComponent.CUSTOM_DATA, CustomData.EMPTY).withTag(tag, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack build() {
|
||||
return ItemStackImpl.create(material, amount, components.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack.@NotNull Builder meta(@NotNull TagHandler tagHandler) {
|
||||
return metaBuilder(new ItemMetaImpl.Builder(tagHandler.copy()));
|
||||
return meta(tagHandler.asCompound());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack.@NotNull Builder meta(@NotNull CompoundBinaryTag compound) {
|
||||
return metaBuilder(new ItemMetaImpl.Builder(TagHandler.fromCompound(compound)));
|
||||
components.set(ItemComponent.CUSTOM_DATA, new CustomData(compound));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack.@NotNull Builder meta(@NotNull ItemMeta itemMeta) {
|
||||
final TagHandler tagHandler = ((ItemMetaImpl) itemMeta).tagHandler();
|
||||
return metaBuilder(new ItemMetaImpl.Builder(tagHandler.copy()));
|
||||
this.components = itemMeta.components().builder();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack.@NotNull Builder meta(@NotNull Consumer<ItemMeta.Builder> consumer) {
|
||||
consumer.accept(metaBuilder);
|
||||
consumer.accept(new ItemMetaImpl.Builder(components));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V extends ItemMetaView.Builder, T extends ItemMetaView<V>> ItemStack.@NotNull Builder meta(@NotNull Class<T> metaType,
|
||||
@NotNull Consumer<@NotNull V> itemMetaConsumer) {
|
||||
V view = ItemMetaViewImpl.constructBuilder(metaType, metaBuilder.tagHandler());
|
||||
V view = ItemMetaViewImpl.constructBuilder(metaType, components);
|
||||
itemMetaConsumer.accept(view);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void setTag(@NotNull Tag<T> tag, @Nullable T value) {
|
||||
this.metaBuilder.setTag(tag, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack build() {
|
||||
return ItemStackImpl.create(material, amount, metaBuilder.build());
|
||||
}
|
||||
|
||||
private ItemStack.@NotNull Builder metaBuilder(@NotNull ItemMetaImpl.Builder builder) {
|
||||
this.metaBuilder = builder;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +0,0 @@
|
||||
package net.minestom.server.item;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.item.attribute.ItemAttribute;
|
||||
import net.minestom.server.tag.Tag;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static net.minestom.server.item.ItemSerializers.*;
|
||||
|
||||
final class ItemTags {
|
||||
static final Tag<Integer> DAMAGE = Tag.Integer("Damage").defaultValue(0);
|
||||
static final Tag<Boolean> UNBREAKABLE = Tag.Boolean("Unbreakable").defaultValue(false);
|
||||
static final Tag<Integer> HIDE_FLAGS = Tag.Integer("HideFlags").defaultValue(0);
|
||||
static final Tag<Integer> CUSTOM_MODEL_DATA = Tag.Integer("CustomModelData").defaultValue(0);
|
||||
static final Tag<Component> NAME = Tag.Component("Name").path("display");
|
||||
static final Tag<List<Component>> LORE = Tag.Component("Lore").path("display").list().defaultValue(List.of());
|
||||
static final Tag<Map<Enchantment, Short>> ENCHANTMENTS = Tag.Structure("Enchantments", ENCHANTMENT_SERIALIZER).list().map(enchantmentEntry -> {
|
||||
Map<Enchantment, Short> map = new HashMap<>();
|
||||
for (var entry : enchantmentEntry) map.put(entry.enchantment(), entry.level());
|
||||
return Map.copyOf(map);
|
||||
}, o -> {
|
||||
List<EnchantmentEntry> entries = new ArrayList<>();
|
||||
for (var entry : o.entrySet()) entries.add(new EnchantmentEntry(entry.getKey(), entry.getValue()));
|
||||
return List.copyOf(entries);
|
||||
}).defaultValue(Map.of());
|
||||
static final Tag<List<ItemAttribute>> ATTRIBUTES = Tag.Structure("AttributeModifiers", ATTRIBUTE_SERIALIZER).list().defaultValue(List.of());
|
||||
static final Tag<List<String>> CAN_PLACE_ON = Tag.String("CanPlaceOn").list().defaultValue(List.of());
|
||||
static final Tag<List<String>> CAN_DESTROY = Tag.String("CanDestroy").list().defaultValue(List.of());
|
||||
}
|
@ -1,12 +1,15 @@
|
||||
package net.minestom.server.item;
|
||||
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.item.component.ItemComponent;
|
||||
import net.minestom.server.item.component.ItemComponentMap;
|
||||
import net.minestom.server.registry.Registry;
|
||||
import net.minestom.server.registry.StaticProtocolObject;
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@ -62,24 +65,22 @@ public sealed interface Material extends StaticProtocolObject, Materials permits
|
||||
return registry().id();
|
||||
}
|
||||
|
||||
default int maxStackSize() {
|
||||
return registry().maxStackSize();
|
||||
}
|
||||
|
||||
default boolean isFood() {
|
||||
return registry().isFood();
|
||||
}
|
||||
|
||||
default boolean isBlock() {
|
||||
return registry().block() != null;
|
||||
}
|
||||
|
||||
default Block block() {
|
||||
default @UnknownNullability Block block() {
|
||||
return registry().block();
|
||||
}
|
||||
|
||||
default @NotNull ItemComponentMap prototype() {
|
||||
return registry().prototype();
|
||||
}
|
||||
|
||||
default boolean isArmor() {
|
||||
return registry().isArmor();
|
||||
//todo how does armor work nowadays
|
||||
return false;
|
||||
// return registry().isArmor();
|
||||
}
|
||||
|
||||
default boolean hasState() {
|
||||
@ -90,6 +91,16 @@ public sealed interface Material extends StaticProtocolObject, Materials permits
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
default int maxStackSize() {
|
||||
return prototype().getOrDefault(ItemComponent.MAX_STACK_SIZE, 64);
|
||||
}
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
default boolean isFood() {
|
||||
return prototype().has(ItemComponent.FOOD);
|
||||
}
|
||||
|
||||
static @NotNull Collection<@NotNull Material> values() {
|
||||
return MaterialImpl.values();
|
||||
}
|
||||
|
@ -1,70 +0,0 @@
|
||||
package net.minestom.server.item;
|
||||
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.function.IntUnaryOperator;
|
||||
|
||||
/**
|
||||
* Represents the stacking rule of an {@link ItemStack}.
|
||||
* This can be used to mimic the vanilla one (using the displayed item quantity)
|
||||
* or a complete new one which can be stored in lore, name, etc...
|
||||
*/
|
||||
public interface StackingRule {
|
||||
|
||||
static @NotNull StackingRule get() {
|
||||
return ItemStackImpl.DEFAULT_STACKING_RULE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to know if two {@link ItemStack} can be stacked together.
|
||||
*
|
||||
* @param item1 the first {@link ItemStack}
|
||||
* @param item2 the second {@link ItemStack}
|
||||
* @return true if both {@link ItemStack} can be stacked together
|
||||
* (without taking their amount in consideration)
|
||||
*/
|
||||
boolean canBeStacked(@NotNull ItemStack item1, @NotNull ItemStack item2);
|
||||
|
||||
/**
|
||||
* Used to know if an {@link ItemStack} can have the size {@code newAmount} applied.
|
||||
*
|
||||
* @param item the {@link ItemStack} to check
|
||||
* @param amount the desired new amount
|
||||
* @return true if {@code item} can have its stack size set to newAmount
|
||||
*/
|
||||
boolean canApply(@NotNull ItemStack item, int amount);
|
||||
|
||||
/**
|
||||
* Changes the size of the {@link ItemStack} to {@code newAmount}.
|
||||
* At this point we know that the item can have this stack size applied.
|
||||
*
|
||||
* @param item the {@link ItemStack} to applies the size to
|
||||
* @param newAmount the new item size
|
||||
* @return a new {@link ItemStack item} with the specified amount
|
||||
*/
|
||||
@Contract("_, _ -> new")
|
||||
@NotNull ItemStack apply(@NotNull ItemStack item, int newAmount);
|
||||
|
||||
@Contract("_, _ -> new")
|
||||
default @NotNull ItemStack apply(@NotNull ItemStack item, @NotNull IntUnaryOperator amountOperator) {
|
||||
return apply(item, amountOperator.applyAsInt(getAmount(item)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to determine the current stack size of an {@link ItemStack}.
|
||||
* It is possible to have it stored in its nbt.
|
||||
*
|
||||
* @param itemStack the {@link ItemStack} to check the size
|
||||
* @return the correct size of {@link ItemStack}
|
||||
*/
|
||||
int getAmount(@NotNull ItemStack itemStack);
|
||||
|
||||
/**
|
||||
* Gets the max size of a stack.
|
||||
*
|
||||
* @param itemStack the item to get the max size from
|
||||
* @return the max size of a stack
|
||||
*/
|
||||
int getMaxSize(@NotNull ItemStack itemStack);
|
||||
}
|
@ -1,10 +1,13 @@
|
||||
package net.minestom.server.item.attribute;
|
||||
|
||||
public enum AttributeSlot {
|
||||
ANY,
|
||||
MAINHAND,
|
||||
OFFHAND,
|
||||
FEET,
|
||||
LEGS,
|
||||
CHEST,
|
||||
HEAD
|
||||
HEAD,
|
||||
ARMOR,
|
||||
BODY,
|
||||
}
|
||||
|
@ -0,0 +1,101 @@
|
||||
package net.minestom.server.item.component;
|
||||
|
||||
import net.kyori.adventure.nbt.*;
|
||||
import net.minestom.server.entity.attribute.Attribute;
|
||||
import net.minestom.server.entity.attribute.AttributeModifier;
|
||||
import net.minestom.server.entity.attribute.AttributeOperation;
|
||||
import net.minestom.server.item.attribute.AttributeSlot;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.utils.UniqueIdUtils;
|
||||
import net.minestom.server.utils.nbt.BinaryTagSerializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public record AttributeList(@NotNull List<Modifier> modifiers, boolean showInTooltip) {
|
||||
public static final AttributeList EMPTY = new AttributeList(List.of(), true);
|
||||
|
||||
public static final NetworkBuffer.Type<AttributeList> NETWORK_TYPE = new NetworkBuffer.Type<>() {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, AttributeList value) {
|
||||
buffer.writeCollection(value.modifiers);
|
||||
buffer.write(NetworkBuffer.BOOLEAN, value.showInTooltip);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeList read(@NotNull NetworkBuffer buffer) {
|
||||
return new AttributeList(buffer.readCollection(Modifier::new, Short.MAX_VALUE),
|
||||
buffer.read(NetworkBuffer.BOOLEAN));
|
||||
}
|
||||
};
|
||||
|
||||
public static final BinaryTagSerializer<AttributeList> NBT_TYPE = new BinaryTagSerializer<>() {
|
||||
@Override
|
||||
public @NotNull BinaryTag write(@NotNull AttributeList value) {
|
||||
ListBinaryTag.Builder<CompoundBinaryTag> modifiers = ListBinaryTag.builder(BinaryTagTypes.COMPOUND);
|
||||
for (Modifier modifier : value.modifiers) {
|
||||
modifiers.add(CompoundBinaryTag.builder()
|
||||
.putString("type", modifier.attribute.name())
|
||||
.putString("slot", modifier.slot.name().toLowerCase(Locale.ROOT))
|
||||
.put("uuid", UniqueIdUtils.toNbt(modifier.modifier.id()))
|
||||
.putString("name", modifier.modifier.name())
|
||||
.putDouble("amount", modifier.modifier.amount())
|
||||
.putString("operation", modifier.modifier.operation().name().toLowerCase(Locale.ROOT))
|
||||
.build());
|
||||
}
|
||||
return CompoundBinaryTag.builder()
|
||||
.put("modifiers", modifiers.build())
|
||||
.putBoolean("show_in_tooltip", value.showInTooltip)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull AttributeList read(@NotNull BinaryTag tag) {
|
||||
boolean showInTooltip = true;
|
||||
ListBinaryTag modifiersTag;
|
||||
if (tag instanceof CompoundBinaryTag compound) {
|
||||
modifiersTag = compound.getList("modifiers", BinaryTagTypes.COMPOUND);
|
||||
showInTooltip = compound.getBoolean("show_in_tooltip", true);
|
||||
} else if (tag instanceof ListBinaryTag list) {
|
||||
modifiersTag = list;
|
||||
} else return EMPTY;
|
||||
List<Modifier> modifiers = new ArrayList<>(modifiersTag.size());
|
||||
for (BinaryTag modifierTagRaw : modifiersTag) {
|
||||
if (!(modifierTagRaw instanceof CompoundBinaryTag modifierTag)) continue;
|
||||
Attribute attribute = Attribute.fromNamespaceId(modifierTag.getString("type"));
|
||||
if (attribute == null) continue; // Unknown attribute, skip
|
||||
AttributeSlot slot = AttributeSlot.valueOf(modifierTag.getString("slot").toUpperCase(Locale.ROOT));
|
||||
AttributeModifier modifier = new AttributeModifier(
|
||||
UniqueIdUtils.fromNbt((IntArrayBinaryTag) modifierTag.get("uuid")),
|
||||
modifierTag.getString("name"),
|
||||
modifierTag.getDouble("amount"),
|
||||
AttributeOperation.valueOf(modifierTag.getString("operation").toUpperCase(Locale.ROOT))
|
||||
);
|
||||
modifiers.add(new Modifier(attribute, modifier, slot));
|
||||
}
|
||||
return new AttributeList(modifiers, showInTooltip);
|
||||
}
|
||||
};
|
||||
|
||||
public record Modifier(
|
||||
@NotNull Attribute attribute,
|
||||
@NotNull AttributeModifier modifier,
|
||||
@NotNull AttributeSlot slot
|
||||
) implements NetworkBuffer.Writer {
|
||||
|
||||
public Modifier(@NotNull NetworkBuffer reader) {
|
||||
this(Attribute.fromId(reader.read(NetworkBuffer.VAR_INT)),
|
||||
new AttributeModifier(reader),
|
||||
reader.readEnum(AttributeSlot.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(NetworkBuffer.VAR_INT, attribute.id());
|
||||
modifier.write(writer);
|
||||
writer.writeEnum(AttributeSlot.class, slot);
|
||||
}
|
||||
}
|
||||
}
|
@ -3,10 +3,13 @@ package net.minestom.server.item.component;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.tag.Tag;
|
||||
import net.minestom.server.tag.TagReadable;
|
||||
import net.minestom.server.utils.nbt.BinaryTagSerializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
|
||||
public record CustomData(@NotNull CompoundBinaryTag nbt) implements ItemComponent {
|
||||
static final Tag<CustomData> TAG = Tag.Structure("ab", CustomData.class);
|
||||
public record CustomData(@NotNull CompoundBinaryTag nbt) implements TagReadable {
|
||||
public static final CustomData EMPTY = new CustomData(CompoundBinaryTag.empty());
|
||||
|
||||
static final NetworkBuffer.Type<CustomData> NETWORK_TYPE = new NetworkBuffer.Type<>() {
|
||||
@Override
|
||||
@ -20,4 +23,17 @@ public record CustomData(@NotNull CompoundBinaryTag nbt) implements ItemComponen
|
||||
}
|
||||
};
|
||||
|
||||
static final BinaryTagSerializer<CustomData> NBT_TYPE = BinaryTagSerializer.COMPOUND.map(CustomData::new, CustomData::nbt);
|
||||
|
||||
@Override
|
||||
public <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) {
|
||||
return tag.read(nbt);
|
||||
}
|
||||
|
||||
public <T> @NotNull CustomData withTag(@NotNull Tag<T> tag, T value) {
|
||||
CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder();
|
||||
builder.put(nbt);
|
||||
tag.write(builder, value);
|
||||
return new CustomData(builder.build());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,57 @@
|
||||
package net.minestom.server.item.component;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.IntBinaryTag;
|
||||
import net.minestom.server.color.Color;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.utils.nbt.BinaryTagSerializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public record DyedItemColor(@NotNull Color color, boolean showInTooltip) {
|
||||
public static DyedItemColor LEATHER = new DyedItemColor(new Color(-6265536), true);
|
||||
|
||||
public static final NetworkBuffer.Type<DyedItemColor> NETWORK_TYPE = new NetworkBuffer.Type<>() {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, DyedItemColor value) {
|
||||
buffer.write(NetworkBuffer.COLOR, value.color);
|
||||
buffer.write(NetworkBuffer.BOOLEAN, value.showInTooltip);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DyedItemColor read(@NotNull NetworkBuffer buffer) {
|
||||
return new DyedItemColor(buffer.read(NetworkBuffer.COLOR), buffer.read(NetworkBuffer.BOOLEAN));
|
||||
}
|
||||
};
|
||||
|
||||
public static final BinaryTagSerializer<DyedItemColor> NBT_TYPE = new BinaryTagSerializer<>() {
|
||||
@Override
|
||||
public @NotNull BinaryTag write(@NotNull DyedItemColor value) {
|
||||
return CompoundBinaryTag.builder()
|
||||
.putInt("color", value.color.asRGB())
|
||||
.putBoolean("show_in_tooltip", value.showInTooltip)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull DyedItemColor read(@NotNull BinaryTag tag) {
|
||||
if (tag instanceof CompoundBinaryTag compoundTag) {
|
||||
int color = compoundTag.getInt("color");
|
||||
boolean showInTooltip = compoundTag.getBoolean("show_in_tooltip", true);
|
||||
return new DyedItemColor(new Color(color), showInTooltip);
|
||||
} else if (tag instanceof IntBinaryTag intTag) {
|
||||
return new DyedItemColor(new Color(intTag.intValue()), true);
|
||||
}
|
||||
return new DyedItemColor(new Color(0), false);
|
||||
}
|
||||
};
|
||||
|
||||
public @NotNull DyedItemColor withColor(@NotNull Color color) {
|
||||
return new DyedItemColor(color, showInTooltip);
|
||||
}
|
||||
|
||||
public @NotNull DyedItemColor withTooltip(boolean showInTooltip) {
|
||||
return new DyedItemColor(color, showInTooltip);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package net.minestom.server.item.component;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.item.Enchantment;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.utils.nbt.BinaryTagSerializer;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public record EnchantmentList(@NotNull Map<Enchantment, Integer> enchantments, boolean showInTooltip) {
|
||||
public static final EnchantmentList EMPTY = new EnchantmentList(Map.of(), true);
|
||||
|
||||
static NetworkBuffer.Type<EnchantmentList> NETWORK_TYPE = new NetworkBuffer.Type<>() {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, @NotNull EnchantmentList value) {
|
||||
buffer.write(NetworkBuffer.VAR_INT, value.enchantments.size());
|
||||
for (Map.Entry<Enchantment, Integer> entry : value.enchantments.entrySet()) {
|
||||
buffer.write(NetworkBuffer.VAR_INT, entry.getKey().id());
|
||||
buffer.write(NetworkBuffer.VAR_INT, entry.getValue());
|
||||
}
|
||||
buffer.write(NetworkBuffer.BOOLEAN, value.showInTooltip);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull EnchantmentList read(@NotNull NetworkBuffer buffer) {
|
||||
int size = buffer.read(NetworkBuffer.VAR_INT);
|
||||
Check.argCondition(size < 0 || size > Short.MAX_VALUE, "Invalid enchantment list size: {0}", size);
|
||||
Map<Enchantment, Integer> enchantments = new HashMap<>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
Enchantment enchantment = Enchantment.fromId(buffer.read(NetworkBuffer.VAR_INT));
|
||||
int level = buffer.read(NetworkBuffer.VAR_INT);
|
||||
enchantments.put(enchantment, level);
|
||||
}
|
||||
boolean showInTooltip = buffer.read(NetworkBuffer.BOOLEAN);
|
||||
return new EnchantmentList(enchantments, showInTooltip);
|
||||
}
|
||||
};
|
||||
|
||||
static BinaryTagSerializer<EnchantmentList> NBT_TYPE = BinaryTagSerializer.COMPOUND.map(
|
||||
tag -> {
|
||||
// We have two variants of the enchantment list, one with {levels: {...}, show_in_tooltip: boolean} and one with {...}.
|
||||
CompoundBinaryTag levels = tag.keySet().contains("levels") ? tag.getCompound("levels") : tag;
|
||||
Map<Enchantment, Integer> enchantments = new HashMap<>(levels.size());
|
||||
for (Map.Entry<String, ? extends BinaryTag> entry : levels) {
|
||||
Enchantment enchantment = Enchantment.fromNamespaceId(entry.getKey());
|
||||
Check.notNull(enchantment, "Unknown enchantment: {0}", entry.getKey());
|
||||
int level = BinaryTagSerializer.INT.read(entry.getValue());
|
||||
if (level > 0) enchantments.put(enchantment, level);
|
||||
}
|
||||
|
||||
// Doesnt matter which variant we chose, the default will work.
|
||||
boolean showInTooltip = tag.getBoolean("show_in_tooltip", true);
|
||||
return new EnchantmentList(enchantments, showInTooltip);
|
||||
},
|
||||
value -> {
|
||||
CompoundBinaryTag.Builder levels = CompoundBinaryTag.builder();
|
||||
for (Map.Entry<Enchantment, Integer> entry : value.enchantments.entrySet()) {
|
||||
levels.put(entry.getKey().name(), BinaryTagSerializer.INT.write(entry.getValue()));
|
||||
}
|
||||
|
||||
return CompoundBinaryTag.builder()
|
||||
.put("levels", levels.build())
|
||||
.putBoolean("show_in_tooltip", value.showInTooltip)
|
||||
.build();
|
||||
}
|
||||
);
|
||||
|
||||
public EnchantmentList {
|
||||
enchantments = Map.copyOf(enchantments);
|
||||
}
|
||||
|
||||
public @NotNull EnchantmentList with(@NotNull Enchantment enchantment, int level) {
|
||||
Map<Enchantment, Integer> newEnchantments = new HashMap<>(enchantments);
|
||||
newEnchantments.put(enchantment, level);
|
||||
return new EnchantmentList(newEnchantments, showInTooltip);
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
package net.minestom.server.item.component;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.color.Color;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.utils.nbt.BinaryTagSerializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public record FireworkExplosion(
|
||||
@NotNull Shape shape,
|
||||
@NotNull List<Color> colors,
|
||||
@NotNull List<Color> fadeColors,
|
||||
boolean hasTrail,
|
||||
boolean hasTwinkle
|
||||
) {
|
||||
|
||||
public enum Shape {
|
||||
SMALL_BALL,
|
||||
LARGE_BALL,
|
||||
STAR,
|
||||
CREEPER,
|
||||
BURST
|
||||
}
|
||||
|
||||
public static final NetworkBuffer.Type<FireworkExplosion> NETWORK_TYPE = new NetworkBuffer.Type<>() {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, FireworkExplosion value) {
|
||||
buffer.writeEnum(Shape.class, value.shape);
|
||||
buffer.writeCollection(NetworkBuffer.COLOR, value.colors);
|
||||
buffer.writeCollection(NetworkBuffer.COLOR, value.fadeColors);
|
||||
buffer.write(NetworkBuffer.BOOLEAN, value.hasTrail);
|
||||
buffer.write(NetworkBuffer.BOOLEAN, value.hasTwinkle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FireworkExplosion read(@NotNull NetworkBuffer buffer) {
|
||||
return new FireworkExplosion(
|
||||
buffer.readEnum(Shape.class),
|
||||
buffer.readCollection(NetworkBuffer.COLOR, Short.MAX_VALUE),
|
||||
buffer.readCollection(NetworkBuffer.COLOR, Short.MAX_VALUE),
|
||||
buffer.read(NetworkBuffer.BOOLEAN),
|
||||
buffer.read(NetworkBuffer.BOOLEAN)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
public static final BinaryTagSerializer<FireworkExplosion> NBT_TYPE = BinaryTagSerializer.COMPOUND.map(
|
||||
tag -> {
|
||||
Shape shape = Shape.valueOf(tag.getString("shape").toUpperCase(Locale.ROOT));
|
||||
List<Color> colors = new ArrayList<>();
|
||||
for (int color : tag.getIntArray("colors"))
|
||||
colors.add(new Color(color));
|
||||
List<Color> fadeColors = new ArrayList<>();
|
||||
for (int fadeColor : tag.getIntArray("fadeColors"))
|
||||
fadeColors.add(new Color(fadeColor));
|
||||
boolean hasTrail = tag.getBoolean("hasTrail");
|
||||
boolean hasTwinkle = tag.getBoolean("hasTwinkle");
|
||||
return new FireworkExplosion(shape, colors, fadeColors, hasTrail, hasTwinkle);
|
||||
},
|
||||
value -> {
|
||||
CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder();
|
||||
builder.putString("shape", value.shape.name().toLowerCase(Locale.ROOT));
|
||||
if (!value.colors.isEmpty()) {
|
||||
int[] colors = new int[value.colors.size()];
|
||||
for (int i = 0; i < value.colors.size(); i++)
|
||||
colors[i] = value.colors.get(i).asRGB();
|
||||
builder.putIntArray("colors", colors);
|
||||
}
|
||||
if (!value.fadeColors.isEmpty()) {
|
||||
int[] fadeColors = new int[value.fadeColors.size()];
|
||||
for (int i = 0; i < value.fadeColors.size(); i++)
|
||||
fadeColors[i] = value.fadeColors.get(i).asRGB();
|
||||
builder.putIntArray("fadeColors", fadeColors);
|
||||
}
|
||||
if (value.hasTrail) builder.putBoolean("hasTrail", value.hasTrail);
|
||||
if (value.hasTwinkle) builder.putBoolean("hasTwinkle", value.hasTwinkle);
|
||||
return builder.build();
|
||||
}
|
||||
);
|
||||
|
||||
public FireworkExplosion {
|
||||
colors = List.copyOf(colors);
|
||||
fadeColors = List.copyOf(fadeColors);
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package net.minestom.server.item.component;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.BinaryTagTypes;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.ListBinaryTag;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.utils.nbt.BinaryTagSerializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public record FireworkList(byte flightDuration, @NotNull List<FireworkExplosion> explosions) {
|
||||
public static final FireworkList EMPTY = new FireworkList((byte) 0, List.of());
|
||||
|
||||
public static final NetworkBuffer.Type<FireworkList> NETWORK_TYPE = new NetworkBuffer.Type<>() {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, FireworkList value) {
|
||||
buffer.write(NetworkBuffer.BYTE, value.flightDuration);
|
||||
buffer.writeCollection(FireworkExplosion.NETWORK_TYPE, value.explosions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FireworkList read(@NotNull NetworkBuffer buffer) {
|
||||
return new FireworkList(buffer.read(NetworkBuffer.BYTE),
|
||||
buffer.readCollection(FireworkExplosion.NETWORK_TYPE, 256));
|
||||
}
|
||||
};
|
||||
|
||||
public static final BinaryTagSerializer<FireworkList> NBT_TYPE = BinaryTagSerializer.COMPOUND.map(
|
||||
tag -> {
|
||||
byte flightDuration = tag.getByte("flight_duration");
|
||||
ListBinaryTag explosionsTag = tag.getList("explosions", BinaryTagTypes.COMPOUND);
|
||||
List<FireworkExplosion> explosions = new ArrayList<>(explosionsTag.size());
|
||||
for (BinaryTag explosionTag : explosionsTag)
|
||||
explosions.add(FireworkExplosion.NBT_TYPE.read(explosionTag));
|
||||
return new FireworkList(flightDuration, explosions);
|
||||
},
|
||||
value -> {
|
||||
ListBinaryTag.Builder<BinaryTag> explosionsTag = ListBinaryTag.builder();
|
||||
for (FireworkExplosion explosion : value.explosions)
|
||||
explosionsTag.add(FireworkExplosion.NBT_TYPE.write(explosion));
|
||||
return CompoundBinaryTag.builder()
|
||||
.putByte("flight_duration", value.flightDuration)
|
||||
.put("explosions", explosionsTag.build())
|
||||
.build();
|
||||
}
|
||||
);
|
||||
|
||||
public FireworkList {
|
||||
explosions = List.copyOf(explosions);
|
||||
}
|
||||
|
||||
public @NotNull FireworkList withFlightDuration(byte flightDuration) {
|
||||
return new FireworkList(flightDuration, explosions);
|
||||
}
|
||||
|
||||
public @NotNull FireworkList withExplosions(@NotNull List<FireworkExplosion> explosions) {
|
||||
return new FireworkList(flightDuration, explosions);
|
||||
}
|
||||
}
|
@ -1,20 +1,93 @@
|
||||
package net.minestom.server.item.component;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.color.Color;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.tag.Tag;
|
||||
import net.minestom.server.registry.StaticProtocolObject;
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
import net.minestom.server.utils.nbt.BinaryTagSerializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public sealed interface ItemComponent permits CustomData {
|
||||
import java.util.List;
|
||||
|
||||
ItemComponent.Type<CustomData> CUSTOM_DATA = new ItemComponent.Type<>("custom_data", CustomData.NETWORK_TYPE, CustomData.TAG);
|
||||
import static net.minestom.server.item.component.ItemComponentImpl.declare;
|
||||
|
||||
record Type<T extends ItemComponent>(
|
||||
@NotNull String name,
|
||||
@NotNull NetworkBuffer.Type<T> network,
|
||||
@NotNull Tag<T> tag
|
||||
) {
|
||||
public sealed interface ItemComponent<T> extends StaticProtocolObject permits ItemComponentImpl {
|
||||
// Note that even non-networked components are declared here as they still contribute to the component ID counter.
|
||||
|
||||
ItemComponent<CustomData> CUSTOM_DATA = declare("custom_data", CustomData.NETWORK_TYPE, CustomData.NBT_TYPE);
|
||||
ItemComponent<Integer> MAX_STACK_SIZE = declare("max_stack_size", NetworkBuffer.VAR_INT, BinaryTagSerializer.INT);
|
||||
ItemComponent<Integer> MAX_DAMAGE = declare("max_damage", NetworkBuffer.VAR_INT, BinaryTagSerializer.INT);
|
||||
ItemComponent<Integer> DAMAGE = declare("damage", NetworkBuffer.VAR_INT, BinaryTagSerializer.INT);
|
||||
ItemComponent<Unbreakable> UNBREAKABLE = declare("unbreakable", Unbreakable.NETWORK_TYPE, Unbreakable.NBT_TYPE);
|
||||
ItemComponent<Component> CUSTOM_NAME = declare("custom_name", NetworkBuffer.COMPONENT, BinaryTagSerializer.JSON_COMPONENT);
|
||||
ItemComponent<Component> ITEM_NAME = declare("item_name", NetworkBuffer.COMPONENT, BinaryTagSerializer.JSON_COMPONENT);
|
||||
ItemComponent<List<Component>> LORE = declare("lore", NetworkBuffer.COMPONENT.list(256), BinaryTagSerializer.JSON_COMPONENT.list());
|
||||
ItemComponent<ItemRarity> RARITY = declare("rarity", ItemRarity.NETWORK_TYPE, ItemRarity.NBT_TYPE);
|
||||
ItemComponent<EnchantmentList> ENCHANTMENTS = declare("enchantments", EnchantmentList.NETWORK_TYPE, EnchantmentList.NBT_TYPE);
|
||||
ItemComponent<Void> CAN_PLACE_ON = declare("can_place_on", null, null); //todo
|
||||
ItemComponent<Void> CAN_BREAK = declare("can_break", null, null); //todo
|
||||
ItemComponent<AttributeList> ATTRIBUTE_MODIFIERS = declare("attribute_modifiers", AttributeList.NETWORK_TYPE, AttributeList.NBT_TYPE);
|
||||
ItemComponent<Integer> CUSTOM_MODEL_DATA = declare("custom_model_data", NetworkBuffer.VAR_INT, BinaryTagSerializer.INT);
|
||||
ItemComponent<Void> HIDE_ADDITIONAL_TOOLTIP = declare("hide_additional_tooltip", NetworkBuffer.NOTHING, BinaryTagSerializer.NOTHING);
|
||||
ItemComponent<Void> HIDE_TOOLTIP = declare("hide_tooltip", NetworkBuffer.NOTHING, BinaryTagSerializer.NOTHING);
|
||||
ItemComponent<Integer> REPAIR_COST = declare("repair_cost", NetworkBuffer.VAR_INT, BinaryTagSerializer.INT);
|
||||
ItemComponent<Void> CREATIVE_SLOT_LOCK = declare("creative_slot_lock", NetworkBuffer.NOTHING, null);
|
||||
ItemComponent<Boolean> ENCHANTMENT_GLINT_OVERRIDE = declare("enchantment_glint_override", NetworkBuffer.BOOLEAN, BinaryTagSerializer.BOOLEAN);
|
||||
ItemComponent<Void> INTANGIBLE_PROJECTILE = declare("intangible_projectile", null, BinaryTagSerializer.NOTHING);
|
||||
ItemComponent<Void> FOOD = declare("food", null, null); //todo
|
||||
ItemComponent<Void> FIRE_RESISTANT = declare("fire_resistant", NetworkBuffer.NOTHING, BinaryTagSerializer.NOTHING);
|
||||
ItemComponent<Void> TOOL = declare("tool", null, null); //todo
|
||||
ItemComponent<EnchantmentList> STORED_ENCHANTMENTS = declare("stored_enchantments", EnchantmentList.NETWORK_TYPE, EnchantmentList.NBT_TYPE);
|
||||
ItemComponent<DyedItemColor> DYED_COLOR = declare("dyed_color", DyedItemColor.NETWORK_TYPE, DyedItemColor.NBT_TYPE);
|
||||
ItemComponent<Color> MAP_COLOR = declare("map_color", NetworkBuffer.COLOR, BinaryTagSerializer.INT.map(Color::new, Color::asRGB));
|
||||
ItemComponent<Integer> MAP_ID = declare("map_id", NetworkBuffer.VAR_INT, BinaryTagSerializer.INT);
|
||||
ItemComponent<MapDecorations> MAP_DECORATIONS = declare("map_decorations", null, MapDecorations.NBT_TYPE);
|
||||
ItemComponent<MapPostProcessing> MAP_POST_PROCESSING = declare("map_post_processing", MapPostProcessing.NETWORK_TYPE, null);
|
||||
ItemComponent<List<ItemStack>> CHARGED_PROJECTILES = declare("charged_projectiles", NetworkBuffer.ITEM.list(Short.MAX_VALUE), BinaryTagSerializer.ITEM.list());
|
||||
ItemComponent<List<ItemStack>> BUNDLE_CONTENTS = declare("bundle_contents", NetworkBuffer.ITEM.list(Short.MAX_VALUE), BinaryTagSerializer.ITEM.list());
|
||||
ItemComponent<Void> POTION_CONTENTS = declare("potion_contents", null, null); //todo
|
||||
ItemComponent<Void> SUSPICIOUS_STEW_EFFECTS = declare("suspicious_stew_effects", null, null); //todo
|
||||
ItemComponent<Void> WRITABLE_BOOK_CONTENT = declare("writable_book_content", null, null); //todo
|
||||
ItemComponent<Void> WRITTEN_BOOK_CONTENT = declare("written_book_content", null, null); //todo
|
||||
ItemComponent<Void> TRIM = declare("trim", null, null); //todo
|
||||
ItemComponent<Void> DEBUG_STICK_STATE = declare("debug_stick_state", null, null); //todo
|
||||
ItemComponent<CustomData> ENTITY_DATA = declare("entity_data", CustomData.NETWORK_TYPE, CustomData.NBT_TYPE);
|
||||
ItemComponent<CustomData> BUCKET_ENTITY_DATA = declare("bucket_entity_data", CustomData.NETWORK_TYPE, CustomData.NBT_TYPE);
|
||||
ItemComponent<CustomData> BLOCK_ENTITY_DATA = declare("block_entity_data", CustomData.NETWORK_TYPE, CustomData.NBT_TYPE);
|
||||
ItemComponent<Void> INSTRUMENT = declare("instrument", null, null); //todo
|
||||
ItemComponent<Integer> OMINOUS_BOTTLE_AMPLIFIER = declare("ominous_bottle_amplifier", NetworkBuffer.VAR_INT, BinaryTagSerializer.INT);
|
||||
ItemComponent<List<String>> RECIPES = declare("recipes", NetworkBuffer.STRING.list(Short.MAX_VALUE), BinaryTagSerializer.STRING.list());
|
||||
ItemComponent<LodestoneTracker> LODESTONE_TRACKER = declare("lodestone_tracker", LodestoneTracker.NETWORK_TYPE, LodestoneTracker.NBT_TYPE);
|
||||
ItemComponent<FireworkExplosion> FIREWORK_EXPLOSION = declare("firework_explosion", FireworkExplosion.NETWORK_TYPE, FireworkExplosion.NBT_TYPE);
|
||||
ItemComponent<FireworkList> FIREWORKS = declare("fireworks", FireworkList.NETWORK_TYPE, FireworkList.NBT_TYPE);
|
||||
ItemComponent<Void> PROFILE = declare("profile", null, null); //todo
|
||||
ItemComponent<String> NOTE_BLOCK_SOUND = declare("note_block_sound", NetworkBuffer.STRING, BinaryTagSerializer.STRING);
|
||||
ItemComponent<Void> BANNER_PATTERNS = declare("banner_patterns", null, null); //todo
|
||||
ItemComponent<Void> BASE_COLOR = declare("base_color", null, null); //todo dyecolor is the same stringrepresentable as item rarity
|
||||
ItemComponent<Void> POT_DECORATIONS = declare("pot_decorations", null, null); //todo
|
||||
ItemComponent<List<ItemStack>> CONTAINER = declare("container", NetworkBuffer.ITEM.list(256), BinaryTagSerializer.ITEM.list());
|
||||
ItemComponent<Void> BLOCK_STATE = declare("block_state", null, null); //todo
|
||||
ItemComponent<Void> BEES = declare("bees", null, null); //todo
|
||||
ItemComponent<String> LOCK = declare("lock", null, BinaryTagSerializer.STRING);
|
||||
ItemComponent<SeededContainerLoot> CONTAINER_LOOT = declare("container_loot", null, SeededContainerLoot.NBT_TYPE);
|
||||
|
||||
@NotNull T read(@NotNull BinaryTag tag);
|
||||
|
||||
@NotNull T read(@NotNull NetworkBuffer reader);
|
||||
|
||||
static @Nullable ItemComponent<?> fromNamespaceId(@NotNull String namespaceId) {
|
||||
return ItemComponentImpl.NAMESPACES.get(namespaceId);
|
||||
}
|
||||
|
||||
static @Nullable ItemComponent<?> fromNamespaceId(@NotNull NamespaceID namespaceId) {
|
||||
return fromNamespaceId(namespaceId.asString());
|
||||
}
|
||||
|
||||
static @Nullable ItemComponent<?> fromId(int id) {
|
||||
return ItemComponentImpl.IDS.get(id);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,47 @@
|
||||
package net.minestom.server.item.component;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
import net.minestom.server.utils.collection.ObjectArray;
|
||||
import net.minestom.server.utils.nbt.BinaryTagSerializer;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
record ItemComponentImpl<T>(
|
||||
int id,
|
||||
@NotNull NamespaceID namespace,
|
||||
@Nullable NetworkBuffer.Type<T> network,
|
||||
@Nullable BinaryTagSerializer<T> nbt
|
||||
) implements ItemComponent<T> {
|
||||
static final Map<String, ItemComponent<?>> NAMESPACES = new HashMap<>(32);
|
||||
static final ObjectArray<ItemComponent<?>> IDS = ObjectArray.singleThread(32);
|
||||
|
||||
static <T> ItemComponent<T> declare(@NotNull String name, @Nullable NetworkBuffer.Type<T> network, @Nullable BinaryTagSerializer<T> nbt) {
|
||||
ItemComponent<T> impl = new ItemComponentImpl<>(NAMESPACES.size(), NamespaceID.from(name), network, nbt);
|
||||
NAMESPACES.put(impl.name(), impl);
|
||||
IDS.set(impl.id(), impl);
|
||||
return impl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull T read(@NotNull BinaryTag tag) {
|
||||
Check.notNull(nbt, "{0} cannot be deserialized from NBT", this);
|
||||
return nbt.read(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull T read(@NotNull NetworkBuffer reader) {
|
||||
Check.notNull(network, "{0} cannot be deserialized from network", this);
|
||||
return network.read(reader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name();
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package net.minestom.server.item.component;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface ItemComponentMap {
|
||||
|
||||
static @NotNull Builder builder() {
|
||||
//todo
|
||||
}
|
||||
|
||||
boolean has(@NotNull ItemComponent<?> component);
|
||||
|
||||
<T> @Nullable T get(@NotNull ItemComponent<T> component);
|
||||
|
||||
default <T> @NotNull T get(@NotNull ItemComponent<T> component, @NotNull T defaultValue) {
|
||||
T value = get(component);
|
||||
return value != null ? value : defaultValue;
|
||||
}
|
||||
|
||||
@NotNull CompoundBinaryTag asCompound();
|
||||
|
||||
interface Builder {
|
||||
|
||||
<T> @NotNull Builder set(@NotNull ItemComponent<T> component, @NotNull T value);
|
||||
|
||||
void remove(@NotNull ItemComponent<?> component);
|
||||
|
||||
@NotNull ItemComponentMap build();
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package net.minestom.server.item.component;
|
||||
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface ItemComponentPatch extends ItemComponentMap {
|
||||
|
||||
static ItemComponentPatch EMPTY = new ItemComponentPatch() {
|
||||
@Override public boolean has(@NotNull ItemComponent<?> component) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public <T> @Nullable T get(@NotNull ItemComponent<T> component) {
|
||||
return null;
|
||||
}
|
||||
}; //todo
|
||||
|
||||
|
||||
<T> @NotNull ItemComponentPatch with(@NotNull ItemComponent<T> component, T value);
|
||||
|
||||
@NotNull ItemComponentPatch without(@NotNull ItemComponent<?> component);
|
||||
|
||||
@NotNull Builder builder();
|
||||
|
||||
interface Builder extends ItemComponentMap {
|
||||
|
||||
@Contract(value = "_, _ -> this", pure = true)
|
||||
<T> @NotNull Builder set(@NotNull ItemComponent<T> component, @NotNull T value);
|
||||
|
||||
@Contract(value = "_ -> this", pure = true)
|
||||
@NotNull Builder remove(@NotNull ItemComponent<?> component);
|
||||
|
||||
@Contract(value = "-> new", pure = true)
|
||||
@NotNull ItemComponentPatch build();
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package net.minestom.server.item.component;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.IntBinaryTag;
|
||||
import net.kyori.adventure.nbt.StringBinaryTag;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.utils.nbt.BinaryTagSerializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public enum ItemRarity {
|
||||
COMMON,
|
||||
UNCOMMON,
|
||||
RARE,
|
||||
EPIC;
|
||||
|
||||
private static final ItemRarity[] VALUES = values();
|
||||
|
||||
static final NetworkBuffer.Type<ItemRarity> NETWORK_TYPE = new NetworkBuffer.Type<ItemRarity>() {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, ItemRarity value) {
|
||||
buffer.writeEnum(ItemRarity.class, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemRarity read(@NotNull NetworkBuffer buffer) {
|
||||
return buffer.readEnum(ItemRarity.class);
|
||||
}
|
||||
};
|
||||
|
||||
static final BinaryTagSerializer<ItemRarity> NBT_TYPE = new BinaryTagSerializer<>() {
|
||||
@Override
|
||||
public @NotNull BinaryTag write(@NotNull ItemRarity value) {
|
||||
return IntBinaryTag.intBinaryTag(value.ordinal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemRarity read(@NotNull BinaryTag tag) {
|
||||
return switch (tag) {
|
||||
case IntBinaryTag intBinaryTag -> VALUES[intBinaryTag.value()];
|
||||
case StringBinaryTag stringBinaryTag -> valueOf(stringBinaryTag.value().toUpperCase(Locale.ROOT));
|
||||
default -> COMMON;
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package net.minestom.server.item.component;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.utils.nbt.BinaryTagSerializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public record LodestoneTracker(@NotNull String dimension, @NotNull Point blockPosition, boolean tracked) {
|
||||
|
||||
public static final NetworkBuffer.Type<LodestoneTracker> NETWORK_TYPE = new NetworkBuffer.Type<>() {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, @NotNull LodestoneTracker value) {
|
||||
buffer.write(NetworkBuffer.STRING, value.dimension);
|
||||
buffer.write(NetworkBuffer.BLOCK_POSITION, value.blockPosition);
|
||||
buffer.write(NetworkBuffer.BOOLEAN, value.tracked);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull LodestoneTracker read(@NotNull NetworkBuffer buffer) {
|
||||
return new LodestoneTracker(
|
||||
buffer.read(NetworkBuffer.STRING),
|
||||
buffer.read(NetworkBuffer.BLOCK_POSITION),
|
||||
buffer.read(NetworkBuffer.BOOLEAN)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
public static final BinaryTagSerializer<LodestoneTracker> NBT_TYPE = new BinaryTagSerializer<>() {
|
||||
@Override
|
||||
public @NotNull BinaryTag write(@NotNull LodestoneTracker value) {
|
||||
throw new UnsupportedOperationException("Not implemented"); //todo
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull LodestoneTracker read(@NotNull BinaryTag tag) {
|
||||
throw new UnsupportedOperationException("Not implemented"); //todo
|
||||
}
|
||||
};
|
||||
|
||||
public @NotNull LodestoneTracker withDimension(@NotNull String dimension) {
|
||||
return new LodestoneTracker(dimension, blockPosition, tracked);
|
||||
}
|
||||
|
||||
public @NotNull LodestoneTracker withBlockPosition(@NotNull Point blockPosition) {
|
||||
return new LodestoneTracker(dimension, blockPosition, tracked);
|
||||
}
|
||||
|
||||
public @NotNull LodestoneTracker withTracked(boolean tracked) {
|
||||
return new LodestoneTracker(dimension, blockPosition, tracked);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package net.minestom.server.item.component;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.utils.nbt.BinaryTagSerializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public record MapDecorations(@NotNull Map<String, Entry> decorations) {
|
||||
|
||||
public record Entry(@NotNull String type, double x, double z, float rotation) {
|
||||
}
|
||||
|
||||
static final BinaryTagSerializer<MapDecorations> NBT_TYPE = BinaryTagSerializer.COMPOUND.map(
|
||||
tag -> {
|
||||
Map<String, Entry> map = new HashMap<>(tag.size());
|
||||
for (Map.Entry<String, ? extends BinaryTag> entry : tag) {
|
||||
if (!(entry instanceof CompoundBinaryTag entryTag)) continue;
|
||||
map.put(entry.getKey(), new Entry(
|
||||
entryTag.getString("type"),
|
||||
entryTag.getDouble("x"),
|
||||
entryTag.getDouble("z"),
|
||||
entryTag.getFloat("rotation")
|
||||
));
|
||||
}
|
||||
return new MapDecorations(map);
|
||||
},
|
||||
decorations -> {
|
||||
CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder();
|
||||
for (Map.Entry<String, Entry> entry : decorations.decorations.entrySet()) {
|
||||
CompoundBinaryTag entryTag = CompoundBinaryTag.builder()
|
||||
.putString("type", entry.getValue().type)
|
||||
.putDouble("x", entry.getValue().x)
|
||||
.putDouble("z", entry.getValue().z)
|
||||
.putFloat("rotation", entry.getValue().rotation)
|
||||
.build();
|
||||
builder.put(entry.getKey(), entryTag);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
);
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package net.minestom.server.item.component;
|
||||
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
|
||||
public enum MapPostProcessing {
|
||||
LOCK,
|
||||
SCALE;
|
||||
private static final MapPostProcessing[] VALUES = values();
|
||||
|
||||
public static final NetworkBuffer.Type<MapPostProcessing> NETWORK_TYPE = new NetworkBuffer.Type<>() {
|
||||
@Override
|
||||
public void write(NetworkBuffer buffer, MapPostProcessing value) {
|
||||
buffer.write(NetworkBuffer.VAR_INT, value.ordinal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapPostProcessing read(NetworkBuffer buffer) {
|
||||
return VALUES[buffer.read(NetworkBuffer.VAR_INT)];
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package net.minestom.server.item.component;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.utils.nbt.BinaryTagSerializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public record PotDecorations(
|
||||
@NotNull Material back,
|
||||
@NotNull Material left,
|
||||
@NotNull Material right,
|
||||
@NotNull Material front
|
||||
) {
|
||||
public static final PotDecorations EMPTY = new PotDecorations(Material.AIR, Material.AIR, Material.AIR, Material.AIR);
|
||||
|
||||
public static NetworkBuffer.Type<PotDecorations> NETWORK_TYPE = new NetworkBuffer.Type<>() {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, PotDecorations value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public PotDecorations read(@NotNull NetworkBuffer buffer) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
public static BinaryTagSerializer<PotDecorations> NBT_TYPE = new BinaryTagSerializer<>() {
|
||||
@Override
|
||||
public @NotNull BinaryTag write(@NotNull PotDecorations value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PotDecorations read(@NotNull BinaryTag tag) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package net.minestom.server.item.component;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.utils.nbt.BinaryTagSerializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public record SeededContainerLoot(@NotNull String lootTable, long seed) {
|
||||
|
||||
public static final BinaryTagSerializer<SeededContainerLoot> NBT_TYPE = BinaryTagSerializer.COMPOUND.map(
|
||||
tag -> new SeededContainerLoot(tag.getString("loot_table"), tag.getLong("seed")),
|
||||
loot -> CompoundBinaryTag.builder()
|
||||
.putString("loot_table", loot.lootTable)
|
||||
.putLong("seed", loot.seed)
|
||||
.build()
|
||||
);
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package net.minestom.server.item.component;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.utils.nbt.BinaryTagSerializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public record Unbreakable(boolean showInTooltip) {
|
||||
public static final Unbreakable DEFAULT = new Unbreakable(false);
|
||||
|
||||
public static final NetworkBuffer.Type<Unbreakable> NETWORK_TYPE = new NetworkBuffer.Type<Unbreakable>() {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, Unbreakable value) {
|
||||
buffer.write(NetworkBuffer.BOOLEAN, value.showInTooltip());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Unbreakable read(@NotNull NetworkBuffer buffer) {
|
||||
return new Unbreakable(buffer.read(NetworkBuffer.BOOLEAN));
|
||||
}
|
||||
};
|
||||
|
||||
public static final BinaryTagSerializer<Unbreakable> NBT_TYPE = BinaryTagSerializer.COMPOUND.map(
|
||||
tag -> new Unbreakable(tag.getBoolean("showInTooltip", false)),
|
||||
unbreakable -> CompoundBinaryTag.builder().putBoolean("showInTooltip", unbreakable.showInTooltip()).build()
|
||||
);
|
||||
|
||||
}
|
@ -2,11 +2,13 @@ package net.minestom.server.item.firework;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.color.Color;
|
||||
import net.minestom.server.item.component.FireworkExplosion;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Deprecated
|
||||
public record FireworkEffect(boolean flicker, boolean trail,
|
||||
@NotNull FireworkEffectType type,
|
||||
@NotNull List<Color> colors,
|
||||
@ -16,6 +18,12 @@ public record FireworkEffect(boolean flicker, boolean trail,
|
||||
fadeColors = List.copyOf(fadeColors);
|
||||
}
|
||||
|
||||
public FireworkEffect(@NotNull FireworkExplosion explosion) {
|
||||
this(explosion.hasTwinkle(), explosion.hasTrail(),
|
||||
FireworkEffectType.fromExplosionShape(explosion.shape()),
|
||||
explosion.colors(), explosion.fadeColors());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a firework effect from the given {@code compound}.
|
||||
*
|
||||
@ -52,4 +60,11 @@ public record FireworkEffect(boolean flicker, boolean trail,
|
||||
.putIntArray("FadeColors", fadeColors.stream().mapToInt(Color::asRGB).toArray())
|
||||
.build();
|
||||
}
|
||||
|
||||
public @NotNull FireworkExplosion toExplosion() {
|
||||
return new FireworkExplosion(
|
||||
type.toExplosionShape(),
|
||||
colors, fadeColors,
|
||||
trail, flicker);
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,13 @@ package net.minestom.server.item.firework;
|
||||
|
||||
import it.unimi.dsi.fastutil.bytes.Byte2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.bytes.Byte2ObjectOpenHashMap;
|
||||
import net.minestom.server.item.component.FireworkExplosion;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* An enumeration that representing all available firework types.
|
||||
*/
|
||||
@Deprecated
|
||||
public enum FireworkEffectType {
|
||||
SMALL_BALL((byte) 0),
|
||||
LARGE_BALL((byte) 1),
|
||||
@ -37,6 +40,16 @@ public enum FireworkEffectType {
|
||||
return BY_ID.get(id);
|
||||
}
|
||||
|
||||
public static FireworkEffectType fromExplosionShape(@NotNull FireworkExplosion.Shape shape) {
|
||||
return switch (shape) {
|
||||
case SMALL_BALL -> SMALL_BALL;
|
||||
case LARGE_BALL -> LARGE_BALL;
|
||||
case STAR -> STAR_SHAPED;
|
||||
case CREEPER -> CREEPER_SHAPED;
|
||||
case BURST -> BURST;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the type of the firework effect.
|
||||
*
|
||||
@ -45,5 +58,15 @@ public enum FireworkEffectType {
|
||||
public byte getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public FireworkExplosion.Shape toExplosionShape() {
|
||||
return switch (this) {
|
||||
case SMALL_BALL -> FireworkExplosion.Shape.SMALL_BALL;
|
||||
case LARGE_BALL -> FireworkExplosion.Shape.LARGE_BALL;
|
||||
case STAR_SHAPED -> FireworkExplosion.Shape.STAR;
|
||||
case CREEPER_SHAPED -> FireworkExplosion.Shape.CREEPER;
|
||||
case BURST -> FireworkExplosion.Shape.BURST;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,51 +2,51 @@ package net.minestom.server.item.metadata;
|
||||
|
||||
import net.minestom.server.item.ItemMetaView;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.component.CustomData;
|
||||
import net.minestom.server.item.component.ItemComponent;
|
||||
import net.minestom.server.item.component.ItemComponentPatch;
|
||||
import net.minestom.server.tag.Tag;
|
||||
import net.minestom.server.tag.TagHandler;
|
||||
import net.minestom.server.tag.TagReadable;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ApiStatus.Experimental
|
||||
public record BundleMeta(TagReadable readable) implements ItemMetaView<BundleMeta.Builder> {
|
||||
private static final Tag<List<ItemStack>> ITEMS = Tag.ItemStack("Items").list().defaultValue(List.of());
|
||||
@Deprecated
|
||||
public record BundleMeta(ItemComponentPatch components) implements ItemMetaView<BundleMeta.Builder> {
|
||||
|
||||
public @NotNull List<ItemStack> getItems() {
|
||||
return getTag(ITEMS);
|
||||
return components.get(ItemComponent.BUNDLE_CONTENTS, List.of());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) {
|
||||
return readable.getTag(tag);
|
||||
return components.get(ItemComponent.CUSTOM_DATA, CustomData.EMPTY).getTag(tag);
|
||||
}
|
||||
|
||||
public record Builder(TagHandler tagHandler) implements ItemMetaView.Builder {
|
||||
public Builder() {
|
||||
this(TagHandler.newHandler());
|
||||
}
|
||||
@Deprecated
|
||||
public record Builder(ItemComponentPatch.Builder components) implements ItemMetaView.Builder {
|
||||
|
||||
public Builder items(@NotNull List<ItemStack> items) {
|
||||
setTag(ITEMS, items);
|
||||
if (items.isEmpty()) {
|
||||
components.remove(ItemComponent.BUNDLE_CONTENTS);
|
||||
} else {
|
||||
components.set(ItemComponent.BUNDLE_CONTENTS, items);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@ApiStatus.Experimental
|
||||
public Builder addItem(@NotNull ItemStack item) {
|
||||
var newList = new ArrayList<>(getTag(ITEMS));
|
||||
var newList = new ArrayList<>(components.get(ItemComponent.BUNDLE_CONTENTS, List.of()));
|
||||
newList.add(item);
|
||||
return items(newList);
|
||||
}
|
||||
|
||||
@ApiStatus.Experimental
|
||||
public Builder removeItem(@NotNull ItemStack item) {
|
||||
var newList = new ArrayList<>(getTag(ITEMS));
|
||||
var newList = new ArrayList<>(components.get(ItemComponent.BUNDLE_CONTENTS, List.of()));
|
||||
newList.remove(item);
|
||||
return items(newList);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -3,66 +3,58 @@ package net.minestom.server.item.metadata;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.coordinate.Vec;
|
||||
import net.minestom.server.item.ItemMetaView;
|
||||
import net.minestom.server.tag.*;
|
||||
import net.minestom.server.item.component.CustomData;
|
||||
import net.minestom.server.item.component.ItemComponent;
|
||||
import net.minestom.server.item.component.ItemComponentPatch;
|
||||
import net.minestom.server.item.component.LodestoneTracker;
|
||||
import net.minestom.server.tag.Tag;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
|
||||
public record CompassMeta(TagReadable readable) implements ItemMetaView<CompassMeta.Builder> {
|
||||
private static final Tag<Boolean> LODESTONE_TRACKED = Tag.Boolean("LodestoneTracked").defaultValue(false);
|
||||
private static final Tag<String> LODESTONE_DIMENSION = Tag.String("LodestoneDimension");
|
||||
private static final Tag<Point> LODESTONE_POSITION = Tag.Structure("LodestonePos", new TagSerializer<>() {
|
||||
@Override
|
||||
public @Nullable Point read(@NotNull TagReadable reader) {
|
||||
final Integer x = reader.getTag(Tag.Integer("X"));
|
||||
final Integer y = reader.getTag(Tag.Integer("Y"));
|
||||
final Integer z = reader.getTag(Tag.Integer("Z"));
|
||||
if (x == null || y == null || z == null) return null;
|
||||
return new Vec(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull TagWritable writer, @NotNull Point value) {
|
||||
writer.setTag(Tag.Integer("X"), value.blockX());
|
||||
writer.setTag(Tag.Integer("Y"), value.blockY());
|
||||
writer.setTag(Tag.Integer("Z"), value.blockZ());
|
||||
}
|
||||
});
|
||||
@Deprecated
|
||||
public record CompassMeta(@NotNull ItemComponentPatch components) implements ItemMetaView<CompassMeta.Builder> {
|
||||
|
||||
public boolean isLodestoneTracked() {
|
||||
return getTag(LODESTONE_TRACKED);
|
||||
LodestoneTracker tracker = components.get(ItemComponent.LODESTONE_TRACKER);
|
||||
return tracker != null && tracker.tracked();
|
||||
}
|
||||
|
||||
public @Nullable String getLodestoneDimension() {
|
||||
return getTag(LODESTONE_DIMENSION);
|
||||
LodestoneTracker tracker = components.get(ItemComponent.LODESTONE_TRACKER);
|
||||
return tracker == null ? null : tracker.dimension();
|
||||
}
|
||||
|
||||
public @Nullable Point getLodestonePosition() {
|
||||
return getTag(LODESTONE_POSITION);
|
||||
LodestoneTracker tracker = components.get(ItemComponent.LODESTONE_TRACKER);
|
||||
return tracker == null ? null : tracker.blockPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) {
|
||||
return readable.getTag(tag);
|
||||
return components.get(ItemComponent.CUSTOM_DATA, CustomData.EMPTY).getTag(tag);
|
||||
}
|
||||
|
||||
public record Builder(TagHandler tagHandler) implements ItemMetaView.Builder {
|
||||
public Builder() {
|
||||
this(TagHandler.newHandler());
|
||||
}
|
||||
@Deprecated
|
||||
public record Builder(@NotNull ItemComponentPatch.Builder components) implements ItemMetaView.Builder {
|
||||
// The empty state isnt really valid because the dimension is empty (invalid), but these functions need to set each so its simpler.
|
||||
private static final LodestoneTracker EMPTY = new LodestoneTracker("", Vec.ZERO, false);
|
||||
|
||||
public Builder lodestoneTracked(boolean lodestoneTracked) {
|
||||
setTag(LODESTONE_TRACKED, lodestoneTracked);
|
||||
LodestoneTracker tracker = components.get(ItemComponent.LODESTONE_TRACKER, EMPTY);
|
||||
components.set(ItemComponent.LODESTONE_TRACKER, tracker.withTracked(lodestoneTracked));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder lodestoneDimension(@Nullable String lodestoneDimension) {
|
||||
setTag(LODESTONE_DIMENSION, lodestoneDimension);
|
||||
LodestoneTracker tracker = components.get(ItemComponent.LODESTONE_TRACKER, EMPTY);
|
||||
components.set(ItemComponent.LODESTONE_TRACKER, tracker.withDimension(lodestoneDimension));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder lodestonePosition(@Nullable Point lodestonePosition) {
|
||||
setTag(LODESTONE_POSITION, lodestonePosition);
|
||||
LodestoneTracker tracker = components.get(ItemComponent.LODESTONE_TRACKER, EMPTY);
|
||||
components.set(ItemComponent.LODESTONE_TRACKER, tracker.withBlockPosition(lodestonePosition));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -2,48 +2,52 @@ package net.minestom.server.item.metadata;
|
||||
|
||||
import net.minestom.server.item.ItemMetaView;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.component.CustomData;
|
||||
import net.minestom.server.item.component.ItemComponent;
|
||||
import net.minestom.server.item.component.ItemComponentPatch;
|
||||
import net.minestom.server.tag.Tag;
|
||||
import net.minestom.server.tag.TagHandler;
|
||||
import net.minestom.server.tag.TagReadable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record CrossbowMeta(TagReadable readable) implements ItemMetaView<CrossbowMeta.Builder> {
|
||||
private static final Tag<List<ItemStack>> PROJECTILES = Tag.ItemStack("ChargedProjectiles").list().defaultValue(List.of());
|
||||
private static final Tag<Boolean> CHARGED = Tag.Boolean("Charged").defaultValue(false);
|
||||
@Deprecated
|
||||
public record CrossbowMeta(@NotNull ItemComponentPatch components) implements ItemMetaView<CrossbowMeta.Builder> {
|
||||
|
||||
public @NotNull List<ItemStack> getProjectiles() {
|
||||
return getTag(PROJECTILES);
|
||||
return components.get(ItemComponent.CHARGED_PROJECTILES, List.of());
|
||||
}
|
||||
|
||||
public boolean isCharged() {
|
||||
return getTag(CHARGED);
|
||||
return components.has(ItemComponent.CHARGED_PROJECTILES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) {
|
||||
return readable.getTag(tag);
|
||||
return components.get(ItemComponent.CUSTOM_DATA, CustomData.EMPTY).getTag(tag);
|
||||
}
|
||||
|
||||
public record Builder(TagHandler tagHandler) implements ItemMetaView.Builder {
|
||||
public Builder() {
|
||||
this(TagHandler.newHandler());
|
||||
}
|
||||
@Deprecated
|
||||
public record Builder(@NotNull ItemComponentPatch.Builder components) implements ItemMetaView.Builder {
|
||||
|
||||
public Builder projectile(@NotNull ItemStack projectile) {
|
||||
setTag(PROJECTILES, List.of(projectile));
|
||||
components.set(ItemComponent.CHARGED_PROJECTILES, List.of(projectile));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder projectiles(@NotNull ItemStack projectile1, @NotNull ItemStack projectile2, @NotNull ItemStack projectile3) {
|
||||
setTag(PROJECTILES, List.of(projectile1, projectile2, projectile3));
|
||||
components.set(ItemComponent.CHARGED_PROJECTILES, List.of(projectile1, projectile2, projectile3));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder charged(boolean charged) {
|
||||
setTag(CHARGED, charged);
|
||||
if (charged) {
|
||||
// Only reset to empty list if we dont have any projectiles yet, as to not overwrite the call to projectiles()
|
||||
if (!components.has(ItemComponent.CHARGED_PROJECTILES))
|
||||
components.set(ItemComponent.CHARGED_PROJECTILES, List.of());
|
||||
} else {
|
||||
components.remove(ItemComponent.CHARGED_PROJECTILES);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -2,55 +2,49 @@ package net.minestom.server.item.metadata;
|
||||
|
||||
import net.minestom.server.item.Enchantment;
|
||||
import net.minestom.server.item.ItemMetaView;
|
||||
import net.minestom.server.item.ItemSerializers;
|
||||
import net.minestom.server.item.component.CustomData;
|
||||
import net.minestom.server.item.component.EnchantmentList;
|
||||
import net.minestom.server.item.component.ItemComponent;
|
||||
import net.minestom.server.item.component.ItemComponentPatch;
|
||||
import net.minestom.server.tag.Tag;
|
||||
import net.minestom.server.tag.TagHandler;
|
||||
import net.minestom.server.tag.TagReadable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static net.minestom.server.item.ItemSerializers.ENCHANTMENT_SERIALIZER;
|
||||
|
||||
public record EnchantedBookMeta(TagReadable readable) implements ItemMetaView<EnchantedBookMeta.Builder> {
|
||||
static final Tag<Map<Enchantment, Short>> ENCHANTMENTS = Tag.Structure("StoredEnchantments", ENCHANTMENT_SERIALIZER).list().map(enchantmentEntry -> {
|
||||
Map<Enchantment, Short> map = new HashMap<>();
|
||||
for (var entry : enchantmentEntry) map.put(entry.enchantment(), entry.level());
|
||||
return Map.copyOf(map);
|
||||
}, o -> {
|
||||
List<ItemSerializers.EnchantmentEntry> entries = new ArrayList<>();
|
||||
for (var entry : o.entrySet())
|
||||
entries.add(new ItemSerializers.EnchantmentEntry(entry.getKey(), entry.getValue()));
|
||||
return List.copyOf(entries);
|
||||
}).defaultValue(Map.of());
|
||||
@Deprecated
|
||||
public record EnchantedBookMeta(@NotNull ItemComponentPatch components) implements ItemMetaView<EnchantedBookMeta.Builder> {
|
||||
|
||||
public @NotNull Map<Enchantment, Short> getStoredEnchantmentMap() {
|
||||
return getTag(ENCHANTMENTS);
|
||||
EnchantmentList value = components.get(ItemComponent.STORED_ENCHANTMENTS, EnchantmentList.EMPTY);
|
||||
Map<Enchantment, Short> map = new HashMap<>();
|
||||
for (var entry : value.enchantments().entrySet())
|
||||
map.put(entry.getKey(), entry.getValue().shortValue());
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) {
|
||||
return readable.getTag(tag);
|
||||
return components.get(ItemComponent.CUSTOM_DATA, CustomData.EMPTY).getTag(tag);
|
||||
}
|
||||
|
||||
public record Builder(TagHandler tagHandler) implements ItemMetaView.Builder {
|
||||
public Builder() {
|
||||
this(TagHandler.newHandler());
|
||||
}
|
||||
@Deprecated
|
||||
public record Builder(@NotNull ItemComponentPatch.Builder components) implements ItemMetaView.Builder {
|
||||
|
||||
public @NotNull Builder enchantments(@NotNull Map<Enchantment, Short> enchantments) {
|
||||
setTag(ENCHANTMENTS, Map.copyOf(enchantments));
|
||||
Map<Enchantment, Integer> map = new HashMap<>();
|
||||
enchantments.forEach((enchantment, level) -> map.put(enchantment, (int) level));
|
||||
// Fetch existing to preserve the showInTooltip value.
|
||||
EnchantmentList existing = components.get(ItemComponent.STORED_ENCHANTMENTS, EnchantmentList.EMPTY);
|
||||
components.set(ItemComponent.STORED_ENCHANTMENTS, new EnchantmentList(map, existing.showInTooltip()));
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull Builder enchantment(@NotNull Enchantment enchantment, short level) {
|
||||
var enchantments = new HashMap<>(getTag(ENCHANTMENTS));
|
||||
enchantments.put(enchantment, level);
|
||||
return enchantments(enchantments);
|
||||
EnchantmentList value = components.get(ItemComponent.STORED_ENCHANTMENTS, EnchantmentList.EMPTY);
|
||||
components.set(ItemComponent.STORED_ENCHANTMENTS, value.with(enchantment, level));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,35 +1,34 @@
|
||||
package net.minestom.server.item.metadata;
|
||||
|
||||
import net.minestom.server.item.ItemMetaView;
|
||||
import net.minestom.server.item.component.*;
|
||||
import net.minestom.server.item.firework.FireworkEffect;
|
||||
import net.minestom.server.tag.Tag;
|
||||
import net.minestom.server.tag.TagHandler;
|
||||
import net.minestom.server.tag.TagReadable;
|
||||
import net.minestom.server.tag.TagSerializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
|
||||
public record FireworkEffectMeta(TagReadable readable) implements ItemMetaView<FireworkEffectMeta.Builder> {
|
||||
private static final Tag<FireworkEffect> FIREWORK_EFFECT = Tag.Structure("Explosion",
|
||||
TagSerializer.fromCompound(FireworkEffect::fromCompound, FireworkEffect::asCompound));
|
||||
|
||||
@Deprecated
|
||||
public record FireworkEffectMeta(@NotNull ItemComponentPatch components) implements ItemMetaView<FireworkEffectMeta.Builder> {
|
||||
public @Nullable FireworkEffect getFireworkEffect() {
|
||||
return getTag(FIREWORK_EFFECT);
|
||||
FireworkExplosion explosion = components.get(ItemComponent.FIREWORK_EXPLOSION);
|
||||
return explosion == null ? null : new FireworkEffect(explosion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) {
|
||||
return readable.getTag(tag);
|
||||
return components.get(ItemComponent.CUSTOM_DATA, CustomData.EMPTY).getTag(tag);
|
||||
}
|
||||
|
||||
public record Builder(TagHandler tagHandler) implements ItemMetaView.Builder {
|
||||
public Builder() {
|
||||
this(TagHandler.newHandler());
|
||||
}
|
||||
@Deprecated
|
||||
public record Builder(@NotNull ItemComponentMap.Builder components) implements ItemMetaView.Builder {
|
||||
|
||||
public Builder effect(@Nullable FireworkEffect fireworkEffect) {
|
||||
setTag(FIREWORK_EFFECT, fireworkEffect);
|
||||
if (fireworkEffect == null) {
|
||||
components.remove(ItemComponent.FIREWORK_EXPLOSION);
|
||||
} else {
|
||||
components.set(ItemComponent.FIREWORK_EXPLOSION, fireworkEffect.toExplosion());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -1,48 +1,48 @@
|
||||
package net.minestom.server.item.metadata;
|
||||
|
||||
import net.minestom.server.item.ItemMetaView;
|
||||
import net.minestom.server.item.component.CustomData;
|
||||
import net.minestom.server.item.component.FireworkList;
|
||||
import net.minestom.server.item.component.ItemComponent;
|
||||
import net.minestom.server.item.component.ItemComponentPatch;
|
||||
import net.minestom.server.item.firework.FireworkEffect;
|
||||
import net.minestom.server.tag.Tag;
|
||||
import net.minestom.server.tag.TagHandler;
|
||||
import net.minestom.server.tag.TagReadable;
|
||||
import net.minestom.server.tag.TagSerializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record FireworkMeta(TagReadable readable) implements ItemMetaView<FireworkMeta.Builder> {
|
||||
private static final Tag<List<FireworkEffect>> EFFECTS = Tag.Structure("Explosions",
|
||||
TagSerializer.fromCompound(FireworkEffect::fromCompound, FireworkEffect::asCompound))
|
||||
.path("Fireworks").list().defaultValue(List.of());
|
||||
private static final Tag<Byte> FLIGHT_DURATION = Tag.Byte("Flight").path("Fireworks");
|
||||
@Deprecated
|
||||
public record FireworkMeta(@NotNull ItemComponentPatch components) implements ItemMetaView<FireworkMeta.Builder> {
|
||||
|
||||
public @NotNull List<FireworkEffect> getEffects() {
|
||||
return getTag(EFFECTS);
|
||||
FireworkList value = components.get(ItemComponent.FIREWORKS);
|
||||
return value == null ? List.of() : value.explosions().stream().map(FireworkEffect::new).toList();
|
||||
}
|
||||
|
||||
public @Nullable Byte getFlightDuration() {
|
||||
return getTag(FLIGHT_DURATION);
|
||||
FireworkList value = components.get(ItemComponent.FIREWORKS);
|
||||
return value == null ? null : value.flightDuration();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) {
|
||||
return readable.getTag(tag);
|
||||
return components.get(ItemComponent.CUSTOM_DATA, CustomData.EMPTY).getTag(tag);
|
||||
}
|
||||
|
||||
public record Builder(TagHandler tagHandler) implements ItemMetaView.Builder {
|
||||
public Builder() {
|
||||
this(TagHandler.newHandler());
|
||||
}
|
||||
@Deprecated
|
||||
public record Builder(@NotNull ItemComponentPatch.Builder components) implements ItemMetaView.Builder {
|
||||
|
||||
public Builder effects(List<FireworkEffect> effects) {
|
||||
setTag(EFFECTS, effects);
|
||||
FireworkList value = components.get(ItemComponent.FIREWORKS, FireworkList.EMPTY);
|
||||
components.set(ItemComponent.FIREWORKS, value.withExplosions(effects.stream().map(FireworkEffect::toExplosion).toList()));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder flightDuration(byte flightDuration) {
|
||||
setTag(FLIGHT_DURATION, flightDuration);
|
||||
FireworkList value = components.get(ItemComponent.FIREWORKS, FireworkList.EMPTY);
|
||||
components.set(ItemComponent.FIREWORKS, value.withFlightDuration(flightDuration));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -2,32 +2,38 @@ package net.minestom.server.item.metadata;
|
||||
|
||||
import net.minestom.server.color.Color;
|
||||
import net.minestom.server.item.ItemMetaView;
|
||||
import net.minestom.server.item.component.CustomData;
|
||||
import net.minestom.server.item.component.DyedItemColor;
|
||||
import net.minestom.server.item.component.ItemComponent;
|
||||
import net.minestom.server.item.component.ItemComponentPatch;
|
||||
import net.minestom.server.tag.Tag;
|
||||
import net.minestom.server.tag.TagHandler;
|
||||
import net.minestom.server.tag.TagReadable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
|
||||
public record LeatherArmorMeta(TagReadable readable) implements ItemMetaView<LeatherArmorMeta.Builder> {
|
||||
private static final Tag<Color> COLOR = Tag.Integer("color").path("display").map(Color::new, Color::asRGB);
|
||||
@Deprecated
|
||||
public record LeatherArmorMeta(@NotNull ItemComponentPatch components) implements ItemMetaView<LeatherArmorMeta.Builder> {
|
||||
|
||||
public @Nullable Color getColor() {
|
||||
return getTag(COLOR);
|
||||
DyedItemColor value = components.get(ItemComponent.DYED_COLOR);
|
||||
return value == null ? null : value.color();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) {
|
||||
return readable.getTag(tag);
|
||||
return components.get(ItemComponent.CUSTOM_DATA, CustomData.EMPTY).getTag(tag);
|
||||
}
|
||||
|
||||
public record Builder(TagHandler tagHandler) implements ItemMetaView.Builder {
|
||||
public Builder() {
|
||||
this(TagHandler.newHandler());
|
||||
}
|
||||
@Deprecated
|
||||
public record Builder(@NotNull ItemComponentPatch.Builder components) implements ItemMetaView.Builder {
|
||||
|
||||
public Builder color(@Nullable Color color) {
|
||||
setTag(COLOR, color);
|
||||
if (color == null) {
|
||||
components.remove(ItemComponent.DYED_COLOR);
|
||||
} else {
|
||||
DyedItemColor value = components.get(ItemComponent.DYED_COLOR, DyedItemColor.LEATHER);
|
||||
components.set(ItemComponent.DYED_COLOR, value.withColor(color));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -2,14 +2,21 @@ package net.minestom.server.item.metadata;
|
||||
|
||||
import net.minestom.server.color.Color;
|
||||
import net.minestom.server.item.ItemMetaView;
|
||||
import net.minestom.server.tag.*;
|
||||
import net.minestom.server.item.component.CustomData;
|
||||
import net.minestom.server.item.component.ItemComponent;
|
||||
import net.minestom.server.item.component.ItemComponentMap;
|
||||
import net.minestom.server.item.component.ItemComponentPatch;
|
||||
import net.minestom.server.tag.Tag;
|
||||
import net.minestom.server.tag.TagReadable;
|
||||
import net.minestom.server.tag.TagSerializer;
|
||||
import net.minestom.server.tag.TagWritable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record MapMeta(TagReadable readable) implements ItemMetaView<MapMeta.Builder> {
|
||||
public record MapMeta(@NotNull ItemComponentPatch components) implements ItemMetaView<MapMeta.Builder> {
|
||||
private static final Tag<Integer> MAP_ID = Tag.Integer("map").defaultValue(0);
|
||||
private static final Tag<Integer> MAP_SCALE_DIRECTION = Tag.Integer("map_scale_direction").defaultValue(0);
|
||||
private static final Tag<List<Decoration>> DECORATIONS = Tag.Structure("Decorations", new TagSerializer<Decoration>() {
|
||||
@ -53,13 +60,10 @@ public record MapMeta(TagReadable readable) implements ItemMetaView<MapMeta.Buil
|
||||
|
||||
@Override
|
||||
public <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) {
|
||||
return readable.getTag(tag);
|
||||
return components.get(ItemComponent.CUSTOM_DATA, CustomData.EMPTY).getTag(tag);
|
||||
}
|
||||
|
||||
public record Builder(TagHandler tagHandler) implements ItemMetaView.Builder {
|
||||
public Builder() {
|
||||
this(TagHandler.newHandler());
|
||||
}
|
||||
public record Builder(@NotNull ItemComponentMap.Builder components) implements ItemMetaView.Builder {
|
||||
|
||||
public Builder mapId(int value) {
|
||||
setTag(MAP_ID, value);
|
||||
|
@ -6,7 +6,14 @@ import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.ListBinaryTag;
|
||||
import net.minestom.server.entity.PlayerSkin;
|
||||
import net.minestom.server.item.ItemMetaView;
|
||||
import net.minestom.server.tag.*;
|
||||
import net.minestom.server.item.component.CustomData;
|
||||
import net.minestom.server.item.component.ItemComponent;
|
||||
import net.minestom.server.item.component.ItemComponentMap;
|
||||
import net.minestom.server.item.component.ItemComponentPatch;
|
||||
import net.minestom.server.tag.Tag;
|
||||
import net.minestom.server.tag.TagReadable;
|
||||
import net.minestom.server.tag.TagSerializer;
|
||||
import net.minestom.server.tag.TagWritable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
@ -15,7 +22,7 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
public record PlayerHeadMeta(TagReadable readable) implements ItemMetaView<PlayerHeadMeta.Builder> {
|
||||
public record PlayerHeadMeta(@NotNull ItemComponentPatch components) implements ItemMetaView<PlayerHeadMeta.Builder> {
|
||||
public static final Tag<UUID> SKULL_OWNER = Tag.UUID("Id").path("SkullOwner");
|
||||
public static final Tag<PlayerSkin> SKIN = Tag.Structure("Properties", new TagSerializer<PlayerSkin>() {
|
||||
private static final Tag<BinaryTag> TEXTURES = Tag.NBT("textures");
|
||||
@ -50,13 +57,10 @@ public record PlayerHeadMeta(TagReadable readable) implements ItemMetaView<Playe
|
||||
|
||||
@Override
|
||||
public <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) {
|
||||
return readable.getTag(tag);
|
||||
return components.get(ItemComponent.CUSTOM_DATA, CustomData.EMPTY).getTag(tag);
|
||||
}
|
||||
|
||||
public record Builder(TagHandler tagHandler) implements ItemMetaView.Builder {
|
||||
public Builder() {
|
||||
this(TagHandler.newHandler());
|
||||
}
|
||||
public record Builder(@NotNull ItemComponentMap.Builder components) implements ItemMetaView.Builder {
|
||||
|
||||
public Builder skullOwner(@Nullable UUID skullOwner) {
|
||||
setTag(SKULL_OWNER, skullOwner);
|
||||
|
@ -2,17 +2,24 @@ package net.minestom.server.item.metadata;
|
||||
|
||||
import net.minestom.server.color.Color;
|
||||
import net.minestom.server.item.ItemMetaView;
|
||||
import net.minestom.server.item.component.CustomData;
|
||||
import net.minestom.server.item.component.ItemComponent;
|
||||
import net.minestom.server.item.component.ItemComponentMap;
|
||||
import net.minestom.server.item.component.ItemComponentPatch;
|
||||
import net.minestom.server.potion.CustomPotionEffect;
|
||||
import net.minestom.server.potion.PotionType;
|
||||
import net.minestom.server.registry.StaticProtocolObject;
|
||||
import net.minestom.server.tag.*;
|
||||
import net.minestom.server.tag.Tag;
|
||||
import net.minestom.server.tag.TagReadable;
|
||||
import net.minestom.server.tag.TagSerializer;
|
||||
import net.minestom.server.tag.TagWritable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record PotionMeta(TagReadable readable) implements ItemMetaView<PotionMeta.Builder> {
|
||||
public record PotionMeta(@NotNull ItemComponentPatch components) implements ItemMetaView<PotionMeta.Builder> {
|
||||
private static final Tag<PotionType> POTION_TYPE = Tag.String("Potion").map(PotionType::fromNamespaceId, StaticProtocolObject::name).defaultValue(PotionType.WATER);
|
||||
private static final Tag<List<CustomPotionEffect>> CUSTOM_POTION_EFFECTS = Tag.Structure("CustomPotionEffects", new TagSerializer<CustomPotionEffect>() {
|
||||
@Override
|
||||
@ -55,13 +62,10 @@ public record PotionMeta(TagReadable readable) implements ItemMetaView<PotionMet
|
||||
|
||||
@Override
|
||||
public <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) {
|
||||
return readable.getTag(tag);
|
||||
return components.get(ItemComponent.CUSTOM_DATA, CustomData.EMPTY).getTag(tag);
|
||||
}
|
||||
|
||||
public record Builder(TagHandler tagHandler) implements ItemMetaView.Builder {
|
||||
public Builder() {
|
||||
this(TagHandler.newHandler());
|
||||
}
|
||||
public record Builder(@NotNull ItemComponentMap.Builder components) implements ItemMetaView.Builder {
|
||||
|
||||
public Builder potionType(@NotNull PotionType potionType) {
|
||||
setTag(POTION_TYPE, potionType);
|
||||
|
@ -3,15 +3,16 @@ package net.minestom.server.item.metadata;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.minestom.server.item.ItemMetaView;
|
||||
import net.minestom.server.item.component.CustomData;
|
||||
import net.minestom.server.item.component.ItemComponent;
|
||||
import net.minestom.server.item.component.ItemComponentPatch;
|
||||
import net.minestom.server.tag.Tag;
|
||||
import net.minestom.server.tag.TagHandler;
|
||||
import net.minestom.server.tag.TagReadable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record WritableBookMeta(TagReadable readable) implements ItemMetaView<WritableBookMeta.Builder> {
|
||||
public record WritableBookMeta(@NotNull ItemComponentPatch components) implements ItemMetaView<WritableBookMeta.Builder> {
|
||||
private static final Tag<List<Component>> PAGES = Tag.String("pages")
|
||||
.<Component>map(s -> LegacyComponentSerializer.legacySection().deserialize(s),
|
||||
textComponent -> LegacyComponentSerializer.legacySection().serialize(textComponent))
|
||||
@ -23,13 +24,10 @@ public record WritableBookMeta(TagReadable readable) implements ItemMetaView<Wri
|
||||
|
||||
@Override
|
||||
public <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) {
|
||||
return readable.getTag(tag);
|
||||
return components.get(ItemComponent.CUSTOM_DATA, CustomData.EMPTY).getTag(tag);
|
||||
}
|
||||
|
||||
public record Builder(TagHandler tagHandler) implements ItemMetaView.Builder {
|
||||
public Builder() {
|
||||
this(TagHandler.newHandler());
|
||||
}
|
||||
public record Builder(@NotNull ItemComponentPatch.Builder components) implements ItemMetaView.Builder {
|
||||
|
||||
public Builder pages(@NotNull List<@NotNull Component> pages) {
|
||||
setTag(PAGES, pages);
|
||||
|
@ -4,9 +4,11 @@ import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.minestom.server.item.ItemMetaView;
|
||||
import net.minestom.server.item.component.CustomData;
|
||||
import net.minestom.server.item.component.ItemComponent;
|
||||
import net.minestom.server.item.component.ItemComponentMap;
|
||||
import net.minestom.server.item.component.ItemComponentPatch;
|
||||
import net.minestom.server.tag.Tag;
|
||||
import net.minestom.server.tag.TagHandler;
|
||||
import net.minestom.server.tag.TagReadable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
@ -14,7 +16,7 @@ import org.jetbrains.annotations.UnknownNullability;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public record WrittenBookMeta(TagReadable readable) implements ItemMetaView<WrittenBookMeta.Builder> {
|
||||
public record WrittenBookMeta(@NotNull ItemComponentPatch components) implements ItemMetaView<WrittenBookMeta.Builder> {
|
||||
private static final Tag<Boolean> RESOLVED = Tag.Boolean("resolved").defaultValue(false);
|
||||
private static final Tag<WrittenBookGeneration> GENERATION = Tag.Integer("resolved").map(integer -> WrittenBookGeneration.values()[integer], Enum::ordinal);
|
||||
private static final Tag<String> AUTHOR = Tag.String("author");
|
||||
@ -45,17 +47,14 @@ public record WrittenBookMeta(TagReadable readable) implements ItemMetaView<Writ
|
||||
|
||||
@Override
|
||||
public <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) {
|
||||
return readable.getTag(tag);
|
||||
return components.get(ItemComponent.CUSTOM_DATA, CustomData.EMPTY).getTag(tag);
|
||||
}
|
||||
|
||||
public enum WrittenBookGeneration {
|
||||
ORIGINAL, COPY_OF_ORIGINAL, COPY_OF_COPY, TATTERED
|
||||
}
|
||||
|
||||
public record Builder(TagHandler tagHandler) implements ItemMetaView.Builder {
|
||||
public Builder() {
|
||||
this(TagHandler.newHandler());
|
||||
}
|
||||
public record Builder(@NotNull ItemComponentMap.Builder components) implements ItemMetaView.Builder {
|
||||
|
||||
public Builder resolved(boolean resolved) {
|
||||
setTag(RESOLVED, resolved);
|
||||
|
@ -1,40 +0,0 @@
|
||||
package net.minestom.server.item.rule;
|
||||
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.StackingRule;
|
||||
import net.minestom.server.utils.MathUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public final class VanillaStackingRule implements StackingRule {
|
||||
|
||||
@Override
|
||||
public boolean canBeStacked(@NotNull ItemStack item1, @NotNull ItemStack item2) {
|
||||
return item1.isSimilar(item2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canApply(@NotNull ItemStack item, int newAmount) {
|
||||
return MathUtils.isBetween(newAmount, 0, getMaxSize(item));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack apply(@NotNull ItemStack item, int amount) {
|
||||
return amount > 0 ? item.withAmount(amount) : ItemStack.AIR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAmount(@NotNull ItemStack itemStack) {
|
||||
return itemStack.amount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxSize(@NotNull ItemStack itemStack) {
|
||||
return itemStack.material().maxStackSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
return obj != null && getClass() == obj.getClass();
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package net.minestom.server.network;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.color.Color;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.metadata.animal.ArmadilloMeta;
|
||||
@ -29,6 +30,7 @@ import java.util.function.Function;
|
||||
|
||||
@ApiStatus.Experimental
|
||||
public final class NetworkBuffer {
|
||||
public static final Type<Void> NOTHING = new NetworkBufferTypeImpl.NothingType();
|
||||
public static final Type<Boolean> BOOLEAN = new NetworkBufferTypeImpl.BooleanType();
|
||||
public static final Type<Byte> BYTE = new NetworkBufferTypeImpl.ByteType();
|
||||
public static final Type<Short> SHORT = new NetworkBufferTypeImpl.ShortType();
|
||||
@ -75,6 +77,7 @@ public final class NetworkBuffer {
|
||||
public static final Type<SnifferMeta.State> SNIFFER_STATE = NetworkBufferTypeImpl.fromEnum(SnifferMeta.State.class);
|
||||
public static final Type<ArmadilloMeta.State> ARMADILLO_STATE = NetworkBufferTypeImpl.fromEnum(ArmadilloMeta.State.class);
|
||||
|
||||
public static final Type<Color> COLOR = new NetworkBufferTypeImpl.ColorType();
|
||||
|
||||
ByteBuffer nioBuffer;
|
||||
final boolean resizable;
|
||||
@ -293,8 +296,21 @@ public final class NetworkBuffer {
|
||||
|
||||
public interface Type<T> {
|
||||
void write(@NotNull NetworkBuffer buffer, T value);
|
||||
|
||||
T read(@NotNull NetworkBuffer buffer);
|
||||
|
||||
default @NotNull Type<List<T>> list(int maxSize) {
|
||||
return new NetworkBuffer.Type<>() {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, List<T> value) {
|
||||
buffer.writeCollection(Type.this, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> read(@NotNull NetworkBuffer buffer) {
|
||||
return buffer.readCollection(Type.this, maxSize);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
|
@ -5,10 +5,12 @@ import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.minestom.server.adventure.serializer.nbt.NbtComponentSerializer;
|
||||
import net.minestom.server.color.Color;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.coordinate.Vec;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.item.component.ItemComponent;
|
||||
import net.minestom.server.network.packet.server.play.data.WorldPos;
|
||||
import net.minestom.server.particle.Particle;
|
||||
import net.minestom.server.particle.data.ParticleData;
|
||||
@ -27,6 +29,17 @@ interface NetworkBufferTypeImpl<T> extends NetworkBuffer.Type<T> {
|
||||
int SEGMENT_BITS = 0x7F;
|
||||
int CONTINUE_BIT = 0x80;
|
||||
|
||||
record NothingType() implements NetworkBufferTypeImpl<Void> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, Void value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void read(@NotNull NetworkBuffer buffer) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
record BooleanType() implements NetworkBufferTypeImpl<Boolean> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, Boolean value) {
|
||||
@ -403,8 +416,11 @@ interface NetworkBufferTypeImpl<T> extends NetworkBuffer.Type<T> {
|
||||
}
|
||||
buffer.write(VAR_INT, value.amount());
|
||||
buffer.write(VAR_INT, value.material().id());
|
||||
buffer.write(VAR_INT, 0); // Added components
|
||||
buffer.write(VAR_INT, 1); // Added components
|
||||
buffer.write(VAR_INT, 0); // Removed components
|
||||
var component = ItemComponent.MAX_STACK_SIZE;
|
||||
buffer.write(VAR_INT, component.id());
|
||||
buffer.write(VAR_INT, 16);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -600,6 +616,18 @@ interface NetworkBufferTypeImpl<T> extends NetworkBuffer.Type<T> {
|
||||
}
|
||||
}
|
||||
|
||||
record ColorType() implements NetworkBufferTypeImpl<Color> {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, Color value) {
|
||||
buffer.write(NetworkBuffer.INT, value.asRGB());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color read(@NotNull NetworkBuffer buffer) {
|
||||
return new Color(buffer.read(NetworkBuffer.INT));
|
||||
}
|
||||
}
|
||||
|
||||
static <T extends Enum<?>> NetworkBufferTypeImpl<T> fromEnum(Class<T> enumClass) {
|
||||
return new NetworkBufferTypeImpl<>() {
|
||||
@Override
|
||||
|
@ -9,20 +9,19 @@ import net.minestom.server.collision.BoundingBox;
|
||||
import net.minestom.server.collision.CollisionUtils;
|
||||
import net.minestom.server.collision.Shape;
|
||||
import net.minestom.server.entity.EntitySpawnType;
|
||||
import net.minestom.server.entity.EntityType;
|
||||
import net.minestom.server.entity.EquipmentSlot;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.item.component.ItemComponent;
|
||||
import net.minestom.server.item.component.ItemComponentMap;
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
import net.minestom.server.utils.collection.ObjectArray;
|
||||
import net.minestom.server.utils.nbt.BinaryTagReader;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Supplier;
|
||||
@ -475,12 +474,11 @@ public final class Registry {
|
||||
private final NamespaceID namespace;
|
||||
private final int id;
|
||||
private final String translationKey;
|
||||
private final int maxStackSize;
|
||||
private final int maxDamage;
|
||||
private final boolean isFood;
|
||||
private final Supplier<Block> blockSupplier;
|
||||
private final EquipmentSlot equipmentSlot;
|
||||
private final EntityType entityType;
|
||||
private final ItemComponentMap prototype;
|
||||
|
||||
// private final EquipmentSlot equipmentSlot; //todo
|
||||
// private final EntityType entityType; //todo
|
||||
private final Properties custom;
|
||||
|
||||
private MaterialEntry(String namespace, Properties main, Properties custom) {
|
||||
@ -488,35 +486,47 @@ public final class Registry {
|
||||
this.namespace = NamespaceID.from(namespace);
|
||||
this.id = main.getInt("id");
|
||||
this.translationKey = main.getString("translationKey");
|
||||
this.maxStackSize = main.getInt("maxStackSize", 64);
|
||||
this.maxDamage = main.getInt("maxDamage", 0);
|
||||
this.isFood = main.getBoolean("edible", false);
|
||||
{
|
||||
final String blockNamespace = main.getString("correspondingBlock", null);
|
||||
this.blockSupplier = blockNamespace != null ? () -> Block.fromNamespaceId(blockNamespace) : () -> null;
|
||||
}
|
||||
{
|
||||
final Properties armorProperties = main.section("armorProperties");
|
||||
if (armorProperties != null) {
|
||||
switch (armorProperties.getString("slot")) {
|
||||
case "feet" -> this.equipmentSlot = EquipmentSlot.BOOTS;
|
||||
case "legs" -> this.equipmentSlot = EquipmentSlot.LEGGINGS;
|
||||
case "chest" -> this.equipmentSlot = EquipmentSlot.CHESTPLATE;
|
||||
case "head" -> this.equipmentSlot = EquipmentSlot.HELMET;
|
||||
default -> this.equipmentSlot = null;
|
||||
}
|
||||
} else {
|
||||
this.equipmentSlot = null;
|
||||
}
|
||||
}
|
||||
{
|
||||
final Properties spawnEggProperties = main.section("spawnEggProperties");
|
||||
if (spawnEggProperties != null) {
|
||||
this.entityType = EntityType.fromNamespaceId(spawnEggProperties.getString("entityType"));
|
||||
} else {
|
||||
this.entityType = null;
|
||||
try {
|
||||
ItemComponentMap.Builder builder = ItemComponentMap.builder();
|
||||
for (Map.Entry<String, Object> entry : main.section("components")) {
|
||||
//noinspection unchecked
|
||||
ItemComponent<Object> component = (ItemComponent<Object>) ItemComponent.fromNamespaceId(entry.getKey());
|
||||
Check.notNull(component, "Unknown component: " + entry.getKey());
|
||||
|
||||
byte[] rawValue = Base64.getDecoder().decode((String) entry.getValue());
|
||||
BinaryTagReader reader = new BinaryTagReader(new DataInputStream(new ByteArrayInputStream(rawValue)));
|
||||
builder.set(component, component.read(reader.readNameless()));
|
||||
}
|
||||
this.prototype = builder.build();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("failed to parse material registry: " + namespace, e);
|
||||
}
|
||||
// {
|
||||
// final Properties armorProperties = main.section("armorProperties");
|
||||
// if (armorProperties != null) {
|
||||
// switch (armorProperties.getString("slot")) {
|
||||
// case "feet" -> this.equipmentSlot = EquipmentSlot.BOOTS;
|
||||
// case "legs" -> this.equipmentSlot = EquipmentSlot.LEGGINGS;
|
||||
// case "chest" -> this.equipmentSlot = EquipmentSlot.CHESTPLATE;
|
||||
// case "head" -> this.equipmentSlot = EquipmentSlot.HELMET;
|
||||
// default -> this.equipmentSlot = null;
|
||||
// }
|
||||
// } else {
|
||||
// this.equipmentSlot = null;
|
||||
// }
|
||||
// }
|
||||
// {
|
||||
// final Properties spawnEggProperties = main.section("spawnEggProperties");
|
||||
// if (spawnEggProperties != null) {
|
||||
// this.entityType = EntityType.fromNamespaceId(spawnEggProperties.getString("entityType"));
|
||||
// } else {
|
||||
// this.entityType = null;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
public @NotNull NamespaceID namespace() {
|
||||
@ -527,41 +537,33 @@ public final class Registry {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String translationKey() {
|
||||
public @NotNull String translationKey() {
|
||||
return translationKey;
|
||||
}
|
||||
|
||||
public int maxStackSize() {
|
||||
return maxStackSize;
|
||||
}
|
||||
|
||||
public int maxDamage() {
|
||||
return maxDamage;
|
||||
}
|
||||
|
||||
public boolean isFood() {
|
||||
return isFood;
|
||||
}
|
||||
|
||||
public @Nullable Block block() {
|
||||
return blockSupplier.get();
|
||||
}
|
||||
|
||||
public boolean isArmor() {
|
||||
return equipmentSlot != null;
|
||||
public @NotNull ItemComponentMap prototype() {
|
||||
return prototype;
|
||||
}
|
||||
|
||||
public @Nullable EquipmentSlot equipmentSlot() {
|
||||
return equipmentSlot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the entity type this item can spawn. Only present for spawn eggs (e.g. wolf spawn egg, skeleton spawn egg)
|
||||
* @return The entity type it can spawn, or null if it is not a spawn egg
|
||||
*/
|
||||
public @Nullable EntityType spawnEntityType() {
|
||||
return entityType;
|
||||
}
|
||||
// public boolean isArmor() {
|
||||
// return equipmentSlot != null;
|
||||
// }
|
||||
//
|
||||
// public @Nullable EquipmentSlot equipmentSlot() {
|
||||
// return equipmentSlot;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Gets the entity type this item can spawn. Only present for spawn eggs (e.g. wolf spawn egg, skeleton spawn egg)
|
||||
// * @return The entity type it can spawn, or null if it is not a spawn egg
|
||||
// */
|
||||
// public @Nullable EntityType spawnEntityType() {
|
||||
// return entityType;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public Properties custom() {
|
||||
|
@ -5,8 +5,8 @@ import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.minestom.server.ServerFlag;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.utils.UniqueIdUtils;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
@ -23,9 +23,7 @@ final class Serializers {
|
||||
static final Entry<String, StringBinaryTag> STRING = new Entry<>(BinaryTagTypes.STRING, StringBinaryTag::value, StringBinaryTag::stringBinaryTag);
|
||||
static final Entry<BinaryTag, BinaryTag> NBT_ENTRY = new Entry<>(null, Function.identity(), Function.identity());
|
||||
|
||||
static final Entry<java.util.UUID, IntArrayBinaryTag> UUID = new Entry<>(BinaryTagTypes.INT_ARRAY,
|
||||
intArray -> intArrayToUuid(intArray.value()),
|
||||
uuid -> IntArrayBinaryTag.intArrayBinaryTag(uuidToIntArray(uuid)));
|
||||
static final Entry<java.util.UUID, IntArrayBinaryTag> UUID = new Entry<>(BinaryTagTypes.INT_ARRAY, UniqueIdUtils::fromNbt, UniqueIdUtils::toNbt);
|
||||
static final Entry<ItemStack, CompoundBinaryTag> ITEM = new Entry<>(BinaryTagTypes.COMPOUND, ItemStack::fromItemNBT, ItemStack::toItemNBT);
|
||||
static final Entry<Component, StringBinaryTag> COMPONENT = new Entry<>(BinaryTagTypes.STRING, input -> GsonComponentSerializer.gson().deserialize(input.value()),
|
||||
component -> StringBinaryTag.stringBinaryTag(GsonComponentSerializer.gson().serialize(component)));
|
||||
@ -59,22 +57,4 @@ final class Serializers {
|
||||
return writer.apply(value);
|
||||
}
|
||||
}
|
||||
|
||||
private static int[] uuidToIntArray(UUID uuid) {
|
||||
final long uuidMost = uuid.getMostSignificantBits();
|
||||
final long uuidLeast = uuid.getLeastSignificantBits();
|
||||
return new int[]{
|
||||
(int) (uuidMost >> 32),
|
||||
(int) uuidMost,
|
||||
(int) (uuidLeast >> 32),
|
||||
(int) uuidLeast
|
||||
};
|
||||
}
|
||||
|
||||
private static UUID intArrayToUuid(int[] array) {
|
||||
final long uuidMost = (long) array[0] << 32 | array[1] & 0xFFFFFFFFL;
|
||||
final long uuidLeast = (long) array[2] << 32 | array[3] & 0xFFFFFFFFL;
|
||||
|
||||
return new UUID(uuidMost, uuidLeast);
|
||||
}
|
||||
}
|
||||
|
@ -263,7 +263,6 @@ public class Tag<T> {
|
||||
return tag(key, Serializers.STRING);
|
||||
}
|
||||
|
||||
@ApiStatus.Experimental
|
||||
public static @NotNull Tag<UUID> UUID(@NotNull String key) {
|
||||
return tag(key, Serializers.UUID);
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package net.minestom.server.utils;
|
||||
|
||||
import net.kyori.adventure.nbt.IntArrayBinaryTag;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Pattern;
|
||||
@ -21,4 +23,30 @@ public final class UniqueIdUtils {
|
||||
public static boolean isUniqueId(String input) {
|
||||
return input.matches(UNIQUE_ID_PATTERN.pattern());
|
||||
}
|
||||
|
||||
public static @NotNull UUID fromNbt(@NotNull IntArrayBinaryTag tag) {
|
||||
return intArrayToUuid(tag.value());
|
||||
}
|
||||
|
||||
public static @NotNull IntArrayBinaryTag toNbt(@NotNull UUID uuid) {
|
||||
return IntArrayBinaryTag.intArrayBinaryTag(uuidToIntArray(uuid));
|
||||
}
|
||||
|
||||
public static int[] uuidToIntArray(UUID uuid) {
|
||||
final long uuidMost = uuid.getMostSignificantBits();
|
||||
final long uuidLeast = uuid.getLeastSignificantBits();
|
||||
return new int[]{
|
||||
(int) (uuidMost >> 32),
|
||||
(int) uuidMost,
|
||||
(int) (uuidLeast >> 32),
|
||||
(int) uuidLeast
|
||||
};
|
||||
}
|
||||
|
||||
public static UUID intArrayToUuid(int[] array) {
|
||||
final long uuidMost = (long) array[0] << 32 | array[1] & 0xFFFFFFFFL;
|
||||
final long uuidLeast = (long) array[2] << 32 | array[3] & 0xFFFFFFFFL;
|
||||
|
||||
return new UUID(uuidMost, uuidLeast);
|
||||
}
|
||||
}
|
||||
|
@ -33,5 +33,4 @@ public class BinaryTagReader {
|
||||
String name = input.readUTF();
|
||||
return Map.entry(name, type.read(input));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,119 @@
|
||||
package net.minestom.server.utils.nbt;
|
||||
|
||||
import net.kyori.adventure.nbt.*;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public interface BinaryTagSerializer<T> {
|
||||
|
||||
BinaryTagSerializer<Void> NOTHING = new BinaryTagSerializer<>() {
|
||||
@Override
|
||||
public @NotNull BinaryTag write(@NotNull Void value) {
|
||||
return EndBinaryTag.endBinaryTag();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Void read(@NotNull BinaryTag tag) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
BinaryTagSerializer<Byte> BYTE = new BinaryTagSerializer<>() {
|
||||
@Override
|
||||
public @NotNull BinaryTag write(@NotNull Byte value) {
|
||||
return ByteBinaryTag.byteBinaryTag(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Byte read(@NotNull BinaryTag tag) {
|
||||
return tag instanceof ByteBinaryTag byteBinaryTag ? byteBinaryTag.value() : 0;
|
||||
}
|
||||
};
|
||||
|
||||
BinaryTagSerializer<Boolean> BOOLEAN = BYTE.map(b -> b != 0, b -> (byte) (b ? 1 : 0));
|
||||
|
||||
BinaryTagSerializer<Integer> INT = new BinaryTagSerializer<>() {
|
||||
@Override
|
||||
public @NotNull BinaryTag write(@NotNull Integer value) {
|
||||
return IntBinaryTag.intBinaryTag(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Integer read(@NotNull BinaryTag tag) {
|
||||
return tag instanceof IntBinaryTag intBinaryTag ? intBinaryTag.value() : 0;
|
||||
}
|
||||
};
|
||||
|
||||
BinaryTagSerializer<String> STRING = new BinaryTagSerializer<>() {
|
||||
@Override
|
||||
public @NotNull BinaryTag write(@NotNull String value) {
|
||||
return StringBinaryTag.stringBinaryTag(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String read(@NotNull BinaryTag tag) {
|
||||
return tag instanceof StringBinaryTag stringBinaryTag ? stringBinaryTag.value() : "";
|
||||
}
|
||||
};
|
||||
|
||||
BinaryTagSerializer<CompoundBinaryTag> COMPOUND = new BinaryTagSerializer<>() {
|
||||
@Override
|
||||
public @NotNull BinaryTag write(@NotNull CompoundBinaryTag value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CompoundBinaryTag read(@NotNull BinaryTag tag) {
|
||||
return tag instanceof CompoundBinaryTag compoundBinaryTag ? compoundBinaryTag : CompoundBinaryTag.empty();
|
||||
}
|
||||
};
|
||||
|
||||
BinaryTagSerializer<Component> JSON_COMPONENT = STRING.map(
|
||||
s -> GsonComponentSerializer.gson().deserialize(s),
|
||||
c -> GsonComponentSerializer.gson().serialize(c)
|
||||
);
|
||||
BinaryTagSerializer<ItemStack> ITEM = COMPOUND.map(ItemStack::fromItemNBT, ItemStack::toItemNBT);
|
||||
|
||||
@NotNull BinaryTag write(@NotNull T value);
|
||||
@NotNull T read(@NotNull BinaryTag tag);
|
||||
|
||||
default <S> BinaryTagSerializer<S> map(@NotNull Function<T, S> to, @NotNull Function<S, T> from) {
|
||||
return new BinaryTagSerializer<>() {
|
||||
@Override
|
||||
public @NotNull BinaryTag write(@NotNull S value) {
|
||||
return BinaryTagSerializer.this.write(from.apply(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull S read(@NotNull BinaryTag tag) {
|
||||
return to.apply(BinaryTagSerializer.this.read(tag));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
default BinaryTagSerializer<List<T>> list() {
|
||||
return new BinaryTagSerializer<>() {
|
||||
@Override
|
||||
public @NotNull BinaryTag write(@NotNull List<T> value) {
|
||||
ListBinaryTag.Builder<BinaryTag> builder = ListBinaryTag.builder();
|
||||
for (T t : value) builder.add(BinaryTagSerializer.this.write(t));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<T> read(@NotNull BinaryTag tag) {
|
||||
if (!(tag instanceof ListBinaryTag listBinaryTag)) return List.of();
|
||||
List<T> list = new ArrayList<>();
|
||||
for (BinaryTag element : listBinaryTag)
|
||||
list.add(BinaryTagSerializer.this.read(element));
|
||||
return list;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -36,5 +36,4 @@ public class BinaryTagWriter {
|
||||
output.writeUTF(name);
|
||||
type.write(tag, output);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user