diff --git a/common/src/main/java/com/viaversion/viabackwards/protocol/v1_19_4to1_19_3/Protocol1_19_4To1_19_3.java b/common/src/main/java/com/viaversion/viabackwards/protocol/v1_19_4to1_19_3/Protocol1_19_4To1_19_3.java index 739242cbb..8b380b21e 100644 --- a/common/src/main/java/com/viaversion/viabackwards/protocol/v1_19_4to1_19_3/Protocol1_19_4To1_19_3.java +++ b/common/src/main/java/com/viaversion/viabackwards/protocol/v1_19_4to1_19_3/Protocol1_19_4To1_19_3.java @@ -24,10 +24,15 @@ import com.viaversion.viabackwards.protocol.v1_19_4to1_19_3.rewriter.ComponentRewriter1_19_4; import com.viaversion.viabackwards.protocol.v1_19_4to1_19_3.rewriter.EntityPacketRewriter1_19_4; import com.viaversion.viabackwards.protocol.v1_19_4to1_19_3.storage.EntityTracker1_19_4; +import com.viaversion.viabackwards.protocol.v1_19_4to1_19_3.storage.LinkedEntityStorage; +import com.viaversion.viabackwards.protocol.v1_21to1_20_5.storage.EnchantmentsPaintingsStorage; import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_19_4; +import com.viaversion.viaversion.api.minecraft.entitydata.EntityData; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_18; +import com.viaversion.viaversion.api.type.types.version.Types1_19_3; import com.viaversion.viaversion.libs.gson.JsonElement; import com.viaversion.viaversion.protocols.v1_19_1to1_19_3.packet.ClientboundPackets1_19_3; import com.viaversion.viaversion.protocols.v1_19_1to1_19_3.packet.ServerboundPackets1_19_3; @@ -38,7 +43,10 @@ import com.viaversion.viaversion.rewriter.CommandRewriter; import com.viaversion.viaversion.rewriter.ParticleRewriter; import com.viaversion.viaversion.rewriter.TagRewriter; + +import java.util.ArrayList; import java.util.Base64; +import java.util.List; public final class Protocol1_19_4To1_19_3 extends BackwardsProtocol { @@ -87,7 +95,33 @@ public void handleArgument(final PacketWrapper wrapper, final String argumentTyp wrapper.write(Types.OPTIONAL_STRING, iconBase64); }); - cancelClientbound(ClientboundPackets1_19_4.BUNDLE_DELIMITER); + registerClientbound(ClientboundPackets1_19_4.BUNDLE_DELIMITER, null, wrapper -> { + // Bundles were introduced in 1.19.4 + wrapper.cancel(); + + // 1.19.3+ only sends non-default values, 1.19->1.18 protocol needs entity data to spawn paintings. + // In 1.19.4 we can detect this because add_entity + set_entity_data are always sent in a bundle + EntityTracker1_19_4 tracker = wrapper.user().getEntityTracker(this); + if (tracker.getSpawningPainting() != -1 && tracker.entityType(tracker.getSpawningPainting()) == EntityTypes1_19_4.PAINTING) { + final int paintingId = tracker.getSpawningPainting(); + final LinkedEntityStorage storage = tracker.linkedEntityStorage(paintingId); + if (storage != null && !storage.sentPaintingType()) { + // Use first type in registry as default, kebab (0) otherwise. + // kebab has been the default painting for most versions, 1.21+ uses alban instead but probably + // unintentionally (first in registry) + final EnchantmentsPaintingsStorage registry = wrapper.user().get(EnchantmentsPaintingsStorage.class); + final int defaultPainting = registry != null ? registry.mappedDefaultPainting() : 0; + final EntityData type = new EntityData(8, Types1_19_3.ENTITY_DATA_TYPES.paintingVariantType, defaultPainting); + + final PacketWrapper packet = PacketWrapper.create(ClientboundPackets1_19_3.SET_ENTITY_DATA, wrapper.user()); + packet.write(Types.VAR_INT, paintingId); + packet.write(Types1_19_3.ENTITY_DATA_LIST, List.of(type)); + packet.send(Protocol1_19_4To1_19_3.class); + } + } + tracker.setSpawningPainting(-1); + }); + cancelClientbound(ClientboundPackets1_19_4.CHUNKS_BIOMES); // We definitely do not want to cache every single chunk just to resent them with new biomes } diff --git a/common/src/main/java/com/viaversion/viabackwards/protocol/v1_19_4to1_19_3/rewriter/EntityPacketRewriter1_19_4.java b/common/src/main/java/com/viaversion/viabackwards/protocol/v1_19_4to1_19_3/rewriter/EntityPacketRewriter1_19_4.java index ce9beef0d..9d79990c6 100644 --- a/common/src/main/java/com/viaversion/viabackwards/protocol/v1_19_4to1_19_3/rewriter/EntityPacketRewriter1_19_4.java +++ b/common/src/main/java/com/viaversion/viabackwards/protocol/v1_19_4to1_19_3/rewriter/EntityPacketRewriter1_19_4.java @@ -105,6 +105,13 @@ public void register() { wrapper.set(Types.VAR_INT, 2, protocol.getMappingData().getNewBlockStateId(blockState)); } + final EntityTracker1_19_4 tracker = wrapper.user().getEntityTracker(protocol); + if (entity.entityType() == EntityTypes1_19_4.PAINTING) { + tracker.setSpawningPainting(entityId); + } else { + tracker.setSpawningPainting(-1); + } + final LinkedEntityStorage storage = new LinkedEntityStorage(); final double x = wrapper.get(Types.DOUBLE, 0); final double z = wrapper.get(Types.DOUBLE, 2); @@ -494,6 +501,14 @@ public void registerRewrites() { } }); + filter().type(EntityTypes1_19_4.PAINTING).index(8).handler((event, data) -> { + // Painting variant + final LinkedEntityStorage storage = event.trackedEntity().get(LinkedEntityStorage.class); + if (storage != null) { + storage.sentPaintingType(true); + } + }); + filter().type(EntityTypes1_19_4.INTERACTION).cancel(8); // Width filter().type(EntityTypes1_19_4.INTERACTION).cancel(9); // Height filter().type(EntityTypes1_19_4.INTERACTION).cancel(10); // Response diff --git a/common/src/main/java/com/viaversion/viabackwards/protocol/v1_19_4to1_19_3/storage/EntityTracker1_19_4.java b/common/src/main/java/com/viaversion/viabackwards/protocol/v1_19_4to1_19_3/storage/EntityTracker1_19_4.java index ba0952d21..35e132302 100644 --- a/common/src/main/java/com/viaversion/viabackwards/protocol/v1_19_4to1_19_3/storage/EntityTracker1_19_4.java +++ b/common/src/main/java/com/viaversion/viabackwards/protocol/v1_19_4to1_19_3/storage/EntityTracker1_19_4.java @@ -35,6 +35,7 @@ public final class EntityTracker1_19_4 extends EntityTrackerBase { private final IntSet generatedEntities = new IntOpenHashSet(); // Track entities spawned to prevent duplicated entity ids + private int spawningPainting = -1; public EntityTracker1_19_4(final UserConnection connection) { super(connection, EntityTypes1_19_4.PLAYER); @@ -62,6 +63,16 @@ public int spawnEntity(final EntityTypes1_19_3 entityType, final double x, final return entityId; } + + + public void setSpawningPainting(int spawningPainting) { + this.spawningPainting = spawningPainting; + } + + public int getSpawningPainting() { + return spawningPainting; + } + @Override public @Nullable TrackedEntity removeEntity(final int id) { final TrackedEntity entity = super.removeEntity(id); diff --git a/common/src/main/java/com/viaversion/viabackwards/protocol/v1_19_4to1_19_3/storage/LinkedEntityStorage.java b/common/src/main/java/com/viaversion/viabackwards/protocol/v1_19_4to1_19_3/storage/LinkedEntityStorage.java index 56bf7c672..baf496f94 100644 --- a/common/src/main/java/com/viaversion/viabackwards/protocol/v1_19_4to1_19_3/storage/LinkedEntityStorage.java +++ b/common/src/main/java/com/viaversion/viabackwards/protocol/v1_19_4to1_19_3/storage/LinkedEntityStorage.java @@ -31,6 +31,7 @@ public class LinkedEntityStorage extends EntityPositionStorage implements Storab private int[] entities; private int[] passengers; private Integer vehicleId; + private boolean sentPaintingType; public int @Nullable [] entities() { return entities; @@ -60,6 +61,14 @@ public void setVehicleId(@Nullable final Integer vehicleId) { this.vehicleId = vehicleId; } + public boolean sentPaintingType() { + return sentPaintingType; + } + + public void sentPaintingType(boolean sentPaintingType) { + this.sentPaintingType = sentPaintingType; + } + public void remove(final UserConnection connection) { final PacketWrapper wrapper = PacketWrapper.create(ClientboundPackets1_19_3.REMOVE_ENTITIES, connection); wrapper.write(Types.VAR_INT_ARRAY_PRIMITIVE, entities); diff --git a/common/src/main/java/com/viaversion/viabackwards/protocol/v1_21to1_20_5/storage/EnchantmentsPaintingsStorage.java b/common/src/main/java/com/viaversion/viabackwards/protocol/v1_21to1_20_5/storage/EnchantmentsPaintingsStorage.java index 6f98c3623..e0a2ead8c 100644 --- a/common/src/main/java/com/viaversion/viabackwards/protocol/v1_21to1_20_5/storage/EnchantmentsPaintingsStorage.java +++ b/common/src/main/java/com/viaversion/viabackwards/protocol/v1_21to1_20_5/storage/EnchantmentsPaintingsStorage.java @@ -58,7 +58,11 @@ public int jubeboxSongToItem(final int id) { } public int mappedPainting(final int id) { - return id > 0 && id < paintingMappings.length ? paintingMappings[id] : 0; + return id >= 0 && id < paintingMappings.length ? paintingMappings[id] : 0; + } + + public int mappedDefaultPainting() { + return mappedPainting(0); } public @Nullable Tag enchantmentDescription(final int id) {