Skip to content

Commit d975df4

Browse files
committed
Fix creative mode clear action in 1.21.2->1.21
Fixes #940
1 parent 206a5b4 commit d975df4

2 files changed

Lines changed: 49 additions & 0 deletions

File tree

common/src/main/java/com/viaversion/viabackwards/protocol/v1_21_2to1_21/rewriter/BlockItemPacketRewriter1_21_2.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
4444
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
4545
import com.viaversion.viaversion.api.minecraft.item.Item;
46+
import com.viaversion.viaversion.api.minecraft.item.StructuredItem;
4647
import com.viaversion.viaversion.api.minecraft.item.data.Consumable1_21_2;
4748
import com.viaversion.viaversion.api.minecraft.item.data.DeathProtection;
4849
import com.viaversion.viaversion.api.minecraft.item.data.Enchantable;
@@ -256,6 +257,33 @@ public void registerPackets() {
256257
}
257258
wrapper.write(itemType(), handleItemToServer(wrapper.user(), wrapper.read(mappedItemType())));
258259
});
260+
protocol.replaceServerbound(ServerboundPackets1_20_5.SET_CREATIVE_MODE_SLOT, wrapper -> {
261+
if (protocol.getEntityRewriter() != null && !protocol.getEntityRewriter().tracker(wrapper.user()).canInstaBuild()) {
262+
wrapper.cancel();
263+
return;
264+
}
265+
266+
final short slot = wrapper.passthrough(Types.SHORT);
267+
final Item item = wrapper.read(mappedItemType());
268+
269+
// Clearing the inventory via the destroy item slot is the only creative action old clients don't
270+
// apply locally, but 1.21.2+ servers do not send back the empty contents.
271+
// Detect the action by checking for linear slot clears and leave other actions alone.
272+
final InventoryStateIdStorage storage = wrapper.user().get(InventoryStateIdStorage.class);
273+
final boolean empty = Item.isEmpty(item);
274+
if (empty && slot == storage.nextClearedSlot()) {
275+
if (slot == 45) {
276+
storage.setNextClearedSlot(0);
277+
sendEmptyInventorySlots(wrapper.user());
278+
} else {
279+
storage.setNextClearedSlot(slot + 1);
280+
}
281+
} else {
282+
storage.setNextClearedSlot(empty && slot == 0 ? 1 : 0);
283+
}
284+
285+
wrapper.write(itemType(), handleItemToServer(wrapper.user(), item));
286+
});
259287

260288
protocol.registerServerbound(ServerboundPackets1_20_5.USE_ITEM_ON, wrapper -> {
261289
wrapper.passthrough(Types.VAR_INT); // Hand
@@ -367,6 +395,18 @@ public void registerPackets() {
367395
});
368396
}
369397

398+
private void sendEmptyInventorySlots(final UserConnection connection) {
399+
final int stateId = connection.get(InventoryStateIdStorage.class).stateId();
400+
for (int slot = 1; slot <= 45; slot++) {
401+
final PacketWrapper setSlotPacket = PacketWrapper.create(ClientboundPackets1_21.CONTAINER_SET_SLOT, connection);
402+
setSlotPacket.write(Types.BYTE, (byte) 0); // Player inventory
403+
setSlotPacket.write(Types.VAR_INT, stateId); // State id; re-use the last known one
404+
setSlotPacket.write(Types.SHORT, (short) slot);
405+
setSlotPacket.write(mappedItemType(), StructuredItem.empty());
406+
setSlotPacket.send(Protocol1_21_2To1_21.class);
407+
}
408+
}
409+
370410
private void varIntToUnsignedByte(final PacketWrapper wrapper) {
371411
final int containerId = wrapper.read(Types.VAR_INT);
372412
wrapper.write(Types.UNSIGNED_BYTE, (short) containerId);

common/src/main/java/com/viaversion/viabackwards/protocol/v1_21_2to1_21/storage/InventoryStateIdStorage.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public final class InventoryStateIdStorage implements StorableObject {
2323

2424
private boolean smithingTableOpen;
2525
private int stateId = -1;
26+
private int nextClearedSlot;
2627

2728
public int stateId() {
2829
return stateId;
@@ -32,6 +33,14 @@ public void setStateId(final int stateId) {
3233
this.stateId = stateId;
3334
}
3435

36+
public int nextClearedSlot() {
37+
return nextClearedSlot;
38+
}
39+
40+
public void setNextClearedSlot(final int nextClearedSlot) {
41+
this.nextClearedSlot = nextClearedSlot;
42+
}
43+
3544
public boolean smithingTableOpen() {
3645
return smithingTableOpen;
3746
}

0 commit comments

Comments
 (0)