Skip to content

Commit 63afb2d

Browse files
Fix inventory desync for <1.17 clients on 1.17+ servers (#1243)
1 parent 827c00f commit 63afb2d

File tree

2 files changed

+32
-3
lines changed

2 files changed

+32
-3
lines changed

common/src/main/java/com/viaversion/viabackwards/protocol/v1_17_1to1_17/Protocol1_17_1To1_17.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ protected void registerPackets() {
7171
// Length is encoded as a var int in 1.17.1
7272
wrapper.write(Types.ITEM1_13_2_SHORT_ARRAY, wrapper.read(Types.ITEM1_13_2_ARRAY));
7373

74-
// Carried item - should work without adding it to the array above
74+
// Carried item - forward as CONTAINER_SET_SLOT for <1.17 clients
7575
Item carried = wrapper.read(Types.ITEM1_13_2);
7676

7777
PlayerLastCursorItem lastCursorItem = wrapper.user().get(PlayerLastCursorItem.class);
@@ -82,6 +82,16 @@ protected void registerPackets() {
8282
// for a subsequent drag
8383

8484
lastCursorItem.setLastCursorItem(carried);
85+
86+
// In 1.17.1+, the carried/cursor item is part of CONTAINER_SET_CONTENT,
87+
// but <1.17 clients don't have this field. Send it as a separate
88+
// CONTAINER_SET_SLOT packet so the client's cursor state is properly synced.
89+
// This fixes inventory desyncs when the server cancels InventoryClickEvents.
90+
PacketWrapper cursorPacket = wrapper.create(ClientboundPackets1_17.CONTAINER_SET_SLOT);
91+
cursorPacket.write(Types.BYTE, (byte) -1); // Window ID: -1 for cursor
92+
cursorPacket.write(Types.SHORT, (short) -1); // Slot: -1 for cursor
93+
cursorPacket.write(Types.ITEM1_13_2, carried);
94+
cursorPacket.send(Protocol1_17_1To1_17.class);
8595
}
8696
});
8797

common/src/main/java/com/viaversion/viabackwards/protocol/v1_17to1_16_4/rewriter/BlockItemPacketRewriter1_17.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.viaversion.viabackwards.api.rewriters.MapColorRewriter;
2727
import com.viaversion.viabackwards.protocol.v1_17to1_16_4.Protocol1_17To1_16_4;
2828
import com.viaversion.viabackwards.protocol.v1_17to1_16_4.data.MapColorMappings1_16_4;
29+
import com.viaversion.viabackwards.protocol.v1_17_1to1_17.storage.InventoryStateIds;
2930
import com.viaversion.viabackwards.protocol.v1_17to1_16_4.storage.PlayerLastCursorItem;
3031
import com.viaversion.viaversion.api.data.entity.EntityTracker;
3132
import com.viaversion.viaversion.api.minecraft.BlockChangeRecord;
@@ -83,8 +84,26 @@ public void register() {
8384
int mode = wrapper.passthrough(Types.VAR_INT); // Mode
8485
Item clicked = handleItemToServer(wrapper.user(), wrapper.read(Types.ITEM1_13_2)); // Clicked item
8586

86-
// The 1.17 client would check the entire inventory for changes before -> after a click and send the changed slots here
87-
wrapper.write(Types.VAR_INT, 0); // Empty array of slot+item
87+
// The 1.17 client would check the entire inventory for changes before -> after a click
88+
// and send the changed slots here. We include the clicked slot so the server
89+
// detects any desync (e.g. cancelled InventoryClickEvent) and sends corrections.
90+
if (slot >= 0 && clicked != null) {
91+
wrapper.write(Types.VAR_INT, 1); // One modified slot
92+
wrapper.write(Types.SHORT, slot); // The clicked slot
93+
wrapper.write(Types.ITEM1_13_2, (Item) null); // Predicted: empty (item picked up)
94+
} else {
95+
wrapper.write(Types.VAR_INT, 0); // Empty array of slot+item
96+
}
97+
98+
// Non-PICKUP modes (shift-click, swap, throw, drag, etc.) affect multiple slots
99+
// that we can't easily predict. Force a state ID mismatch so the server
100+
// sends a full inventory resync instead of individual slot corrections.
101+
if (mode != 0) {
102+
InventoryStateIds stateIds = wrapper.user().get(InventoryStateIds.class);
103+
if (stateIds != null) {
104+
stateIds.setStateId(wrapper.get(Types.BYTE, 0), -1);
105+
}
106+
}
88107

89108
PlayerLastCursorItem state = wrapper.user().get(PlayerLastCursorItem.class);
90109
if (mode == 0 && button == 0 && clicked != null) {

0 commit comments

Comments
 (0)