From 263790e9f6da43e6af75cc7c664ced0b207b54fd Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Fri, 3 May 2024 20:00:14 +0200 Subject: [PATCH] 24w18a --- .../api/ViaBackwardsPlatform.java | 2 + .../api/data/BackwardsMappingData.java | 5 + .../BackwardsStructuredItemRewriter.java | 17 +- .../StructuredEnchantmentRewriter.java | 49 +++-- .../Protocol1_20_5To1_21.java | 126 ++++++++++++ .../rewriter/BlockItemPacketRewriter1_21.java | 153 +++++++++++++++ .../rewriter/EntityPacketRewriter1_21.java | 183 ++++++++++++++++++ .../storage/EnchantmentsPaintingsStorage.java | 61 ++++++ .../BlockItemPacketRewriter1_20_5.java | 9 + .../data/mappings-1.21to1.20.5.nbt | Bin 0 -> 794 bytes gradle.properties | 2 +- gradle/libs.versions.toml | 2 +- .../template/protocol/Protocol1_98To1_99.java | 14 +- .../rewriter/EntityPacketRewriter1_99.java | 27 ++- 14 files changed, 602 insertions(+), 48 deletions(-) create mode 100644 common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_5to1_21/Protocol1_20_5To1_21.java create mode 100644 common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_5to1_21/rewriter/BlockItemPacketRewriter1_21.java create mode 100644 common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_5to1_21/rewriter/EntityPacketRewriter1_21.java create mode 100644 common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_5to1_21/storage/EnchantmentsPaintingsStorage.java create mode 100644 common/src/main/resources/assets/viabackwards/data/mappings-1.21to1.20.5.nbt diff --git a/common/src/main/java/com/viaversion/viabackwards/api/ViaBackwardsPlatform.java b/common/src/main/java/com/viaversion/viabackwards/api/ViaBackwardsPlatform.java index 21f60927..3d34a480 100644 --- a/common/src/main/java/com/viaversion/viabackwards/api/ViaBackwardsPlatform.java +++ b/common/src/main/java/com/viaversion/viabackwards/api/ViaBackwardsPlatform.java @@ -138,6 +138,8 @@ public interface ViaBackwardsPlatform { protocolManager.registerProtocol(new Protocol1_20_2To1_20(), ProtocolVersion.v1_20, ProtocolVersion.v1_20_2); protocolManager.registerProtocol(new Protocol1_20_3To1_20_2(), ProtocolVersion.v1_20_2, ProtocolVersion.v1_20_3); protocolManager.registerProtocol(new Protocol1_20_5To1_20_3(), ProtocolVersion.v1_20_3, ProtocolVersion.v1_20_5); + + protocolManager.registerProtocol(new Protocol1_20_5To1_21(), ProtocolVersion.v1_20_5, ProtocolVersion.v1_21); } /** diff --git a/common/src/main/java/com/viaversion/viabackwards/api/data/BackwardsMappingData.java b/common/src/main/java/com/viaversion/viabackwards/api/data/BackwardsMappingData.java index 052f0232..a1acfe5e 100644 --- a/common/src/main/java/com/viaversion/viabackwards/api/data/BackwardsMappingData.java +++ b/common/src/main/java/com/viaversion/viabackwards/api/data/BackwardsMappingData.java @@ -151,6 +151,11 @@ public class BackwardsMappingData extends MappingDataBase { return checkValidity(id, this.itemMappings.inverse().getNewId(id), "item"); } + @Override + public int getNewAttributeId(final int id) { + return this.attributeMappings.getNewId(id); + } + public @Nullable MappedItem getMappedItem(final int id) { return backwardsItemMappings != null ? backwardsItemMappings.get(id) : null; } diff --git a/common/src/main/java/com/viaversion/viabackwards/api/rewriters/BackwardsStructuredItemRewriter.java b/common/src/main/java/com/viaversion/viabackwards/api/rewriters/BackwardsStructuredItemRewriter.java index fa68a9f4..66028768 100644 --- a/common/src/main/java/com/viaversion/viabackwards/api/rewriters/BackwardsStructuredItemRewriter.java +++ b/common/src/main/java/com/viaversion/viabackwards/api/rewriters/BackwardsStructuredItemRewriter.java @@ -34,11 +34,11 @@ import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType; import com.viaversion.viaversion.api.type.Type; import org.checkerframework.checker.nullness.qual.Nullable; +import static com.viaversion.viaversion.rewriter.StructuredItemRewriter.updateItemComponents; + public class BackwardsStructuredItemRewriter> extends BackwardsItemRewriter { - protected final StructuredEnchantmentRewriter enchantmentRewriter = new StructuredEnchantmentRewriter(this); - public BackwardsStructuredItemRewriter(final T protocol, final Type itemType, final Type itemArrayType) { super(protocol, itemType, itemArrayType); } @@ -56,10 +56,6 @@ public class BackwardsStructuredItemRewriter customNameData = data.getNonEmpty(StructuredDataKey.CUSTOM_NAME); @@ -86,6 +82,8 @@ public class BackwardsStructuredItemRewriter { + final Mappings mappings = mappingData.getEnchantmentMappings(); + return mappings.getNewId(id); + }; + final DescriptionSupplier descriptionSupplier = (id, level) -> { + final String remappedName = mappingData.mappedEnchantmentName(id); + return ComponentUtil.jsonStringToTag(ComponentUtil.legacyToJsonString("§7" + remappedName + " " + EnchantmentRewriter.getRomanNumber(level), true)); + }; + rewriteEnchantmentsToClient(data, StructuredDataKey.ENCHANTMENTS, idRewriteFunction, descriptionSupplier, false); + rewriteEnchantmentsToClient(data, StructuredDataKey.STORED_ENCHANTMENTS, idRewriteFunction, descriptionSupplier, true); } public void handleToServer(final Item item) { @@ -60,15 +69,11 @@ public class StructuredEnchantmentRewriter { } final CompoundTag tag = customData.value(); - if (tag.contains(itemRewriter.nbtTagName("enchantments"))) { - rewriteEnchantmentsToServer(data, tag, StructuredDataKey.ENCHANTMENTS, false); - } - if (tag.contains(itemRewriter.nbtTagName("stored_enchantments"))) { - rewriteEnchantmentsToServer(data, tag, StructuredDataKey.STORED_ENCHANTMENTS, true); - } + rewriteEnchantmentsToServer(data, tag, StructuredDataKey.ENCHANTMENTS); + rewriteEnchantmentsToServer(data, tag, StructuredDataKey.STORED_ENCHANTMENTS); } - public void rewriteEnchantmentsToClient(final StructuredDataContainer data, final StructuredDataKey key, final boolean storedEnchant) { + public void rewriteEnchantmentsToClient(final StructuredDataContainer data, final StructuredDataKey key, final IdRewriteFunction rewriteFunction, final DescriptionSupplier descriptionSupplier, final boolean storedEnchant) { final StructuredData enchantmentsData = data.getNonEmpty(key); if (enchantmentsData == null) { return; @@ -83,33 +88,33 @@ public class StructuredEnchantmentRewriter { final List updatedIds = new ArrayList<>(); while (iterator.hasNext()) { final Int2IntMap.Entry entry = iterator.next(); - final BackwardsMappingData mappingData = itemRewriter.protocol().getMappingData(); - final Mappings mappings = mappingData.getEnchantmentMappings(); - final int mappedId = mappings.getNewId(entry.getIntKey()); + final int id = entry.getIntKey(); + final int mappedId = rewriteFunction.rewrite(id); if (mappedId != -1) { if (rewriteIds) { // Update the map after to iteration to preserve the current ids before possibly saving the original, avoid CME - updatedIds.add(IntIntPair.of(entry.getIntKey(), mappedId)); + updatedIds.add(IntIntPair.of(id, mappedId)); } continue; } - final String remappedName = mappingData.mappedEnchantmentName(entry.getIntKey()); - if (remappedName != null) { + final int level = entry.getIntValue(); + final Tag description = descriptionSupplier.get(id, level); + if (description != null) { if (!changed) { // Backup original before doing modifications itemRewriter.saveListTag(tag, asTag(enchantments), key.identifier()); changed = true; } - final int level = entry.getIntValue(); - loreToAdd.add(ComponentUtil.jsonStringToTag(ComponentUtil.legacyToJsonString("§7" + remappedName + " " + EnchantmentRewriter.getRomanNumber(level), true))); + loreToAdd.add(description); iterator.remove(); } } for (final IntIntPair pair : updatedIds) { - enchantments.add(pair.firstInt(), pair.secondInt()); + final int level = enchantments.enchantments().remove(pair.firstInt()); + enchantments.add(pair.secondInt(), level); } if (loreToAdd.isEmpty()) { @@ -156,7 +161,7 @@ public class StructuredEnchantmentRewriter { return listTag; } - public void rewriteEnchantmentsToServer(final StructuredDataContainer data, final CompoundTag tag, final StructuredDataKey key, final boolean storedEnchant) { + public void rewriteEnchantmentsToServer(final StructuredDataContainer data, final CompoundTag tag, final StructuredDataKey key) { final ListTag enchantmentsTag = itemRewriter.removeListTag(tag, key.identifier(), CompoundTag.class); if (enchantmentsTag == null) { return; @@ -186,4 +191,10 @@ public class StructuredEnchantmentRewriter { public void setRewriteIds(final boolean rewriteIds) { this.rewriteIds = rewriteIds; } + + @FunctionalInterface + public interface DescriptionSupplier { + + Tag get(int id, int level); + } } diff --git a/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_5to1_21/Protocol1_20_5To1_21.java b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_5to1_21/Protocol1_20_5To1_21.java new file mode 100644 index 00000000..bd95427c --- /dev/null +++ b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_5to1_21/Protocol1_20_5To1_21.java @@ -0,0 +1,126 @@ +/* + * This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards + * Copyright (C) 2016-2024 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.viabackwards.protocol.protocol1_20_5to1_21; + +import com.viaversion.viabackwards.api.BackwardsProtocol; +import com.viaversion.viabackwards.api.data.BackwardsMappings; +import com.viaversion.viabackwards.api.rewriters.SoundRewriter; +import com.viaversion.viabackwards.api.rewriters.TranslatableRewriter; +import com.viaversion.viabackwards.protocol.protocol1_20_5to1_21.rewriter.BlockItemPacketRewriter1_21; +import com.viaversion.viabackwards.protocol.protocol1_20_5to1_21.rewriter.EntityPacketRewriter1_21; +import com.viaversion.viabackwards.protocol.protocol1_20_5to1_21.storage.EnchantmentsPaintingsStorage; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_20_5; +import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvider; +import com.viaversion.viaversion.api.protocol.packet.provider.SimplePacketTypesProvider; +import com.viaversion.viaversion.data.entity.EntityTrackerBase; +import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.packet.ClientboundConfigurationPackets1_20_5; +import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.packet.ClientboundPacket1_20_5; +import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.packet.ClientboundPackets1_20_5; +import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.packet.ServerboundConfigurationPackets1_20_5; +import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.packet.ServerboundPacket1_20_5; +import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.packet.ServerboundPackets1_20_5; +import com.viaversion.viaversion.protocols.protocol1_21to1_20_5.Protocol1_21To1_20_5; +import com.viaversion.viaversion.rewriter.AttributeRewriter; +import com.viaversion.viaversion.rewriter.ComponentRewriter.ReadType; +import com.viaversion.viaversion.rewriter.StatisticsRewriter; +import com.viaversion.viaversion.rewriter.TagRewriter; + +import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap; + +public final class Protocol1_20_5To1_21 extends BackwardsProtocol { + + public static final BackwardsMappings MAPPINGS = new BackwardsMappings("1.21", "1.20.5", Protocol1_21To1_20_5.class); + private final EntityPacketRewriter1_21 entityRewriter = new EntityPacketRewriter1_21(this); + private final BlockItemPacketRewriter1_21 itemRewriter = new BlockItemPacketRewriter1_21(this); + private final TranslatableRewriter translatableRewriter = new TranslatableRewriter<>(this, ReadType.NBT); + private final TagRewriter tagRewriter = new TagRewriter<>(this); + + public Protocol1_20_5To1_21() { + super(ClientboundPacket1_20_5.class, ClientboundPacket1_20_5.class, ServerboundPacket1_20_5.class, ServerboundPacket1_20_5.class); + } + + @Override + protected void registerPackets() { + super.registerPackets(); + + tagRewriter.registerGeneric(ClientboundPackets1_20_5.TAGS); + tagRewriter.registerGeneric(ClientboundConfigurationPackets1_20_5.UPDATE_TAGS); + + final SoundRewriter soundRewriter = new SoundRewriter<>(this); + soundRewriter.register1_19_3Sound(ClientboundPackets1_20_5.SOUND); + soundRewriter.register1_19_3Sound(ClientboundPackets1_20_5.ENTITY_SOUND); + soundRewriter.registerStopSound(ClientboundPackets1_20_5.STOP_SOUND); + + new StatisticsRewriter<>(this).register(ClientboundPackets1_20_5.STATISTICS); + new AttributeRewriter<>(this).register1_20_5(ClientboundPackets1_20_5.ENTITY_PROPERTIES); + + translatableRewriter.registerOpenWindow(ClientboundPackets1_20_5.OPEN_WINDOW); + translatableRewriter.registerComponentPacket(ClientboundPackets1_20_5.ACTIONBAR); + translatableRewriter.registerComponentPacket(ClientboundPackets1_20_5.TITLE_TEXT); + translatableRewriter.registerComponentPacket(ClientboundPackets1_20_5.TITLE_SUBTITLE); + translatableRewriter.registerBossBar(ClientboundPackets1_20_5.BOSSBAR); + translatableRewriter.registerComponentPacket(ClientboundPackets1_20_5.DISCONNECT); + translatableRewriter.registerTabList(ClientboundPackets1_20_5.TAB_LIST); + translatableRewriter.registerCombatKill1_20(ClientboundPackets1_20_5.COMBAT_KILL); + translatableRewriter.registerComponentPacket(ClientboundPackets1_20_5.SYSTEM_CHAT); + translatableRewriter.registerComponentPacket(ClientboundPackets1_20_5.DISGUISED_CHAT); + translatableRewriter.registerPing(); + } + + @Override + public void init(final UserConnection user) { + addEntityTracker(user, new EntityTrackerBase(user, EntityTypes1_20_5.PLAYER)); + user.put(new EnchantmentsPaintingsStorage()); + } + + @Override + public BackwardsMappings getMappingData() { + return MAPPINGS; + } + + @Override + public EntityPacketRewriter1_21 getEntityRewriter() { + return entityRewriter; + } + + @Override + public BlockItemPacketRewriter1_21 getItemRewriter() { + return itemRewriter; + } + + @Override + public TranslatableRewriter getTranslatableRewriter() { + return translatableRewriter; + } + + @Override + public TagRewriter getTagRewriter() { + return tagRewriter; + } + + @Override + protected PacketTypesProvider createPacketTypesProvider() { + return new SimplePacketTypesProvider<>( + packetTypeMap(unmappedClientboundPacketType, ClientboundPackets1_20_5.class, ClientboundConfigurationPackets1_20_5.class), + packetTypeMap(mappedClientboundPacketType, ClientboundPackets1_20_5.class, ClientboundConfigurationPackets1_20_5.class), + packetTypeMap(mappedServerboundPacketType, ServerboundPackets1_20_5.class, ServerboundConfigurationPackets1_20_5.class), + packetTypeMap(unmappedServerboundPacketType, ServerboundPackets1_20_5.class, ServerboundConfigurationPackets1_20_5.class) + ); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_5to1_21/rewriter/BlockItemPacketRewriter1_21.java b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_5to1_21/rewriter/BlockItemPacketRewriter1_21.java new file mode 100644 index 00000000..a9d557e6 --- /dev/null +++ b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_5to1_21/rewriter/BlockItemPacketRewriter1_21.java @@ -0,0 +1,153 @@ +/* + * This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards + * Copyright (C) 2016-2024 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.viabackwards.protocol.protocol1_20_5to1_21.rewriter; + +import com.viaversion.viabackwards.api.rewriters.BackwardsStructuredItemRewriter; +import com.viaversion.viabackwards.api.rewriters.EnchantmentRewriter; +import com.viaversion.viabackwards.api.rewriters.StructuredEnchantmentRewriter; +import com.viaversion.viabackwards.protocol.protocol1_20_5to1_21.Protocol1_20_5To1_21; +import com.viaversion.viabackwards.protocol.protocol1_20_5to1_21.storage.EnchantmentsPaintingsStorage; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.minecraft.data.StructuredData; +import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer; +import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey; +import com.viaversion.viaversion.api.minecraft.item.Item; +import com.viaversion.viaversion.api.minecraft.item.data.Enchantments; +import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_20_2; +import com.viaversion.viaversion.api.type.types.version.Types1_20_5; +import com.viaversion.viaversion.api.type.types.version.Types1_21; +import com.viaversion.viaversion.libs.fastutil.ints.Int2IntMap; +import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag; +import com.viaversion.viaversion.libs.opennbt.tag.builtin.ListTag; +import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag; +import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag; +import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.rewriter.RecipeRewriter1_20_3; +import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.data.Enchantments1_20_5; +import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.packet.ClientboundPacket1_20_5; +import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.packet.ClientboundPackets1_20_5; +import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.packet.ServerboundPacket1_20_5; +import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.packet.ServerboundPackets1_20_5; +import com.viaversion.viaversion.rewriter.BlockRewriter; +import com.viaversion.viaversion.rewriter.IdRewriteFunction; +import java.util.ArrayList; +import java.util.Arrays; +import org.checkerframework.checker.nullness.qual.Nullable; + +public final class BlockItemPacketRewriter1_21 extends BackwardsStructuredItemRewriter { + + private final StructuredEnchantmentRewriter enchantmentRewriter = new StructuredEnchantmentRewriter(this); + + public BlockItemPacketRewriter1_21(final Protocol1_20_5To1_21 protocol) { + super(protocol, Types1_20_5.ITEM, Types1_20_5.ITEM_ARRAY, Types1_21.ITEM, Types1_21.ITEM_ARRAY); + } + + @Override + public void registerPackets() { + final BlockRewriter blockRewriter = BlockRewriter.for1_20_2(protocol); + blockRewriter.registerBlockAction(ClientboundPackets1_20_5.BLOCK_ACTION); + blockRewriter.registerBlockChange(ClientboundPackets1_20_5.BLOCK_CHANGE); + blockRewriter.registerVarLongMultiBlockChange1_20(ClientboundPackets1_20_5.MULTI_BLOCK_CHANGE); + blockRewriter.registerEffect(ClientboundPackets1_20_5.EFFECT, 1010, 2001); + blockRewriter.registerChunkData1_19(ClientboundPackets1_20_5.CHUNK_DATA, ChunkType1_20_2::new); + blockRewriter.registerBlockEntityData(ClientboundPackets1_20_5.BLOCK_ENTITY_DATA); + + registerSetCooldown(ClientboundPackets1_20_5.COOLDOWN); + registerWindowItems1_17_1(ClientboundPackets1_20_5.WINDOW_ITEMS); + registerSetSlot1_17_1(ClientboundPackets1_20_5.SET_SLOT); + registerAdvancements1_20_3(ClientboundPackets1_20_5.ADVANCEMENTS); + registerEntityEquipmentArray(ClientboundPackets1_20_5.ENTITY_EQUIPMENT); + registerClickWindow1_17_1(ServerboundPackets1_20_5.CLICK_WINDOW); + registerTradeList1_20_5(ClientboundPackets1_20_5.TRADE_LIST, Types1_20_5.ITEM_COST, Types1_20_5.ITEM_COST, Types1_21.OPTIONAL_ITEM_COST, Types1_21.OPTIONAL_ITEM_COST); + registerCreativeInvAction(ServerboundPackets1_20_5.CREATIVE_INVENTORY_ACTION); + registerWindowPropertyEnchantmentHandler(ClientboundPackets1_20_5.WINDOW_PROPERTY); + registerSpawnParticle1_20_5(ClientboundPackets1_20_5.SPAWN_PARTICLE, Types1_20_5.PARTICLE, Types1_21.PARTICLE); + registerExplosion(ClientboundPackets1_20_5.EXPLOSION, Types1_20_5.PARTICLE, Types1_21.PARTICLE); + + new RecipeRewriter1_20_3<>(protocol).register1_20_5(ClientboundPackets1_20_5.DECLARE_RECIPES); + } + + @Override + public @Nullable Item handleItemToClient(final UserConnection connection, @Nullable final Item item) { + if (item == null) return null; + + item.structuredData().setIdLookup(protocol, true); + + // Enchantments + final EnchantmentsPaintingsStorage storage = connection.get(EnchantmentsPaintingsStorage.class); + final StructuredDataContainer data = item.structuredData(); + final IdRewriteFunction idRewriteFunction = id -> { + final String key = storage.enchantments().idToKey(id); + return key != null ? Enchantments1_20_5.keyToId(key) : -1; + }; + final StructuredEnchantmentRewriter.DescriptionSupplier descriptionSupplier = (id, level) -> { + final Tag description = storage.enchantmentDescription(id); + if (description == null) { + return new StringTag("Unknown enchantment"); + } + + final CompoundTag fullDescription = new CompoundTag(); + fullDescription.putString("translate", "%s " + EnchantmentRewriter.getRomanNumber(level)); + fullDescription.put("with", new ListTag<>(Arrays.asList(description))); + return fullDescription; + }; + enchantmentRewriter.rewriteEnchantmentsToClient(data, StructuredDataKey.ENCHANTMENTS, idRewriteFunction, descriptionSupplier, false); + enchantmentRewriter.rewriteEnchantmentsToClient(data, StructuredDataKey.STORED_ENCHANTMENTS, idRewriteFunction, descriptionSupplier, true); + + return super.handleItemToClient(connection, item); + } + + @Override + public @Nullable Item handleItemToServer(final UserConnection connection, @Nullable final Item item) { + if (item == null) return null; + + final StructuredDataContainer dataContainer = item.structuredData(); + dataContainer.setIdLookup(protocol, false); + + // Rewrite enchantments + final EnchantmentsPaintingsStorage storage = connection.get(EnchantmentsPaintingsStorage.class); + rewriteEnchantmentToServer(storage, item, StructuredDataKey.ENCHANTMENTS); + rewriteEnchantmentToServer(storage, item, StructuredDataKey.STORED_ENCHANTMENTS); + + // Restore originals if present + enchantmentRewriter.handleToServer(item); + + return super.handleItemToServer(connection, item); + } + + private void rewriteEnchantmentToServer(final EnchantmentsPaintingsStorage storage, final Item item, final StructuredDataKey key) { + final StructuredData enchantmentsData = item.structuredData().getNonEmpty(key); + if (enchantmentsData == null) { + return; + } + + final Enchantments enchantments = enchantmentsData.value(); + for (final Int2IntMap.Entry entry : new ArrayList<>(enchantments.enchantments().int2IntEntrySet())) { + final int id = entry.getIntKey(); + final String enchantmentKey = Enchantments1_20_5.idToKey(id); + if (enchantmentKey == null) { + continue; + } + + final int mappedId = storage.enchantments().keyToId(enchantmentKey); + if (id != mappedId) { + enchantments.enchantments().remove(id); + enchantments.enchantments().put(mappedId, entry.getIntValue()); + } + } + } +} \ No newline at end of file diff --git a/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_5to1_21/rewriter/EntityPacketRewriter1_21.java b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_5to1_21/rewriter/EntityPacketRewriter1_21.java new file mode 100644 index 00000000..07144c8e --- /dev/null +++ b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_5to1_21/rewriter/EntityPacketRewriter1_21.java @@ -0,0 +1,183 @@ +/* + * This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards + * Copyright (C) 2016-2024 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.viabackwards.protocol.protocol1_20_5to1_21.rewriter; + +import com.viaversion.viabackwards.api.rewriters.EntityRewriter; +import com.viaversion.viabackwards.protocol.protocol1_20_5to1_21.Protocol1_20_5To1_21; +import com.viaversion.viabackwards.protocol.protocol1_20_5to1_21.storage.EnchantmentsPaintingsStorage; +import com.viaversion.viaversion.api.minecraft.RegistryEntry; +import com.viaversion.viaversion.api.minecraft.entities.EntityType; +import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_20_5; +import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; +import com.viaversion.viaversion.api.type.Type; +import com.viaversion.viaversion.api.type.types.version.Types1_20_5; +import com.viaversion.viaversion.api.type.types.version.Types1_21; +import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag; +import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag; +import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.packet.ClientboundConfigurationPackets1_20_5; +import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.packet.ClientboundPacket1_20_5; +import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.packet.ClientboundPackets1_20_5; +import com.viaversion.viaversion.protocols.protocol1_21to1_20_5.data.Paintings1_20_5; +import com.viaversion.viaversion.util.Key; +import com.viaversion.viaversion.util.KeyMappings; +import java.util.HashMap; +import java.util.Map; + +public final class EntityPacketRewriter1_21 extends EntityRewriter { + + private final Map oldPaintings = new HashMap<>(); + + public EntityPacketRewriter1_21(final Protocol1_20_5To1_21 protocol) { + super(protocol, Types1_20_5.META_TYPES.optionalComponentType, Types1_20_5.META_TYPES.booleanType); + + for (int i = 0; i < Paintings1_20_5.PAINTINGS.length; i++) { + final Paintings1_20_5.PaintingVariant painting = Paintings1_20_5.PAINTINGS[i]; + oldPaintings.put(painting.key(), new PaintingData(painting, i)); + } + } + + @Override + public void registerPackets() { + registerTrackerWithData1_19(ClientboundPackets1_20_5.SPAWN_ENTITY, EntityTypes1_20_5.FALLING_BLOCK); + registerMetadataRewriter(ClientboundPackets1_20_5.ENTITY_METADATA, Types1_21.METADATA_LIST, Types1_20_5.METADATA_LIST); + registerRemoveEntities(ClientboundPackets1_20_5.REMOVE_ENTITIES); + + protocol.registerClientbound(ClientboundConfigurationPackets1_20_5.REGISTRY_DATA, wrapper -> { + final String key = Key.stripMinecraftNamespace(wrapper.passthrough(Type.STRING)); + final RegistryEntry[] entries = wrapper.passthrough(Type.REGISTRY_ENTRY_ARRAY); + final boolean paintingVariant = key.equals("painting_variant"); + if (paintingVariant || key.equals("enchantment")) { + // Track custom registries and cancel the packet + final String[] keys = new String[entries.length]; + for (int i = 0; i < entries.length; i++) { + keys[i] = Key.stripMinecraftNamespace(entries[i].key()); + } + + final EnchantmentsPaintingsStorage storage = wrapper.user().get(EnchantmentsPaintingsStorage.class); + if (paintingVariant) { + storage.setPaintings(new KeyMappings(keys), paintingMappingsForEntries(entries)); + } else { + final Tag[] descriptions = new Tag[entries.length]; + for (int i = 0; i < entries.length; i++) { + final RegistryEntry entry = entries[i]; + if (entry.tag() != null) { + descriptions[i] = ((CompoundTag) entry.tag()).get("description"); + } + } + storage.setEnchantments(new KeyMappings(keys), descriptions); + } + + wrapper.cancel(); + } else { + handleRegistryData1_20_5(wrapper.user(), key, entries); + } + }); + + protocol.registerClientbound(ClientboundPackets1_20_5.JOIN_GAME, new PacketHandlers() { + @Override + public void register() { + map(Type.INT); // Entity id + map(Type.BOOLEAN); // Hardcore + map(Type.STRING_ARRAY); // World List + map(Type.VAR_INT); // Max players + map(Type.VAR_INT); // View distance + map(Type.VAR_INT); // Simulation distance + map(Type.BOOLEAN); // Reduced debug info + map(Type.BOOLEAN); // Show death screen + map(Type.BOOLEAN); // Limited crafting + map(Type.VAR_INT); // Dimension key + map(Type.STRING); // World + handler(worldDataTrackerHandlerByKey1_20_5(3)); + } + }); + + protocol.registerClientbound(ClientboundPackets1_20_5.RESPAWN, wrapper -> { + final int dimensionId = wrapper.passthrough(Type.VAR_INT); + final String world = wrapper.passthrough(Type.STRING); + trackWorldDataByKey1_20_5(wrapper.user(), dimensionId, world); // Tracks world height and name for chunk data and entity (un)tracking + }); + } + + private int[] paintingMappingsForEntries(final RegistryEntry[] entries) { + final int[] mappings = new int[entries.length]; + for (int i = 0; i < entries.length; i++) { + final RegistryEntry entry = entries[i]; + final PaintingData paintingData = oldPaintings.get(Key.stripMinecraftNamespace(entry.key())); + if (paintingData != null) { + mappings[i] = paintingData.id; + continue; + } + + // Figure out which works by size + if (entry.tag() == null) { + continue; + } + + final CompoundTag tag = (CompoundTag) entry.tag(); + for (int j = 0; j < Paintings1_20_5.PAINTINGS.length; j++) { + final Paintings1_20_5.PaintingVariant painting = Paintings1_20_5.PAINTINGS[j]; + if (painting.width() == tag.getInt("width") && painting.height() == tag.getInt("height")) { + mappings[i] = j; + break; + } + } + } + return mappings; + } + + @Override + protected void registerRewrites() { + filter().mapMetaType(Types1_20_5.META_TYPES::byId); + + registerMetaTypeHandler1_20_3( + Types1_20_5.META_TYPES.itemType, + Types1_20_5.META_TYPES.blockStateType, + Types1_20_5.META_TYPES.optionalBlockStateType, + Types1_20_5.META_TYPES.particleType, + Types1_20_5.META_TYPES.particlesType, + Types1_20_5.META_TYPES.componentType, + Types1_20_5.META_TYPES.optionalComponentType + ); + + filter().metaType(Types1_20_5.META_TYPES.paintingVariantType).handler((event, meta) -> { + final EnchantmentsPaintingsStorage storage = event.user().get(EnchantmentsPaintingsStorage.class); + final int id = meta.value(); + meta.setValue(storage.mappedPainting(id)); + }); + + filter().type(EntityTypes1_20_5.MINECART_ABSTRACT).index(11).handler((event, meta) -> { + final int blockState = meta.value(); + meta.setValue(protocol.getMappingData().getNewBlockStateId(blockState)); + }); + } + + @Override + public EntityType typeFromId(final int type) { + return EntityTypes1_20_5.getTypeFromId(type); + } + + private static final class PaintingData { + private final Paintings1_20_5.PaintingVariant painting; + private final int id; + + private PaintingData(final Paintings1_20_5.PaintingVariant painting, final int id) { + this.painting = painting; + this.id = id; + } + } +} \ No newline at end of file diff --git a/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_5to1_21/storage/EnchantmentsPaintingsStorage.java b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_5to1_21/storage/EnchantmentsPaintingsStorage.java new file mode 100644 index 00000000..94a01ed3 --- /dev/null +++ b/common/src/main/java/com/viaversion/viabackwards/protocol/protocol1_20_5to1_21/storage/EnchantmentsPaintingsStorage.java @@ -0,0 +1,61 @@ +/* + * This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards + * Copyright (C) 2016-2024 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.viabackwards.protocol.protocol1_20_5to1_21.storage; + +import com.viaversion.viaversion.api.connection.StorableObject; +import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag; +import com.viaversion.viaversion.util.KeyMappings; +import org.checkerframework.checker.nullness.qual.Nullable; + +public final class EnchantmentsPaintingsStorage implements StorableObject { + private KeyMappings enchantments; + private KeyMappings paintings; + private int[] paintingMappings; + private Tag[] enchantmentDescriptions; + + public KeyMappings enchantments() { + return enchantments; + } + + public void setEnchantments(final KeyMappings enchantment, final Tag[] enchantmentDescriptions) { + this.enchantments = enchantment; + this.enchantmentDescriptions = enchantmentDescriptions; + } + + public KeyMappings paintings() { + return paintings; + } + + public void setPaintings(final KeyMappings paintings, final int[] paintingMappings) { + this.paintings = paintings; + this.paintingMappings = paintingMappings; + } + + @Override + public boolean clearOnServerSwitch() { + return false; + } + + public int mappedPainting(final int id) { + return id > 0 && id < paintingMappings.length ? paintingMappings[id] : 0; + } + + public @Nullable Tag enchantmentDescription(final int id) { + return id > 0 && id < enchantmentDescriptions.length ? enchantmentDescriptions[id] : null; + } +} diff --git a/common/src/main/java/com/viaversion/viabackwards/protocol/v1_20_5to1_20_3/rewriter/BlockItemPacketRewriter1_20_5.java b/common/src/main/java/com/viaversion/viabackwards/protocol/v1_20_5to1_20_3/rewriter/BlockItemPacketRewriter1_20_5.java index 52ab1714..84e6de54 100644 --- a/common/src/main/java/com/viaversion/viabackwards/protocol/v1_20_5to1_20_3/rewriter/BlockItemPacketRewriter1_20_5.java +++ b/common/src/main/java/com/viaversion/viabackwards/protocol/v1_20_5to1_20_3/rewriter/BlockItemPacketRewriter1_20_5.java @@ -23,6 +23,7 @@ import com.viaversion.nbt.tag.ListTag; import com.viaversion.nbt.tag.StringTag; import com.viaversion.nbt.tag.Tag; import com.viaversion.viabackwards.api.rewriters.BackwardsStructuredItemRewriter; +import com.viaversion.viabackwards.api.rewriters.StructuredEnchantmentRewriter; import com.viaversion.viabackwards.protocol.v1_20_5to1_20_3.Protocol1_20_5To1_20_3; import com.viaversion.viaversion.api.Via; import com.viaversion.viaversion.api.connection.UserConnection; @@ -53,6 +54,7 @@ public final class BlockItemPacketRewriter1_20_5 extends BackwardsStructuredItem private static final StructuredDataConverter DATA_CONVERTER = new StructuredDataConverter(true); private final Protocol1_20_3To1_20_5 vvProtocol = Via.getManager().getProtocolManager().getProtocol(Protocol1_20_3To1_20_5.class); + private final StructuredEnchantmentRewriter enchantmentRewriter = new StructuredEnchantmentRewriter(this); public BlockItemPacketRewriter1_20_5(final Protocol1_20_5To1_20_3 protocol) { super(protocol, Types1_20_5.ITEM, Types1_20_5.ITEM_ARRAY, Types.ITEM1_20_2, Types.ITEM1_20_2_ARRAY); @@ -329,6 +331,9 @@ public final class BlockItemPacketRewriter1_20_5 extends BackwardsStructuredItem return null; } + item.structuredData().setIdLookup(protocol, true); + enchantmentRewriter.handleToClient(item); + super.handleItemToClient(connection, item); // In 1.20.6, some items have default values which are not written into the components @@ -354,6 +359,10 @@ public final class BlockItemPacketRewriter1_20_5 extends BackwardsStructuredItem // Convert to structured item first final Item structuredItem = vvProtocol.getItemRewriter().toStructuredItem(connection, item); + + item.structuredData().setIdLookup(protocol, false); + enchantmentRewriter.handleToServer(item); + return super.handleItemToServer(connection, structuredItem); } } \ No newline at end of file diff --git a/common/src/main/resources/assets/viabackwards/data/mappings-1.21to1.20.5.nbt b/common/src/main/resources/assets/viabackwards/data/mappings-1.21to1.20.5.nbt new file mode 100644 index 0000000000000000000000000000000000000000..d108819b0907f238a84a48f01c40edd16fbee4ca GIT binary patch literal 794 zcmaKq+e*Vg5Qe8s4{7SLRz(mj)C;`{wBq5yD-{Gm5PX2JO%}V@WJ7j)(8mxJyc2y; z{c~t3ZFR{9!_2?`W@gtSGN?S@krFZ>qMSw5PEWdzN;A!sL6*Ig0lFH35qO%o|4c0u25`5S){*G+=Ub(%JrJ)P$O8kQ6Doqz z*covdn4khIPz6h18LWU+ur{S%k7ML&U?Yp`h&RWYBxg}2o^rr^u1qSlTBmK=ZrSZt zDa+qe?SZCpm2X&I&UBWnIpZycn1F68Ji(Vm^q&aCz>;;smV%i}2}caWXEpF9s6 zV`Du>g=`q`$ddM4HUcn*$- dIoNJGhxi_L=hIG_>PWl}lj>7~aMCm8{|l|5 createPacketTypesProvider() { + return new SimplePacketTypesProvider<>( + packetTypeMap(unmappedClientboundPacketType, ClientboundPackets1_20_5.class, ClientboundConfigurationPackets1_20_5.class), + packetTypeMap(mappedClientboundPacketType, ClientboundPackets1_20_5.class, ClientboundConfigurationPackets1_20_5.class), + packetTypeMap(mappedServerboundPacketType, ServerboundPackets1_20_5.class, ServerboundConfigurationPackets1_20_5.class), + packetTypeMap(unmappedServerboundPacketType, ServerboundPackets1_20_5.class, ServerboundConfigurationPackets1_20_5.class) + ); + } } \ No newline at end of file diff --git a/template/src/main/java/com/viaversion/viabackwards/template/protocol/rewriter/EntityPacketRewriter1_99.java b/template/src/main/java/com/viaversion/viabackwards/template/protocol/rewriter/EntityPacketRewriter1_99.java index 5b017354..ba784c6b 100644 --- a/template/src/main/java/com/viaversion/viabackwards/template/protocol/rewriter/EntityPacketRewriter1_99.java +++ b/template/src/main/java/com/viaversion/viabackwards/template/protocol/rewriter/EntityPacketRewriter1_99.java @@ -19,9 +19,9 @@ package com.viaversion.viabackwards.template.protocol.rewriter; import com.viaversion.viabackwards.api.rewriters.EntityRewriter; import com.viaversion.viabackwards.template.protocol.Protocol1_98To1_99; +import com.viaversion.viaversion.api.minecraft.RegistryEntry; import com.viaversion.viaversion.api.minecraft.entities.EntityType; import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_20_5; -import com.viaversion.viaversion.api.protocol.packet.State; import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.types.version.Types1_20_5; @@ -45,13 +45,10 @@ public final class EntityPacketRewriter1_99 extends EntityRewriter { + final String registryKey = Key.stripMinecraftNamespace(wrapper.passthrough(Types.STRING)); + final RegistryEntry[] entries = wrapper.passthrough(Types.REGISTRY_ENTRY_ARRAY); + handleRegistryData1_20_5(wrapper.user(), registryKey, entries); // Caches dimensions to access data like height later and tracks the amount of biomes sent for chunk data }); protocol.registerClientbound(ClientboundPackets1_20_5.LOGIN, new PacketHandlers() { @@ -72,13 +69,10 @@ public final class EntityPacketRewriter1_99 extends EntityRewriter { + final int dimensionId = wrapper.passthrough(Types.VAR_INT); + final String world = wrapper.passthrough(Types.STRING); + trackWorldDataByKey1_20_5(wrapper.user(), dimensionId, world); // Tracks world height and name for chunk data and entity (un)tracking }); } @@ -100,7 +94,8 @@ public final class EntityPacketRewriter1_99 extends EntityRewriter