mirror of
https://github.com/ViaVersion/ViaVersion.git
synced 2024-11-22 10:05:12 +01:00
Move component conversion into its own class
Remove serialized component type in 1.20.3->1.20.2
This commit is contained in:
parent
1656ad45a0
commit
2c9affa0e3
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
|
||||
* Copyright (C) 2016-2023 ViaVersion and contributors
|
||||
*
|
||||
* 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 com.viaversion.viaversion.api.type.types;
|
||||
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.util.UUID;
|
||||
|
||||
public class UUIDIntArrayType extends Type<UUID> {
|
||||
|
||||
public UUIDIntArrayType() {
|
||||
super(UUID.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID read(ByteBuf buffer) {
|
||||
int[] ints = {
|
||||
buffer.readInt(),
|
||||
buffer.readInt(),
|
||||
buffer.readInt(),
|
||||
buffer.readInt()
|
||||
};
|
||||
return uuidFromIntArray(ints);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buffer, UUID object) {
|
||||
int[] ints = uuidToIntArray(object);
|
||||
buffer.writeInt(ints[0]);
|
||||
buffer.writeInt(ints[1]);
|
||||
buffer.writeInt(ints[2]);
|
||||
buffer.writeInt(ints[3]);
|
||||
}
|
||||
|
||||
public static UUID uuidFromIntArray(int[] ints) {
|
||||
return new UUID((long) ints[0] << 32 | ((long) ints[1] & 0xFFFFFFFFL), (long) ints[2] << 32 | ((long) ints[3] & 0xFFFFFFFFL));
|
||||
}
|
||||
|
||||
public static int[] uuidToIntArray(UUID uuid) {
|
||||
return bitsToIntArray(uuid.getMostSignificantBits(), uuid.getLeastSignificantBits());
|
||||
}
|
||||
|
||||
public static int[] bitsToIntArray(long long1, long long2) {
|
||||
return new int[]{(int) (long1 >> 32), (int) long1, (int) (long2 >> 32), (int) long2};
|
||||
}
|
||||
}
|
@ -29,7 +29,6 @@ import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
|
||||
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
|
||||
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.types.UUIDIntArrayType;
|
||||
import com.viaversion.viaversion.protocols.protocol1_15to1_14_4.ClientboundPackets1_15;
|
||||
import com.viaversion.viaversion.protocols.protocol1_16to1_15_2.ClientboundPackets1_16;
|
||||
import com.viaversion.viaversion.protocols.protocol1_16to1_15_2.Protocol1_16To1_15_2;
|
||||
@ -38,6 +37,7 @@ import com.viaversion.viaversion.protocols.protocol1_16to1_15_2.storage.Inventor
|
||||
import com.viaversion.viaversion.rewriter.ItemRewriter;
|
||||
import com.viaversion.viaversion.rewriter.RecipeRewriter;
|
||||
import com.viaversion.viaversion.util.Key;
|
||||
import com.viaversion.viaversion.util.UUIDUtil;
|
||||
import java.util.UUID;
|
||||
|
||||
public class InventoryPackets extends ItemRewriter<ClientboundPackets1_15, ServerboundPackets1_16, Protocol1_16To1_15_2> {
|
||||
@ -153,7 +153,7 @@ public class InventoryPackets extends ItemRewriter<ClientboundPackets1_15, Serve
|
||||
Tag idTag = ownerCompundTag.get("Id");
|
||||
if (idTag instanceof StringTag) {
|
||||
UUID id = UUID.fromString((String) idTag.getValue());
|
||||
ownerCompundTag.put("Id", new IntArrayTag(UUIDIntArrayType.uuidToIntArray(id)));
|
||||
ownerCompundTag.put("Id", new IntArrayTag(UUIDUtil.toIntArray(id)));
|
||||
}
|
||||
}
|
||||
} else if (item.identifier() == 759 && tag != null) {
|
||||
@ -187,7 +187,7 @@ public class InventoryPackets extends ItemRewriter<ClientboundPackets1_15, Serve
|
||||
CompoundTag ownerCompundTag = (CompoundTag) ownerTag;
|
||||
Tag idTag = ownerCompundTag.get("Id");
|
||||
if (idTag instanceof IntArrayTag) {
|
||||
UUID id = UUIDIntArrayType.uuidFromIntArray((int[]) idTag.getValue());
|
||||
UUID id = UUIDUtil.fromIntArray((int[]) idTag.getValue());
|
||||
ownerCompundTag.put("Id", new StringTag(id.toString()));
|
||||
}
|
||||
}
|
||||
@ -210,7 +210,7 @@ public class InventoryPackets extends ItemRewriter<ClientboundPackets1_15, Serve
|
||||
Tag leastTag = attribute.get("UUIDLeast");
|
||||
if (leastTag != null) {
|
||||
Tag mostTag = attribute.get("UUIDMost");
|
||||
int[] uuidIntArray = UUIDIntArrayType.bitsToIntArray(((NumberTag) leastTag).asLong(), ((NumberTag) mostTag).asLong());
|
||||
int[] uuidIntArray = UUIDUtil.toIntArray(((NumberTag) leastTag).asLong(), ((NumberTag) mostTag).asLong());
|
||||
attribute.put("UUID", new IntArrayTag(uuidIntArray));
|
||||
}
|
||||
}
|
||||
@ -228,7 +228,7 @@ public class InventoryPackets extends ItemRewriter<ClientboundPackets1_15, Serve
|
||||
rewriteAttributeName(attribute, "Name", true);
|
||||
IntArrayTag uuidTag = attribute.get("UUID");
|
||||
if (uuidTag != null && uuidTag.getValue().length == 4) {
|
||||
UUID uuid = UUIDIntArrayType.uuidFromIntArray(uuidTag.getValue());
|
||||
UUID uuid = UUIDUtil.fromIntArray(uuidTag.getValue());
|
||||
attribute.put("UUIDLeast", new LongTag(uuid.getLeastSignificantBits()));
|
||||
attribute.put("UUIDMost", new LongTag(uuid.getMostSignificantBits()));
|
||||
}
|
||||
|
@ -29,13 +29,13 @@ import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
|
||||
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
|
||||
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.types.UUIDIntArrayType;
|
||||
import com.viaversion.viaversion.protocols.protocol1_15to1_14_4.ClientboundPackets1_15;
|
||||
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_15;
|
||||
import com.viaversion.viaversion.protocols.protocol1_16to1_15_2.Protocol1_16To1_15_2;
|
||||
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_16;
|
||||
import com.viaversion.viaversion.rewriter.BlockRewriter;
|
||||
import com.viaversion.viaversion.util.CompactArrayUtil;
|
||||
import com.viaversion.viaversion.util.UUIDUtil;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@ -112,13 +112,13 @@ public class WorldPackets {
|
||||
|
||||
// target_uuid -> Target
|
||||
UUID targetUuid = UUID.fromString((String) targetUuidTag.getValue());
|
||||
compoundTag.put("Target", new IntArrayTag(UUIDIntArrayType.uuidToIntArray(targetUuid)));
|
||||
compoundTag.put("Target", new IntArrayTag(UUIDUtil.toIntArray(targetUuid)));
|
||||
} else if (id.equals("minecraft:skull") && compoundTag.get("Owner") instanceof CompoundTag) {
|
||||
CompoundTag ownerTag = compoundTag.remove("Owner");
|
||||
StringTag ownerUuidTag = ownerTag.remove("Id");
|
||||
if (ownerUuidTag != null) {
|
||||
UUID ownerUuid = UUID.fromString(ownerUuidTag.getValue());
|
||||
ownerTag.put("Id", new IntArrayTag(UUIDIntArrayType.uuidToIntArray(ownerUuid)));
|
||||
ownerTag.put("Id", new IntArrayTag(UUIDUtil.toIntArray(ownerUuid)));
|
||||
}
|
||||
|
||||
// Owner -> SkullOwner
|
||||
|
@ -17,26 +17,6 @@
|
||||
*/
|
||||
package com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2;
|
||||
|
||||
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.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.data.MappingData;
|
||||
import com.viaversion.viaversion.api.data.MappingDataBase;
|
||||
@ -49,7 +29,6 @@ import com.viaversion.viaversion.api.protocol.packet.State;
|
||||
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
|
||||
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.types.UUIDIntArrayType;
|
||||
import com.viaversion.viaversion.api.type.types.misc.ParticleType;
|
||||
import com.viaversion.viaversion.api.type.types.version.Types1_20_3;
|
||||
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
|
||||
@ -63,30 +42,17 @@ import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.packet.Clientb
|
||||
import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.packet.ServerboundPackets1_20_3;
|
||||
import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.rewriter.BlockItemPacketRewriter1_20_3;
|
||||
import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.rewriter.EntityPacketRewriter1_20_3;
|
||||
import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.util.ComponentConverter;
|
||||
import com.viaversion.viaversion.rewriter.SoundRewriter;
|
||||
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
|
||||
import com.viaversion.viaversion.rewriter.TagRewriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.BitSet;
|
||||
import java.util.HashSet;
|
||||
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 Protocol1_20_3To1_20_2 extends AbstractProtocol<ClientboundPackets1_20_2, ClientboundPackets1_20_3, ServerboundPackets1_20_2, ServerboundPackets1_20_3> {
|
||||
|
||||
public static final MappingData MAPPINGS = new MappingDataBase("1.20.2", "1.20.3");
|
||||
private static final Set<String> BOOLEAN_TYPES = new HashSet<>(Arrays.asList(
|
||||
"interpret",
|
||||
"bold",
|
||||
"italic",
|
||||
"underlined",
|
||||
"strikethrough",
|
||||
"obfuscated"
|
||||
));
|
||||
private final BlockItemPacketRewriter1_20_3 itemRewriter = new BlockItemPacketRewriter1_20_3(this);
|
||||
private final EntityPacketRewriter1_20_3 entityRewriter = new EntityPacketRewriter1_20_3(this);
|
||||
|
||||
@ -370,248 +336,11 @@ public final class Protocol1_20_3To1_20_2 extends AbstractProtocol<ClientboundPa
|
||||
}
|
||||
|
||||
private void convertComponent(final PacketWrapper wrapper) throws Exception {
|
||||
wrapper.write(Type.TAG, jsonComponentToTag(wrapper.read(Type.COMPONENT)));
|
||||
wrapper.write(Type.TAG, ComponentConverter.jsonComponentToTag(wrapper.read(Type.COMPONENT)));
|
||||
}
|
||||
|
||||
private void convertOptionalComponent(final PacketWrapper wrapper) throws Exception {
|
||||
wrapper.write(Type.OPTIONAL_TAG, jsonComponentToTag(wrapper.read(Type.OPTIONAL_COMPONENT)));
|
||||
}
|
||||
|
||||
public static @Nullable JsonElement tagComponentToJson(@Nullable final Tag tag) {
|
||||
try {
|
||||
return convertToJson(null, tag);
|
||||
} catch (final Exception e) {
|
||||
Via.getPlatform().getLogger().log(Level.SEVERE, "Error converting component: " + tag, e);
|
||||
return new JsonPrimitive("<error>");
|
||||
}
|
||||
}
|
||||
|
||||
public static @Nullable Tag jsonComponentToTag(@Nullable final JsonElement component) {
|
||||
try {
|
||||
return convertToTag(component);
|
||||
} catch (final Exception e) {
|
||||
Via.getPlatform().getLogger().log(Level.SEVERE, "Error converting component: " + component, e);
|
||||
return new StringTag("<error>");
|
||||
}
|
||||
}
|
||||
|
||||
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<String, JsonElement> 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 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
|
||||
// Order is important
|
||||
if (object.has("text")) {
|
||||
tag.put("type", new StringTag("text"));
|
||||
} else if (object.has("translate")) {
|
||||
tag.put("type", new StringTag("translatable"));
|
||||
} else if (object.has("score")) {
|
||||
tag.put("type", new StringTag("score"));
|
||||
} else if (object.has("selector")) {
|
||||
tag.put("type", new StringTag("selector"));
|
||||
} else if (object.has("keybind")) {
|
||||
tag.put("type", new StringTag("keybind"));
|
||||
} else if (object.has("nbt")) {
|
||||
tag.put("type", new StringTag("nbt"));
|
||||
}
|
||||
}
|
||||
|
||||
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, 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 = parseUUID(id.getAsString())) != null) {
|
||||
hoverEvent.remove("id");
|
||||
|
||||
final CompoundTag convertedTag = (CompoundTag) convertToTag(value);
|
||||
convertedTag.put("id", new IntArrayTag(UUIDIntArrayType.uuidToIntArray(uuid)));
|
||||
tag.put(key, convertedTag);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
tag.put(key, convertToTag(value));
|
||||
}
|
||||
|
||||
private static @Nullable UUID parseUUID(final String uuidString) {
|
||||
try {
|
||||
return UUID.fromString(uuidString);
|
||||
} catch (final IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
for (final Map.Entry<String, Tag> 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);
|
||||
convertedElement.addProperty("id", uuidIntsToString(((IntArrayTag) idTag).getValue()));
|
||||
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 String uuidIntsToString(final int[] parts) {
|
||||
if (parts.length != 4) {
|
||||
return new UUID(0, 0).toString();
|
||||
}
|
||||
return UUIDIntArrayType.uuidFromIntArray(parts).toString();
|
||||
wrapper.write(Type.OPTIONAL_TAG, ComponentConverter.jsonComponentToTag(wrapper.read(Type.OPTIONAL_COMPONENT)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -32,6 +32,7 @@ import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.Clientbou
|
||||
import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ClientboundPackets1_20_2;
|
||||
import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.Protocol1_20_3To1_20_2;
|
||||
import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.packet.ClientboundPackets1_20_3;
|
||||
import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.util.ComponentConverter;
|
||||
import com.viaversion.viaversion.rewriter.EntityRewriter;
|
||||
import com.viaversion.viaversion.util.Key;
|
||||
|
||||
@ -102,9 +103,9 @@ public final class EntityPacketRewriter1_20_3 extends EntityRewriter<Clientbound
|
||||
filter().handler((event, meta) -> {
|
||||
final MetaType type = meta.metaType();
|
||||
if (type == Types1_20_2.META_TYPES.componentType) {
|
||||
meta.setTypeAndValue(Types1_20_3.META_TYPES.componentType, Protocol1_20_3To1_20_2.jsonComponentToTag(meta.value()));
|
||||
meta.setTypeAndValue(Types1_20_3.META_TYPES.componentType, ComponentConverter.jsonComponentToTag(meta.value()));
|
||||
} else if (type == Types1_20_2.META_TYPES.optionalComponentType) {
|
||||
meta.setTypeAndValue(Types1_20_3.META_TYPES.optionalComponentType, Protocol1_20_3To1_20_2.jsonComponentToTag(meta.value()));
|
||||
meta.setTypeAndValue(Types1_20_3.META_TYPES.optionalComponentType, ComponentConverter.jsonComponentToTag(meta.value()));
|
||||
} else if (type == Types1_20_2.META_TYPES.particleType) {
|
||||
final Particle particle = (Particle) meta.getValue();
|
||||
final ParticleMappings particleMappings = protocol.getMappingData().getParticleMappings();
|
||||
|
@ -0,0 +1,304 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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 Set<String> BOOLEAN_TYPES = new HashSet<>(Arrays.asList(
|
||||
"interpret",
|
||||
"bold",
|
||||
"italic",
|
||||
"underlined",
|
||||
"strikethrough",
|
||||
"obfuscated"
|
||||
));
|
||||
// Order is important
|
||||
private static final List<Pair<String, String>> 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) {
|
||||
try {
|
||||
return convertToJson(null, tag);
|
||||
} catch (final Exception e) {
|
||||
Via.getPlatform().getLogger().log(Level.SEVERE, "Error converting component: " + tag, e);
|
||||
return new JsonPrimitive("<error>");
|
||||
}
|
||||
}
|
||||
|
||||
public static @Nullable Tag jsonComponentToTag(@Nullable final JsonElement component) {
|
||||
try {
|
||||
return convertToTag(component);
|
||||
} catch (final Exception e) {
|
||||
Via.getPlatform().getLogger().log(Level.SEVERE, "Error converting component: " + component, e);
|
||||
return new StringTag("<error>");
|
||||
}
|
||||
}
|
||||
|
||||
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<String, JsonElement> 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, 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<String, String> 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<String, Tag> 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.isJsonPrimitive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the other fields
|
||||
final String typeString = type.getAsString();
|
||||
for (final Pair<String, String> pair : COMPONENT_TYPES) {
|
||||
if (!pair.key().equals(typeString)) {
|
||||
object.remove(pair.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.viaversion.viaversion.util;
|
||||
|
||||
import java.util.UUID;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public final class UUIDUtil {
|
||||
|
||||
public static UUID fromIntArray(final int[] parts) {
|
||||
if (parts.length != 4) {
|
||||
return new UUID(0, 0);
|
||||
}
|
||||
return new UUID((long) parts[0] << 32 | (parts[1] & 0xFFFFFFFFL), (long) parts[2] << 32 | (parts[3] & 0xFFFFFFFFL));
|
||||
}
|
||||
|
||||
public static int[] toIntArray(final UUID uuid) {
|
||||
return toIntArray(uuid.getMostSignificantBits(), uuid.getLeastSignificantBits());
|
||||
}
|
||||
|
||||
public static int[] toIntArray(final long msb, final long lsb) {
|
||||
return new int[]{(int) (msb >> 32), (int) msb, (int) (lsb >> 32), (int) lsb};
|
||||
}
|
||||
|
||||
public static @Nullable UUID parseUUID(final String uuidString) {
|
||||
try {
|
||||
return UUID.fromString(uuidString);
|
||||
} catch (final IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user