From a151352e200df4b69206417ac4d348212a75173a Mon Sep 17 00:00:00 2001 From: Riley Park Date: Thu, 31 Oct 2024 23:46:45 -0700 Subject: [PATCH 01/15] feat: initial work for shadow colors --- .../text/AbstractComponentBuilder.java | 15 +++++ .../net/kyori/adventure/text/Component.java | 33 +++++++++++ .../kyori/adventure/text/ScopedComponent.java | 13 +++++ .../adventure/text/format/ShadowColor.java | 41 +++++++++++++ .../text/format/ShadowColorImpl.java | 37 ++++++++++++ .../adventure/text/format/StyleGetter.java | 8 +++ .../adventure/text/format/StyleImpl.java | 57 +++++++++++++++---- .../adventure/text/format/StyleSetter.java | 18 ++++++ .../serializer/gson/SerializerFactory.java | 4 ++ .../gson/ShadowColorSerializer.java | 49 ++++++++++++++++ .../text/serializer/gson/StyleSerializer.java | 8 +++ .../json/JSONComponentConstants.java | 1 + 12 files changed, 274 insertions(+), 10 deletions(-) create mode 100644 api/src/main/java/net/kyori/adventure/text/format/ShadowColor.java create mode 100644 api/src/main/java/net/kyori/adventure/text/format/ShadowColorImpl.java create mode 100644 text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/ShadowColorSerializer.java diff --git a/api/src/main/java/net/kyori/adventure/text/AbstractComponentBuilder.java b/api/src/main/java/net/kyori/adventure/text/AbstractComponentBuilder.java index 44de2449b..25ce1eb48 100644 --- a/api/src/main/java/net/kyori/adventure/text/AbstractComponentBuilder.java +++ b/api/src/main/java/net/kyori/adventure/text/AbstractComponentBuilder.java @@ -33,6 +33,7 @@ import net.kyori.adventure.key.Key; import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.event.HoverEventSource; +import net.kyori.adventure.text.format.ShadowColor; import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.TextColor; import net.kyori.adventure.text.format.TextDecoration; @@ -236,6 +237,20 @@ private void prepareChildren() { return (B) this; } + @Override + @SuppressWarnings("unchecked") + public @NotNull B shadowColor(final @Nullable ShadowColor color) { + this.styleBuilder().shadowColor(color); + return (B) this; + } + + @Override + @SuppressWarnings("unchecked") + public @NotNull B shadowColorIfAbsent(final @Nullable ShadowColor color) { + this.styleBuilder().shadowColorIfAbsent(color); + return (B) this; + } + @Override @SuppressWarnings("unchecked") public @NotNull B decoration(final @NotNull TextDecoration decoration, final TextDecoration.@NotNull State state) { diff --git a/api/src/main/java/net/kyori/adventure/text/Component.java b/api/src/main/java/net/kyori/adventure/text/Component.java index e120afe07..8ddec4eaf 100644 --- a/api/src/main/java/net/kyori/adventure/text/Component.java +++ b/api/src/main/java/net/kyori/adventure/text/Component.java @@ -45,6 +45,7 @@ import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.text.event.HoverEventSource; +import net.kyori.adventure.text.format.ShadowColor; import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.StyleBuilderApplicable; import net.kyori.adventure.text.format.StyleGetter; @@ -2189,6 +2190,11 @@ default void detectCycle(final @NotNull Component that) { return this.style().color(); } + @Override + default @Nullable ShadowColor shadowColor() { + return this.style().shadowColor(); + } + /** * Sets the color of this component. * @@ -2216,6 +2222,33 @@ default void detectCycle(final @NotNull Component that) { return this; } + /** + * Sets the shadow color of this component. + * + * @param color the color + * @return a component + * @since 4.18.0 + */ + @Contract(pure = true) + @Override + default @NotNull Component shadowColor(final @Nullable ShadowColor color) { + return this.style(this.style().shadowColor(color)); + } + + /** + * Sets the shadow color if there isn't one set already. + * + * @param color the color + * @return a component + * @since 4.18.0 + */ + @Contract(pure = true) + @Override + default @NotNull Component shadowColorIfAbsent(final @Nullable ShadowColor color) { + if (this.shadowColor() == null) return this.shadowColorIfAbsent(color); + return this; + } + /** * Tests if this component has a decoration. * diff --git a/api/src/main/java/net/kyori/adventure/text/ScopedComponent.java b/api/src/main/java/net/kyori/adventure/text/ScopedComponent.java index d9d123939..315ba57fe 100644 --- a/api/src/main/java/net/kyori/adventure/text/ScopedComponent.java +++ b/api/src/main/java/net/kyori/adventure/text/ScopedComponent.java @@ -28,6 +28,7 @@ import java.util.function.Consumer; import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.event.HoverEventSource; +import net.kyori.adventure.text.format.ShadowColor; import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.TextColor; import net.kyori.adventure.text.format.TextDecoration; @@ -107,6 +108,18 @@ public interface ScopedComponent extends Component { return (C) Component.super.colorIfAbsent(color); } + @Override + @SuppressWarnings("unchecked") + default @NotNull C shadowColor(final @Nullable ShadowColor color) { + return (C) Component.super.shadowColor(color); + } + + @Override + @SuppressWarnings("unchecked") + default @NotNull C shadowColorIfAbsent(final @Nullable ShadowColor color) { + return (C) Component.super.shadowColorIfAbsent(color); + } + @Override @SuppressWarnings("unchecked") default @NotNull C decorate(final @NotNull TextDecoration decoration) { diff --git a/api/src/main/java/net/kyori/adventure/text/format/ShadowColor.java b/api/src/main/java/net/kyori/adventure/text/format/ShadowColor.java new file mode 100644 index 000000000..08bcc33ce --- /dev/null +++ b/api/src/main/java/net/kyori/adventure/text/format/ShadowColor.java @@ -0,0 +1,41 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2023 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.format; + +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +public interface ShadowColor extends StyleBuilderApplicable { + @Contract(pure = true) + static ShadowColor shadowColor(final int value) { + return new ShadowColorImpl(value); + } + + int value(); + + @Override + default void styleApply(final Style.@NotNull Builder style) { + style.color(this); + } +} diff --git a/api/src/main/java/net/kyori/adventure/text/format/ShadowColorImpl.java b/api/src/main/java/net/kyori/adventure/text/format/ShadowColorImpl.java new file mode 100644 index 000000000..7e58b4e79 --- /dev/null +++ b/api/src/main/java/net/kyori/adventure/text/format/ShadowColorImpl.java @@ -0,0 +1,37 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2023 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.format; + +final class ShadowColorImpl implements ShadowColor { + private final int value; + + ShadowColorImpl(final int value) { + this.value = value; + } + + @Override + public int value() { + return this.value; + } +} diff --git a/api/src/main/java/net/kyori/adventure/text/format/StyleGetter.java b/api/src/main/java/net/kyori/adventure/text/format/StyleGetter.java index f05f0a0a7..41457e436 100644 --- a/api/src/main/java/net/kyori/adventure/text/format/StyleGetter.java +++ b/api/src/main/java/net/kyori/adventure/text/format/StyleGetter.java @@ -58,6 +58,14 @@ public interface StyleGetter { */ @Nullable TextColor color(); + /** + * Gets the shadow color. + * + * @return the shadow color + * @since 4.18.0 + */ + @Nullable ShadowColor shadowColor(); + /** * Tests if this stylable has a decoration. * diff --git a/api/src/main/java/net/kyori/adventure/text/format/StyleImpl.java b/api/src/main/java/net/kyori/adventure/text/format/StyleImpl.java index 6bc5efc08..6c529fc3f 100644 --- a/api/src/main/java/net/kyori/adventure/text/format/StyleImpl.java +++ b/api/src/main/java/net/kyori/adventure/text/format/StyleImpl.java @@ -40,10 +40,11 @@ import static java.util.Objects.requireNonNull; final class StyleImpl implements Style { - static final StyleImpl EMPTY = new StyleImpl(null, null, DecorationMap.EMPTY, null, null, null); + static final StyleImpl EMPTY = new StyleImpl(null, null, null, DecorationMap.EMPTY, null, null, null); // visible to avoid generating accessors when creating a builder final @Nullable Key font; final @Nullable TextColor color; + final @Nullable ShadowColor shadowColor; final @NotNull DecorationMap decorations; final @Nullable ClickEvent clickEvent; final @Nullable HoverEvent hoverEvent; @@ -52,6 +53,7 @@ final class StyleImpl implements Style { StyleImpl( final @Nullable Key font, final @Nullable TextColor color, + final @Nullable ShadowColor shadowColor, final @NotNull Map decorations, final @Nullable ClickEvent clickEvent, final @Nullable HoverEvent hoverEvent, @@ -59,6 +61,7 @@ final class StyleImpl implements Style { ) { this.font = font; this.color = color; + this.shadowColor = shadowColor; this.decorations = DecorationMap.fromMap(decorations); this.clickEvent = clickEvent; this.hoverEvent = hoverEvent; @@ -73,7 +76,7 @@ final class StyleImpl implements Style { @Override public @NotNull Style font(final @Nullable Key font) { if (Objects.equals(this.font, font)) return this; - return new StyleImpl(font, this.color, this.decorations, this.clickEvent, this.hoverEvent, this.insertion); + return new StyleImpl(font, this.color, this.shadowColor, this.decorations, this.clickEvent, this.hoverEvent, this.insertion); } @Override @@ -84,7 +87,7 @@ final class StyleImpl implements Style { @Override public @NotNull Style color(final @Nullable TextColor color) { if (Objects.equals(this.color, color)) return this; - return new StyleImpl(this.font, color, this.decorations, this.clickEvent, this.hoverEvent, this.insertion); + return new StyleImpl(this.font, color, this.shadowColor, this.decorations, this.clickEvent, this.hoverEvent, this.insertion); } @Override @@ -95,6 +98,25 @@ final class StyleImpl implements Style { return this; } + @Override + public @Nullable ShadowColor shadowColor() { + return this.shadowColor; + } + + @Override + public @NotNull Style shadowColor(final @Nullable ShadowColor color) { + if (Objects.equals(this.shadowColor, color)) return this; + return new StyleImpl(this.font, this.color, color, this.decorations, this.clickEvent, this.hoverEvent, this.insertion); + } + + @Override + public @NotNull Style shadowColorIfAbsent(final @Nullable ShadowColor color) { + if (this.shadowColor == null) { + return this.shadowColor(color); + } + return this; + } + @Override public TextDecoration.@NotNull State decoration(final @NotNull TextDecoration decoration) { // null -> null @@ -109,7 +131,7 @@ final class StyleImpl implements Style { public @NotNull Style decoration(final @NotNull TextDecoration decoration, final TextDecoration.@NotNull State state) { requireNonNull(state, "state"); if (this.decoration(decoration) == state) return this; - return new StyleImpl(this.font, this.color, this.decorations.with(decoration, state), this.clickEvent, this.hoverEvent, this.insertion); + return new StyleImpl(this.font, this.color, this.shadowColor, this.decorations.with(decoration, state), this.clickEvent, this.hoverEvent, this.insertion); } @Override @@ -117,7 +139,7 @@ final class StyleImpl implements Style { requireNonNull(state, "state"); final TextDecoration.@Nullable State oldState = this.decorations.get(decoration); if (oldState == TextDecoration.State.NOT_SET) { - return new StyleImpl(this.font, this.color, this.decorations.with(decoration, state), this.clickEvent, this.hoverEvent, this.insertion); + return new StyleImpl(this.font, this.color, this.shadowColor, this.decorations.with(decoration, state), this.clickEvent, this.hoverEvent, this.insertion); } if (oldState != null) { return this; @@ -132,7 +154,7 @@ final class StyleImpl implements Style { @Override public @NotNull Style decorations(final @NotNull Map decorations) { - return new StyleImpl(this.font, this.color, DecorationMap.merge(decorations, this.decorations), this.clickEvent, this.hoverEvent, this.insertion); + return new StyleImpl(this.font, this.color, this.shadowColor, DecorationMap.merge(decorations, this.decorations), this.clickEvent, this.hoverEvent, this.insertion); } @Override @@ -142,7 +164,7 @@ final class StyleImpl implements Style { @Override public @NotNull Style clickEvent(final @Nullable ClickEvent event) { - return new StyleImpl(this.font, this.color, this.decorations, event, this.hoverEvent, this.insertion); + return new StyleImpl(this.font, this.color, this.shadowColor, this.decorations, event, this.hoverEvent, this.insertion); } @Override @@ -152,7 +174,7 @@ final class StyleImpl implements Style { @Override public @NotNull Style hoverEvent(final @Nullable HoverEventSource source) { - return new StyleImpl(this.font, this.color, this.decorations, this.clickEvent, HoverEventSource.unbox(source), this.insertion); + return new StyleImpl(this.font, this.color, this.shadowColor, this.decorations, this.clickEvent, HoverEventSource.unbox(source), this.insertion); } @Override @@ -163,7 +185,7 @@ final class StyleImpl implements Style { @Override public @NotNull Style insertion(final @Nullable String insertion) { if (Objects.equals(this.insertion, insertion)) return this; - return new StyleImpl(this.font, this.color, this.decorations, this.clickEvent, this.hoverEvent, insertion); + return new StyleImpl(this.font, this.color, this.shadowColor, this.decorations, this.clickEvent, this.hoverEvent, insertion); } @Override @@ -286,6 +308,7 @@ public int hashCode() { static final class BuilderImpl implements Builder { @Nullable Key font; @Nullable TextColor color; + @Nullable ShadowColor shadowColor; final Map decorations; @Nullable ClickEvent clickEvent; @Nullable HoverEvent hoverEvent; @@ -324,6 +347,20 @@ static final class BuilderImpl implements Builder { return this; } + @Override + public @NotNull Builder shadowColor(final @Nullable ShadowColor color) { + this.shadowColor = color; + return this; + } + + @Override + public @NotNull Builder shadowColorIfAbsent(final @Nullable ShadowColor color) { + if (this.shadowColor == null) { + this.shadowColor = color; + } + return this; + } + @Override public @NotNull Builder decoration(final @NotNull TextDecoration decoration, final TextDecoration.@NotNull State state) { requireNonNull(state, "state"); @@ -438,7 +475,7 @@ static final class BuilderImpl implements Builder { if (this.isEmpty()) { return EMPTY; } - return new StyleImpl(this.font, this.color, this.decorations, this.clickEvent, this.hoverEvent, this.insertion); + return new StyleImpl(this.font, this.color, this.shadowColor, this.decorations, this.clickEvent, this.hoverEvent, this.insertion); } private boolean isEmpty() { diff --git a/api/src/main/java/net/kyori/adventure/text/format/StyleSetter.java b/api/src/main/java/net/kyori/adventure/text/format/StyleSetter.java index a9aa4f888..64c4c5bf9 100644 --- a/api/src/main/java/net/kyori/adventure/text/format/StyleSetter.java +++ b/api/src/main/java/net/kyori/adventure/text/format/StyleSetter.java @@ -73,6 +73,24 @@ public interface StyleSetter> { */ @NotNull T colorIfAbsent(final @Nullable TextColor color); + /** + * Sets the shadow color. + * + * @param color the color + * @return an object ({@code T}) + * @since 4.18.0 + */ + @NotNull T shadowColor(final @Nullable ShadowColor color); + + /** + * Sets the shadow color if there isn't one set already. + * + * @param color the color + * @return an object ({@code T}) + * @since 4.18.0 + */ + @NotNull T shadowColorIfAbsent(final @Nullable ShadowColor color); + /** * Sets the state of {@code decoration} to {@link TextDecoration.State#TRUE}. * 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 7f8e66c93..f4de4249e 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 @@ -34,6 +34,7 @@ import net.kyori.adventure.text.TranslationArgument; import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.format.ShadowColor; import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.TextColor; import net.kyori.adventure.text.format.TextDecoration; @@ -52,6 +53,7 @@ final class SerializerFactory implements TypeAdapterFactory { static final Class STRING_TYPE = String.class; static final Class COLOR_WRAPPER_TYPE = TextColorWrapper.class; static final Class COLOR_TYPE = TextColor.class; + static final Class SHADOW_COLOR_TYPE = ShadowColor.class; static final Class TEXT_DECORATION_TYPE = TextDecoration.class; static final Class BLOCK_NBT_POS_TYPE = BlockNBTComponent.Pos.class; static final Class UUID_TYPE = UUID.class; @@ -87,6 +89,8 @@ public TypeAdapter create(final Gson gson, final TypeToken type) { return (TypeAdapter) TextColorWrapper.Serializer.INSTANCE; } else if (COLOR_TYPE.isAssignableFrom(rawType)) { return (TypeAdapter) (this.features.value(JSONOptions.EMIT_RGB) ? TextColorSerializer.INSTANCE : TextColorSerializer.DOWNSAMPLE_COLOR); + } else if (SHADOW_COLOR_TYPE.isAssignableFrom(rawType)) { + return (TypeAdapter) ShadowColorSerializer.INSTANCE; } else if (TEXT_DECORATION_TYPE.isAssignableFrom(rawType)) { return (TypeAdapter) TextDecorationSerializer.INSTANCE; } else if (BLOCK_NBT_POS_TYPE.isAssignableFrom(rawType)) { diff --git a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/ShadowColorSerializer.java b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/ShadowColorSerializer.java new file mode 100644 index 000000000..a1d30de1e --- /dev/null +++ b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/ShadowColorSerializer.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.gson; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import net.kyori.adventure.text.format.ShadowColor; + +final class ShadowColorSerializer extends TypeAdapter { + static final TypeAdapter INSTANCE = new ShadowColorSerializer().nullSafe(); + + @Override + public void write(final JsonWriter out, final ShadowColor value) throws IOException { + out.value(value.value()); + } + + @Override + public ShadowColor read(final JsonReader in) throws IOException { + if (in.peek() == JsonToken.BEGIN_ARRAY) { + throw new UnsupportedOperationException(); // TODO + } + + return ShadowColor.shadowColor(in.nextInt()); + } +} 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 7c4fd2f9b..8cd6f945e 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 @@ -40,6 +40,7 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.format.ShadowColor; import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.TextColor; import net.kyori.adventure.text.format.TextDecoration; @@ -58,6 +59,7 @@ import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.HOVER_EVENT_CONTENTS; import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.HOVER_EVENT_VALUE; import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.INSERTION; +import static net.kyori.adventure.text.serializer.json.JSONComponentConstants.SHADOW_COLOR; final class StyleSerializer extends TypeAdapter