chore: start testing components, fix valueless components

This commit is contained in:
mworzala 2024-05-04 00:48:05 -04:00
parent 7aa5eb6df3
commit 9ddf41bd89
No known key found for this signature in database
GPG Key ID: B148F922E64797C7
22 changed files with 382 additions and 53 deletions

View File

@ -1,6 +1,7 @@
package net.minestom.server.color;
import net.kyori.adventure.util.RGBLike;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.utils.MathUtils;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull;
@ -13,6 +14,23 @@ import org.jetbrains.annotations.NotNull;
public record Color(int red, int green, int blue) implements RGBLike {
private static final int BIT_MASK = 0xff;
public static final NetworkBuffer.Type<RGBLike> NETWORK_TYPE = new NetworkBuffer.Type<RGBLike>() {
@Override
public void write(@NotNull NetworkBuffer buffer, RGBLike value) {
buffer.write(NetworkBuffer.INT, Color.fromRGBLike(value).asRGB());
}
@Override
public RGBLike read(@NotNull NetworkBuffer buffer) {
return new Color(buffer.read(NetworkBuffer.INT));
}
};
public static @NotNull Color fromRGBLike(@NotNull RGBLike rgbLike) {
if (rgbLike instanceof Color color) return color;
return new Color(rgbLike.red(), rgbLike.green(), rgbLike.blue());
}
public Color {
Check.argCondition(!MathUtils.isBetween(red, 0, 255), "Red is not between 0-255: {0}", red);
Check.argCondition(!MathUtils.isBetween(green, 0, 255), "Green is not between 0-255: {0}", green);

View File

@ -13,6 +13,9 @@ import java.util.Collection;
public sealed interface DataComponent<T> extends StaticProtocolObject permits DataComponentImpl {
boolean isSynced();
boolean isSerialized();
@NotNull T read(@NotNull BinaryTag tag);
@NotNull BinaryTag write(@NotNull T value);

View File

@ -23,6 +23,16 @@ record DataComponentImpl<T>(
static final Map<String, DataComponent<?>> NAMESPACES = new HashMap<>(32);
static final ObjectArray<DataComponent<?>> IDS = ObjectArray.singleThread(32);
@Override
public boolean isSynced() {
return network != null;
}
@Override
public boolean isSerialized() {
return nbt != null;
}
@Override
public @NotNull T read(@NotNull BinaryTag tag) {
Check.notNull(nbt, "{0} cannot be deserialized from NBT", this);

View File

@ -128,7 +128,7 @@ public final class AttributeInstance {
result *= (1.0f + modifier.getAmount());
}
this.cachedValue = Math.min(result, getAttribute().maxValue());
this.cachedValue = Math.clamp(result, getAttribute().minValue(), getAttribute().maxValue());
// Signal entity
if (propertyChangeListener != null) {

View File

@ -10,6 +10,7 @@ import net.minestom.server.utils.nbt.BinaryTagSerializer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.Objects;
import java.util.function.Predicate;
@ -36,6 +37,12 @@ public record BlockPredicate(
* Matches all blocks.
*/
public static final BlockPredicate ALL = new BlockPredicate(null, null, null);
/**
* <p>Matches no blocks.</p>
*
* <p>Works based on the property that an exact property will never match a property which doesnt exist on any block.</p>
*/
public static final BlockPredicate NONE = new BlockPredicate(null, new PropertiesPredicate(Map.of("no_such_property", new PropertiesPredicate.ValuePredicate.Exact("never"))), null);
public static final NetworkBuffer.Type<BlockPredicate> NETWORK_TYPE = new NetworkBuffer.Type<>() {
@Override
@ -89,6 +96,10 @@ public record BlockPredicate(
this(blocks, null, null);
}
public BlockPredicate(@NotNull Block... blocks) {
this(new BlockTypeFilter.Blocks(blocks));
}
public BlockPredicate(@NotNull PropertiesPredicate state) {
this(null, state, null);
}

View File

@ -1,11 +1,13 @@
package net.minestom.server.item;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.util.RGBLike;
import net.minestom.server.color.Color;
import net.minestom.server.color.DyeColor;
import net.minestom.server.component.DataComponent;
import net.minestom.server.item.component.*;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.utils.Unit;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
import java.util.List;
@ -28,18 +30,18 @@ public final class ItemComponent {
public static final DataComponent<BlockPredicates> CAN_BREAK = DataComponent.register("can_break", BlockPredicates.NETWORK_TYPE, BlockPredicates.NBT_TYPE);
public static final DataComponent<AttributeList> ATTRIBUTE_MODIFIERS = DataComponent.register("attribute_modifiers", AttributeList.NETWORK_TYPE, AttributeList.NBT_TYPE);
public static final DataComponent<Integer> CUSTOM_MODEL_DATA = DataComponent.register("custom_model_data", NetworkBuffer.VAR_INT, BinaryTagSerializer.INT);
public static final DataComponent<Void> HIDE_ADDITIONAL_TOOLTIP = DataComponent.register("hide_additional_tooltip", NetworkBuffer.NOTHING, BinaryTagSerializer.NOTHING);
public static final DataComponent<Void> HIDE_TOOLTIP = DataComponent.register("hide_tooltip", NetworkBuffer.NOTHING, BinaryTagSerializer.NOTHING);
public static final DataComponent<Unit> HIDE_ADDITIONAL_TOOLTIP = DataComponent.register("hide_additional_tooltip", NetworkBuffer.UNIT, BinaryTagSerializer.UNIT);
public static final DataComponent<Unit> HIDE_TOOLTIP = DataComponent.register("hide_tooltip", NetworkBuffer.UNIT, BinaryTagSerializer.UNIT);
public static final DataComponent<Integer> REPAIR_COST = DataComponent.register("repair_cost", NetworkBuffer.VAR_INT, BinaryTagSerializer.INT);
public static final DataComponent<Void> CREATIVE_SLOT_LOCK = DataComponent.register("creative_slot_lock", NetworkBuffer.NOTHING, null);
public static final DataComponent<Unit> CREATIVE_SLOT_LOCK = DataComponent.register("creative_slot_lock", NetworkBuffer.UNIT, null);
public static final DataComponent<Boolean> ENCHANTMENT_GLINT_OVERRIDE = DataComponent.register("enchantment_glint_override", NetworkBuffer.BOOLEAN, BinaryTagSerializer.BOOLEAN);
public static final DataComponent<Void> INTANGIBLE_PROJECTILE = DataComponent.register("intangible_projectile", null, BinaryTagSerializer.NOTHING);
public static final DataComponent<Unit> INTANGIBLE_PROJECTILE = DataComponent.register("intangible_projectile", null, BinaryTagSerializer.UNIT);
public static final DataComponent<Food> FOOD = DataComponent.register("food", Food.NETWORK_TYPE, Food.NBT_TYPE);
public static final DataComponent<Void> FIRE_RESISTANT = DataComponent.register("fire_resistant", NetworkBuffer.NOTHING, BinaryTagSerializer.NOTHING);
public static final DataComponent<Unit> FIRE_RESISTANT = DataComponent.register("fire_resistant", NetworkBuffer.UNIT, BinaryTagSerializer.UNIT);
public static final DataComponent<Tool> TOOL = DataComponent.register("tool", Tool.NETWORK_TYPE, Tool.NBT_TYPE);
public static final DataComponent<EnchantmentList> STORED_ENCHANTMENTS = DataComponent.register("stored_enchantments", EnchantmentList.NETWORK_TYPE, EnchantmentList.NBT_TYPE);
public static final DataComponent<DyedItemColor> DYED_COLOR = DataComponent.register("dyed_color", DyedItemColor.NETWORK_TYPE, DyedItemColor.NBT_TYPE);
public static final DataComponent<Color> MAP_COLOR = DataComponent.register("map_color", NetworkBuffer.COLOR, BinaryTagSerializer.INT.map(Color::new, Color::asRGB));
public static final DataComponent<RGBLike> MAP_COLOR = DataComponent.register("map_color", Color.NETWORK_TYPE, BinaryTagSerializer.INT.map(Color::new, color -> Color.fromRGBLike(color).asRGB()));
public static final DataComponent<Integer> MAP_ID = DataComponent.register("map_id", NetworkBuffer.VAR_INT, BinaryTagSerializer.INT);
public static final DataComponent<MapDecorations> MAP_DECORATIONS = DataComponent.register("map_decorations", null, MapDecorations.NBT_TYPE);
public static final DataComponent<MapPostProcessing> MAP_POST_PROCESSING = DataComponent.register("map_post_processing", MapPostProcessing.NETWORK_TYPE, null);

View File

@ -17,7 +17,9 @@ public record Bee(@NotNull CustomData entityData, int ticksInHive, int minTicksI
@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));
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(
@ -30,4 +32,16 @@ public record Bee(@NotNull CustomData entityData, int ticksInHive, int minTicksI
.putInt("min_ticks_in_hive", value.minTicksInHive)
.build()
);
public @NotNull Bee withEntityData(@NotNull CustomData entityData) {
return new Bee(entityData, ticksInHive, minTicksInHive);
}
public @NotNull Bee withTicksInHive(int ticksInHive) {
return new Bee(entityData, ticksInHive, minTicksInHive);
}
public @NotNull Bee withMinTicksInHive(int minTicksInHive) {
return new Bee(entityData, ticksInHive, minTicksInHive);
}
}

View File

@ -1,6 +1,7 @@
package net.minestom.server.item.component;
import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.nbt.ByteBinaryTag;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.predicate.BlockPredicate;
@ -56,7 +57,11 @@ public record BlockPredicates(@NotNull List<BlockPredicate> predicates, boolean
}
// This default is fine in either case because the single predicate shouldnt have this key anyway.
boolean showInTooltip = compound.getBoolean("show_in_tooltip", true);
// https://github.com/KyoriPowered/adventure/issues/1068
boolean showInTooltip = true;
if (compound.get("show_in_tooltip") instanceof ByteBinaryTag showInTooltipTag)
showInTooltip = showInTooltipTag.value() != 0;
return new BlockPredicates(predicates, showInTooltip);
}
};
@ -65,6 +70,10 @@ public record BlockPredicates(@NotNull List<BlockPredicate> predicates, boolean
predicates = List.copyOf(predicates);
}
public BlockPredicates(@NotNull List<BlockPredicate> predicates) {
this(predicates, true);
}
public BlockPredicates(@NotNull BlockPredicate predicate) {
this(List.of(predicate), true);
}

View File

@ -35,4 +35,16 @@ public record DebugStickState(@NotNull Map<String, String> state) {
state = Map.copyOf(state);
}
public @NotNull DebugStickState set(@NotNull String key, @NotNull String value) {
Map<String, String> newState = new HashMap<>(state);
newState.put(key, value);
return new DebugStickState(newState);
}
public @NotNull DebugStickState remove(@NotNull String key) {
Map<String, String> newState = new HashMap<>(state);
newState.remove(key);
return new DebugStickState(newState);
}
}

View File

@ -1,26 +1,28 @@
package net.minestom.server.item.component;
import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.nbt.ByteBinaryTag;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.IntBinaryTag;
import net.kyori.adventure.util.RGBLike;
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 record DyedItemColor(@NotNull RGBLike 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(Color.NETWORK_TYPE, 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));
return new DyedItemColor(buffer.read(Color.NETWORK_TYPE), buffer.read(NetworkBuffer.BOOLEAN));
}
};
@ -28,7 +30,7 @@ public record DyedItemColor(@NotNull Color color, boolean showInTooltip) {
@Override
public @NotNull BinaryTag write(@NotNull DyedItemColor value) {
return CompoundBinaryTag.builder()
.putInt("color", value.color.asRGB())
.putInt("color", Color.fromRGBLike(value.color).asRGB())
.putBoolean("show_in_tooltip", value.showInTooltip)
.build();
}
@ -37,7 +39,8 @@ public record DyedItemColor(@NotNull Color color, boolean showInTooltip) {
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);
// https://github.com/KyoriPowered/adventure/issues/1068
boolean showInTooltip = !(compoundTag.get("show_in_tooltip") instanceof ByteBinaryTag showInTooltipTag) || showInTooltipTag.value() != 0;
return new DyedItemColor(new Color(color), showInTooltip);
} else if (tag instanceof IntBinaryTag intTag) {
return new DyedItemColor(new Color(intTag.intValue()), true);
@ -46,6 +49,18 @@ public record DyedItemColor(@NotNull Color color, boolean showInTooltip) {
}
};
public DyedItemColor(int color) {
this(color, true);
}
public DyedItemColor(@NotNull RGBLike color) {
this(color, true);
}
public DyedItemColor(int color, boolean showInTooltip) {
this(new Color(color), showInTooltip);
}
public @NotNull DyedItemColor withColor(@NotNull Color color) {
return new DyedItemColor(color, showInTooltip);
}

View File

@ -1,6 +1,7 @@
package net.minestom.server.item.component;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.util.RGBLike;
import net.minestom.server.color.Color;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.utils.nbt.BinaryTagSerializer;
@ -12,8 +13,8 @@ import java.util.Locale;
public record FireworkExplosion(
@NotNull Shape shape,
@NotNull List<Color> colors,
@NotNull List<Color> fadeColors,
@NotNull List<RGBLike> colors,
@NotNull List<RGBLike> fadeColors,
boolean hasTrail,
boolean hasTwinkle
) {
@ -30,8 +31,8 @@ public record FireworkExplosion(
@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.writeCollection(Color.NETWORK_TYPE, value.colors);
buffer.writeCollection(Color.NETWORK_TYPE, value.fadeColors);
buffer.write(NetworkBuffer.BOOLEAN, value.hasTrail);
buffer.write(NetworkBuffer.BOOLEAN, value.hasTwinkle);
}
@ -40,8 +41,8 @@ public record FireworkExplosion(
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.readCollection(Color.NETWORK_TYPE, Short.MAX_VALUE),
buffer.readCollection(Color.NETWORK_TYPE, Short.MAX_VALUE),
buffer.read(NetworkBuffer.BOOLEAN),
buffer.read(NetworkBuffer.BOOLEAN)
);
@ -51,10 +52,10 @@ public record FireworkExplosion(
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<>();
List<RGBLike> colors = new ArrayList<>();
for (int color : tag.getIntArray("colors"))
colors.add(new Color(color));
List<Color> fadeColors = new ArrayList<>();
List<RGBLike> fadeColors = new ArrayList<>();
for (int fadeColor : tag.getIntArray("fadeColors"))
fadeColors.add(new Color(fadeColor));
boolean hasTrail = tag.getBoolean("hasTrail");
@ -67,13 +68,13 @@ public record FireworkExplosion(
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();
colors[i] = Color.fromRGBLike(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();
fadeColors[i] = Color.fromRGBLike(value.fadeColors.get(i)).asRGB();
builder.putIntArray("fadeColors", fadeColors);
}
if (value.hasTrail) builder.putBoolean("hasTrail", value.hasTrail);

View File

@ -1,6 +1,7 @@
package net.minestom.server.item.component;
import net.kyori.adventure.nbt.*;
import net.kyori.adventure.util.RGBLike;
import net.minestom.server.color.Color;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.potion.CustomPotionEffect;
@ -14,7 +15,7 @@ import java.util.List;
public record PotionContents(
@Nullable PotionType potion,
@Nullable Color customColor,
@Nullable RGBLike customColor,
@NotNull List<CustomPotionEffect> customEffects
) {
public static final int POTION_DRINK_TIME = 32; // 32 ticks, in ms
@ -25,7 +26,7 @@ public record PotionContents(
public void write(@NotNull NetworkBuffer buffer, PotionContents value) {
Integer typeId = value.potion == null ? null : value.potion.id();
buffer.writeOptional(NetworkBuffer.VAR_INT, typeId);
buffer.writeOptional(NetworkBuffer.COLOR, value.customColor);
buffer.writeOptional(Color.NETWORK_TYPE, value.customColor);
buffer.writeCollection(CustomPotionEffect.NETWORK_TYPE, value.customEffects);
}
@ -34,7 +35,7 @@ public record PotionContents(
Integer typeId = buffer.readOptional(NetworkBuffer.VAR_INT);
return new PotionContents(
typeId == null ? null : PotionType.fromId(typeId),
buffer.readOptional(NetworkBuffer.COLOR),
buffer.readOptional(Color.NETWORK_TYPE),
buffer.readCollection(CustomPotionEffect.NETWORK_TYPE, Short.MAX_VALUE)
);
}

View File

@ -2,7 +2,6 @@ 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;
@ -31,8 +30,7 @@ import java.util.function.Supplier;
@ApiStatus.Experimental
public final class NetworkBuffer {
public static final Type<Void> NOTHING = new NetworkBufferTypeImpl.NothingType<>();
public static final Type<Unit> NOTHING_V2 = new NetworkBufferTypeImpl.NothingType<>();
public static final Type<Unit> UNIT = new NetworkBufferTypeImpl.UnitType();
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();
@ -78,8 +76,6 @@ 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();
public static <E extends Enum<E>> Type<E> fromEnum(@NotNull Class<E> enumClass) {
return NetworkBufferTypeImpl.fromEnum(enumClass);
}

View File

@ -4,12 +4,12 @@ import net.kyori.adventure.nbt.BinaryTag;
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.network.packet.server.play.data.WorldPos;
import net.minestom.server.particle.Particle;
import net.minestom.server.particle.data.ParticleData;
import net.minestom.server.utils.Unit;
import net.minestom.server.utils.nbt.BinaryTagReader;
import net.minestom.server.utils.nbt.BinaryTagWriter;
import net.minestom.server.utils.validate.Check;
@ -25,14 +25,14 @@ interface NetworkBufferTypeImpl<T> extends NetworkBuffer.Type<T> {
int SEGMENT_BITS = 0x7F;
int CONTINUE_BIT = 0x80;
record NothingType<T>() implements NetworkBufferTypeImpl<T> {
record UnitType() implements NetworkBufferTypeImpl<Unit> {
@Override
public void write(@NotNull NetworkBuffer buffer, T value) {
public void write(@NotNull NetworkBuffer buffer, Unit value) {
}
@Override
public T read(@NotNull NetworkBuffer buffer) {
return null;
public Unit read(@NotNull NetworkBuffer buffer) {
return Unit.INSTANCE;
}
}
@ -580,18 +580,6 @@ 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

View File

@ -5,6 +5,7 @@ import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.minestom.server.item.ItemStack;
import net.minestom.server.utils.UniqueIdUtils;
import net.minestom.server.utils.Unit;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
@ -108,15 +109,15 @@ public interface BinaryTagSerializer<T> {
};
}
BinaryTagSerializer<Void> NOTHING = new BinaryTagSerializer<>() {
BinaryTagSerializer<Unit> UNIT = new BinaryTagSerializer<>() {
@Override
public @NotNull BinaryTag write(@NotNull Void value) {
public @NotNull BinaryTag write(@NotNull Unit value) {
return EndBinaryTag.endBinaryTag();
}
@Override
public @NotNull Void read(@NotNull BinaryTag tag) {
return null;
public @NotNull Unit read(@NotNull BinaryTag tag) {
return Unit.INSTANCE;
}
};

View File

@ -0,0 +1,58 @@
package net.minestom.server.item.component;
import net.minestom.server.component.DataComponent;
import net.minestom.server.network.NetworkBuffer;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public abstract class AbstractItemComponentTest<T> {
protected abstract @NotNull DataComponent<T> component();
protected abstract @NotNull List<Map.Entry<String, T>> directReadWriteEntries();
private @NotNull Stream<Arguments> directReadWriteMethodSource() {
return directReadWriteEntries().stream().map(entry -> Arguments.of(entry.getKey(), entry.getValue()));
}
@ParameterizedTest(name = "{0}")
@MethodSource("directReadWriteMethodSource")
public void directReadWriteNbt(String testName, @NotNull T entry) {
assumeTrue(component().isSerialized());
var written1 = component().write(entry);
var read = component().read(written1);
assertEquals(entry, read);
var written2 = component().write(read);
assertEquals(written1, written2);
}
@ParameterizedTest(name = "{0}")
@MethodSource("directReadWriteMethodSource")
public void directReadWriteNetwork(String testName, @NotNull T entry) {
assumeTrue(component().isSynced());
var written1 = NetworkBuffer.makeArray(b -> component().write(b, entry));
var read = component().read(new NetworkBuffer(ByteBuffer.wrap(written1)));
assertEquals(entry, read);
var written2 = NetworkBuffer.makeArray(b -> component().write(b, entry));
assertArrayEquals(written1, written2);
}
}

View File

@ -0,0 +1,31 @@
package net.minestom.server.item.component;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.component.DataComponent;
import net.minestom.server.item.ItemComponent;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Map;
import static java.util.Map.entry;
public class BeesTest extends AbstractItemComponentTest<List<Bee>> {
private static final CustomData SOME_DATA = new CustomData(CompoundBinaryTag.builder()
.putString("Id", "minecraft:bee")
.build());
@Override
protected @NotNull DataComponent<List<Bee>> component() {
return ItemComponent.BEES;
}
@Override
public @NotNull List<Map.Entry<String, List<Bee>>> directReadWriteEntries() {
return List.of(
entry("empty", List.of()),
entry("single", List.of(new Bee(SOME_DATA, 1, 2))),
entry("multiple", List.of(new Bee(SOME_DATA, 1, 2), new Bee(SOME_DATA, 3, 4)))
);
}
}

View File

@ -0,0 +1,50 @@
package net.minestom.server.item.component;
import net.kyori.adventure.nbt.TagStringIOExt;
import net.minestom.server.component.DataComponent;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.predicate.BlockPredicate;
import net.minestom.server.item.ItemComponent;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import static java.util.Map.entry;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class BlockPredicatesTest extends AbstractItemComponentTest<BlockPredicates> {
@Override
protected @NotNull DataComponent<BlockPredicates> component() {
return ItemComponent.CAN_PLACE_ON; // CAN_BREAK is the same thing
}
@Override
protected @NotNull List<Map.Entry<String, BlockPredicates>> directReadWriteEntries() {
return List.of(
entry("empty", new BlockPredicates(List.of(), true)),
entry("single, no tooltip", new BlockPredicates(BlockPredicate.ALL, false)),
entry("many", new BlockPredicates(List.of(BlockPredicate.ALL, BlockPredicate.NONE), true))
);
}
@Test
public void testSingleBlockNbtInput() throws IOException {
var tag = TagStringIOExt.readTag("{blocks:'minecraft:stone'}");
var component = ItemComponent.CAN_PLACE_ON.read(tag);
var expected = new BlockPredicates(new BlockPredicate(Block.STONE));
assertEquals(expected, component);
}
@Test
public void testMultiMatch() {
// Just sanity check that it actually runs both of the predicates
var predicate = new BlockPredicates(List.of(BlockPredicate.NONE, BlockPredicate.ALL), true);
assertTrue(predicate.test(Block.AIR));
}
}

View File

@ -0,0 +1,30 @@
package net.minestom.server.item.component;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.minestom.server.component.DataComponent;
import net.minestom.server.item.ItemComponent;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Map;
import static java.util.Map.entry;
public class CustomDataTest extends AbstractItemComponentTest<CustomData> {
@Override
protected @NotNull DataComponent<CustomData> component() {
return ItemComponent.CUSTOM_DATA;
}
@Override
protected @NotNull List<Map.Entry<String, CustomData>> directReadWriteEntries() {
return List.of(
entry("simple", new CustomData(CompoundBinaryTag.builder()
.putString("hello", "world")
.put("nested", CompoundBinaryTag.builder()
.putInt("number", 42)
.build())
.build()))
);
}
}

View File

@ -0,0 +1,28 @@
package net.minestom.server.item.component;
import net.minestom.server.component.DataComponent;
import net.minestom.server.item.ItemComponent;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Map;
import static java.util.Map.entry;
public class DebugStickStateTest extends AbstractItemComponentTest<DebugStickState> {
@Override
protected @NotNull DataComponent<DebugStickState> component() {
return ItemComponent.DEBUG_STICK_STATE;
}
@Override
protected @NotNull List<Map.Entry<String, DebugStickState>> directReadWriteEntries() {
return List.of(
entry("empty", new DebugStickState(Map.of())),
// Note that an invalid block id is present. Minestom currently does not validate the block id or state value.
entry("contents", new DebugStickState(Map.of("minecraft:stone_stairs", "shape", "minecraft:nothing", "abcdef")))
);
}
}

View File

@ -0,0 +1,26 @@
package net.minestom.server.item.component;
import net.minestom.server.component.DataComponent;
import net.minestom.server.item.ItemComponent;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Map;
import static java.util.Map.entry;
public class DyedItemColorTest extends AbstractItemComponentTest<DyedItemColor> {
@Override
protected @NotNull DataComponent<DyedItemColor> component() {
return ItemComponent.DYED_COLOR;
}
@Override
protected @NotNull List<Map.Entry<String, DyedItemColor>> directReadWriteEntries() {
return List.of(
entry("default leather", DyedItemColor.LEATHER),
entry("no tooltip", new DyedItemColor(0xCAFEBB, false))
);
}
}

View File

@ -0,0 +1,25 @@
package net.minestom.server.item.component;
import net.minestom.server.component.DataComponent;
import net.minestom.server.item.ItemComponent;
import net.minestom.server.utils.Unit;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Map;
import static java.util.Map.entry;
public class UnitTest extends AbstractItemComponentTest<Unit> {
@Override
protected @NotNull DataComponent<Unit> component() {
return ItemComponent.HIDE_TOOLTIP;
}
@Override
protected @NotNull List<Map.Entry<String, Unit>> directReadWriteEntries() {
return List.of(
entry("instance", Unit.INSTANCE)
);
}
}