diff --git a/settings.gradle.kts b/settings.gradle.kts index 85bcd1333..6368001ed 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -47,6 +47,7 @@ sequenceOf( "text-serializer-legacy", "text-serializer-plain", "text-serializer-ansi", + "text-serializer-nbt" ).forEach { include("adventure-$it") project(":adventure-$it").projectDir = file(it) diff --git a/text-serializer-nbt/build.gradle.kts b/text-serializer-nbt/build.gradle.kts new file mode 100644 index 000000000..a7e7bbe31 --- /dev/null +++ b/text-serializer-nbt/build.gradle.kts @@ -0,0 +1,11 @@ +plugins { + id("adventure.common-conventions") +} + +dependencies { + api(libs.option) + api(projects.adventureApi) + api(projects.adventureNbt) +} + +applyJarMetadata("net.kyori.adventure.text.serializer.nbt") diff --git a/text-serializer-nbt/src/main/java/net/kyori/adventure/text/serializer/nbt/ClickEventSerializer.java b/text-serializer-nbt/src/main/java/net/kyori/adventure/text/serializer/nbt/ClickEventSerializer.java new file mode 100644 index 000000000..4218dffa7 --- /dev/null +++ b/text-serializer-nbt/src/main/java/net/kyori/adventure/text/serializer/nbt/ClickEventSerializer.java @@ -0,0 +1,59 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2024 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.serializer.nbt; + +import net.kyori.adventure.nbt.BinaryTag; +import net.kyori.adventure.nbt.CompoundBinaryTag; +import net.kyori.adventure.nbt.StringBinaryTag; +import net.kyori.adventure.text.event.ClickEvent; +import org.jetbrains.annotations.NotNull; + +final class ClickEventSerializer { + + private static final String ACTION = "action"; + private static final String VALUE = "value"; + + private ClickEventSerializer() { + } + + static @NotNull ClickEvent deserialize(@NotNull CompoundBinaryTag tag) { + BinaryTag actionTag = tag.get(ACTION); + + if (actionTag == null) { + throw new IllegalArgumentException("The serialized click event doesn't contain an action"); + } + + String actionString = ((StringBinaryTag) actionTag).value(); + ClickEvent.Action action = ClickEvent.Action.NAMES.valueOrThrow(actionString); + + return ClickEvent.clickEvent(action, tag.getString(VALUE)); + } + + static @NotNull CompoundBinaryTag serialize(@NotNull ClickEvent event) { + return CompoundBinaryTag.builder() + .putString(ACTION, ClickEvent.Action.NAMES.keyOrThrow(event.action())) + .putString(VALUE, event.value()) + .build(); + } +} diff --git a/text-serializer-nbt/src/main/java/net/kyori/adventure/text/serializer/nbt/HoverEventSerializer.java b/text-serializer-nbt/src/main/java/net/kyori/adventure/text/serializer/nbt/HoverEventSerializer.java new file mode 100644 index 000000000..adf20b540 --- /dev/null +++ b/text-serializer-nbt/src/main/java/net/kyori/adventure/text/serializer/nbt/HoverEventSerializer.java @@ -0,0 +1,163 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2024 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.serializer.nbt; + +import net.kyori.adventure.key.Key; +import net.kyori.adventure.nbt.BinaryTag; +import net.kyori.adventure.nbt.CompoundBinaryTag; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.DataComponentValue; +import net.kyori.adventure.text.event.HoverEvent; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +final class HoverEventSerializer { + + private static final String HOVER_EVENT_ACTION = "action"; + private static final String HOVER_EVENT_CONTENTS = "contents"; + + private static final String HOVER_EVENT_SHOW_TEXT = "show_text"; + private static final String HOVER_EVENT_SHOW_ITEM = "show_item"; + private static final String HOVER_EVENT_SHOW_ENTITY = "show_entity"; + + private static final String SHOW_ITEM_ID = "id"; + private static final String SHOW_ITEM_COUNT = "count"; + private static final String SHOW_ITEM_COMPONENTS = "components"; + + private static final String SHOW_ENTITY_TYPE = "type"; + private static final String SHOW_ENTITY_ID = "id"; + private static final String SHOW_ENTITY_NAME = "name"; + + private HoverEventSerializer() { + } + + static @NotNull HoverEvent deserialize(@NotNull CompoundBinaryTag compound, @NotNull NBTComponentSerializerImpl serializer) { + String actionString = compound.getString(HOVER_EVENT_ACTION); + HoverEvent.Action action = HoverEvent.Action.NAMES.valueOrThrow(actionString); + Class actionType = action.type(); + + BinaryTag contents = compound.get(HOVER_EVENT_CONTENTS); + if (contents == null) { + throw new IllegalArgumentException("The hover event doesn't contain any contents"); + } + + if (Component.class.isAssignableFrom(actionType)) { + return HoverEvent.showText(serializer.deserialize(contents)); + } else if (HoverEvent.ShowItem.class.isAssignableFrom(actionType)) { + CompoundBinaryTag showItemContents = (CompoundBinaryTag) contents; + + Key itemId = Key.key(showItemContents.getString(SHOW_ITEM_ID)); + int itemCount = showItemContents.getInt(SHOW_ITEM_COUNT); + + BinaryTag components = showItemContents.get(SHOW_ITEM_COMPONENTS); + + if (components != null) { + CompoundBinaryTag componentsCompound = (CompoundBinaryTag) components; + Map componentValues = new HashMap<>(); + + for (String string : componentsCompound.keySet()) { + BinaryTag value = componentsCompound.get(string); + if (value == null) continue; + componentValues.put(Key.key(string), NBTDataComponentValue.nbtDataComponentValue(value)); + } + + return HoverEvent.showItem(itemId, itemCount, componentValues); + } else { + return HoverEvent.showItem(itemId, itemCount); + } + } else if (HoverEvent.ShowEntity.class.isAssignableFrom(actionType)) { + CompoundBinaryTag showEntityContents = (CompoundBinaryTag) contents; + + Key entityType = Key.key(showEntityContents.getString(SHOW_ENTITY_TYPE)); + UUID entityId = UUID.fromString(showEntityContents.getString(SHOW_ENTITY_ID)); + + BinaryTag entityName = showEntityContents.get(SHOW_ENTITY_NAME); + + if (entityName != null) { + return HoverEvent.showEntity(entityType, entityId, serializer.deserialize(entityName)); + } else { + return HoverEvent.showEntity(entityType, entityId); + } + } else { + throw new IllegalArgumentException("Don't know how to deserialize a hoverEvent with action of " + actionString + " from a binary tag"); + } + } + + static @NotNull CompoundBinaryTag serialize(@NotNull HoverEvent event, @NotNull NBTComponentSerializerImpl serializer) { + HoverEvent.Action action = event.action(); + + BinaryTag contents; + String actionString; + + if (action == HoverEvent.Action.SHOW_TEXT) { + contents = serializer.serialize((Component) event.value()); + actionString = HOVER_EVENT_SHOW_TEXT; + } else if (action == HoverEvent.Action.SHOW_ITEM) { + HoverEvent.ShowItem item = (HoverEvent.ShowItem) event.value(); + + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder() + .putString(SHOW_ITEM_ID, item.item().asString()) + .putInt(SHOW_ITEM_COUNT, item.count()); + + Map components = item.dataComponentsAs(NBTDataComponentValue.class); + + if (!components.isEmpty()) { + CompoundBinaryTag.Builder dataComponentsBuilder = CompoundBinaryTag.builder(); + + for (Map.Entry entry : components.entrySet()) { + dataComponentsBuilder.put(entry.getKey().asString(), entry.getValue().binaryTag()); + } + + builder.put(SHOW_ITEM_COMPONENTS, dataComponentsBuilder.build()); + } + + contents = builder.build(); + actionString = HOVER_EVENT_SHOW_ITEM; + } else if (action == HoverEvent.Action.SHOW_ENTITY) { + HoverEvent.ShowEntity item = (HoverEvent.ShowEntity) event.value(); + + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder() + .putString(SHOW_ENTITY_TYPE, item.type().asString()) + .putString(SHOW_ENTITY_ID, item.id().toString()); + + Component customName = item.name(); + if (customName != null) { + builder.put(SHOW_ENTITY_NAME, serializer.serialize(customName)); + } + + contents = builder.build(); + actionString = HOVER_EVENT_SHOW_ENTITY; + } else { + throw new IllegalArgumentException("Don't know how to serialize " + event + " as a binary tag"); + } + + return CompoundBinaryTag.builder() + .putString(HOVER_EVENT_ACTION, actionString) + .put(HOVER_EVENT_CONTENTS, contents) + .build(); + } +} diff --git a/text-serializer-nbt/src/main/java/net/kyori/adventure/text/serializer/nbt/NBTComponentSerializer.java b/text-serializer-nbt/src/main/java/net/kyori/adventure/text/serializer/nbt/NBTComponentSerializer.java new file mode 100644 index 000000000..82b1eac07 --- /dev/null +++ b/text-serializer-nbt/src/main/java/net/kyori/adventure/text/serializer/nbt/NBTComponentSerializer.java @@ -0,0 +1,149 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2024 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.serializer.nbt; + +import net.kyori.adventure.builder.AbstractBuilder; +import net.kyori.adventure.nbt.BinaryTag; +import net.kyori.adventure.nbt.CompoundBinaryTag; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.Style; +import net.kyori.adventure.text.serializer.ComponentSerializer; +import net.kyori.adventure.util.PlatformAPI; +import net.kyori.option.OptionState; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Consumer; + +/** + * A NBT component serializer. + * + * @since 4.18.0 + */ +public interface NBTComponentSerializer extends ComponentSerializer { + /** + * Deserializes a {@linkplain Style style} from a {@linkplain BinaryTag binary tag}. + * + * @param tag the binary tag + * @return the style + * @since 4.18.0 + */ + @NotNull Style deserializeStyle(@NotNull CompoundBinaryTag tag); + + /** + * Serializes a {@linkplain Style style} to a {@linkplain BinaryTag binary tag}. + * + * @param style the style + * @return the binary tag + * @since 4.18.0 + */ + @NotNull CompoundBinaryTag serializeStyle(@NotNull Style style); + + /** + * Gets a component serializer for NBT serialization and deserialization. + * + * @return a NBT component serializer + * @since 4.18.0 + */ + static @NotNull NBTComponentSerializer nbt() { + return NBTComponentSerializerImpl.Instances.INSTANCE; + } + + /** + * Creates a new {@link NBTComponentSerializer.Builder}. + * + * @return a builder + * @since 4.18.0 + */ + static @NotNull Builder builder() { + return new NBTComponentSerializerImpl.BuilderImpl(); + } + + /** + * A builder for {@link NBTComponentSerializer}. + * + * @since 4.18.0 + */ + interface Builder extends AbstractBuilder { + /** + * Set the option state to apply on this serializer. + * + *

This controls how the serializer emits and interprets components.

+ * + * @param flags the flag set to use + * @return this builder + * @see NBTSerializerOptions + * @since 4.18.0 + */ + @NotNull Builder options(final @NotNull OptionState flags); + + /** + * Edit the active set of serializer options. + * + * @param optionEditor the consumer operating on the existing flag set + * @return this builder + * @see NBTSerializerOptions + * @since 4.18.0 + */ + @NotNull Builder editOptions(final @NotNull Consumer optionEditor); + + /** + * Builds the serializer. + * + * @return the built serializer + * @since 4.18.0 + */ + @Override + @NotNull NBTComponentSerializer build(); + } + + /** + * A {@link NBTComponentSerializer} service provider. + * + * @since 4.18.0 + */ + @ApiStatus.Internal + @PlatformAPI + interface Provider { + /** + * Provides a standard {@link NBTComponentSerializer}. + * + * @return a {@link NBTComponentSerializer} + * @since 4.18.0 + */ + @ApiStatus.Internal + @PlatformAPI + @NotNull NBTComponentSerializer nbt(); + + /** + * Completes the building process of {@link Builder}. + * + * @return a {@link Consumer} + * @since 4.18.0 + */ + @ApiStatus.Internal + @PlatformAPI + @NotNull Consumer builder(); + } +} diff --git a/text-serializer-nbt/src/main/java/net/kyori/adventure/text/serializer/nbt/NBTComponentSerializerImpl.java b/text-serializer-nbt/src/main/java/net/kyori/adventure/text/serializer/nbt/NBTComponentSerializerImpl.java new file mode 100644 index 000000000..ac30ae102 --- /dev/null +++ b/text-serializer-nbt/src/main/java/net/kyori/adventure/text/serializer/nbt/NBTComponentSerializerImpl.java @@ -0,0 +1,409 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2024 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.serializer.nbt; + +import net.kyori.adventure.key.Key; +import net.kyori.adventure.nbt.BinaryTag; +import net.kyori.adventure.nbt.CompoundBinaryTag; +import net.kyori.adventure.nbt.ListBinaryTag; +import net.kyori.adventure.nbt.StringBinaryTag; +import net.kyori.adventure.text.BlockNBTComponent; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.EntityNBTComponent; +import net.kyori.adventure.text.KeybindComponent; +import net.kyori.adventure.text.NBTComponent; +import net.kyori.adventure.text.ScoreComponent; +import net.kyori.adventure.text.SelectorComponent; +import net.kyori.adventure.text.StorageNBTComponent; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.TranslatableComponent; +import net.kyori.adventure.text.TranslationArgument; +import net.kyori.adventure.text.format.Style; +import net.kyori.adventure.util.Services; +import net.kyori.option.OptionState; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.function.Consumer; + +import static java.util.Objects.requireNonNull; + +final class NBTComponentSerializerImpl implements NBTComponentSerializer { + + private static final Optional SERVICE = Services.service(Provider.class); + private static final Consumer BUILDER = SERVICE + .map(Provider::builder) + .orElse(builder -> { + // NOOP + }); + + @Override + public @NotNull Style deserializeStyle(@NotNull CompoundBinaryTag tag) { + return StyleSerializer.deserialize(tag, this); + } + + @Override + public @NotNull CompoundBinaryTag serializeStyle(@NotNull Style style) { + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(); + StyleSerializer.serialize(style, builder, this); + return builder.build(); + } + + // We cannot store these fields in NBTComponentSerializerImpl directly due to class initialisation issues. + static final class Instances { + static final NBTComponentSerializer INSTANCE = SERVICE + .map(Provider::nbt) + .orElseGet(() -> new NBTComponentSerializerImpl(OptionState.emptyOptionState())); + } + + private static final String TYPE = "type"; + + private static final String TYPE_TEXT = "text"; + private static final String TYPE_TRANSLATABLE = "translatable"; + private static final String TYPE_KEYBIND = "keybind"; + private static final String TYPE_SCORE = "score"; + private static final String TYPE_SELECTOR = "selector"; + private static final String TYPE_NBT = "nbt"; + + private static final String EXTRA = "extra"; + + private static final String TEXT = "text"; + + private static final String TRANSLATE_KEY = "translate"; + private static final String TRANSLATE_WITH = "with"; + private static final String TRANSLATE_FALLBACK = "fallback"; + + private static final String KEYBIND = "keybind"; + + private static final String SCORE = "score"; + private static final String SCORE_NAME = "name"; + private static final String SCORE_OBJECTIVE = "objective"; + + private static final String SELECTOR = "selector"; + private static final String SELECTOR_SEPARATOR = "separator"; + + private static final String NBT = "nbt"; + private static final String NBT_INTERPRET = "interpret"; + private static final String NBT_SEPARATOR = "separator"; + private static final String NBT_BLOCK = "block"; + private static final String NBT_ENTITY = "entity"; + private static final String NBT_STORAGE = "storage"; + + private final OptionState flags; + + NBTComponentSerializerImpl(@NotNull OptionState flags) { + this.flags = flags; + } + + @Override + public @NotNull Component deserialize(@NotNull BinaryTag input) { + if (input instanceof StringBinaryTag) { + return Component.text(((StringBinaryTag) input).value()); + } + + if (!(input instanceof CompoundBinaryTag)) { + throw new IllegalArgumentException("The input isn't a compound or string binary tag"); + } + + CompoundBinaryTag compound = (CompoundBinaryTag) input; + String type = compound.getString(TYPE); + + if (type.isEmpty()) { + if (compound.get(TEXT) != null) { + type = TYPE_TEXT; + } else if (compound.get(TRANSLATE_KEY) != null) { + type = TYPE_TRANSLATABLE; + } else if (compound.get(KEYBIND) != null) { + type = TYPE_KEYBIND; + } else if (compound.get(SCORE) != null) { + type = TYPE_SCORE; + } else if (compound.get(SELECTOR) != null) { + type = TYPE_SELECTOR; + } else if (compound.get(NBT) != null && (compound.get(NBT_BLOCK) != null + || compound.get(NBT_STORAGE) != null || compound.get(NBT_ENTITY) != null)) { + type = TYPE_NBT; + } else { + throw new IllegalArgumentException("Could not guess type of the component"); + } + } + + Style style = StyleSerializer.deserialize(compound, this); + + List children = new ArrayList<>(); + ListBinaryTag binaryChildren = compound.getList(EXTRA); + binaryChildren.forEach(child -> children.add(this.deserialize(child))); + + switch (type) { + case TYPE_TEXT: + return Component.text() + .content(compound.getString(TEXT)) + .style(style) + .append(children) + .build(); + case TYPE_TRANSLATABLE: + ListBinaryTag binaryArguments = compound.getList(TRANSLATE_WITH); + String fallback = compound.getString(TRANSLATE_FALLBACK); + + if (fallback.isEmpty()) { + fallback = null; + } + + List arguments = new ArrayList<>(); + for (BinaryTag argument : binaryArguments) { + arguments.add(this.deserialize(argument)); + } + + return Component.translatable() + .key(compound.getString(TRANSLATE_KEY)) + .fallback(fallback) + .arguments(arguments) + .style(style) + .append(children) + .build(); + case TYPE_KEYBIND: + return Component.keybind() + .keybind(compound.getString(KEYBIND)) + .style(style) + .append(children) + .build(); + case TYPE_SCORE: + CompoundBinaryTag binaryScore = compound.getCompound(SCORE); + + String scoreName = binaryScore.getString(SCORE_NAME); + String scoreObjective = binaryScore.getString(SCORE_OBJECTIVE); + + return Component.score() + .name(scoreName) + .objective(scoreObjective) + .style(style) + .append(children) + .build(); + case TYPE_SELECTOR: + String selector = compound.getString(SELECTOR); + Component selectorSeparator = null; + + BinaryTag binarySelectorSeparator = compound.get(SELECTOR_SEPARATOR); + if (binarySelectorSeparator != null) { + selectorSeparator = this.deserialize(binarySelectorSeparator); + } + + return Component.selector() + .pattern(selector) + .separator(selectorSeparator) + .style(style) + .append(children) + .build(); + case TYPE_NBT: + String nbtPath = compound.getString(NBT); + boolean nbtInterpret = compound.getBoolean(NBT_INTERPRET); + Component nbtSeparator = null; + + BinaryTag binaryNbtSeparator = compound.get(NBT_SEPARATOR); + if (binaryNbtSeparator != null) { + nbtSeparator = this.deserialize(binaryNbtSeparator); + } + + BinaryTag binaryBlock = compound.get(NBT_BLOCK); + BinaryTag binaryEntity = compound.get(NBT_ENTITY); + BinaryTag binaryStorage = compound.get(NBT_STORAGE); + + if (binaryBlock != null) { + BlockNBTComponent.Pos pos = BlockNBTComponent.Pos.fromString(((StringBinaryTag) binaryBlock).value()); + return Component.blockNBT() + .nbtPath(nbtPath) + .interpret(nbtInterpret) + .separator(nbtSeparator) + .pos(pos) + .style(style) + .append(children) + .build(); + } else if (binaryEntity != null) { + return Component.entityNBT() + .nbtPath(nbtPath) + .interpret(nbtInterpret) + .separator(nbtSeparator) + .selector(((StringBinaryTag) binaryEntity).value()) + .style(style) + .append(children) + .build(); + } else if (binaryStorage != null) { + return Component.storageNBT() + .nbtPath(nbtPath) + .interpret(nbtInterpret) + .separator(nbtSeparator) + .storage(Key.key(((StringBinaryTag) binaryStorage).value())) + .style(style) + .append(children) + .build(); + } + default: + throw new IllegalArgumentException("Unknown component type " + type); + } + } + + @Override + public @NotNull BinaryTag serialize(@NotNull Component component) { + if (this.flags.value(NBTSerializerOptions.EMIT_COMPACT_TEXT_COMPONENT) && component instanceof TextComponent + && !component.hasStyling() && component.children().isEmpty()) { + return StringBinaryTag.stringBinaryTag(((TextComponent) component).content()); + } + return writeCompoundComponent(component); + } + + private @NotNull CompoundBinaryTag writeCompoundComponent(@NotNull Component component) { + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(); + StyleSerializer.serialize(component.style(), builder, this); + + if (component instanceof TextComponent) { + this.writeComponentType(TYPE_TEXT, builder); + builder.putString(TEXT, ((TextComponent) component).content()); + } else if (component instanceof TranslatableComponent) { + this.writeComponentType(TYPE_TRANSLATABLE, builder); + + TranslatableComponent translatable = (TranslatableComponent) component; + builder.putString(TRANSLATE_KEY, translatable.key()); + + List arguments = translatable.arguments(); + + if (!arguments.isEmpty()) { + List argumentsTags = new ArrayList<>(); + + for (TranslationArgument argument : arguments) { + argumentsTags.add(this.writeCompoundComponent(argument.asComponent())); + } + + builder.put(TRANSLATE_WITH, ListBinaryTag.from(argumentsTags)); + } + + String fallback = translatable.fallback(); + if (fallback != null) { + builder.putString(TRANSLATE_FALLBACK, fallback); + } + } else if (component instanceof KeybindComponent) { + this.writeComponentType(TYPE_KEYBIND, builder); + builder.putString(KEYBIND, ((KeybindComponent) component).keybind()); + } else if (component instanceof ScoreComponent) { + this.writeComponentType(TYPE_SCORE, builder); + ScoreComponent score = (ScoreComponent) component; + + CompoundBinaryTag.Builder scoreBuilder = CompoundBinaryTag.builder() + .putString(SCORE_NAME, score.name()) + .putString(SCORE_OBJECTIVE, score.objective()); + + builder.put(SCORE, scoreBuilder.build()); + } else if (component instanceof SelectorComponent) { + this.writeComponentType(TYPE_SELECTOR, builder); + + SelectorComponent selector = (SelectorComponent) component; + builder.putString(SELECTOR, selector.pattern()); + + Component separator = selector.separator(); + if (separator != null) { + builder.put(SELECTOR_SEPARATOR, this.serialize(separator)); + } + } else if (component instanceof NBTComponent) { + this.writeComponentType(TYPE_NBT, builder); + + NBTComponent nbt = (NBTComponent) component; + builder.putString(NBT, nbt.nbtPath()); + builder.putBoolean(NBT_INTERPRET, nbt.interpret()); + + Component separator = nbt.separator(); + if (separator != null) { + builder.put(NBT_SEPARATOR, this.serialize(separator)); + } + + if (nbt instanceof BlockNBTComponent) { + builder.putString(NBT_BLOCK, ((BlockNBTComponent) nbt).pos().asString()); + } else if (nbt instanceof EntityNBTComponent) { + builder.putString(NBT_ENTITY, ((EntityNBTComponent) nbt).selector()); + } else if (nbt instanceof StorageNBTComponent) { + builder.putString(NBT_STORAGE, ((StorageNBTComponent) nbt).storage().asString()); + } else { + throw notSureHowToSerialize(component); + } + } else { + throw notSureHowToSerialize(component); + } + + List children = component.children(); + + if (!children.isEmpty()) { + List serializedChildren = new ArrayList<>(); + + for (Component child : children) { + serializedChildren.add(this.writeCompoundComponent(child)); + } + + builder.put(EXTRA, ListBinaryTag.from(serializedChildren)); + } + + return builder.build(); + } + + @NotNull OptionState flags() { + return this.flags; + } + + private void writeComponentType(final String componentType, final CompoundBinaryTag.Builder builder) { + if (this.flags.value(NBTSerializerOptions.SERIALIZE_COMPONENT_TYPES)) { + builder.putString(TYPE, componentType); + } + } + + private static IllegalArgumentException notSureHowToSerialize(final Component component) { + return new IllegalArgumentException("Don't know how to serialize " + component + " as a Component"); + } + + static final class BuilderImpl implements NBTComponentSerializer.Builder { + + private OptionState flags = OptionState.emptyOptionState(); + + BuilderImpl() { + BUILDER.accept(this); // let service provider touch the builder before anybody else touches it + } + + @Override + public @NotNull Builder options(@NotNull OptionState flags) { + this.flags = requireNonNull(flags, "flags"); + return this; + } + + @Override + public @NotNull Builder editOptions(@NotNull Consumer optionEditor) { + final OptionState.Builder builder = OptionState.optionState() + .values(this.flags); + requireNonNull(optionEditor, "optionEditor").accept(builder); + this.flags = builder.build(); + return this; + } + + @Override + public @NotNull NBTComponentSerializer build() { + return new NBTComponentSerializerImpl(this.flags); + } + } +} diff --git a/text-serializer-nbt/src/main/java/net/kyori/adventure/text/serializer/nbt/NBTDataComponentValue.java b/text-serializer-nbt/src/main/java/net/kyori/adventure/text/serializer/nbt/NBTDataComponentValue.java new file mode 100644 index 000000000..69c346ac5 --- /dev/null +++ b/text-serializer-nbt/src/main/java/net/kyori/adventure/text/serializer/nbt/NBTDataComponentValue.java @@ -0,0 +1,58 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2024 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.serializer.nbt; + +import net.kyori.adventure.nbt.BinaryTag; +import net.kyori.adventure.text.event.DataComponentValue; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +/** + * An {@link DataComponentValue} implementation that holds a {@linkplain BinaryTag binary tag}. + * + *

This holder is exposed to allow conversions to/from NBT data holders.

+ * + * @since 4.18.0 + */ +@ApiStatus.NonExtendable +public interface NBTDataComponentValue extends DataComponentValue { + /** + * The contained element, intended for read-only use. + * + * @return a copy of the contained element + * @since 4.18.0 + */ + @NotNull BinaryTag binaryTag(); + + /** + * Create a box for item data that can be understood by the NBT serializer. + * + * @param binaryTag the item data to hold + * @return a newly created item data holder instance + * @since 4.18.0 + */ + static @NotNull NBTDataComponentValue nbtDataComponentValue(@NotNull BinaryTag binaryTag) { + return new NBTDataComponentValueImpl(binaryTag); + } +} diff --git a/text-serializer-nbt/src/main/java/net/kyori/adventure/text/serializer/nbt/NBTDataComponentValueImpl.java b/text-serializer-nbt/src/main/java/net/kyori/adventure/text/serializer/nbt/NBTDataComponentValueImpl.java new file mode 100644 index 000000000..bd94d5558 --- /dev/null +++ b/text-serializer-nbt/src/main/java/net/kyori/adventure/text/serializer/nbt/NBTDataComponentValueImpl.java @@ -0,0 +1,56 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2024 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.serializer.nbt; + +import net.kyori.adventure.nbt.BinaryTag; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; + +final class NBTDataComponentValueImpl implements NBTDataComponentValue { + + private final BinaryTag binaryTag; + + NBTDataComponentValueImpl(@NotNull BinaryTag binaryTag) { + this.binaryTag = binaryTag; + } + + @Override + public @NotNull BinaryTag binaryTag() { + return this.binaryTag; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof NBTDataComponentValueImpl)) return false; + NBTDataComponentValueImpl that = (NBTDataComponentValueImpl) o; + return Objects.equals(this.binaryTag, that.binaryTag); + } + + @Override + public int hashCode() { + return Objects.hashCode(this.binaryTag); + } +} diff --git a/text-serializer-nbt/src/main/java/net/kyori/adventure/text/serializer/nbt/NBTSerializerOptions.java b/text-serializer-nbt/src/main/java/net/kyori/adventure/text/serializer/nbt/NBTSerializerOptions.java new file mode 100644 index 000000000..d32eab1ab --- /dev/null +++ b/text-serializer-nbt/src/main/java/net/kyori/adventure/text/serializer/nbt/NBTSerializerOptions.java @@ -0,0 +1,56 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2024 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.serializer.nbt; + +import net.kyori.option.Option; + +/** + * Options that can apply to {@linkplain NBTComponentSerializer NBT serializers}. + * + *

See serializer documentation for specific details on which flags are supported.

+ * + * @since 4.18.0 + */ +public final class NBTSerializerOptions { + /** + * Whether to emit text components with no style and no children as plain text. + * + * @since 4.18.0 + * @sinceMinecraft 1.20.3 + */ + public static final Option EMIT_COMPACT_TEXT_COMPONENT = Option.booleanOption(key("emit/compact_text_component"), true); + /** + * Whether to serialize the types of {@linkplain net.kyori.adventure.text.Component components}. + * + * @since 4.18.0 + */ + public static final Option SERIALIZE_COMPONENT_TYPES = Option.booleanOption(key("serialize/component-types"), true); + + private NBTSerializerOptions() { + } + + private static String key(final String value) { + return "adventure:nbt/" + value; + } +} diff --git a/text-serializer-nbt/src/main/java/net/kyori/adventure/text/serializer/nbt/StyleSerializer.java b/text-serializer-nbt/src/main/java/net/kyori/adventure/text/serializer/nbt/StyleSerializer.java new file mode 100644 index 000000000..ad0ab12cb --- /dev/null +++ b/text-serializer-nbt/src/main/java/net/kyori/adventure/text/serializer/nbt/StyleSerializer.java @@ -0,0 +1,163 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2024 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.serializer.nbt; + +import net.kyori.adventure.key.Key; +import net.kyori.adventure.nbt.BinaryTag; +import net.kyori.adventure.nbt.ByteBinaryTag; +import net.kyori.adventure.nbt.CompoundBinaryTag; +import net.kyori.adventure.nbt.StringBinaryTag; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.Style; +import net.kyori.adventure.text.format.TextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.jetbrains.annotations.NotNull; + +final class StyleSerializer { + + private static final String COLOR = "color"; + private static final String BOLD = "bold"; + private static final String ITALIC = "italic"; + private static final String UNDERLINED = "underlined"; + private static final String STRIKETHROUGH = "strikethrough"; + private static final String OBFUSCATED = "obfuscated"; + private static final String FONT = "font"; + private static final String INSERTION = "insertion"; + private static final String CLICK_EVENT = "clickEvent"; + private static final String HOVER_EVENT = "hoverEvent"; + + private StyleSerializer() { + } + + static @NotNull Style deserialize(@NotNull CompoundBinaryTag compound, @NotNull NBTComponentSerializerImpl serializer) { + Style.Builder styleBuilder = Style.style(); + + String colorString = compound.getString(COLOR); + if (!colorString.isEmpty()) { + if (colorString.startsWith(TextColor.HEX_PREFIX)) { + styleBuilder.color(TextColor.fromHexString(colorString)); + } else { + styleBuilder.color(NamedTextColor.NAMES.value(colorString)); + } + } + + styleBuilder.decoration(TextDecoration.BOLD, readOptionalState(BOLD, compound)) + .decoration(TextDecoration.ITALIC, readOptionalState(ITALIC, compound)) + .decoration(TextDecoration.UNDERLINED, readOptionalState(UNDERLINED, compound)) + .decoration(TextDecoration.STRIKETHROUGH, readOptionalState(STRIKETHROUGH, compound)) + .decoration(TextDecoration.OBFUSCATED, readOptionalState(OBFUSCATED, compound)); + + String fontString = compound.getString(FONT); + if (!fontString.isEmpty()) { + styleBuilder.font(Key.key(fontString)); + } + + BinaryTag binaryInsertion = compound.get(INSERTION); + if (binaryInsertion != null) { + styleBuilder.insertion(((StringBinaryTag) binaryInsertion).value()); + } + + BinaryTag binaryClickEvent = compound.get(CLICK_EVENT); + if (binaryClickEvent != null) { + styleBuilder.clickEvent(ClickEventSerializer.deserialize((CompoundBinaryTag) binaryClickEvent)); + } + + BinaryTag binaryHoverEvent = compound.get(HOVER_EVENT); + if (binaryHoverEvent != null) { + styleBuilder.hoverEvent(HoverEventSerializer.deserialize((CompoundBinaryTag) binaryHoverEvent, serializer)); + } + + return styleBuilder.build(); + } + + static void serialize(@NotNull Style style, CompoundBinaryTag.@NotNull Builder builder, + @NotNull NBTComponentSerializerImpl serializer) { + TextColor color = style.color(); + if (color != null) { + builder.putString(COLOR, color.toString()); + } + + style.decorations().forEach((decoration, state) -> { + if (state != TextDecoration.State.NOT_SET) { + String decorationName; + + switch (decoration) { + case OBFUSCATED: + decorationName = OBFUSCATED; + break; + case BOLD: + decorationName = BOLD; + break; + case STRIKETHROUGH: + decorationName = STRIKETHROUGH; + break; + case UNDERLINED: + decorationName = UNDERLINED; + break; + case ITALIC: + decorationName = ITALIC; + break; + default: + // Never called, but needed for proper compilation + throw new IllegalStateException("Unknown text decoration: " + decoration); + } + + builder.putBoolean(decorationName, state == TextDecoration.State.TRUE); + } + }); + + Key font = style.font(); + + if (font != null) { + builder.putString(FONT, font.asString()); + } + + String insertion = style.insertion(); + + if (insertion != null) { + builder.putString(INSERTION, insertion); + } + + ClickEvent clickEvent = style.clickEvent(); + + if (clickEvent != null) { + builder.put(CLICK_EVENT, ClickEventSerializer.serialize(clickEvent)); + } + + HoverEvent hoverEvent = style.hoverEvent(); + if (hoverEvent != null) { + builder.put(HOVER_EVENT, HoverEventSerializer.serialize(hoverEvent, serializer)); + } + } + + private static TextDecoration.@NotNull State readOptionalState(@NotNull String key, @NotNull CompoundBinaryTag compound) { + BinaryTag tag = compound.get(key); + if (tag == null) { + return TextDecoration.State.NOT_SET; + } + return TextDecoration.State.byBoolean(((ByteBinaryTag) tag).value() != 0); + } +} diff --git a/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/BlockNBTComponentTest.java b/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/BlockNBTComponentTest.java new file mode 100644 index 000000000..ee66aeed4 --- /dev/null +++ b/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/BlockNBTComponentTest.java @@ -0,0 +1,54 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2024 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.serializer.nbt; + +import net.kyori.adventure.text.BlockNBTComponent; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.junit.jupiter.api.Test; + +import static net.kyori.adventure.text.BlockNBTComponent.WorldPos.Coordinate.absolute; + +final class BlockNBTComponentTest implements NBTComponentTest { + @Test + public void testNoStyling() { + this.test(Component.blockNBT( + "abc", + true, + Component.text("separator?"), + BlockNBTComponent.WorldPos.worldPos(absolute(435), absolute(512), absolute(4243))) + ); + } + + @Test + public void testWithStyling() { + this.test(Component.blockNBT() + .nbtPath("cab") + .interpret(false) + .separator(Component.text("another-separator", NamedTextColor.RED, TextDecoration.OBFUSCATED)) + .worldPos(absolute(44), absolute(51), absolute(42)) + .build()); + } +} diff --git a/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/ClickEventTest.java b/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/ClickEventTest.java new file mode 100644 index 000000000..926e481ba --- /dev/null +++ b/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/ClickEventTest.java @@ -0,0 +1,60 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2024 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.serializer.nbt; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; +import org.junit.jupiter.api.Test; + +final class ClickEventTest implements NBTComponentTest { + @Test + public void testUrl() { + this.test(Component.empty().clickEvent(ClickEvent.openUrl("https://docs.advntr.dev/"))); + } + + @Test + public void testFile() { + this.test(Component.empty().clickEvent(ClickEvent.openFile("/root/some-file.extension"))); + } + + @Test + public void testRunCommand() { + this.test(Component.empty().clickEvent(ClickEvent.runCommand("/help"))); + } + + @Test + public void testSuggestCommand() { + this.test(Component.empty().clickEvent(ClickEvent.suggestCommand("/?"))); + } + + @Test + public void testChangePage() { + this.test(Component.empty().clickEvent(ClickEvent.changePage(6))); + } + + @Test + public void testCopyToClipboard() { + this.test(Component.empty().clickEvent(ClickEvent.copyToClipboard("abcdxyz"))); + } +} diff --git a/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/EntityNBTComponentTest.java b/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/EntityNBTComponentTest.java new file mode 100644 index 000000000..d42756db1 --- /dev/null +++ b/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/EntityNBTComponentTest.java @@ -0,0 +1,46 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2024 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.serializer.nbt; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.junit.jupiter.api.Test; + +final class EntityNBTComponentTest implements NBTComponentTest { + @Test + public void testNoStyling() { + this.test(Component.entityNBT("abc", "@a")); + } + + @Test + public void testWithStyling() { + this.test(Component.entityNBT() + .nbtPath("cab") + .interpret(true) + .separator(Component.text("another-separator", NamedTextColor.RED, TextDecoration.OBFUSCATED)) + .selector("@p") + .build()); + } +} diff --git a/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/HoverEventTest.java b/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/HoverEventTest.java new file mode 100644 index 000000000..1f44bbca5 --- /dev/null +++ b/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/HoverEventTest.java @@ -0,0 +1,63 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2024 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.serializer.nbt; + +import com.google.common.collect.ImmutableMap; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.nbt.IntBinaryTag; +import net.kyori.adventure.nbt.StringBinaryTag; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.junit.jupiter.api.Test; + +import java.util.UUID; + +final class HoverEventTest implements NBTComponentTest { + @Test + public void testShowText() { + this.test(Component.empty().hoverEvent( + HoverEvent.showText(Component.text("Hi!", NamedTextColor.RED, TextDecoration.STRIKETHROUGH)) + )); + } + + @Test + public void testShowItem() { + this.test(Component.empty().hoverEvent(HoverEvent.showItem(Key.key("netherite_chestplate"), 2, ImmutableMap.of( + Key.key("count"), NBTDataComponentValue.nbtDataComponentValue(IntBinaryTag.intBinaryTag(2)), + Key.key("display_name"), NBTDataComponentValue.nbtDataComponentValue(StringBinaryTag.stringBinaryTag("test")) + )))); + } + + @Test + public void testShowEntity() { + this.test(Component.empty().hoverEvent( + HoverEvent.showEntity( + Key.key("enderman"), + UUID.randomUUID(), + Component.text("An entity name", NamedTextColor.RED, TextDecoration.STRIKETHROUGH)) + )); + } +} diff --git a/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/KeybindComponentTest.java b/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/KeybindComponentTest.java new file mode 100644 index 000000000..22e26b2a7 --- /dev/null +++ b/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/KeybindComponentTest.java @@ -0,0 +1,42 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2024 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.serializer.nbt; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.junit.jupiter.api.Test; + +final class KeybindComponentTest implements NBTComponentTest { + @Test + public void testNoStyling() { + this.test(Component.translatable("some.translation")); + } + + @Test + public void testWithStyling() { + this.test(Component.translatable("another-translation", NamedTextColor.GOLD, TextDecoration.STRIKETHROUGH) + .decoration(TextDecoration.ITALIC, false)); + } +} diff --git a/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/NBTComponentTest.java b/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/NBTComponentTest.java new file mode 100644 index 000000000..226e657f7 --- /dev/null +++ b/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/NBTComponentTest.java @@ -0,0 +1,46 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2024 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.serializer.nbt; + +import net.kyori.adventure.nbt.BinaryTag; +import net.kyori.adventure.nbt.CompoundBinaryTag; +import net.kyori.adventure.text.Component; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Assertions; + +interface NBTComponentTest { + default void test(@NotNull Component component) { + this.test(component, CompoundBinaryTag.class); + } + + default void test(@NotNull Component component, @NotNull Class expectedTag) { + NBTComponentSerializer serializer = NBTComponentSerializer.nbt(); + + BinaryTag serialized = serializer.serialize(component); + Assertions.assertInstanceOf(expectedTag, serialized); + + Component deserialized = serializer.deserialize(serialized); + Assertions.assertEquals(component, deserialized); + } +} diff --git a/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/ScoreComponentTest.java b/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/ScoreComponentTest.java new file mode 100644 index 000000000..1277fe63d --- /dev/null +++ b/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/ScoreComponentTest.java @@ -0,0 +1,43 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2024 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.serializer.nbt; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.junit.jupiter.api.Test; + +final class ScoreComponentTest implements NBTComponentTest { + @Test + public void testNoStyling() { + this.test(Component.score("a-score", "dummy")); + } + + @Test + public void testWithStyling() { + this.test(Component.score("some-score", "another-dummy-objective") + .decorate(TextDecoration.BOLD) + .color(NamedTextColor.RED)); + } +} diff --git a/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/SelectorComponentTest.java b/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/SelectorComponentTest.java new file mode 100644 index 000000000..505abc8b0 --- /dev/null +++ b/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/SelectorComponentTest.java @@ -0,0 +1,43 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2024 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.serializer.nbt; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.junit.jupiter.api.Test; + +final class SelectorComponentTest implements NBTComponentTest { + @Test + public void testNoStyling() { + this.test(Component.selector("@p", Component.text("a-separator"))); + } + + @Test + public void testWithStyling() { + this.test(Component.selector("@e", Component.text("some-separator", NamedTextColor.RED, TextDecoration.STRIKETHROUGH)) + .color(NamedTextColor.GOLD) + .decorate(TextDecoration.BOLD)); + } +} diff --git a/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/StorageNBTComponentTest.java b/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/StorageNBTComponentTest.java new file mode 100644 index 000000000..ef386d8b8 --- /dev/null +++ b/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/StorageNBTComponentTest.java @@ -0,0 +1,49 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2024 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.serializer.nbt; + +import net.kyori.adventure.key.Key; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.junit.jupiter.api.Test; + +final class StorageNBTComponentTest implements NBTComponentTest { + @Test + public void testNoStyling() { + this.test(Component.storageNBT("dsa", true, Component.text("separator?"), Key.key("minecraft", "chest"))); + } + + @Test + public void testWithStyling() { + this.test(Component.storageNBT() + .nbtPath("rsaby") + .interpret(false) + .separator(Component.text("another-separator", NamedTextColor.RED, TextDecoration.OBFUSCATED)) + .storage(Key.key("dummy", "storage")) + .color(NamedTextColor.YELLOW) + .decorate(TextDecoration.BOLD) + .build()); + } +} diff --git a/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/TextComponentTest.java b/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/TextComponentTest.java new file mode 100644 index 000000000..f30b47dbe --- /dev/null +++ b/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/TextComponentTest.java @@ -0,0 +1,42 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2024 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.serializer.nbt; + +import net.kyori.adventure.nbt.StringBinaryTag; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.junit.jupiter.api.Test; + +final class TextComponentTest implements NBTComponentTest { + @Test + public void testNoStyling() { + this.test(Component.text("Codestech was here!"), StringBinaryTag.class); + } + + @Test + public void testWithStyling() { + this.test(Component.text("A component with style!", NamedTextColor.RED, TextDecoration.BOLD)); + } +} diff --git a/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/TranslatableComponentTest.java b/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/TranslatableComponentTest.java new file mode 100644 index 000000000..acb291996 --- /dev/null +++ b/text-serializer-nbt/src/test/java/net/kyori/adventure/text/serializer/nbt/TranslatableComponentTest.java @@ -0,0 +1,42 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2024 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.text.serializer.nbt; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.junit.jupiter.api.Test; + +final class TranslatableComponentTest implements NBTComponentTest { + @Test + public void testNoStyling() { + this.test(Component.translatable("some.translation")); + } + + @Test + public void testWithStyling() { + this.test(Component.translatable("another-translation", NamedTextColor.GOLD, TextDecoration.STRIKETHROUGH) + .decoration(TextDecoration.ITALIC, false)); + } +}