From 4190c837d5814cc5e8f04ccaf1df4ca911b74e94 Mon Sep 17 00:00:00 2001 From: FlorianMichael Date: Sat, 17 Aug 2024 21:40:38 +0200 Subject: [PATCH] Emulate block and item display entities in 1.19.4->1.19.3 --- .../Protocol1_19_4To1_19_3.java | 7 +- .../rewriter/EntityPacketRewriter1_19_4.java | 30 +++++- .../storage/EntityTracker1_19_4.java | 102 ++++++++++++++++++ .../storage/LinkedEntityStorage.java | 36 +++++++ 4 files changed, 170 insertions(+), 5 deletions(-) create mode 100644 common/src/main/java/com/viaversion/viabackwards/protocol/v1_19_4to1_19_3/storage/EntityTracker1_19_4.java create mode 100644 common/src/main/java/com/viaversion/viabackwards/protocol/v1_19_4to1_19_3/storage/LinkedEntityStorage.java 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 2c0c4de3..8906a768 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 @@ -23,11 +23,10 @@ import com.viaversion.viabackwards.api.rewriters.SoundRewriter; import com.viaversion.viabackwards.api.rewriters.TranslatableRewriter; import com.viaversion.viabackwards.protocol.v1_19_4to1_19_3.rewriter.BlockItemPacketRewriter1_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.viaversion.api.connection.UserConnection; -import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_19_4; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.type.Types; -import com.viaversion.viaversion.data.entity.EntityTrackerBase; 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; @@ -110,7 +109,7 @@ public final class Protocol1_19_4To1_19_3 extends BackwardsProtocol getTagRewriter() { return tagRewriter; } -} \ No newline at end of file +} 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 eb985ca7..a733899d 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 @@ -23,9 +23,14 @@ import com.viaversion.nbt.tag.NumberTag; import com.viaversion.viabackwards.api.entities.storage.EntityReplacement; import com.viaversion.viabackwards.api.rewriters.EntityRewriter; import com.viaversion.viabackwards.protocol.v1_19_4to1_19_3.Protocol1_19_4To1_19_3; +import com.viaversion.viabackwards.protocol.v1_19_4to1_19_3.storage.LinkedEntityStorage; +import com.viaversion.viabackwards.protocol.v1_19_4to1_19_3.storage.EntityTracker1_19_4; import com.viaversion.viaversion.api.minecraft.entities.EntityType; +import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_19_3; import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_19_4; import com.viaversion.viaversion.api.minecraft.entitydata.EntityData; +import com.viaversion.viaversion.api.minecraft.item.Item; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.types.version.Types1_19_3; @@ -171,8 +176,31 @@ public final class EntityPacketRewriter1_19_4 extends EntityRewriter { + final int value = data.value(); + + final EntityTracker1_19_4 tracker = tracker(event.user()); + tracker.clearLinkedEntityStorage(event.entityId()); + + final int linkedEntity = tracker.spawnEntity(EntityTypes1_19_3.FALLING_BLOCK, value); + tracker.entityData(event.entityId()).put(new LinkedEntityStorage(linkedEntity)); + + final PacketWrapper wrapper = PacketWrapper.create(ClientboundPackets1_19_3.SET_PASSENGERS, event.user()); + wrapper.write(Types.VAR_INT, event.entityId()); // Entity id + wrapper.write(Types.VAR_INT_ARRAY_PRIMITIVE, new int[] { linkedEntity }); // Passenger entity ids + wrapper.send(Protocol1_19_4To1_19_3.class); + }); + filter().type(EntityTypes1_19_4.ITEM_DISPLAY).index(22).handler((event, data) -> { + final Item value = data.value(); + + final PacketWrapper setEquipment = PacketWrapper.create(ClientboundPackets1_19_3.SET_EQUIPMENT, event.user()); + setEquipment.write(Types.VAR_INT, event.entityId()); // Entity id + setEquipment.write(Types.BYTE, (byte) 5); // Slot - head + setEquipment.write(Types.ITEM1_13_2, value); + + setEquipment.send(Protocol1_19_4To1_19_3.class); + }); filter().type(EntityTypes1_19_4.DISPLAY).handler((event, data) -> { - // TODO Maybe spawn an extra entity to ride the armor stand for blocks and items // Remove a large heap of display entity data if (event.index() > 7) { event.cancel(); 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 new file mode 100644 index 00000000..4a97fc77 --- /dev/null +++ b/common/src/main/java/com/viaversion/viabackwards/protocol/v1_19_4to1_19_3/storage/EntityTracker1_19_4.java @@ -0,0 +1,102 @@ +/* + * 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.v1_19_4to1_19_3.storage; + +import com.viaversion.viabackwards.protocol.v1_19_4to1_19_3.Protocol1_19_4To1_19_3; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.data.entity.TrackedEntity; +import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_19_3; +import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_19_4; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; +import com.viaversion.viaversion.api.type.Types; +import com.viaversion.viaversion.data.entity.EntityTrackerBase; +import com.viaversion.viaversion.libs.fastutil.ints.IntArraySet; +import com.viaversion.viaversion.libs.fastutil.ints.IntSet; +import com.viaversion.viaversion.protocols.v1_19_1to1_19_3.packet.ClientboundPackets1_19_3; +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; + +public final class EntityTracker1_19_4 extends EntityTrackerBase { + + private final IntSet generatedEntities = new IntArraySet(); // Track entities spawned to prevent duplicated entity ids + + public EntityTracker1_19_4(final UserConnection connection) { + super(connection, EntityTypes1_19_4.PLAYER); + } + + public int spawnEntity(final EntityTypes1_19_3 entityType, final int data) { + final int entityId = nextEntityId(); + + final PacketWrapper addEntity = PacketWrapper.create(ClientboundPackets1_19_3.ADD_ENTITY, user()); + addEntity.write(Types.VAR_INT, entityId); // Entity id + addEntity.write(Types.UUID, UUID.randomUUID()); // Entity UUID + addEntity.write(Types.VAR_INT, entityType.getId()); // Entity type + addEntity.write(Types.DOUBLE, 0.0); // X + addEntity.write(Types.DOUBLE, 0.0); // Y + addEntity.write(Types.DOUBLE, 0.0); // Z + addEntity.write(Types.BYTE, (byte) 0); // Pitch + addEntity.write(Types.BYTE, (byte) 0); // Yaw + addEntity.write(Types.BYTE, (byte) 0); // Head yaw + addEntity.write(Types.VAR_INT, data); // Data + addEntity.write(Types.SHORT, (short) 0); // Velocity X + addEntity.write(Types.SHORT, (short) 0); // Velocity Y + addEntity.write(Types.SHORT, (short) 0); // Velocity Z + + addEntity.send(Protocol1_19_4To1_19_3.class); + + generatedEntities.add(entityId); + return entityId; + } + + + @Override + public void clearEntities() { + for (final Integer id : entities.keySet()) { + clearLinkedEntityStorage(id); + } + super.clearEntities(); + } + + @Override + public void removeEntity(final int id) { + clearLinkedEntityStorage(id); + super.removeEntity(id); + } + + public void clearLinkedEntityStorage(final int id) { + final TrackedEntity entity = entity(id); + if (!entity.hasData()) { + return; + } + + final LinkedEntityStorage storage = entity.data().get(LinkedEntityStorage.class); + if (storage != null) { + storage.remove(user()); + generatedEntities.remove(id); + } + } + + private int nextEntityId() { + final int entityId = -ThreadLocalRandom.current().nextInt(10_000); + if (generatedEntities.contains(entityId)) { + return nextEntityId(); + } + return entityId; + } + +} 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 new file mode 100644 index 00000000..231410c0 --- /dev/null +++ b/common/src/main/java/com/viaversion/viabackwards/protocol/v1_19_4to1_19_3/storage/LinkedEntityStorage.java @@ -0,0 +1,36 @@ +/* + * 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.v1_19_4to1_19_3.storage; + +import com.viaversion.viabackwards.protocol.v1_19_4to1_19_3.Protocol1_19_4To1_19_3; +import com.viaversion.viaversion.api.connection.StorableObject; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; +import com.viaversion.viaversion.api.type.Types; +import com.viaversion.viaversion.protocols.v1_19_1to1_19_3.packet.ClientboundPackets1_19_3; + +public record LinkedEntityStorage(int... entities) implements StorableObject { + + 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); + + wrapper.send(Protocol1_19_4To1_19_3.class); + } + +}