Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ protected void registerPackets() {
// Length is encoded as a var int in 1.17.1
wrapper.write(Types.ITEM1_13_2_SHORT_ARRAY, wrapper.read(Types.ITEM1_13_2_ARRAY));

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

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

lastCursorItem.setLastCursorItem(carried);

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.viaversion.viabackwards.api.rewriters.MapColorRewriter;
import com.viaversion.viabackwards.protocol.v1_17to1_16_4.Protocol1_17To1_16_4;
import com.viaversion.viabackwards.protocol.v1_17to1_16_4.data.MapColorMappings1_16_4;
import com.viaversion.viabackwards.protocol.v1_17_1to1_17.storage.InventoryStateIds;
import com.viaversion.viabackwards.protocol.v1_17to1_16_4.storage.PlayerLastCursorItem;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.minecraft.BlockChangeRecord;
Expand Down Expand Up @@ -83,8 +84,26 @@ public void register() {
int mode = wrapper.passthrough(Types.VAR_INT); // Mode
Item clicked = handleItemToServer(wrapper.user(), wrapper.read(Types.ITEM1_13_2)); // Clicked item

// The 1.17 client would check the entire inventory for changes before -> after a click and send the changed slots here
wrapper.write(Types.VAR_INT, 0); // Empty array of slot+item
// The 1.17 client would check the entire inventory for changes before -> after a click
// and send the changed slots here. We include the clicked slot so the server
// detects any desync (e.g. cancelled InventoryClickEvent) and sends corrections.
if (slot >= 0 && clicked != null) {
wrapper.write(Types.VAR_INT, 1); // One modified slot
wrapper.write(Types.SHORT, slot); // The clicked slot
wrapper.write(Types.ITEM1_13_2, (Item) null); // Predicted: empty (item picked up)
} else {
wrapper.write(Types.VAR_INT, 0); // Empty array of slot+item
}

// Non-PICKUP modes (shift-click, swap, throw, drag, etc.) affect multiple slots
// that we can't easily predict. Force a state ID mismatch so the server
// sends a full inventory resync instead of individual slot corrections.
if (mode != 0) {
InventoryStateIds stateIds = wrapper.user().get(InventoryStateIds.class);
if (stateIds != null) {
stateIds.setStateId(wrapper.get(Types.BYTE, 0), -1);
}
}

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