From de37bf6cb61f3725f56e014cdb9c1efda44751f2 Mon Sep 17 00:00:00 2001 From: zml Date: Sat, 7 Dec 2024 13:57:20 -0800 Subject: [PATCH] shadow color: support in json serializer, fill in some style gaps --- .../kyori/adventure/text/format/Style.java | 2 +- .../adventure/text/format/StyleImpl.java | 16 ++++++ .../serializer/gson/SerializerFactory.java | 2 +- .../gson/ShadowColorSerializer.java | 50 +++++++++++++++++-- .../text/serializer/gson/StyleSerializer.java | 8 ++- .../text/serializer/json/JSONOptions.java | 40 +++++++++++++++ 6 files changed, 112 insertions(+), 6 deletions(-) diff --git a/api/src/main/java/net/kyori/adventure/text/format/Style.java b/api/src/main/java/net/kyori/adventure/text/format/Style.java index 0c9882e86..efac65fda 100644 --- a/api/src/main/java/net/kyori/adventure/text/format/Style.java +++ b/api/src/main/java/net/kyori/adventure/text/format/Style.java @@ -562,7 +562,7 @@ default boolean hasDecoration(final @NotNull TextDecoration decoration) { */ enum Merge { /** - * Merges {@link Style#color()}. + * Merges {@link Style#color()} and {@link Style#shadowColor()}. * * @since 4.0.0 */ 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 dccf344ae..65d106565 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 @@ -223,6 +223,10 @@ final class StyleImpl implements Style { builder.color(null); } + if (Objects.equals(this.shadowColor(), that.shadowColor())) { + builder.shadowColor(null); + } + for (int i = 0, length = DecorationMap.DECORATIONS.length; i < length; i++) { final TextDecoration decoration = DecorationMap.DECORATIONS[i]; if (this.decoration(decoration) == that.decoration(decoration)) { @@ -269,6 +273,7 @@ public boolean isEmpty() { this.decorations.examinableProperties(), Stream.of( ExaminableProperty.of("color", this.color), + ExaminableProperty.of("shadowColor", this.shadowColor), ExaminableProperty.of("clickEvent", this.clickEvent), ExaminableProperty.of("hoverEvent", this.hoverEvent), ExaminableProperty.of("insertion", this.insertion), @@ -289,6 +294,7 @@ public boolean equals(final @Nullable Object other) { final StyleImpl that = (StyleImpl) other; return Objects.equals(this.color, that.color) && this.decorations.equals(that.decorations) + && Objects.equals(this.shadowColor, that.shadowColor) && Objects.equals(this.clickEvent, that.clickEvent) && Objects.equals(this.hoverEvent, that.hoverEvent) && Objects.equals(this.insertion, that.insertion) @@ -298,6 +304,7 @@ public boolean equals(final @Nullable Object other) { @Override public int hashCode() { int result = Objects.hashCode(this.color); + result = (31 * result) + Objects.hashCode(this.shadowColor); result = (31 * result) + this.decorations.hashCode(); result = (31 * result) + Objects.hashCode(this.clickEvent); result = (31 * result) + Objects.hashCode(this.hoverEvent); @@ -321,6 +328,7 @@ static final class BuilderImpl implements Builder { BuilderImpl(final @NotNull StyleImpl style) { this.color = style.color; + this.shadowColor = style.shadowColor; this.decorations = new EnumMap<>(style.decorations); this.clickEvent = style.clickEvent; this.hoverEvent = style.hoverEvent; @@ -418,6 +426,13 @@ static final class BuilderImpl implements Builder { this.color(color); } } + + final ShadowColor shadowColor = that.shadowColor(); + if (shadowColor != null) { + if (strategy == Merge.Strategy.ALWAYS || (strategy == Merge.Strategy.IF_ABSENT_ON_TARGET && this.shadowColor == null)) { + this.shadowColor(shadowColor); + } + } } if (merges.contains(Merge.DECORATIONS)) { @@ -481,6 +496,7 @@ static final class BuilderImpl implements Builder { private boolean isEmpty() { return this.color == null + && this.shadowColor == null && this.decorations.values().stream().allMatch(state -> state == TextDecoration.State.NOT_SET) && this.clickEvent == null && this.hoverEvent == null 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 f4de4249e..6d0fc3eff 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 @@ -90,7 +90,7 @@ public TypeAdapter create(final Gson gson, final TypeToken type) { } 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; + return (TypeAdapter) ShadowColorSerializer.create(this.features); } 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 index a1d30de1e..809772d2b 100644 --- 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 @@ -23,27 +23,71 @@ */ package net.kyori.adventure.text.serializer.gson; +import com.google.gson.JsonParseException; 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; +import net.kyori.adventure.text.serializer.json.JSONOptions; +import net.kyori.option.OptionState; final class ShadowColorSerializer extends TypeAdapter { - static final TypeAdapter INSTANCE = new ShadowColorSerializer().nullSafe(); + static TypeAdapter create(final OptionState options) { + return new ShadowColorSerializer(options.value(JSONOptions.SHADOW_COLOR_MODE) == JSONOptions.ShadowColorEmitMode.EMIT_ARRAY).nullSafe(); + } + + private final boolean emitArray; + + private ShadowColorSerializer(final boolean emitArray) { + this.emitArray = emitArray; + } @Override public void write(final JsonWriter out, final ShadowColor value) throws IOException { - out.value(value.value()); + if (this.emitArray) { + out.beginArray() + .value(componentAsFloat(value.red())) + .value(componentAsFloat(value.green())) + .value(componentAsFloat(value.blue())) + .value(componentAsFloat(value.alpha())) + .endArray(); + + } else { + out.value(value.value()); + } } @Override public ShadowColor read(final JsonReader in) throws IOException { if (in.peek() == JsonToken.BEGIN_ARRAY) { - throw new UnsupportedOperationException(); // TODO + in.beginArray(); + final double r = in.nextDouble(); + final double g = in.nextDouble(); + final double b = in.nextDouble(); + final double a = in.nextDouble(); + if (in.peek() != JsonToken.END_ARRAY) { + throw new JsonParseException("Failed to parse shadow colour at " + in.getPath() + ": expected end of 4-element array but got " + in.peek() + " instead."); + } + in.endArray(); + + return ShadowColor.shadowColor( + componentFromFloat(r), + componentFromFloat(g), + componentFromFloat(b), + componentFromFloat(a) + ); } return ShadowColor.shadowColor(in.nextInt()); } + + static float componentAsFloat(final int element) { + return (float) element / 0xff; + } + + static int componentFromFloat(final double element) { + return (int) ((float) element) * 0xff; + } } 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 8cd6f945e..a0331b3da 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 @@ -91,6 +91,7 @@ static TypeAdapter