mirror of
https://github.com/GeyserMC/Geyser.git
synced 2025-04-17 19:12:14 +02:00
Merge cb76b8093c
into 23a462d60c
This commit is contained in:
commit
845e9bf134
81 changed files with 1023 additions and 847 deletions
core/src/main/java/org/geysermc/geyser
command/defaults
inventory
AnvilContainer.javaBeaconContainer.javaCartographyContainer.javaContainer.javaCrafterContainer.javaEnchantingContainer.javaGeneric3X3Container.javaGeneric9X3Container.javaInventory.javaInventoryHolder.javaLecternContainer.javaMerchantContainer.javaPlayerInventory.javaStonecutterContainer.java
click
holder
updater
session
translator
inventory
AbstractBlockInventoryTranslator.javaAnvilInventoryTranslator.javaBaseInventoryTranslator.javaBeaconInventoryTranslator.javaBrewingInventoryTranslator.javaBundleInventoryTranslator.javaCartographyInventoryTranslator.javaCrafterInventoryTranslator.javaCraftingInventoryTranslator.javaEnchantingInventoryTranslator.javaGeneric3X3InventoryTranslator.javaGrindstoneInventoryTranslator.javaHopperInventoryTranslator.javaInventoryTranslator.javaLecternInventoryTranslator.javaLoomInventoryTranslator.javaMerchantInventoryTranslator.javaOldSmithingTableTranslator.javaPlayerInventoryTranslator.javaShulkerInventoryTranslator.javaSmithingInventoryTranslator.javaStonecutterInventoryTranslator.java
chest
furnace
AbstractFurnaceInventoryTranslator.javaBlastFurnaceInventoryTranslator.javaFurnaceInventoryTranslator.javaSmokerInventoryTranslator.java
horse
protocol
bedrock
BedrockBookEditTranslator.javaBedrockContainerCloseTranslator.javaBedrockFilterTextTranslator.javaBedrockInventoryTransactionTranslator.javaBedrockItemStackRequestTranslator.javaBedrockLecternUpdateTranslator.javaBedrockSetLocalPlayerAsInitializedTranslator.java
entity
java
JavaRespawnTranslator.java
entity
inventory
JavaContainerCloseTranslator.javaJavaContainerSetContentTranslator.javaJavaContainerSetDataTranslator.javaJavaContainerSetSlotTranslator.javaJavaHorseScreenOpenTranslator.javaJavaMerchantOffersTranslator.javaJavaOpenBookTranslator.javaJavaOpenScreenTranslator.javaJavaSetPlayerInventoryTranslator.java
util
|
@ -51,6 +51,6 @@ public class AdvancedTooltipsCommand extends GeyserCommand {
|
|||
+ MinecraftLocale.getLocaleString("debug.prefix", session.locale())
|
||||
+ " " + ChatColor.RESET
|
||||
+ MinecraftLocale.getLocaleString("debug.advanced_tooltips." + onOrOff, session.locale()));
|
||||
session.getPlayerInventory().updateInventory();
|
||||
session.getPlayerInventoryHolder().updateInventory();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ import lombok.Setter;
|
|||
import net.kyori.adventure.text.Component;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes;
|
||||
|
@ -63,8 +62,8 @@ public class AnvilContainer extends Container {
|
|||
|
||||
private int lastTargetSlot = -1;
|
||||
|
||||
public AnvilContainer(GeyserSession session, String title, int id, int size, ContainerType containerType, PlayerInventory playerInventory, InventoryTranslator translator) {
|
||||
super(session, title, id, size, containerType, playerInventory, translator);
|
||||
public AnvilContainer(GeyserSession session, String title, int id, int size, ContainerType containerType) {
|
||||
super(session, title, id, size, containerType);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,11 +25,10 @@
|
|||
|
||||
package org.geysermc.geyser.inventory;
|
||||
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
|
@ -37,7 +36,7 @@ public class BeaconContainer extends Container {
|
|||
private int primaryId;
|
||||
private int secondaryId;
|
||||
|
||||
public BeaconContainer(GeyserSession session, String title, int id, int size, ContainerType containerType, PlayerInventory playerInventory, InventoryTranslator translator) {
|
||||
super(session, title, id, size, containerType, playerInventory, translator);
|
||||
public BeaconContainer(GeyserSession session, String title, int id, int size, ContainerType containerType) {
|
||||
super(session, title, id, size, containerType);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,11 +26,10 @@
|
|||
package org.geysermc.geyser.inventory;
|
||||
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
||||
|
||||
public class CartographyContainer extends Container {
|
||||
public CartographyContainer(GeyserSession session, String title, int id, int size, ContainerType containerType, PlayerInventory playerInventory, InventoryTranslator translator) {
|
||||
super(session, title, id, size, containerType, playerInventory, translator);
|
||||
public CartographyContainer(GeyserSession session, String title, int id, int size, ContainerType containerType) {
|
||||
super(session, title, id, size, containerType);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,9 +46,9 @@ public class Container extends Inventory {
|
|||
*/
|
||||
private boolean isUsingRealBlock = false;
|
||||
|
||||
public Container(GeyserSession session, String title, int id, int size, ContainerType containerType, PlayerInventory playerInventory, InventoryTranslator translator) {
|
||||
super(session, title, id, size, containerType, translator);
|
||||
this.playerInventory = playerInventory;
|
||||
public Container(GeyserSession session, String title, int id, int size, ContainerType containerType) {
|
||||
super(session, title, id, size, containerType);
|
||||
this.playerInventory = session.getPlayerInventory();
|
||||
this.containerSize = this.size + InventoryTranslator.PLAYER_INVENTORY_SIZE;
|
||||
}
|
||||
|
||||
|
|
|
@ -48,8 +48,8 @@ public class CrafterContainer extends Container {
|
|||
*/
|
||||
private short disabledSlotsMask = 0;
|
||||
|
||||
public CrafterContainer(GeyserSession session, String title, int id, int size, ContainerType containerType, PlayerInventory playerInventory, InventoryTranslator translator) {
|
||||
super(session, title, id, size, containerType, playerInventory, translator);
|
||||
public CrafterContainer(GeyserSession session, String title, int id, int size, ContainerType containerType) {
|
||||
super(session, title, id, size, containerType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
package org.geysermc.geyser.inventory;
|
||||
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.EnchantOptionData;
|
||||
import lombok.Getter;
|
||||
|
@ -42,8 +41,8 @@ public class EnchantingContainer extends Container {
|
|||
*/
|
||||
private final GeyserEnchantOption[] geyserEnchantOptions;
|
||||
|
||||
public EnchantingContainer(GeyserSession session, String title, int id, int size, ContainerType containerType, PlayerInventory playerInventory, InventoryTranslator translator) {
|
||||
super(session, title, id, size, containerType, playerInventory, translator);
|
||||
public EnchantingContainer(GeyserSession session, String title, int id, int size, ContainerType containerType) {
|
||||
super(session, title, id, size, containerType);
|
||||
|
||||
enchantOptions = new EnchantOptionData[3];
|
||||
geyserEnchantOptions = new GeyserEnchantOption[3];
|
||||
|
|
|
@ -30,7 +30,6 @@ import org.geysermc.geyser.level.block.Blocks;
|
|||
import org.geysermc.geyser.level.block.type.Block;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.Generic3X3InventoryTranslator;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
||||
|
||||
@Getter
|
||||
|
@ -38,12 +37,12 @@ public class Generic3X3Container extends Container {
|
|||
/**
|
||||
* Whether we need to set the container type as {@link org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType#DROPPER}.
|
||||
* <p>
|
||||
* Used at {@link Generic3X3InventoryTranslator#openInventory(GeyserSession, Inventory)}
|
||||
* Used at {@link Generic3X3InventoryTranslator#openInventory(GeyserSession, Generic3X3Container)}
|
||||
*/
|
||||
private boolean isDropper = false;
|
||||
|
||||
public Generic3X3Container(GeyserSession session, String title, int id, int size, ContainerType containerType, PlayerInventory playerInventory, InventoryTranslator translator) {
|
||||
super(session, title, id, size, containerType, playerInventory, translator);
|
||||
public Generic3X3Container(GeyserSession session, String title, int id, int size, ContainerType containerType) {
|
||||
super(session, title, id, size, containerType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2025 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.inventory;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.geyser.level.block.Blocks;
|
||||
import org.geysermc.geyser.level.block.type.Block;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
||||
|
||||
/**
|
||||
* A "hack" to be able to use existing barrels.
|
||||
* The only difference to chests appears to be the different ContainerSlotType - this accounts for it.
|
||||
*/
|
||||
@Getter @Setter
|
||||
public class Generic9X3Container extends Container {
|
||||
|
||||
private boolean isBarrel;
|
||||
|
||||
public Generic9X3Container(GeyserSession session, String title, int id, int size, ContainerType containerType) {
|
||||
super(session, title, id, size, containerType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUsingRealBlock(boolean usingRealBlock, Block block) {
|
||||
super.setUsingRealBlock(usingRealBlock, block);
|
||||
if (usingRealBlock) {
|
||||
isBarrel = block == Blocks.BARREL;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,7 +35,6 @@ import org.geysermc.geyser.GeyserImpl;
|
|||
import org.geysermc.geyser.inventory.click.ClickPlan;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.geyser.translator.item.ItemTranslator;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes;
|
||||
|
@ -95,44 +94,24 @@ public abstract class Inventory {
|
|||
@Setter
|
||||
protected long holderId = -1;
|
||||
|
||||
/**
|
||||
* Whether this inventory is currently pending.
|
||||
* It can be pending if this inventory was opened while another inventory was still open,
|
||||
* or because opening this inventory takes more time (e.g. virtual inventories).
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean pending = false;
|
||||
|
||||
/**
|
||||
* Whether this inventory is currently shown to the Bedrock player.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean displayed = false;
|
||||
private boolean displayed;
|
||||
|
||||
/**
|
||||
* The translator for this inventory. Stored here to avoid de-syncs of the inventory and current translator.
|
||||
*/
|
||||
@Getter
|
||||
private final InventoryTranslator translator;
|
||||
|
||||
@Getter
|
||||
private final GeyserSession session;
|
||||
|
||||
protected Inventory(GeyserSession session, int id, int size, ContainerType containerType, InventoryTranslator translator) {
|
||||
this(session, "Inventory", id, size, containerType, translator);
|
||||
protected Inventory(GeyserSession session, int id, int size, ContainerType containerType) {
|
||||
this(session, "Inventory", id, size, containerType);
|
||||
}
|
||||
|
||||
protected Inventory(GeyserSession session, String title, int javaId, int size, ContainerType containerType, InventoryTranslator translator) {
|
||||
protected Inventory(GeyserSession session, String title, int javaId, int size, ContainerType containerType) {
|
||||
this.title = title;
|
||||
this.javaId = javaId;
|
||||
this.size = size;
|
||||
this.containerType = containerType;
|
||||
this.items = new GeyserItemStack[size];
|
||||
Arrays.fill(items, GeyserItemStack.EMPTY);
|
||||
this.translator = translator;
|
||||
this.session = session;
|
||||
|
||||
// This is to prevent conflicts with special bedrock inventory IDs.
|
||||
// The vanilla java server only sends an ID between 1 and 100 when opening an inventory,
|
||||
|
@ -144,7 +123,7 @@ public abstract class Inventory {
|
|||
// Java wouldn't - e.g. for virtual chest menus that switch pages.
|
||||
// And, well, we want to avoid reusing Bedrock inventory id's that are currently being used in a closing inventory;
|
||||
// so to be safe we just deviate in that case as well.
|
||||
if ((session.getOpenInventory() != null && session.getOpenInventory().getBedrockId() == bedrockId) || session.isClosingInventory()) {
|
||||
if ((session.getInventoryHolder() != null && session.getInventoryHolder().bedrockId() == bedrockId) || session.isClosingInventory()) {
|
||||
this.bedrockId += 1;
|
||||
}
|
||||
}
|
||||
|
@ -214,20 +193,4 @@ public abstract class Inventory {
|
|||
public boolean shouldConfirmContainerClose() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper methods to avoid using the wrong translator to update specific inventories.
|
||||
*/
|
||||
|
||||
public void updateInventory() {
|
||||
this.translator.updateInventory(session, this);
|
||||
}
|
||||
|
||||
public void updateProperty(int rawProperty, int value) {
|
||||
this.translator.updateProperty(session, this, rawProperty, value);
|
||||
}
|
||||
|
||||
public void updateSlot(int slot) {
|
||||
this.translator.updateSlot(session, this, slot);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Copyright (c) 2025 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.inventory;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequest;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A helper class storing the current inventory, translator, and session.
|
||||
*/
|
||||
@Accessors(fluent = true)
|
||||
@Getter
|
||||
public final class InventoryHolder<T extends Inventory> {
|
||||
private final GeyserSession session;
|
||||
private final T inventory;
|
||||
private final InventoryTranslator<T> translator;
|
||||
|
||||
/**
|
||||
* Whether this inventory is currently pending.
|
||||
* It can be pending if this inventory was opened while another inventory was still open,
|
||||
* or because opening this inventory takes more time (e.g. virtual inventories).
|
||||
*/
|
||||
@Setter
|
||||
private boolean pending;
|
||||
|
||||
/**
|
||||
* Stores the number of attempts to open virtual inventories.
|
||||
* Capped at 3, and isn't used in ideal circumstances.
|
||||
* Used to resolve <a href="https://github.com/GeyserMC/Geyser/issues/5426">container closing issues.</a>
|
||||
*/
|
||||
@Setter
|
||||
private int containerOpenAttempts;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public InventoryHolder(GeyserSession session, Inventory newInventory, InventoryTranslator<? extends Inventory> newTranslator) {
|
||||
this.session = session;
|
||||
this.inventory = (T) newInventory;
|
||||
this.translator = (InventoryTranslator<T>) newTranslator;
|
||||
}
|
||||
|
||||
public void markCurrent() {
|
||||
this.session.setInventoryHolder(this);
|
||||
}
|
||||
|
||||
public boolean shouldSetPending() {
|
||||
return session.isClosingInventory() || !session.getUpstream().isInitialized() || session.getPendingOrCurrentBedrockInventoryId() != -1;
|
||||
}
|
||||
|
||||
public boolean shouldConfirmClose(boolean confirm) {
|
||||
return confirm && inventory.isDisplayed() && !pending && !(inventory instanceof LecternContainer);
|
||||
}
|
||||
|
||||
public void inheritFromExisting(InventoryHolder<? extends Inventory> existing) {
|
||||
inventory.setBedrockId(existing.inventory.getBedrockId());
|
||||
|
||||
// Also mirror other properties - in case we're e.g. dealing with a pending virtual inventory
|
||||
this.pending = existing.pending();
|
||||
inventory.setDisplayed(existing.inventory().isDisplayed());
|
||||
inventory.setHolderPosition(existing.inventory().getHolderPosition());
|
||||
inventory.setHolderId(existing.inventory().getHolderId());
|
||||
this.markCurrent();
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper methods to avoid using the wrong translator to update specific inventories.
|
||||
*/
|
||||
|
||||
public void updateInventory() {
|
||||
this.translator.updateInventory(session, inventory);
|
||||
}
|
||||
|
||||
public void updateProperty(int rawProperty, int value) {
|
||||
this.translator.updateProperty(session, inventory, rawProperty, value);
|
||||
}
|
||||
|
||||
public void updateSlot(int slot) {
|
||||
this.translator.updateSlot(session, inventory, slot);
|
||||
}
|
||||
|
||||
public void openInventory() {
|
||||
this.translator.openInventory(session, inventory);
|
||||
this.pending = false;
|
||||
this.inventory.setDisplayed(true);
|
||||
}
|
||||
|
||||
public void closeInventory(boolean force) {
|
||||
this.translator.closeInventory(session, inventory, force);
|
||||
if (session.getContainerOutputFuture() != null) {
|
||||
session.getContainerOutputFuture().cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean requiresOpeningDelay() {
|
||||
return this.translator.requiresOpeningDelay(session, inventory);
|
||||
}
|
||||
|
||||
public boolean prepareInventory() {
|
||||
return this.translator.prepareInventory(session, inventory);
|
||||
}
|
||||
|
||||
public void translateRequests(List<ItemStackRequest> requests) {
|
||||
this.translator.translateRequests(session, inventory, requests);
|
||||
}
|
||||
|
||||
public GeyserSession session() {
|
||||
return session;
|
||||
}
|
||||
|
||||
public T inventory() {
|
||||
return inventory;
|
||||
}
|
||||
|
||||
public InventoryTranslator<T> translator() {
|
||||
return translator;
|
||||
}
|
||||
|
||||
public void incrementContainerOpenAttempts() {
|
||||
this.containerOpenAttempts++;
|
||||
}
|
||||
|
||||
public int javaId() {
|
||||
return inventory.getJavaId();
|
||||
}
|
||||
|
||||
public int bedrockId() {
|
||||
return inventory.getBedrockId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "InventoryHolder[" +
|
||||
"session=" + session + ", " +
|
||||
"inventory=" + inventory + ", " +
|
||||
"translator=" + translator + ']';
|
||||
}
|
||||
}
|
|
@ -27,11 +27,8 @@ package org.geysermc.geyser.inventory;
|
|||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.cloudburstmc.math.vector.Vector3i;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.java.inventory.JavaOpenBookTranslator;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
||||
|
||||
|
@ -41,33 +38,18 @@ public class LecternContainer extends Container {
|
|||
private int currentBedrockPage = 0;
|
||||
@Setter
|
||||
private NbtMap blockEntityTag;
|
||||
@Setter
|
||||
private Vector3i position;
|
||||
|
||||
private boolean isBookInPlayerInventory = false;
|
||||
|
||||
public LecternContainer(GeyserSession session, String title, int id, int size, ContainerType containerType, PlayerInventory playerInventory, InventoryTranslator translator) {
|
||||
super(session, title, id, size, containerType, playerInventory, translator);
|
||||
}
|
||||
|
||||
/**
|
||||
* When the Java server asks the client to open a book in their hotbar, we create a fake lectern to show it to the client.
|
||||
* We can't use the {@link #isUsingRealBlock()} check as we may also be dealing with a real virtual lectern (with its own inventory).
|
||||
*/
|
||||
@Override
|
||||
public void setItem(int slot, @NonNull GeyserItemStack newItem, GeyserSession session) {
|
||||
if (isBookInPlayerInventory) {
|
||||
session.getPlayerInventory().setItem(slot, newItem, session);
|
||||
} else {
|
||||
super.setItem(slot, newItem, session);
|
||||
}
|
||||
public LecternContainer(GeyserSession session, String title, int id, int size, ContainerType containerType) {
|
||||
super(session, title, id, size, containerType);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used ONLY once to set the book of a fake lectern in {@link JavaOpenBookTranslator}.
|
||||
* See {@link LecternContainer#setItem(int, GeyserItemStack, GeyserSession)} as for why this is separate.
|
||||
*/
|
||||
public void setFakeLecternBook(GeyserItemStack book, GeyserSession session) {
|
||||
public void setVirtualLecternBook(GeyserItemStack book, GeyserSession session) {
|
||||
this.isBookInPlayerInventory = true;
|
||||
super.setItem(0, book, session);
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ import lombok.Setter;
|
|||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||
import org.geysermc.geyser.entity.type.Entity;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.inventory.VillagerTrade;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundMerchantOffersPacket;
|
||||
|
@ -47,8 +46,8 @@ public class MerchantContainer extends Container {
|
|||
@Getter
|
||||
private int tradeExperience;
|
||||
|
||||
public MerchantContainer(GeyserSession session, String title, int id, int size, ContainerType containerType, PlayerInventory playerInventory, InventoryTranslator translator) {
|
||||
super(session, title, id, size, containerType, playerInventory, translator);
|
||||
public MerchantContainer(GeyserSession session, String title, int id, int size, ContainerType containerType) {
|
||||
super(session, title, id, size, containerType);
|
||||
}
|
||||
|
||||
public void onTradeSelected(GeyserSession session, int slot) {
|
||||
|
|
|
@ -31,7 +31,6 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
|
@ -48,7 +47,7 @@ public class PlayerInventory extends Inventory {
|
|||
private GeyserItemStack cursor = GeyserItemStack.EMPTY;
|
||||
|
||||
public PlayerInventory(GeyserSession session) {
|
||||
super(session, 0, 46, null, InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR);
|
||||
super(session, 0, 46, null);
|
||||
heldItemSlot = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@ import lombok.Getter;
|
|||
import lombok.Setter;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
||||
|
||||
@Setter
|
||||
|
@ -40,8 +39,8 @@ public class StonecutterContainer extends Container {
|
|||
*/
|
||||
private int stonecutterButton = -1;
|
||||
|
||||
public StonecutterContainer(GeyserSession session, String title, int id, int size, ContainerType containerType, PlayerInventory playerInventory, InventoryTranslator translator) {
|
||||
super(session, title, id, size, containerType, playerInventory, translator);
|
||||
public StonecutterContainer(GeyserSession session, String title, int id, int size, ContainerType containerType) {
|
||||
super(session, title, id, size, containerType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -66,11 +66,11 @@ public final class ClickPlan {
|
|||
private boolean executionBegan;
|
||||
|
||||
private final GeyserSession session;
|
||||
private final InventoryTranslator translator;
|
||||
private final InventoryTranslator<?> translator;
|
||||
private final Inventory inventory;
|
||||
private final int gridSize;
|
||||
|
||||
public ClickPlan(GeyserSession session, InventoryTranslator translator, Inventory inventory) {
|
||||
public ClickPlan(GeyserSession session, InventoryTranslator<?> translator, Inventory inventory) {
|
||||
this.session = session;
|
||||
this.translator = translator;
|
||||
this.inventory = inventory;
|
||||
|
|
|
@ -90,15 +90,15 @@ public class BlockInventoryHolder extends InventoryHolder {
|
|||
if (Objects.equals(position, previous.getHolderPosition())) {
|
||||
return true;
|
||||
} else {
|
||||
GeyserImpl.getInstance().getLogger().debug(session, "Not reusing inventory (%s) due to virtual block holder changing (%s -> %s)!",
|
||||
InventoryUtils.debugInventory(container), previous.getHolderPosition(), position);
|
||||
GeyserImpl.getInstance().getLogger().debug(session, "Not reusing inventory due to virtual block holder changing (%s -> %s)!",
|
||||
previous.getHolderPosition(), position);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean prepareInventory(GeyserSession session, Container inventory) {
|
||||
if (canUseRealBlock(session, inventory)) {
|
||||
public boolean prepareInventory(GeyserSession session, Container container) {
|
||||
if (canUseRealBlock(session, container)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -113,14 +113,14 @@ public class BlockInventoryHolder extends InventoryHolder {
|
|||
blockPacket.setDefinition(session.getBlockMappings().getVanillaBedrockBlock(defaultJavaBlockState));
|
||||
blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
|
||||
session.sendUpstreamPacket(blockPacket);
|
||||
inventory.setHolderPosition(position);
|
||||
container.setHolderPosition(position);
|
||||
|
||||
setCustomName(session, position, inventory, defaultJavaBlockState);
|
||||
setCustomName(session, position, container, defaultJavaBlockState);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean canUseRealBlock(GeyserSession session, Container inventory) {
|
||||
protected boolean canUseRealBlock(GeyserSession session, Container container) {
|
||||
// Check to see if there is an existing block we can use that the player just selected.
|
||||
// First, verify that the player's position has not changed, so we don't try to select a block wildly out of range.
|
||||
// (This could be a virtual inventory that the player is opening)
|
||||
|
@ -131,9 +131,9 @@ public class BlockInventoryHolder extends InventoryHolder {
|
|||
if (!BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.get().containsKey(state.javaId())) {
|
||||
if (isValidBlock(state)) {
|
||||
// We can safely use this block
|
||||
inventory.setHolderPosition(session.getLastInteractionBlockPosition());
|
||||
inventory.setUsingRealBlock(true, state.block());
|
||||
setCustomName(session, session.getLastInteractionBlockPosition(), inventory, state);
|
||||
container.setHolderPosition(session.getLastInteractionBlockPosition());
|
||||
container.setUsingRealBlock(true, state.block());
|
||||
setCustomName(session, session.getLastInteractionBlockPosition(), container, state);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -30,8 +30,8 @@ import org.geysermc.geyser.inventory.Container;
|
|||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
||||
public abstract class InventoryHolder {
|
||||
public abstract boolean canReuseContainer(GeyserSession session, Container inventory, Container oldInventory);
|
||||
public abstract boolean prepareInventory(GeyserSession session, Container inventory);
|
||||
public abstract void openInventory(GeyserSession session, Container inventory);
|
||||
public abstract void closeInventory(GeyserSession session, Container inventory, ContainerType containerType);
|
||||
public abstract boolean canReuseContainer(GeyserSession session, Container container, Container oldInventory);
|
||||
public abstract boolean prepareInventory(GeyserSession session, Container container);
|
||||
public abstract void openInventory(GeyserSession session, Container container);
|
||||
public abstract void closeInventory(GeyserSession session, Container container, ContainerType containerType);
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
|
|||
private static final int MAX_LEVEL_COST = 40;
|
||||
|
||||
@Override
|
||||
public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {
|
||||
public void updateInventory(InventoryTranslator<?> translator, GeyserSession session, Inventory inventory) {
|
||||
super.updateInventory(translator, session, inventory);
|
||||
AnvilContainer anvilContainer = (AnvilContainer) inventory;
|
||||
updateInventoryState(session, anvilContainer);
|
||||
|
@ -82,7 +82,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean updateSlot(InventoryTranslator translator, GeyserSession session, Inventory inventory, int javaSlot) {
|
||||
public boolean updateSlot(InventoryTranslator<?> translator, GeyserSession session, Inventory inventory, int javaSlot) {
|
||||
if (super.updateSlot(translator, session, inventory, javaSlot))
|
||||
return true;
|
||||
AnvilContainer anvilContainer = (AnvilContainer) inventory;
|
||||
|
@ -151,7 +151,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
|
|||
return 0;
|
||||
}
|
||||
|
||||
private void updateTargetSlot(InventoryTranslator translator, GeyserSession session, AnvilContainer anvilContainer, int slot) {
|
||||
private void updateTargetSlot(InventoryTranslator<?> translator, GeyserSession session, AnvilContainer anvilContainer, int slot) {
|
||||
ItemData itemData = anvilContainer.getItem(slot).getItemData(session);
|
||||
itemData = hijackRepairCost(session, anvilContainer, itemData);
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ public class ChestInventoryUpdater extends InventoryUpdater {
|
|||
private final int paddedSize;
|
||||
|
||||
@Override
|
||||
public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {
|
||||
public void updateInventory(InventoryTranslator<?> translator, GeyserSession session, Inventory inventory) {
|
||||
super.updateInventory(translator, session, inventory);
|
||||
|
||||
List<ItemData> bedrockItems = new ArrayList<>(paddedSize);
|
||||
|
@ -65,7 +65,7 @@ public class ChestInventoryUpdater extends InventoryUpdater {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean updateSlot(InventoryTranslator translator, GeyserSession session, Inventory inventory, int javaSlot) {
|
||||
public boolean updateSlot(InventoryTranslator<?> translator, GeyserSession session, Inventory inventory, int javaSlot) {
|
||||
if (super.updateSlot(translator, session, inventory, javaSlot))
|
||||
return true;
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ public class ContainerInventoryUpdater extends InventoryUpdater {
|
|||
public static final ContainerInventoryUpdater INSTANCE = new ContainerInventoryUpdater();
|
||||
|
||||
@Override
|
||||
public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {
|
||||
public void updateInventory(InventoryTranslator<?> translator, GeyserSession session, Inventory inventory) {
|
||||
super.updateInventory(translator, session, inventory);
|
||||
|
||||
ItemData[] bedrockItems = new ItemData[translator.size];
|
||||
|
@ -53,7 +53,7 @@ public class ContainerInventoryUpdater extends InventoryUpdater {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean updateSlot(InventoryTranslator translator, GeyserSession session, Inventory inventory, int javaSlot) {
|
||||
public boolean updateSlot(InventoryTranslator<?> translator, GeyserSession session, Inventory inventory, int javaSlot) {
|
||||
if (super.updateSlot(translator, session, inventory, javaSlot))
|
||||
return true;
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ public class CrafterInventoryUpdater extends InventoryUpdater {
|
|||
public static final CrafterInventoryUpdater INSTANCE = new CrafterInventoryUpdater();
|
||||
|
||||
@Override
|
||||
public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {
|
||||
public void updateInventory(InventoryTranslator<?> translator, GeyserSession session, Inventory inventory) {
|
||||
ItemData[] bedrockItems;
|
||||
InventoryContentPacket contentPacket;
|
||||
|
||||
|
@ -74,7 +74,7 @@ public class CrafterInventoryUpdater extends InventoryUpdater {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean updateSlot(InventoryTranslator translator, GeyserSession session, Inventory inventory, int javaSlot) {
|
||||
public boolean updateSlot(InventoryTranslator<?> translator, GeyserSession session, Inventory inventory, int javaSlot) {
|
||||
int containerId;
|
||||
if (javaSlot < CrafterInventoryTranslator.GRID_SIZE || javaSlot == CrafterInventoryTranslator.JAVA_RESULT_SLOT) {
|
||||
// Parts of the Crafter UI
|
||||
|
|
|
@ -38,7 +38,7 @@ public class HorseInventoryUpdater extends InventoryUpdater {
|
|||
public static final HorseInventoryUpdater INSTANCE = new HorseInventoryUpdater();
|
||||
|
||||
@Override
|
||||
public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {
|
||||
public void updateInventory(InventoryTranslator<?> translator, GeyserSession session, Inventory inventory) {
|
||||
super.updateInventory(translator, session, inventory);
|
||||
|
||||
ItemData[] bedrockItems = new ItemData[translator.size];
|
||||
|
@ -53,7 +53,7 @@ public class HorseInventoryUpdater extends InventoryUpdater {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean updateSlot(InventoryTranslator translator, GeyserSession session, Inventory inventory, int javaSlot) {
|
||||
public boolean updateSlot(InventoryTranslator<?> translator, GeyserSession session, Inventory inventory, int javaSlot) {
|
||||
if (super.updateSlot(translator, session, inventory, javaSlot))
|
||||
return true;
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
|||
import java.util.Arrays;
|
||||
|
||||
public class InventoryUpdater {
|
||||
public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {
|
||||
public void updateInventory(InventoryTranslator<?> translator, GeyserSession session, Inventory inventory) {
|
||||
ItemData[] bedrockItems = new ItemData[36];
|
||||
for (int i = 0; i < 36; i++) {
|
||||
final int offset = i < 9 ? 27 : -9;
|
||||
|
@ -48,7 +48,7 @@ public class InventoryUpdater {
|
|||
session.sendUpstreamPacket(contentPacket);
|
||||
}
|
||||
|
||||
public boolean updateSlot(InventoryTranslator translator, GeyserSession session, Inventory inventory, int javaSlot) {
|
||||
public boolean updateSlot(InventoryTranslator<?> translator, GeyserSession session, Inventory inventory, int javaSlot) {
|
||||
if (javaSlot >= translator.size) {
|
||||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||
slotPacket.setContainerId(ContainerId.INVENTORY);
|
||||
|
|
|
@ -35,7 +35,7 @@ public class UIInventoryUpdater extends InventoryUpdater {
|
|||
public static final UIInventoryUpdater INSTANCE = new UIInventoryUpdater();
|
||||
|
||||
@Override
|
||||
public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {
|
||||
public void updateInventory(InventoryTranslator<?> translator, GeyserSession session, Inventory inventory) {
|
||||
super.updateInventory(translator, session, inventory);
|
||||
|
||||
for (int i = 0; i < translator.size; i++) {
|
||||
|
@ -51,7 +51,7 @@ public class UIInventoryUpdater extends InventoryUpdater {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean updateSlot(InventoryTranslator translator, GeyserSession session, Inventory inventory, int javaSlot) {
|
||||
public boolean updateSlot(InventoryTranslator<?> translator, GeyserSession session, Inventory inventory, int javaSlot) {
|
||||
if (super.updateSlot(translator, session, inventory, javaSlot))
|
||||
return true;
|
||||
|
||||
|
|
|
@ -139,6 +139,8 @@ import org.geysermc.geyser.event.type.SessionDisconnectEventImpl;
|
|||
import org.geysermc.geyser.impl.camera.CameraDefinitions;
|
||||
import org.geysermc.geyser.impl.camera.GeyserCameraData;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.InventoryHolder;
|
||||
import org.geysermc.geyser.inventory.LecternContainer;
|
||||
import org.geysermc.geyser.inventory.PlayerInventory;
|
||||
import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
|
||||
import org.geysermc.geyser.inventory.recipe.GeyserSmithingRecipe;
|
||||
|
@ -175,6 +177,8 @@ import org.geysermc.geyser.session.cache.WorldBorder;
|
|||
import org.geysermc.geyser.session.cache.WorldCache;
|
||||
import org.geysermc.geyser.session.cache.registry.JavaRegistries;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.geyser.translator.inventory.PlayerInventoryTranslator;
|
||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||
import org.geysermc.geyser.util.ChunkUtils;
|
||||
import org.geysermc.geyser.util.EntityUtils;
|
||||
|
@ -290,11 +294,24 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||
*/
|
||||
private boolean isInWorldBorderWarningArea = false;
|
||||
|
||||
private final PlayerInventory playerInventory;
|
||||
/**
|
||||
* Stores the player inventory and player inventory translator
|
||||
*/
|
||||
private final InventoryHolder<PlayerInventory> playerInventoryHolder;
|
||||
|
||||
/**
|
||||
* Stores the current open Bedrock inventory, including the correct translator.
|
||||
* Prefer using {@link InventoryUtils#getInventory(GeyserSession, int)}, as this
|
||||
* method can e.g. return a {@code InventoryHolder<LecternContainer>} due to the
|
||||
* workaround in {@link LecternContainer#isBookInPlayerInventory()} workaround.
|
||||
*/
|
||||
@Setter
|
||||
private @Nullable Inventory openInventory;
|
||||
private @Nullable InventoryHolder<? extends Inventory> inventoryHolder;
|
||||
|
||||
/**
|
||||
* Whether the client is currently closing an inventory.
|
||||
* Used to open new inventories while another one is currently open.
|
||||
*/
|
||||
@Setter
|
||||
private boolean closingInventory;
|
||||
|
||||
|
@ -532,14 +549,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||
@Setter
|
||||
private boolean placedBucket;
|
||||
|
||||
/**
|
||||
* Stores whether the Java server requested the player inventory to be closed.
|
||||
* Used to prevent our hacky player inventory closing workaround in {@link org.geysermc.geyser.translator.inventory.PlayerInventoryTranslator#closeInventory(GeyserSession, Inventory)}
|
||||
* to run when the closing is initated by the Bedrock client.
|
||||
*/
|
||||
@Setter
|
||||
private boolean serverRequestedClosePlayerInventory;
|
||||
|
||||
/**
|
||||
* Counts how many ticks have occurred since an arm animation started.
|
||||
* -1 means there is no active arm swing
|
||||
|
@ -681,15 +690,6 @@ 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;
|
||||
this.upstream = new UpstreamSession(bedrockServerSession);
|
||||
|
@ -723,8 +723,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||
this.playerEntity = new SessionPlayerEntity(this);
|
||||
collisionManager.updatePlayerBoundingBox(this.playerEntity.getPosition());
|
||||
|
||||
this.playerInventory = new PlayerInventory(this);
|
||||
this.openInventory = null;
|
||||
this.playerInventoryHolder = new InventoryHolder<>(this, new PlayerInventory(this), InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR);
|
||||
this.inventoryHolder = null;
|
||||
this.craftingRecipes = new Int2ObjectOpenHashMap<>();
|
||||
this.javaToBedrockRecipeIds = new Int2ObjectOpenHashMap<>();
|
||||
this.lastRecipeNetId = new AtomicInteger(InventoryUtils.LAST_RECIPE_NET_ID + 1);
|
||||
|
@ -1239,10 +1239,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||
worldTicks++;
|
||||
}
|
||||
|
||||
public void setAuthenticationData(AuthData authData) {
|
||||
this.authData = authData;
|
||||
}
|
||||
|
||||
public void startSneaking() {
|
||||
// Toggle the shield, if there is no ongoing arm animation
|
||||
// This matches Bedrock Edition behavior as of 1.18.12
|
||||
|
@ -1332,8 +1328,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||
|
||||
public void setClientData(BedrockClientData data) {
|
||||
this.clientData = data;
|
||||
this.inputCache.setInputMode(
|
||||
org.cloudburstmc.protocol.bedrock.data.InputMode.values()[data.getCurrentInputMode().ordinal()]);
|
||||
this.inputCache.setInputMode(org.cloudburstmc.protocol.bedrock.data.InputMode.values()[data.getCurrentInputMode().ordinal()]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1356,9 +1351,9 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||
* blocking and sends a packet to the Java server.
|
||||
*/
|
||||
private boolean attemptToBlock() {
|
||||
if (playerInventory.getItemInHand().asItem() == Items.SHIELD) {
|
||||
if (playerInventoryHolder.inventory().getItemInHand().asItem() == Items.SHIELD) {
|
||||
useItem(Hand.MAIN_HAND);
|
||||
} else if (playerInventory.getOffhand().asItem() == Items.SHIELD) {
|
||||
} else if (playerInventoryHolder.inventory().getOffhand().asItem() == Items.SHIELD) {
|
||||
useItem(Hand.OFF_HAND);
|
||||
} else {
|
||||
// No blocking
|
||||
|
@ -1507,6 +1502,17 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||
return true;
|
||||
}
|
||||
|
||||
public @NonNull PlayerInventory getPlayerInventory() {
|
||||
return this.playerInventoryHolder.inventory();
|
||||
}
|
||||
|
||||
public @Nullable Inventory getOpenInventory() {
|
||||
if (this.inventoryHolder == null) {
|
||||
return null;
|
||||
}
|
||||
return this.inventoryHolder.inventory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendForm(@NonNull FormBuilder<?, ?, ?> formBuilder) {
|
||||
formCache.showForm(formBuilder.build());
|
||||
|
|
|
@ -40,7 +40,7 @@ import org.geysermc.geyser.session.GeyserSession;
|
|||
/**
|
||||
* Provided as a base for any inventory that requires a block for opening it
|
||||
*/
|
||||
public abstract class AbstractBlockInventoryTranslator extends BaseInventoryTranslator {
|
||||
public abstract class AbstractBlockInventoryTranslator<Type extends Container> extends BaseInventoryTranslator<Type> {
|
||||
private final InventoryHolder holder;
|
||||
private final InventoryUpdater updater;
|
||||
|
||||
|
@ -78,43 +78,44 @@ public abstract class AbstractBlockInventoryTranslator extends BaseInventoryTran
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresOpeningDelay(GeyserSession session, Inventory inventory) {
|
||||
return inventory instanceof Container container && !container.isUsingRealBlock();
|
||||
public boolean requiresOpeningDelay(GeyserSession session, Type container) {
|
||||
return !container.isUsingRealBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canReuseInventory(GeyserSession session, @NonNull Inventory inventory, @NonNull Inventory previous) {
|
||||
if (super.canReuseInventory(session, inventory, previous)
|
||||
&& inventory instanceof Container container
|
||||
&& previous instanceof Container previousContainer) {
|
||||
public boolean canReuseInventory(GeyserSession session, @NonNull Inventory newInventory, @NonNull Inventory previous) {
|
||||
if (super.canReuseInventory(session, newInventory, previous)
|
||||
&& newInventory instanceof Container container
|
||||
&& previous instanceof Container previousContainer
|
||||
) {
|
||||
return holder.canReuseContainer(session, container, previousContainer);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean prepareInventory(GeyserSession session, Inventory inventory) {
|
||||
return holder.prepareInventory(session, (Container) inventory);
|
||||
public boolean prepareInventory(GeyserSession session, Type container) {
|
||||
return holder.prepareInventory(session, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openInventory(GeyserSession session, Inventory inventory) {
|
||||
holder.openInventory(session, (Container) inventory);
|
||||
public void openInventory(GeyserSession session, Type container) {
|
||||
holder.openInventory(session, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeInventory(GeyserSession session, Inventory inventory) {
|
||||
holder.closeInventory(session, (Container) inventory, closeContainerType(inventory));
|
||||
public void closeInventory(GeyserSession session, Type container, boolean force) {
|
||||
holder.closeInventory(session, container, closeContainerType(container));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateInventory(GeyserSession session, Inventory inventory) {
|
||||
updater.updateInventory(this, session, inventory);
|
||||
public void updateInventory(GeyserSession session, Type container) {
|
||||
updater.updateInventory(this, session, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSlot(GeyserSession session, Inventory inventory, int slot) {
|
||||
updater.updateSlot(this, session, inventory, slot);
|
||||
public void updateSlot(GeyserSession session, Type container, int slot) {
|
||||
updater.updateSlot(this, session, container, slot);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -122,5 +123,5 @@ public abstract class AbstractBlockInventoryTranslator extends BaseInventoryTran
|
|||
But only for some blocks! And some blocks only respond to specific container types (dispensers/droppers now require the specific type...)
|
||||
When this returns null, we just... break the block, and replace it. Primitive. But if that works... fine.
|
||||
*/
|
||||
public abstract @Nullable ContainerType closeContainerType(Inventory inventory);
|
||||
public abstract @Nullable ContainerType closeContainerType(Type container);
|
||||
}
|
||||
|
|
|
@ -35,8 +35,6 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action
|
|||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponse;
|
||||
import org.geysermc.geyser.inventory.AnvilContainer;
|
||||
import org.geysermc.geyser.inventory.BedrockContainerSlot;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.PlayerInventory;
|
||||
import org.geysermc.geyser.inventory.updater.AnvilInventoryUpdater;
|
||||
import org.geysermc.geyser.level.block.Blocks;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
@ -44,22 +42,21 @@ import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
|||
|
||||
import java.util.Objects;
|
||||
|
||||
public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator {
|
||||
public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator<AnvilContainer> {
|
||||
public AnvilInventoryTranslator() {
|
||||
super(3, Blocks.ANVIL, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.ANVIL, AnvilInventoryUpdater.INSTANCE,
|
||||
Blocks.CHIPPED_ANVIL, Blocks.DAMAGED_ANVIL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldHandleRequestFirst(ItemStackRequestAction action, Inventory inventory) {
|
||||
protected boolean shouldHandleRequestFirst(ItemStackRequestAction action, AnvilContainer container) {
|
||||
return action.getType() == ItemStackRequestActionType.CRAFT_RECIPE_OPTIONAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ItemStackResponse translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
|
||||
protected ItemStackResponse translateSpecialRequest(GeyserSession session, AnvilContainer container, ItemStackRequest request) {
|
||||
// Guarded by shouldHandleRequestFirst check
|
||||
CraftRecipeOptionalAction data = (CraftRecipeOptionalAction) request.getActions()[0];
|
||||
AnvilContainer container = (AnvilContainer) inventory;
|
||||
|
||||
if (request.getFilterStrings().length != 0) {
|
||||
// Required as of 1.18.30 - FilterTextPackets no longer appear to be sent
|
||||
|
@ -69,7 +66,7 @@ public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator {
|
|||
}
|
||||
}
|
||||
|
||||
return super.translateRequest(session, inventory, request);
|
||||
return super.translateRequest(session, container, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -83,12 +80,12 @@ public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot, AnvilContainer container) {
|
||||
return switch (slot) {
|
||||
case 0 -> new BedrockContainerSlot(ContainerSlotType.ANVIL_INPUT, 1);
|
||||
case 1 -> new BedrockContainerSlot(ContainerSlotType.ANVIL_MATERIAL, 2);
|
||||
case 2 -> new BedrockContainerSlot(ContainerSlotType.ANVIL_RESULT, 50);
|
||||
default -> super.javaSlotToBedrockContainer(slot);
|
||||
default -> super.javaSlotToBedrockContainer(slot, container);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -103,22 +100,21 @@ public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Inventory createInventory(GeyserSession session, String name, int windowId, ContainerType containerType, PlayerInventory playerInventory) {
|
||||
return new AnvilContainer(session, name, windowId, this.size, containerType, playerInventory, this);
|
||||
public AnvilContainer createInventory(GeyserSession session, String name, int windowId, ContainerType containerType) {
|
||||
return new AnvilContainer(session, name, windowId, this.size, containerType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) {
|
||||
public void updateProperty(GeyserSession session, AnvilContainer container, int key, int value) {
|
||||
// The only property sent by Java is key 0 which is the level cost
|
||||
if (key != 0) return;
|
||||
AnvilContainer anvilContainer = (AnvilContainer) inventory;
|
||||
anvilContainer.setJavaLevelCost(value);
|
||||
anvilContainer.setUseJavaLevelCost(true);
|
||||
updateSlot(session, anvilContainer, 1);
|
||||
container.setJavaLevelCost(value);
|
||||
container.setUseJavaLevelCost(true);
|
||||
updateSlot(session, container, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.cloudburstmc.protocol.bedrock.data.inventory.@Nullable ContainerType closeContainerType(Inventory inventory) {
|
||||
public org.cloudburstmc.protocol.bedrock.data.inventory.@Nullable ContainerType closeContainerType(AnvilContainer container) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,17 +27,19 @@ package org.geysermc.geyser.translator.inventory;
|
|||
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
|
||||
import org.geysermc.geyser.inventory.*;
|
||||
import org.geysermc.geyser.inventory.BedrockContainerSlot;
|
||||
import org.geysermc.geyser.inventory.Container;
|
||||
import org.geysermc.geyser.inventory.SlotType;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
||||
|
||||
public abstract class BaseInventoryTranslator extends InventoryTranslator {
|
||||
public abstract class BaseInventoryTranslator<Type extends Container> extends InventoryTranslator<Type> {
|
||||
public BaseInventoryTranslator(int size) {
|
||||
super(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) {
|
||||
public void updateProperty(GeyserSession session, Type container, int key, int value) {
|
||||
//
|
||||
}
|
||||
|
||||
|
@ -72,7 +74,7 @@ public abstract class BaseInventoryTranslator extends InventoryTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot, Type inventory) {
|
||||
if (slot >= this.size) {
|
||||
final int tmp = slot - this.size;
|
||||
if (tmp < 27) {
|
||||
|
@ -90,7 +92,8 @@ public abstract class BaseInventoryTranslator extends InventoryTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Inventory createInventory(GeyserSession session, String name, int windowId, ContainerType containerType, PlayerInventory playerInventory) {
|
||||
return new Container(session, name, windowId, this.size, containerType, playerInventory, this);
|
||||
public Type createInventory(GeyserSession session, String name, int windowId, ContainerType containerType) {
|
||||
//noinspection unchecked
|
||||
return (Type) new Container(session, name, windowId, this.size, containerType);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,8 +39,6 @@ import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;
|
|||
import org.geysermc.geyser.inventory.BeaconContainer;
|
||||
import org.geysermc.geyser.inventory.BedrockContainerSlot;
|
||||
import org.geysermc.geyser.inventory.Container;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.PlayerInventory;
|
||||
import org.geysermc.geyser.inventory.holder.BlockInventoryHolder;
|
||||
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
|
||||
import org.geysermc.geyser.level.block.Blocks;
|
||||
|
@ -52,7 +50,7 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.S
|
|||
|
||||
import java.util.OptionalInt;
|
||||
|
||||
public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator {
|
||||
public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator<BeaconContainer> {
|
||||
public BeaconInventoryTranslator() {
|
||||
super(1, new BlockInventoryHolder(Blocks.BEACON, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.BEACON) {
|
||||
@Override
|
||||
|
@ -73,28 +71,27 @@ public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator
|
|||
}
|
||||
|
||||
@Override
|
||||
public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) {
|
||||
public void updateProperty(GeyserSession session, BeaconContainer container, int key, int value) {
|
||||
//FIXME?: Beacon graphics look weird after inputting an item. This might be a Bedrock bug, since it resets to nothing
|
||||
// on BDS
|
||||
BeaconContainer beaconContainer = (BeaconContainer) inventory;
|
||||
switch (key) {
|
||||
case 0:
|
||||
// Power - beacon doesn't use this, and uses the block position instead
|
||||
break;
|
||||
case 1:
|
||||
beaconContainer.setPrimaryId(value == -1 ? 0 : value);
|
||||
container.setPrimaryId(value == -1 ? 0 : value);
|
||||
break;
|
||||
case 2:
|
||||
beaconContainer.setSecondaryId(value == -1 ? 0 : value);
|
||||
container.setSecondaryId(value == -1 ? 0 : value);
|
||||
break;
|
||||
}
|
||||
|
||||
// Send a block entity data packet update to the fake beacon inventory
|
||||
Vector3i position = inventory.getHolderPosition();
|
||||
Vector3i position = container.getHolderPosition();
|
||||
NbtMapBuilder builder = BlockEntityTranslator.getConstantBedrockTag("Beacon", position)
|
||||
.putString("CustomName", inventory.getTitle())
|
||||
.putInt("primary", beaconContainer.getPrimaryId())
|
||||
.putInt("secondary", beaconContainer.getSecondaryId());
|
||||
.putString("CustomName", container.getTitle())
|
||||
.putInt("primary", container.getPrimaryId())
|
||||
.putInt("secondary", container.getSecondaryId());
|
||||
|
||||
BlockEntityDataPacket packet = new BlockEntityDataPacket();
|
||||
packet.setBlockPosition(position);
|
||||
|
@ -103,17 +100,17 @@ public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldHandleRequestFirst(ItemStackRequestAction action, Inventory inventory) {
|
||||
protected boolean shouldHandleRequestFirst(ItemStackRequestAction action, BeaconContainer container) {
|
||||
return action.getType() == ItemStackRequestActionType.BEACON_PAYMENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStackResponse translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
|
||||
public ItemStackResponse translateSpecialRequest(GeyserSession session, BeaconContainer container, ItemStackRequest request) {
|
||||
// Input a beacon payment
|
||||
BeaconPaymentAction beaconPayment = (BeaconPaymentAction) request.getActions()[0];
|
||||
ServerboundSetBeaconPacket packet = new ServerboundSetBeaconPacket(toJava(beaconPayment.getPrimaryEffect()), toJava(beaconPayment.getSecondaryEffect()));
|
||||
session.sendDownstreamGamePacket(packet);
|
||||
return acceptRequest(request, makeContainerEntries(session, inventory, IntSets.emptySet()));
|
||||
return acceptRequest(request, makeContainerEntries(session, container, IntSets.emptySet()));
|
||||
}
|
||||
|
||||
private OptionalInt toJava(int effectChoice) {
|
||||
|
@ -129,11 +126,11 @@ public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator
|
|||
}
|
||||
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot, BeaconContainer container) {
|
||||
if (slot == 0) {
|
||||
return new BedrockContainerSlot(ContainerSlotType.BEACON_PAYMENT, 27);
|
||||
}
|
||||
return super.javaSlotToBedrockContainer(slot);
|
||||
return super.javaSlotToBedrockContainer(slot, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -145,12 +142,12 @@ public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator
|
|||
}
|
||||
|
||||
@Override
|
||||
public Inventory createInventory(GeyserSession session, String name, int windowId, ContainerType containerType, PlayerInventory playerInventory) {
|
||||
return new BeaconContainer(session, name, windowId, this.size, containerType, playerInventory, this);
|
||||
public BeaconContainer createInventory(GeyserSession session, String name, int windowId, ContainerType containerType) {
|
||||
return new BeaconContainer(session, name, windowId, this.size, containerType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType closeContainerType(Inventory inventory) {
|
||||
public org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType closeContainerType(BeaconContainer container) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,13 +31,13 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
|
|||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ContainerSetDataPacket;
|
||||
import org.geysermc.geyser.inventory.BedrockContainerSlot;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.Container;
|
||||
import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater;
|
||||
import org.geysermc.geyser.level.block.Blocks;
|
||||
import org.geysermc.geyser.level.block.property.Properties;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
||||
public class BrewingInventoryTranslator extends AbstractBlockInventoryTranslator {
|
||||
public class BrewingInventoryTranslator extends AbstractBlockInventoryTranslator<Container> {
|
||||
public BrewingInventoryTranslator() {
|
||||
super(5, Blocks.BREWING_STAND.defaultBlockState()
|
||||
.withValue(Properties.HAS_BOTTLE_0, false)
|
||||
|
@ -46,19 +46,19 @@ public class BrewingInventoryTranslator extends AbstractBlockInventoryTranslator
|
|||
}
|
||||
|
||||
@Override
|
||||
public void openInventory(GeyserSession session, Inventory inventory) {
|
||||
super.openInventory(session, inventory);
|
||||
public void openInventory(GeyserSession session, Container container) {
|
||||
super.openInventory(session, container);
|
||||
ContainerSetDataPacket dataPacket = new ContainerSetDataPacket();
|
||||
dataPacket.setWindowId((byte) inventory.getBedrockId());
|
||||
dataPacket.setWindowId((byte) container.getBedrockId());
|
||||
dataPacket.setProperty(ContainerSetDataPacket.BREWING_STAND_FUEL_TOTAL);
|
||||
dataPacket.setValue(20);
|
||||
session.sendUpstreamPacket(dataPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) {
|
||||
public void updateProperty(GeyserSession session, Container container, int key, int value) {
|
||||
ContainerSetDataPacket dataPacket = new ContainerSetDataPacket();
|
||||
dataPacket.setWindowId((byte) inventory.getBedrockId());
|
||||
dataPacket.setWindowId((byte) container.getBedrockId());
|
||||
switch (key) {
|
||||
case 0:
|
||||
dataPacket.setProperty(ContainerSetDataPacket.BREWING_STAND_BREW_TIME);
|
||||
|
@ -99,17 +99,17 @@ public class BrewingInventoryTranslator extends AbstractBlockInventoryTranslator
|
|||
}
|
||||
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot, Container container) {
|
||||
return switch (slot) {
|
||||
case 0, 1, 2 -> new BedrockContainerSlot(ContainerSlotType.BREWING_RESULT, javaSlotToBedrock(slot));
|
||||
case 3 -> new BedrockContainerSlot(ContainerSlotType.BREWING_INPUT, 0);
|
||||
case 4 -> new BedrockContainerSlot(ContainerSlotType.BREWING_FUEL, 4);
|
||||
default -> super.javaSlotToBedrockContainer(slot);
|
||||
default -> super.javaSlotToBedrockContainer(slot, container);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ContainerType closeContainerType(Inventory inventory) {
|
||||
public @Nullable ContainerType closeContainerType(Container container) {
|
||||
return ContainerType.BREWING_STAND;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ public final class BundleInventoryTranslator {
|
|||
* @return a processed bundle interaction, or null to resume normal transaction handling.
|
||||
*/
|
||||
@Nullable
|
||||
static ItemStackResponse handleBundle(GeyserSession session, InventoryTranslator translator, Inventory inventory, ItemStackRequest request, boolean sendCreativePackets) {
|
||||
static <T extends Inventory> ItemStackResponse handleBundle(GeyserSession session, InventoryTranslator<T> translator, T inventory, ItemStackRequest request, boolean sendCreativePackets) {
|
||||
TransferItemStackRequestAction action = null;
|
||||
for (ItemStackRequestAction requestAction : request.getActions()) {
|
||||
if (requestAction instanceof SwapAction swapAction) {
|
||||
|
|
|
@ -35,21 +35,21 @@ import org.geysermc.geyser.level.block.Blocks;
|
|||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
||||
|
||||
public class CartographyInventoryTranslator extends AbstractBlockInventoryTranslator {
|
||||
public class CartographyInventoryTranslator extends AbstractBlockInventoryTranslator<CartographyContainer> {
|
||||
public CartographyInventoryTranslator() {
|
||||
super(3, Blocks.CARTOGRAPHY_TABLE, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.CARTOGRAPHY, UIInventoryUpdater.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, ContainerSlotType bedrockSourceContainer,
|
||||
protected boolean shouldRejectItemPlace(GeyserSession session, CartographyContainer container, ContainerSlotType bedrockSourceContainer,
|
||||
int javaSourceSlot, ContainerSlotType bedrockDestinationContainer, int javaDestinationSlot) {
|
||||
if (javaDestinationSlot == 0) {
|
||||
// Bedrock Edition can use paper or an empty map in slot 0
|
||||
GeyserItemStack itemStack = javaSourceSlot == -1 ? session.getPlayerInventory().getCursor() : inventory.getItem(javaSourceSlot);
|
||||
GeyserItemStack itemStack = javaSourceSlot == -1 ? session.getPlayerInventory().getCursor() : container.getItem(javaSourceSlot);
|
||||
return itemStack.asItem() == Items.PAPER || itemStack.asItem() == Items.MAP;
|
||||
} else if (javaDestinationSlot == 1) {
|
||||
// Bedrock Edition can use a compass to create locator maps, or use a filled map, in the ADDITIONAL slot
|
||||
GeyserItemStack itemStack = javaSourceSlot == -1 ? session.getPlayerInventory().getCursor() : inventory.getItem(javaSourceSlot);
|
||||
GeyserItemStack itemStack = javaSourceSlot == -1 ? session.getPlayerInventory().getCursor() : container.getItem(javaSourceSlot);
|
||||
return itemStack.asItem() == Items.COMPASS || itemStack.asItem() == Items.FILLED_MAP;
|
||||
}
|
||||
return false;
|
||||
|
@ -66,12 +66,12 @@ public class CartographyInventoryTranslator extends AbstractBlockInventoryTransl
|
|||
}
|
||||
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot, CartographyContainer container) {
|
||||
return switch (slot) {
|
||||
case 0 -> new BedrockContainerSlot(ContainerSlotType.CARTOGRAPHY_INPUT, 12);
|
||||
case 1 -> new BedrockContainerSlot(ContainerSlotType.CARTOGRAPHY_ADDITIONAL, 13);
|
||||
case 2 -> new BedrockContainerSlot(ContainerSlotType.CARTOGRAPHY_RESULT, 50);
|
||||
default -> super.javaSlotToBedrockContainer(slot);
|
||||
default -> super.javaSlotToBedrockContainer(slot, container);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -86,12 +86,12 @@ public class CartographyInventoryTranslator extends AbstractBlockInventoryTransl
|
|||
}
|
||||
|
||||
@Override
|
||||
public Inventory createInventory(GeyserSession session, String name, int windowId, ContainerType containerType, PlayerInventory playerInventory) {
|
||||
return new CartographyContainer(session, name, windowId, this.size, containerType, playerInventory, this);
|
||||
public CartographyContainer createInventory(GeyserSession session, String name, int windowId, ContainerType containerType) {
|
||||
return new CartographyContainer(session, name, windowId, this.size, containerType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.cloudburstmc.protocol.bedrock.data.inventory.@Nullable ContainerType closeContainerType(Inventory inventory) {
|
||||
public org.cloudburstmc.protocol.bedrock.data.inventory.@Nullable ContainerType closeContainerType(CartographyContainer container) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
|||
* cannot be used to calculate the inventory slot indices. The Translator and the Updater must then
|
||||
* override any methods that use the size for such calculations
|
||||
*/
|
||||
public class CrafterInventoryTranslator extends AbstractBlockInventoryTranslator {
|
||||
public class CrafterInventoryTranslator extends AbstractBlockInventoryTranslator<CrafterContainer> {
|
||||
|
||||
public static final int JAVA_RESULT_SLOT = 45;
|
||||
public static final int BEDROCK_RESULT_SLOT = 50;
|
||||
|
@ -58,10 +58,8 @@ public class CrafterInventoryTranslator extends AbstractBlockInventoryTranslator
|
|||
}
|
||||
|
||||
@Override
|
||||
public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) {
|
||||
public void updateProperty(GeyserSession session, CrafterContainer container, int key, int value) {
|
||||
// the slot bits and triggered state are sent here rather than in a BlockEntityDataPacket. Yippee.
|
||||
CrafterContainer container = (CrafterContainer) inventory;
|
||||
|
||||
if (key == TRIGGERED_KEY) {
|
||||
container.setTriggered(value == TRIGGERED);
|
||||
} else {
|
||||
|
@ -111,7 +109,7 @@ public class CrafterInventoryTranslator extends AbstractBlockInventoryTranslator
|
|||
}
|
||||
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int javaSlot) {
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int javaSlot, CrafterContainer container) {
|
||||
if (javaSlot == JAVA_RESULT_SLOT) {
|
||||
return new BedrockContainerSlot(ContainerSlotType.CRAFTER_BLOCK_CONTAINER, BEDROCK_RESULT_SLOT);
|
||||
}
|
||||
|
@ -139,9 +137,9 @@ public class CrafterInventoryTranslator extends AbstractBlockInventoryTranslator
|
|||
}
|
||||
|
||||
@Override
|
||||
public Inventory createInventory(GeyserSession session, String name, int windowId, ContainerType containerType, PlayerInventory playerInventory) {
|
||||
public CrafterContainer createInventory(GeyserSession session, String name, int windowId, ContainerType containerType) {
|
||||
// Java sends the triggered and slot bits incrementally through properties, which we store here
|
||||
return new CrafterContainer(session, name, windowId, this.size, containerType, playerInventory, this);
|
||||
return new CrafterContainer(session, name, windowId, this.size, containerType);
|
||||
}
|
||||
|
||||
private static void updateBlockEntity(GeyserSession session, CrafterContainer container) {
|
||||
|
@ -164,7 +162,7 @@ public class CrafterInventoryTranslator extends AbstractBlockInventoryTranslator
|
|||
}
|
||||
|
||||
@Override
|
||||
public org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType closeContainerType(Inventory inventory) {
|
||||
public org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType closeContainerType(CrafterContainer container) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,12 +29,12 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
|||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
|
||||
import org.geysermc.geyser.inventory.BedrockContainerSlot;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.Container;
|
||||
import org.geysermc.geyser.inventory.SlotType;
|
||||
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
|
||||
import org.geysermc.geyser.level.block.Blocks;
|
||||
|
||||
public class CraftingInventoryTranslator extends AbstractBlockInventoryTranslator {
|
||||
public class CraftingInventoryTranslator extends AbstractBlockInventoryTranslator<Container> {
|
||||
public CraftingInventoryTranslator() {
|
||||
super(10, Blocks.CRAFTING_TABLE, ContainerType.WORKBENCH, UIInventoryUpdater.INSTANCE);
|
||||
}
|
||||
|
@ -53,14 +53,14 @@ public class CraftingInventoryTranslator extends AbstractBlockInventoryTranslato
|
|||
}
|
||||
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot, Container container) {
|
||||
if (isCraftingGrid(slot)) {
|
||||
return new BedrockContainerSlot(ContainerSlotType.CRAFTING_INPUT, slot + 31);
|
||||
}
|
||||
if (slot == 0) {
|
||||
return new BedrockContainerSlot(ContainerSlotType.CRAFTING_OUTPUT, 0);
|
||||
}
|
||||
return super.javaSlotToBedrockContainer(slot);
|
||||
return super.javaSlotToBedrockContainer(slot, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -89,7 +89,7 @@ public class CraftingInventoryTranslator extends AbstractBlockInventoryTranslato
|
|||
}
|
||||
|
||||
@Override
|
||||
public ContainerType closeContainerType(Inventory inventory) {
|
||||
public ContainerType closeContainerType(Container container) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,15 +47,14 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.S
|
|||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class EnchantingInventoryTranslator extends AbstractBlockInventoryTranslator {
|
||||
public class EnchantingInventoryTranslator extends AbstractBlockInventoryTranslator<EnchantingContainer> {
|
||||
public EnchantingInventoryTranslator() {
|
||||
super(2, Blocks.ENCHANTING_TABLE, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.ENCHANTMENT, UIInventoryUpdater.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) {
|
||||
public void updateProperty(GeyserSession session, EnchantingContainer container, int key, int value) {
|
||||
int slotToUpdate;
|
||||
EnchantingContainer enchantingInventory = (EnchantingContainer) inventory;
|
||||
boolean shouldUpdate = false;
|
||||
switch (key) {
|
||||
case 0:
|
||||
|
@ -63,7 +62,7 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla
|
|||
case 2:
|
||||
// Experience required
|
||||
slotToUpdate = key;
|
||||
enchantingInventory.getGeyserEnchantOptions()[slotToUpdate].setXpCost(value);
|
||||
container.getGeyserEnchantOptions()[slotToUpdate].setXpCost(value);
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
|
@ -83,45 +82,44 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla
|
|||
bedrockIndex = -1;
|
||||
}
|
||||
}
|
||||
enchantingInventory.getGeyserEnchantOptions()[slotToUpdate].setEnchantIndex(bedrockIndex);
|
||||
container.getGeyserEnchantOptions()[slotToUpdate].setEnchantIndex(bedrockIndex);
|
||||
break;
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
// Enchantment level
|
||||
slotToUpdate = key - 7;
|
||||
enchantingInventory.getGeyserEnchantOptions()[slotToUpdate].setEnchantLevel(value);
|
||||
container.getGeyserEnchantOptions()[slotToUpdate].setEnchantLevel(value);
|
||||
shouldUpdate = true; // Java sends each property as its own packet, so let's only update after all properties have been sent
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
GeyserEnchantOption enchantOption = enchantingInventory.getGeyserEnchantOptions()[slotToUpdate];
|
||||
GeyserEnchantOption enchantOption = container.getGeyserEnchantOptions()[slotToUpdate];
|
||||
if (shouldUpdate && enchantOption.hasChanged()) {
|
||||
enchantingInventory.getEnchantOptions()[slotToUpdate] = enchantOption.build(session);
|
||||
container.getEnchantOptions()[slotToUpdate] = enchantOption.build(session);
|
||||
PlayerEnchantOptionsPacket packet = new PlayerEnchantOptionsPacket();
|
||||
packet.getOptions().addAll(Arrays.asList(enchantingInventory.getEnchantOptions()));
|
||||
packet.getOptions().addAll(Arrays.asList(container.getEnchantOptions()));
|
||||
session.sendUpstreamPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldHandleRequestFirst(ItemStackRequestAction action, Inventory inventory) {
|
||||
protected boolean shouldHandleRequestFirst(ItemStackRequestAction action, EnchantingContainer container) {
|
||||
return action.getType() == ItemStackRequestActionType.CRAFT_RECIPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStackResponse translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
|
||||
public ItemStackResponse translateSpecialRequest(GeyserSession session, EnchantingContainer container, ItemStackRequest request) {
|
||||
// Client has requested an item to be enchanted
|
||||
CraftRecipeAction craftRecipeData = (CraftRecipeAction) request.getActions()[0];
|
||||
EnchantingContainer enchantingInventory = (EnchantingContainer) inventory;
|
||||
int javaSlot = -1;
|
||||
for (int i = 0; i < enchantingInventory.getEnchantOptions().length; i++) {
|
||||
EnchantOptionData enchantData = enchantingInventory.getEnchantOptions()[i];
|
||||
for (int i = 0; i < container.getEnchantOptions().length; i++) {
|
||||
EnchantOptionData enchantData = container.getEnchantOptions()[i];
|
||||
if (enchantData != null) {
|
||||
if (craftRecipeData.getRecipeNetworkId() == enchantData.getEnchantNetId()) {
|
||||
// Enchant net ID is how we differentiate between what item Bedrock wants
|
||||
javaSlot = enchantingInventory.getGeyserEnchantOptions()[i].getJavaIndex();
|
||||
javaSlot = container.getGeyserEnchantOptions()[i].getJavaIndex();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -130,9 +128,9 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla
|
|||
// Slot should be determined as 0, 1, or 2
|
||||
return rejectRequest(request);
|
||||
}
|
||||
ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getJavaId(), javaSlot);
|
||||
ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(container.getJavaId(), javaSlot);
|
||||
session.sendDownstreamGamePacket(packet);
|
||||
return acceptRequest(request, makeContainerEntries(session, inventory, IntSets.emptySet()));
|
||||
return acceptRequest(request, makeContainerEntries(session, container, IntSets.emptySet()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -147,14 +145,14 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla
|
|||
}
|
||||
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot, EnchantingContainer container) {
|
||||
if (slot == 0) {
|
||||
return new BedrockContainerSlot(ContainerSlotType.ENCHANTING_INPUT, 14);
|
||||
}
|
||||
if (slot == 1) {
|
||||
return new BedrockContainerSlot(ContainerSlotType.ENCHANTING_MATERIAL, 15);
|
||||
}
|
||||
return super.javaSlotToBedrockContainer(slot);
|
||||
return super.javaSlotToBedrockContainer(slot, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -169,12 +167,12 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla
|
|||
}
|
||||
|
||||
@Override
|
||||
public Inventory createInventory(GeyserSession session, String name, int windowId, ContainerType containerType, PlayerInventory playerInventory) {
|
||||
return new EnchantingContainer(session, name, windowId, this.size, containerType, playerInventory, this);
|
||||
public EnchantingContainer createInventory(GeyserSession session, String name, int windowId, ContainerType containerType) {
|
||||
return new EnchantingContainer(session, name, windowId, this.size, containerType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.cloudburstmc.protocol.bedrock.data.inventory.@Nullable ContainerType closeContainerType(Inventory inventory) {
|
||||
public org.cloudburstmc.protocol.bedrock.data.inventory.@Nullable ContainerType closeContainerType(EnchantingContainer container) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,8 +29,6 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
|||
import org.cloudburstmc.protocol.bedrock.packet.ContainerOpenPacket;
|
||||
import org.geysermc.geyser.inventory.BedrockContainerSlot;
|
||||
import org.geysermc.geyser.inventory.Generic3X3Container;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.PlayerInventory;
|
||||
import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater;
|
||||
import org.geysermc.geyser.level.block.Blocks;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
@ -39,39 +37,39 @@ import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
|||
/**
|
||||
* Droppers and dispensers
|
||||
*/
|
||||
public class Generic3X3InventoryTranslator extends AbstractBlockInventoryTranslator {
|
||||
public class Generic3X3InventoryTranslator extends AbstractBlockInventoryTranslator<Generic3X3Container> {
|
||||
public Generic3X3InventoryTranslator() {
|
||||
super(9, Blocks.DISPENSER, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.DISPENSER, ContainerInventoryUpdater.INSTANCE,
|
||||
Blocks.DROPPER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Inventory createInventory(GeyserSession session, String name, int windowId, ContainerType containerType, PlayerInventory playerInventory) {
|
||||
return new Generic3X3Container(session, name, windowId, this.size, containerType, playerInventory, this);
|
||||
public Generic3X3Container createInventory(GeyserSession session, String name, int windowId, ContainerType containerType) {
|
||||
return new Generic3X3Container(session, name, windowId, this.size, containerType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openInventory(GeyserSession session, Inventory inventory) {
|
||||
public void openInventory(GeyserSession session, Generic3X3Container container) {
|
||||
ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket();
|
||||
containerOpenPacket.setId((byte) inventory.getBedrockId());
|
||||
containerOpenPacket.setId((byte) container.getBedrockId());
|
||||
// Required for opening the real block - otherwise, if the container type is incorrect, it refuses to open
|
||||
containerOpenPacket.setType(((Generic3X3Container) inventory).isDropper() ? org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.DROPPER : org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.DISPENSER);
|
||||
containerOpenPacket.setBlockPosition(inventory.getHolderPosition());
|
||||
containerOpenPacket.setUniqueEntityId(inventory.getHolderId());
|
||||
containerOpenPacket.setType(container.isDropper() ? org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.DROPPER : org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.DISPENSER);
|
||||
containerOpenPacket.setBlockPosition(container.getHolderPosition());
|
||||
containerOpenPacket.setUniqueEntityId(container.getHolderId());
|
||||
session.sendUpstreamPacket(containerOpenPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int javaSlot) {
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int javaSlot, Generic3X3Container container) {
|
||||
if (javaSlot < this.size) {
|
||||
return new BedrockContainerSlot(ContainerSlotType.LEVEL_ENTITY, javaSlot);
|
||||
}
|
||||
return super.javaSlotToBedrockContainer(javaSlot);
|
||||
return super.javaSlotToBedrockContainer(javaSlot, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType closeContainerType(Inventory inventory) {
|
||||
return ((Generic3X3Container) inventory).isDropper() ? org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.DROPPER :
|
||||
public org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType closeContainerType(Generic3X3Container container) {
|
||||
return container.isDropper() ? org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.DROPPER :
|
||||
org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.DISPENSER;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,11 +29,11 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
|||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
|
||||
import org.geysermc.geyser.inventory.BedrockContainerSlot;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.Container;
|
||||
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
|
||||
import org.geysermc.geyser.level.block.Blocks;
|
||||
|
||||
public class GrindstoneInventoryTranslator extends AbstractBlockInventoryTranslator {
|
||||
public class GrindstoneInventoryTranslator extends AbstractBlockInventoryTranslator<Container> {
|
||||
public GrindstoneInventoryTranslator() {
|
||||
super(3, Blocks.GRINDSTONE, ContainerType.GRINDSTONE, UIInventoryUpdater.INSTANCE);
|
||||
}
|
||||
|
@ -49,12 +49,12 @@ public class GrindstoneInventoryTranslator extends AbstractBlockInventoryTransla
|
|||
}
|
||||
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot, Container container) {
|
||||
return switch (slot) {
|
||||
case 0 -> new BedrockContainerSlot(ContainerSlotType.GRINDSTONE_INPUT, 16);
|
||||
case 1 -> new BedrockContainerSlot(ContainerSlotType.GRINDSTONE_ADDITIONAL, 17);
|
||||
case 2 -> new BedrockContainerSlot(ContainerSlotType.GRINDSTONE_RESULT, 50);
|
||||
default -> super.javaSlotToBedrockContainer(slot);
|
||||
default -> super.javaSlotToBedrockContainer(slot, container);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ public class GrindstoneInventoryTranslator extends AbstractBlockInventoryTransla
|
|||
}
|
||||
|
||||
@Override
|
||||
public ContainerType closeContainerType(Inventory inventory) {
|
||||
public ContainerType closeContainerType(Container container) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,28 +29,28 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
|||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
|
||||
import org.geysermc.geyser.inventory.BedrockContainerSlot;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.Container;
|
||||
import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater;
|
||||
import org.geysermc.geyser.level.block.Blocks;
|
||||
|
||||
/**
|
||||
* Implemented on top of any block that does not have special properties implemented
|
||||
*/
|
||||
public class HopperInventoryTranslator extends AbstractBlockInventoryTranslator {
|
||||
public class HopperInventoryTranslator extends AbstractBlockInventoryTranslator<Container> {
|
||||
public HopperInventoryTranslator() {
|
||||
super(5, Blocks.HOPPER, ContainerType.HOPPER, ContainerInventoryUpdater.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int javaSlot) {
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int javaSlot, Container container) {
|
||||
if (javaSlot < this.size) {
|
||||
return new BedrockContainerSlot(ContainerSlotType.LEVEL_ENTITY, javaSlot);
|
||||
}
|
||||
return super.javaSlotToBedrockContainer(javaSlot);
|
||||
return super.javaSlotToBedrockContainer(javaSlot, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ContainerType closeContainerType(Inventory inventory) {
|
||||
public @Nullable ContainerType closeContainerType(Container container) {
|
||||
return ContainerType.HOPPER;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,10 +92,10 @@ import java.util.Objects;
|
|||
import static org.geysermc.geyser.translator.inventory.BundleInventoryTranslator.isBundle;
|
||||
|
||||
@AllArgsConstructor
|
||||
public abstract class InventoryTranslator {
|
||||
public abstract class InventoryTranslator<Type extends Inventory> {
|
||||
|
||||
public static final InventoryTranslator PLAYER_INVENTORY_TRANSLATOR = new PlayerInventoryTranslator();
|
||||
private static final Map<ContainerType, InventoryTranslator> INVENTORY_TRANSLATORS = new EnumMap<>(ContainerType.class) {
|
||||
public static final InventoryTranslator<PlayerInventory> PLAYER_INVENTORY_TRANSLATOR = new PlayerInventoryTranslator();
|
||||
private static final Map<ContainerType, InventoryTranslator<? extends Inventory>> INVENTORY_TRANSLATORS = new EnumMap<>(ContainerType.class) {
|
||||
{
|
||||
/* Chest UIs */
|
||||
put(ContainerType.GENERIC_9X1, new SingleChestInventoryTranslator(9));
|
||||
|
@ -138,7 +138,7 @@ public abstract class InventoryTranslator {
|
|||
public final int size;
|
||||
|
||||
// Whether the inventory open should be delayed.
|
||||
public boolean requiresOpeningDelay(GeyserSession session, Inventory inventory) {
|
||||
public boolean requiresOpeningDelay(GeyserSession session, Type inventory) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -147,42 +147,74 @@ public abstract class InventoryTranslator {
|
|||
*/
|
||||
public boolean canReuseInventory(GeyserSession session, @NonNull Inventory inventory, @NonNull Inventory previous) {
|
||||
// Filter for mismatches that require a new inventory.
|
||||
if (inventory.getContainerType() == null || previous.getContainerType() == null
|
||||
|| !Objects.equals(inventory.getContainerType(), previous.getContainerType())
|
||||
if (inventory.getContainerType() == null || previous.getContainerType() == null ||
|
||||
!Objects.equals(inventory.getContainerType(), previous.getContainerType()) ||
|
||||
!Objects.equals(inventory.getTitle(), previous.getTitle()) ||
|
||||
inventory.getSize() != previous.getSize()
|
||||
) {
|
||||
GeyserImpl.getInstance().getLogger().debug(session, "Not reusing inventory (%s) due to type change! ", InventoryUtils.debugInventory(inventory));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (inventory.getSize() != previous.getSize()) {
|
||||
GeyserImpl.getInstance().getLogger().debug(session, "Not reusing inventory (%s) due to size change! ", InventoryUtils.debugInventory(inventory));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Objects.equals(inventory.getTitle(), previous.getTitle())) {
|
||||
GeyserImpl.getInstance().getLogger().debug(session, "Not reusing inventory (%s) due to title change! ", InventoryUtils.debugInventory(inventory));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (previous.getHolderId() == -1 && previous.getHolderPosition() == Vector3i.ZERO) {
|
||||
GeyserImpl.getInstance().getLogger().debug(session, "Not reusing inventory (%s) since the old was not initialized! ", InventoryUtils.debugInventory(inventory));
|
||||
return false;
|
||||
}
|
||||
|
||||
// We can likely reuse the inventory!
|
||||
return true;
|
||||
// Finally, ensure that the previous inventory has been initialized
|
||||
return previous.getHolderId() != -1 || previous.getHolderPosition() != Vector3i.ZERO;
|
||||
}
|
||||
public abstract boolean prepareInventory(GeyserSession session, Inventory inventory);
|
||||
public abstract void openInventory(GeyserSession session, Inventory inventory);
|
||||
public abstract void closeInventory(GeyserSession session, Inventory inventory);
|
||||
public abstract void updateProperty(GeyserSession session, Inventory inventory, int key, int value);
|
||||
public abstract void updateInventory(GeyserSession session, Inventory inventory);
|
||||
public abstract void updateSlot(GeyserSession session, Inventory inventory, int slot);
|
||||
|
||||
/**
|
||||
* Prepares the inventory before opening it. Bedrock requires the inventory to "exist" before opening it - that can be
|
||||
* either a real block (e.g. chest), or an entity (e.g. horse)
|
||||
* @return whether the inventory was successfully prepared
|
||||
*/
|
||||
public abstract boolean prepareInventory(GeyserSession session, Type inventory);
|
||||
|
||||
/**
|
||||
* Opens the previously prepared inventory.
|
||||
*/
|
||||
public abstract void openInventory(GeyserSession session, Type inventory);
|
||||
|
||||
/**
|
||||
* Closes the inventory, and if necessary, cleans up the prepared inventory.
|
||||
*/
|
||||
public abstract void closeInventory(GeyserSession session, Type inventory, boolean force);
|
||||
|
||||
/**
|
||||
* Updates a property in the inventory.
|
||||
*/
|
||||
public abstract void updateProperty(GeyserSession session, Type inventory, int key, int value);
|
||||
|
||||
/**
|
||||
* Updates the inventory by re-sending items for all slots of the inventory.
|
||||
*/
|
||||
public abstract void updateInventory(GeyserSession session, Type inventory);
|
||||
|
||||
/**
|
||||
* Updates a specific slot by re-sending the item.
|
||||
*/
|
||||
public abstract void updateSlot(GeyserSession session, Type inventory, int slot);
|
||||
|
||||
/**
|
||||
* Converts the Bedrock slot to the corresponding Java slot.
|
||||
*/
|
||||
public abstract int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData);
|
||||
|
||||
/**
|
||||
* Converts a Java slot to the corresponding Bedrock slot.
|
||||
*/
|
||||
public abstract int javaSlotToBedrock(int javaSlot);
|
||||
public abstract BedrockContainerSlot javaSlotToBedrockContainer(int javaSlot);
|
||||
|
||||
/**
|
||||
* Converts a Java slot to the corresponding Bedrock container and slot
|
||||
*/
|
||||
public abstract BedrockContainerSlot javaSlotToBedrockContainer(int javaSlot, Type inventory);
|
||||
|
||||
/**
|
||||
* Returns the slot type for a Java slot id
|
||||
*/
|
||||
public abstract SlotType getSlotType(int javaSlot);
|
||||
public abstract Inventory createInventory(GeyserSession session, String name, int windowId, ContainerType containerType, PlayerInventory playerInventory);
|
||||
|
||||
/**
|
||||
* Creates a new inventory.
|
||||
*/
|
||||
public abstract Type createInventory(GeyserSession session, String name, int windowId, ContainerType containerType);
|
||||
|
||||
/**
|
||||
* Used for crafting-related transactions. Will override in PlayerInventoryTranslator and CraftingInventoryTranslator.
|
||||
|
@ -199,7 +231,7 @@ public abstract class InventoryTranslator {
|
|||
*
|
||||
* @return true if this transfer should be rejected
|
||||
*/
|
||||
protected boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, ContainerSlotType bedrockSourceContainer,
|
||||
protected boolean shouldRejectItemPlace(GeyserSession session, Type inventory, ContainerSlotType bedrockSourceContainer,
|
||||
int javaSourceSlot, ContainerSlotType bedrockDestinationContainer, int javaDestinationSlot) {
|
||||
return false;
|
||||
}
|
||||
|
@ -208,18 +240,18 @@ public abstract class InventoryTranslator {
|
|||
* Should be overrided if this request matches a certain criteria and shouldn't be treated normally.
|
||||
* E.G. anvil renaming or enchanting
|
||||
*/
|
||||
protected boolean shouldHandleRequestFirst(ItemStackRequestAction action, Inventory inventory) {
|
||||
protected boolean shouldHandleRequestFirst(ItemStackRequestAction action, Type inventory) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If {@link #shouldHandleRequestFirst(ItemStackRequestAction, Inventory)} returns true, this will be called
|
||||
*/
|
||||
protected ItemStackResponse translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
|
||||
protected ItemStackResponse translateSpecialRequest(GeyserSession session, Type inventory, ItemStackRequest request) {
|
||||
return rejectRequest(request);
|
||||
}
|
||||
|
||||
public final void translateRequests(GeyserSession session, Inventory inventory, List<ItemStackRequest> requests) {
|
||||
public final void translateRequests(GeyserSession session, Type inventory, List<ItemStackRequest> requests) {
|
||||
boolean refresh = false;
|
||||
ItemStackResponsePacket responsePacket = new ItemStackResponsePacket();
|
||||
for (ItemStackRequest request : requests) {
|
||||
|
@ -261,7 +293,7 @@ public abstract class InventoryTranslator {
|
|||
inventory.resetNextStateId();
|
||||
}
|
||||
|
||||
public ItemStackResponse translateRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
|
||||
public ItemStackResponse translateRequest(GeyserSession session, Type inventory, ItemStackRequest request) {
|
||||
ClickPlan plan = new ClickPlan(session, this, inventory);
|
||||
IntSet affectedSlots = new IntOpenHashSet();
|
||||
int pendingOutput = 0;
|
||||
|
@ -589,7 +621,7 @@ public abstract class InventoryTranslator {
|
|||
return acceptRequest(request, makeContainerEntries(session, inventory, affectedSlots));
|
||||
}
|
||||
|
||||
public ItemStackResponse translateCraftingRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
|
||||
public ItemStackResponse translateCraftingRequest(GeyserSession session, Type inventory, ItemStackRequest request) {
|
||||
int resultSize = 0;
|
||||
int timesCrafted;
|
||||
CraftState craftState = CraftState.START;
|
||||
|
@ -712,7 +744,7 @@ public abstract class InventoryTranslator {
|
|||
return acceptRequest(request, makeContainerEntries(session, inventory, affectedSlots));
|
||||
}
|
||||
|
||||
public ItemStackResponse translateAutoCraftingRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
|
||||
public ItemStackResponse translateAutoCraftingRequest(GeyserSession session, Type inventory, ItemStackRequest request) {
|
||||
final int gridSize = getGridSize();
|
||||
if (gridSize == -1) {
|
||||
return rejectRequest(request);
|
||||
|
@ -899,7 +931,7 @@ public abstract class InventoryTranslator {
|
|||
/**
|
||||
* Handled in {@link PlayerInventoryTranslator}
|
||||
*/
|
||||
protected ItemStackResponse translateCreativeRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
|
||||
protected ItemStackResponse translateCreativeRequest(GeyserSession session, Type inventory, ItemStackRequest request) {
|
||||
return rejectRequest(request);
|
||||
}
|
||||
|
||||
|
@ -961,14 +993,14 @@ public abstract class InventoryTranslator {
|
|||
/**
|
||||
* Print out the contents of an ItemStackRequest, should the net ID check fail.
|
||||
*/
|
||||
protected void dumpStackRequestDetails(GeyserSession session, Inventory inventory, ItemStackRequestSlotData source, ItemStackRequestSlotData destination) {
|
||||
protected void dumpStackRequestDetails(GeyserSession session, Type inventory, ItemStackRequestSlotData source, ItemStackRequestSlotData destination) {
|
||||
session.getGeyser().getLogger().error("Source: " + source.toString() + " Result: " + checkNetId(session, inventory, source));
|
||||
session.getGeyser().getLogger().error("Destination: " + destination.toString() + " Result: " + checkNetId(session, inventory, destination));
|
||||
session.getGeyser().getLogger().error("Geyser's record of source slot: " + inventory.getItem(bedrockSlotToJava(source)));
|
||||
session.getGeyser().getLogger().error("Geyser's record of destination slot: " + inventory.getItem(bedrockSlotToJava(destination)));
|
||||
}
|
||||
|
||||
public boolean checkNetId(GeyserSession session, Inventory inventory, ItemStackRequestSlotData slotInfoData) {
|
||||
public boolean checkNetId(GeyserSession session, Type inventory, ItemStackRequestSlotData slotInfoData) {
|
||||
if (BundleInventoryTranslator.isBundle(slotInfoData)) {
|
||||
// Will thoroughly be investigated, if needed, in bundle checks.
|
||||
return true;
|
||||
|
@ -1050,13 +1082,13 @@ public abstract class InventoryTranslator {
|
|||
return -1;
|
||||
}
|
||||
|
||||
protected final List<ItemStackResponseContainer> makeContainerEntries(GeyserSession session, Inventory inventory, IntSet affectedSlots) {
|
||||
protected final List<ItemStackResponseContainer> makeContainerEntries(GeyserSession session, Type inventory, IntSet affectedSlots) {
|
||||
Map<ContainerSlotType, List<ItemStackResponseSlot>> containerMap = new HashMap<>();
|
||||
// Manually call iterator to prevent Integer boxing
|
||||
IntIterator it = affectedSlots.iterator();
|
||||
while (it.hasNext()) {
|
||||
int slot = it.nextInt();
|
||||
BedrockContainerSlot bedrockSlot = javaSlotToBedrockContainer(slot);
|
||||
BedrockContainerSlot bedrockSlot = javaSlotToBedrockContainer(slot, inventory);
|
||||
List<ItemStackResponseSlot> list = containerMap.computeIfAbsent(bedrockSlot.container(), k -> new ArrayList<>());
|
||||
list.add(makeItemEntry(bedrockSlot.slot(), inventory.getItem(slot)));
|
||||
}
|
||||
|
@ -1102,7 +1134,7 @@ public abstract class InventoryTranslator {
|
|||
* @return the InventoryType for the given ContainerType.
|
||||
*/
|
||||
@Nullable
|
||||
public static InventoryTranslator inventoryTranslator(@Nullable ContainerType type) {
|
||||
public static InventoryTranslator<? extends Inventory> inventoryTranslator(@Nullable ContainerType type) {
|
||||
if (type == null) {
|
||||
return PLAYER_INVENTORY_TRANSLATOR;
|
||||
}
|
||||
|
|
|
@ -32,9 +32,8 @@ import org.cloudburstmc.nbt.NbtMapBuilder;
|
|||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.geysermc.erosion.util.LecternUtils;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.InventoryHolder;
|
||||
import org.geysermc.geyser.inventory.LecternContainer;
|
||||
import org.geysermc.geyser.inventory.PlayerInventory;
|
||||
import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater;
|
||||
import org.geysermc.geyser.level.block.Blocks;
|
||||
import org.geysermc.geyser.level.block.property.Properties;
|
||||
|
@ -48,7 +47,9 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.WritableBook
|
|||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.WrittenBookContent;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket;
|
||||
|
||||
public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator {
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator<LecternContainer> {
|
||||
|
||||
/**
|
||||
* Hack: Java opens a lectern first, and then follows it up with a ClientboundContainerSetContentPacket
|
||||
|
@ -57,15 +58,15 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator
|
|||
private boolean receivedBook = false;
|
||||
|
||||
public LecternInventoryTranslator() {
|
||||
super(1, Blocks.LECTERN, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.LECTERN , ContainerInventoryUpdater.INSTANCE);
|
||||
super(1, Blocks.LECTERN, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.LECTERN, ContainerInventoryUpdater.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean prepareInventory(GeyserSession session, Inventory inventory) {
|
||||
super.prepareInventory(session, inventory);
|
||||
if (((LecternContainer) inventory).isBookInPlayerInventory()) {
|
||||
public boolean prepareInventory(GeyserSession session, LecternContainer container) {
|
||||
super.prepareInventory(session, container);
|
||||
if (container.isBookInPlayerInventory()) {
|
||||
// See JavaOpenBookTranslator; this isn't a lectern but a book in the player inventory
|
||||
updateBook(session, inventory, inventory.getItem(0));
|
||||
updateBook(session, container, container.getItem(0));
|
||||
receivedBook = true;
|
||||
} else {
|
||||
receivedBook = false; // We have to wait until we get the book
|
||||
|
@ -74,95 +75,103 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator
|
|||
}
|
||||
|
||||
@Override
|
||||
public void openInventory(GeyserSession session, Inventory inventory) {
|
||||
public void openInventory(GeyserSession session, LecternContainer container) {
|
||||
// Hacky, but we're dealing with LECTERNS! It cannot not be hacky.
|
||||
// "initialized" indicates whether we've received the book from the Java server yet.
|
||||
// dropping lectern book is the fun workaround when we have to enter the gui to drop the book.
|
||||
// Since we leave it immediately... don't open it!
|
||||
if (receivedBook && !session.isDroppingLecternBook()) {
|
||||
super.openInventory(session, inventory);
|
||||
super.openInventory(session, container);
|
||||
}
|
||||
}
|
||||
|
||||
// Lecterns don't require a delay before opening.
|
||||
@Override
|
||||
public void closeInventory(GeyserSession session, Inventory inventory) {
|
||||
public boolean requiresOpeningDelay(GeyserSession session, LecternContainer container) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeInventory(GeyserSession session, LecternContainer container, boolean force) {
|
||||
// Of course, sending a simple ContainerClosePacket, or even breaking the block doesn't work to close a lectern.
|
||||
// Heck, the latter crashes the client xd
|
||||
// BDS just sends an empty base lectern tag... that kicks out the client. Fine. Let's do that!
|
||||
LecternContainer lecternContainer = (LecternContainer) inventory;
|
||||
Vector3i position = lecternContainer.isUsingRealBlock() ? session.getLastInteractionBlockPosition() : inventory.getHolderPosition();
|
||||
Vector3i position = container.getHolderPosition();
|
||||
var baseLecternTag = LecternUtils.getBaseLecternTag(position.getX(), position.getY(), position.getZ(), 0);
|
||||
BlockEntityUtils.updateBlockEntity(session, baseLecternTag.build(), position);
|
||||
|
||||
// Closing lecterns isn't followed up by a ContainerClosePacket, so this wouldn't ever be reset.
|
||||
session.setPendingOrCurrentBedrockInventoryId(-1);
|
||||
|
||||
super.closeInventory(session, inventory); // Removes the fake blocks if need be
|
||||
|
||||
super.closeInventory(session, container, force); // Removes the fake blocks if need be
|
||||
// Now: Restore the lectern, if it actually exists
|
||||
if (lecternContainer.isUsingRealBlock()) {
|
||||
boolean hasBook = session.getGeyser().getWorldManager().blockAt(session, position).getValue(Properties.HAS_BOOK, false);
|
||||
NbtMap map = LecternBlock.getBaseLecternTag(position, hasBook);
|
||||
BlockEntityUtils.updateBlockEntity(session, map, position);
|
||||
}
|
||||
}
|
||||
if (container.isUsingRealBlock()) {
|
||||
Runnable closeLecternRunnable = () -> {
|
||||
boolean hasBook = session.getGeyser().getWorldManager().blockAt(session, position).getValue(Properties.HAS_BOOK, false);
|
||||
NbtMap map = LecternBlock.getBaseLecternTag(position, hasBook);
|
||||
BlockEntityUtils.updateBlockEntity(session, map, position);
|
||||
};
|
||||
|
||||
@Override
|
||||
public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) {
|
||||
if (key == 0) { // Lectern page update
|
||||
LecternContainer lecternContainer = (LecternContainer) inventory;
|
||||
lecternContainer.setCurrentBedrockPage(value / 2);
|
||||
lecternContainer.setBlockEntityTag(lecternContainer.getBlockEntityTag().toBuilder().putInt("page", lecternContainer.getCurrentBedrockPage()).build());
|
||||
BlockEntityUtils.updateBlockEntity(session, lecternContainer.getBlockEntityTag(), lecternContainer.getPosition());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateInventory(GeyserSession session, Inventory inventory) {
|
||||
GeyserItemStack itemStack = inventory.getItem(0);
|
||||
if (!itemStack.isEmpty()) {
|
||||
boolean isDropping = session.isDroppingLecternBook();
|
||||
updateBook(session, inventory, itemStack);
|
||||
|
||||
if (!receivedBook && !isDropping) {
|
||||
receivedBook = true;
|
||||
openInventory(session, inventory);
|
||||
if (force) {
|
||||
// Without a delay, an inventory close request can *occasionally* be ignored as we're restoring the book too quickly
|
||||
session.scheduleInEventLoop(closeLecternRunnable, 100, TimeUnit.MILLISECONDS);
|
||||
} else {
|
||||
closeLecternRunnable.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSlot(GeyserSession session, Inventory inventory, int slot) {
|
||||
// If we're not in a real lectern, the Java server thinks we are still in the player inventory.
|
||||
if (((LecternContainer) inventory).isBookInPlayerInventory()) {
|
||||
InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR.updateSlot(session, session.getPlayerInventory(), slot);
|
||||
return;
|
||||
}
|
||||
super.updateSlot(session, inventory, slot);
|
||||
if (slot == 0) {
|
||||
updateBook(session, inventory, inventory.getItem(0));
|
||||
public void updateProperty(GeyserSession session, LecternContainer container, int key, int value) {
|
||||
if (key == 0) { // Lectern page update
|
||||
container.setCurrentBedrockPage(value / 2);
|
||||
container.setBlockEntityTag(container.getBlockEntityTag().toBuilder().putInt("page", container.getCurrentBedrockPage()).build());
|
||||
BlockEntityUtils.updateBlockEntity(session, container.getBlockEntityTag(), container.getHolderPosition());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.cloudburstmc.protocol.bedrock.data.inventory.@Nullable ContainerType closeContainerType(Inventory inventory) {
|
||||
public void updateInventory(GeyserSession session, LecternContainer container) {
|
||||
GeyserItemStack itemStack = container.getItem(0);
|
||||
if (!itemStack.isEmpty()) {
|
||||
boolean isDropping = session.isDroppingLecternBook();
|
||||
updateBook(session, container, itemStack);
|
||||
|
||||
if (!receivedBook && !isDropping) {
|
||||
receivedBook = true;
|
||||
openInventory(session, container);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSlot(GeyserSession session, LecternContainer container, int slot) {
|
||||
super.updateSlot(session, container, slot);
|
||||
if (slot == 0) {
|
||||
updateBook(session, container, container.getItem(0));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.cloudburstmc.protocol.bedrock.data.inventory.@Nullable ContainerType closeContainerType(LecternContainer container) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate the data of the book in the lectern into a block entity tag.
|
||||
*/
|
||||
private void updateBook(GeyserSession session, Inventory inventory, GeyserItemStack book) {
|
||||
LecternContainer lecternContainer = (LecternContainer) inventory;
|
||||
private void updateBook(GeyserSession session, LecternContainer container, GeyserItemStack book) {
|
||||
if (session.isDroppingLecternBook()) {
|
||||
// We have to enter the inventory GUI to eject the book
|
||||
ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getJavaId(), 3);
|
||||
session.sendDownstreamGamePacket(packet);
|
||||
session.setDroppingLecternBook(false);
|
||||
InventoryUtils.closeInventory(session, inventory.getJavaId(), false);
|
||||
} else if (lecternContainer.getBlockEntityTag() == null) {
|
||||
Vector3i position = lecternContainer.isUsingRealBlock() ?
|
||||
session.getLastInteractionBlockPosition() : inventory.getHolderPosition();
|
||||
InventoryHolder<?> holder = session.getInventoryHolder();
|
||||
if (holder != null && !container.isBookInPlayerInventory()) {
|
||||
// We have to enter the inventory GUI to eject the book
|
||||
ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(container.getJavaId(), 3);
|
||||
session.sendDownstreamGamePacket(packet);
|
||||
session.setDroppingLecternBook(false);
|
||||
InventoryUtils.closeInventory(session, container.getJavaId(), false);
|
||||
}
|
||||
} else if (container.getBlockEntityTag() == null) {
|
||||
Vector3i position = container.getHolderPosition();
|
||||
|
||||
NbtMap blockEntityTag;
|
||||
if (book.hasNonBaseComponents()) {
|
||||
|
@ -185,24 +194,21 @@ public class LecternInventoryTranslator extends AbstractBlockInventoryTranslator
|
|||
.putString("Name", "minecraft:written_book")
|
||||
.putCompound("tag", itemData.getTag())
|
||||
.build());
|
||||
lecternTag.putInt("page", lecternContainer.getCurrentBedrockPage());
|
||||
lecternTag.putInt("page", container.getCurrentBedrockPage());
|
||||
blockEntityTag = lecternTag.build();
|
||||
} else {
|
||||
// There is *a* book here, but... no NBT.
|
||||
blockEntityTag = LecternBlock.getBaseLecternTag(position, true);
|
||||
}
|
||||
|
||||
// Even with serverside access to lecterns, we don't easily know which lectern this is, so we need to rebuild
|
||||
// the block entity tag
|
||||
lecternContainer.setBlockEntityTag(blockEntityTag);
|
||||
lecternContainer.setPosition(position);
|
||||
container.setBlockEntityTag(blockEntityTag);
|
||||
|
||||
BlockEntityUtils.updateBlockEntity(session, blockEntityTag, position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Inventory createInventory(GeyserSession session, String name, int windowId, ContainerType containerType, PlayerInventory playerInventory) {
|
||||
return new LecternContainer(session, name, windowId, this.size + playerInventory.getSize(), containerType, playerInventory, this);
|
||||
public LecternContainer createInventory(GeyserSession session, String name, int windowId, ContainerType containerType) {
|
||||
return new LecternContainer(session, name, windowId, this.size, containerType);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,8 +40,8 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action
|
|||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponse;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.inventory.BedrockContainerSlot;
|
||||
import org.geysermc.geyser.inventory.Container;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.SlotType;
|
||||
import org.geysermc.geyser.inventory.item.BannerPattern;
|
||||
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
|
||||
|
@ -58,7 +58,7 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.S
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator {
|
||||
public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator<Container> {
|
||||
|
||||
private static final Tag<BannerPattern> NO_ITEMS_REQUIRED = new Tag<>(JavaRegistries.BANNER_PATTERN, Key.key("no_item_required"));
|
||||
|
||||
|
@ -67,12 +67,12 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, ContainerSlotType bedrockSourceContainer,
|
||||
protected boolean shouldRejectItemPlace(GeyserSession session, Container container, ContainerSlotType bedrockSourceContainer,
|
||||
int javaSourceSlot, ContainerSlotType bedrockDestinationContainer, int javaDestinationSlot) {
|
||||
if (javaDestinationSlot != 1) {
|
||||
return false;
|
||||
}
|
||||
GeyserItemStack itemStack = javaSourceSlot == -1 ? session.getPlayerInventory().getCursor() : inventory.getItem(javaSourceSlot);
|
||||
GeyserItemStack itemStack = javaSourceSlot == -1 ? session.getPlayerInventory().getCursor() : container.getItem(javaSourceSlot);
|
||||
if (itemStack.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -82,13 +82,13 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldHandleRequestFirst(ItemStackRequestAction action, Inventory inventory) {
|
||||
protected boolean shouldHandleRequestFirst(ItemStackRequestAction action, Container container) {
|
||||
// If the LOOM_MATERIAL slot is empty, we are crafting a pattern that does not come from an item
|
||||
return action.getType() == ItemStackRequestActionType.CRAFT_LOOM && inventory.getItem(2).isEmpty();
|
||||
return action.getType() == ItemStackRequestActionType.CRAFT_LOOM && container.getItem(2).isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStackResponse translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
|
||||
public ItemStackResponse translateSpecialRequest(GeyserSession session, Container container, ItemStackRequest request) {
|
||||
ItemStackRequestAction headerData = request.getActions()[0];
|
||||
ItemStackRequestAction data = request.getActions()[1];
|
||||
if (!(headerData instanceof CraftLoomAction)) {
|
||||
|
@ -119,10 +119,10 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator {
|
|||
// Java's formula: 4 * row + col
|
||||
// And the Java loom window has a fixed row/width of four
|
||||
// So... Number / 4 = row (so we don't have to bother there), and number % 4 is our column, which leads us back to our index. :)
|
||||
ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getJavaId(), index);
|
||||
ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(container.getJavaId(), index);
|
||||
session.sendDownstreamGamePacket(packet);
|
||||
|
||||
GeyserItemStack inputCopy = inventory.getItem(0).copy(1);
|
||||
GeyserItemStack inputCopy = container.getItem(0).copy(1);
|
||||
inputCopy.setNetId(session.getNextItemNetId());
|
||||
BannerPatternLayer bannerPatternLayer = BannerItem.getJavaBannerPattern(session, pattern); // TODO
|
||||
if (bannerPatternLayer != null) {
|
||||
|
@ -132,9 +132,9 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator {
|
|||
}
|
||||
|
||||
// Set the new item as the output
|
||||
inventory.setItem(3, inputCopy, session);
|
||||
container.setItem(3, inputCopy, session);
|
||||
|
||||
return translateRequest(session, inventory, request);
|
||||
return translateRequest(session, container, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -149,13 +149,13 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot, Container container) {
|
||||
return switch (slot) {
|
||||
case 0 -> new BedrockContainerSlot(ContainerSlotType.LOOM_INPUT, 9);
|
||||
case 1 -> new BedrockContainerSlot(ContainerSlotType.LOOM_DYE, 10);
|
||||
case 2 -> new BedrockContainerSlot(ContainerSlotType.LOOM_MATERIAL, 11);
|
||||
case 3 -> new BedrockContainerSlot(ContainerSlotType.LOOM_RESULT, 50);
|
||||
default -> super.javaSlotToBedrockContainer(slot);
|
||||
default -> super.javaSlotToBedrockContainer(slot, container);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -179,7 +179,7 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ContainerType closeContainerType(Inventory inventory) {
|
||||
public @Nullable ContainerType closeContainerType(Container container) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.S
|
|||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class MerchantInventoryTranslator extends BaseInventoryTranslator {
|
||||
public class MerchantInventoryTranslator extends BaseInventoryTranslator<MerchantContainer> {
|
||||
private final InventoryUpdater updater;
|
||||
|
||||
public MerchantInventoryTranslator() {
|
||||
|
@ -66,12 +66,12 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot, MerchantContainer container) {
|
||||
return switch (slot) {
|
||||
case 0 -> new BedrockContainerSlot(ContainerSlotType.TRADE2_INGREDIENT_1, 4);
|
||||
case 1 -> new BedrockContainerSlot(ContainerSlotType.TRADE2_INGREDIENT_2, 5);
|
||||
case 2 -> new BedrockContainerSlot(ContainerSlotType.TRADE2_RESULT, 50);
|
||||
default -> super.javaSlotToBedrockContainer(slot);
|
||||
default -> super.javaSlotToBedrockContainer(slot, container);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -94,9 +94,8 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean prepareInventory(GeyserSession session, Inventory inventory) {
|
||||
MerchantContainer merchantInventory = (MerchantContainer) inventory;
|
||||
if (merchantInventory.getVillager() == null) {
|
||||
public boolean prepareInventory(GeyserSession session, MerchantContainer container) {
|
||||
if (container.getVillager() == null) {
|
||||
long geyserId = session.getEntityCache().getNextEntityId().incrementAndGet();
|
||||
Vector3f pos = session.getPlayerEntity().getPosition().sub(0, 3, 0);
|
||||
|
||||
|
@ -115,66 +114,63 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator {
|
|||
linkPacket.setEntityLink(new EntityLinkData(session.getPlayerEntity().getGeyserId(), geyserId, type, true, false, 0f));
|
||||
session.sendUpstreamPacket(linkPacket);
|
||||
|
||||
merchantInventory.setVillager(villager);
|
||||
container.setVillager(villager);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openInventory(GeyserSession session, Inventory inventory) {
|
||||
public void openInventory(GeyserSession session, MerchantContainer container) {
|
||||
//Handled in JavaMerchantOffersTranslator
|
||||
//TODO: send a blank inventory here in case the villager doesn't send a TradeList packet
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeInventory(GeyserSession session, Inventory inventory) {
|
||||
MerchantContainer merchantInventory = (MerchantContainer) inventory;
|
||||
if (merchantInventory.getVillager() != null) {
|
||||
merchantInventory.getVillager().despawnEntity();
|
||||
public void closeInventory(GeyserSession session, MerchantContainer container, boolean force) {
|
||||
if (container.getVillager() != null) {
|
||||
container.getVillager().despawnEntity();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStackResponse translateCraftingRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
|
||||
public ItemStackResponse translateCraftingRequest(GeyserSession session, MerchantContainer container, ItemStackRequest request) {
|
||||
// Behavior as of 1.18.10.
|
||||
// We set the net ID to the trade index + 1. This doesn't appear to cause issues and means we don't have to
|
||||
// store a map of net ID to trade index on our end.
|
||||
int tradeChoice = ((CraftRecipeAction) request.getActions()[0]).getRecipeNetworkId() - 1;
|
||||
return handleTrade(session, inventory, request, tradeChoice);
|
||||
return handleTrade(session, container, request, tradeChoice);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStackResponse translateAutoCraftingRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
|
||||
public ItemStackResponse translateAutoCraftingRequest(GeyserSession session, MerchantContainer container, ItemStackRequest request) {
|
||||
// 1.18.10 update - seems impossible to call without consoles/controller input
|
||||
// We set the net ID to the trade index + 1. This doesn't appear to cause issues and means we don't have to
|
||||
// store a map of net ID to trade index on our end.
|
||||
int tradeChoice = ((AutoCraftRecipeAction) request.getActions()[0]).getRecipeNetworkId() - 1;
|
||||
return handleTrade(session, inventory, request, tradeChoice);
|
||||
return handleTrade(session, container, request, tradeChoice);
|
||||
}
|
||||
|
||||
private ItemStackResponse handleTrade(GeyserSession session, Inventory inventory, ItemStackRequest request, int tradeChoice) {
|
||||
private ItemStackResponse handleTrade(GeyserSession session, MerchantContainer container, ItemStackRequest request, int tradeChoice) {
|
||||
ServerboundSelectTradePacket packet = new ServerboundSelectTradePacket(tradeChoice);
|
||||
session.sendDownstreamGamePacket(packet);
|
||||
|
||||
if (session.isEmulatePost1_13Logic()) {
|
||||
// 1.18 Java cooperates nicer than older versions
|
||||
if (inventory instanceof MerchantContainer merchantInventory) {
|
||||
merchantInventory.onTradeSelected(session, tradeChoice);
|
||||
}
|
||||
return translateRequest(session, inventory, request);
|
||||
container.onTradeSelected(session, tradeChoice);
|
||||
return translateRequest(session, container, request);
|
||||
} else {
|
||||
// 1.18 servers works fine without a workaround, but ViaVersion needs to work around 1.13 servers,
|
||||
// so we need to work around that with the delay. Specifically they force a window refresh after a
|
||||
// trade packet has been sent.
|
||||
session.scheduleInEventLoop(() -> {
|
||||
if (inventory instanceof MerchantContainer merchantInventory) {
|
||||
if (session.getOpenInventory() instanceof MerchantContainer merchantInventory) {
|
||||
merchantInventory.onTradeSelected(session, tradeChoice);
|
||||
// Ignore output since we don't want to send a delayed response packet back to the client
|
||||
translateRequest(session, inventory, request);
|
||||
translateRequest(session, container, request);
|
||||
|
||||
// Resync items once more
|
||||
updateInventory(session, inventory);
|
||||
updateInventory(session, container);
|
||||
InventoryUtils.updateCursor(session);
|
||||
}
|
||||
}, 100, TimeUnit.MILLISECONDS);
|
||||
|
@ -185,17 +181,17 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void updateInventory(GeyserSession session, Inventory inventory) {
|
||||
updater.updateInventory(this, session, inventory);
|
||||
public void updateInventory(GeyserSession session, MerchantContainer container) {
|
||||
updater.updateInventory(this, session, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSlot(GeyserSession session, Inventory inventory, int slot) {
|
||||
updater.updateSlot(this, session, inventory, slot);
|
||||
public void updateSlot(GeyserSession session, MerchantContainer container, int slot) {
|
||||
updater.updateSlot(this, session, container, slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Inventory createInventory(GeyserSession session, String name, int windowId, ContainerType containerType, PlayerInventory playerInventory) {
|
||||
return new MerchantContainer(session, name, windowId, this.size, containerType, playerInventory, this);
|
||||
public MerchantContainer createInventory(GeyserSession session, String name, int windowId, ContainerType containerType) {
|
||||
return new MerchantContainer(session, name, windowId, this.size, containerType);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action
|
|||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponse;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket;
|
||||
import org.geysermc.geyser.inventory.BedrockContainerSlot;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.Container;
|
||||
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
|
||||
import org.geysermc.geyser.level.block.Blocks;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
@ -52,7 +52,7 @@ import java.util.function.IntFunction;
|
|||
* Translator for smithing tables for pre-1.20 servers.
|
||||
* This adapts ViaVersion's furnace ui to the 1.20+ smithing table; with the addition of a fake smithing template so Bedrock clients can use it.
|
||||
*/
|
||||
public class OldSmithingTableTranslator extends AbstractBlockInventoryTranslator {
|
||||
public class OldSmithingTableTranslator extends AbstractBlockInventoryTranslator<Container> {
|
||||
|
||||
public static final OldSmithingTableTranslator INSTANCE = new OldSmithingTableTranslator();
|
||||
|
||||
|
@ -73,12 +73,12 @@ public class OldSmithingTableTranslator extends AbstractBlockInventoryTranslator
|
|||
}
|
||||
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot, Container container) {
|
||||
return switch (slot) {
|
||||
case 0 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_INPUT, 51);
|
||||
case 1 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_MATERIAL, 52);
|
||||
case 2 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_RESULT, 50);
|
||||
default -> super.javaSlotToBedrockContainer(slot);
|
||||
default -> super.javaSlotToBedrockContainer(slot, container);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -93,12 +93,12 @@ public class OldSmithingTableTranslator extends AbstractBlockInventoryTranslator
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldHandleRequestFirst(ItemStackRequestAction action, Inventory inventory) {
|
||||
public boolean shouldHandleRequestFirst(ItemStackRequestAction action, Container container) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ItemStackResponse translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
|
||||
protected ItemStackResponse translateSpecialRequest(GeyserSession session, Container container, ItemStackRequest request) {
|
||||
for (var action: request.getActions()) {
|
||||
switch (action.getType()) {
|
||||
case DROP -> {
|
||||
|
@ -127,7 +127,7 @@ public class OldSmithingTableTranslator extends AbstractBlockInventoryTranslator
|
|||
}
|
||||
}
|
||||
// Allow everything else that doesn't involve the fake template
|
||||
return super.translateRequest(session, inventory, request);
|
||||
return super.translateRequest(session, container, request);
|
||||
}
|
||||
|
||||
private boolean isInvalidAction(ItemStackRequestSlotData slotData) {
|
||||
|
@ -135,8 +135,8 @@ public class OldSmithingTableTranslator extends AbstractBlockInventoryTranslator
|
|||
}
|
||||
|
||||
@Override
|
||||
public void openInventory(GeyserSession session, Inventory inventory) {
|
||||
super.openInventory(session, inventory);
|
||||
public void openInventory(GeyserSession session, Container container) {
|
||||
super.openInventory(session, container);
|
||||
|
||||
// pre-1.20 server has no concept of templates, but we are working with a 1.20 client
|
||||
// put a fake netherite upgrade template in the template slot otherwise the client doesn't recognize a valid recipe
|
||||
|
@ -148,7 +148,7 @@ public class OldSmithingTableTranslator extends AbstractBlockInventoryTranslator
|
|||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ContainerType closeContainerType(Inventory inventory) {
|
||||
public @Nullable ContainerType closeContainerType(Container container) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ import java.util.List;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.IntFunction;
|
||||
|
||||
public class PlayerInventoryTranslator extends InventoryTranslator {
|
||||
public class PlayerInventoryTranslator extends InventoryTranslator<PlayerInventory> {
|
||||
private static final IntFunction<ItemData> UNUSUABLE_CRAFTING_SPACE_BLOCK = InventoryUtils.createUnusableSpaceBlock(GeyserLocale.getLocaleStringLog("geyser.inventory.unusable_item.creative"));
|
||||
|
||||
public PlayerInventoryTranslator() {
|
||||
|
@ -84,7 +84,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void updateInventory(GeyserSession session, Inventory inventory) {
|
||||
public void updateInventory(GeyserSession session, PlayerInventory inventory) {
|
||||
updateCraftingGrid(session, inventory);
|
||||
|
||||
InventoryContentPacket inventoryContentPacket = new InventoryContentPacket();
|
||||
|
@ -129,7 +129,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
* @param session Connection of the player
|
||||
* @param inventory Inventory of the player
|
||||
*/
|
||||
public static void updateCraftingGrid(GeyserSession session, Inventory inventory) {
|
||||
public static void updateCraftingGrid(GeyserSession session, PlayerInventory inventory) {
|
||||
// Crafting grid
|
||||
for (int i = 1; i < 5; i++) {
|
||||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||
|
@ -147,7 +147,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void updateSlot(GeyserSession session, Inventory inventory, int slot) {
|
||||
public void updateSlot(GeyserSession session, PlayerInventory inventory, int slot) {
|
||||
GeyserItemStack javaItem = inventory.getItem(slot);
|
||||
ItemData bedrockItem = javaItem.getItemData(session);
|
||||
|
||||
|
@ -227,7 +227,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot, PlayerInventory inventory) {
|
||||
if (slot >= 36 && slot <= 44) {
|
||||
return new BedrockContainerSlot(ContainerSlotType.HOTBAR, slot - 36);
|
||||
} else if (slot >= 9 && slot <= 35) {
|
||||
|
@ -253,7 +253,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ItemStackResponse translateRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
|
||||
public ItemStackResponse translateRequest(GeyserSession session, PlayerInventory inventory, ItemStackRequest request) {
|
||||
if (session.getGameMode() != GameMode.CREATIVE) {
|
||||
return super.translateRequest(session, inventory, request);
|
||||
}
|
||||
|
@ -438,7 +438,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected ItemStackResponse translateCreativeRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
|
||||
protected ItemStackResponse translateCreativeRequest(GeyserSession session, PlayerInventory inventory, ItemStackRequest request) {
|
||||
ItemStack javaCreativeItem = null;
|
||||
boolean bundle = false;
|
||||
IntSet affectedSlots = new IntOpenHashSet();
|
||||
|
@ -570,7 +570,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Inventory createInventory(GeyserSession session, String name, int windowId, ContainerType containerType, PlayerInventory playerInventory) {
|
||||
public PlayerInventory createInventory(GeyserSession session, String name, int windowId, ContainerType containerType) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
@ -580,12 +580,12 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean prepareInventory(GeyserSession session, Inventory inventory) {
|
||||
public boolean prepareInventory(GeyserSession session, PlayerInventory inventory) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openInventory(GeyserSession session, Inventory inventory) {
|
||||
public void openInventory(GeyserSession session, PlayerInventory inventory) {
|
||||
ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket();
|
||||
containerOpenPacket.setId((byte) 0);
|
||||
containerOpenPacket.setType(org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.INVENTORY);
|
||||
|
@ -595,9 +595,8 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void closeInventory(GeyserSession session, Inventory inventory) {
|
||||
if (session.isServerRequestedClosePlayerInventory()) {
|
||||
session.setServerRequestedClosePlayerInventory(false);
|
||||
public void closeInventory(GeyserSession session, PlayerInventory inventory, boolean force) {
|
||||
if (force) {
|
||||
Vector3i pos = session.getPlayerEntity().getPosition().toInt();
|
||||
|
||||
UpdateBlockPacket packet = new UpdateBlockPacket();
|
||||
|
@ -617,6 +616,6 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) {
|
||||
public void updateProperty(GeyserSession session, PlayerInventory inventory, int key, int value) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
|||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;
|
||||
import org.geysermc.geyser.inventory.BedrockContainerSlot;
|
||||
import org.geysermc.geyser.inventory.Container;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.holder.BlockInventoryHolder;
|
||||
import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater;
|
||||
|
@ -45,7 +46,7 @@ import org.geysermc.geyser.session.GeyserSession;
|
|||
import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
|
||||
|
||||
public class ShulkerInventoryTranslator extends AbstractBlockInventoryTranslator {
|
||||
public class ShulkerInventoryTranslator extends AbstractBlockInventoryTranslator<Container> {
|
||||
public ShulkerInventoryTranslator() {
|
||||
// Ensure that the shulker box default state won't be trying to open in a state facing the player
|
||||
super(27, new BlockInventoryHolder(Blocks.SHULKER_BOX.defaultBlockState().withValue(Properties.FACING, Direction.NORTH), ContainerType.CONTAINER) {
|
||||
|
@ -75,15 +76,15 @@ public class ShulkerInventoryTranslator extends AbstractBlockInventoryTranslator
|
|||
}
|
||||
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int javaSlot) {
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int javaSlot, Container container) {
|
||||
if (javaSlot < this.size) {
|
||||
return new BedrockContainerSlot(ContainerSlotType.SHULKER_BOX, javaSlot);
|
||||
}
|
||||
return super.javaSlotToBedrockContainer(javaSlot);
|
||||
return super.javaSlotToBedrockContainer(javaSlot, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ContainerType closeContainerType(Inventory inventory) {
|
||||
public @Nullable ContainerType closeContainerType(Container container) {
|
||||
return ContainerType.CONTAINER;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,11 +29,11 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
|||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
|
||||
import org.geysermc.geyser.inventory.BedrockContainerSlot;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.Container;
|
||||
import org.geysermc.geyser.inventory.updater.UIInventoryUpdater;
|
||||
import org.geysermc.geyser.level.block.Blocks;
|
||||
|
||||
public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslator {
|
||||
public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslator<Container> {
|
||||
public static final int TEMPLATE = 0;
|
||||
public static final int INPUT = 1;
|
||||
public static final int MATERIAL = 2;
|
||||
|
@ -55,13 +55,13 @@ public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslato
|
|||
}
|
||||
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot, Container container) {
|
||||
return switch (slot) {
|
||||
case TEMPLATE -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_TEMPLATE, 53);
|
||||
case INPUT -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_INPUT, 51);
|
||||
case MATERIAL -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_MATERIAL, 52);
|
||||
case OUTPUT -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_RESULT, 50);
|
||||
default -> super.javaSlotToBedrockContainer(slot);
|
||||
default -> super.javaSlotToBedrockContainer(slot, container);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -77,7 +77,7 @@ public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslato
|
|||
}
|
||||
|
||||
@Override
|
||||
public ContainerType closeContainerType(Inventory inventory) {
|
||||
public ContainerType closeContainerType(Container container) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,18 +42,18 @@ import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
|||
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket;
|
||||
|
||||
public class StonecutterInventoryTranslator extends AbstractBlockInventoryTranslator {
|
||||
public class StonecutterInventoryTranslator extends AbstractBlockInventoryTranslator<StonecutterContainer> {
|
||||
public StonecutterInventoryTranslator() {
|
||||
super(2, Blocks.STONECUTTER, org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.STONECUTTER, UIInventoryUpdater.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldHandleRequestFirst(ItemStackRequestAction action, Inventory inventory) {
|
||||
protected boolean shouldHandleRequestFirst(ItemStackRequestAction action, StonecutterContainer container) {
|
||||
return action.getType() == ItemStackRequestActionType.CRAFT_RECIPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ItemStackResponse translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) {
|
||||
protected ItemStackResponse translateSpecialRequest(GeyserSession session, StonecutterContainer container, ItemStackRequest request) {
|
||||
// Guarded by shouldHandleRequestFirst
|
||||
CraftRecipeAction data = (CraftRecipeAction) request.getActions()[0];
|
||||
|
||||
|
@ -63,24 +63,23 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl
|
|||
return rejectRequest(request);
|
||||
}
|
||||
|
||||
StonecutterContainer container = (StonecutterContainer) inventory;
|
||||
ItemStack javaOutput = craftingData.output();
|
||||
int button = craftingData.buttonId();
|
||||
|
||||
// If we've already pressed the button with this item, no need to press it again!
|
||||
if (container.getStonecutterButton() != button) {
|
||||
// Getting the index of the item in the Java stonecutter list
|
||||
ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getJavaId(), button);
|
||||
ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(container.getJavaId(), button);
|
||||
session.sendDownstreamGamePacket(packet);
|
||||
container.setStonecutterButton(button);
|
||||
}
|
||||
|
||||
if (inventory.getItem(1).getJavaId() != javaOutput.getId()) {
|
||||
if (container.getItem(1).getJavaId() != javaOutput.getId()) {
|
||||
// We don't know there is an output here, so we tell ourselves that there is
|
||||
inventory.setItem(1, GeyserItemStack.from(javaOutput), session);
|
||||
container.setItem(1, GeyserItemStack.from(javaOutput), session);
|
||||
}
|
||||
|
||||
return translateRequest(session, inventory, request);
|
||||
return translateRequest(session, container, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -93,14 +92,14 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl
|
|||
}
|
||||
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot, StonecutterContainer container) {
|
||||
if (slot == 0) {
|
||||
return new BedrockContainerSlot(ContainerSlotType.STONECUTTER_INPUT, 3);
|
||||
}
|
||||
if (slot == 1) {
|
||||
return new BedrockContainerSlot(ContainerSlotType.STONECUTTER_RESULT, 50);
|
||||
}
|
||||
return super.javaSlotToBedrockContainer(slot);
|
||||
return super.javaSlotToBedrockContainer(slot, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -123,12 +122,12 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl
|
|||
}
|
||||
|
||||
@Override
|
||||
public Inventory createInventory(GeyserSession session, String name, int windowId, ContainerType containerType, PlayerInventory playerInventory) {
|
||||
return new StonecutterContainer(session, name, windowId, this.size, containerType, playerInventory, this);
|
||||
public StonecutterContainer createInventory(GeyserSession session, String name, int windowId, ContainerType containerType) {
|
||||
return new StonecutterContainer(session, name, windowId, this.size, containerType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.cloudburstmc.protocol.bedrock.data.inventory.@Nullable ContainerType closeContainerType(Inventory inventory) {
|
||||
public org.cloudburstmc.protocol.bedrock.data.inventory.@Nullable ContainerType closeContainerType(StonecutterContainer container) {
|
||||
return org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType.STONECUTTER;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,13 +28,12 @@ package org.geysermc.geyser.translator.inventory.chest;
|
|||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
||||
import org.geysermc.geyser.inventory.BedrockContainerSlot;
|
||||
import org.geysermc.geyser.inventory.Container;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.updater.ChestInventoryUpdater;
|
||||
import org.geysermc.geyser.inventory.updater.InventoryUpdater;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.BaseInventoryTranslator;
|
||||
|
||||
public abstract class ChestInventoryTranslator extends BaseInventoryTranslator {
|
||||
public abstract class ChestInventoryTranslator<Type extends Container> extends BaseInventoryTranslator<Type> {
|
||||
private final InventoryUpdater updater;
|
||||
|
||||
public ChestInventoryTranslator(int size, int paddedSize) {
|
||||
|
@ -43,35 +42,43 @@ public abstract class ChestInventoryTranslator extends BaseInventoryTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, ContainerSlotType bedrockSourceContainer,
|
||||
protected boolean shouldRejectItemPlace(GeyserSession session, Type container, ContainerSlotType bedrockSourceContainer,
|
||||
int javaSourceSlot, ContainerSlotType bedrockDestinationContainer, int javaDestinationSlot) {
|
||||
// Reject any item placements that occur in the unusable inventory space
|
||||
if (bedrockSourceContainer == ContainerSlotType.LEVEL_ENTITY && javaSourceSlot >= this.size) {
|
||||
if (bedrockSourceContainer == slotType(container) && javaSourceSlot >= this.size) {
|
||||
return true;
|
||||
}
|
||||
return bedrockDestinationContainer == ContainerSlotType.LEVEL_ENTITY && javaDestinationSlot >= this.size;
|
||||
return bedrockDestinationContainer == slotType(container) && javaDestinationSlot >= this.size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresOpeningDelay(GeyserSession session, Inventory inventory) {
|
||||
return inventory instanceof Container container && !container.isUsingRealBlock();
|
||||
public boolean requiresOpeningDelay(GeyserSession session, Type container) {
|
||||
return !container.isUsingRealBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateInventory(GeyserSession session, Inventory inventory) {
|
||||
updater.updateInventory(this, session, inventory);
|
||||
public void updateInventory(GeyserSession session, Type container) {
|
||||
updater.updateInventory(this, session, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSlot(GeyserSession session, Inventory inventory, int slot) {
|
||||
updater.updateSlot(this, session, inventory, slot);
|
||||
public void updateSlot(GeyserSession session, Type container, int slot) {
|
||||
updater.updateSlot(this, session, container, slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int javaSlot) {
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int javaSlot, Type inventory) {
|
||||
if (javaSlot < this.size) {
|
||||
return new BedrockContainerSlot(ContainerSlotType.LEVEL_ENTITY, javaSlot);
|
||||
return new BedrockContainerSlot(slotType(inventory), javaSlot);
|
||||
}
|
||||
return super.javaSlotToBedrockContainer(javaSlot);
|
||||
return super.javaSlotToBedrockContainer(javaSlot, inventory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden by the SingleChestInventoryTranslator in case barrels are used.
|
||||
* Bedrock uses the ContainerSlotType.BARREL for those.
|
||||
*/
|
||||
protected ContainerSlotType slotType(Type type) {
|
||||
return ContainerSlotType.LEVEL_ENTITY;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ import org.geysermc.geyser.util.InventoryUtils;
|
|||
|
||||
import java.util.Objects;
|
||||
|
||||
public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
|
||||
public class DoubleChestInventoryTranslator extends ChestInventoryTranslator<Container> {
|
||||
private final int defaultJavaBlockState;
|
||||
|
||||
public DoubleChestInventoryTranslator(int size) {
|
||||
|
@ -68,9 +68,9 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
|
|||
* Mirrors {@link BlockInventoryHolder#canReuseContainer(GeyserSession, Container, Container)}
|
||||
*/
|
||||
@Override
|
||||
public boolean canReuseInventory(GeyserSession session, @NonNull Inventory inventory, @NonNull Inventory oldInventory) {
|
||||
if (!super.canReuseInventory(session, inventory, oldInventory) ||
|
||||
!(inventory instanceof Container container) ||
|
||||
public boolean canReuseInventory(GeyserSession session, @NonNull Inventory newInventory, @NonNull Inventory oldInventory) {
|
||||
if (!super.canReuseInventory(session, newInventory, oldInventory) ||
|
||||
!(newInventory instanceof Container) ||
|
||||
!(oldInventory instanceof Container previous)
|
||||
) {
|
||||
return false;
|
||||
|
@ -86,15 +86,15 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
|
|||
if (Objects.equals(position, previous.getHolderPosition())) {
|
||||
return true;
|
||||
} else {
|
||||
GeyserImpl.getInstance().getLogger().debug(session, "Not reusing inventory (%s) due to virtual block holder changing (%s -> %s)!",
|
||||
InventoryUtils.debugInventory(inventory), previous.getHolderPosition(), position);
|
||||
GeyserImpl.getInstance().getLogger().debug(session, "Not reusing inventory due to virtual block holder changing (%s -> %s)!",
|
||||
previous.getHolderPosition(), position);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean prepareInventory(GeyserSession session, Inventory inventory) {
|
||||
if (canUseRealBlock(session, inventory)) {
|
||||
public boolean prepareInventory(GeyserSession session, Container container) {
|
||||
if (canUseRealBlock(session, container)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -116,7 +116,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
|
|||
NbtMapBuilder tag = BlockEntityTranslator.getConstantBedrockTag("Chest", position)
|
||||
.putInt("pairx", pairPosition.getX())
|
||||
.putInt("pairz", pairPosition.getZ())
|
||||
.putString("CustomName", inventory.getTitle())
|
||||
.putString("CustomName", container.getTitle())
|
||||
.putBoolean("pairlead", false);
|
||||
|
||||
BlockEntityDataPacket dataPacket = new BlockEntityDataPacket();
|
||||
|
@ -138,7 +138,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
|
|||
.putInt("z", pairPosition.getZ())
|
||||
.putInt("pairx", position.getX())
|
||||
.putInt("pairz", position.getZ())
|
||||
.putString("CustomName", inventory.getTitle())
|
||||
.putString("CustomName", container.getTitle())
|
||||
.putBoolean("pairlead", true);
|
||||
|
||||
dataPacket = new BlockEntityDataPacket();
|
||||
|
@ -146,53 +146,37 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
|
|||
dataPacket.setBlockPosition(pairPosition);
|
||||
session.sendUpstreamPacket(dataPacket);
|
||||
|
||||
inventory.setHolderPosition(position);
|
||||
container.setHolderPosition(position);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openInventory(GeyserSession session, Inventory inventory) {
|
||||
public void openInventory(GeyserSession session, Container container) {
|
||||
ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket();
|
||||
containerOpenPacket.setId((byte) inventory.getBedrockId());
|
||||
containerOpenPacket.setId((byte) container.getBedrockId());
|
||||
containerOpenPacket.setType(ContainerType.CONTAINER);
|
||||
containerOpenPacket.setBlockPosition(inventory.getHolderPosition());
|
||||
containerOpenPacket.setUniqueEntityId(inventory.getHolderId());
|
||||
containerOpenPacket.setBlockPosition(container.getHolderPosition());
|
||||
containerOpenPacket.setUniqueEntityId(container.getHolderId());
|
||||
session.sendUpstreamPacket(containerOpenPacket);
|
||||
|
||||
GeyserImpl.getInstance().getLogger().debug(session, containerOpenPacket.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeInventory(GeyserSession session, Inventory inventory) {
|
||||
// this should no longer be possible; as we're storing the translator with the inventory to avoid desyncs.
|
||||
// TODO use generics to ensure we don't need to cast unsafely in the first place
|
||||
if (!(inventory instanceof Container container)) {
|
||||
GeyserImpl.getInstance().getLogger().warning("Tried to close a non-container inventory in a block inventory holder! Please report this error on discord.");
|
||||
GeyserImpl.getInstance().getLogger().warning("Current inventory translator: " + InventoryUtils.getInventoryTranslator(session).getClass().getSimpleName());
|
||||
GeyserImpl.getInstance().getLogger().warning("Current inventory: " + inventory.getClass().getSimpleName());
|
||||
// Try to save ourselves? maybe?
|
||||
// https://github.com/GeyserMC/Geyser/issues/4141
|
||||
// TODO: improve once this issue is pinned down
|
||||
if (session.getOpenInventory() != null) {
|
||||
session.getOpenInventory().getTranslator().closeInventory(session, inventory);
|
||||
session.setOpenInventory(null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
public void closeInventory(GeyserSession session, Container container, boolean force) {
|
||||
// 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.
|
||||
if (container.isDisplayed()) {
|
||||
ContainerClosePacket packet = new ContainerClosePacket();
|
||||
packet.setId((byte) inventory.getBedrockId());
|
||||
packet.setId((byte) container.getBedrockId());
|
||||
packet.setServerInitiated(true);
|
||||
packet.setType(ContainerType.CONTAINER);
|
||||
session.sendUpstreamPacket(packet);
|
||||
}
|
||||
|
||||
if (!container.isUsingRealBlock()) {
|
||||
Vector3i holderPos = inventory.getHolderPosition();
|
||||
Vector3i holderPos = container.getHolderPosition();
|
||||
int realBlock = session.getGeyser().getWorldManager().getBlockAt(session, holderPos);
|
||||
UpdateBlockPacket blockPacket = new UpdateBlockPacket();
|
||||
blockPacket.setDataLayer(0);
|
||||
|
@ -210,18 +194,18 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean canUseRealBlock(GeyserSession session, Inventory inventory) {
|
||||
private boolean canUseRealBlock(GeyserSession session, Container container) {
|
||||
// See BlockInventoryHolder - same concept there except we're also dealing with a specific block state
|
||||
if (session.getLastInteractionPlayerPosition().equals(session.getPlayerEntity().getPosition())) {
|
||||
BlockState state = session.getGeyser().getWorldManager().blockAt(session, session.getLastInteractionBlockPosition());
|
||||
if (!BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.get().containsKey(state.javaId())) {
|
||||
if ((state.block() == Blocks.CHEST || state.block() == Blocks.TRAPPED_CHEST)
|
||||
&& state.getValue(Properties.CHEST_TYPE) != ChestType.SINGLE) {
|
||||
inventory.setHolderPosition(session.getLastInteractionBlockPosition());
|
||||
((Container) inventory).setUsingRealBlock(true, state.block());
|
||||
container.setHolderPosition(session.getLastInteractionBlockPosition());
|
||||
container.setUsingRealBlock(true, state.block());
|
||||
|
||||
NbtMapBuilder tag = BlockEntityTranslator.getConstantBedrockTag("Chest", session.getLastInteractionBlockPosition())
|
||||
.putString("CustomName", inventory.getTitle());
|
||||
.putString("CustomName", container.getTitle());
|
||||
|
||||
DoubleChestBlockEntityTranslator.translateChestValue(tag, state,
|
||||
session.getLastInteractionBlockPosition().getX(), session.getLastInteractionBlockPosition().getZ());
|
||||
|
|
|
@ -25,9 +25,9 @@
|
|||
|
||||
package org.geysermc.geyser.translator.inventory.chest;
|
||||
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
|
||||
import org.geysermc.geyser.inventory.Container;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.Generic9X3Container;
|
||||
import org.geysermc.geyser.inventory.holder.BlockInventoryHolder;
|
||||
import org.geysermc.geyser.inventory.holder.InventoryHolder;
|
||||
import org.geysermc.geyser.level.block.Blocks;
|
||||
|
@ -36,7 +36,7 @@ import org.geysermc.geyser.level.block.property.Properties;
|
|||
import org.geysermc.geyser.level.block.type.BlockState;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
||||
public class SingleChestInventoryTranslator extends ChestInventoryTranslator {
|
||||
public class SingleChestInventoryTranslator extends ChestInventoryTranslator<Generic9X3Container> {
|
||||
private final InventoryHolder holder;
|
||||
|
||||
public SingleChestInventoryTranslator(int size) {
|
||||
|
@ -57,17 +57,30 @@ public class SingleChestInventoryTranslator extends ChestInventoryTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean prepareInventory(GeyserSession session, Inventory inventory) {
|
||||
return holder.prepareInventory(session, (Container) inventory);
|
||||
public boolean prepareInventory(GeyserSession session, Generic9X3Container container) {
|
||||
return holder.prepareInventory(session, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openInventory(GeyserSession session, Inventory inventory) {
|
||||
holder.openInventory(session, (Container) inventory);
|
||||
public void openInventory(GeyserSession session, Generic9X3Container container) {
|
||||
holder.openInventory(session, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeInventory(GeyserSession session, Inventory inventory) {
|
||||
holder.closeInventory(session, (Container) inventory, ContainerType.CONTAINER);
|
||||
public void closeInventory(GeyserSession session, Generic9X3Container container, boolean force) {
|
||||
holder.closeInventory(session, container, ContainerType.CONTAINER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Generic9X3Container createInventory(GeyserSession session, String name, int windowId, org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType containerType) {
|
||||
return new Generic9X3Container(session, name, windowId, this.size, containerType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ContainerSlotType slotType(Generic9X3Container generic9X3Container) {
|
||||
if (generic9X3Container.isBarrel()) {
|
||||
return ContainerSlotType.BARREL;
|
||||
}
|
||||
return super.slotType(generic9X3Container);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
|||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ContainerSetDataPacket;
|
||||
import org.geysermc.geyser.inventory.BedrockContainerSlot;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.Container;
|
||||
import org.geysermc.geyser.inventory.SlotType;
|
||||
import org.geysermc.geyser.inventory.updater.ContainerInventoryUpdater;
|
||||
import org.geysermc.geyser.level.block.property.Properties;
|
||||
|
@ -37,15 +37,15 @@ import org.geysermc.geyser.level.block.type.Block;
|
|||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.AbstractBlockInventoryTranslator;
|
||||
|
||||
public abstract class AbstractFurnaceInventoryTranslator extends AbstractBlockInventoryTranslator {
|
||||
public abstract class AbstractFurnaceInventoryTranslator extends AbstractBlockInventoryTranslator<Container> {
|
||||
AbstractFurnaceInventoryTranslator(Block javaBlock, ContainerType containerType) {
|
||||
super(3, javaBlock.defaultBlockState().withValue(Properties.LIT, false), containerType, ContainerInventoryUpdater.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) {
|
||||
public void updateProperty(GeyserSession session, Container container, int key, int value) {
|
||||
ContainerSetDataPacket dataPacket = new ContainerSetDataPacket();
|
||||
dataPacket.setWindowId((byte) inventory.getBedrockId());
|
||||
dataPacket.setWindowId((byte) container.getBedrockId());
|
||||
switch (key) {
|
||||
case 0:
|
||||
dataPacket.setProperty(ContainerSetDataPacket.FURNACE_LIT_TIME);
|
||||
|
@ -71,13 +71,13 @@ public abstract class AbstractFurnaceInventoryTranslator extends AbstractBlockIn
|
|||
}
|
||||
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot, Container container) {
|
||||
if (slot == 1) {
|
||||
return new BedrockContainerSlot(ContainerSlotType.FURNACE_FUEL, javaSlotToBedrock(slot));
|
||||
}
|
||||
if (slot == 2) {
|
||||
return new BedrockContainerSlot(ContainerSlotType.FURNACE_RESULT, javaSlotToBedrock(slot));
|
||||
}
|
||||
return super.javaSlotToBedrockContainer(slot);
|
||||
return super.javaSlotToBedrockContainer(slot, container);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
|||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
|
||||
import org.geysermc.geyser.inventory.BedrockContainerSlot;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.Container;
|
||||
import org.geysermc.geyser.level.block.Blocks;
|
||||
|
||||
public class BlastFurnaceInventoryTranslator extends AbstractFurnaceInventoryTranslator {
|
||||
|
@ -38,15 +38,15 @@ public class BlastFurnaceInventoryTranslator extends AbstractFurnaceInventoryTra
|
|||
}
|
||||
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot, Container container) {
|
||||
if (slot == 0) {
|
||||
return new BedrockContainerSlot(ContainerSlotType.BLAST_FURNACE_INGREDIENT, javaSlotToBedrock(slot));
|
||||
}
|
||||
return super.javaSlotToBedrockContainer(slot);
|
||||
return super.javaSlotToBedrockContainer(slot, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ContainerType closeContainerType(Inventory inventory) {
|
||||
public @Nullable ContainerType closeContainerType(Container container) {
|
||||
return ContainerType.BLAST_FURNACE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
|||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
|
||||
import org.geysermc.geyser.inventory.BedrockContainerSlot;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.Container;
|
||||
import org.geysermc.geyser.level.block.Blocks;
|
||||
|
||||
public class FurnaceInventoryTranslator extends AbstractFurnaceInventoryTranslator {
|
||||
|
@ -38,15 +38,15 @@ public class FurnaceInventoryTranslator extends AbstractFurnaceInventoryTranslat
|
|||
}
|
||||
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot, Container container) {
|
||||
if (slot == 0) {
|
||||
return new BedrockContainerSlot(ContainerSlotType.FURNACE_INGREDIENT, javaSlotToBedrock(slot));
|
||||
}
|
||||
return super.javaSlotToBedrockContainer(slot);
|
||||
return super.javaSlotToBedrockContainer(slot, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ContainerType closeContainerType(Inventory inventory) {
|
||||
public @Nullable ContainerType closeContainerType(Container container) {
|
||||
return ContainerType.FURNACE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
|||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
|
||||
import org.geysermc.geyser.inventory.BedrockContainerSlot;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.Container;
|
||||
import org.geysermc.geyser.level.block.Blocks;
|
||||
|
||||
public class SmokerInventoryTranslator extends AbstractFurnaceInventoryTranslator {
|
||||
|
@ -38,15 +38,15 @@ public class SmokerInventoryTranslator extends AbstractFurnaceInventoryTranslato
|
|||
}
|
||||
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot, Container container) {
|
||||
if (slot == 0) {
|
||||
return new BedrockContainerSlot(ContainerSlotType.SMOKER_INGREDIENT, javaSlotToBedrock(slot));
|
||||
}
|
||||
return super.javaSlotToBedrockContainer(slot);
|
||||
return super.javaSlotToBedrockContainer(slot, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ContainerType closeContainerType(Inventory inventory) {
|
||||
public @Nullable ContainerType closeContainerType(Container container) {
|
||||
return ContainerType.SMOKER;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,13 +25,13 @@
|
|||
|
||||
package org.geysermc.geyser.translator.inventory.horse;
|
||||
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.Container;
|
||||
import org.geysermc.geyser.inventory.updater.HorseInventoryUpdater;
|
||||
import org.geysermc.geyser.inventory.updater.InventoryUpdater;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.BaseInventoryTranslator;
|
||||
|
||||
public abstract class AbstractHorseInventoryTranslator extends BaseInventoryTranslator {
|
||||
public abstract class AbstractHorseInventoryTranslator extends BaseInventoryTranslator<Container> {
|
||||
private final InventoryUpdater updater;
|
||||
|
||||
public AbstractHorseInventoryTranslator(int size) {
|
||||
|
@ -40,27 +40,27 @@ public abstract class AbstractHorseInventoryTranslator extends BaseInventoryTran
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean prepareInventory(GeyserSession session, Inventory inventory) {
|
||||
public boolean prepareInventory(GeyserSession session, Container container) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openInventory(GeyserSession session, Inventory inventory) {
|
||||
public void openInventory(GeyserSession session, Container container) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeInventory(GeyserSession session, Inventory inventory) {
|
||||
public void closeInventory(GeyserSession session, Container container, boolean force) {
|
||||
// TODO find a way to implement
|
||||
// Can cause inventory de-sync if the Java server requests an inventory close
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateInventory(GeyserSession session, Inventory inventory) {
|
||||
updater.updateInventory(this, session, inventory);
|
||||
public void updateInventory(GeyserSession session, Container container) {
|
||||
updater.updateInventory(this, session, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSlot(GeyserSession session, Inventory inventory, int slot) {
|
||||
updater.updateSlot(this, session, inventory, slot);
|
||||
public void updateSlot(GeyserSession session, Container container, int slot) {
|
||||
updater.updateSlot(this, session, container, slot);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
|||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket;
|
||||
import org.geysermc.geyser.inventory.BedrockContainerSlot;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.Container;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
@ -63,14 +63,14 @@ public abstract class ChestedHorseInventoryTranslator extends AbstractHorseInven
|
|||
}
|
||||
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot, Container container) {
|
||||
if (slot == this.equipSlot) {
|
||||
return new BedrockContainerSlot(ContainerSlotType.HORSE_EQUIP, 0);
|
||||
}
|
||||
if (slot <= this.size - 1) { // Accommodate for the lack of one slot (saddle or armor)
|
||||
return new BedrockContainerSlot(ContainerSlotType.LEVEL_ENTITY, slot - 1);
|
||||
}
|
||||
return super.javaSlotToBedrockContainer(slot);
|
||||
return super.javaSlotToBedrockContainer(slot, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -85,11 +85,11 @@ public abstract class ChestedHorseInventoryTranslator extends AbstractHorseInven
|
|||
}
|
||||
|
||||
@Override
|
||||
public void updateInventory(GeyserSession session, Inventory inventory) {
|
||||
public void updateInventory(GeyserSession session, Container container) {
|
||||
ItemData[] bedrockItems = new ItemData[36];
|
||||
for (int i = 0; i < 36; i++) {
|
||||
final int offset = i < 9 ? 27 : -9;
|
||||
bedrockItems[i] = inventory.getItem(this.size + i + offset).getItemData(session);
|
||||
bedrockItems[i] = container.getItem(this.size + i + offset).getItemData(session);
|
||||
}
|
||||
InventoryContentPacket contentPacket = new InventoryContentPacket();
|
||||
contentPacket.setContainerId(ContainerId.INVENTORY);
|
||||
|
@ -99,13 +99,13 @@ public abstract class ChestedHorseInventoryTranslator extends AbstractHorseInven
|
|||
ItemData[] horseItems = new ItemData[chestSize + 1];
|
||||
// Manually specify the first slot - Java always has two slots (armor and saddle) and one is invisible.
|
||||
// Bedrock doesn't have this invisible slot.
|
||||
horseItems[0] = inventory.getItem(this.equipSlot).getItemData(session);
|
||||
horseItems[0] = container.getItem(this.equipSlot).getItemData(session);
|
||||
for (int i = 1; i < horseItems.length; i++) {
|
||||
horseItems[i] = inventory.getItem(i + 1).getItemData(session);
|
||||
horseItems[i] = container.getItem(i + 1).getItemData(session);
|
||||
}
|
||||
|
||||
InventoryContentPacket horseContentsPacket = new InventoryContentPacket();
|
||||
horseContentsPacket.setContainerId(inventory.getBedrockId());
|
||||
horseContentsPacket.setContainerId(container.getBedrockId());
|
||||
horseContentsPacket.setContents(Arrays.asList(horseItems));
|
||||
session.sendUpstreamPacket(horseContentsPacket);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.inventory.horse;
|
|||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData;
|
||||
import org.geysermc.geyser.inventory.BedrockContainerSlot;
|
||||
import org.geysermc.geyser.inventory.Container;
|
||||
|
||||
public class HorseInventoryTranslator extends AbstractHorseInventoryTranslator {
|
||||
public HorseInventoryTranslator(int size) {
|
||||
|
@ -43,10 +44,10 @@ public class HorseInventoryTranslator extends AbstractHorseInventoryTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
|
||||
public BedrockContainerSlot javaSlotToBedrockContainer(int slot, Container container) {
|
||||
if (slot == 0 || slot == 1) {
|
||||
return new BedrockContainerSlot(ContainerSlotType.HORSE_EQUIP, slot);
|
||||
}
|
||||
return super.javaSlotToBedrockContainer(slot);
|
||||
return super.javaSlotToBedrockContainer(slot, container);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -132,7 +132,7 @@ public class BedrockBookEditTranslator extends PacketTranslator<BookEditPacket>
|
|||
|
||||
// Update local copy
|
||||
session.getPlayerInventory().setItem(36 + session.getPlayerInventory().getHeldItemSlot(), GeyserItemStack.from(bookItem), session);
|
||||
session.getPlayerInventory().updateInventory();
|
||||
session.getPlayerInventoryHolder().updateInventory();
|
||||
|
||||
String title;
|
||||
if (packet.getAction() == BookEditPacket.Action.SIGN_BOOK) {
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.cloudburstmc.protocol.bedrock.packet.ContainerClosePacket;
|
|||
import org.cloudburstmc.protocol.bedrock.packet.NetworkStackLatencyPacket;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.InventoryHolder;
|
||||
import org.geysermc.geyser.inventory.MerchantContainer;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.MerchantInventoryTranslator;
|
||||
|
@ -54,17 +55,18 @@ public class BedrockContainerCloseTranslator extends PacketTranslator<ContainerC
|
|||
session.setClosingInventory(false);
|
||||
|
||||
// 1.21.70: Bedrock can reject opening inventories - in those cases it replies with -1
|
||||
Inventory openInventory = session.getOpenInventory();
|
||||
if (bedrockId == -1 && openInventory != null) {
|
||||
InventoryHolder<? extends Inventory> holder = session.getInventoryHolder();
|
||||
if (bedrockId == -1 && holder != null) {
|
||||
// 1.16.200 - window ID is always -1 sent from Bedrock for merchant containers
|
||||
if (openInventory.getTranslator() instanceof MerchantInventoryTranslator) {
|
||||
bedrockId = (byte) openInventory.getBedrockId();
|
||||
} else if (openInventory.getBedrockId() == session.getPendingOrCurrentBedrockInventoryId()) {
|
||||
if (holder.translator() instanceof MerchantInventoryTranslator) {
|
||||
bedrockId = (byte) holder.bedrockId();
|
||||
} else if (holder.bedrockId() == session.getPendingOrCurrentBedrockInventoryId()) {
|
||||
// If virtual inventories are opened too quickly, they can be occasionally rejected
|
||||
// We just try and queue a new one.
|
||||
// Before making another attempt to re-open, let's make sure we actually need this inventory open.
|
||||
if (session.getContainerOpenAttempts() < 3) {
|
||||
openInventory.setPending(true);
|
||||
if (holder.containerOpenAttempts() < 5) {
|
||||
holder.incrementContainerOpenAttempts();
|
||||
holder.pending(true);
|
||||
|
||||
session.scheduleInEventLoop(() -> {
|
||||
NetworkStackLatencyPacket latencyPacket = new NetworkStackLatencyPacket();
|
||||
|
@ -75,26 +77,25 @@ public class BedrockContainerCloseTranslator extends PacketTranslator<ContainerC
|
|||
}, 100, TimeUnit.MILLISECONDS);
|
||||
return;
|
||||
} else {
|
||||
GeyserImpl.getInstance().getLogger().debug(session, "Exceeded 3 attempts to open a virtual inventory!");
|
||||
GeyserImpl.getInstance().getLogger().debug(session, packet + " " + session.getOpenInventory().getClass().getSimpleName());
|
||||
GeyserImpl.getInstance().getLogger().debug(session, "Exceeded 5 attempts to open a virtual inventory!");
|
||||
GeyserImpl.getInstance().getLogger().debug(session, packet + " " + session.getInventoryHolder().getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
session.setPendingOrCurrentBedrockInventoryId(-1);
|
||||
session.setContainerOpenAttempts(0);
|
||||
closeCurrentOrOpenPending(session, bedrockId, openInventory);
|
||||
closeCurrentOrOpenPending(session, bedrockId, holder);
|
||||
}
|
||||
|
||||
private void closeCurrentOrOpenPending(GeyserSession session, byte bedrockId, Inventory openInventory) {
|
||||
if (openInventory != null) {
|
||||
if (bedrockId == openInventory.getBedrockId()) {
|
||||
InventoryUtils.sendJavaContainerClose(session, openInventory);
|
||||
InventoryUtils.closeInventory(session, openInventory.getJavaId(), false);
|
||||
} else if (openInventory.isPending()) {
|
||||
InventoryUtils.displayInventory(session, openInventory);
|
||||
private void closeCurrentOrOpenPending(GeyserSession session, byte bedrockId, InventoryHolder<? extends Inventory> holder) {
|
||||
if (holder != null) {
|
||||
if (bedrockId == holder.bedrockId()) {
|
||||
InventoryUtils.sendJavaContainerClose(holder);
|
||||
InventoryUtils.closeInventory(session, holder, false);
|
||||
} else if (holder.pending()) {
|
||||
InventoryUtils.displayInventory(holder);
|
||||
|
||||
if (openInventory instanceof MerchantContainer merchantContainer && merchantContainer.getPendingOffersPacket() != null) {
|
||||
if (holder.inventory() instanceof MerchantContainer merchantContainer && merchantContainer.getPendingOffersPacket() != null) {
|
||||
JavaMerchantOffersTranslator.openMerchant(session, merchantContainer.getPendingOffersPacket(), merchantContainer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.protocol.bedrock;
|
|||
import org.cloudburstmc.protocol.bedrock.packet.FilterTextPacket;
|
||||
import org.geysermc.geyser.inventory.AnvilContainer;
|
||||
import org.geysermc.geyser.inventory.CartographyContainer;
|
||||
import org.geysermc.geyser.inventory.InventoryHolder;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.Translator;
|
||||
|
@ -41,15 +42,20 @@ public class BedrockFilterTextTranslator extends PacketTranslator<FilterTextPack
|
|||
|
||||
@Override
|
||||
public void translate(GeyserSession session, FilterTextPacket packet) {
|
||||
if (session.getOpenInventory() instanceof CartographyContainer) {
|
||||
// We don't want to be able to rename in the cartography table
|
||||
return;
|
||||
InventoryHolder<?> holder = session.getInventoryHolder();
|
||||
|
||||
if (holder != null) {
|
||||
if (holder.inventory() instanceof CartographyContainer) {
|
||||
// We don't want to be able to rename in the cartography table
|
||||
return;
|
||||
}
|
||||
if (holder.inventory() instanceof AnvilContainer anvilContainer) {
|
||||
packet.setText(anvilContainer.checkForRename(session, packet.getText()));
|
||||
holder.updateSlot(1);
|
||||
}
|
||||
}
|
||||
|
||||
packet.setFromServer(true);
|
||||
if (session.getOpenInventory() instanceof AnvilContainer anvilContainer) {
|
||||
packet.setText(anvilContainer.checkForRename(session, packet.getText()));
|
||||
anvilContainer.updateSlot(1);
|
||||
}
|
||||
session.sendUpstreamPacket(packet);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,7 +70,6 @@ import org.geysermc.geyser.registry.BlockRegistries;
|
|||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.SkullCache;
|
||||
import org.geysermc.geyser.skin.FakeHeadProvider;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.geyser.translator.item.ItemTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.Translator;
|
||||
|
@ -363,7 +362,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
}
|
||||
case 1 -> {
|
||||
if (isIncorrectHeldItem(session, packet)) {
|
||||
InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR.updateSlot(session, session.getPlayerInventory(), session.getPlayerInventory().getOffsetForHotbar(packet.getHotbarSlot()));
|
||||
session.getPlayerInventoryHolder().updateSlot(session.getPlayerInventory().getOffsetForHotbar(packet.getHotbarSlot()));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -580,7 +579,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
session.sendUpstreamPacket(updateWaterPacket);
|
||||
|
||||
// Reset the item in hand to prevent "missing" blocks
|
||||
InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR.updateSlot(session, session.getPlayerInventory(), session.getPlayerInventory().getHeldItemSlot()); // TODO test
|
||||
session.getPlayerInventoryHolder().updateSlot(session.getPlayerInventory().getHeldItemSlot()); // TODO test
|
||||
}
|
||||
|
||||
private boolean isIncorrectHeldItem(GeyserSession session, InventoryTransactionPacket packet) {
|
||||
|
@ -599,9 +598,9 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
|
||||
private boolean useItem(GeyserSession session, InventoryTransactionPacket packet, int blockState) {
|
||||
// Update the player's inventory to remove any items added by the client itself
|
||||
Inventory playerInventory = session.getPlayerInventory();
|
||||
PlayerInventory playerInventory = session.getPlayerInventory();
|
||||
int heldItemSlot = playerInventory.getOffsetForHotbar(packet.getHotbarSlot());
|
||||
InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR.updateSlot(session, playerInventory, heldItemSlot);
|
||||
session.getPlayerInventoryHolder().updateSlot(heldItemSlot);
|
||||
GeyserItemStack itemStack = playerInventory.getItem(heldItemSlot);
|
||||
if (itemStack.getAmount() > 1) {
|
||||
if (itemStack.asItem() == Items.BUCKET || itemStack.asItem() == Items.GLASS_BOTTLE) {
|
||||
|
@ -614,7 +613,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
slot = playerInventory.getOffsetForHotbar(slot);
|
||||
}
|
||||
if (playerInventory.getItem(slot).isEmpty()) {
|
||||
InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR.updateSlot(session, playerInventory, slot);
|
||||
session.getPlayerInventoryHolder().updateSlot(slot);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,12 +26,10 @@
|
|||
package org.geysermc.geyser.translator.protocol.bedrock;
|
||||
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ItemStackRequestPacket;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.InventoryHolder;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.Translator;
|
||||
import org.geysermc.geyser.util.InventoryUtils;
|
||||
|
||||
/**
|
||||
* The packet sent for server-authoritative-style inventory transactions.
|
||||
|
@ -41,11 +39,10 @@ public class BedrockItemStackRequestTranslator extends PacketTranslator<ItemStac
|
|||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ItemStackRequestPacket packet) {
|
||||
Inventory inventory = session.getOpenInventory();
|
||||
if (inventory == null)
|
||||
InventoryHolder<?> holder = session.getInventoryHolder();
|
||||
if (holder == null)
|
||||
return;
|
||||
|
||||
InventoryTranslator translator = InventoryUtils.getInventoryTranslator(session);
|
||||
translator.translateRequests(session, inventory, packet.getRequests());
|
||||
holder.translateRequests(packet.getRequests());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
package org.geysermc.geyser.translator.protocol.bedrock;
|
||||
|
||||
import org.cloudburstmc.protocol.bedrock.packet.LecternUpdatePacket;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.InventoryHolder;
|
||||
import org.geysermc.geyser.inventory.LecternContainer;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
|
@ -43,15 +43,16 @@ public class BedrockLecternUpdateTranslator extends PacketTranslator<LecternUpda
|
|||
@Override
|
||||
public void translate(GeyserSession session, LecternUpdatePacket packet) {
|
||||
// Bedrock wants to either move a page or exit
|
||||
if (!(session.getOpenInventory() instanceof LecternContainer lecternContainer)) {
|
||||
InventoryHolder<?> holder = session.getInventoryHolder();
|
||||
if (holder == null || !(holder.inventory() instanceof LecternContainer lecternContainer)) {
|
||||
session.getGeyser().getLogger().debug("Expected lectern but it wasn't open!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (lecternContainer.getCurrentBedrockPage() == packet.getPage()) {
|
||||
// The same page means Bedrock is closing the window
|
||||
InventoryUtils.sendJavaContainerClose(session, lecternContainer);
|
||||
InventoryUtils.closeInventory(session, lecternContainer.getJavaId(), false);
|
||||
InventoryUtils.sendJavaContainerClose(holder);
|
||||
InventoryUtils.closeInventory(session, holder, false);
|
||||
} else {
|
||||
// Each "page" Bedrock gives to us actually represents two pages (think opening a book and seeing two pages)
|
||||
// Each "page" on Java is just one page (think a spiral notebook folded back to only show one page)
|
||||
|
@ -61,8 +62,7 @@ public class BedrockLecternUpdateTranslator extends PacketTranslator<LecternUpda
|
|||
// So, fun fact: We need to separately handle fake lecterns!
|
||||
// Since those are not actually a real lectern... the Java server won't respond to our requests.
|
||||
if (!lecternContainer.isUsingRealBlock()) {
|
||||
Inventory inventory = session.getOpenInventory();
|
||||
inventory.getTranslator().updateProperty(session, inventory, 0, newJavaPage);
|
||||
holder.updateProperty(0, newJavaPage);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ public class BedrockSetLocalPlayerAsInitializedTranslator extends PacketTranslat
|
|||
session.getEntityCache().updateBossBars();
|
||||
|
||||
// Double sigh - https://github.com/GeyserMC/Geyser/issues/2677 - as of Bedrock 1.18
|
||||
if (session.getOpenInventory() != null) {
|
||||
if (session.getInventoryHolder() != null) {
|
||||
InventoryUtils.openPendingInventory(session);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,13 +25,12 @@
|
|||
|
||||
package org.geysermc.geyser.translator.protocol.bedrock.entity;
|
||||
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSelectTradePacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.MerchantContainer;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.Translator;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSelectTradePacket;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -52,8 +51,7 @@ public class BedrockEntityEventTranslator extends PacketTranslator<EntityEventPa
|
|||
session.sendDownstreamGamePacket(selectTradePacket);
|
||||
|
||||
session.scheduleInEventLoop(() -> {
|
||||
Inventory openInventory = session.getOpenInventory();
|
||||
if (openInventory instanceof MerchantContainer merchantInventory) {
|
||||
if (session.getOpenInventory() instanceof MerchantContainer merchantInventory) {
|
||||
merchantInventory.onTradeSelected(session, packet.getData());
|
||||
}
|
||||
}, 100, TimeUnit.MILLISECONDS);
|
||||
|
|
|
@ -121,14 +121,14 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket>
|
|||
}
|
||||
break;
|
||||
case OPEN_INVENTORY:
|
||||
if (session.getOpenInventory() == null) {
|
||||
if (session.getInventoryHolder() == null) {
|
||||
Entity ridingEntity = session.getPlayerEntity().getVehicle();
|
||||
if (ridingEntity instanceof AbstractHorseEntity || ridingEntity instanceof ChestBoatEntity) {
|
||||
// This mob has an inventory of its own that we should open instead.
|
||||
ServerboundPlayerCommandPacket openVehicleWindowPacket = new ServerboundPlayerCommandPacket(session.getPlayerEntity().getEntityId(), PlayerState.OPEN_VEHICLE_INVENTORY);
|
||||
session.sendDownstreamGamePacket(openVehicleWindowPacket);
|
||||
} else {
|
||||
InventoryUtils.openInventory(session, session.getPlayerInventory());
|
||||
InventoryUtils.openInventory(session.getPlayerInventoryHolder());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ public class BedrockSetPlayerInventoryOptionsTranslator extends PacketTranslator
|
|||
|
||||
// This should ensure that we never send these packets when the player inventory is opened while in creative
|
||||
// Java edition can't craft in the 2x2 grid in creative, and subsequently doesn't have a recipe book
|
||||
if (session.getGameMode() == GameMode.CREATIVE && session.getPlayerInventory() == session.getOpenInventory()) {
|
||||
if (session.getGameMode() == GameMode.CREATIVE && session.getPlayerInventoryHolder() == session.getInventoryHolder()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ public class JavaRespawnTranslator extends PacketTranslator<ClientboundRespawnPa
|
|||
entity.setHealth(entity.getMaxHealth());
|
||||
entity.getAttributes().put(GeyserAttributeType.HEALTH, entity.createHealthAttribute());
|
||||
|
||||
session.setOpenInventory(null);
|
||||
session.setInventoryHolder(null);
|
||||
session.setClosingInventory(false);
|
||||
|
||||
entity.setLastDeathPosition(spawnInfo.getLastDeathPos());
|
||||
|
|
|
@ -48,7 +48,6 @@ import org.geysermc.geyser.entity.type.living.monster.CreakingEntity;
|
|||
import org.geysermc.geyser.entity.type.living.monster.WardenEntity;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.Translator;
|
||||
import org.geysermc.geyser.util.InventoryUtils;
|
||||
|
@ -186,7 +185,7 @@ public class JavaEntityEventTranslator extends PacketTranslator<ClientboundEntit
|
|||
|
||||
if (totemItemWorkaround) {
|
||||
// Reset the item again
|
||||
InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR.updateSlot(session, session.getPlayerInventory(), 45);
|
||||
session.getPlayerInventoryHolder().updateSlot(45);
|
||||
}
|
||||
|
||||
return;
|
||||
|
|
|
@ -25,7 +25,9 @@
|
|||
|
||||
package org.geysermc.geyser.translator.protocol.java.inventory;
|
||||
|
||||
import org.geysermc.geyser.inventory.PlayerInventory;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.InventoryHolder;
|
||||
import org.geysermc.geyser.inventory.LecternContainer;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.Translator;
|
||||
|
@ -39,7 +41,19 @@ public class JavaContainerCloseTranslator extends PacketTranslator<ClientboundCo
|
|||
public void translate(GeyserSession session, ClientboundContainerClosePacket packet) {
|
||||
// Sometimes the server can request a window close of ID 0... when the window isn't even open
|
||||
// Don't confirm in this instance
|
||||
session.setServerRequestedClosePlayerInventory(packet.getContainerId() == 0 && session.getOpenInventory() instanceof PlayerInventory);
|
||||
InventoryUtils.closeInventory(session, packet.getContainerId(), (session.getOpenInventory() != null && session.getOpenInventory().getJavaId() == packet.getContainerId()));
|
||||
InventoryHolder<? extends Inventory> holder = session.getInventoryHolder();
|
||||
boolean confirm = false;
|
||||
if (holder != null) {
|
||||
if (packet.getContainerId() == 0) {
|
||||
if (holder.inventory() instanceof LecternContainer container && container.isBookInPlayerInventory()) {
|
||||
InventoryUtils.closeInventory(session, holder, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
confirm = holder.javaId() == packet.getContainerId();
|
||||
}
|
||||
|
||||
InventoryUtils.closeInventory(session, packet.getContainerId(), confirm);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,9 +28,8 @@ package org.geysermc.geyser.translator.protocol.java.inventory;
|
|||
import org.geysermc.geyser.GeyserLogger;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.InventoryHolder;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.geyser.translator.inventory.PlayerInventoryTranslator;
|
||||
import org.geysermc.geyser.translator.inventory.SmithingInventoryTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.Translator;
|
||||
|
@ -42,10 +41,12 @@ public class JavaContainerSetContentTranslator extends PacketTranslator<Clientbo
|
|||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundContainerSetContentPacket packet) {
|
||||
Inventory inventory = InventoryUtils.getInventory(session, packet.getContainerId());
|
||||
if (inventory == null)
|
||||
InventoryHolder<?> holder = InventoryUtils.getInventory(session, packet.getContainerId());
|
||||
if (holder == null)
|
||||
return;
|
||||
|
||||
Inventory inventory = holder.inventory();
|
||||
|
||||
int inventorySize = inventory.getSize();
|
||||
for (int i = 0; i < packet.getItems().length; i++) {
|
||||
if (i >= inventorySize) {
|
||||
|
@ -56,7 +57,7 @@ public class JavaContainerSetContentTranslator extends PacketTranslator<Clientbo
|
|||
logger.debug(packet);
|
||||
logger.debug(inventory);
|
||||
}
|
||||
updateInventory(session, inventory, packet.getContainerId());
|
||||
holder.updateInventory();
|
||||
// 1.18.1 behavior: the previous items will be correctly set, but the state ID and carried item will not
|
||||
// as this produces a stack trace on the client.
|
||||
// If Java processes this correctly in the future, we can revert this behavior
|
||||
|
@ -68,7 +69,7 @@ public class JavaContainerSetContentTranslator extends PacketTranslator<Clientbo
|
|||
inventory.setItem(i, newItem, session);
|
||||
}
|
||||
|
||||
updateInventory(session, inventory, packet.getContainerId());
|
||||
holder.updateInventory();
|
||||
|
||||
int stateId = packet.getStateId();
|
||||
session.setEmulatePost1_16Logic(stateId > 0 || stateId != inventory.getStateId());
|
||||
|
@ -79,25 +80,15 @@ public class JavaContainerSetContentTranslator extends PacketTranslator<Clientbo
|
|||
session.getPlayerInventory().setCursor(cursor, session);
|
||||
InventoryUtils.updateCursor(session);
|
||||
|
||||
if (InventoryUtils.getInventoryTranslator(session) instanceof SmithingInventoryTranslator) {
|
||||
if (holder.translator() instanceof SmithingInventoryTranslator) {
|
||||
// On 1.21.1, the recipe output is sometimes only updated here.
|
||||
// This can be replicated with shift-clicking the last item into the smithing table.
|
||||
// It seems that something in Via 5.1.1 causes 1.21.3 clients - even Java ones -
|
||||
// to make the server send a slot update.
|
||||
// That plus shift-clicking means that the state ID becomes outdated and forces
|
||||
// a complete inventory update.
|
||||
JavaContainerSetSlotTranslator.updateSmithingTableOutput(session, SmithingInventoryTranslator.OUTPUT,
|
||||
packet.getItems()[SmithingInventoryTranslator.OUTPUT], inventory);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateInventory(GeyserSession session, Inventory inventory, int containerId) {
|
||||
InventoryTranslator translator = InventoryUtils.getInventoryTranslator(session);
|
||||
if (containerId == 0 && !(translator instanceof PlayerInventoryTranslator)) {
|
||||
// In rare cases, the window ID can still be 0 but Java treats it as valid
|
||||
InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR.updateInventory(session, inventory);
|
||||
} else {
|
||||
translator.updateInventory(session, inventory);
|
||||
JavaContainerSetSlotTranslator.updateSmithingTableOutput(SmithingInventoryTranslator.OUTPUT,
|
||||
packet.getItems()[SmithingInventoryTranslator.OUTPUT], holder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
package org.geysermc.geyser.translator.protocol.java.inventory;
|
||||
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.InventoryHolder;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.Translator;
|
||||
|
@ -37,7 +37,7 @@ public class JavaContainerSetDataTranslator extends PacketTranslator<Clientbound
|
|||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundContainerSetDataPacket packet) {
|
||||
Inventory inventory = InventoryUtils.getInventory(session, packet.getContainerId());
|
||||
InventoryHolder<?> inventory = InventoryUtils.getInventory(session, packet.getContainerId());
|
||||
if (inventory == null)
|
||||
return;
|
||||
|
||||
|
|
|
@ -36,12 +36,11 @@ import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket;
|
|||
import org.geysermc.geyser.GeyserLogger;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.InventoryHolder;
|
||||
import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe;
|
||||
import org.geysermc.geyser.inventory.recipe.GeyserSmithingRecipe;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.geyser.translator.inventory.PlayerInventoryTranslator;
|
||||
import org.geysermc.geyser.translator.inventory.SmithingInventoryTranslator;
|
||||
import org.geysermc.geyser.translator.item.ItemTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
|
@ -64,68 +63,60 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator<Clientbound
|
|||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundContainerSetSlotPacket packet) {
|
||||
//TODO: support window id -2, should update player inventory
|
||||
//TODO: ^ I think this is outdated.
|
||||
Inventory inventory = InventoryUtils.getInventory(session, packet.getContainerId());
|
||||
if (inventory == null) {
|
||||
InventoryHolder<?> holder = InventoryUtils.getInventory(session, packet.getContainerId());
|
||||
if (holder == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
InventoryTranslator translator = InventoryUtils.getInventoryTranslator(session);
|
||||
if (translator != null) {
|
||||
int slot = packet.getSlot();
|
||||
if (slot >= inventory.getSize()) {
|
||||
GeyserLogger logger = session.getGeyser().getLogger();
|
||||
logger.warning("ClientboundContainerSetSlotPacket sent to " + session.bedrockUsername()
|
||||
+ " that exceeds inventory size!");
|
||||
if (logger.isDebug()) {
|
||||
logger.debug(packet.toString());
|
||||
logger.debug(inventory.toString());
|
||||
}
|
||||
// 1.19.0 behavior: the state ID will not be set due to exception
|
||||
return;
|
||||
Inventory inventory = holder.inventory();
|
||||
int slot = packet.getSlot();
|
||||
if (slot >= inventory.getSize()) {
|
||||
GeyserLogger logger = session.getGeyser().getLogger();
|
||||
logger.warning("ClientboundContainerSetSlotPacket sent to " + session.bedrockUsername()
|
||||
+ " that exceeds inventory size!");
|
||||
if (logger.isDebug()) {
|
||||
logger.debug(packet.toString());
|
||||
logger.debug(inventory.toString());
|
||||
}
|
||||
|
||||
if (translator instanceof SmithingInventoryTranslator) {
|
||||
updateSmithingTableOutput(session, slot, packet.getItem(), inventory);
|
||||
} else {
|
||||
updateCraftingGrid(session, slot, packet.getItem(), inventory, translator);
|
||||
}
|
||||
|
||||
GeyserItemStack newItem = GeyserItemStack.from(packet.getItem());
|
||||
session.getBundleCache().initialize(newItem);
|
||||
if (packet.getContainerId() == 0 && !(translator instanceof PlayerInventoryTranslator)) {
|
||||
// In rare cases, the window ID can still be 0 but Java treats it as valid
|
||||
// This behavior still exists as of Java Edition 1.21.2, despite the new packet
|
||||
session.getPlayerInventory().setItem(slot, newItem, session);
|
||||
InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR.updateSlot(session, session.getPlayerInventory(), slot);
|
||||
} else {
|
||||
inventory.setItem(slot, newItem, session);
|
||||
translator.updateSlot(session, inventory, slot);
|
||||
}
|
||||
|
||||
// Intentional behavior here below the cursor; Minecraft 1.18.1 also does this.
|
||||
int stateId = packet.getStateId();
|
||||
session.setEmulatePost1_16Logic(stateId > 0 || stateId != inventory.getStateId());
|
||||
inventory.setStateId(stateId);
|
||||
// 1.19.0 behavior: the state ID will not be set due to exception
|
||||
return;
|
||||
}
|
||||
|
||||
if (holder.translator() instanceof SmithingInventoryTranslator) {
|
||||
updateSmithingTableOutput(slot, packet.getItem(), holder);
|
||||
} else {
|
||||
updateCraftingGrid(slot, packet.getItem(), holder);
|
||||
}
|
||||
|
||||
GeyserItemStack newItem = GeyserItemStack.from(packet.getItem());
|
||||
session.getBundleCache().initialize(newItem);
|
||||
|
||||
holder.inventory().setItem(slot, newItem, session);
|
||||
holder.updateSlot(slot);
|
||||
|
||||
// Intentional behavior here below the cursor; Minecraft 1.18.1 also does this.
|
||||
int stateId = packet.getStateId();
|
||||
session.setEmulatePost1_16Logic(stateId > 0 || stateId != inventory.getStateId());
|
||||
inventory.setStateId(stateId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for a changed output slot in the crafting grid, and ensures Bedrock sees the recipe.
|
||||
*/
|
||||
private static void updateCraftingGrid(GeyserSession session, int slot, ItemStack item, Inventory inventory, InventoryTranslator translator) {
|
||||
private static void updateCraftingGrid(int slot, ItemStack item, InventoryHolder<? extends Inventory> holder) {
|
||||
// Check if it's the crafting grid result slot.
|
||||
if (slot != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if there is any crafting grid.
|
||||
int gridSize = translator.getGridSize();
|
||||
int gridSize = holder.translator().getGridSize();
|
||||
if (gridSize == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
GeyserSession session = holder.session();
|
||||
|
||||
// Only process the most recent crafting grid result, and cancel the previous one.
|
||||
if (session.getContainerOutputFuture() != null) {
|
||||
session.getContainerOutputFuture().cancel(false);
|
||||
|
@ -142,7 +133,7 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator<Clientbound
|
|||
int firstCol = -1, width = -1;
|
||||
for (int row = 0; row < gridDimensions; row++) {
|
||||
for (int col = 0; col < gridDimensions; col++) {
|
||||
if (!inventory.getItem(col + (row * gridDimensions) + 1).isEmpty()) {
|
||||
if (!holder.inventory().getItem(col + (row * gridDimensions) + 1).isEmpty()) {
|
||||
if (firstRow == -1) {
|
||||
firstRow = row;
|
||||
firstCol = col;
|
||||
|
@ -163,7 +154,7 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator<Clientbound
|
|||
height += -firstRow + 1;
|
||||
width += -firstCol + 1;
|
||||
|
||||
if (InventoryUtils.getValidRecipe(session, item, inventory::getItem, gridDimensions, firstRow,
|
||||
if (InventoryUtils.getValidRecipe(session, item, holder.inventory()::getItem, gridDimensions, firstRow,
|
||||
height, firstCol, width) != null) {
|
||||
// Recipe is already present on the client; don't send packet
|
||||
return;
|
||||
|
@ -178,7 +169,7 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator<Clientbound
|
|||
int index = 0;
|
||||
for (int row = firstRow; row < height + firstRow; row++) {
|
||||
for (int col = firstCol; col < width + firstCol; col++) {
|
||||
GeyserItemStack geyserItemStack = inventory.getItem(col + (row * gridDimensions) + 1);
|
||||
GeyserItemStack geyserItemStack = holder.inventory().getItem(col + (row * gridDimensions) + 1);
|
||||
ingredients[index] = geyserItemStack.getItemData(session);
|
||||
javaIngredients.add(geyserItemStack.asSlotDisplay());
|
||||
|
||||
|
@ -225,10 +216,11 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator<Clientbound
|
|||
}, 150, TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
static void updateSmithingTableOutput(GeyserSession session, int slot, ItemStack output, Inventory inventory) {
|
||||
static void updateSmithingTableOutput(int slot, ItemStack output, InventoryHolder<?> holder) {
|
||||
if (slot != SmithingInventoryTranslator.OUTPUT) {
|
||||
return;
|
||||
}
|
||||
GeyserSession session = holder.session();
|
||||
|
||||
// Only process the most recent output result, and cancel the previous one.
|
||||
if (session.getContainerOutputFuture() != null) {
|
||||
|
@ -239,6 +231,7 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator<Clientbound
|
|||
return;
|
||||
}
|
||||
|
||||
Inventory inventory = holder.inventory();
|
||||
session.setContainerOutputFuture(session.scheduleInEventLoop(() -> {
|
||||
GeyserItemStack template = inventory.getItem(SmithingInventoryTranslator.TEMPLATE);
|
||||
if (template.asItem() != Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE) {
|
||||
|
@ -285,11 +278,11 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator<Clientbound
|
|||
// Just set one of the slots to air, then right back to its proper item.
|
||||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||
slotPacket.setContainerId(ContainerId.UI);
|
||||
slotPacket.setSlot(InventoryUtils.getInventoryTranslator(session).javaSlotToBedrock(SmithingInventoryTranslator.MATERIAL));
|
||||
slotPacket.setSlot(holder.translator().javaSlotToBedrock(SmithingInventoryTranslator.MATERIAL));
|
||||
slotPacket.setItem(ItemData.AIR);
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
|
||||
InventoryUtils.getInventoryTranslator(session).updateSlot(session, inventory, SmithingInventoryTranslator.MATERIAL);
|
||||
holder.updateSlot(SmithingInventoryTranslator.MATERIAL);
|
||||
}, 150, TimeUnit.MILLISECONDS));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.geysermc.geyser.entity.type.living.animal.horse.LlamaEntity;
|
|||
import org.geysermc.geyser.entity.type.living.animal.horse.SkeletonHorseEntity;
|
||||
import org.geysermc.geyser.entity.type.living.animal.horse.ZombieHorseEntity;
|
||||
import org.geysermc.geyser.inventory.Container;
|
||||
import org.geysermc.geyser.inventory.InventoryHolder;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.geyser.translator.inventory.horse.DonkeyInventoryTranslator;
|
||||
|
@ -119,7 +120,7 @@ public class JavaHorseScreenOpenTranslator extends PacketTranslator<ClientboundH
|
|||
// but everything is still indexed the same.
|
||||
int slotCount = 2; // Don't depend on slot count sent from server
|
||||
|
||||
InventoryTranslator inventoryTranslator;
|
||||
InventoryTranslator<Container> inventoryTranslator;
|
||||
if (entity instanceof LlamaEntity llamaEntity) {
|
||||
if (entity.getFlag(EntityFlag.CHESTED)) {
|
||||
slotCount += llamaEntity.getStrength() * 3;
|
||||
|
@ -153,6 +154,7 @@ public class JavaHorseScreenOpenTranslator extends PacketTranslator<ClientboundH
|
|||
updateEquipPacket.setTag(builder.build());
|
||||
session.sendUpstreamPacket(updateEquipPacket);
|
||||
|
||||
InventoryUtils.openInventory(session, new Container(session, entity.getNametag(), packet.getContainerId(), slotCount, null, session.getPlayerInventory(), inventoryTranslator));
|
||||
Container container = new Container(session, entity.getNametag(), packet.getContainerId(), slotCount, null);
|
||||
InventoryUtils.openInventory(new InventoryHolder<>(session, container, inventoryTranslator));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
package org.geysermc.geyser.translator.protocol.java.inventory;
|
||||
|
||||
import org.geysermc.geyser.inventory.InventoryHolder;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.inventory.VillagerTrade;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
||||
|
@ -56,13 +57,18 @@ public class JavaMerchantOffersTranslator extends PacketTranslator<ClientboundMe
|
|||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundMerchantOffersPacket packet) {
|
||||
Inventory openInventory = session.getOpenInventory();
|
||||
if (!(openInventory instanceof MerchantContainer merchantInventory && openInventory.getJavaId() == packet.getContainerId())) {
|
||||
InventoryHolder<?> holder = session.getInventoryHolder();
|
||||
if (holder == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Inventory inventory = holder.inventory();
|
||||
if (!(inventory instanceof MerchantContainer merchantInventory && inventory.getJavaId() == packet.getContainerId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// No previous inventory was closed -> no need of queuing the merchant inventory
|
||||
if (!openInventory.isPending()) {
|
||||
if (!holder.pending()) {
|
||||
openMerchant(session, packet, merchantInventory);
|
||||
return;
|
||||
}
|
||||
|
@ -94,7 +100,7 @@ public class JavaMerchantOffersTranslator extends PacketTranslator<ClientboundMe
|
|||
updateTradePacket.setTradeTier(packet.getVillagerLevel() - 1);
|
||||
updateTradePacket.setContainerId((short) packet.getContainerId());
|
||||
updateTradePacket.setContainerType(ContainerType.TRADE);
|
||||
updateTradePacket.setDisplayName(session.getOpenInventory().getTitle());
|
||||
updateTradePacket.setDisplayName(merchantInventory.getTitle());
|
||||
updateTradePacket.setSize(0);
|
||||
updateTradePacket.setNewTradingUi(true);
|
||||
updateTradePacket.setUsingEconomyTrade(true);
|
||||
|
|
|
@ -26,15 +26,15 @@
|
|||
package org.geysermc.geyser.translator.protocol.java.inventory;
|
||||
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.InventoryHolder;
|
||||
import org.geysermc.geyser.inventory.LecternContainer;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
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.data.game.inventory.ContainerType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundOpenBookPacket;
|
||||
|
||||
import java.util.Objects;
|
||||
|
@ -59,21 +59,21 @@ public class JavaOpenBookTranslator extends PacketTranslator<ClientboundOpenBook
|
|||
return;
|
||||
}
|
||||
|
||||
if (stack.asItem().equals(Items.WRITTEN_BOOK)) {
|
||||
Inventory openInventory = session.getOpenInventory();
|
||||
// The item doesn't need to be a book; just needs to have either of these components.
|
||||
if (stack.getComponent(DataComponentTypes.WRITABLE_BOOK_CONTENT) != null ||
|
||||
stack.getComponent(DataComponentTypes.WRITTEN_BOOK_CONTENT) != null) {
|
||||
InventoryHolder<?> openInventory = session.getInventoryHolder();
|
||||
if (openInventory != null) {
|
||||
InventoryUtils.closeInventory(session, openInventory.getJavaId(), true);
|
||||
InventoryUtils.sendJavaContainerClose(session, openInventory);
|
||||
InventoryUtils.sendJavaContainerClose(openInventory);
|
||||
InventoryUtils.closeInventory(session, openInventory, true);
|
||||
}
|
||||
|
||||
InventoryTranslator translator = InventoryTranslator.inventoryTranslator(ContainerType.LECTERN);
|
||||
//noinspection unchecked
|
||||
InventoryTranslator<LecternContainer> translator = (InventoryTranslator<LecternContainer>) InventoryTranslator.inventoryTranslator(ContainerType.LECTERN);
|
||||
Objects.requireNonNull(translator, "could not find lectern inventory translator!");
|
||||
|
||||
// Should never be null
|
||||
Objects.requireNonNull(translator, "lectern translator must exist");
|
||||
Inventory inventory = translator.createInventory(session, "", FAKE_LECTERN_WINDOW_ID, ContainerType.LECTERN, session.getPlayerInventory());
|
||||
((LecternContainer) inventory).setFakeLecternBook(stack, session);
|
||||
InventoryUtils.openInventory(session, inventory);
|
||||
LecternContainer container = translator.createInventory(session, "", FAKE_LECTERN_WINDOW_ID, ContainerType.LECTERN);
|
||||
container.setVirtualLecternBook(stack, session);
|
||||
InventoryUtils.openInventory(new InventoryHolder<>(session, container, translator));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.protocol.java.inventory;
|
|||
import net.kyori.adventure.text.Component;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.InventoryHolder;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.geyser.translator.inventory.OldSmithingTableTranslator;
|
||||
|
@ -51,8 +52,8 @@ public class JavaOpenScreenTranslator extends PacketTranslator<ClientboundOpenSc
|
|||
return;
|
||||
}
|
||||
|
||||
InventoryTranslator newTranslator;
|
||||
Inventory openInventory = session.getOpenInventory();
|
||||
InventoryTranslator<? extends Inventory> newTranslator;
|
||||
InventoryHolder<? extends Inventory> currentInventory = session.getInventoryHolder();
|
||||
|
||||
// Hack: ViaVersion translates the old (pre 1.20) smithing table to a anvil (does not work for Bedrock). We can detect this and translate it back to a smithing table.
|
||||
// (Implementation note: used to be a furnace. Was changed sometime before 1.21.2)
|
||||
|
@ -64,8 +65,8 @@ public class JavaOpenScreenTranslator extends PacketTranslator<ClientboundOpenSc
|
|||
|
||||
// No translator exists for this window type. Close all windows and return.
|
||||
if (newTranslator == null) {
|
||||
if (openInventory != null) {
|
||||
InventoryUtils.closeInventory(session, openInventory.getJavaId(), true);
|
||||
if (currentInventory != null) {
|
||||
InventoryUtils.closeInventory(session, currentInventory, true);
|
||||
}
|
||||
|
||||
ServerboundContainerClosePacket closeWindowPacket = new ServerboundContainerClosePacket(packet.getContainerId());
|
||||
|
@ -75,35 +76,26 @@ public class JavaOpenScreenTranslator extends PacketTranslator<ClientboundOpenSc
|
|||
|
||||
String name = MessageTranslator.convertMessage(packet.getTitle(), session.locale());
|
||||
|
||||
Inventory newInventory = newTranslator.createInventory(session, name, packet.getContainerId(), packet.getType(), session.getPlayerInventory());
|
||||
if (openInventory != null) {
|
||||
var newInventory = newTranslator.createInventory(session, name, packet.getContainerId(), packet.getType());
|
||||
InventoryHolder<? extends Inventory> newInventoryHolder = new InventoryHolder<>(session, newInventory, newTranslator);
|
||||
if (currentInventory != null) {
|
||||
// Attempt to re-use existing open inventories, if possible.
|
||||
// Pending inventories are also considered, as a Java server can re-request the same inventory.
|
||||
if (newTranslator.canReuseInventory(session, newInventory, openInventory)) {
|
||||
// Use the same Bedrock id
|
||||
newInventory.setBedrockId(openInventory.getBedrockId());
|
||||
|
||||
// Also mirror other properties - in case we're e.g. dealing with a pending virtual inventory
|
||||
boolean pending = openInventory.isPending();
|
||||
newInventory.setDisplayed(openInventory.isDisplayed());
|
||||
newInventory.setPending(pending);
|
||||
newInventory.setHolderPosition(openInventory.getHolderPosition());
|
||||
newInventory.setHolderId(openInventory.getHolderId());
|
||||
session.setOpenInventory(newInventory);
|
||||
|
||||
GeyserImpl.getInstance().getLogger().debug(session, "Able to reuse current inventory. Is current pending? %s", pending);
|
||||
if (newTranslator.canReuseInventory(session, newInventory, currentInventory.inventory())) {
|
||||
newInventoryHolder.inheritFromExisting(currentInventory);
|
||||
GeyserImpl.getInstance().getLogger().debug(session, "Able to reuse current inventory. Is current pending? %s", currentInventory.pending());
|
||||
|
||||
// If the current inventory is still pending, it'll be updated once open
|
||||
if (newInventory.isDisplayed()) {
|
||||
newTranslator.updateInventory(session, newInventory);
|
||||
newInventoryHolder.updateInventory();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
InventoryUtils.closeInventory(session, openInventory.getJavaId(), true);
|
||||
InventoryUtils.closeInventory(session, currentInventory, true);
|
||||
}
|
||||
|
||||
InventoryUtils.openInventory(session, newInventory);
|
||||
InventoryUtils.openInventory(newInventoryHolder);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@ package org.geysermc.geyser.translator.protocol.java.inventory;
|
|||
import org.geysermc.geyser.GeyserLogger;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.Translator;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundSetPlayerInventoryPacket;
|
||||
|
@ -58,6 +57,6 @@ public class JavaSetPlayerInventoryTranslator extends PacketTranslator<Clientbou
|
|||
GeyserItemStack newItem = GeyserItemStack.from(packet.getContents());
|
||||
session.getBundleCache().initialize(newItem);
|
||||
session.getPlayerInventory().setItem(slot, newItem, session);
|
||||
InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR.updateSlot(session, session.getPlayerInventory(), slot);
|
||||
session.getPlayerInventoryHolder().updateSlot(slot);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
|
||||
package org.geysermc.geyser.util;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.cloudburstmc.math.vector.Vector3i;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
|
@ -39,7 +38,7 @@ import org.cloudburstmc.protocol.bedrock.packet.NetworkStackLatencyPacket;
|
|||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.LecternContainer;
|
||||
import org.geysermc.geyser.inventory.InventoryHolder;
|
||||
import org.geysermc.geyser.inventory.click.Click;
|
||||
import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
|
||||
import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe;
|
||||
|
@ -54,8 +53,6 @@ import org.geysermc.geyser.session.cache.registry.JavaRegistries;
|
|||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
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.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;
|
||||
|
@ -65,6 +62,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.ItemSta
|
|||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.TagSlotDisplay;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.WithRemainderSlotDisplay;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundOpenBookPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClosePacket;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
|
||||
|
@ -95,20 +93,20 @@ public class InventoryUtils {
|
|||
* The main entrypoint to open an inventory. It will mark inventories as pending when the client isn't ready to
|
||||
* open the new inventory yet.
|
||||
*
|
||||
* @param session the geyser session
|
||||
* @param inventory the new inventory to open
|
||||
* @param holder the new inventory to open
|
||||
*/
|
||||
public static void openInventory(GeyserSession session, Inventory inventory) {
|
||||
session.setOpenInventory(inventory);
|
||||
if (session.isClosingInventory() || !session.getUpstream().isInitialized() || session.getPendingOrCurrentBedrockInventoryId() != -1) {
|
||||
public static void openInventory(InventoryHolder<?> holder) {
|
||||
holder.markCurrent();
|
||||
if (holder.shouldSetPending()) {
|
||||
// Wait for close confirmation from client before opening the new inventory.
|
||||
// Handled in BedrockContainerCloseTranslator
|
||||
// or - client hasn't yet loaded in; wait until inventory is shown
|
||||
inventory.setPending(true);
|
||||
GeyserImpl.getInstance().getLogger().debug(session, "Inventory (%s) set pending: closing inv? %s, pending inv id? %s", debugInventory(inventory), session.isClosingInventory(), session.getPendingOrCurrentBedrockInventoryId());
|
||||
holder.pending(true);
|
||||
GeyserImpl.getInstance().getLogger().debug(holder.session(), "Inventory (%s) set pending: closing inv? %s, pending inv id? %s",
|
||||
debugInventory(holder), holder.session().isClosingInventory(), holder.session().getPendingOrCurrentBedrockInventoryId());
|
||||
return;
|
||||
}
|
||||
displayInventory(session, inventory);
|
||||
displayInventory(holder);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -117,71 +115,57 @@ public class InventoryUtils {
|
|||
* occurred in the time. For example, a queued virtual inventory might be "outdated", so we wouldn't open it.
|
||||
*/
|
||||
public static void openPendingInventory(GeyserSession session) {
|
||||
Inventory currentInventory = session.getOpenInventory();
|
||||
if (currentInventory == null || !currentInventory.isPending()) {
|
||||
InventoryHolder<?> holder = session.getInventoryHolder();
|
||||
if (holder == null || !holder.pending()) {
|
||||
session.setPendingOrCurrentBedrockInventoryId(-1);
|
||||
GeyserImpl.getInstance().getLogger().debug(session, "No pending inventory, not opening an inventory! Current inventory: %s", debugInventory(currentInventory));
|
||||
GeyserImpl.getInstance().getLogger().debug(session, "No pending inventory, not opening an inventory! Current inventory: %s", debugInventory(holder));
|
||||
return;
|
||||
}
|
||||
|
||||
// Current inventory isn't null! Let's see if we need to open it.
|
||||
if (currentInventory.getBedrockId() == session.getPendingOrCurrentBedrockInventoryId()) {
|
||||
GeyserImpl.getInstance().getLogger().debug(session, "Attempting to open currently delayed inventory with matching bedrock id! " + currentInventory.getBedrockId());
|
||||
openAndUpdateInventory(session, currentInventory);
|
||||
if (holder.inventory().getBedrockId() == session.getPendingOrCurrentBedrockInventoryId()) {
|
||||
GeyserImpl.getInstance().getLogger().debug(session, "Attempting to open currently delayed inventory with matching bedrock id! " + holder.bedrockId());
|
||||
openAndUpdateInventory(holder);
|
||||
return;
|
||||
}
|
||||
|
||||
GeyserImpl.getInstance().getLogger().debug(session, "Opening any pending inventory! " + debugInventory(currentInventory));
|
||||
displayInventory(session, currentInventory);
|
||||
GeyserImpl.getInstance().getLogger().debug(session, "Opening any pending inventory! " + debugInventory(holder));
|
||||
displayInventory(holder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares and displays the current inventory. If necessary, it will queue the opening of virtual inventories.
|
||||
* @param inventory the inventory to display
|
||||
* @param holder the inventory to display
|
||||
*/
|
||||
public static void displayInventory(GeyserSession session, Inventory inventory) {
|
||||
InventoryTranslator translator = inventory.getTranslator();
|
||||
if (translator.prepareInventory(session, inventory)) {
|
||||
session.setPendingOrCurrentBedrockInventoryId(inventory.getBedrockId());
|
||||
if (translator.requiresOpeningDelay(session, inventory)) {
|
||||
inventory.setPending(true);
|
||||
public static void displayInventory(InventoryHolder<?> holder) {
|
||||
if (holder.prepareInventory()) {
|
||||
holder.session().setPendingOrCurrentBedrockInventoryId(holder.bedrockId());
|
||||
if (holder.requiresOpeningDelay()) {
|
||||
holder.pending(true);
|
||||
|
||||
NetworkStackLatencyPacket latencyPacket = new NetworkStackLatencyPacket();
|
||||
latencyPacket.setFromServer(true);
|
||||
latencyPacket.setTimestamp(MAGIC_VIRTUAL_INVENTORY_HACK);
|
||||
session.sendUpstreamPacket(latencyPacket);
|
||||
holder.session().sendUpstreamPacket(latencyPacket);
|
||||
|
||||
GeyserImpl.getInstance().getLogger().debug(session, "Queuing virtual inventory (%s)", debugInventory(inventory));
|
||||
GeyserImpl.getInstance().getLogger().debug(holder.session(), "Queuing virtual inventory (%s)", debugInventory(holder));
|
||||
} else {
|
||||
openAndUpdateInventory(session, inventory);
|
||||
openAndUpdateInventory(holder);
|
||||
}
|
||||
} else {
|
||||
// Can occur if we e.g. did not find a spot to put a fake container in
|
||||
session.setPendingOrCurrentBedrockInventoryId(-1);
|
||||
sendJavaContainerClose(session, inventory);
|
||||
session.setOpenInventory(null);
|
||||
holder.session().setPendingOrCurrentBedrockInventoryId(-1);
|
||||
sendJavaContainerClose(holder);
|
||||
holder.session().setInventoryHolder(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens and updates an inventory, and resets no longer used inventory variables.
|
||||
* Opens and updates an inventory
|
||||
*/
|
||||
public static void openAndUpdateInventory(GeyserSession session, Inventory inventory) {
|
||||
inventory.getTranslator().openInventory(session, inventory);
|
||||
inventory.getTranslator().updateInventory(session, inventory);
|
||||
inventory.setDisplayed(true);
|
||||
inventory.setPending(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current inventory translator.
|
||||
*/
|
||||
public static @NonNull InventoryTranslator getInventoryTranslator(GeyserSession session) {
|
||||
Inventory inventory = session.getOpenInventory();
|
||||
if (inventory == null) {
|
||||
return InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR;
|
||||
}
|
||||
return inventory.getTranslator();
|
||||
public static void openAndUpdateInventory(InventoryHolder<?> holder) {
|
||||
holder.openInventory();
|
||||
holder.updateInventory();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -191,45 +175,47 @@ public class InventoryUtils {
|
|||
* @param confirm whether to wait for the session to process the close before opening a new inventory.
|
||||
*/
|
||||
public static void closeInventory(GeyserSession session, int javaId, boolean confirm) {
|
||||
InventoryHolder<?> holder = getInventory(session, javaId);
|
||||
closeInventory(session, holder, confirm);
|
||||
}
|
||||
|
||||
public static void closeInventory(GeyserSession session, InventoryHolder<?> holder, boolean confirm) {
|
||||
session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY, session);
|
||||
updateCursor(session);
|
||||
|
||||
Inventory inventory = getInventory(session, javaId);
|
||||
if (inventory != null) {
|
||||
InventoryTranslator translator = inventory.getTranslator();
|
||||
translator.closeInventory(session, inventory);
|
||||
if (confirm && inventory.isDisplayed() && !inventory.isPending()
|
||||
&& !(translator instanceof LecternInventoryTranslator) // Closing lecterns is not followed with a close confirmation
|
||||
) {
|
||||
if (holder != null) {
|
||||
holder.closeInventory(confirm);
|
||||
if (holder.shouldConfirmClose(confirm)) {
|
||||
session.setClosingInventory(true);
|
||||
}
|
||||
session.getBundleCache().onInventoryClose(inventory);
|
||||
GeyserImpl.getInstance().getLogger().debug(session, "Closed inventory: (java id: %s/bedrock id: %s), waiting on confirm? %s", inventory.getJavaId(), inventory.getBedrockId(), session.isClosingInventory());
|
||||
session.getBundleCache().onInventoryClose(holder.inventory());
|
||||
GeyserImpl.getInstance().getLogger().debug(session, "Closed inventory: (java id: %s/bedrock id: %s), waiting on confirm? %s", holder.javaId(), holder.bedrockId(), session.isClosingInventory());
|
||||
}
|
||||
|
||||
session.setOpenInventory(null);
|
||||
session.setInventoryHolder(null);
|
||||
}
|
||||
|
||||
public static @Nullable Inventory getInventory(GeyserSession session, int javaId) {
|
||||
/**
|
||||
* A util method to get an (open) inventory based on a Java id. This method should be used over
|
||||
* {@link GeyserSession#getOpenInventory()} (or {@link GeyserSession#getInventoryHolder()}) to account for an edge-case where the Java server expects
|
||||
* Geyser to have the player inventory open while we're using a virtual lectern for the {@link ClientboundOpenBookPacket}.
|
||||
*/
|
||||
public static @Nullable InventoryHolder<?> getInventory(GeyserSession session, int javaId) {
|
||||
if (javaId == 0) {
|
||||
// ugly hack: lecterns aren't their own inventory on Java, and can hence be closed with e.g. an id of 0
|
||||
if (session.getOpenInventory() instanceof LecternContainer) {
|
||||
return session.getOpenInventory();
|
||||
}
|
||||
return session.getPlayerInventory();
|
||||
return session.getPlayerInventoryHolder();
|
||||
} else {
|
||||
Inventory openInventory = session.getOpenInventory();
|
||||
if (openInventory != null && javaId == openInventory.getJavaId()) {
|
||||
return openInventory;
|
||||
InventoryHolder<?> holder = session.getInventoryHolder();
|
||||
if (holder != null && javaId == holder.javaId()) {
|
||||
return holder;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendJavaContainerClose(GeyserSession session, Inventory inventory) {
|
||||
if (inventory.shouldConfirmContainerClose()) {
|
||||
ServerboundContainerClosePacket closeWindowPacket = new ServerboundContainerClosePacket(inventory.getJavaId());
|
||||
session.sendDownstreamGamePacket(closeWindowPacket);
|
||||
public static void sendJavaContainerClose(InventoryHolder<? extends Inventory> holder) {
|
||||
if (holder.inventory().shouldConfirmContainerClose()) {
|
||||
ServerboundContainerClosePacket closeWindowPacket = new ServerboundContainerClosePacket(holder.inventory().getJavaId());
|
||||
holder.session().sendDownstreamGamePacket(closeWindowPacket);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -488,17 +474,18 @@ public class InventoryUtils {
|
|||
return true;
|
||||
}
|
||||
|
||||
public static String debugInventory(@Nullable Inventory inventory) {
|
||||
if (inventory == null) {
|
||||
public static String debugInventory(@Nullable InventoryHolder<? extends Inventory> holder) {
|
||||
if (holder == null) {
|
||||
return "null";
|
||||
}
|
||||
Inventory inventory = holder.inventory();
|
||||
|
||||
String inventoryType = inventory.getContainerType() != null ?
|
||||
inventory.getContainerType().name() : "null";
|
||||
|
||||
return inventory.getClass().getSimpleName() + ": javaId=" + inventory.getJavaId() +
|
||||
", bedrockId=" + inventory.getBedrockId() + ", size=" + inventory.getSize() +
|
||||
", type=" + inventoryType + ", pending=" + inventory.isPending() +
|
||||
", displayed=" + inventory.isPending() + ", delayed=" + inventory.isPending();
|
||||
", type=" + inventoryType + ", pending=" + holder.pending() +
|
||||
", displayed=" + inventory.isDisplayed();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ public class LoginEncryptionUtils {
|
|||
}
|
||||
|
||||
IdentityData extraData = result.identityClaims().extraData;
|
||||
session.setAuthenticationData(new AuthData(extraData.displayName, extraData.identity, extraData.xuid));
|
||||
session.setAuthData(new AuthData(extraData.displayName, extraData.identity, extraData.xuid));
|
||||
session.setCertChainData(certChainData);
|
||||
|
||||
PublicKey identityPublicKey = result.identityClaims().parsedIdentityPublicKey();
|
||||
|
|
Loading…
Add table
Reference in a new issue