diff --git a/.idea/copyright/viaversion_gpl.xml b/.idea/copyright/viaversion_gpl.xml index 6fe78116d..b5c493ae8 100644 --- a/.idea/copyright/viaversion_gpl.xml +++ b/.idea/copyright/viaversion_gpl.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/.idea/copyright/viaversion_mit.xml b/.idea/copyright/viaversion_mit.xml index f373dd6ea..533a6e30a 100644 --- a/.idea/copyright/viaversion_mit.xml +++ b/.idea/copyright/viaversion_mit.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/adventure/build.gradle.kts b/adventure/build.gradle.kts deleted file mode 100644 index c2847bb39..000000000 --- a/adventure/build.gradle.kts +++ /dev/null @@ -1,25 +0,0 @@ -plugins { - id("com.github.johnrengelman.shadow") -} - -// Shade and relocate adventure in an extra module, so that common/the rest can directly depend on a -// relocated adventure without breaking native platform's adventure usage with project wide relocation -tasks { - shadowJar { - relocate("net.kyori", "com.viaversion.viaversion.libs.kyori") - } - build { - dependsOn(shadowJar) - } -} - -dependencies { - api(libs.bundles.adventure) { - exclude("org.checkerframework") - exclude("net.kyori", "adventure-api") - exclude("net.kyori", "adventure-bom") - exclude("com.google.code.gson", "gson") - } -} - -publishShadowJar() diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 44254f00c..e686e3ee7 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -15,14 +15,14 @@ sourceSets { } dependencies { - api(projects.adventure) { - targetConfiguration = "shadow" - } api(libs.fastutil) api(libs.flare) api(libs.flareFastutil) api(libs.vianbt) api(libs.gson) + implementation(rootProject.libs.text) { + exclude("com.google.code.gson", "gson") + } compileOnlyApi(libs.snakeYaml) compileOnlyApi(libs.netty) diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/signature/model/chain/v1_19_1/MessageBody.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/signature/model/chain/v1_19_1/MessageBody.java index 1a28ff4fe..bfc665375 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/signature/model/chain/v1_19_1/MessageBody.java +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/signature/model/chain/v1_19_1/MessageBody.java @@ -25,7 +25,7 @@ package com.viaversion.viaversion.api.minecraft.signature.model.chain.v1_19_1; import com.viaversion.viaversion.api.minecraft.PlayerMessageSignature; import com.viaversion.viaversion.api.minecraft.signature.model.DecoratableMessage; import com.viaversion.viaversion.api.minecraft.signature.util.DataConsumer; -import com.viaversion.viaversion.util.GsonUtil; +import net.lenni0451.mcstructs.text.utils.JsonUtils; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; @@ -62,7 +62,7 @@ public class MessageBody { dataOutputStream.write(this.content.plain().getBytes(StandardCharsets.UTF_8)); dataOutputStream.write(HASH_SEPARATOR_BYTE); if (this.content.isDecorated()) { - dataOutputStream.write(GsonUtil.toSortedString(this.content.decorated(), null).getBytes(StandardCharsets.UTF_8)); + dataOutputStream.write(JsonUtils.toSortedString(this.content.decorated(), null).getBytes(StandardCharsets.UTF_8)); } for (PlayerMessageSignature lastSeenMessage : this.lastSeenMessages) { diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/signature/storage/ChatSession1_19_0.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/signature/storage/ChatSession1_19_0.java index ad04f4872..43f6d412f 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/signature/storage/ChatSession1_19_0.java +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/signature/storage/ChatSession1_19_0.java @@ -25,7 +25,7 @@ package com.viaversion.viaversion.api.minecraft.signature.storage; import com.viaversion.viaversion.api.minecraft.ProfileKey; import com.viaversion.viaversion.api.minecraft.signature.model.DecoratableMessage; import com.viaversion.viaversion.api.minecraft.signature.model.MessageMetadata; -import com.viaversion.viaversion.util.GsonUtil; +import net.lenni0451.mcstructs.text.utils.JsonUtils; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -48,7 +48,7 @@ public class ChatSession1_19_0 extends ChatSession { buffer.putLong(metadata.sender().getMostSignificantBits()).putLong(metadata.sender().getLeastSignificantBits()); buffer.putLong(metadata.timestamp().getEpochSecond()); signer.accept(data); - signer.accept(GsonUtil.toSortedString(content.decorated(), null).getBytes(StandardCharsets.UTF_8)); + signer.accept(JsonUtils.toSortedString(content.decorated(), null).getBytes(StandardCharsets.UTF_8)); }); } diff --git a/api/src/main/java/com/viaversion/viaversion/api/type/types/chunk/ChunkSectionType1_8.java b/api/src/main/java/com/viaversion/viaversion/api/type/types/chunk/ChunkSectionType1_8.java index 73eef9dfd..8d9a8bb48 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/type/types/chunk/ChunkSectionType1_8.java +++ b/api/src/main/java/com/viaversion/viaversion/api/type/types/chunk/ChunkSectionType1_8.java @@ -46,7 +46,7 @@ public class ChunkSectionType1_8 extends Type { ByteBuf littleEndianView = buffer.order(ByteOrder.LITTLE_ENDIAN); for (int idx = 0; idx < ChunkSection.SIZE; idx++) { - blocks.setIdAt(idx, littleEndianView.readShort()); + blocks.setIdAt(idx, littleEndianView.readUnsignedShort()); } return chunkSection; diff --git a/api/src/main/java/com/viaversion/viaversion/util/GsonUtil.java b/api/src/main/java/com/viaversion/viaversion/util/GsonUtil.java index 79012f69e..0a20d98f3 100644 --- a/api/src/main/java/com/viaversion/viaversion/util/GsonUtil.java +++ b/api/src/main/java/com/viaversion/viaversion/util/GsonUtil.java @@ -22,12 +22,8 @@ */ package com.viaversion.viaversion.util; -import com.google.gson.*; -import org.checkerframework.checker.nullness.qual.Nullable; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; public final class GsonUtil { private static final Gson GSON = new GsonBuilder().create(); @@ -41,52 +37,4 @@ public final class GsonUtil { return GSON; } - /** - * Convert a json element to a sorted string.
- * If the {@code comparator} is null, {@link Comparator#naturalOrder()} will be used. - * - * @param element The element to convert - * @param comparator The comparator to use - * @return The sorted string - */ - public static String toSortedString(@Nullable final JsonElement element, @Nullable final Comparator comparator) { - if (element == null) { - return null; - } else if (comparator != null) { - return sort(element, comparator).toString(); - } else { - return sort(element, Comparator.naturalOrder()).toString(); - } - } - - /** - * Sort a json element. - * - * @param element The element to sort - * @param comparator The comparator to use - * @return The sorted element - */ - public static JsonElement sort(@Nullable final JsonElement element, final Comparator comparator) { - if (element == null) { - return null; - } else if (element.isJsonArray()) { - final JsonArray array = element.getAsJsonArray(); - for (int i = 0; i < array.size(); i++) { - array.set(i, sort(array.get(i), comparator)); - } - return array; - } else if (element.isJsonObject()) { - final JsonObject object = element.getAsJsonObject(); - final JsonObject sorted = new JsonObject(); - final List keys = new ArrayList<>(object.keySet()); - keys.sort(comparator); - for (String key : keys) { - sorted.add(key, sort(object.get(key), comparator)); - } - return sorted; - } else { - return element; - } - } - } diff --git a/build-logic/src/main/kotlin/via.shadow-conventions.gradle.kts b/build-logic/src/main/kotlin/via.shadow-conventions.gradle.kts index 68a001e4e..a820b6d0e 100644 --- a/build-logic/src/main/kotlin/via.shadow-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/via.shadow-conventions.gradle.kts @@ -26,6 +26,7 @@ fun ShadowJar.configureRelocations() { relocate("com.github.steveice10.opennbt", "com.viaversion.viaversion.libs.opennbt") relocate("it.unimi.dsi.fastutil", "com.viaversion.viaversion.libs.fastutil") relocate("space.vectrix.flare", "com.viaversion.viaversion.libs.flare") + relocate("net.lenni0451.mcstructs", "com.viaversion.viaversion.libs.mcstructs") } fun ShadowJar.configureExcludes() { diff --git a/build.gradle.kts b/build.gradle.kts index 1d82fd121..5151f9692 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -20,14 +20,12 @@ val main = setOf( projects.viaversionVelocity ).map { it.dependencyProject } -val special = setOf( - projects.adventure -).map { it.dependencyProject } +// val special = setOf().map { it.dependencyProject } subprojects { when (this) { in main -> plugins.apply("via.shadow-conventions") - in special -> plugins.apply("via.base-conventions") + // in special -> plugins.apply("via.base-conventions") else -> plugins.apply("via.standard-conventions") } } diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 42620c811..06cf4f2e1 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -1,6 +1,9 @@ dependencies { api(projects.viaversionApi) api(projects.viaversionApiLegacy) + api(rootProject.libs.text) { + exclude("com.google.code.gson", "gson") + } implementation(projects.compat.snakeyaml2Compat) implementation(projects.compat.snakeyaml1Compat) diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/ChatRewriter.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/ChatRewriter.java deleted file mode 100644 index cb72abbfc..000000000 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/ChatRewriter.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion - * Copyright (C) 2016-2023 ViaVersion and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.viaversion.viaversion.protocols.protocol1_13to1_12_2; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.viaversion.viaversion.api.Via; -import com.viaversion.viaversion.libs.kyori.adventure.text.Component; -import com.viaversion.viaversion.libs.kyori.adventure.text.format.TextDecoration; -import com.viaversion.viaversion.libs.kyori.adventure.text.serializer.gson.GsonComponentSerializer; -import com.viaversion.viaversion.libs.kyori.adventure.text.serializer.gson.legacyimpl.NBTLegacyHoverEventSerializer; -import com.viaversion.viaversion.libs.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; -import java.util.logging.Level; - -public final class ChatRewriter { - public static final GsonComponentSerializer HOVER_GSON_SERIALIZER = GsonComponentSerializer.builder().emitLegacyHoverEvent().legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get()).build(); - - public static JsonObject emptyComponent() { - final JsonObject object = new JsonObject(); - object.addProperty("text", ""); - return object; - } - - public static String emptyComponentString() { - return "{\"text\":\"\"}"; - } - - public static String legacyTextToJsonString(String message, boolean itemData) { - // Not used for chat messages, so no need for url extraction - Component component = LegacyComponentSerializer.legacySection().deserialize(message); - if (itemData) { - component = Component.text().decoration(TextDecoration.ITALIC, false).append(component).build(); - } - return GsonComponentSerializer.gson().serialize(component); - } - - public static String legacyTextToJsonString(String legacyText) { - return legacyTextToJsonString(legacyText, false); - } - - public static JsonElement legacyTextToJson(String legacyText) { - return JsonParser.parseString(legacyTextToJsonString(legacyText, false)); - } - - public static String jsonToLegacyText(String value) { - try { - Component component = HOVER_GSON_SERIALIZER.deserialize(value); - return LegacyComponentSerializer.legacySection().serialize(component); - } catch (Exception e) { - Via.getPlatform().getLogger().log(Level.WARNING, "Error converting json text to legacy: " + value, e); - return ""; - } - } - - @Deprecated/*(forRemoval = true)*/ - public static void processTranslate(JsonElement value) { - Via.getManager().getProtocolManager().getProtocol(Protocol1_13To1_12_2.class).getComponentRewriter().processText(value); - } -} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/Protocol1_13To1_12_2.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/Protocol1_13To1_12_2.java index bd996da0a..b00819e99 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/Protocol1_13To1_12_2.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/Protocol1_13To1_12_2.java @@ -62,6 +62,7 @@ import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.storage.BlockSto import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.storage.TabCompleteTracker; import com.viaversion.viaversion.rewriter.SoundRewriter; import com.viaversion.viaversion.util.ChatColorUtil; +import com.viaversion.viaversion.util.ComponentUtil; import com.viaversion.viaversion.util.GsonUtil; import java.util.ArrayList; import java.util.HashMap; @@ -435,7 +436,7 @@ public class Protocol1_13To1_12_2 extends AbstractProtocol { @@ -51,7 +51,7 @@ public class MetadataRewriter1_13To1_12_2 extends EntityRewriter Chat DisplayName if (metadata.id() == 2) { if (metadata.getValue() != null && !((String) metadata.getValue()).isEmpty()) { - metadata.setTypeAndValue(Types1_13.META_TYPES.optionalComponentType, ChatRewriter.legacyTextToJson((String) metadata.getValue())); + metadata.setTypeAndValue(Types1_13.META_TYPES.optionalComponentType, ComponentUtil.legacyToJson((String) metadata.getValue())); } else { metadata.setTypeAndValue(Types1_13.META_TYPES.optionalComponentType, null); } diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/packets/InventoryPackets.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/packets/InventoryPackets.java index 956111ea5..7c5353eed 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/packets/InventoryPackets.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/packets/InventoryPackets.java @@ -31,7 +31,6 @@ import com.viaversion.viaversion.api.minecraft.item.Item; import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.protocols.protocol1_12_1to1_12.ClientboundPackets1_12_1; -import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ChatRewriter; import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ClientboundPackets1_13; import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2; import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ServerboundPackets1_13; @@ -40,6 +39,7 @@ import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.data.MappingData import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.data.SoundSource; import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.data.SpawnEggRewriter; import com.viaversion.viaversion.rewriter.ItemRewriter; +import com.viaversion.viaversion.util.ComponentUtil; import com.viaversion.viaversion.util.Key; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -315,7 +315,7 @@ public class InventoryPackets extends ItemRewriter { @@ -326,7 +330,13 @@ public final class Protocol1_19_1To1_19 extends AbstractProtocolget(key).asByte() == 1); + for (final Map.Entry entry : TextFormatting.FORMATTINGS.entrySet()) { + final Tag formattingTag = styleTag.get(entry.getKey()); + if (!(formattingTag instanceof ByteTag)) { + continue; + } + + final boolean value = ((NumberTag) formattingTag).asBoolean(); + final TextFormatting formatting = entry.getValue(); + if (formatting == TextFormatting.OBFUSCATED) { + style.setObfuscated(value); + } else if (formatting == TextFormatting.BOLD) { + style.setBold(value); + } else if (formatting == TextFormatting.STRIKETHROUGH) { + style.setStrikethrough(value); + } else if (formatting == TextFormatting.UNDERLINE) { + style.setUnderlined(value); + } else if (formatting == TextFormatting.ITALIC) { + style.setItalic(value); } } - componentBuilder.style(styleBuilder.build()); } // Add the replacements - final ListTag parameters = decoaration.get("parameters"); + final ListTag parameters = tag.get("parameters"); + final List arguments = new ArrayList<>(); if (parameters != null) { - final List arguments = new ArrayList<>(); for (final Tag element : parameters) { JsonElement argument = null; switch ((String) element.getValue()) { @@ -386,18 +418,19 @@ public final class Protocol1_19_1To1_19 extends AbstractProtocol { @@ -68,7 +68,7 @@ public final class Protocol1_19To1_18_2 extends AbstractProtocol { @@ -103,9 +103,9 @@ public final class EntityPacketRewriter1_20_3 extends EntityRewriter { final MetaType type = meta.metaType(); if (type == Types1_20_2.META_TYPES.componentType) { - meta.setTypeAndValue(Types1_20_3.META_TYPES.componentType, ComponentConverter.jsonComponentToTag(meta.value())); + meta.setTypeAndValue(Types1_20_3.META_TYPES.componentType, ComponentUtil.jsonToTag(meta.value())); } else if (type == Types1_20_2.META_TYPES.optionalComponentType) { - meta.setTypeAndValue(Types1_20_3.META_TYPES.optionalComponentType, ComponentConverter.jsonComponentToTag(meta.value())); + meta.setTypeAndValue(Types1_20_3.META_TYPES.optionalComponentType, ComponentUtil.jsonToTag(meta.value())); } else if (type == Types1_20_2.META_TYPES.particleType) { final Particle particle = (Particle) meta.getValue(); final ParticleMappings particleMappings = protocol.getMappingData().getParticleMappings(); diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_3to1_20_2/util/ComponentConverter.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_3to1_20_2/util/ComponentConverter.java deleted file mode 100644 index 5e8a2e1ea..000000000 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_3to1_20_2/util/ComponentConverter.java +++ /dev/null @@ -1,313 +0,0 @@ -/* - * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion - * Copyright (C) 2023 ViaVersion and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.util; - -import com.github.steveice10.opennbt.tag.builtin.ByteArrayTag; -import com.github.steveice10.opennbt.tag.builtin.ByteTag; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.DoubleTag; -import com.github.steveice10.opennbt.tag.builtin.FloatTag; -import com.github.steveice10.opennbt.tag.builtin.IntArrayTag; -import com.github.steveice10.opennbt.tag.builtin.IntTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.LongArrayTag; -import com.github.steveice10.opennbt.tag.builtin.LongTag; -import com.github.steveice10.opennbt.tag.builtin.NumberTag; -import com.github.steveice10.opennbt.tag.builtin.ShortTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; -import com.google.gson.internal.LazilyParsedNumber; -import com.viaversion.viaversion.api.Via; -import com.viaversion.viaversion.util.Pair; -import com.viaversion.viaversion.util.UUIDUtil; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.logging.Level; -import org.checkerframework.checker.nullness.qual.Nullable; - -public final class ComponentConverter { - - private static final boolean DEBUG = Boolean.getBoolean("viaversion.debug.components"); - private static final Set BOOLEAN_TYPES = new HashSet<>(Arrays.asList( - "interpret", - "bold", - "italic", - "underlined", - "strikethrough", - "obfuscated" - )); - // Order is important - private static final List> COMPONENT_TYPES = Arrays.asList( - new Pair<>("text", "text"), - new Pair<>("translatable", "translate"), - new Pair<>("score", "score"), - new Pair<>("selector", "selector"), - new Pair<>("keybind", "keybind"), - new Pair<>("nbt", "nbt") - ); - - public static @Nullable JsonElement tagComponentToJson(@Nullable final Tag tag) { - if (DEBUG) { - Via.getPlatform().getLogger().info("Converting tag to json: " + tag); - } - - try { - return convertToJson(null, tag); - } catch (final Exception e) { - Via.getPlatform().getLogger().log(Level.SEVERE, "Error converting component: " + tag, e); - return new JsonPrimitive(""); - } - } - - public static @Nullable Tag jsonComponentToTag(@Nullable final JsonElement component) { - if (DEBUG) { - Via.getPlatform().getLogger().info("Converting json to tag: " + component); - } - - try { - return convertToTag(component); - } catch (final Exception e) { - Via.getPlatform().getLogger().log(Level.SEVERE, "Error converting component: " + component, e); - return new StringTag(""); - } - } - - private static @Nullable Tag convertToTag(final @Nullable JsonElement element) { - if (element == null || element.isJsonNull()) { - return null; - } else if (element.isJsonObject()) { - final CompoundTag tag = new CompoundTag(); - final JsonObject jsonObject = element.getAsJsonObject(); - for (final Map.Entry entry : jsonObject.entrySet()) { - convertObjectEntry(entry.getKey(), entry.getValue(), tag); - } - - addComponentType(jsonObject, tag); - return tag; - } else if (element.isJsonArray()) { - return convertJsonArray(element.getAsJsonArray()); - } else if (element.isJsonPrimitive()) { - final JsonPrimitive primitive = element.getAsJsonPrimitive(); - if (primitive.isString()) { - return new StringTag(primitive.getAsString()); - } else if (primitive.isBoolean()) { - return new ByteTag((byte) (primitive.getAsBoolean() ? 1 : 0)); - } - - final Number number = primitive.getAsNumber(); - if (number instanceof Integer) { - return new IntTag(number.intValue()); - } else if (number instanceof Byte) { - return new ByteTag(number.byteValue()); - } else if (number instanceof Short) { - return new ShortTag(number.shortValue()); - } else if (number instanceof Long) { - return new LongTag(number.longValue()); - } else if (number instanceof Double) { - return new DoubleTag(number.doubleValue()); - } else if (number instanceof Float) { - return new FloatTag(number.floatValue()); - } else if (number instanceof LazilyParsedNumber) { - // TODO: This might need better handling - return new IntTag(number.intValue()); - } - return new IntTag(number.intValue()); // ??? - } - throw new IllegalArgumentException("Unhandled json type " + element.getClass().getSimpleName() + " with value " + element.getAsString()); - } - - private static ListTag convertJsonArray(final JsonArray array) { - // TODO Number arrays? - final ListTag listTag = new ListTag(); - boolean singleType = true; - for (final JsonElement entry : array) { - final Tag convertedEntryTag = convertToTag(entry); - if (listTag.getElementType() != null && listTag.getElementType() != convertedEntryTag.getClass()) { - singleType = false; - break; - } - - listTag.add(convertedEntryTag); - } - - if (singleType) { - return listTag; - } - - // Generally, modern vanilla-esque serializers should not produce this format, so it should be rare - // Lists are only used for lists of components ("extra" and "with") - final ListTag processedListTag = new ListTag(); - for (final JsonElement entry : array) { - final Tag convertedTag = convertToTag(entry); - if (convertedTag instanceof CompoundTag) { - processedListTag.add(convertedTag); - continue; - } - - // Wrap all entries in compound tags, as lists can only consist of one type of tag - final CompoundTag compoundTag = new CompoundTag(); - compoundTag.put("type", new StringTag("text")); - if (convertedTag instanceof ListTag) { - compoundTag.put("text", new StringTag()); - compoundTag.put("extra", convertedTag); - } else { - compoundTag.put("text", new StringTag(convertedTag.asRawString())); - } - processedListTag.add(compoundTag); - } - return processedListTag; - } - - /** - * Converts a json object entry to a tag entry. - * - * @param key key of the entry - * @param value value of the entry - * @param tag the resulting compound tag - */ - private static void convertObjectEntry(final String key, final JsonElement value, final CompoundTag tag) { - if ((key.equals("contents")) && value.isJsonObject()) { - // Store show_entity id as int array instead of uuid string - // Not really required, but we might as well make it more compact - final JsonObject hoverEvent = value.getAsJsonObject(); - final JsonElement id = hoverEvent.get("id"); - final UUID uuid; - if (id != null && id.isJsonPrimitive() && (uuid = UUIDUtil.parseUUID(id.getAsString())) != null) { - hoverEvent.remove("id"); - - final CompoundTag convertedTag = (CompoundTag) convertToTag(value); - convertedTag.put("id", new IntArrayTag(UUIDUtil.toIntArray(uuid))); - tag.put(key, convertedTag); - return; - } - } - - tag.put(key, convertToTag(value)); - } - - private static void addComponentType(final JsonObject object, final CompoundTag tag) { - if (object.has("type")) { - return; - } - - // Add the type to speed up deserialization and make DFU errors slightly more useful - for (final Pair pair : COMPONENT_TYPES) { - if (object.has(pair.value())) { - tag.put("type", new StringTag(pair.key())); - return; - } - } - } - - private static @Nullable JsonElement convertToJson(final @Nullable String key, final @Nullable Tag tag) { - if (tag == null) { - return null; - } else if (tag instanceof CompoundTag) { - final JsonObject object = new JsonObject(); - if (!"value".equals(key)) { - removeComponentType(object); - } - - for (final Map.Entry entry : ((CompoundTag) tag).entrySet()) { - convertCompoundTagEntry(entry.getKey(), entry.getValue(), object); - } - return object; - } else if (tag instanceof ListTag) { - final ListTag list = (ListTag) tag; - final JsonArray array = new JsonArray(); - for (final Tag listEntry : list) { - array.add(convertToJson(null, listEntry)); - } - return array; - } else if (tag instanceof NumberTag) { - final NumberTag numberTag = (NumberTag) tag; - if (key != null && BOOLEAN_TYPES.contains(key)) { - // Booleans don't have a direct representation in nbt - return new JsonPrimitive(numberTag.asBoolean()); - } - return new JsonPrimitive(numberTag.getValue()); - } else if (tag instanceof StringTag) { - return new JsonPrimitive(((StringTag) tag).getValue()); - } else if (tag instanceof ByteArrayTag) { - final ByteArrayTag arrayTag = (ByteArrayTag) tag; - final JsonArray array = new JsonArray(); - for (final byte num : arrayTag.getValue()) { - array.add(num); - } - return array; - } else if (tag instanceof IntArrayTag) { - final IntArrayTag arrayTag = (IntArrayTag) tag; - final JsonArray array = new JsonArray(); - for (final int num : arrayTag.getValue()) { - array.add(num); - } - return array; - } else if (tag instanceof LongArrayTag) { - final LongArrayTag arrayTag = (LongArrayTag) tag; - final JsonArray array = new JsonArray(); - for (final long num : arrayTag.getValue()) { - array.add(num); - } - return array; - } - throw new IllegalArgumentException("Unhandled tag type " + tag.getClass().getSimpleName()); - } - - private static void convertCompoundTagEntry(final String key, final Tag tag, final JsonObject object) { - if ((key.equals("contents")) && tag instanceof CompoundTag) { - // Back to a UUID string - final CompoundTag showEntity = (CompoundTag) tag; - final Tag idTag = showEntity.get("id"); - if (idTag instanceof IntArrayTag) { - showEntity.remove("id"); - - final JsonObject convertedElement = (JsonObject) convertToJson(key, tag); - final UUID uuid = UUIDUtil.fromIntArray(((IntArrayTag) idTag).getValue()); - convertedElement.addProperty("id", uuid.toString()); - object.add(key, convertedElement); - return; - } - } - - // "":1 is a valid tag, but not a valid json component - object.add(key.isEmpty() ? "text" : key, convertToJson(key, tag)); - } - - private static void removeComponentType(final JsonObject object) { - final JsonElement type = object.remove("type"); - if (type == null || !type.isJsonPrimitive()) { - return; - } - - // Remove the other fields - final String typeString = type.getAsString(); - for (final Pair pair : COMPONENT_TYPES) { - if (!pair.key().equals(typeString)) { - object.remove(pair.value()); - } - } - } -} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20to1_19_4/packets/InventoryPackets.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20to1_19_4/packets/InventoryPackets.java index 275f91ee4..79190311b 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20to1_19_4/packets/InventoryPackets.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20to1_19_4/packets/InventoryPackets.java @@ -25,7 +25,6 @@ import com.viaversion.viaversion.api.minecraft.BlockChangeRecord; import com.viaversion.viaversion.api.minecraft.blockentity.BlockEntity; import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; import com.viaversion.viaversion.api.type.Type; -import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ChatRewriter; import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_18; import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ClientboundPackets1_19_4; import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ServerboundPackets1_19_4; @@ -34,6 +33,7 @@ import com.viaversion.viaversion.protocols.protocol1_20to1_19_4.Protocol1_20To1_ import com.viaversion.viaversion.rewriter.BlockRewriter; import com.viaversion.viaversion.rewriter.ItemRewriter; import com.viaversion.viaversion.rewriter.RecipeRewriter; +import com.viaversion.viaversion.util.ComponentUtil; import com.viaversion.viaversion.util.Key; public final class InventoryPackets extends ItemRewriter { @@ -173,7 +173,7 @@ public final class InventoryPackets extends ItemRewriter. + */ +package com.viaversion.viaversion.util; + +import com.github.steveice10.opennbt.tag.builtin.StringTag; +import com.github.steveice10.opennbt.tag.builtin.Tag; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.viaversion.viaversion.api.Via; +import net.lenni0451.mcstructs.snbt.SNbtSerializer; +import net.lenni0451.mcstructs.text.ATextComponent; +import net.lenni0451.mcstructs.text.Style; +import net.lenni0451.mcstructs.text.events.hover.AHoverEvent; +import net.lenni0451.mcstructs.text.events.hover.impl.TextHoverEvent; +import net.lenni0451.mcstructs.text.serializer.LegacyStringDeserializer; +import net.lenni0451.mcstructs.text.serializer.TextComponentCodec; +import net.lenni0451.mcstructs.text.serializer.TextComponentSerializer; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.logging.Level; + +/** + * Component conversion utility, trying to divert most calls to the component library to this class instead for easy replacement. + */ +public final class ComponentUtil { + + public static JsonObject emptyJsonComponent() { + return plainToJson(""); + } + + public static String emptyJsonComponentString() { + return "{\"text\":\"\"}"; + } + + public static JsonObject plainToJson(final String message) { + final JsonObject object = new JsonObject(); + object.addProperty("text", message); + return object; + } + + public static @Nullable JsonElement tagToJson(@Nullable final Tag tag) { + final ATextComponent component = TextComponentCodec.V1_20_3.deserializeNbtTree(NBTConverter.viaToMcStructs(tag)); + return component != null ? SerializerVersion.V1_19_4.toJson(component) : null; + } + + public static @Nullable Tag jsonToTag(@Nullable final JsonElement element) { + if (element == null) { + return null; + } + + try { + final ATextComponent component = TextComponentSerializer.V1_19_4.deserialize(element); + return NBTConverter.mcStructsToVia(TextComponentCodec.V1_20_3.serializeNbt(component)); + } catch (final Exception e) { + Via.getPlatform().getLogger().log(Level.SEVERE, "Error converting component: " + element, e); + return new StringTag(""); + } + } + + public static @Nullable JsonElement convertJson(@Nullable final JsonElement element, final SerializerVersion from, final SerializerVersion to) { + final ATextComponent component = from.jsonSerializer.deserialize(element); + if (element == null) { + return null; + } + + if (from.ordinal() >= SerializerVersion.V1_16.ordinal() && to.ordinal() < SerializerVersion.V1_16.ordinal()) { + // Convert hover event to legacy format + final Style style = component.getStyle(); + final AHoverEvent hoverEvent = style.getHoverEvent(); + if (hoverEvent != null && !(hoverEvent instanceof TextHoverEvent)) { + style.setHoverEvent(hoverEvent.toLegacy(to.jsonSerializer, to.snbtSerializer)); + } + } + return to.toJson(component); + } + + public static JsonElement legacyToJson(final String message) { + return SerializerVersion.V1_12.toJson(LegacyStringDeserializer.parse(message, true)); + } + + public static String legacyToJsonString(final String message) { + return legacyToJsonString(message, false); + } + + public static String legacyToJsonString(final String message, final boolean itemData) { + final ATextComponent component = LegacyStringDeserializer.parse(message, true); + if (itemData) { + component.setParentStyle(new Style().setItalic(false)); + } + return TextComponentSerializer.V1_12.serialize(component); + } + + public static String jsonToLegacy(final String value) { + return TextComponentSerializer.V1_12.deserializeReader(value).asLegacyFormatString(); + } + + public static String jsonToLegacy(final JsonElement value) { + return TextComponentSerializer.V1_12.deserialize(value).asLegacyFormatString(); + } + + public enum SerializerVersion { + V1_8(TextComponentSerializer.V1_8, SNbtSerializer.V1_8), + V1_9(TextComponentSerializer.V1_9, SNbtSerializer.V1_8), + V1_12(TextComponentSerializer.V1_12, SNbtSerializer.V1_12), + V1_14(TextComponentSerializer.V1_14, SNbtSerializer.V1_14), + V1_15(TextComponentSerializer.V1_15, SNbtSerializer.V1_14), + V1_16(TextComponentSerializer.V1_16, SNbtSerializer.V1_14), + V1_17(TextComponentSerializer.V1_17, SNbtSerializer.V1_14), + V1_18(TextComponentSerializer.V1_18, SNbtSerializer.V1_14), + V1_19_4(TextComponentSerializer.V1_19_4, SNbtSerializer.V1_14), + V1_20_3(TextComponentCodec.V1_20_3, SNbtSerializer.V1_14); + + private final TextComponentSerializer jsonSerializer; + private final SNbtSerializer snbtSerializer; + private final TextComponentCodec codec; + + SerializerVersion(final TextComponentSerializer jsonSerializer, final SNbtSerializer snbtSerializer) { + this.jsonSerializer = jsonSerializer; + this.snbtSerializer = snbtSerializer; + this.codec = null; + } + + SerializerVersion(final TextComponentCodec codec, final SNbtSerializer snbtSerializer) { + this.codec = codec; + this.jsonSerializer = codec.asSerializer(); + this.snbtSerializer = snbtSerializer; + } + + public JsonElement toJson(final ATextComponent component) { + return jsonSerializer.serializeJson(component); + } + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/util/Config.java b/common/src/main/java/com/viaversion/viaversion/util/Config.java index c4d259fd7..25d74cbf2 100644 --- a/common/src/main/java/com/viaversion/viaversion/util/Config.java +++ b/common/src/main/java/com/viaversion/viaversion/util/Config.java @@ -21,12 +21,9 @@ import com.google.gson.JsonElement; import com.viaversion.viaversion.compatibility.YamlCompat; import com.viaversion.viaversion.compatibility.unsafe.Yaml1Compat; import com.viaversion.viaversion.compatibility.unsafe.Yaml2Compat; -import com.viaversion.viaversion.libs.kyori.adventure.text.serializer.gson.GsonComponentSerializer; -import com.viaversion.viaversion.libs.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.checkerframework.checker.nullness.qual.Nullable; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; - import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -231,7 +228,7 @@ public abstract class Config { public @Nullable JsonElement getSerializedComponent(String key) { final Object o = this.config.get(key); if (o != null && !((String) o).isEmpty()) { - return GsonComponentSerializer.gson().serializeToTree(LegacyComponentSerializer.legacySection().deserialize((String) o)); + return ComponentUtil.legacyToJson((String) o); } else { return null; } diff --git a/common/src/main/java/com/viaversion/viaversion/util/NBTConverter.java b/common/src/main/java/com/viaversion/viaversion/util/NBTConverter.java new file mode 100644 index 000000000..0b8c8f6c2 --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/util/NBTConverter.java @@ -0,0 +1,121 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2023 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.util; + +import com.github.steveice10.opennbt.tag.builtin.ByteArrayTag; +import com.github.steveice10.opennbt.tag.builtin.ByteTag; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.DoubleTag; +import com.github.steveice10.opennbt.tag.builtin.FloatTag; +import com.github.steveice10.opennbt.tag.builtin.IntArrayTag; +import com.github.steveice10.opennbt.tag.builtin.IntTag; +import com.github.steveice10.opennbt.tag.builtin.ListTag; +import com.github.steveice10.opennbt.tag.builtin.LongArrayTag; +import com.github.steveice10.opennbt.tag.builtin.LongTag; +import com.github.steveice10.opennbt.tag.builtin.NumberTag; +import com.github.steveice10.opennbt.tag.builtin.ShortTag; +import com.github.steveice10.opennbt.tag.builtin.StringTag; +import com.github.steveice10.opennbt.tag.builtin.Tag; +import java.util.Map; +import net.lenni0451.mcstructs.nbt.INbtTag; +import org.checkerframework.checker.nullness.qual.Nullable; + +final class NBTConverter { + + static @Nullable Tag mcStructsToVia(@Nullable final INbtTag nbtTag) { + if (nbtTag == null) { + return null; + } else if (nbtTag.isByteTag()) { + return new ByteTag(nbtTag.asByteTag().getValue()); + } else if (nbtTag.isShortTag()) { + return new ShortTag(nbtTag.asShortTag().getValue()); + } else if (nbtTag.isIntTag()) { + return new IntTag(nbtTag.asIntTag().getValue()); + } else if (nbtTag.isLongTag()) { + return new LongTag(nbtTag.asLongTag().getValue()); + } else if (nbtTag.isFloatTag()) { + return new FloatTag(nbtTag.asFloatTag().getValue()); + } else if (nbtTag.isDoubleTag()) { + return new DoubleTag(nbtTag.asDoubleTag().getValue()); + } else if (nbtTag.isByteArrayTag()) { + return new ByteArrayTag(nbtTag.asByteArrayTag().getValue()); + } else if (nbtTag.isStringTag()) { + return new StringTag(nbtTag.asStringTag().getValue()); + } else if (nbtTag.isListTag()) { + final ListTag list = new ListTag(); + for (final INbtTag t : nbtTag.asListTag().getValue()) { + list.add(mcStructsToVia(t)); + } + return list; + } else if (nbtTag.isCompoundTag()) { + final Map values = nbtTag.asCompoundTag().getValue(); + final CompoundTag compound = new CompoundTag(); + for (final Map.Entry entry : values.entrySet()) { + compound.put(entry.getKey(), mcStructsToVia(entry.getValue())); + } + return compound; + } else if (nbtTag.isIntArrayTag()) { + return new IntArrayTag(nbtTag.asIntArrayTag().getValue()); + } else if (nbtTag.isLongArrayTag()) { + return new LongArrayTag(nbtTag.asLongArrayTag().getValue()); + } else { + throw new IllegalArgumentException("Unsupported tag type: " + nbtTag.getClass().getName()); + } + } + + static @Nullable INbtTag viaToMcStructs(@Nullable final Tag tag) { + if (tag == null) { + return null; + } else if (tag instanceof ByteTag) { + return new net.lenni0451.mcstructs.nbt.tags.ByteTag(((NumberTag) tag).asByte()); + } else if (tag instanceof ShortTag) { + return new net.lenni0451.mcstructs.nbt.tags.ShortTag(((NumberTag) tag).asShort()); + } else if (tag instanceof IntTag) { + return new net.lenni0451.mcstructs.nbt.tags.IntTag(((NumberTag) tag).asInt()); + } else if (tag instanceof LongTag) { + return new net.lenni0451.mcstructs.nbt.tags.LongTag(((NumberTag) tag).asLong()); + } else if (tag instanceof FloatTag) { + return new net.lenni0451.mcstructs.nbt.tags.FloatTag(((NumberTag) tag).asFloat()); + } else if (tag instanceof DoubleTag) { + return new net.lenni0451.mcstructs.nbt.tags.DoubleTag(((NumberTag) tag).asDouble()); + } else if (tag instanceof ByteArrayTag) { + return new net.lenni0451.mcstructs.nbt.tags.ByteArrayTag(((ByteArrayTag) tag).getValue()); + } else if (tag instanceof StringTag) { + return new net.lenni0451.mcstructs.nbt.tags.StringTag(((StringTag) tag).getValue()); + } else if (tag instanceof ListTag) { + final net.lenni0451.mcstructs.nbt.tags.ListTag list = new net.lenni0451.mcstructs.nbt.tags.ListTag<>(); + for (final Tag t : ((ListTag) tag).getValue()) { + list.add(viaToMcStructs(t)); + } + return list; + } else if (tag instanceof CompoundTag) { + final Map values = ((CompoundTag) tag).getValue(); + final net.lenni0451.mcstructs.nbt.tags.CompoundTag compound = new net.lenni0451.mcstructs.nbt.tags.CompoundTag(); + for (final Map.Entry entry : values.entrySet()) { + compound.add(entry.getKey(), viaToMcStructs(entry.getValue())); + } + return compound; + } else if (tag instanceof IntArrayTag) { + return new net.lenni0451.mcstructs.nbt.tags.IntArrayTag(((IntArrayTag) tag).getValue()); + } else if (tag instanceof LongArrayTag) { + return new net.lenni0451.mcstructs.nbt.tags.LongArrayTag(((LongArrayTag) tag).getValue()); + } else { + throw new IllegalArgumentException("Unsupported tag type: " + tag.getClass().getName()); + } + } +} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5cfc04844..1117bdb23 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,11 +2,11 @@ metadata.format.version = "1.1" [versions] -adventure = "4.14.0" gson = "2.10.1" fastutil = "8.5.12" flare = "2.0.1" vianbt = "3.3.0" +mcstructs = "2.4.1" # Common provided netty = "4.0.20.Final" @@ -27,16 +27,12 @@ velocity = "3.1.1" [libraries] -adventureApi = { group = "net.kyori", name = "adventure-api", version.ref = "adventure" } -adventureTextSerializerGson = { group = "net.kyori", name = "adventure-text-serializer-gson", version.ref = "adventure" } -adventureTextSerializerGsonLegacy = { group = "net.kyori", name = "adventure-text-serializer-gson-legacy-impl", version.ref = "adventure" } -adventureTextSerializerLegacy = { group = "net.kyori", name = "adventure-text-serializer-legacy", version.ref = "adventure" } - gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" } fastutil = { group = "it.unimi.dsi", name = "fastutil", version.ref = "fastutil" } flare = { group = "space.vectrix.flare", name = "flare", version.ref = "flare" } flareFastutil = { group = "space.vectrix.flare", name = "flare-fastutil", version.ref = "flare" } vianbt = { group = "com.viaversion", name = "nbt", version.ref = "vianbt" } +text = { group = "net.lenni0451.mcstructs", name = "text", version.ref = "mcstructs" } netty = { group = "io.netty", name = "netty-all", version.ref = "netty" } guava = { group = "com.google.guava", name = "guava", version.ref = "guava" } @@ -56,5 +52,4 @@ velocity = { group = "com.velocitypowered", name = "velocity-api", version.ref = [bundles] -adventure = ["adventureApi", "adventureTextSerializerGson", "adventureTextSerializerGsonLegacy", "adventureTextSerializerLegacy"] junit = ["jupiterApi", "jupiterEngine"] diff --git a/settings.gradle.kts b/settings.gradle.kts index 564e6dbb0..5e0f402c9 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -27,7 +27,6 @@ rootProject.name = "viaversion-parent" includeBuild("build-logic") -include("adventure") include("compat", "compat:snakeyaml-compat-common", "compat:snakeyaml2-compat", "compat:snakeyaml1-compat", "compat:protocolsupport-compat") setupViaSubproject("api")