forked from GeyserMC/Geyser
Fix bucket interactions on creative mode (#1369)
* Fix bucket interactions on creative mode Bedrock uses the BLOCK_INTERACT enum of BedrockActionTranslator to truly indicate if a bucket should be used or not. In order to hook into this, we need to delay the bucket placing by about 5 milliseconds - this gives us time to cancel the interaction if needed. Bucket sounds will now not play in this case as well.
This commit is contained in:
parent
ffcff96bea
commit
96db37c14c
4 changed files with 27 additions and 10 deletions
|
@ -84,6 +84,7 @@ import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.security.spec.InvalidKeySpecException;
|
import java.security.spec.InvalidKeySpecException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
|
@ -210,6 +211,13 @@ public class GeyserSession implements CommandSender {
|
||||||
@Setter
|
@Setter
|
||||||
private long lastInteractionTime;
|
private long lastInteractionTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores a future interaction to place a bucket. Will be cancelled if the client instead intended to
|
||||||
|
* interact with a block.
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
private ScheduledFuture<?> bucketScheduledFuture;
|
||||||
|
|
||||||
private boolean reducedDebugInfo = false;
|
private boolean reducedDebugInfo = false;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
|
|
|
@ -61,6 +61,8 @@ import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
import org.geysermc.connector.utils.BlockUtils;
|
import org.geysermc.connector.utils.BlockUtils;
|
||||||
import org.geysermc.connector.utils.InventoryUtils;
|
import org.geysermc.connector.utils.InventoryUtils;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@Translator(packet = InventoryTransactionPacket.class)
|
@Translator(packet = InventoryTransactionPacket.class)
|
||||||
public class BedrockInventoryTransactionTranslator extends PacketTranslator<InventoryTransactionPacket> {
|
public class BedrockInventoryTransactionTranslator extends PacketTranslator<InventoryTransactionPacket> {
|
||||||
|
|
||||||
|
@ -120,18 +122,19 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||||
session.sendDownstreamPacket(itemPacket);
|
session.sendDownstreamPacket(itemPacket);
|
||||||
}
|
}
|
||||||
// Check actions, otherwise buckets may be activated when block inventories are accessed
|
// Check actions, otherwise buckets may be activated when block inventories are accessed
|
||||||
// But don't check actions if the item damage is 0
|
else if (packet.getItemInHand() != null && packet.getItemInHand().getId() == ItemRegistry.BUCKET.getBedrockId()) {
|
||||||
else if (packet.getItemInHand() != null && packet.getItemInHand().getId() == ItemRegistry.BUCKET.getBedrockId() &&
|
|
||||||
(packet.getItemInHand().getDamage() == 0 || !packet.getActions().isEmpty())) {
|
|
||||||
ClientPlayerUseItemPacket itemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
|
|
||||||
session.sendDownstreamPacket(itemPacket);
|
|
||||||
|
|
||||||
// Let the server decide if the bucket item should change, not the client, and revert the changes the client made
|
// Let the server decide if the bucket item should change, not the client, and revert the changes the client made
|
||||||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||||
slotPacket.setContainerId(ContainerId.INVENTORY);
|
slotPacket.setContainerId(ContainerId.INVENTORY);
|
||||||
slotPacket.setSlot(packet.getHotbarSlot());
|
slotPacket.setSlot(packet.getHotbarSlot());
|
||||||
slotPacket.setItem(packet.getItemInHand());
|
slotPacket.setItem(packet.getItemInHand());
|
||||||
session.sendUpstreamPacket(slotPacket);
|
session.sendUpstreamPacket(slotPacket);
|
||||||
|
// Delay the interaction in case the client doesn't intend to actually use the bucket
|
||||||
|
// See BedrockActionTranslator.java
|
||||||
|
session.setBucketScheduledFuture(session.getConnector().getGeneralThreadPool().schedule(() -> {
|
||||||
|
ClientPlayerUseItemPacket itemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
|
||||||
|
session.sendDownstreamPacket(itemPacket);
|
||||||
|
}, 5, TimeUnit.MILLISECONDS));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packet.getActions().isEmpty()) {
|
if (packet.getActions().isEmpty()) {
|
||||||
|
@ -167,10 +170,9 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handled in ITEM_USE
|
// Handled in ITEM_USE if the item is not milk
|
||||||
if (packet.getItemInHand() != null && packet.getItemInHand().getId() == ItemRegistry.BUCKET.getBedrockId() &&
|
if (packet.getItemInHand() != null && packet.getItemInHand().getId() == ItemRegistry.BUCKET.getBedrockId() &&
|
||||||
// Normal bucket, water bucket, lava bucket
|
packet.getItemInHand().getDamage() != 1) {
|
||||||
(packet.getItemInHand().getDamage() == 0 || packet.getItemInHand().getDamage() == 8 || packet.getItemInHand().getDamage() == 10)) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -114,7 +114,12 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
|
||||||
session.sendDownstreamPacket(stopSleepingPacket);
|
session.sendDownstreamPacket(stopSleepingPacket);
|
||||||
break;
|
break;
|
||||||
case BLOCK_INTERACT:
|
case BLOCK_INTERACT:
|
||||||
// Handled in BedrockInventoryTransactionTranslator
|
// Client means to interact with a block; cancel bucket interaction, if any
|
||||||
|
if (session.getBucketScheduledFuture() != null) {
|
||||||
|
session.getBucketScheduledFuture().cancel(true);
|
||||||
|
session.setBucketScheduledFuture(null);
|
||||||
|
}
|
||||||
|
// Otherwise handled in BedrockInventoryTransactionTranslator
|
||||||
break;
|
break;
|
||||||
case START_BREAK:
|
case START_BREAK:
|
||||||
if (session.getConnector().getConfig().isCacheChunks()) {
|
if (session.getConnector().getConfig().isCacheChunks()) {
|
||||||
|
|
|
@ -38,6 +38,7 @@ public class BucketSoundInteractionHandler implements BlockSoundInteractionHandl
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleInteraction(GeyserSession session, Vector3f position, String identifier) {
|
public void handleInteraction(GeyserSession session, Vector3f position, String identifier) {
|
||||||
|
if (session.getBucketScheduledFuture() == null) return; // No bucket was really interacted with
|
||||||
String handItemIdentifier = ItemRegistry.getItem(session.getInventory().getItemInHand()).getJavaIdentifier();
|
String handItemIdentifier = ItemRegistry.getItem(session.getInventory().getItemInHand()).getJavaIdentifier();
|
||||||
LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket();
|
LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket();
|
||||||
soundEventPacket.setPosition(position);
|
soundEventPacket.setPosition(position);
|
||||||
|
@ -68,5 +69,6 @@ public class BucketSoundInteractionHandler implements BlockSoundInteractionHandl
|
||||||
soundEventPacket.setSound(soundEvent);
|
soundEventPacket.setSound(soundEvent);
|
||||||
session.sendUpstreamPacket(soundEventPacket);
|
session.sendUpstreamPacket(soundEventPacket);
|
||||||
}
|
}
|
||||||
|
session.setBucketScheduledFuture(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue