Partially revert previous commit and implement hotbar swap actions

1.16.5 does not cooperate well when an action is invalid, and this breaks hard when crafting.
This commit is contained in:
Camotoy 2022-01-11 16:56:11 -05:00
parent a29e7731e8
commit 1c11a2ef01
No known key found for this signature in database
GPG key ID: 7EEFB66FE798081F
6 changed files with 94 additions and 18 deletions

View file

@ -38,7 +38,16 @@ public enum Click {
DROP_ONE(ContainerActionType.DROP_ITEM, DropItemAction.DROP_FROM_SELECTED),
DROP_ALL(ContainerActionType.DROP_ITEM, DropItemAction.DROP_SELECTED_STACK),
LEFT_OUTSIDE(ContainerActionType.CLICK_ITEM, ClickItemAction.LEFT_CLICK),
RIGHT_OUTSIDE(ContainerActionType.CLICK_ITEM, ClickItemAction.RIGHT_CLICK);
RIGHT_OUTSIDE(ContainerActionType.CLICK_ITEM, ClickItemAction.RIGHT_CLICK),
SWAP_TO_HOTBAR_1(ContainerActionType.MOVE_TO_HOTBAR_SLOT, MoveToHotbarAction.SLOT_1),
SWAP_TO_HOTBAR_2(ContainerActionType.MOVE_TO_HOTBAR_SLOT, MoveToHotbarAction.SLOT_2),
SWAP_TO_HOTBAR_3(ContainerActionType.MOVE_TO_HOTBAR_SLOT, MoveToHotbarAction.SLOT_3),
SWAP_TO_HOTBAR_4(ContainerActionType.MOVE_TO_HOTBAR_SLOT, MoveToHotbarAction.SLOT_4),
SWAP_TO_HOTBAR_5(ContainerActionType.MOVE_TO_HOTBAR_SLOT, MoveToHotbarAction.SLOT_5),
SWAP_TO_HOTBAR_6(ContainerActionType.MOVE_TO_HOTBAR_SLOT, MoveToHotbarAction.SLOT_6),
SWAP_TO_HOTBAR_7(ContainerActionType.MOVE_TO_HOTBAR_SLOT, MoveToHotbarAction.SLOT_7),
SWAP_TO_HOTBAR_8(ContainerActionType.MOVE_TO_HOTBAR_SLOT, MoveToHotbarAction.SLOT_8),
SWAP_TO_HOTBAR_9(ContainerActionType.MOVE_TO_HOTBAR_SLOT, MoveToHotbarAction.SLOT_9);
public static final int OUTSIDE_SLOT = -999;

View file

@ -28,6 +28,7 @@ package org.geysermc.geyser.inventory.click;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.mc.protocol.data.game.inventory.ContainerActionType;
import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType;
import com.github.steveice10.mc.protocol.data.game.inventory.MoveToHotbarAction;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
@ -107,12 +108,13 @@ public class ClickPlan {
ClickAction action = planIter.next();
if (action.slot != Click.OUTSIDE_SLOT && translator.getSlotType(action.slot) != SlotType.NORMAL) {
// Needed with Paper 1.16.5
refresh = true;
}
int stateId = stateIdHack(action);
//int stateId = stateIdHack(action);
simulateAction(action);
//simulateAction(action);
ItemStack clickedItemStack;
if (!planIter.hasNext() && refresh) {
@ -120,13 +122,14 @@ public class ClickPlan {
} else if (action.click.actionType == ContainerActionType.DROP_ITEM || action.slot == Click.OUTSIDE_SLOT) {
clickedItemStack = null;
} else {
// The action must be simulated first as Java expects the new contents of the cursor (as of 1.18.1)
clickedItemStack = simulatedCursor.getItemStack();
//// The action must be simulated first as Java expects the new contents of the cursor (as of 1.18.1)
//clickedItemStack = simulatedCursor.getItemStack(); TODO fix - this is the proper behavior but it terribly breaks 1.16.5
clickedItemStack = getItem(action.slot).getItemStack();
}
ServerboundContainerClickPacket clickPacket = new ServerboundContainerClickPacket(
inventory.getId(),
stateId,
inventory.getStateId(),
action.slot,
action.click.actionType,
action.click.action,
@ -134,6 +137,8 @@ public class ClickPlan {
Collections.emptyMap() // Anything else we change, at this time, should have a packet sent to address
);
simulateAction(action);
session.sendDownstreamPacket(clickPacket);
}
@ -228,6 +233,33 @@ public class ClickPlan {
clicked.add(1);
}
break;
case SWAP_TO_HOTBAR_1:
swap(action.slot, 36, clicked);
break;
case SWAP_TO_HOTBAR_2:
swap(action.slot, 37, clicked);
break;
case SWAP_TO_HOTBAR_3:
swap(action.slot, 38, clicked);
break;
case SWAP_TO_HOTBAR_4:
swap(action.slot, 39, clicked);
break;
case SWAP_TO_HOTBAR_5:
swap(action.slot, 40, clicked);
break;
case SWAP_TO_HOTBAR_6:
swap(action.slot, 41, clicked);
break;
case SWAP_TO_HOTBAR_7:
swap(action.slot, 42, clicked);
break;
case SWAP_TO_HOTBAR_8:
swap(action.slot, 43, clicked);
break;
case SWAP_TO_HOTBAR_9:
swap(action.slot, 44, clicked);
break;
case LEFT_SHIFT:
//TODO
break;
@ -243,6 +275,15 @@ public class ClickPlan {
}
}
/**
* Swap between two inventory slots without a cursor. This should only be used with {@link ContainerActionType#MOVE_TO_HOTBAR_SLOT}
*/
private void swap(int sourceSlot, int destSlot, GeyserItemStack sourceItem) {
GeyserItemStack destinationItem = simulating ? getItem(destSlot) : inventory.getItem(destSlot);
setItem(sourceSlot, destinationItem);
setItem(destSlot, sourceItem);
}
private int stateIdHack(ClickAction action) {
int stateId;
if (inventory.getNextStateId() != -1) {
@ -297,6 +338,9 @@ public class ClickPlan {
stateIdIncrements = 2;
}
inventory.incrementStateId(stateIdIncrements);
} else if (action.click.action instanceof MoveToHotbarAction) {
// Two slot changes sent
inventory.incrementStateId(2);
} else {
inventory.incrementStateId(1);
}

View file

@ -42,7 +42,7 @@ public class CartographyInventoryTranslator extends AbstractBlockInventoryTransl
}
@Override
public boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, ContainerSlotType bedrockSourceContainer,
protected boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, ContainerSlotType bedrockSourceContainer,
int javaSourceSlot, ContainerSlotType bedrockDestinationContainer, int javaDestinationSlot) {
if (javaDestinationSlot == 0) {
// Bedrock Edition can use paper or an empty map in slot 0

View file

@ -127,7 +127,7 @@ public abstract class InventoryTranslator {
*
* @return true if this transfer should be rejected
*/
public boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, ContainerSlotType bedrockSourceContainer,
protected boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, ContainerSlotType bedrockSourceContainer,
int javaSourceSlot, ContainerSlotType bedrockDestinationContainer, int javaDestinationSlot) {
return false;
}
@ -288,26 +288,49 @@ public abstract class InventoryTranslator {
}
case SWAP: {
SwapStackRequestActionData swapAction = (SwapStackRequestActionData) action;
if (!(checkNetId(session, inventory, swapAction.getSource()) && checkNetId(session, inventory, swapAction.getDestination()))) {
StackRequestSlotInfoData source = swapAction.getSource();
StackRequestSlotInfoData destination = swapAction.getDestination();
if (!(checkNetId(session, inventory, source) && checkNetId(session, inventory, destination))) {
if (session.getGeyser().getConfig().isDebugMode()) {
session.getGeyser().getLogger().error("DEBUG: About to reject SWAP request made by " + session.name());
dumpStackRequestDetails(session, inventory, swapAction.getSource(), swapAction.getDestination());
dumpStackRequestDetails(session, inventory, source, destination);
}
return rejectRequest(request);
}
int sourceSlot = bedrockSlotToJava(swapAction.getSource());
int destSlot = bedrockSlotToJava(swapAction.getDestination());
boolean isSourceCursor = isCursor(swapAction.getSource());
boolean isDestCursor = isCursor(swapAction.getDestination());
int sourceSlot = bedrockSlotToJava(source);
int destSlot = bedrockSlotToJava(destination);
boolean isSourceCursor = isCursor(source);
boolean isDestCursor = isCursor(destination);
if (shouldRejectItemPlace(session, inventory, swapAction.getSource().getContainer(),
if (shouldRejectItemPlace(session, inventory, source.getContainer(),
isSourceCursor ? -1 : sourceSlot,
swapAction.getDestination().getContainer(), isDestCursor ? -1 : destSlot)) {
destination.getContainer(), isDestCursor ? -1 : destSlot)) {
// This item would not be here in Java
return rejectRequest(request, false);
}
if (!isSourceCursor && destination.getContainer() == ContainerSlotType.HOTBAR || destination.getContainer() == ContainerSlotType.HOTBAR_AND_INVENTORY) {
// Tell the server we're pressing one of the hotbar keys to save clicks
Click click = switch (destination.getSlot()) {
case 0 -> Click.SWAP_TO_HOTBAR_1;
case 1 -> Click.SWAP_TO_HOTBAR_2;
case 2 -> Click.SWAP_TO_HOTBAR_3;
case 3 -> Click.SWAP_TO_HOTBAR_4;
case 4 -> Click.SWAP_TO_HOTBAR_5;
case 5 -> Click.SWAP_TO_HOTBAR_6;
case 6 -> Click.SWAP_TO_HOTBAR_7;
case 7 -> Click.SWAP_TO_HOTBAR_8;
case 8 -> Click.SWAP_TO_HOTBAR_9;
default -> null;
};
if (click != null) {
plan.add(click, sourceSlot);
break;
}
}
if (isSourceCursor && isDestCursor) { //???
return rejectRequest(request);
} else if (isSourceCursor) { //swap cursor

View file

@ -102,7 +102,7 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator {
}
@Override
public boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, ContainerSlotType bedrockSourceContainer,
protected boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, ContainerSlotType bedrockSourceContainer,
int javaSourceSlot, ContainerSlotType bedrockDestinationContainer, int javaDestinationSlot) {
if (javaDestinationSlot != 1) {
return false;

View file

@ -42,7 +42,7 @@ public abstract class ChestInventoryTranslator extends BaseInventoryTranslator {
}
@Override
public boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, ContainerSlotType bedrockSourceContainer,
protected boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, ContainerSlotType bedrockSourceContainer,
int javaSourceSlot, ContainerSlotType bedrockDestinationContainer, int javaDestinationSlot) {
// Reject any item placements that occur in the unusable inventory space
if (bedrockSourceContainer == ContainerSlotType.CONTAINER && javaSourceSlot >= this.size) {