mirror of
https://github.com/GeyserMC/Geyser.git
synced 2026-01-06 15:41:50 +00:00
Fix virtual inventory opening
This commit is contained in:
@@ -168,19 +168,20 @@ public class BlockInventoryHolder extends InventoryHolder {
|
||||
return;
|
||||
}
|
||||
|
||||
// Bedrock broke inventory closing. I wish i was kidding.
|
||||
// "type" is explicitly passed to keep track of which inventory types can be closed without
|
||||
// ""workarounds"". yippie.
|
||||
// Further, Lecterns cannot be closed with any of the two methods below.
|
||||
|
||||
// Lecterns are special, and cannot be closed with any of the two methods below.
|
||||
if (container.isUsingRealBlock() && !(container instanceof LecternContainer)) {
|
||||
// No need to reset a block since we didn't change any blocks
|
||||
// But send a container close packet because we aren't destroying the original.
|
||||
ContainerClosePacket packet = new ContainerClosePacket();
|
||||
packet.setId((byte) inventory.getBedrockId());
|
||||
packet.setServerInitiated(true);
|
||||
packet.setType(type != null ? type : containerType);
|
||||
session.sendUpstreamPacket(packet);
|
||||
|
||||
// Here comes the ugly part. This is a manual check to filter specific containers
|
||||
// that won't close anymore with "just" a ContainerClosePacket.
|
||||
if (type != null) {
|
||||
// No need to reset a block since we didn't change any blocks
|
||||
// But send a container close packet because we aren't destroying the original.
|
||||
ContainerClosePacket packet = new ContainerClosePacket();
|
||||
packet.setId((byte) inventory.getBedrockId());
|
||||
packet.setServerInitiated(true);
|
||||
packet.setType(type);
|
||||
session.sendUpstreamPacket(packet);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -675,6 +675,14 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
@Setter
|
||||
private int stepTicks = 0;
|
||||
|
||||
/*
|
||||
* Stores the number of attempts to open virtual inventories.
|
||||
* Capped at 3, and isn't used in ideal circumstances.
|
||||
* Used to resolve https://github.com/GeyserMC/Geyser/issues/5426
|
||||
*/
|
||||
@Setter
|
||||
private int containerOpenAttempts;
|
||||
|
||||
|
||||
public GeyserSession(GeyserImpl geyser, BedrockServerSession bedrockServerSession, EventLoop tickEventLoop) {
|
||||
this.geyser = geyser;
|
||||
|
||||
@@ -102,12 +102,14 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
|
||||
blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
|
||||
session.sendUpstreamPacket(blockPacket);
|
||||
|
||||
NbtMap tag = BlockEntityTranslator.getConstantBedrockTag("Chest", position)
|
||||
NbtMapBuilder tag = BlockEntityTranslator.getConstantBedrockTag("Chest", position)
|
||||
.putInt("pairx", pairPosition.getX())
|
||||
.putInt("pairz", pairPosition.getZ())
|
||||
.putString("CustomName", inventory.getTitle()).build();
|
||||
.putString("CustomName", inventory.getTitle())
|
||||
.putBoolean("pairlead", false);
|
||||
|
||||
BlockEntityDataPacket dataPacket = new BlockEntityDataPacket();
|
||||
dataPacket.setData(tag);
|
||||
dataPacket.setData(tag.build());
|
||||
dataPacket.setBlockPosition(position);
|
||||
session.sendUpstreamPacket(dataPacket);
|
||||
|
||||
@@ -125,14 +127,15 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
|
||||
.putInt("z", pairPosition.getZ())
|
||||
.putInt("pairx", position.getX())
|
||||
.putInt("pairz", position.getZ())
|
||||
.putString("CustomName", inventory.getTitle()).build();
|
||||
.putString("CustomName", inventory.getTitle())
|
||||
.putBoolean("pairlead", true);
|
||||
|
||||
dataPacket = new BlockEntityDataPacket();
|
||||
dataPacket.setData(tag);
|
||||
dataPacket.setData(tag.build());
|
||||
dataPacket.setBlockPosition(pairPosition);
|
||||
session.sendUpstreamPacket(dataPacket);
|
||||
|
||||
inventory.setHolderPosition(position);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -160,31 +163,30 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
|
||||
return;
|
||||
}
|
||||
|
||||
if (container.isUsingRealBlock()) {
|
||||
// No need to reset a block since we didn't change any blocks
|
||||
// But send a container close packet because we aren't destroying the original.
|
||||
ContainerClosePacket packet = new ContainerClosePacket();
|
||||
packet.setId((byte) inventory.getBedrockId());
|
||||
packet.setServerInitiated(true);
|
||||
packet.setType(ContainerType.CONTAINER);
|
||||
session.sendUpstreamPacket(packet);
|
||||
return;
|
||||
// No need to reset a block since we didn't change any blocks
|
||||
// But send a container close packet because we aren't destroying the original.
|
||||
ContainerClosePacket packet = new ContainerClosePacket();
|
||||
packet.setId((byte) inventory.getBedrockId());
|
||||
packet.setServerInitiated(true);
|
||||
packet.setType(ContainerType.CONTAINER);
|
||||
session.sendUpstreamPacket(packet);
|
||||
|
||||
if (!container.isUsingRealBlock()) {
|
||||
Vector3i holderPos = inventory.getHolderPosition();
|
||||
int realBlock = session.getGeyser().getWorldManager().getBlockAt(session, holderPos);
|
||||
UpdateBlockPacket blockPacket = new UpdateBlockPacket();
|
||||
blockPacket.setDataLayer(0);
|
||||
blockPacket.setBlockPosition(holderPos);
|
||||
blockPacket.setDefinition(session.getBlockMappings().getBedrockBlock(realBlock));
|
||||
session.sendUpstreamPacket(blockPacket);
|
||||
|
||||
holderPos = holderPos.add(Vector3i.UNIT_X);
|
||||
realBlock = session.getGeyser().getWorldManager().getBlockAt(session, holderPos);
|
||||
blockPacket = new UpdateBlockPacket();
|
||||
blockPacket.setDataLayer(0);
|
||||
blockPacket.setBlockPosition(holderPos);
|
||||
blockPacket.setDefinition(session.getBlockMappings().getBedrockBlock(realBlock));
|
||||
session.sendUpstreamPacket(blockPacket);
|
||||
}
|
||||
|
||||
Vector3i holderPos = inventory.getHolderPosition();
|
||||
int realBlock = session.getGeyser().getWorldManager().getBlockAt(session, holderPos);
|
||||
UpdateBlockPacket blockPacket = new UpdateBlockPacket();
|
||||
blockPacket.setDataLayer(0);
|
||||
blockPacket.setBlockPosition(holderPos);
|
||||
blockPacket.setDefinition(session.getBlockMappings().getBedrockBlock(realBlock));
|
||||
session.sendUpstreamPacket(blockPacket);
|
||||
|
||||
holderPos = holderPos.add(Vector3i.UNIT_X);
|
||||
realBlock = session.getGeyser().getWorldManager().getBlockAt(session, holderPos);
|
||||
blockPacket = new UpdateBlockPacket();
|
||||
blockPacket.setDataLayer(0);
|
||||
blockPacket.setBlockPosition(holderPos);
|
||||
blockPacket.setDefinition(session.getBlockMappings().getBedrockBlock(realBlock));
|
||||
session.sendUpstreamPacket(blockPacket);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
package org.geysermc.geyser.translator.protocol.bedrock;
|
||||
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ContainerClosePacket;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.inventory.Container;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.MerchantContainer;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
@@ -45,12 +47,29 @@ public class BedrockContainerCloseTranslator extends PacketTranslator<ContainerC
|
||||
session.sendUpstreamPacket(packet);
|
||||
session.setClosingInventory(false);
|
||||
|
||||
if (bedrockId == -1 && session.getOpenInventory() instanceof MerchantContainer) {
|
||||
// 1.16.200 - window ID is always -1 sent from Bedrock
|
||||
bedrockId = (byte) session.getOpenInventory().getBedrockId();
|
||||
// 1.21.70: Bedrock can reject opening inventories - in those cases it replies with -1
|
||||
Inventory openInventory = session.getOpenInventory();
|
||||
if (bedrockId == -1 && openInventory != null) {
|
||||
// 1.16.200 - window ID is always -1 sent from Bedrock for merchant containers
|
||||
bedrockId = (byte) openInventory.getBedrockId();
|
||||
|
||||
// If virtual inventories are opened too quickly, they can be occasionally rejected
|
||||
if (openInventory instanceof Container container && !container.isUsingRealBlock()) {
|
||||
if (session.getContainerOpenAttempts() < 3) {
|
||||
session.setContainerOpenAttempts(session.getContainerOpenAttempts() + 1);
|
||||
session.getInventoryTranslator().openInventory(session, session.getOpenInventory());
|
||||
session.getInventoryTranslator().updateInventory(session, session.getOpenInventory());
|
||||
session.getOpenInventory().setDisplayed(true);
|
||||
return;
|
||||
} else {
|
||||
GeyserImpl.getInstance().getLogger().debug("Exceeded 3 attempts to open a virtual inventory!");
|
||||
GeyserImpl.getInstance().getLogger().debug(packet + " " + session.getOpenInventory().getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Inventory openInventory = session.getOpenInventory();
|
||||
session.setContainerOpenAttempts(0);
|
||||
|
||||
if (openInventory != null) {
|
||||
if (bedrockId == openInventory.getBedrockId()) {
|
||||
InventoryUtils.sendJavaContainerClose(session, openInventory);
|
||||
|
||||
@@ -26,11 +26,11 @@
|
||||
package org.geysermc.geyser.translator.protocol.java.inventory;
|
||||
|
||||
import org.geysermc.geyser.inventory.PlayerInventory;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundContainerClosePacket;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.Translator;
|
||||
import org.geysermc.geyser.util.InventoryUtils;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundContainerClosePacket;
|
||||
|
||||
@Translator(packet = ClientboundContainerClosePacket.class)
|
||||
public class JavaContainerCloseTranslator extends PacketTranslator<ClientboundContainerClosePacket> {
|
||||
|
||||
@@ -25,9 +25,6 @@
|
||||
|
||||
package org.geysermc.geyser.translator.protocol.java.inventory;
|
||||
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundOpenScreenPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClosePacket;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
@@ -37,6 +34,9 @@ import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.Translator;
|
||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||
import org.geysermc.geyser.util.InventoryUtils;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundOpenScreenPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClosePacket;
|
||||
|
||||
@Translator(packet = ClientboundOpenScreenPacket.class)
|
||||
public class JavaOpenScreenTranslator extends PacketTranslator<ClientboundOpenScreenPacket> {
|
||||
|
||||
@@ -55,7 +55,6 @@ import org.geysermc.geyser.text.ChatColor;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator;
|
||||
import org.geysermc.geyser.translator.inventory.chest.DoubleChestInventoryTranslator;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.CompositeSlotDisplay;
|
||||
@@ -100,7 +99,8 @@ public class InventoryUtils {
|
||||
public static void displayInventory(GeyserSession session, Inventory inventory) {
|
||||
InventoryTranslator translator = session.getInventoryTranslator();
|
||||
if (translator.prepareInventory(session, inventory)) {
|
||||
if (translator instanceof DoubleChestInventoryTranslator && !((Container) inventory).isUsingRealBlock()) {
|
||||
// 1.21.70 wants a delay on all virtual inventories: https://github.com/GeyserMC/Geyser/issues/5426
|
||||
if (inventory instanceof Container container && !container.isUsingRealBlock()) {
|
||||
session.scheduleInEventLoop(() -> {
|
||||
Inventory openInv = session.getOpenInventory();
|
||||
if (openInv != null && openInv.getJavaId() == inventory.getJavaId()) {
|
||||
@@ -111,7 +111,7 @@ public class InventoryUtils {
|
||||
// Presumably, this inventory is no longer relevant, and the client doesn't care about it
|
||||
displayInventory(session, openInv);
|
||||
}
|
||||
}, 200, TimeUnit.MILLISECONDS);
|
||||
}, 300, TimeUnit.MILLISECONDS);
|
||||
} else {
|
||||
translator.openInventory(session, inventory);
|
||||
translator.updateInventory(session, inventory);
|
||||
|
||||
Reference in New Issue
Block a user