feat: more components

This commit is contained in:
mworzala 2024-04-18 06:18:28 -04:00
parent 3fdd9ab9bb
commit 2b974d95f9
No known key found for this signature in database
GPG Key ID: B148F922E64797C7
38 changed files with 708 additions and 102 deletions

View File

@ -37,8 +37,7 @@ allprojects {
withSourcesJar()
withJavadocJar()
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
toolchain.languageVersion = JavaLanguageVersion.of(21)
}
tasks.withType<Zip> {

View File

@ -26,7 +26,7 @@ public class Generators {
generator.generate(resource("items.json"), "net.minestom.server.item", "Material", "MaterialImpl", "Materials");
generator.generate(resource("entities.json"), "net.minestom.server.entity", "EntityType", "EntityTypeImpl", "EntityTypes");
generator.generate(resource("biomes.json"), "net.minestom.server.world.biomes", "Biome", "BiomeImpl", "Biomes");
generator.generate(resource("enchantments.json"), "net.minestom.server.item", "Enchantment", "EnchantmentImpl", "Enchantments");
generator.generate(resource("enchantments.json"), "net.minestom.server.item.enchant", "Enchantment", "EnchantmentImpl", "Enchantments");
generator.generate(resource("potion_effects.json"), "net.minestom.server.potion", "PotionEffect", "PotionEffectImpl", "PotionEffects");
generator.generate(resource("potions.json"), "net.minestom.server.potion", "PotionType", "PotionTypeImpl", "PotionTypes");
generator.generate(resource("particles.json"), "net.minestom.server.particle", "Particle", "ParticleImpl", "Particles");

View File

@ -31,15 +31,16 @@ import net.minestom.server.inventory.InventoryType;
import net.minestom.server.item.ItemComponent;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.item.component.ItemBlockState;
import net.minestom.server.monitoring.BenchmarkManager;
import net.minestom.server.monitoring.TickMonitor;
import net.minestom.server.utils.MathUtils;
import net.minestom.server.utils.Unit;
import net.minestom.server.utils.time.TimeUnit;
import net.minestom.server.world.DimensionType;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicReference;
@ -115,13 +116,9 @@ public class PlayerInit {
.build();
player.getInventory().addItemStack(bundle);
try {
player.getInventory().addItemStack(ItemStack.builder(Material.STICK)
.set(ItemComponent.CREATIVE_SLOT_LOCK, Unit.INSTANCE)
.build());
} catch (Exception e) {
throw new RuntimeException(e);
}
player.getInventory().addItemStack(ItemStack.builder(Material.STONE_STAIRS)
.set(ItemComponent.BLOCK_STATE, new ItemBlockState(Map.of("facing", "west", "half", "top")))
.build());
if (event.isFirstSpawn()) {
Notification notification = new Notification(

View File

@ -1,6 +1,8 @@
package net.minestom.server.color;
import net.kyori.adventure.util.RGBLike;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import org.jetbrains.annotations.NotNull;
/**
@ -39,6 +41,9 @@ public enum DyeColor implements RGBLike {
BLACK(new Color(0x1d1d21), new Color(0x0), new Color(0x1e1b1b), 29);
public static final NetworkBuffer.Type<DyeColor> NETWORK_TYPE = NetworkBuffer.fromEnum(DyeColor.class);
public static final BinaryTagSerializer<DyeColor> NBT_TYPE = BinaryTagSerializer.fromEnumStringable(DyeColor.class);
private final Color textureDiffuseColor;
private final Color textColor;

View File

@ -1,4 +1,4 @@
package net.minestom.server.item;
package net.minestom.server.item.enchant;
/**
* Code autogenerated, do not edit!

View File

@ -49,7 +49,7 @@ interface PotionEffects {
PotionEffect ABSORPTION = PotionEffectImpl.get("minecraft:absorption");
PotionEffect SATURATION = PotionEffectImpl.get("minecraft:saturation");
PotionEffect SATURATION = PotionEffectImpl.get("minecraft:saturationModifier");
PotionEffect GLOWING = PotionEffectImpl.get("minecraft:glowing");

View File

@ -1,6 +1,6 @@
package net.minestom.server.command.builder.arguments.minecraft.registry;
import net.minestom.server.item.Enchantment;
import net.minestom.server.item.enchant.Enchantment;
import org.jetbrains.annotations.NotNull;
/**

View File

@ -1098,14 +1098,14 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
}
/**
* Sets and refresh client food saturation.
* Sets and refresh client food saturationModifier.
*
* @param foodSaturation the food saturation
* @param foodSaturation the food saturationModifier
* @throws IllegalArgumentException if {@code foodSaturation} is not between 0 and 20
*/
public void setFoodSaturation(float foodSaturation) {
Check.argCondition(!MathUtils.isBetween(foodSaturation, 0, 20),
"Food saturation has to be between 0 and 20");
"Food saturationModifier has to be between 0 and 20");
this.foodSaturation = foodSaturation;
sendPacket(new UpdateHealthPacket(getHealth(), food, foodSaturation));
}

View File

@ -4,7 +4,7 @@ import net.kyori.adventure.text.Component;
import net.minestom.server.inventory.ContainerInventory;
import net.minestom.server.inventory.InventoryProperty;
import net.minestom.server.inventory.InventoryType;
import net.minestom.server.item.Enchantment;
import net.minestom.server.item.enchant.Enchantment;
import org.jetbrains.annotations.NotNull;
public class EnchantmentTableInventory extends ContainerInventory {

View File

@ -3,11 +3,11 @@ package net.minestom.server.item;
import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.text.Component;
import net.minestom.server.color.Color;
import net.minestom.server.color.DyeColor;
import net.minestom.server.item.component.*;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.registry.StaticProtocolObject;
import net.minestom.server.utils.NamespaceID;
import net.minestom.server.utils.Unit;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -36,10 +36,10 @@ public sealed interface ItemComponent<T> extends StaticProtocolObject permits It
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<Unit> CREATIVE_SLOT_LOCK = declare("creative_slot_lock", NetworkBuffer.NOTHING_V2, null);
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<Food> FOOD = declare("food", Food.NETWORK_TYPE, Food.NBT_TYPE);
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);
@ -50,16 +50,16 @@ public sealed interface ItemComponent<T> extends StaticProtocolObject permits It
ItemComponent<MapPostProcessing> MAP_POST_PROCESSING = declare("map_post_processing", MapPostProcessing.NETWORK_TYPE, null);
ItemComponent<List<ItemStack>> CHARGED_PROJECTILES = declare("charged_projectiles", ItemStack.NETWORK_TYPE.list(Short.MAX_VALUE), BinaryTagSerializer.ITEM.list());
ItemComponent<List<ItemStack>> BUNDLE_CONTENTS = declare("bundle_contents", ItemStack.NETWORK_TYPE.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<PotionContents> POTION_CONTENTS = declare("potion_contents", PotionContents.NETWORK_TYPE, PotionContents.NBT_TYPE);
ItemComponent<SuspiciousStewEffects> SUSPICIOUS_STEW_EFFECTS = declare("suspicious_stew_effects", SuspiciousStewEffects.NETWORK_TYPE, SuspiciousStewEffects.NBT_TYPE);
ItemComponent<WritableBookContent> WRITABLE_BOOK_CONTENT = declare("writable_book_content", WritableBookContent.NETWORK_TYPE, WritableBookContent.NBT_TYPE);
ItemComponent<WrittenBookContent> WRITTEN_BOOK_CONTENT = declare("written_book_content", WrittenBookContent.NETWORK_TYPE, WrittenBookContent.NBT_TYPE);
ItemComponent<Void> TRIM = declare("trim", null, null); //todo
ItemComponent<Void> DEBUG_STICK_STATE = declare("debug_stick_state", null, null); //todo
ItemComponent<ArmorTrim> TRIM = declare("trim", ArmorTrim.NETWORK_TYPE, ArmorTrim.NBT_TYPE);
ItemComponent<DebugStickState> DEBUG_STICK_STATE = declare("debug_stick_state", null, DebugStickState.NBT_TYPE);
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<String> INSTRUMENT = declare("instrument", NetworkBuffer.STRING, BinaryTagSerializer.STRING);
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);
@ -68,11 +68,11 @@ public sealed interface ItemComponent<T> extends StaticProtocolObject permits It
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<DyeColor> BASE_COLOR = declare("base_color", DyeColor.NETWORK_TYPE, DyeColor.NBT_TYPE);
ItemComponent<PotDecorations> POT_DECORATIONS = declare("pot_decorations", PotDecorations.NETWORK_TYPE, PotDecorations.NBT_TYPE);
ItemComponent<List<ItemStack>> CONTAINER = declare("container", ItemStack.NETWORK_TYPE.list(256), BinaryTagSerializer.ITEM.list());
ItemComponent<Void> BLOCK_STATE = declare("block_state", null, null); //todo
ItemComponent<Void> BEES = declare("bees", null, null); //todo
ItemComponent<ItemBlockState> BLOCK_STATE = declare("block_state", ItemBlockState.NETWORK_TYPE, ItemBlockState.NBT_TYPE);
ItemComponent<List<Bee>> BEES = declare("bees", Bee.NETWORK_TYPE.list(Short.MAX_VALUE), Bee.NBT_TYPE.list());
ItemComponent<String> LOCK = declare("lock", null, BinaryTagSerializer.STRING);
ItemComponent<SeededContainerLoot> CONTAINER_LOOT = declare("container_loot", null, SeededContainerLoot.NBT_TYPE);

View File

@ -1,9 +1,11 @@
package net.minestom.server.item;
import net.minestom.server.instance.block.Block;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.registry.Registry;
import net.minestom.server.registry.StaticProtocolObject;
import net.minestom.server.utils.NamespaceID;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -45,6 +47,9 @@ import java.util.Collection;
public sealed interface Material extends StaticProtocolObject, Materials permits MaterialImpl {
NetworkBuffer.Type<Material> NETWORK_TYPE = MaterialImpl.NETWORK_TYPE;
BinaryTagSerializer<Material> NBT_TYPE = MaterialImpl.NBT_TYPE;
/**
* Returns the material registry.
*

View File

@ -1,6 +1,8 @@
package net.minestom.server.item;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.registry.Registry;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
@ -9,6 +11,9 @@ record MaterialImpl(Registry.MaterialEntry registry) implements Material {
private static final Registry.Container<Material> CONTAINER = Registry.createStaticContainer(Registry.Resource.ITEMS,
(namespace, properties) -> new MaterialImpl(Registry.material(namespace, properties)));
static final NetworkBuffer.Type<Material> NETWORK_TYPE = NetworkBuffer.VAR_INT.map(MaterialImpl::getId, Material::id);
static final BinaryTagSerializer<Material> NBT_TYPE = BinaryTagSerializer.STRING.map(MaterialImpl::getSafe, Material::name);
static Material get(@NotNull String namespace) {
return CONTAINER.get(namespace);
}

View File

@ -8,6 +8,7 @@ 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 java.util.Collection;
import java.util.Map;
@ -52,6 +53,14 @@ public interface TrimMaterial extends StaticProtocolObject {
);
}
static @Nullable TrimMaterial fromId(int id) {
return TrimMaterialImpl.fromId(id);
}
static @Nullable TrimMaterial fromNamespaceId(@NotNull String id) {
return TrimMaterialImpl.fromNamespaceId(id);
}
static Collection<TrimMaterial> values() {
return TrimMaterialImpl.values();
}

View File

@ -4,6 +4,8 @@ import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.StringBinaryTag;
import net.minestom.server.adventure.serializer.nbt.NbtComponentSerializer;
import net.minestom.server.registry.Registry;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Map;
@ -27,6 +29,14 @@ record TrimMaterialImpl(Registry.TrimMaterialEntry registry, int id) implements
return CONTAINER.get(namespace);
}
static @Nullable TrimMaterial fromId(int id) {
return CONTAINER.getId(id);
}
static @Nullable TrimMaterial fromNamespaceId(@NotNull String id) {
return CONTAINER.get(id);
}
static Collection<TrimMaterial> values() {
return CONTAINER.values();
}

View File

@ -8,6 +8,7 @@ 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 java.util.Collection;
@ -33,6 +34,14 @@ public interface TrimPattern extends StaticProtocolObject {
);
}
static @Nullable TrimPattern fromId(int id) {
return TrimPatternImpl.fromId(id);
}
static @Nullable TrimPattern fromNamespaceId(@NotNull String id) {
return TrimPatternImpl.fromNamespaceId(id);
}
static Collection<TrimPattern> values() {
return TrimPatternImpl.values();
}

View File

@ -20,6 +20,14 @@ record TrimPatternImpl(Registry.TrimPatternEntry registry, int id) implements Tr
this(registry, i.getAndIncrement());
}
public static TrimPattern fromId(int id) {
return CONTAINER.getId(id);
}
public static TrimPattern fromNamespaceId(String namespace) {
return CONTAINER.getSafe(namespace);
}
public static TrimPattern get(String namespace) {
return CONTAINER.get(namespace);
}

View File

@ -0,0 +1,43 @@
package net.minestom.server.item.component;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.item.armor.TrimMaterial;
import net.minestom.server.item.armor.TrimPattern;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
public record ArmorTrim(@NotNull TrimMaterial material, @NotNull TrimPattern pattern, boolean showInTooltip) {
public static final NetworkBuffer.Type<ArmorTrim> NETWORK_TYPE = new NetworkBuffer.Type<>() {
@Override
public void write(@NotNull NetworkBuffer buffer, ArmorTrim value) {
buffer.write(NetworkBuffer.VAR_INT, value.material.id());
buffer.write(NetworkBuffer.VAR_INT, value.pattern.id());
buffer.write(NetworkBuffer.BOOLEAN, value.showInTooltip);
}
@Override
public ArmorTrim read(@NotNull NetworkBuffer buffer) {
TrimMaterial material = Objects.requireNonNull(TrimMaterial.fromId(buffer.read(NetworkBuffer.VAR_INT)), "unknown trim material");
TrimPattern pattern = Objects.requireNonNull(TrimPattern.fromId(buffer.read(NetworkBuffer.VAR_INT)), "unknown trim pattern");
return new ArmorTrim(material, pattern, buffer.read(NetworkBuffer.BOOLEAN));
}
};
public static final BinaryTagSerializer<ArmorTrim> NBT_TYPE = BinaryTagSerializer.COMPOUND.map(
tag -> {
TrimMaterial material = Objects.requireNonNull(TrimMaterial.fromNamespaceId(tag.getString("material")), "unknown trim material");
TrimPattern pattern = Objects.requireNonNull(TrimPattern.fromNamespaceId(tag.getString("pattern")), "unknown trim pattern");
boolean showInTooltip = tag.getBoolean("show_in_tooltip", true);
return new ArmorTrim(material, pattern, showInTooltip);
},
value -> CompoundBinaryTag.builder()
.putString("material", value.material.name())
.putString("pattern", value.pattern.name())
.putBoolean("show_in_tooltip", value.showInTooltip)
.build()
);
}

View File

@ -0,0 +1,33 @@
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 Bee(@NotNull CustomData entityData, int ticksInHive, int minTicksInHive) {
public static @NotNull NetworkBuffer.Type<Bee> NETWORK_TYPE = new NetworkBuffer.Type<Bee>() {
@Override
public void write(@NotNull NetworkBuffer buffer, Bee value) {
buffer.write(CustomData.NETWORK_TYPE, value.entityData);
buffer.write(NetworkBuffer.VAR_INT, value.ticksInHive);
buffer.write(NetworkBuffer.VAR_INT, value.minTicksInHive);
}
@Override
public Bee read(@NotNull NetworkBuffer buffer) {
return new Bee(buffer.read(CustomData.NETWORK_TYPE), buffer.read(NetworkBuffer.VAR_INT), buffer.read(NetworkBuffer.VAR_INT));
}
};
public static @NotNull BinaryTagSerializer<Bee> NBT_TYPE = BinaryTagSerializer.COMPOUND.map(
tag -> new Bee(CustomData.NBT_TYPE.read(tag.getCompound("entity_data")),
tag.getInt("ticks_in_hive"),
tag.getInt("min_ticks_in_hive")),
value -> CompoundBinaryTag.builder()
.put("entity_data", CustomData.NBT_TYPE.write(value.entityData))
.putInt("ticks_in_hive", value.ticksInHive)
.putInt("min_ticks_in_hive", value.minTicksInHive)
.build()
);
}

View File

@ -0,0 +1,38 @@
package net.minestom.server.item.component;
import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.StringBinaryTag;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
public record DebugStickState(@NotNull Map<String, String> state) {
public static final DebugStickState EMPTY = new DebugStickState(Map.of());
public static final BinaryTagSerializer<DebugStickState> NBT_TYPE = BinaryTagSerializer.COMPOUND.map(
tag -> {
Map<String, String> state = new HashMap<>();
for (Map.Entry<String, ? extends BinaryTag> entry : tag) {
if (!(entry.getValue() instanceof StringBinaryTag property))
continue;
state.put(entry.getKey(), property.value());
}
return new DebugStickState(state);
},
state -> {
CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder();
for (Map.Entry<String, String> entry : state.state().entrySet()) {
builder.put(entry.getKey(), StringBinaryTag.stringBinaryTag(entry.getValue()));
}
return builder.build();
}
);
public DebugStickState {
state = Map.copyOf(state);
}
}

View File

@ -2,7 +2,7 @@ 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.item.enchant.Enchantment;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import net.minestom.server.utils.validate.Check;

View File

@ -0,0 +1,85 @@
package net.minestom.server.item.component;
import net.kyori.adventure.nbt.BinaryTagTypes;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.ServerFlag;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.potion.CustomPotionEffect;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public record Food(int nutrition, float saturationModifier, boolean canAlwaysEat, float eatSeconds, @NotNull List<EffectChance> effects) {
public static final float DEFAULT_EAT_SECONDS = 1.6f;
public static final NetworkBuffer.Type<Food> NETWORK_TYPE = new NetworkBuffer.Type<>() {
@Override
public void write(@NotNull NetworkBuffer buffer, Food value) {
buffer.write(NetworkBuffer.VAR_INT, value.nutrition);
buffer.write(NetworkBuffer.FLOAT, value.saturationModifier);
buffer.write(NetworkBuffer.BOOLEAN, value.canAlwaysEat);
buffer.write(NetworkBuffer.FLOAT, value.eatSeconds);
buffer.writeCollection(EffectChance.NETWORK_TYPE, value.effects);
}
@Override
public Food read(@NotNull NetworkBuffer buffer) {
return new Food(
buffer.read(NetworkBuffer.VAR_INT),
buffer.read(NetworkBuffer.FLOAT),
buffer.read(NetworkBuffer.BOOLEAN),
buffer.read(NetworkBuffer.FLOAT),
buffer.readCollection(EffectChance.NETWORK_TYPE, Short.MAX_VALUE)
);
}
};
public static final BinaryTagSerializer<Food> NBT_TYPE = BinaryTagSerializer.COMPOUND.map(
tag -> new Food(
tag.getInt("nutrition"),
tag.getFloat("saturation_modifier"),
tag.getBoolean("can_always_eat"),
tag.getFloat("eat_seconds", DEFAULT_EAT_SECONDS),
EffectChance.NBT_LIST_TYPE.read(tag.getList("effects", BinaryTagTypes.COMPOUND))),
value -> CompoundBinaryTag.builder()
.putInt("nutrition", value.nutrition)
.putFloat("saturationModifier", value.saturationModifier)
.putBoolean("canAlwaysEat", value.canAlwaysEat)
.putFloat("eatSeconds", value.eatSeconds)
.put("effects", EffectChance.NBT_LIST_TYPE.write(value.effects))
.build()
);
public Food {
effects = List.copyOf(effects);
}
public int eatDurationTicks() {
return (int) (eatSeconds * ServerFlag.SERVER_TICKS_PER_SECOND);
}
public record EffectChance(@NotNull CustomPotionEffect effect, float probability) {
public static final NetworkBuffer.Type<EffectChance> NETWORK_TYPE = new NetworkBuffer.Type<>() {
@Override
public void write(@NotNull NetworkBuffer buffer, EffectChance value) {
}
@Override
public EffectChance read(@NotNull NetworkBuffer buffer) {
return null;
}
};
public static final BinaryTagSerializer<EffectChance> NBT_TYPE = BinaryTagSerializer.COMPOUND.map(
tag -> new EffectChance(
CustomPotionEffect.NBT_TYPE.read(tag.getCompound("effect")),
tag.getFloat("probability", 1f)),
value -> CompoundBinaryTag.builder()
.put("effect", CustomPotionEffect.NBT_TYPE.write(value.effect()))
.putFloat("probability", value.probability)
.build()
);
public static final BinaryTagSerializer<List<EffectChance>> NBT_LIST_TYPE = NBT_TYPE.list();
}
}

View File

@ -0,0 +1,74 @@
package net.minestom.server.item.component;
import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.StringBinaryTag;
import net.minestom.server.instance.block.Block;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
public record ItemBlockState(@NotNull Map<String, String> properties) {
public static final ItemBlockState EMPTY = new ItemBlockState(Map.of());
public static final NetworkBuffer.Type<ItemBlockState> NETWORK_TYPE = new NetworkBuffer.Type<>() {
@Override
public void write(@NotNull NetworkBuffer buffer, ItemBlockState value) {
buffer.write(NetworkBuffer.VAR_INT, value.properties.size());
for (Map.Entry<String, String> entry : value.properties.entrySet()) {
buffer.write(NetworkBuffer.STRING, entry.getKey());
buffer.write(NetworkBuffer.STRING, entry.getValue());
}
}
@Override
public ItemBlockState read(@NotNull NetworkBuffer buffer) {
int size = buffer.read(NetworkBuffer.VAR_INT);
Map<String, String> properties = new HashMap<>(size);
for (int i = 0; i < size; i++) {
properties.put(buffer.read(NetworkBuffer.STRING), buffer.read(NetworkBuffer.STRING));
}
return new ItemBlockState(properties);
}
};
public static final BinaryTagSerializer<ItemBlockState> NBT_TYPE = BinaryTagSerializer.COMPOUND.map(
tag -> {
Map<String, String> properties = new HashMap<>(tag.size());
for (Map.Entry<String, ? extends BinaryTag> entry : tag) {
if (!(entry.getValue() instanceof StringBinaryTag str)) continue;
properties.put(entry.getKey(), str.value());
}
return new ItemBlockState(properties);
},
value -> {
CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder();
for (Map.Entry<String, String> entry : value.properties.entrySet()) {
builder.put(entry.getKey(), StringBinaryTag.stringBinaryTag(entry.getValue()));
}
return builder.build();
}
);
public ItemBlockState {
properties = Map.copyOf(properties);
}
public @NotNull ItemBlockState with(@NotNull String key, @NotNull String value) {
Map<String, String> newProperties = new HashMap<>(properties);
newProperties.put(key, value);
return new ItemBlockState(newProperties);
}
public @NotNull Block apply(@NotNull Block block) {
for (Map.Entry<String, String> entry : properties.entrySet()) {
if (block.getProperty(entry.getKey()) == null)
continue; // Ignore properties not present on this block
block = block.withProperty(entry.getKey(), entry.getValue());
}
return block;
}
}

View File

@ -1,13 +1,7 @@
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,
@ -17,31 +11,6 @@ public enum ItemRarity {
private static final ItemRarity[] VALUES = values();
public 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);
}
};
public 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;
};
}
};
public static final NetworkBuffer.Type<ItemRarity> NETWORK_TYPE = NetworkBuffer.fromEnum(ItemRarity.class);
public static final BinaryTagSerializer<ItemRarity> NBT_TYPE = BinaryTagSerializer.fromEnumStringable(ItemRarity.class);
}

View File

@ -6,35 +6,45 @@ import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import org.jetbrains.annotations.NotNull;
import java.util.List;
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) {
public static final @NotNull Material DEFAULT_ITEM = Material.BRICK;
public static final PotDecorations EMPTY = new PotDecorations(DEFAULT_ITEM, DEFAULT_ITEM, DEFAULT_ITEM, DEFAULT_ITEM);
public static NetworkBuffer.Type<PotDecorations> NETWORK_TYPE = new NetworkBuffer.Type<PotDecorations>() {
@Override public void write(@NotNull NetworkBuffer buffer, PotDecorations value) {
Material.NETWORK_TYPE.list(4).map(PotDecorations::new, PotDecorations::asList).write(buffer, value);
}
@Override
public PotDecorations read(@NotNull NetworkBuffer buffer) {
return null;
@Override public PotDecorations read(@NotNull NetworkBuffer buffer) {
return Material.NETWORK_TYPE.list(4).map(PotDecorations::new, PotDecorations::asList).read(buffer);
}
};
public static BinaryTagSerializer<PotDecorations> NBT_TYPE = new BinaryTagSerializer<PotDecorations>() {
@Override public @NotNull BinaryTag write(@NotNull PotDecorations value) {
return Material.NBT_TYPE.list().map(PotDecorations::new, PotDecorations::asList).write(value);
}
@Override public @NotNull PotDecorations read(@NotNull BinaryTag tag) {
return Material.NBT_TYPE.list().map(PotDecorations::new, PotDecorations::asList).read(tag);
}
};
public static BinaryTagSerializer<PotDecorations> NBT_TYPE = new BinaryTagSerializer<>() {
@Override
public @NotNull BinaryTag write(@NotNull PotDecorations value) {
return null;
}
public PotDecorations(@NotNull List<Material> list) {
this(getOrAir(list, 0), getOrAir(list, 1), getOrAir(list, 2), getOrAir(list, 3));
}
@Override
public @NotNull PotDecorations read(@NotNull BinaryTag tag) {
return null;
}
};
public @NotNull List<Material> asList() {
return List.of(back, left, right, front);
}
private static @NotNull Material getOrAir(@NotNull List<Material> list, int index) {
return index < list.size() ? list.get(index) : Material.BRICK;
}
}

View File

@ -0,0 +1,83 @@
package net.minestom.server.item.component;
import net.kyori.adventure.nbt.*;
import net.minestom.server.color.Color;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.potion.CustomPotionEffect;
import net.minestom.server.potion.PotionEffect;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
public record PotionContents(
@Nullable PotionEffect potion,
@Nullable Color customColor,
@NotNull List<CustomPotionEffect> customEffects
) {
public static final PotionContents EMPTY = new PotionContents(null, null, List.of());
public static final NetworkBuffer.Type<PotionContents> NETWORK_TYPE = new NetworkBuffer.Type<>() {
@Override
public void write(@NotNull NetworkBuffer buffer, PotionContents value) {
buffer.writeOptional(PotionEffect.NETWORK_TYPE, value.potion);
buffer.writeOptional(NetworkBuffer.COLOR, value.customColor);
buffer.writeCollection(CustomPotionEffect.NETWORK_TYPE, value.customEffects);
}
@Override
public PotionContents read(@NotNull NetworkBuffer buffer) {
return new PotionContents(
buffer.readOptional(PotionEffect.NETWORK_TYPE),
buffer.readOptional(NetworkBuffer.COLOR),
buffer.readCollection(CustomPotionEffect.NETWORK_TYPE, Short.MAX_VALUE)
);
}
};
public static final BinaryTagSerializer<PotionContents> NBT_TYPE = new BinaryTagSerializer<>() {
@Override
public @NotNull BinaryTag write(@NotNull PotionContents value) {
return null;
}
@Override
public @NotNull PotionContents read(@NotNull BinaryTag tag) {
// Can be a string with just a potion effect id
if (tag instanceof StringBinaryTag string) {
return new PotionContents(PotionEffect.fromNamespaceId(string.value()), null, List.of());
}
// Otherwise must be a compound
if (!(tag instanceof CompoundBinaryTag compound)) {
return EMPTY;
}
PotionEffect potion = null;
if (compound.get("potion") instanceof StringBinaryTag potionTag)
potion = PotionEffect.fromNamespaceId(potionTag.value());
Color customColor = null;
if (compound.get("custom_color") instanceof IntBinaryTag colorTag) {
customColor = new Color(colorTag.value());
}
List<CustomPotionEffect> customEffects = new ArrayList<>();
ListBinaryTag customEffectsTag = compound.getList("custom_effects", BinaryTagTypes.COMPOUND);
for (BinaryTag customEffectTag : customEffectsTag) {
if (!(customEffectTag instanceof CompoundBinaryTag customEffectCompound)) {
continue;
}
customEffects.add(CustomPotionEffect.NBT_TYPE.read(customEffectCompound));
}
return new PotionContents(potion, customColor, customEffects);
}
};
public PotionContents {
customEffects = List.copyOf(customEffects);
}
}

View File

@ -0,0 +1,49 @@
package net.minestom.server.item.component;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.potion.PotionEffect;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public record SuspiciousStewEffects(@NotNull List<Effect> effects) {
public static final int DEFAULT_DURATION = 160;
public static final NetworkBuffer.Type<SuspiciousStewEffects> NETWORK_TYPE = Effect.NETWORK_TYPE.list(Short.MAX_VALUE).map(SuspiciousStewEffects::new, SuspiciousStewEffects::effects);
public static final BinaryTagSerializer<SuspiciousStewEffects> NBT_TYPE = Effect.NBT_TYPE.list().map(SuspiciousStewEffects::new, SuspiciousStewEffects::effects);
public SuspiciousStewEffects {
effects = List.copyOf(effects);
}
public record Effect(@NotNull PotionEffect id, int durationTicks) {
public static final NetworkBuffer.Type<Effect> NETWORK_TYPE = new NetworkBuffer.Type<>() {
@Override
public void write(@NotNull NetworkBuffer buffer, Effect value) {
buffer.write(PotionEffect.NETWORK_TYPE, value.id);
buffer.write(NetworkBuffer.VAR_INT, value.durationTicks);
}
@Override
public Effect read(@NotNull NetworkBuffer buffer) {
return new Effect(buffer.read(PotionEffect.NETWORK_TYPE), buffer.read(NetworkBuffer.VAR_INT));
}
};
public static final BinaryTagSerializer<Effect> NBT_TYPE = BinaryTagSerializer.COMPOUND.map(
tag -> new Effect(PotionEffect.fromNamespaceId(tag.getString("id")),
tag.getInt("duration", DEFAULT_DURATION)),
value -> CompoundBinaryTag.builder()
.putString("id", value.id.name())
.putInt("duration", value.durationTicks)
.build()
);
public Effect(@NotNull PotionEffect id) {
this(id, DEFAULT_DURATION);
}
}
}

View File

@ -1,7 +1,7 @@
package net.minestom.server.item;
package net.minestom.server.item.enchant;
import net.minestom.server.registry.StaticProtocolObject;
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;

View File

@ -1,4 +1,4 @@
package net.minestom.server.item;
package net.minestom.server.item.enchant;
import net.minestom.server.registry.Registry;
import org.jetbrains.annotations.NotNull;

View File

@ -19,8 +19,10 @@ import net.minestom.server.instance.block.BlockHandler;
import net.minestom.server.instance.block.BlockManager;
import net.minestom.server.instance.block.rule.BlockPlacementRule;
import net.minestom.server.inventory.PlayerInventory;
import net.minestom.server.item.ItemComponent;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.item.component.ItemBlockState;
import net.minestom.server.network.packet.client.play.ClientPlayerBlockPlacementPacket;
import net.minestom.server.network.packet.server.play.AcknowledgeBlockChangePacket;
import net.minestom.server.network.packet.server.play.BlockChangePacket;
@ -139,7 +141,9 @@ public class BlockPlacementListener {
return;
}
final Block placedBlock = useMaterial.block();
final ItemBlockState blockState = usedItem.get(ItemComponent.BLOCK_STATE, ItemBlockState.EMPTY);
final Block placedBlock = blockState.apply(useMaterial.block());
Entity collisionEntity = CollisionUtils.canPlaceBlockAt(instance, placementPosition, placedBlock);
if (collisionEntity != null) {
// If a player is trying to place a block on themselves, the client will send a block change but will not set the block on the client

View File

@ -80,6 +80,10 @@ public final class NetworkBuffer {
public static final Type<Color> COLOR = new NetworkBufferTypeImpl.ColorType();
public static <E extends Enum<E>> Type<E> fromEnum(@NotNull Class<E> enumClass) {
return NetworkBufferTypeImpl.fromEnum(enumClass);
}
ByteBuffer nioBuffer;
final boolean resizable;
int writeIndex;
@ -299,6 +303,20 @@ public final class NetworkBuffer {
void write(@NotNull NetworkBuffer buffer, T value);
T read(@NotNull NetworkBuffer buffer);
default <S> @NotNull Type<S> map(@NotNull Function<T, S> to, @NotNull Function<S, T> from) {
return new Type<S>() {
@Override
public void write(@NotNull NetworkBuffer buffer, S value) {
Type.this.write(buffer, from.apply(value));
}
@Override
public S read(@NotNull NetworkBuffer buffer) {
return to.apply(Type.this.read(buffer));
}
};
}
default @NotNull Type<List<T>> list(int maxSize) {
return new NetworkBuffer.Type<>() {
@Override

View File

@ -1,9 +1,120 @@
package net.minestom.server.potion;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Represents a custom effect in {@link net.minestom.server.item.metadata.PotionMeta}.
* Represents a custom effect in {@link net.minestom.server.item.ItemComponent#POTION_CONTENTS}.
*/
public record CustomPotionEffect(byte id, byte amplifier, int duration,
boolean isAmbient, boolean showParticles,
boolean showIcon) {
public record CustomPotionEffect(@NotNull PotionEffect id, @NotNull Settings settings) {
public static final NetworkBuffer.Type<CustomPotionEffect> NETWORK_TYPE = new NetworkBuffer.Type<>() {
@Override
public void write(@NotNull NetworkBuffer buffer, CustomPotionEffect value) {
buffer.write(PotionEffect.NETWORK_TYPE, value.id);
buffer.write(Settings.NETWORK_TYPE, value.settings);
}
@Override
public CustomPotionEffect read(@NotNull NetworkBuffer buffer) {
return new CustomPotionEffect(buffer.read(PotionEffect.NETWORK_TYPE), buffer.read(Settings.NETWORK_TYPE));
}
};
public static final BinaryTagSerializer<CustomPotionEffect> NBT_TYPE = BinaryTagSerializer.COMPOUND.map(
tag -> new CustomPotionEffect(
PotionEffect.fromNamespaceId(tag.getString("id")),
Settings.NBT_TYPE.read(tag)),
value -> CompoundBinaryTag.builder()
.putString("id", value.id.name())
.put((CompoundBinaryTag) Settings.NBT_TYPE.write(value.settings))
.build()
);
public CustomPotionEffect(@NotNull PotionEffect id, byte amplifier, int duration, boolean isAmbient, boolean showParticles, boolean showIcon) {
this(id, new Settings(amplifier, duration, isAmbient, showParticles, showIcon, null));
}
public byte amplifier() {
return settings.amplifier;
}
public int duration() {
return settings.duration;
}
public boolean isAmbient() {
return settings.isAmbient;
}
public boolean showParticles() {
return settings.showParticles;
}
public boolean showIcon() {
return settings.showIcon;
}
public record Settings(
byte amplifier, int duration,
boolean isAmbient, boolean showParticles, boolean showIcon,
@Nullable Settings hiddenEffect
) {
public static final NetworkBuffer.Type<Settings> NETWORK_TYPE = new NetworkBuffer.Type<>() {
@Override
public void write(@NotNull NetworkBuffer buffer, Settings value) {
buffer.write(NetworkBuffer.VAR_INT, (int) value.amplifier);
buffer.write(NetworkBuffer.VAR_INT, value.duration);
buffer.write(NetworkBuffer.BOOLEAN, value.isAmbient);
buffer.write(NetworkBuffer.BOOLEAN, value.showParticles);
buffer.write(NetworkBuffer.BOOLEAN, value.showIcon);
buffer.writeOptional(NETWORK_TYPE, value.hiddenEffect);
}
@Override
public Settings read(@NotNull NetworkBuffer buffer) {
return new Settings(
buffer.read(NetworkBuffer.VAR_INT).byteValue(),
buffer.read(NetworkBuffer.VAR_INT),
buffer.read(NetworkBuffer.BOOLEAN),
buffer.read(NetworkBuffer.BOOLEAN),
buffer.read(NetworkBuffer.BOOLEAN),
buffer.readOptional(NETWORK_TYPE)
);
}
};
public static final BinaryTagSerializer<Settings> NBT_TYPE = BinaryTagSerializer.recursive(self -> BinaryTagSerializer.COMPOUND.map(
tag -> {
byte amplifier = tag.getByte("amplifier");
int duration = tag.getInt("duration");
boolean ambient = tag.getBoolean("ambient");
boolean showParticles = tag.getBoolean("show_particles", true);
boolean showIcon = tag.getBoolean("show_icon", showParticles);
Settings hiddenEffect = null;
if (tag.get("hidden_effect") instanceof CompoundBinaryTag hiddenEffectTag) {
hiddenEffect = self.read(hiddenEffectTag);
}
return new Settings(amplifier, duration, ambient, showParticles, showIcon, hiddenEffect);
},
value -> {
CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder()
.putByte("amplifier", value.amplifier)
.putInt("duration", value.duration)
.putBoolean("ambient", value.isAmbient)
.putBoolean("show_particles", value.showParticles)
.putBoolean("show_icon", value.showIcon);
if (value.hiddenEffect != null) {
builder.put("hidden_effect", self.write(value.hiddenEffect));
}
return builder.build();
}
));
}
}

View File

@ -1,7 +1,8 @@
package net.minestom.server.potion;
import net.minestom.server.registry.StaticProtocolObject;
import net.minestom.server.network.NetworkBuffer;
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;
@ -11,6 +12,8 @@ import java.util.Collection;
public sealed interface PotionEffect extends StaticProtocolObject, PotionEffects permits PotionEffectImpl {
NetworkBuffer.Type<PotionEffect> NETWORK_TYPE = PotionEffectImpl.NETWORK_TYPE;
@Contract(pure = true)
@NotNull Registry.PotionEffectEntry registry();

View File

@ -1,5 +1,6 @@
package net.minestom.server.potion;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.registry.Registry;
import org.jetbrains.annotations.NotNull;
@ -9,6 +10,8 @@ record PotionEffectImpl(Registry.PotionEffectEntry registry) implements PotionEf
private static final Registry.Container<PotionEffect> CONTAINER = Registry.createStaticContainer(Registry.Resource.POTION_EFFECTS,
(namespace, properties) -> new PotionEffectImpl(Registry.potionEffect(namespace, properties)));
public static final NetworkBuffer.Type<PotionEffect> NETWORK_TYPE = NetworkBuffer.VAR_INT.map(PotionEffectImpl::getId, PotionEffect::id);
static PotionEffect get(@NotNull String namespace) {
return CONTAINER.get(namespace);
}

View File

@ -6,12 +6,53 @@ 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.*;
import java.util.function.Function;
import java.util.stream.Collectors;
public interface BinaryTagSerializer<T> {
static <T> @NotNull BinaryTagSerializer<T> recursive(@NotNull Function<BinaryTagSerializer<T>, BinaryTagSerializer<T>> self) {
return new BinaryTagSerializer<>() {
private BinaryTagSerializer<T> serializer = null;
@Override
public @NotNull BinaryTag write(@NotNull T value) {
return serializer().write(value);
}
@Override
public @NotNull T read(@NotNull BinaryTag tag) {
return serializer().read(tag);
}
private BinaryTagSerializer<T> serializer() {
if (serializer == null) serializer = self.apply(this);
return serializer;
}
};
}
static <E extends Enum<E>> @NotNull BinaryTagSerializer<E> fromEnumStringable(@NotNull Class<E> enumClass) {
final E[] values = enumClass.getEnumConstants();
final Map<String, E> nameMap = Arrays.stream(values).collect(Collectors.toMap(e -> e.name().toLowerCase(Locale.ROOT), Function.identity()));
return new BinaryTagSerializer<E>() {
@Override
public @NotNull BinaryTag write(@NotNull E value) {
return StringBinaryTag.stringBinaryTag(value.name().toLowerCase(Locale.ROOT));
}
@Override
public @NotNull E read(@NotNull BinaryTag tag) {
return switch (tag) {
case IntBinaryTag intBinaryTag -> values[intBinaryTag.value()];
case StringBinaryTag string -> nameMap.getOrDefault(string.value().toLowerCase(Locale.ROOT), values[0]);
default -> values[0];
};
}
};
}
BinaryTagSerializer<Void> NOTHING = new BinaryTagSerializer<>() {
@Override
public @NotNull BinaryTag write(@NotNull Void value) {

View File

@ -12,11 +12,10 @@ import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.EntityType;
import net.minestom.server.instance.block.Block;
import net.minestom.server.item.Enchantment;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.item.enchant.Enchantment;
import net.minestom.server.particle.Particle;
import net.minestom.server.potion.PotionEffect;
import net.minestom.server.tag.Tag;
import net.minestom.server.utils.location.RelativeVec;
import net.minestom.server.utils.math.FloatRange;

View File

@ -4,16 +4,13 @@ import net.minestom.server.command.builder.Command;
import net.minestom.server.command.builder.CommandContext;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.instance.block.Block;
import net.minestom.server.item.Enchantment;
import net.minestom.server.item.enchant.Enchantment;
import org.junit.jupiter.api.Test;
import java.lang.String;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import static net.minestom.server.command.builder.arguments.ArgumentType.Integer;
import static net.minestom.server.command.builder.arguments.ArgumentType.String;
import static net.minestom.server.command.builder.arguments.ArgumentType.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;

View File

@ -1,12 +1,10 @@
package net.minestom.server.item;
import net.minestom.server.item.enchant.Enchantment;
import org.junit.jupiter.api.Test;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ItemEnchantTest {
@Test

View File

@ -3,6 +3,7 @@ package net.minestom.server.item;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.entity.EntityType;
import net.minestom.server.item.enchant.Enchantment;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.junit.jupiter.api.Test;