From 4bfdb843bbe99661040709f67970341260357bd5 Mon Sep 17 00:00:00 2001 From: RoccoDev Date: Tue, 20 Oct 2026 08:18:59 +0200 Subject: [PATCH 1/2] Properly handle equipment updates in containers --- .../protocol/v1_9to1_8/Protocol1_9To1_8.java | 11 +-- .../rewriter/BlockItemPacketRewriter1_9.java | 20 ++++++ .../rewriter/EntityPacketRewriter1_9.java | 25 ++++--- .../storage/ContainerEquipmentTracker.java | 67 +++++++++++++++++++ 4 files changed, 106 insertions(+), 17 deletions(-) create mode 100644 common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/storage/ContainerEquipmentTracker.java diff --git a/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/Protocol1_9To1_8.java b/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/Protocol1_9To1_8.java index 9777e996f..3194e34a4 100644 --- a/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/Protocol1_9To1_8.java +++ b/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/Protocol1_9To1_8.java @@ -24,15 +24,7 @@ import com.viaversion.viarewind.protocol.v1_9to1_8.rewriter.EntityPacketRewriter1_9; import com.viaversion.viarewind.protocol.v1_9to1_8.rewriter.PlayerPacketRewriter1_9; import com.viaversion.viarewind.protocol.v1_9to1_8.rewriter.WorldPacketRewriter1_9; -import com.viaversion.viarewind.protocol.v1_9to1_8.storage.BlockPlaceDestroyTracker; -import com.viaversion.viarewind.protocol.v1_9to1_8.storage.BossBarStorage; -import com.viaversion.viarewind.protocol.v1_9to1_8.storage.CommandBlockStateStorage; -import com.viaversion.viarewind.protocol.v1_9to1_8.storage.CooldownStorage; -import com.viaversion.viarewind.protocol.v1_9to1_8.storage.EntityTracker1_9; -import com.viaversion.viarewind.protocol.v1_9to1_8.storage.LevitationStorage; -import com.viaversion.viarewind.protocol.v1_9to1_8.storage.PlayerPositionTracker; -import com.viaversion.viarewind.protocol.v1_9to1_8.storage.LastTitle; -import com.viaversion.viarewind.protocol.v1_9to1_8.storage.WindowTracker; +import com.viaversion.viarewind.protocol.v1_9to1_8.storage.*; import com.viaversion.viarewind.protocol.v1_9to1_8.task.CooldownIndicatorTask; import com.viaversion.viarewind.protocol.v1_9to1_8.task.LevitationUpdateTask; import com.viaversion.viaversion.api.Via; @@ -95,6 +87,7 @@ public void init(UserConnection connection) { connection.put(new BlockPlaceDestroyTracker()); connection.put(new BossBarStorage(connection)); connection.put(new CommandBlockStateStorage()); + connection.put(new ContainerEquipmentTracker()); } @Override diff --git a/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/rewriter/BlockItemPacketRewriter1_9.java b/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/rewriter/BlockItemPacketRewriter1_9.java index 2b38afde6..29257cf8f 100644 --- a/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/rewriter/BlockItemPacketRewriter1_9.java +++ b/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/rewriter/BlockItemPacketRewriter1_9.java @@ -28,6 +28,7 @@ import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8; import com.viaversion.viarewind.protocol.v1_9to1_8.data.PotionIdMappings1_8; import com.viaversion.viarewind.protocol.v1_9to1_8.storage.CommandBlockStateStorage; +import com.viaversion.viarewind.protocol.v1_9to1_8.storage.ContainerEquipmentTracker; import com.viaversion.viarewind.protocol.v1_9to1_8.storage.WindowTracker; import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.minecraft.BlockChangeRecord; @@ -95,6 +96,11 @@ protected void registerPackets() { tracker.clearEnchantmentProperties(); } tracker.remove(windowId); + + if (windowId != 0) { + final ContainerEquipmentTracker equipment = wrapper.user().get(ContainerEquipmentTracker.class); + equipment.sendAll(wrapper.user()); + } }); protocol.registerClientbound(ClientboundPackets1_9.OPEN_SCREEN, wrapper -> { @@ -116,6 +122,11 @@ protected void registerPackets() { items[i] = handleItemToClient(wrapper.user(), items[i]); } + if (windowId == 0) { + // 1.8 clients handle it fine even when another container is open, clear equipment to send + wrapper.user().get(ContainerEquipmentTracker.class).invalidate(); + } + if (windowId == 0 && items.length == 46) { Item[] old = items; items = new Item[45]; @@ -154,6 +165,10 @@ protected void registerPackets() { } else if (slot >= 9 && slot <= 35) { containerSlot = size + slot - 9; } else { // armor/offhand: no slot in a foreign container + if (slot <= 39) { + final ContainerEquipmentTracker equipment = wrapper.user().get(ContainerEquipmentTracker.class); + equipment.setEquipment(39 - slot, item); + } wrapper.cancel(); return; } @@ -201,6 +216,11 @@ protected void registerPackets() { protocol.registerServerbound(ServerboundPackets1_8.CONTAINER_CLOSE, wrapper -> { final byte windowId = wrapper.passthrough(Types.BYTE); wrapper.user().get(WindowTracker.class).remove(windowId); + + if (windowId != 0) { + final ContainerEquipmentTracker equipment = wrapper.user().get(ContainerEquipmentTracker.class); + equipment.sendAll(wrapper.user()); + } }); protocol.registerServerbound(ServerboundPackets1_8.CONTAINER_CLICK, new PacketHandlers() { 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 40a0e40ed..2c529c5ae 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 @@ -21,10 +21,7 @@ import com.viaversion.viarewind.api.rewriter.VREntityRewriter; import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8; import com.viaversion.viarewind.protocol.v1_9to1_8.data.EntityDataIndex1_8; -import com.viaversion.viarewind.protocol.v1_9to1_8.storage.CooldownStorage; -import com.viaversion.viarewind.protocol.v1_9to1_8.storage.EntityTracker1_9; -import com.viaversion.viarewind.protocol.v1_9to1_8.storage.LevitationStorage; -import com.viaversion.viarewind.protocol.v1_9to1_8.storage.PlayerPositionTracker; +import com.viaversion.viarewind.protocol.v1_9to1_8.storage.*; import com.viaversion.viaversion.api.minecraft.BlockPosition; import com.viaversion.viaversion.api.minecraft.ClientWorld; import com.viaversion.viaversion.api.minecraft.EulerAngle; @@ -412,11 +409,8 @@ public void register() { public void register() { map(Types.VAR_INT); // Entity id handler(wrapper -> { - // 1.8 clients write their own equipment to armorInventory[slot] without the -1 offset, - // shifting armor up one slot; the window 0 set slot packets already carry it. - final int entityId = wrapper.get(Types.VAR_INT, 0); int slot = wrapper.read(Types.VAR_INT); - if (slot == 1 || entityId == wrapper.user().getEntityTracker(protocol).clientEntityId()) { + if (slot == 1) { wrapper.cancel(); } else if (slot > 1) { slot -= 1; @@ -425,6 +419,21 @@ public void register() { }); map(Types.ITEM1_8); // Item handler(wrapper -> protocol.getItemRewriter().handleItemToClient(wrapper.user(), wrapper.get(Types.ITEM1_8, 0))); + handler(wrapper -> { + if (wrapper.get(Types.VAR_INT, 0) == tracker(wrapper.user()).clientEntityId()) { + // Vanilla 1.8.9 doesn't properly handle this and Forge handles it differently, use set + // slot packets instead + final Item item = wrapper.get(Types.ITEM1_8, 0); + final int slot = 4 - wrapper.get(Types.SHORT, 0); + wrapper.cancel(); + final ContainerEquipmentTracker equipment = wrapper.user().get(ContainerEquipmentTracker.class); + final WindowTracker window = wrapper.user().get(WindowTracker.class); + equipment.setEquipment(slot, item); + if (window.openWindowId() == 0) { + equipment.sendAsSlot(wrapper.user(), slot); + } + } + }); } }); diff --git a/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/storage/ContainerEquipmentTracker.java b/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/storage/ContainerEquipmentTracker.java new file mode 100644 index 000000000..7538b453d --- /dev/null +++ b/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/storage/ContainerEquipmentTracker.java @@ -0,0 +1,67 @@ +/* + * This file is part of ViaRewind - https://github.com/ViaVersion/ViaRewind + * Copyright (C) 2018-2026 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.viarewind.protocol.v1_9to1_8.storage; + +import com.viaversion.viarewind.protocol.v1_9to1_8.Protocol1_9To1_8; +import com.viaversion.viaversion.api.connection.StorableObject; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.minecraft.item.Item; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; +import com.viaversion.viaversion.api.type.Types; +import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8; + +import java.util.Arrays; + +/** + * Tracks equipment changes while a foreign container is open. + */ +public class ContainerEquipmentTracker implements StorableObject { + // 0: helmet, 3: boots + private final Slot[] equipment = new Slot[4]; + + public void setEquipment(final int slot, final Item item) { + equipment[slot] = new Slot(item); + } + + public void sendAsSlot(final UserConnection connection, final int slot) { + if (equipment[slot] == null) { + // needs no update + return; + } + + final PacketWrapper setSlot = PacketWrapper.create(ClientboundPackets1_8.CONTAINER_SET_SLOT, connection); + setSlot.write(Types.BYTE, (byte) 0); + setSlot.write(Types.SHORT, (short) (5 + slot)); + setSlot.write(Types.ITEM1_8, equipment[slot].item); + setSlot.send(Protocol1_9To1_8.class); + + equipment[slot] = null; + } + + public void sendAll(UserConnection connection) { + for (int slot = 0; slot < equipment.length; slot++) { + sendAsSlot(connection, slot); + } + } + + public void invalidate() { + Arrays.fill(equipment, null); + } + + private record Slot(Item item) {} +} From 70ac8838eff10b83fff97cbd916cbdde3b5a414f Mon Sep 17 00:00:00 2001 From: RoccoDev Date: Tue, 20 Oct 2026 08:38:53 +0200 Subject: [PATCH 2/2] Properly handle undersized window items --- .../v1_9to1_8/rewriter/BlockItemPacketRewriter1_9.java | 4 ++-- .../protocol/v1_9to1_8/storage/ContainerEquipmentTracker.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/rewriter/BlockItemPacketRewriter1_9.java b/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/rewriter/BlockItemPacketRewriter1_9.java index 29257cf8f..e76b4a095 100644 --- a/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/rewriter/BlockItemPacketRewriter1_9.java +++ b/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/rewriter/BlockItemPacketRewriter1_9.java @@ -122,9 +122,9 @@ protected void registerPackets() { items[i] = handleItemToClient(wrapper.user(), items[i]); } - if (windowId == 0) { + if (windowId == 0 && items.length > 5) { // 1.8 clients handle it fine even when another container is open, clear equipment to send - wrapper.user().get(ContainerEquipmentTracker.class).invalidate(); + wrapper.user().get(ContainerEquipmentTracker.class).invalidate(items.length - 5); } if (windowId == 0 && items.length == 46) { diff --git a/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/storage/ContainerEquipmentTracker.java b/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/storage/ContainerEquipmentTracker.java index 7538b453d..92798b180 100644 --- a/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/storage/ContainerEquipmentTracker.java +++ b/common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/storage/ContainerEquipmentTracker.java @@ -59,8 +59,8 @@ public void sendAll(UserConnection connection) { } } - public void invalidate() { - Arrays.fill(equipment, null); + public void invalidate(int count) { + Arrays.fill(equipment, 0, Math.min(count, equipment.length), null); } private record Slot(Item item) {}