diff --git a/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/rewriter/EntityPacketRewriter1_9.java b/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/rewriter/EntityPacketRewriter1_9.java index 39da66209..abc4b4398 100644 --- a/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/rewriter/EntityPacketRewriter1_9.java +++ b/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/rewriter/EntityPacketRewriter1_9.java @@ -45,6 +45,7 @@ import com.viaversion.viaversion.rewriter.entitydata.EntityDataHandlerEvent; import com.viaversion.viaversion.util.IdAndData; import com.viaversion.viaversion.util.Pair; + import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -230,6 +231,65 @@ public void register() { handler(wrapper -> { final int entityId = wrapper.get(Types.VAR_INT, 0); wrapper.user().getEntityTracker(protocol).addEntity(entityId, EntityTypes1_9.EntityType.PAINTING); + + final BlockPosition position = wrapper.get(Types.BLOCK_POSITION1_8, 0); + short dir = wrapper.get(Types.UNSIGNED_BYTE, 0); + double width = 0, height = 0; + switch (wrapper.get(Types.STRING, 0)) { + case "Kebab", "Aztec", "Alban", "Aztec2", "Bomb", "Plant", "Wasteland" -> { + width = 16; + height = 16; + } + case "Pool", "Courbet", "Sea", "Sunset", "Creebet" -> { + width = 32; + height = 16; + } + case "Wanderer", "Graham" -> { + width = 16; + height = 32; + } + case "Match", "Bust", "Stage", "Void", "SkullAndRoses", "Wither" -> { + width = 32; + height = 32; + } + case "Fighters" -> { + width = 64; + height = 32; + } + case "Pointer", "Pigscene", "BurningSkull" -> { + width = 64; + height = 64; + } + case "Skeleton", "DonkeyKong" -> { + width = 64; + height = 48; + } + } + + // Calculate painting entity coords + double resX = position.x() + 0.5, resY = position.y() + 0.5, resZ = position.z() + 0.5; + double againstWall = -0.46875; + switch (dir) { + case 2 -> resZ -= againstWall; // North -z + case 0 -> resZ += againstWall; // South +z + case 1 -> resX -= againstWall; // West -x + case 3 -> resX += againstWall; // East +x + } + + double horizontalOffset = width % 32 == 0 ? 0.5 : 0.0; + double verticalOffset = height % 32 == 0 ? 0.5 : 0.0; + resY += verticalOffset; + switch (dir) { + case 3 -> resZ -= horizontalOffset; // East -> North -z + case 1 -> resZ += horizontalOffset; // West -> South +z + case 2 -> resX -= horizontalOffset; // North -> West -x + case 0 -> resX += horizontalOffset; // South -> East +x + } + + // Can't use the position from the spawn packet here, the same-block teleport bug + // depends on the entity coordinates + wrapper.user().getEntityTracker(protocol).getPaintings().put(entityId, + new BlockPosition((int) Math.floor(resX), (int) Math.floor(resY), (int) Math.floor(resZ))); }); } }); @@ -505,6 +565,20 @@ public void register() { y += 6; wrapper.set(Types.INT, 1, y); } + + if (tracker.entityType(entityId) == EntityTypes1_9.EntityType.PAINTING) { + // Paintings break in 1.8 if teleported to the same block + final BlockPosition storedPos = tracker.getPaintings().get(entityId); + final int newX = Math.floorDiv(wrapper.get(Types.INT, 0), 32); + final int newY = Math.floorDiv(wrapper.get(Types.INT, 1), 32); + final int newZ = Math.floorDiv(wrapper.get(Types.INT, 2), 32); + if (storedPos != null && newX == storedPos.x() && newY == storedPos.y() && newZ == storedPos.z()) { + wrapper.cancel(); + } else { + tracker.getPaintings().put(entityId, new BlockPosition(newX, newY, newZ)); + } + } + tracker.resetEntityOffset(entityId); }); } diff --git a/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/storage/EntityTracker1_9.java b/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/storage/EntityTracker1_9.java index 292d80f8e..9359de6e3 100644 --- a/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/storage/EntityTracker1_9.java +++ b/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/storage/EntityTracker1_9.java @@ -19,17 +19,12 @@ import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.data.entity.TrackedEntity; +import com.viaversion.viaversion.api.minecraft.BlockPosition; import com.viaversion.viaversion.api.minecraft.Vector; import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_9; import com.viaversion.viaversion.data.entity.EntityTrackerBase; -import com.viaversion.viaversion.libs.fastutil.ints.Int2IntMap; -import com.viaversion.viaversion.libs.fastutil.ints.Int2IntOpenHashMap; -import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectMap; -import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectOpenHashMap; -import com.viaversion.viaversion.libs.fastutil.ints.IntArrayList; -import com.viaversion.viaversion.libs.fastutil.ints.IntList; -import com.viaversion.viaversion.libs.fastutil.ints.IntOpenHashSet; -import com.viaversion.viaversion.libs.fastutil.ints.IntSet; +import com.viaversion.viaversion.libs.fastutil.ints.*; + import java.util.List; import java.util.Map; @@ -40,6 +35,7 @@ public class EntityTracker1_9 extends EntityTrackerBase { private final Int2IntMap status = new Int2IntOpenHashMap(); private final IntSet handActive = new IntOpenHashSet(); private final Int2ObjectMap pendingPotions = new Int2ObjectOpenHashMap<>(); + private final Int2ObjectMap paintings = new Int2ObjectOpenHashMap<>(); public EntityTracker1_9(UserConnection connection) { super(connection, EntityTypes1_9.EntityType.PLAYER); @@ -52,6 +48,7 @@ public TrackedEntity removeEntity(int id) { status.remove(id); handActive.remove(id); pendingPotions.remove(id); + paintings.remove(id); vehicles.forEach((vehicle, passengers) -> passengers.rem(id)); vehicles.int2ObjectEntrySet().removeIf(entry -> entry.getValue().isEmpty()); @@ -112,6 +109,10 @@ public Int2ObjectMap getPendingPotions() { return pendingPotions; } + public Int2ObjectMap getPaintings() { + return paintings; + } + public record PendingPotionEntity(int x, int y, int z, byte pitch, byte yaw, short velocityX, short velocityY, short velocityZ) { public PendingPotionEntity withPosition(final int x, final int y, final int z, final byte pitch, final byte yaw) {