From 6feacda2eedef5edfb20e280540d00933861886e Mon Sep 17 00:00:00 2001 From: zml Date: Wed, 11 Oct 2023 12:23:42 -0700 Subject: [PATCH 1/4] feat(text-serializer-gson): Support reading int array-format UUIDs --- .../serializer/gson/SerializerFactory.java | 4 + .../serializer/gson/ShowEntitySerializer.java | 2 +- .../text/serializer/gson/UUIDSerializer.java | 60 +++++++++++++++ .../json/ShowEntitySerializerTest.java | 73 +++++++++++++++++++ 4 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/UUIDSerializer.java create mode 100644 text-serializer-json/src/testFixtures/java/net/kyori/adventure/text/serializer/json/ShowEntitySerializerTest.java 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 3ffaed8bd..e32a08eea 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 @@ -27,6 +27,7 @@ import com.google.gson.TypeAdapter; import com.google.gson.TypeAdapterFactory; import com.google.gson.reflect.TypeToken; +import java.util.UUID; import net.kyori.adventure.key.Key; import net.kyori.adventure.text.BlockNBTComponent; import net.kyori.adventure.text.Component; @@ -50,6 +51,7 @@ final class SerializerFactory implements TypeAdapterFactory { static final Class COLOR_TYPE = TextColor.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; private final boolean downsampleColors; private final net.kyori.adventure.text.serializer.json.LegacyHoverEventSerializer legacyHoverSerializer; @@ -87,6 +89,8 @@ public TypeAdapter create(final Gson gson, final TypeToken type) { 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; } else { return null; } 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 bcd9b72c0..74500bd03 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 @@ -63,7 +63,7 @@ public HoverEvent.ShowEntity read(final JsonReader in) throws IOException { if (fieldName.equals(SHOW_ENTITY_TYPE)) { type = this.gson.fromJson(in, SerializerFactory.KEY_TYPE); } else if (fieldName.equals(SHOW_ENTITY_ID)) { - id = UUID.fromString(in.nextString()); + id = this.gson.fromJson(in, SerializerFactory.UUID_TYPE); } else if (fieldName.equals(SHOW_ENTITY_NAME)) { name = this.gson.fromJson(in, SerializerFactory.COMPONENT_TYPE); } else { diff --git a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/UUIDSerializer.java b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/UUIDSerializer.java new file mode 100644 index 000000000..123c529b1 --- /dev/null +++ b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/UUIDSerializer.java @@ -0,0 +1,60 @@ +/* + * 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.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 java.util.UUID; + +final class UUIDSerializer extends TypeAdapter { + static final TypeAdapter INSTANCE = new UUIDSerializer().nullSafe(); + + private UUIDSerializer() { + } + + @Override + public void write(final JsonWriter out, final UUID value) throws IOException { + // todo: feature flag to choose whether to emit as 4-int syntax + out.value(value.toString()); + } + + @Override + public UUID read(final JsonReader in) throws IOException { + // int-array format was added in 23w40a, a pre for 1.20.3 + if (in.peek() == JsonToken.BEGIN_ARRAY) { + in.beginArray(); + final int v0 = in.nextInt(); + final int v1 = in.nextInt(); + final int v2 = in.nextInt(); + final int v3 = in.nextInt(); + in.endArray(); + return new UUID((long) v0 << 32 | ((long) v1 & 0xffffffffl), (long) v2 << 32 | ((long) v3 & 0xffffffffl)); + } + + return UUID.fromString(in.nextString()); + } +} diff --git a/text-serializer-json/src/testFixtures/java/net/kyori/adventure/text/serializer/json/ShowEntitySerializerTest.java b/text-serializer-json/src/testFixtures/java/net/kyori/adventure/text/serializer/json/ShowEntitySerializerTest.java new file mode 100644 index 000000000..fbaa11d76 --- /dev/null +++ b/text-serializer-json/src/testFixtures/java/net/kyori/adventure/text/serializer/json/ShowEntitySerializerTest.java @@ -0,0 +1,73 @@ +/* + * 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.serializer.json; + +import java.util.UUID; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.format.Style; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +final class ShowEntitySerializerTest extends SerializerTest { + @Test + void testWithStringUuid() { + final UUID id = UUID.randomUUID(); + this.testStyle(Style.style().hoverEvent(HoverEvent.showEntity(Key.key("zombie"), id)).build(), json -> { + json.add(JSONComponentConstants.HOVER_EVENT, object(hover -> { + hover.addProperty(JSONComponentConstants.HOVER_EVENT_ACTION, "show_entity"); + hover.add(JSONComponentConstants.HOVER_EVENT_CONTENTS, object(contents -> { + contents.addProperty(JSONComponentConstants.SHOW_ENTITY_TYPE, "minecraft:zombie"); + contents.addProperty(JSONComponentConstants.SHOW_ENTITY_ID, id.toString()); + })); + })); + }); + } + + @Test + void testWithIntArrayUuid() { + final UUID id = UUID.randomUUID(); + assertEquals( + Component.text("", Style.style().hoverEvent(HoverEvent.showEntity(Key.key("zombie"), id)).build()), + this.deserialize(object(comp -> { + comp.addProperty(JSONComponentConstants.TEXT, ""); + comp.add(JSONComponentConstants.HOVER_EVENT, object(hover -> { + hover.addProperty(JSONComponentConstants.HOVER_EVENT_ACTION, "show_entity"); + hover.add(JSONComponentConstants.HOVER_EVENT_CONTENTS, object(contents -> { + contents.addProperty(JSONComponentConstants.SHOW_ENTITY_TYPE, "minecraft:zombie"); + contents.add(JSONComponentConstants.SHOW_ENTITY_ID, array(idArray -> { + idArray.add((int) (id.getMostSignificantBits() >> 32)); + idArray.add((int) (id.getMostSignificantBits() & 0xffffffffl)); + idArray.add((int) (id.getLeastSignificantBits() >> 32)); + idArray.add((int) (id.getLeastSignificantBits() & 0xffffffffl)); + })); + })); + })); + }) + ) + ); + } +} From f9a739cfe20faa9e461301b239ca3bf6ef955e5b Mon Sep 17 00:00:00 2001 From: zml Date: Thu, 16 Nov 2023 12:47:08 -0800 Subject: [PATCH 2/4] Improve var names in UUID serializer Co-authored-by: Riley Park --- .../adventure/text/serializer/gson/UUIDSerializer.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/UUIDSerializer.java b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/UUIDSerializer.java index 123c529b1..b4652e3f6 100644 --- a/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/UUIDSerializer.java +++ b/text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/UUIDSerializer.java @@ -47,12 +47,12 @@ public UUID read(final JsonReader in) throws IOException { // int-array format was added in 23w40a, a pre for 1.20.3 if (in.peek() == JsonToken.BEGIN_ARRAY) { in.beginArray(); - final int v0 = in.nextInt(); - final int v1 = in.nextInt(); - final int v2 = in.nextInt(); - final int v3 = in.nextInt(); + final int msb0 = in.nextInt(); + final int msb1 = in.nextInt(); + final int lsb0 = in.nextInt(); + final int lsb1 = in.nextInt(); in.endArray(); - return new UUID((long) v0 << 32 | ((long) v1 & 0xffffffffl), (long) v2 << 32 | ((long) v3 & 0xffffffffl)); + return new UUID((long) msb0 << 32 | ((long) msb1 & 0xffffffffl), (long) lsb0 << 32 | ((long) lsb1 & 0xffffffffl)); } return UUID.fromString(in.nextString()); From 2b1b4cb074dfafe5b811e20e0bba947f17360eee Mon Sep 17 00:00:00 2001 From: Riley Park Date: Mon, 20 Nov 2023 16:42:40 -0800 Subject: [PATCH 3/4] feat: ResourcePackRequest now has a UUID --- .../resource/ResourcePackRequest.java | 29 ++++++++++++++--- .../resource/ResourcePackRequestImpl.java | 32 +++++++++++++++---- 2 files changed, 50 insertions(+), 11 deletions(-) diff --git a/api/src/main/java/net/kyori/adventure/resource/ResourcePackRequest.java b/api/src/main/java/net/kyori/adventure/resource/ResourcePackRequest.java index a77f657f3..ab7bcc8d8 100644 --- a/api/src/main/java/net/kyori/adventure/resource/ResourcePackRequest.java +++ b/api/src/main/java/net/kyori/adventure/resource/ResourcePackRequest.java @@ -24,6 +24,7 @@ package net.kyori.adventure.resource; import java.net.URI; +import java.util.UUID; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.builder.AbstractBuilder; import net.kyori.adventure.text.Component; @@ -42,19 +43,21 @@ public interface ResourcePackRequest extends Examinable, ResourcePackRequestLike /** * Creates a resource pack request. * + * @param id the id * @param uri the uri * @param hash the sha-1 hash * @param required whether the resource pack is required or not * @return the resource pack request * @since 4.15.0 */ - static @NotNull ResourcePackRequest resourcePackRequest(final @NotNull URI uri, final @NotNull String hash, final boolean required) { - return resourcePackRequest(uri, hash, required, null); + static @NotNull ResourcePackRequest resourcePackRequest(final @NotNull UUID id, final @NotNull URI uri, final @NotNull String hash, final boolean required) { + return resourcePackRequest(id, uri, hash, required, null); } /** * Creates a resource pack request. * + * @param id the id * @param uri the uri * @param hash the sha-1 hash * @param required whether the resource pack is required or not @@ -62,8 +65,8 @@ public interface ResourcePackRequest extends Examinable, ResourcePackRequestLike * @return the resource pack request * @since 4.15.0 */ - static @NotNull ResourcePackRequest resourcePackRequest(final @NotNull URI uri, final @NotNull String hash, final boolean required, final @Nullable Component prompt) { - return new ResourcePackRequestImpl(uri, hash, required, prompt); + static @NotNull ResourcePackRequest resourcePackRequest(final @NotNull UUID id, final @NotNull URI uri, final @NotNull String hash, final boolean required, final @Nullable Component prompt) { + return new ResourcePackRequestImpl(id, uri, hash, required, prompt); } /** @@ -76,6 +79,14 @@ public interface ResourcePackRequest extends Examinable, ResourcePackRequestLike return new ResourcePackRequestImpl.BuilderImpl(); } + /** + * Gets the id. + * + * @return the id + * @since 4.15.0 + */ + @NotNull UUID id(); + /** * Gets the uri. * @@ -121,6 +132,16 @@ public interface ResourcePackRequest extends Examinable, ResourcePackRequestLike * @since 4.15.0 */ interface Builder extends AbstractBuilder, ResourcePackRequestLike { + /** + * Sets the id. + * + * @param uri the id + * @return this builder + * @since 4.15.0 + */ + @Contract("_ -> this") + @NotNull Builder id(final @NotNull UUID id); + /** * Sets the uri. * diff --git a/api/src/main/java/net/kyori/adventure/resource/ResourcePackRequestImpl.java b/api/src/main/java/net/kyori/adventure/resource/ResourcePackRequestImpl.java index c3b186f7f..a81524531 100644 --- a/api/src/main/java/net/kyori/adventure/resource/ResourcePackRequestImpl.java +++ b/api/src/main/java/net/kyori/adventure/resource/ResourcePackRequestImpl.java @@ -25,6 +25,7 @@ import java.net.URI; import java.util.Objects; +import java.util.UUID; import java.util.stream.Stream; import net.kyori.adventure.internal.Internals; import net.kyori.adventure.text.Component; @@ -35,18 +36,25 @@ import static java.util.Objects.requireNonNull; final class ResourcePackRequestImpl implements ResourcePackRequest { + private final UUID id; private final URI uri; private final String hash; private final boolean required; private final Component prompt; - ResourcePackRequestImpl(final @NotNull URI uri, final @NotNull String hash, final boolean required, final @Nullable Component prompt) { + ResourcePackRequestImpl(final @NotNull UUID id, final @NotNull URI uri, final @NotNull String hash, final boolean required, final @Nullable Component prompt) { + this.id = requireNonNull(id, "id"); this.uri = requireNonNull(uri, "uri"); this.hash = requireNonNull(hash, "hash"); this.required = required; this.prompt = prompt; } + @Override + public @NotNull UUID id() { + return this.id; + } + @Override public @NotNull URI uri() { return this.uri; @@ -70,6 +78,7 @@ public boolean required() { @Override public @NotNull Stream examinableProperties() { return Stream.of( + ExaminableProperty.of("id", this.id), ExaminableProperty.of("uri", this.uri), ExaminableProperty.of("hash", this.hash), ExaminableProperty.of("required", this.required), @@ -87,15 +96,17 @@ public boolean equals(final @Nullable Object other) { if (this == other) return true; if (!(other instanceof ResourcePackRequestImpl)) return false; final ResourcePackRequestImpl that = (ResourcePackRequestImpl) other; - return this.required == that.required - && this.uri.equals(that.uri) - && this.hash.equals(that.hash) - && Objects.equals(this.prompt, that.prompt); + return this.id.equals(that.id) && + this.uri.equals(that.uri) && + this.hash.equals(that.hash) && + this.required == that.required && + Objects.equals(this.prompt, that.prompt); } @Override public int hashCode() { - int result = this.uri.hashCode(); + int result = this.id.hashCode(); + result = 31 * result + this.uri.hashCode(); result = 31 * result + this.hash.hashCode(); result = 31 * result + (this.required ? 1 : 0); result = 31 * result + (this.prompt != null ? this.prompt.hashCode() : 0); @@ -103,6 +114,7 @@ public int hashCode() { } static final class BuilderImpl implements Builder { + private UUID id; private URI uri; private String hash; private boolean required; @@ -111,6 +123,12 @@ static final class BuilderImpl implements Builder { BuilderImpl() { } + @Override + public @NotNull Builder id(final @NotNull UUID id) { + this.id = requireNonNull(id, "id"); + return this; + } + @Override public @NotNull Builder uri(final @NotNull URI uri) { this.uri = requireNonNull(uri, "uri"); @@ -137,7 +155,7 @@ static final class BuilderImpl implements Builder { @Override public @NotNull ResourcePackRequest build() { - return new ResourcePackRequestImpl(this.uri, this.hash, this.required, this.prompt); + return new ResourcePackRequestImpl(this.id, this.uri, this.hash, this.required, this.prompt); } } } From 35a4051fcf352290962c941a0b59a63dfa1df075 Mon Sep 17 00:00:00 2001 From: zml Date: Wed, 6 Dec 2023 19:26:51 -0800 Subject: [PATCH 4/4] chore: fix checkstyle --- .../java/net/kyori/adventure/resource/ResourcePackRequest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/net/kyori/adventure/resource/ResourcePackRequest.java b/api/src/main/java/net/kyori/adventure/resource/ResourcePackRequest.java index ab7bcc8d8..7484ad208 100644 --- a/api/src/main/java/net/kyori/adventure/resource/ResourcePackRequest.java +++ b/api/src/main/java/net/kyori/adventure/resource/ResourcePackRequest.java @@ -135,7 +135,7 @@ interface Builder extends AbstractBuilder, ResourcePackRequ /** * Sets the id. * - * @param uri the id + * @param id the id * @return this builder * @since 4.15.0 */