diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0bf164d50..56041ddf9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,6 +17,7 @@ truth = "1.1.5" # shared examination-api = { module = "net.kyori:examination-api", version.ref = "examination" } examination-string = { module = "net.kyori:examination-string", version.ref = "examination" } +option = { module = "net.kyori:option", version = "1.0.0" } guava = { module = "com.google.guava:guava", version.ref = "guava" } guava-testlib = { module = "com.google.guava:guava-testlib", version.ref = "guava" } jetbrainsAnnotations = "org.jetbrains:annotations:24.1.0" diff --git a/nbt/build.gradle.kts b/nbt/build.gradle.kts index 4de83c6f6..c4c8dff0d 100644 --- a/nbt/build.gradle.kts +++ b/nbt/build.gradle.kts @@ -3,6 +3,7 @@ plugins { } dependencies { + api(libs.option) api(libs.examination.api) api(libs.examination.string) compileOnlyApi(libs.jetbrainsAnnotations) diff --git a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/ComponentSerializerImpl.java b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/ComponentSerializerImpl.java index 0fb070b54..c7170eaf1 100644 --- a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/ComponentSerializerImpl.java +++ b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/ComponentSerializerImpl.java @@ -52,6 +52,8 @@ import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.TranslatableComponent; import net.kyori.adventure.text.TranslationArgument; +import net.kyori.adventure.text.serializer.json.JSONOptions; +import net.kyori.option.OptionState; import org.jetbrains.annotations.Nullable; import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.EXTRA; @@ -76,13 +78,15 @@ final class ComponentSerializerImpl extends TypeAdapter { static final Type COMPONENT_LIST_TYPE = new TypeToken>() {}.getType(); static final Type TRANSLATABLE_ARGUMENT_LIST_TYPE = new TypeToken>() {}.getType(); - static TypeAdapter create(final Gson gson) { - return new ComponentSerializerImpl(gson).nullSafe(); + static TypeAdapter create(final OptionState features, final Gson gson) { + return new ComponentSerializerImpl(features.value(JSONOptions.EMIT_COMPACT_TEXT_COMPONENT), gson).nullSafe(); } + private final boolean emitCompactTextComponent; private final Gson gson; - private ComponentSerializerImpl(final Gson gson) { + private ComponentSerializerImpl(final boolean emitCompactTextComponent, final Gson gson) { + this.emitCompactTextComponent = emitCompactTextComponent; this.gson = gson; } @@ -232,6 +236,16 @@ private static , B extends NBTComponentBuilder, Buildable.Builder, JSONComponentSerializer.Builder { + @Override + @NotNull Builder options(final @NotNull OptionState flags); + + @Override + @NotNull Builder editOptions(final @NotNull Consumer optionEditor); + /** * Sets that the serializer should downsample hex colors to named colors. * @@ -129,7 +137,9 @@ interface Builder extends AbstractBuilder, Buildable.Bu * @since 4.0.0 */ @Override - @NotNull Builder downsampleColors(); + default @NotNull Builder downsampleColors() { + return this.editOptions(features -> features.value(JSONOptions.EMIT_RGB, false)); + } /** * Sets a serializer that will be used to interpret legacy hover event {@code value} payloads. @@ -154,8 +164,11 @@ interface Builder extends AbstractBuilder, Buildable.Bu * * @since 4.0.0 */ + @Deprecated @Override - @NotNull Builder emitLegacyHoverEvent(); + default @NotNull Builder emitLegacyHoverEvent() { + return this.editOptions(b -> b.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.BOTH)); + } /** * Builds the serializer. diff --git a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/GsonComponentSerializerImpl.java b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/GsonComponentSerializerImpl.java index acf1b65f8..d71a2d4f4 100644 --- a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/GsonComponentSerializerImpl.java +++ b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/GsonComponentSerializerImpl.java @@ -30,10 +30,14 @@ import java.util.function.Consumer; import java.util.function.UnaryOperator; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.json.JSONOptions; import net.kyori.adventure.util.Services; +import net.kyori.option.OptionState; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import static java.util.Objects.requireNonNull; + final class GsonComponentSerializerImpl implements GsonComponentSerializer { private static final Optional SERVICE = Services.service(Provider.class); static final Consumer BUILDER = SERVICE @@ -46,24 +50,22 @@ final class GsonComponentSerializerImpl implements GsonComponentSerializer { static final class Instances { static final GsonComponentSerializer INSTANCE = SERVICE .map(Provider::gson) - .orElseGet(() -> new GsonComponentSerializerImpl(false, null, false)); + .orElseGet(() -> new GsonComponentSerializerImpl(JSONOptions.byDataVersion(), null)); static final GsonComponentSerializer LEGACY_INSTANCE = SERVICE .map(Provider::gsonLegacy) - .orElseGet(() -> new GsonComponentSerializerImpl(true, null, true)); + .orElseGet(() -> new GsonComponentSerializerImpl(JSONOptions.byDataVersion().at(2525 /* just before 1.16 */), null)); } private final Gson serializer; private final UnaryOperator populator; - private final boolean downsampleColor; private final net.kyori.adventure.text.serializer.json.@Nullable LegacyHoverEventSerializer legacyHoverSerializer; - private final boolean emitLegacyHover; + private final OptionState flags; - GsonComponentSerializerImpl(final boolean downsampleColor, final net.kyori.adventure.text.serializer.json.@Nullable LegacyHoverEventSerializer legacyHoverSerializer, final boolean emitLegacyHover) { - this.downsampleColor = downsampleColor; + GsonComponentSerializerImpl(final OptionState flags, final net.kyori.adventure.text.serializer.json.@Nullable LegacyHoverEventSerializer legacyHoverSerializer) { + this.flags = flags; this.legacyHoverSerializer = legacyHoverSerializer; - this.emitLegacyHover = emitLegacyHover; this.populator = builder -> { - builder.registerTypeAdapterFactory(new SerializerFactory(downsampleColor, legacyHoverSerializer, emitLegacyHover)); + builder.registerTypeAdapterFactory(new SerializerFactory(flags, legacyHoverSerializer)); return builder; }; this.serializer = this.populator.apply( @@ -120,9 +122,8 @@ static final class Instances { } static final class BuilderImpl implements Builder { - private boolean downsampleColor = false; + private OptionState flags = JSONOptions.byDataVersion(); // latest private net.kyori.adventure.text.serializer.json.@Nullable LegacyHoverEventSerializer legacyHoverSerializer; - private boolean emitLegacyHover = false; BuilderImpl() { BUILDER.accept(this); // let service provider touch the builder before anybody else touches it @@ -130,36 +131,34 @@ static final class BuilderImpl implements Builder { BuilderImpl(final GsonComponentSerializerImpl serializer) { this(); - this.downsampleColor = serializer.downsampleColor; - this.emitLegacyHover = serializer.emitLegacyHover; + this.flags = serializer.flags; this.legacyHoverSerializer = serializer.legacyHoverSerializer; } @Override - public @NotNull Builder downsampleColors() { - this.downsampleColor = true; + public @NotNull Builder options(final @NotNull OptionState flags) { + this.flags = requireNonNull(flags, "flags"); return this; } @Override - public @NotNull Builder legacyHoverEventSerializer(final net.kyori.adventure.text.serializer.json.@Nullable LegacyHoverEventSerializer serializer) { - this.legacyHoverSerializer = serializer; + public @NotNull Builder editOptions(final @NotNull Consumer optionEditor) { + final OptionState.Builder builder = OptionState.optionState() + .values(this.flags); + requireNonNull(optionEditor, "flagEditor").accept(builder); + this.flags = builder.build(); return this; } @Override - public @NotNull Builder emitLegacyHoverEvent() { - this.emitLegacyHover = true; + public @NotNull Builder legacyHoverEventSerializer(final net.kyori.adventure.text.serializer.json.@Nullable LegacyHoverEventSerializer serializer) { + this.legacyHoverSerializer = serializer; return this; } @Override public @NotNull GsonComponentSerializer build() { - if (this.legacyHoverSerializer == null) { - return this.downsampleColor ? Instances.LEGACY_INSTANCE : Instances.INSTANCE; - } else { - return new GsonComponentSerializerImpl(this.downsampleColor, this.legacyHoverSerializer, this.emitLegacyHover); - } + return new GsonComponentSerializerImpl(this.flags, this.legacyHoverSerializer); } } } diff --git a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/SerializerFactory.java b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/SerializerFactory.java index 3bd77c814..52b081fe1 100644 --- a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/SerializerFactory.java +++ b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/SerializerFactory.java @@ -37,6 +37,8 @@ import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.TextColor; import net.kyori.adventure.text.format.TextDecoration; +import net.kyori.adventure.text.serializer.json.JSONOptions; +import net.kyori.option.OptionState; import org.jetbrains.annotations.Nullable; final class SerializerFactory implements TypeAdapterFactory { @@ -55,14 +57,12 @@ final class SerializerFactory implements TypeAdapterFactory { static final Class UUID_TYPE = UUID.class; static final Class TRANSLATION_ARGUMENT_TYPE = TranslationArgument.class; - private final boolean downsampleColors; + private final OptionState features; private final net.kyori.adventure.text.serializer.json.LegacyHoverEventSerializer legacyHoverSerializer; - private final boolean emitLegacyHover; - SerializerFactory(final boolean downsampleColors, final net.kyori.adventure.text.serializer.json.@Nullable LegacyHoverEventSerializer legacyHoverSerializer, final boolean emitLegacyHover) { - this.downsampleColors = downsampleColors; + SerializerFactory(final OptionState features, final net.kyori.adventure.text.serializer.json.@Nullable LegacyHoverEventSerializer legacyHoverSerializer) { + this.features = features; this.legacyHoverSerializer = legacyHoverSerializer; - this.emitLegacyHover = emitLegacyHover; } @Override @@ -70,11 +70,11 @@ final class SerializerFactory implements TypeAdapterFactory { public TypeAdapter create(final Gson gson, final TypeToken type) { final Class rawType = type.getRawType(); if (COMPONENT_TYPE.isAssignableFrom(rawType)) { - return (TypeAdapter) ComponentSerializerImpl.create(gson); + return (TypeAdapter) ComponentSerializerImpl.create(this.features, gson); } else if (KEY_TYPE.isAssignableFrom(rawType)) { return (TypeAdapter) KeySerializer.INSTANCE; } else if (STYLE_TYPE.isAssignableFrom(rawType)) { - return (TypeAdapter) StyleSerializer.create(this.legacyHoverSerializer, this.emitLegacyHover, gson); + return (TypeAdapter) StyleSerializer.create(this.legacyHoverSerializer, this.features, gson); } else if (CLICK_ACTION_TYPE.isAssignableFrom(rawType)) { return (TypeAdapter) ClickEventActionSerializer.INSTANCE; } else if (HOVER_ACTION_TYPE.isAssignableFrom(rawType)) { @@ -86,13 +86,13 @@ public TypeAdapter create(final Gson gson, final TypeToken type) { } else if (COLOR_WRAPPER_TYPE.isAssignableFrom(rawType)) { return (TypeAdapter) TextColorWrapper.Serializer.INSTANCE; } else if (COLOR_TYPE.isAssignableFrom(rawType)) { - return (TypeAdapter) (this.downsampleColors ? TextColorSerializer.DOWNSAMPLE_COLOR : TextColorSerializer.INSTANCE); + return (TypeAdapter) (this.features.value(JSONOptions.EMIT_RGB) ? TextColorSerializer.INSTANCE : TextColorSerializer.DOWNSAMPLE_COLOR); } else if (TEXT_DECORATION_TYPE.isAssignableFrom(rawType)) { return (TypeAdapter) TextDecorationSerializer.INSTANCE; } else if (BLOCK_NBT_POS_TYPE.isAssignableFrom(rawType)) { return (TypeAdapter) BlockNBTComponentPosSerializer.INSTANCE; } else if (UUID_TYPE.isAssignableFrom(rawType)) { - return (TypeAdapter) UUIDSerializer.INSTANCE; + return (TypeAdapter) UUIDSerializer.uuidSerializer(this.features); } else if (TRANSLATION_ARGUMENT_TYPE.isAssignableFrom(rawType)) { return (TypeAdapter) TranslationArgumentSerializer.create(gson); } else { diff --git a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/ShowEntitySerializer.java b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/ShowEntitySerializer.java index 74500bd03..ecc4d2593 100644 --- a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/ShowEntitySerializer.java +++ b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/ShowEntitySerializer.java @@ -87,7 +87,7 @@ public void write(final JsonWriter out, final HoverEvent.ShowEntity value) throw this.gson.toJson(value.type(), SerializerFactory.KEY_TYPE, out); out.name(SHOW_ENTITY_ID); - out.value(value.id().toString()); + this.gson.toJson(value.id(), SerializerFactory.UUID_TYPE, out); final @Nullable Component name = value.name(); if (name != null) { diff --git a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/StyleSerializer.java b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/StyleSerializer.java index eab226419..af48b0b6d 100644 --- a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/StyleSerializer.java +++ b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/StyleSerializer.java @@ -43,7 +43,9 @@ import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.TextColor; import net.kyori.adventure.text.format.TextDecoration; +import net.kyori.adventure.text.serializer.json.JSONOptions; import net.kyori.adventure.util.Codec; +import net.kyori.option.OptionState; import org.jetbrains.annotations.Nullable; import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.CLICK_EVENT; @@ -80,17 +82,34 @@ final class StyleSerializer extends TypeAdapter