diff --git a/connector/pom.xml b/connector/pom.xml
index 6da797b30..3bd75fa2e 100644
--- a/connector/pom.xml
+++ b/connector/pom.xml
@@ -30,9 +30,9 @@
compile
- com.github.CloudburstMC.Protocol
- bedrock-v419
- ce59d39118
+ com.nukkitx.protocol
+ bedrock-v422
+ 2.6.0-SNAPSHOT
compile
diff --git a/connector/src/main/java/org/geysermc/connector/entity/Entity.java b/connector/src/main/java/org/geysermc/connector/entity/Entity.java
index 592165ab4..68b2b2666 100644
--- a/connector/src/main/java/org/geysermc/connector/entity/Entity.java
+++ b/connector/src/main/java/org/geysermc/connector/entity/Entity.java
@@ -50,6 +50,7 @@ import org.geysermc.connector.entity.attribute.AttributeType;
import org.geysermc.connector.entity.living.ArmorStandEntity;
import org.geysermc.connector.entity.player.PlayerEntity;
import org.geysermc.connector.entity.type.EntityType;
+import org.geysermc.connector.inventory.PlayerInventory;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.item.ItemRegistry;
import org.geysermc.connector.utils.AttributeUtils;
@@ -284,11 +285,12 @@ public class Entity {
// Shield code
if (session.getPlayerEntity().getEntityId() == entityId && metadata.getFlags().getFlag(EntityFlag.SNEAKING)) {
- if ((session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemRegistry.SHIELD.getJavaId()) ||
- (session.getInventoryCache().getPlayerInventory().getItem(45) != null && session.getInventoryCache().getPlayerInventory().getItem(45).getId() == ItemRegistry.SHIELD.getJavaId())) {
+ PlayerInventory playerInv = session.getPlayerInventory();
+ if ((playerInv.getItemInHand().getId() == ItemRegistry.SHIELD.getJavaId()) ||
+ (playerInv.getOffhand().getId() == ItemRegistry.SHIELD.getJavaId())) {
ClientPlayerUseItemPacket useItemPacket;
metadata.getFlags().setFlag(EntityFlag.BLOCKING, true);
- if (session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemRegistry.SHIELD.getJavaId()) {
+ if (playerInv.getItemInHand().getId() == ItemRegistry.SHIELD.getJavaId()) {
useItemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
}
// Else we just assume it's the offhand, to simplify logic and to assure the packet gets sent
diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Container.java b/connector/src/main/java/org/geysermc/connector/inventory/Container.java
new file mode 100644
index 000000000..acf450e14
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/inventory/Container.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2019-2020 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.connector.inventory;
+
+import com.github.steveice10.mc.protocol.data.game.window.WindowType;
+import lombok.Getter;
+import lombok.NonNull;
+import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
+
+/**
+ * Combination of {@link Inventory} and {@link PlayerInventory}
+ */
+@Getter
+public class Container extends Inventory {
+ private final PlayerInventory playerInventory;
+ private final int containerSize;
+
+ public Container(String title, int id, WindowType windowType, int size, PlayerInventory playerInventory) {
+ super(title, id, windowType, size);
+ this.playerInventory = playerInventory;
+ this.containerSize = this.size + InventoryTranslator.PLAYER_INVENTORY_SIZE;
+ }
+
+ @Override
+ public GeyserItemStack getItem(int slot) {
+ if (slot < this.size) {
+ return super.getItem(slot);
+ } else {
+ return playerInventory.getItem(slot - this.size + InventoryTranslator.PLAYER_INVENTORY_OFFSET);
+ }
+ }
+
+ @Override
+ public void setItem(int slot, @NonNull GeyserItemStack item) {
+ if (slot < this.size) {
+ super.setItem(slot, item);
+ } else {
+ playerInventory.setItem(slot - this.size + InventoryTranslator.PLAYER_INVENTORY_OFFSET, item);
+ }
+ }
+
+ @Override
+ public int getSize() {
+ return this.containerSize;
+ }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/inventory/EnchantmentInventory.java b/connector/src/main/java/org/geysermc/connector/inventory/EnchantmentInventory.java
new file mode 100644
index 000000000..65debc486
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/inventory/EnchantmentInventory.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019-2020 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.connector.inventory;
+
+import com.github.steveice10.mc.protocol.data.game.window.WindowType;
+import com.nukkitx.protocol.bedrock.data.inventory.EnchantOptionData;
+import lombok.Getter;
+
+@Getter
+public class EnchantmentInventory extends Inventory {
+ private EnchantOptionData[] enchantOptions;
+
+ public EnchantmentInventory(String title, int id, WindowType windowType, int size) {
+ super(title, id, windowType, size);
+ }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/inventory/FurnaceInventory.java b/connector/src/main/java/org/geysermc/connector/inventory/FurnaceInventory.java
new file mode 100644
index 000000000..4dc098d89
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/inventory/FurnaceInventory.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2019-2020 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.connector.inventory;
+
+import com.github.steveice10.mc.protocol.data.game.window.WindowType;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+public class FurnaceInventory extends Inventory {
+ @Setter
+ private int test;
+
+ public FurnaceInventory(String title, int id, WindowType windowType, int size) {
+ super(title, id, windowType, size);
+ }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java b/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java
new file mode 100644
index 000000000..c935fcdb4
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/inventory/GeyserItemStack.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2019-2020 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.connector.inventory;
+
+import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
+import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
+import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
+import lombok.Data;
+import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.network.translators.item.ItemEntry;
+import org.geysermc.connector.network.translators.item.ItemRegistry;
+import org.geysermc.connector.network.translators.item.ItemTranslator;
+
+@Data
+public class GeyserItemStack {
+ public static final GeyserItemStack EMPTY = new GeyserItemStack(0, 0, null);
+
+ private final int id;
+ private int amount;
+ private CompoundTag nbt;
+ private int netId;
+
+ public GeyserItemStack(int id) {
+ this(id, 1);
+ }
+
+ public GeyserItemStack(int id, int amount) {
+ this(id, amount, null);
+ }
+
+ public GeyserItemStack(int id, int amount, CompoundTag nbt) {
+ this(id, amount, nbt, 1);
+ }
+
+ public GeyserItemStack(int id, int amount, CompoundTag nbt, int netId) {
+ this.id = id;
+ this.amount = amount;
+ this.nbt = nbt;
+ this.netId = netId;
+ }
+
+ public int getId() {
+ return isEmpty() ? 0 : id;
+ }
+
+ public int getAmount() {
+ return isEmpty() ? 0 : amount;
+ }
+
+ public CompoundTag getNbt() {
+ return isEmpty() ? null : nbt;
+ }
+
+ public int getNetId() {
+ return isEmpty() ? 0 : netId;
+ }
+
+ public void add(int add) {
+ amount += add;
+ }
+
+ public void sub(int sub) {
+ amount -= sub;
+ }
+
+ public static GeyserItemStack from(ItemStack itemStack) {
+ return from(itemStack, 1);
+ }
+
+ public static GeyserItemStack from(ItemStack itemStack, int netId) {
+ return itemStack == null ? EMPTY : new GeyserItemStack(itemStack.getId(), itemStack.getAmount(), itemStack.getNbt(), netId);
+ }
+
+ public ItemStack getItemStack() {
+ return isEmpty() ? null : new ItemStack(id, amount, nbt);
+ }
+
+ public ItemData getItemData(GeyserSession session) {
+ ItemData itemData = ItemTranslator.translateToBedrock(session, getItemStack());
+ itemData.setNetId(getNetId());
+ return itemData;
+ }
+
+ public ItemEntry getItemEntry() {
+ return ItemRegistry.ITEM_ENTRIES.get(getId());
+ }
+
+ public boolean isEmpty() {
+ return amount <= 0 || id == 0;
+ }
+
+ public GeyserItemStack copy() {
+ return copy(amount);
+ }
+
+ public GeyserItemStack copy(int newAmount) {
+ return isEmpty() ? EMPTY : new GeyserItemStack(id, newAmount, nbt == null ? null : nbt.clone(), netId);
+ }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java
index 539fe1e26..f4aea4c90 100644
--- a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java
+++ b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java
@@ -25,23 +25,19 @@
package org.geysermc.connector.inventory;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
import com.nukkitx.math.vector.Vector3i;
import lombok.Getter;
+import lombok.NonNull;
import lombok.Setter;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.util.Arrays;
public class Inventory {
@Getter
protected int id;
- @Getter
- @Setter
- protected boolean open;
-
@Getter
protected WindowType windowType;
@@ -52,8 +48,7 @@ public class Inventory {
@Setter
protected String title;
- @Setter
- protected ItemStack[] items;
+ protected GeyserItemStack[] items;
@Getter
@Setter
@@ -64,27 +59,30 @@ public class Inventory {
protected long holderId = -1;
@Getter
- protected AtomicInteger transactionId = new AtomicInteger(1);
+ protected short transactionId = 0;
- public Inventory(int id, WindowType windowType, int size) {
+ protected Inventory(int id, WindowType windowType, int size) {
this("Inventory", id, windowType, size);
}
- public Inventory(String title, int id, WindowType windowType, int size) {
+ protected Inventory(String title, int id, WindowType windowType, int size) {
this.title = title;
this.id = id;
this.windowType = windowType;
this.size = size;
- this.items = new ItemStack[size];
+ this.items = new GeyserItemStack[size];
+ Arrays.fill(items, GeyserItemStack.EMPTY);
}
- public ItemStack getItem(int slot) {
+ public GeyserItemStack getItem(int slot) {
return items[slot];
}
- public void setItem(int slot, ItemStack item) {
- if (item != null && (item.getId() == 0 || item.getAmount() < 1))
- item = null;
+ public void setItem(int slot, @NonNull GeyserItemStack item) {
items[slot] = item;
}
+
+ public short getNextTransactionId() {
+ return ++transactionId;
+ }
}
diff --git a/connector/src/main/java/org/geysermc/connector/inventory/MerchantContainer.java b/connector/src/main/java/org/geysermc/connector/inventory/MerchantContainer.java
new file mode 100644
index 000000000..03ae8ac3a
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/inventory/MerchantContainer.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2019-2020 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.connector.inventory;
+
+import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade;
+import com.github.steveice10.mc.protocol.data.game.window.WindowType;
+import lombok.Getter;
+import lombok.Setter;
+import org.geysermc.connector.entity.Entity;
+
+@Getter
+@Setter
+public class MerchantContainer extends Container {
+ private Entity villager;
+ private VillagerTrade[] villagerTrades;
+
+ public MerchantContainer(String title, int id, WindowType windowType, int size, PlayerInventory playerInventory) {
+ super(title, id, windowType, size, playerInventory);
+ }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java b/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java
index 225335a97..e6aeb5cab 100644
--- a/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java
+++ b/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java
@@ -25,8 +25,8 @@
package org.geysermc.connector.inventory;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import lombok.Getter;
+import lombok.NonNull;
import lombok.Setter;
public class PlayerInventory extends Inventory {
@@ -40,20 +40,24 @@ public class PlayerInventory extends Inventory {
private int heldItemSlot;
@Getter
- private ItemStack cursor;
+ @Setter
+ @NonNull
+ private GeyserItemStack cursor = GeyserItemStack.EMPTY;
public PlayerInventory() {
super(0, null, 46);
heldItemSlot = 0;
}
- public void setCursor(ItemStack stack) {
- if (stack != null && (stack.getId() == 0 || stack.getAmount() < 1))
- stack = null;
- cursor = stack;
- }
-
- public ItemStack getItemInHand() {
+ public GeyserItemStack getItemInHand() {
return items[36 + heldItemSlot];
}
+
+ public void setItemInHand(@NonNull GeyserItemStack item) {
+ items[36 + heldItemSlot] = item;
+ }
+
+ public GeyserItemStack getOffhand() {
+ return items[45];
+ }
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/BedrockProtocol.java b/connector/src/main/java/org/geysermc/connector/network/BedrockProtocol.java
index 0b96b5b54..d0cc0f42a 100644
--- a/connector/src/main/java/org/geysermc/connector/network/BedrockProtocol.java
+++ b/connector/src/main/java/org/geysermc/connector/network/BedrockProtocol.java
@@ -27,6 +27,7 @@ package org.geysermc.connector.network;
import com.nukkitx.protocol.bedrock.BedrockPacketCodec;
import com.nukkitx.protocol.bedrock.v419.Bedrock_v419;
+import com.nukkitx.protocol.bedrock.v422.Bedrock_v422;
import java.util.ArrayList;
import java.util.List;
@@ -39,22 +40,18 @@ public class BedrockProtocol {
* Default Bedrock codec that should act as a fallback. Should represent the latest available
* release of the game that Geyser supports.
*/
- public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v419.V419_CODEC;
+ public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v422.V422_CODEC;
/**
* A list of all supported Bedrock versions that can join Geyser
*/
public static final List SUPPORTED_BEDROCK_CODECS = new ArrayList<>();
static {
- SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder()
+ SUPPORTED_BEDROCK_CODECS.add(Bedrock_v419.V419_CODEC.toBuilder()
.minecraftVersion("1.16.100/1.16.101") // We change this as 1.16.100.60 (beta) crashes with Geyser
.build()
);
- SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder()
- .protocolVersion(422)
- .minecraftVersion("1.16.200.56")
- .build()
- );
+ SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC);
}
/**
diff --git a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java
index f4e3ca214..18a7f3d5d 100644
--- a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java
+++ b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java
@@ -82,7 +82,9 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
ResourcePacksInfoPacket resourcePacksInfo = new ResourcePacksInfoPacket();
for(ResourcePack resourcePack : ResourcePack.PACKS.values()) {
ResourcePackManifest.Header header = resourcePack.getManifest().getHeader();
- resourcePacksInfo.getResourcePackInfos().add(new ResourcePacksInfoPacket.Entry(header.getUuid().toString(), header.getVersionString(), resourcePack.getFile().length(), "", "", "", false));
+ resourcePacksInfo.getResourcePackInfos().add(new ResourcePacksInfoPacket.Entry(
+ header.getUuid().toString(), header.getVersionString(), resourcePack.getFile().length(),
+ "", "", "", false, false));
}
resourcePacksInfo.setForcedToAccept(GeyserConnector.getInstance().getConfig().isForceResourcePacks());
session.sendUpstreamPacket(resourcePacksInfo);
diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java
index fc73b62ae..4a640489c 100644
--- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java
+++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java
@@ -33,6 +33,7 @@ import com.github.steveice10.mc.protocol.MinecraftProtocol;
import com.github.steveice10.mc.protocol.data.SubProtocol;
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
import com.github.steveice10.mc.protocol.data.game.statistic.Statistic;
+import com.github.steveice10.mc.protocol.data.game.recipe.Recipe;
import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade;
import com.github.steveice10.mc.protocol.packet.handshake.client.HandshakePacket;
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionRotationPacket;
@@ -58,6 +59,7 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2LongMap;
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
+import lombok.AccessLevel;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
@@ -69,6 +71,7 @@ import org.geysermc.connector.common.AuthType;
import org.geysermc.connector.entity.Entity;
import org.geysermc.connector.entity.player.SkullPlayerEntity;
import org.geysermc.connector.entity.player.SessionPlayerEntity;
+import org.geysermc.connector.inventory.Inventory;
import org.geysermc.connector.inventory.PlayerInventory;
import org.geysermc.connector.network.translators.chat.MessageTranslator;
import org.geysermc.connector.network.remote.RemoteServer;
@@ -79,7 +82,6 @@ import org.geysermc.connector.network.translators.BiomeTranslator;
import org.geysermc.connector.network.translators.EntityIdentifierRegistry;
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
import org.geysermc.connector.network.translators.collision.CollisionManager;
-import org.geysermc.connector.network.translators.inventory.EnchantmentInventoryTranslator;
import org.geysermc.connector.network.translators.item.ItemRegistry;
import org.geysermc.connector.skin.SkinManager;
import org.geysermc.connector.utils.*;
@@ -91,6 +93,12 @@ import java.net.InetSocketAddress;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
@@ -109,16 +117,25 @@ public class GeyserSession implements CommandSender {
private BedrockClientData clientData;
private final SessionPlayerEntity playerEntity;
- private PlayerInventory inventory;
private ChunkCache chunkCache;
private EntityCache entityCache;
private EntityEffectCache effectCache;
- private InventoryCache inventoryCache;
private WorldCache worldCache;
private WindowCache windowCache;
private final Int2ObjectMap teleportMap = new Int2ObjectOpenHashMap<>();
+ private final PlayerInventory playerInventory;
+ @Setter
+ private Inventory openInventory;
+
+ private final AtomicInteger itemNetId = new AtomicInteger(1);
+
+ @Getter(AccessLevel.NONE)
+ private final Object inventoryLock = new Object();
+ @Getter(AccessLevel.NONE)
+ private CompletableFuture inventoryFuture;
+
/**
* Stores session collision
*/
@@ -190,9 +207,6 @@ public class GeyserSession implements CommandSender {
@Setter
private Entity ridingVehicleEntity;
- @Setter
- private int craftSlot = 0;
-
@Setter
private long lastWindowCloseTime = 0;
@@ -207,10 +221,8 @@ public class GeyserSession implements CommandSender {
@Setter
private long lastInteractedVillagerEid;
- /**
- * Stores the enchantment information the client has received if they are in an enchantment table GUI
- */
- private final EnchantmentInventoryTranslator.EnchantmentSlotData[] enchantmentSlotData = new EnchantmentInventoryTranslator.EnchantmentSlotData[3];
+ @Setter
+ private Int2ObjectMap craftingRecipes;
/**
* The current attack speed of the player. Used for sending proper cooldown timings.
@@ -326,20 +338,23 @@ public class GeyserSession implements CommandSender {
this.chunkCache = new ChunkCache(this);
this.entityCache = new EntityCache(this);
this.effectCache = new EntityEffectCache();
- this.inventoryCache = new InventoryCache(this);
this.worldCache = new WorldCache(this);
this.windowCache = new WindowCache(this);
this.collisionManager = new CollisionManager(this);
this.playerEntity = new SessionPlayerEntity(this);
- this.inventory = new PlayerInventory();
+ this.worldCache = new WorldCache(this);
+ this.windowCache = new WindowCache(this);
+
+ this.playerInventory = new PlayerInventory();
+ this.openInventory = null;
+ this.inventoryFuture = CompletableFuture.completedFuture(null);
+ this.craftingRecipes = new Int2ObjectOpenHashMap<>();
this.spawned = false;
this.loggedIn = false;
- this.inventoryCache.getInventories().put(0, inventory);
-
connector.getPlayers().forEach(player -> this.emotes.addAll(player.getEmotes()));
bedrockServerSession.addDisconnectHandler(disconnectReason -> {
@@ -578,7 +593,6 @@ public class GeyserSession implements CommandSender {
this.entityCache = null;
this.effectCache = null;
this.worldCache = null;
- this.inventoryCache = null;
this.windowCache = null;
closed = true;
@@ -697,10 +711,47 @@ public class GeyserSession implements CommandSender {
startGamePacket.setMultiplayerCorrelationId("");
startGamePacket.setItemEntries(ItemRegistry.ITEMS);
startGamePacket.setVanillaVersion("*");
+ // startGamePacket.setMovementServerAuthoritative(true);
+ startGamePacket.setInventoriesServerAuthoritative(true);
startGamePacket.setAuthoritativeMovementMode(AuthoritativeMovementMode.CLIENT);
upstream.sendPacket(startGamePacket);
}
+ /**
+ * Adds a new inventory task.
+ * Inventory tasks are executed one at a time, in order.
+ *
+ * @param task the task to run
+ */
+ public void addInventoryTask(Runnable task) {
+ synchronized (inventoryLock) {
+ System.out.println("new task " + task.toString());
+ inventoryFuture = inventoryFuture.thenRun(task).exceptionally(throwable -> {
+ GeyserConnector.getInstance().getLogger().error("Error processing inventory task", throwable.getCause());
+ return null;
+ });
+ }
+ }
+
+ /**
+ * Adds a new inventory task with a delay.
+ * The delay is achieved by scheduling with the Geyser general thread pool.
+ * Inventory tasks are executed one at a time, in order.
+ *
+ * @param task the delayed task to run
+ * @param delayMillis delay in milliseconds
+ */
+ public void addInventoryTask(Runnable task, long delayMillis) {
+ synchronized (inventoryLock) {
+ System.out.println("new delayed task " + task.toString());
+ Executor delayedExecutor = command -> GeyserConnector.getInstance().getGeneralThreadPool().schedule(command, delayMillis, TimeUnit.MILLISECONDS);
+ inventoryFuture = inventoryFuture.thenRunAsync(task, delayedExecutor).exceptionally(throwable -> {
+ GeyserConnector.getInstance().getLogger().error("Error processing inventory task", throwable.getCause());
+ return null;
+ });
+ }
+ }
+
public void addTeleport(TeleportCache teleportCache) {
teleportMap.put(teleportCache.getTeleportConfirmId(), teleportCache);
diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/InventoryCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/InventoryCache.java
deleted file mode 100644
index 032f64024..000000000
--- a/connector/src/main/java/org/geysermc/connector/network/session/cache/InventoryCache.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2019-2020 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.connector.network.session.cache;
-
-import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
-import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
-import lombok.Getter;
-import lombok.Setter;
-import org.geysermc.connector.inventory.Inventory;
-import org.geysermc.connector.network.session.GeyserSession;
-
-public class InventoryCache {
-
- private GeyserSession session;
-
- @Getter
- @Setter
- private Inventory openInventory;
-
- @Getter
- private Int2ObjectMap inventories = new Int2ObjectOpenHashMap<>();
-
- public InventoryCache(GeyserSession session) {
- this.session = session;
- }
-
- public Inventory getPlayerInventory() {
- return inventories.get(0);
- }
-
- public void cacheInventory(Inventory inventory) {
- inventories.put(inventory.getId(), inventory);
- }
-
- public void uncacheInventory(int id) {
- inventories.remove(id);
- }
-}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java
index 00905f6d9..5571ff8b9 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java
@@ -38,24 +38,24 @@ public class BedrockContainerCloseTranslator extends PacketTranslator {
+ session.setLastWindowCloseTime(0);
+ byte windowId = packet.getId();
+
+ if (windowId == -1 && session.getOpenInventory() != null) {
+ windowId = (byte) session.getOpenInventory().getId();
}
- }
- if (windowId == 0 || (openInventory != null && openInventory.getId() == windowId)) {
- ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(windowId);
- session.getDownstream().getSession().send(closeWindowPacket);
- InventoryUtils.closeInventory(session, windowId);
- }
+ Inventory openInventory = session.getOpenInventory();
+ if (openInventory != null && windowId == openInventory.getId()) {
+ System.out.println(packet);
+ ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(windowId);
+ session.getDownstream().getSession().send(closeWindowPacket);
+ InventoryUtils.closeInventory(session, windowId);
+ }
- //Client wants close confirmation
- session.sendUpstreamPacket(packet);
+ //Client wants close confirmation
+ session.sendUpstreamPacket(packet);
+ });
}
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java
index 5b0fbb222..54221b4ad 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java
@@ -25,7 +25,6 @@
package org.geysermc.connector.network.translators.bedrock;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
@@ -43,6 +42,8 @@ import com.nukkitx.protocol.bedrock.data.inventory.ContainerId;
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
+import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData;
+import com.nukkitx.protocol.bedrock.data.inventory.InventorySource;
import com.nukkitx.protocol.bedrock.packet.InventoryTransactionPacket;
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
import org.geysermc.connector.entity.CommandBlockMinecartEntity;
@@ -50,17 +51,15 @@ import org.geysermc.connector.entity.Entity;
import org.geysermc.connector.entity.ItemFrameEntity;
import org.geysermc.connector.entity.living.merchant.AbstractMerchantEntity;
import org.geysermc.connector.entity.type.EntityType;
-import org.geysermc.connector.inventory.Inventory;
+import org.geysermc.connector.inventory.GeyserItemStack;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
-import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
import org.geysermc.connector.network.translators.item.ItemEntry;
import org.geysermc.connector.network.translators.item.ItemRegistry;
import org.geysermc.connector.network.translators.sound.EntitySoundInteractionHandler;
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
import org.geysermc.connector.utils.BlockUtils;
-import org.geysermc.connector.utils.InventoryUtils;
import java.util.concurrent.TimeUnit;
@@ -71,15 +70,36 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator {
+ if (session.getPlayerInventory().getHeldItemSlot() != containerAction.getSlot())
+ return;
+ if (session.getPlayerInventory().getItemInHand().isEmpty())
+ return;
+
+ boolean dropAll = worldAction.getToItem().getCount() > 1;
+ ClientPlayerActionPacket dropAllPacket = new ClientPlayerActionPacket(
+ dropAll ? PlayerAction.DROP_ITEM_STACK : PlayerAction.DROP_ITEM,
+ new Position(0, 0, 0),
+ BlockFace.DOWN
+ );
+ session.sendDownstreamPacket(dropAllPacket);
+
+ if (dropAll) {
+ session.getPlayerInventory().setItemInHand(GeyserItemStack.EMPTY);
+ } else {
+ session.getPlayerInventory().getItemInHand().sub(1);
+ }
+ });
+ }
+ }
break;
case INVENTORY_MISMATCH:
- Inventory inv = session.getInventoryCache().getOpenInventory();
- if (inv == null) inv = session.getInventory();
- InventoryTranslator.INVENTORY_TRANSLATORS.get(inv.getWindowType()).updateInventory(session, inv);
- InventoryUtils.updateCursor(session);
break;
case ITEM_USE:
switch (packet.getActionType()) {
@@ -165,9 +185,8 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator {
+
+ @Override
+ public void translate(ItemStackRequestPacket packet, GeyserSession session) {
+ Inventory inventory = session.getOpenInventory();
+ if (inventory == null)
+ return;
+
+ InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
+ session.addInventoryTask(() -> translator.translateRequests(session, inventory, packet.getRequests()));
+ }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMobEquipmentTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMobEquipmentTranslator.java
index a220e389f..ade949199 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMobEquipmentTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMobEquipmentTranslator.java
@@ -40,12 +40,12 @@ public class BedrockMobEquipmentTranslator extends PacketTranslator 8 ||
- packet.getContainerId() != ContainerId.INVENTORY || session.getInventory().getHeldItemSlot() == packet.getHotbarSlot()) {
+ packet.getContainerId() != ContainerId.INVENTORY || session.getPlayerInventory().getHeldItemSlot() == packet.getHotbarSlot()) {
// For the last condition - Don't update the slot if the slot is the same - not Java Edition behavior and messes with plugins such as Grief Prevention
return;
}
- session.getInventory().setHeldItemSlot(packet.getHotbarSlot());
+ session.getPlayerInventory().setHeldItemSlot(packet.getHotbarSlot());
ClientPlayerChangeHeldItemPacket changeHeldItemPacket = new ClientPlayerChangeHeldItemPacket(packet.getHotbarSlot());
session.sendDownstreamPacket(changeHeldItemPacket);
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/BedrockEntityEventTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/BedrockEntityEventTranslator.java
index 7cf3fec29..8e94d64cb 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/BedrockEntityEventTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/BedrockEntityEventTranslator.java
@@ -26,12 +26,13 @@
package org.geysermc.connector.network.translators.bedrock.entity;
import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade;
-import com.github.steveice10.mc.protocol.data.game.window.WindowType;
import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientSelectTradePacket;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
import org.geysermc.connector.entity.Entity;
+import org.geysermc.connector.inventory.GeyserItemStack;
import org.geysermc.connector.inventory.Inventory;
+import org.geysermc.connector.inventory.MerchantContainer;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
@@ -47,20 +48,25 @@ public class BedrockEntityEventTranslator extends PacketTranslator {
+ ClientSelectTradePacket selectTradePacket = new ClientSelectTradePacket(packet.getData());
+ session.sendDownstreamPacket(selectTradePacket);
+ });
- Entity villager = session.getPlayerEntity();
- Inventory openInventory = session.getInventoryCache().getOpenInventory();
- if (openInventory != null && openInventory.getWindowType() == WindowType.MERCHANT) {
- VillagerTrade[] trades = session.getVillagerTrades();
- if (trades != null && packet.getData() >= 0 && packet.getData() < trades.length) {
- VillagerTrade trade = session.getVillagerTrades()[packet.getData()];
- openInventory.setItem(2, trade.getOutput());
- villager.getMetadata().put(EntityData.TRADE_XP, trade.getXp() + villager.getMetadata().getInt(EntityData.TRADE_XP));
- villager.updateBedrockMetadata(session);
+ session.addInventoryTask(() -> {
+ Entity villager = session.getPlayerEntity();
+ Inventory openInventory = session.getOpenInventory();
+ if (openInventory instanceof MerchantContainer) {
+ MerchantContainer merchantInventory = (MerchantContainer) openInventory;
+ VillagerTrade[] trades = merchantInventory.getVillagerTrades();
+ if (trades != null && packet.getData() >= 0 && packet.getData() < trades.length) {
+ VillagerTrade trade = merchantInventory.getVillagerTrades()[packet.getData()];
+ openInventory.setItem(2, GeyserItemStack.from(trade.getOutput()));
+ villager.getMetadata().put(EntityData.TRADE_XP, trade.getXp() + villager.getMetadata().getInt(EntityData.TRADE_XP));
+ villager.updateBedrockMetadata(session);
+ }
}
- }
+ }, 100);
return;
}
session.getConnector().getLogger().debug("Did not translate incoming EntityEventPacket: " + packet.toString());
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java
index 6c03cd033..a2739cd8c 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java
@@ -39,6 +39,7 @@ import com.nukkitx.protocol.bedrock.packet.InteractPacket;
import lombok.Getter;
import org.geysermc.connector.entity.Entity;
import org.geysermc.connector.entity.type.EntityType;
+import org.geysermc.connector.inventory.GeyserItemStack;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
@@ -98,7 +99,7 @@ public class BedrockInteractTranslator extends PacketTranslator
switch (packet.getAction()) {
case INTERACT:
- if (session.getInventory().getItem(session.getInventory().getHeldItemSlot() + 36).getId() == ItemRegistry.SHIELD.getJavaId()) {
+ if (session.getPlayerInventory().getItemInHand().getId() == ItemRegistry.SHIELD.getJavaId()) {
break;
}
ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
@@ -122,7 +123,7 @@ public class BedrockInteractTranslator extends PacketTranslator
if (interactEntity == null)
return;
EntityDataMap entityMetadata = interactEntity.getMetadata();
- ItemEntry itemEntry = session.getInventory().getItemInHand() == null ? ItemEntry.AIR : ItemRegistry.getItem(session.getInventory().getItemInHand());
+ ItemEntry itemEntry = session.getPlayerInventory().getItemInHand() == GeyserItemStack.EMPTY ? ItemEntry.AIR : ItemRegistry.getItem(session.getPlayerInventory().getItemInHand().getItemStack());
String javaIdentifierStripped = itemEntry.getJavaIdentifier().replace("minecraft:", "");
// TODO - in the future, update these in the metadata? So the client doesn't have to wiggle their cursor around for it to happen
@@ -136,8 +137,8 @@ public class BedrockInteractTranslator extends PacketTranslator
interactEntity.getEntityType() == EntityType.PIG || interactEntity.getEntityType() == EntityType.STRIDER)) {
// Entity can be saddled and the conditions meet (entity can be saddled and, if needed, is tamed)
interactiveTag = InteractiveTag.SADDLE;
- } else if (javaIdentifierStripped.equals("name_tag") && session.getInventory().getItemInHand().getNbt() != null &&
- session.getInventory().getItemInHand().getNbt().contains("display")) {
+ } else if (javaIdentifierStripped.equals("name_tag") && session.getPlayerInventory().getItemInHand().getNbt() != null &&
+ session.getPlayerInventory().getItemInHand().getNbt().contains("display")) {
// Holding a named name tag
interactiveTag = InteractiveTag.NAME;
} else if (javaIdentifierStripped.equals("lead") && LEASHABLE_MOB_TYPES.contains(interactEntity.getEntityType()) &&
@@ -355,14 +356,15 @@ public class BedrockInteractTranslator extends PacketTranslator
}
break;
case OPEN_INVENTORY:
- if (!session.getInventory().isOpen()) {
+ if (session.getOpenInventory() == null) {
+ session.setOpenInventory(session.getPlayerInventory());
+
ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket();
containerOpenPacket.setId((byte) 0);
containerOpenPacket.setType(ContainerType.INVENTORY);
containerOpenPacket.setUniqueEntityId(-1);
containerOpenPacket.setBlockPosition(entity.getPosition().toInt());
session.sendUpstreamPacket(containerOpenPacket);
- session.getInventory().setOpen(true);
}
break;
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java
deleted file mode 100644
index ab266faef..000000000
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (c) 2019-2020 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.connector.network.translators.inventory;
-
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
-import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientRenameItemPacket;
-import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
-import com.google.gson.JsonSyntaxException;
-import com.nukkitx.nbt.NbtMap;
-import com.nukkitx.protocol.bedrock.data.inventory.*;
-import net.kyori.adventure.text.Component;
-import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
-import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
-import org.geysermc.connector.inventory.Inventory;
-import org.geysermc.connector.network.session.GeyserSession;
-import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-public class AnvilInventoryTranslator extends BlockInventoryTranslator {
- public AnvilInventoryTranslator() {
- super(3, "minecraft:anvil[facing=north]", ContainerType.ANVIL, new CursorInventoryUpdater());
- }
-
- @Override
- public int bedrockSlotToJava(InventoryActionData action) {
- if (action.getSource().getContainerId() == ContainerId.UI) {
- switch (action.getSlot()) {
- case 1:
- return 0;
- case 2:
- return 1;
- case 50:
- return 2;
- }
- }
- if (action.getSource().getContainerId() == ContainerId.ANVIL_RESULT) {
- return 2;
- }
- return super.bedrockSlotToJava(action);
- }
-
- @Override
- public int javaSlotToBedrock(int slot) {
- switch (slot) {
- case 0:
- return 1;
- case 1:
- return 2;
- case 2:
- return 50;
- }
- return super.javaSlotToBedrock(slot);
- }
-
- @Override
- public SlotType getSlotType(int javaSlot) {
- if (javaSlot == 2)
- return SlotType.OUTPUT;
- return SlotType.NORMAL;
- }
-
- @Override
- public void translateActions(GeyserSession session, Inventory inventory, List actions) {
- InventoryActionData anvilResult = null;
- InventoryActionData anvilInput = null;
- for (InventoryActionData action : actions) {
- if (action.getSource().getContainerId() == ContainerId.ANVIL_MATERIAL) {
- //useless packet
- return;
- } else if (action.getSource().getContainerId() == ContainerId.ANVIL_RESULT) {
- anvilResult = action;
- } else if (bedrockSlotToJava(action) == 0) {
- anvilInput = action;
- }
- }
- ItemData itemName = null;
- if (anvilResult != null) {
- itemName = anvilResult.getFromItem();
- } else if (anvilInput != null) {
- itemName = anvilInput.getToItem();
- }
- if (itemName != null) {
- String rename;
- NbtMap tag = itemName.getTag();
- if (tag != null && tag.containsKey("display")) {
- String name = tag.getCompound("display").getString("Name");
- try {
- Component component = GsonComponentSerializer.gson().deserialize(name);
- rename = LegacyComponentSerializer.legacySection().serialize(component);
- } catch (JsonSyntaxException e) {
- rename = name;
- }
- } else {
- rename = "";
- }
- ClientRenameItemPacket renameItemPacket = new ClientRenameItemPacket(rename);
- session.sendDownstreamPacket(renameItemPacket);
- }
- if (anvilResult != null) {
- //Strip unnecessary actions
- List strippedActions = actions.stream()
- .filter(action -> action.getSource().getContainerId() == ContainerId.ANVIL_RESULT
- || (action.getSource().getType() == InventorySource.Type.CONTAINER
- && !(action.getSource().getContainerId() == ContainerId.UI && action.getSlot() != 0)))
- .collect(Collectors.toList());
- super.translateActions(session, inventory, strippedActions);
- return;
- }
-
- super.translateActions(session, inventory, actions);
- }
-
- @Override
- public void updateSlot(GeyserSession session, Inventory inventory, int slot) {
- if (slot == 0) {
- ItemStack item = inventory.getItem(slot);
- if (item != null) {
- String rename;
- CompoundTag tag = item.getNbt();
- if (tag != null) {
- CompoundTag displayTag = tag.get("display");
- if (displayTag != null && displayTag.contains("Name")) {
- String itemName = displayTag.get("Name").getValue().toString();
- try {
- Component component = GsonComponentSerializer.gson().deserialize(itemName);
- rename = LegacyComponentSerializer.legacySection().serialize(component);
- } catch (JsonSyntaxException e) {
- rename = itemName;
- }
- } else {
- rename = "";
- }
- } else {
- rename = "";
- }
- ClientRenameItemPacket renameItemPacket = new ClientRenameItemPacket(rename);
- session.sendDownstreamPacket(renameItemPacket);
- }
- }
- super.updateSlot(session, inventory, slot);
- }
-}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BaseInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BaseInventoryTranslator.java
index 6f00fc4d7..7d54667bd 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BaseInventoryTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BaseInventoryTranslator.java
@@ -25,15 +25,15 @@
package org.geysermc.connector.network.translators.inventory;
-import com.nukkitx.protocol.bedrock.data.inventory.ContainerId;
-import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData;
+import com.github.steveice10.mc.protocol.data.game.window.WindowType;
+import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType;
+import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData;
+import org.geysermc.connector.inventory.Container;
import org.geysermc.connector.inventory.Inventory;
+import org.geysermc.connector.inventory.PlayerInventory;
import org.geysermc.connector.network.session.GeyserSession;
-import org.geysermc.connector.network.translators.inventory.action.InventoryActionDataTranslator;
-import java.util.List;
-
-public abstract class BaseInventoryTranslator extends InventoryTranslator{
+public abstract class BaseInventoryTranslator extends InventoryTranslator {
BaseInventoryTranslator(int size) {
super(size);
}
@@ -44,15 +44,18 @@ public abstract class BaseInventoryTranslator extends InventoryTranslator{
}
@Override
- public int bedrockSlotToJava(InventoryActionData action) {
- int slotnum = action.getSlot();
- if (action.getSource().getContainerId() == ContainerId.INVENTORY) {
- //hotbar
- if (slotnum >= 9) {
- return slotnum + this.size - 9;
- } else {
- return slotnum + this.size + 27;
- }
+ public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
+ int slotnum = slotInfoData.getSlot();
+ switch (slotInfoData.getContainer()) {
+ case HOTBAR_AND_INVENTORY:
+ case HOTBAR:
+ case INVENTORY:
+ //hotbar
+ if (slotnum >= 9) {
+ return slotnum + this.size - 9;
+ } else {
+ return slotnum + this.size + 27;
+ }
}
return slotnum;
}
@@ -70,13 +73,26 @@ public abstract class BaseInventoryTranslator extends InventoryTranslator{
return slot;
}
+ @Override
+ public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
+ if (slot >= this.size) {
+ final int tmp = slot - this.size;
+ if (tmp < 27) {
+ return new BedrockContainerSlot(ContainerSlotType.INVENTORY, tmp + 9);
+ } else {
+ return new BedrockContainerSlot(ContainerSlotType.HOTBAR, tmp - 27);
+ }
+ }
+ throw new IllegalArgumentException("Unknown bedrock slot");
+ }
+
@Override
public SlotType getSlotType(int javaSlot) {
return SlotType.NORMAL;
}
@Override
- public void translateActions(GeyserSession session, Inventory inventory, List actions) {
- InventoryActionDataTranslator.translate(this, session, inventory, actions);
+ public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) {
+ return new Container(name, windowId, windowType, this.size, playerInventory);
}
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BedrockContainerSlot.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BedrockContainerSlot.java
new file mode 100644
index 000000000..b3a09e167
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BedrockContainerSlot.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2019-2020 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.connector.network.translators.inventory;
+
+import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType;
+import lombok.Value;
+
+@Value
+public class BedrockContainerSlot {
+ ContainerSlotType container;
+ int slot;
+}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java
deleted file mode 100644
index 4b8b57e8f..000000000
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2019-2020 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.connector.network.translators.inventory;
-
-import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
-import org.geysermc.connector.inventory.Inventory;
-import org.geysermc.connector.network.session.GeyserSession;
-import org.geysermc.connector.network.translators.world.block.BlockTranslator;
-import org.geysermc.connector.network.translators.inventory.holder.BlockInventoryHolder;
-import org.geysermc.connector.network.translators.inventory.holder.InventoryHolder;
-import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
-
-public class BlockInventoryTranslator extends BaseInventoryTranslator {
- private final InventoryHolder holder;
- private final InventoryUpdater updater;
-
- public BlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType, InventoryUpdater updater) {
- super(size);
- int javaBlockState = BlockTranslator.getJavaBlockState(javaBlockIdentifier);
- int blockId = BlockTranslator.getBedrockBlockId(javaBlockState);
- this.holder = new BlockInventoryHolder(blockId, containerType);
- this.updater = updater;
- }
-
- @Override
- public void prepareInventory(GeyserSession session, Inventory inventory) {
- holder.prepareInventory(this, session, inventory);
- }
-
- @Override
- public void openInventory(GeyserSession session, Inventory inventory) {
- holder.openInventory(this, session, inventory);
- }
-
- @Override
- public void closeInventory(GeyserSession session, Inventory inventory) {
- holder.closeInventory(this, session, inventory);
- }
-
- @Override
- public void updateInventory(GeyserSession session, Inventory inventory) {
- updater.updateInventory(this, session, inventory);
- }
-
- @Override
- public void updateSlot(GeyserSession session, Inventory inventory, int slot) {
- updater.updateSlot(this, session, inventory, slot);
- }
-}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingInventoryTranslator.java
deleted file mode 100644
index 89cdbe8d7..000000000
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingInventoryTranslator.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (c) 2019-2020 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.connector.network.translators.inventory;
-
-import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
-import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData;
-import com.nukkitx.protocol.bedrock.packet.ContainerSetDataPacket;
-import org.geysermc.connector.inventory.Inventory;
-import org.geysermc.connector.network.session.GeyserSession;
-import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater;
-
-public class BrewingInventoryTranslator extends BlockInventoryTranslator {
- public BrewingInventoryTranslator() {
- super(5, "minecraft:brewing_stand[has_bottle_0=false,has_bottle_1=false,has_bottle_2=false]", ContainerType.BREWING_STAND, new ContainerInventoryUpdater());
- }
-
- @Override
- public void openInventory(GeyserSession session, Inventory inventory) {
- super.openInventory(session, inventory);
- ContainerSetDataPacket dataPacket = new ContainerSetDataPacket();
- dataPacket.setWindowId((byte) inventory.getId());
- 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) {
- ContainerSetDataPacket dataPacket = new ContainerSetDataPacket();
- dataPacket.setWindowId((byte) inventory.getId());
- switch (key) {
- case 0:
- dataPacket.setProperty(ContainerSetDataPacket.BREWING_STAND_BREW_TIME);
- break;
- case 1:
- dataPacket.setProperty(ContainerSetDataPacket.BREWING_STAND_FUEL_AMOUNT);
- break;
- default:
- return;
- }
- dataPacket.setValue(value);
- session.sendUpstreamPacket(dataPacket);
- }
-
- @Override
- public int bedrockSlotToJava(InventoryActionData action) {
- final int slot = super.bedrockSlotToJava(action);
- switch (slot) {
- case 0:
- return 3;
- case 1:
- return 0;
- case 2:
- return 1;
- case 3:
- return 2;
- default:
- return slot;
- }
- }
-
- @Override
- public int javaSlotToBedrock(int slot) {
- switch (slot) {
- case 0:
- return 1;
- case 1:
- return 2;
- case 2:
- return 3;
- case 3:
- return 0;
- }
- return super.javaSlotToBedrock(slot);
- }
-}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java
index 152f4a852..df97563e5 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java
@@ -25,14 +25,11 @@
package org.geysermc.connector.network.translators.inventory;
-import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData;
+import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType;
import org.geysermc.connector.inventory.Inventory;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.inventory.updater.ChestInventoryUpdater;
import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
-import org.geysermc.connector.utils.InventoryUtils;
-
-import java.util.List;
public abstract class ChestInventoryTranslator extends BaseInventoryTranslator {
private final InventoryUpdater updater;
@@ -53,17 +50,10 @@ public abstract class ChestInventoryTranslator extends BaseInventoryTranslator {
}
@Override
- public void translateActions(GeyserSession session, Inventory inventory, List actions) {
- for (InventoryActionData action : actions) {
- if (action.getSource().getContainerId() == inventory.getId()) {
- if (action.getSlot() >= size) {
- updateInventory(session, inventory);
- InventoryUtils.updateCursor(session);
- return;
- }
- }
+ public BedrockContainerSlot javaSlotToBedrockContainer(int javaSlot) {
+ if (javaSlot < this.size) {
+ return new BedrockContainerSlot(ContainerSlotType.CONTAINER, javaSlot);
}
-
- super.translateActions(session, inventory, actions);
+ return super.javaSlotToBedrockContainer(javaSlot);
}
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java
deleted file mode 100644
index b260565b8..000000000
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) 2019-2020 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.connector.network.translators.inventory;
-
-import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
-import com.nukkitx.protocol.bedrock.data.inventory.ContainerId;
-import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
-import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData;
-import com.nukkitx.protocol.bedrock.data.inventory.InventorySource;
-import org.geysermc.connector.inventory.Inventory;
-import org.geysermc.connector.network.session.GeyserSession;
-import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater;
-import org.geysermc.connector.utils.InventoryUtils;
-
-import java.util.List;
-
-public class CraftingInventoryTranslator extends BlockInventoryTranslator {
- public CraftingInventoryTranslator() {
- super(10, "minecraft:crafting_table", ContainerType.WORKBENCH, new CursorInventoryUpdater());
- }
-
- @Override
- public int bedrockSlotToJava(InventoryActionData action) {
- if (action.getSlot() == 50) {
- // Slot 50 is used for crafting with a controller.
- return 0;
- }
-
- if (action.getSource().getContainerId() == ContainerId.UI) {
- int slotnum = action.getSlot();
- if (slotnum >= 32 && 42 >= slotnum) {
- return slotnum - 31;
- }
- }
- return super.bedrockSlotToJava(action);
- }
-
- @Override
- public int javaSlotToBedrock(int slot) {
- if (slot < size) {
- return slot == 0 ? 50 : slot + 31;
- }
- return super.javaSlotToBedrock(slot);
- }
-
- @Override
- public SlotType getSlotType(int javaSlot) {
- if (javaSlot == 0)
- return SlotType.OUTPUT;
- return SlotType.NORMAL;
- }
-
- @Override
- public void translateActions(GeyserSession session, Inventory inventory, List actions) {
- if (session.getGameMode() == GameMode.CREATIVE) {
- for (InventoryActionData action : actions) {
- if (action.getSource().getType() == InventorySource.Type.CREATIVE) {
- updateInventory(session, inventory);
- InventoryUtils.updateCursor(session);
- return;
- }
- }
- }
- super.translateActions(session, inventory, actions);
- }
-}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/EnchantmentInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/EnchantmentInventoryTranslator.java
deleted file mode 100644
index 20a47fd02..000000000
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/EnchantmentInventoryTranslator.java
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Copyright (c) 2019-2020 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.connector.network.translators.inventory;
-
-import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientClickWindowButtonPacket;
-import com.nukkitx.nbt.NbtMap;
-import com.nukkitx.nbt.NbtMapBuilder;
-import com.nukkitx.nbt.NbtType;
-import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
-import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData;
-import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
-import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket;
-import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
-import lombok.ToString;
-import org.geysermc.connector.common.ChatColor;
-import org.geysermc.connector.inventory.Inventory;
-import org.geysermc.connector.network.session.GeyserSession;
-import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
-import org.geysermc.connector.network.translators.item.ItemRegistry;
-import org.geysermc.connector.network.translators.item.ItemTranslator;
-import org.geysermc.connector.utils.InventoryUtils;
-import org.geysermc.connector.utils.LocaleUtils;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * A temporary reconstruction of the enchantment table UI until our inventory rewrite is complete.
- * The enchantment table on Bedrock without server authoritative inventories doesn't tell us which button is pressed
- * when selecting an enchantment.
- */
-public class EnchantmentInventoryTranslator extends BlockInventoryTranslator {
-
- private static final int DYE_ID = ItemRegistry.getItemEntry("minecraft:lapis_lazuli").getBedrockId();
- private static final int ENCHANTED_BOOK_ID = ItemRegistry.getItemEntry("minecraft:enchanted_book").getBedrockId();
-
- public EnchantmentInventoryTranslator(InventoryUpdater updater) {
- super(2, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, updater);
- }
-
- @Override
- public void translateActions(GeyserSession session, Inventory inventory, List actions) {
- for (InventoryActionData action : actions) {
- if (action.getSource().getContainerId() == inventory.getId()) {
- // This is the hopper UI
- switch (action.getSlot()) {
- case 1:
- // Don't allow the slot to be put through if the item isn't lapis
- if ((action.getToItem().getId() != DYE_ID) && action.getToItem() != ItemData.AIR) {
- updateInventory(session, inventory);
- InventoryUtils.updateCursor(session);
- return;
- }
- break;
- case 2:
- case 3:
- case 4:
- // The books here act as buttons
- ClientClickWindowButtonPacket packet = new ClientClickWindowButtonPacket(inventory.getId(), action.getSlot() - 2);
- session.sendDownstreamPacket(packet);
- updateInventory(session, inventory);
- InventoryUtils.updateCursor(session);
- return;
- default:
- break;
- }
- }
- }
-
- super.translateActions(session, inventory, actions);
- }
-
- @Override
- public void updateInventory(GeyserSession session, Inventory inventory) {
- super.updateInventory(session, inventory);
- ItemData[] items = new ItemData[5];
- items[0] = ItemTranslator.translateToBedrock(session, inventory.getItem(0));
- items[1] = ItemTranslator.translateToBedrock(session, inventory.getItem(1));
- for (int i = 0; i < 3; i++) {
- items[i + 2] = session.getEnchantmentSlotData()[i].getItem() != null ? session.getEnchantmentSlotData()[i].getItem() : createEnchantmentBook();
- }
-
- InventoryContentPacket contentPacket = new InventoryContentPacket();
- contentPacket.setContainerId(inventory.getId());
- contentPacket.setContents(items);
- session.sendUpstreamPacket(contentPacket);
- }
-
- @Override
- public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) {
- int bookSlotToUpdate;
- switch (key) {
- case 0:
- case 1:
- case 2:
- // Experience required
- bookSlotToUpdate = key;
- session.getEnchantmentSlotData()[bookSlotToUpdate].setExperienceRequired(value);
- break;
- case 4:
- case 5:
- case 6:
- // Enchantment name
- bookSlotToUpdate = key - 4;
- if (value != -1) {
- session.getEnchantmentSlotData()[bookSlotToUpdate].setEnchantmentType(EnchantmentTableEnchantments.values()[value - 1]);
- } else {
- // -1 means no enchantment specified
- session.getEnchantmentSlotData()[bookSlotToUpdate].setEnchantmentType(null);
- }
- break;
- case 7:
- case 8:
- case 9:
- // Enchantment level
- bookSlotToUpdate = key - 7;
- session.getEnchantmentSlotData()[bookSlotToUpdate].setEnchantmentLevel(value);
- break;
- default:
- return;
- }
- updateEnchantmentBook(session, inventory, bookSlotToUpdate);
- }
-
- @Override
- public void openInventory(GeyserSession session, Inventory inventory) {
- super.openInventory(session, inventory);
- for (int i = 0; i < session.getEnchantmentSlotData().length; i++) {
- session.getEnchantmentSlotData()[i] = new EnchantmentSlotData();
- }
- }
-
- @Override
- public void closeInventory(GeyserSession session, Inventory inventory) {
- super.closeInventory(session, inventory);
- Arrays.fill(session.getEnchantmentSlotData(), null);
- }
-
- private ItemData createEnchantmentBook() {
- NbtMapBuilder root = NbtMap.builder();
- NbtMapBuilder display = NbtMap.builder();
-
- display.putString("Name", ChatColor.RESET + "No Enchantment");
-
- root.put("display", display.build());
- return ItemData.of(ENCHANTED_BOOK_ID, (short) 0, 1, root.build());
- }
-
- private void updateEnchantmentBook(GeyserSession session, Inventory inventory, int slot) {
- NbtMapBuilder root = NbtMap.builder();
- NbtMapBuilder display = NbtMap.builder();
- EnchantmentSlotData data = session.getEnchantmentSlotData()[slot];
- if (data.getEnchantmentType() != null) {
- display.putString("Name", ChatColor.ITALIC + data.getEnchantmentType().toString(session) +
- (data.getEnchantmentLevel() != -1 ? " " + toRomanNumeral(session, data.getEnchantmentLevel()) : "") + "?");
- } else {
- display.putString("Name", ChatColor.RESET + "No Enchantment");
- }
-
- display.putList("Lore", NbtType.STRING, Collections.singletonList(ChatColor.DARK_GRAY + data.getExperienceRequired() + "xp"));
- root.put("display", display.build());
- ItemData book = ItemData.of(ENCHANTED_BOOK_ID, (short) 0, 1, root.build());
-
- InventorySlotPacket slotPacket = new InventorySlotPacket();
- slotPacket.setContainerId(inventory.getId());
- slotPacket.setSlot(slot + 2);
- slotPacket.setItem(book);
- session.sendUpstreamPacket(slotPacket);
- data.setItem(book);
- }
-
- private String toRomanNumeral(GeyserSession session, int level) {
- return LocaleUtils.getLocaleString("enchantment.level." + level,
- session.getLocale());
- }
-
- /**
- * Stores the data of each slot in an enchantment table
- */
- @NoArgsConstructor
- @Getter
- @Setter
- @ToString
- public static class EnchantmentSlotData {
- private EnchantmentTableEnchantments enchantmentType = null;
- private int enchantmentLevel = 0;
- private int experienceRequired = 0;
- private ItemData item;
- }
-
- /**
- * Classifies enchantments by Java order
- */
- public enum EnchantmentTableEnchantments {
- PROTECTION,
- FIRE_PROTECTION,
- FEATHER_FALLING,
- BLAST_PROTECTION,
- PROJECTILE_PROTECTION,
- RESPIRATION,
- AQUA_AFFINITY,
- THORNS,
- DEPTH_STRIDER,
- FROST_WALKER,
- BINDING_CURSE,
- SHARPNESS,
- SMITE,
- BANE_OF_ARTHROPODS,
- KNOCKBACK,
- FIRE_ASPECT,
- LOOTING,
- SWEEPING,
- EFFICIENCY,
- SILK_TOUCH,
- UNBREAKING,
- FORTUNE,
- POWER,
- PUNCH,
- FLAME,
- INFINITY,
- LUCK_OF_THE_SEA,
- LURE,
- LOYALTY,
- IMPALING,
- RIPTIDE,
- CHANNELING,
- MENDING,
- VANISHING_CURSE, // After this is not documented
- MULTISHOT,
- PIERCING,
- QUICK_CHARGE,
- SOUL_SPEED;
-
- public String toString(GeyserSession session) {
- return LocaleUtils.getLocaleString("enchantment.minecraft." + this.toString().toLowerCase(),
- session.getLocale());
- }
- }
-}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java
deleted file mode 100644
index 1f148e024..000000000
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 2019-2020 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.connector.network.translators.inventory;
-
-import com.github.steveice10.mc.protocol.data.game.window.WindowType;
-import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
-import com.nukkitx.protocol.bedrock.packet.ContainerSetDataPacket;
-import org.geysermc.connector.inventory.Inventory;
-import org.geysermc.connector.network.session.GeyserSession;
-import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater;
-
-public class FurnaceInventoryTranslator extends BlockInventoryTranslator {
- public FurnaceInventoryTranslator() {
- super(3, "minecraft:furnace[facing=north,lit=false]", ContainerType.FURNACE, new ContainerInventoryUpdater());
- }
-
- @Override
- public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) {
- ContainerSetDataPacket dataPacket = new ContainerSetDataPacket();
- dataPacket.setWindowId((byte) inventory.getId());
- switch (key) {
- case 0:
- dataPacket.setProperty(ContainerSetDataPacket.FURNACE_LIT_TIME);
- break;
- case 1:
- dataPacket.setProperty(ContainerSetDataPacket.FURNACE_LIT_DURATION);
- break;
- case 2:
- dataPacket.setProperty(ContainerSetDataPacket.FURNACE_TICK_COUNT);
- if (inventory.getWindowType() == WindowType.BLAST_FURNACE || inventory.getWindowType() == WindowType.SMOKER) {
- value *= 2;
- }
- break;
- default:
- return;
- }
- dataPacket.setValue(value);
- session.sendUpstreamPacket(dataPacket);
- }
-
- @Override
- public SlotType getSlotType(int javaSlot) {
- if (javaSlot == 2)
- return SlotType.FURNACE_OUTPUT;
- return SlotType.NORMAL;
- }
-}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/GrindstoneInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/GrindstoneInventoryTranslator.java
deleted file mode 100644
index 4b4a12465..000000000
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/GrindstoneInventoryTranslator.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2019-2020 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.connector.network.translators.inventory;
-
-import com.nukkitx.protocol.bedrock.data.inventory.ContainerId;
-import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
-import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData;
-import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater;
-
-public class GrindstoneInventoryTranslator extends BlockInventoryTranslator {
-
- public GrindstoneInventoryTranslator() {
- super(3, "minecraft:grindstone[face=floor,facing=north]", ContainerType.GRINDSTONE, new CursorInventoryUpdater());
- }
-
- @Override
- public int bedrockSlotToJava(InventoryActionData action) {
- final int slot = super.bedrockSlotToJava(action);
- if (action.getSource().getContainerId() == ContainerId.UI) {
- switch (slot) {
- case 16:
- return 0;
- case 17:
- return 1;
- case 50:
- return 2;
- default:
- return slot;
- }
- } return slot;
- }
-
- @Override
- public int javaSlotToBedrock(int slot) {
- switch (slot) {
- case 0:
- return 16;
- case 1:
- return 17;
- case 2:
- return 50;
- }
- return super.javaSlotToBedrock(slot);
- }
-
-}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java
index 3016871f0..69670a3de 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java
@@ -25,18 +25,26 @@
package org.geysermc.connector.network.translators.inventory;
+import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
-import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
-import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData;
+import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCreativeInventoryActionPacket;
+import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType;
+import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData;
+import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.*;
+import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket;
+import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket;
import lombok.AllArgsConstructor;
+import org.geysermc.connector.inventory.GeyserItemStack;
import org.geysermc.connector.inventory.Inventory;
+import org.geysermc.connector.inventory.PlayerInventory;
import org.geysermc.connector.network.session.GeyserSession;
-import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater;
-import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
+import org.geysermc.connector.network.translators.inventory.click.Click;
+import org.geysermc.connector.network.translators.inventory.click.ClickPlan;
+import org.geysermc.connector.network.translators.item.ItemRegistry;
+import org.geysermc.connector.network.translators.item.ItemTranslator;
+import org.geysermc.connector.utils.InventoryUtils;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
@AllArgsConstructor
public abstract class InventoryTranslator {
@@ -50,12 +58,13 @@ public abstract class InventoryTranslator {
put(WindowType.GENERIC_9X4, new DoubleChestInventoryTranslator(36));
put(WindowType.GENERIC_9X5, new DoubleChestInventoryTranslator(45));
put(WindowType.GENERIC_9X6, new DoubleChestInventoryTranslator(54));
- put(WindowType.BREWING_STAND, new BrewingInventoryTranslator());
+ /*put(WindowType.BREWING_STAND, new BrewingInventoryTranslator());
put(WindowType.ANVIL, new AnvilInventoryTranslator());
put(WindowType.CRAFTING, new CraftingInventoryTranslator());
- //put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator()); //FIXME
+ put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator());*/
put(WindowType.MERCHANT, new MerchantInventoryTranslator());
- //put(WindowType.SMITHING, new SmithingInventoryTranslator()); //TODO for server authoritative inventories
+ /*put(WindowType.SMITHING, new SmithingInventoryTranslator());
+ //put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator()); //TODO
InventoryTranslator furnace = new FurnaceInventoryTranslator();
put(WindowType.FURNACE, furnace);
@@ -63,14 +72,15 @@ public abstract class InventoryTranslator {
put(WindowType.SMOKER, furnace);
InventoryUpdater containerUpdater = new ContainerInventoryUpdater();
- put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator(containerUpdater)); //TODO
put(WindowType.GENERIC_3X3, new BlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER, containerUpdater));
put(WindowType.HOPPER, new BlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, containerUpdater));
put(WindowType.SHULKER_BOX, new BlockInventoryTranslator(27, "minecraft:shulker_box[facing=north]", ContainerType.CONTAINER, containerUpdater));
- //put(WindowType.BEACON, new BlockInventoryTranslator(1, "minecraft:beacon", ContainerType.BEACON)); //TODO
+ //put(WindowType.BEACON, new BlockInventoryTranslator(1, "minecraft:beacon", ContainerType.BEACON)); //TODO*/
}
};
+ public static final int PLAYER_INVENTORY_SIZE = 36;
+ public static final int PLAYER_INVENTORY_OFFSET = 9;
public final int size;
public abstract void prepareInventory(GeyserSession session, Inventory inventory);
@@ -79,8 +89,428 @@ public abstract class InventoryTranslator {
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);
- public abstract int bedrockSlotToJava(InventoryActionData action);
- public abstract int javaSlotToBedrock(int slot);
+ public abstract int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData);
+ public abstract int javaSlotToBedrock(int javaSlot); //TODO
+ public abstract BedrockContainerSlot javaSlotToBedrockContainer(int javaSlot); //TODO
public abstract SlotType getSlotType(int javaSlot);
- public abstract void translateActions(GeyserSession session, Inventory inventory, List actions);
+ public abstract Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory);
+
+ public void translateRequests(GeyserSession session, Inventory inventory, List requests) {
+ ItemStackResponsePacket responsePacket = new ItemStackResponsePacket();
+ for (ItemStackRequestPacket.Request request : requests) {
+ if (request.getActions().length > 0) {
+ StackRequestActionData firstAction = request.getActions()[0];
+ if (firstAction.getType() == StackRequestActionType.CRAFT_RECIPE || firstAction.getType() == StackRequestActionType.CRAFT_RECIPE_AUTO) {
+ responsePacket.getEntries().add(translateCraftingRequest(session, inventory, request));
+ } else if (firstAction.getType() == StackRequestActionType.CRAFT_CREATIVE) {
+ responsePacket.getEntries().add(translateCreativeRequest(session, inventory, request));
+ } else {
+ responsePacket.getEntries().add(translateRequest(session, inventory, request));
+ }
+ } else {
+ responsePacket.getEntries().add(rejectRequest(request));
+ }
+ }
+ session.sendUpstreamPacket(responsePacket);
+ System.out.println(responsePacket);
+ }
+
+ public ItemStackResponsePacket.Response translateRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) {
+ System.out.println(request);
+ ClickPlan plan = new ClickPlan(session, this, inventory);
+ for (StackRequestActionData action : request.getActions()) {
+ GeyserItemStack cursor = session.getPlayerInventory().getCursor();
+ switch (action.getType()) {
+ case TAKE:
+ case PLACE: {
+ TransferStackRequestActionData transferAction = (TransferStackRequestActionData) action;
+ if (!(checkNetId(session, inventory, transferAction.getSource()) && checkNetId(session, inventory, transferAction.getDestination())))
+ return rejectRequest(request);
+
+ if (isCursor(transferAction.getSource()) && isCursor(transferAction.getDestination())) { //???
+ return rejectRequest(request);
+ } else if (isCursor(transferAction.getSource())) { //releasing cursor
+ int sourceAmount = cursor.getAmount();
+ int destSlot = bedrockSlotToJava(transferAction.getDestination());
+ if (transferAction.getCount() == sourceAmount) { //release all
+ plan.add(Click.LEFT, destSlot);
+ } else { //release some
+ for (int i = 0; i < transferAction.getCount(); i++) {
+ plan.add(Click.RIGHT, destSlot);
+ }
+ }
+ } else if (isCursor(transferAction.getDestination())) { //picking up into cursor
+ int sourceSlot = bedrockSlotToJava(transferAction.getSource());
+ GeyserItemStack sourceItem = plan.getItem(sourceSlot);
+ int sourceAmount = sourceItem.getAmount();
+ if (cursor.isEmpty()) { //picking up into empty cursor
+ if (transferAction.getCount() == sourceAmount) { //pickup all
+ plan.add(Click.LEFT, sourceSlot);
+ } else if (transferAction.getCount() == sourceAmount - (sourceAmount / 2)) { //larger half; simple right click
+ plan.add(Click.RIGHT, sourceSlot);
+ } else { //pickup some; not a simple right click
+ plan.add(Click.LEFT, sourceSlot); //first pickup all
+ for (int i = 0; i < sourceAmount - transferAction.getCount(); i++) {
+ plan.add(Click.RIGHT, sourceSlot); //release extra items back into source slot
+ }
+ }
+ } else { //pickup into non-empty cursor
+ if (!InventoryUtils.canStack(cursor, plan.getItem(sourceSlot))) { //doesn't make sense, reject
+ return rejectRequest(request);
+ }
+ if (transferAction.getCount() != sourceAmount) { //TODO: handle partially picking up into non-empty cursor (temp slot)
+ return rejectRequest(request);
+ }
+ plan.add(Click.LEFT, sourceSlot); //release cursor onto source slot
+ plan.add(Click.LEFT, sourceSlot); //pickup combined cursor and source
+ }
+ } else { //transfer from one slot to another
+ if (!cursor.isEmpty()) { //TODO: handle slot transfer when cursor is already in use (temp slot)
+ return rejectRequest(request);
+ }
+ int sourceSlot = bedrockSlotToJava(transferAction.getSource());
+ int sourceAmount = plan.getItem(sourceSlot).getAmount();
+ int destSlot = bedrockSlotToJava(transferAction.getDestination());
+ if (transferAction.getCount() == sourceAmount) { //transfer all
+ plan.add(Click.LEFT, sourceSlot); //pickup source
+ plan.add(Click.LEFT, destSlot); //let go of all items and done
+ } else { //transfer some
+ //try to transfer items with least clicks possible
+ int halfSource = sourceAmount / 2; //smaller half
+ int holding;
+ if (transferAction.getCount() <= halfSource) { //faster to take only half
+ plan.add(Click.RIGHT, sourceSlot);
+ holding = halfSource;
+ } else { //need all
+ plan.add(Click.LEFT, sourceSlot);
+ holding = sourceAmount;
+ }
+ if (transferAction.getCount() > holding / 2) { //faster to release extra items onto source or dest slot?
+ for (int i = 0; i < holding - transferAction.getCount(); i++) {
+ plan.add(Click.RIGHT, sourceSlot); //prepare cursor
+ }
+ plan.add(Click.LEFT, destSlot); //release cursor onto dest slot
+ } else {
+ for (int i = 0; i < transferAction.getCount(); i++) {
+ plan.add(Click.RIGHT, destSlot); //right click until transfer goal is met
+ }
+ plan.add(Click.LEFT, sourceSlot); //return extra items to source slot
+ }
+ }
+ }
+ break;
+ }
+ case SWAP: { //TODO
+ SwapStackRequestActionData swapAction = (SwapStackRequestActionData) action;
+ if (!(checkNetId(session, inventory, swapAction.getSource()) && checkNetId(session, inventory, swapAction.getDestination())))
+ return rejectRequest(request);
+
+ if (isCursor(swapAction.getSource()) && isCursor(swapAction.getDestination())) { //???
+ return rejectRequest(request);
+ } else if (isCursor(swapAction.getSource())) { //swap cursor
+ int destSlot = bedrockSlotToJava(swapAction.getDestination());
+ if (InventoryUtils.canStack(cursor, plan.getItem(destSlot))) { //TODO: cannot simply swap if cursor stacks with slot (temp slot)
+ return rejectRequest(request);
+ }
+ plan.add(Click.LEFT, destSlot);
+ } else if (isCursor(swapAction.getDestination())) { //swap cursor
+ int sourceSlot = bedrockSlotToJava(swapAction.getSource());
+ if (InventoryUtils.canStack(cursor, plan.getItem(sourceSlot))) { //TODO
+ return rejectRequest(request);
+ }
+ plan.add(Click.LEFT, sourceSlot);
+ } else {
+ int sourceSlot = bedrockSlotToJava(swapAction.getSource());
+ int destSlot = bedrockSlotToJava(swapAction.getDestination());
+ if (!cursor.isEmpty()) { //TODO: (temp slot)
+ return rejectRequest(request);
+ }
+ if (sourceSlot == destSlot) { //doesn't make sense
+ return rejectRequest(request);
+ }
+ if (InventoryUtils.canStack(plan.getItem(sourceSlot), plan.getItem(destSlot))) { //TODO: (temp slot)
+ return rejectRequest(request);
+ }
+ plan.add(Click.LEFT, sourceSlot); //pickup source into cursor
+ plan.add(Click.LEFT, destSlot); //swap cursor with dest slot
+ plan.add(Click.LEFT, sourceSlot); //release cursor onto source
+ }
+ break;
+ }
+ case DROP: {
+ DropStackRequestActionData dropAction = (DropStackRequestActionData) action;
+ if (!checkNetId(session, inventory, dropAction.getSource()))
+ return rejectRequest(request);
+
+ if (isCursor(dropAction.getSource())) { //clicking outside of window
+ int sourceAmount = plan.getCursor().getAmount();
+ if (dropAction.getCount() == sourceAmount) { //drop all
+ plan.add(Click.LEFT_OUTSIDE, Click.OUTSIDE_SLOT);
+ } else { //drop some
+ for (int i = 0; i < dropAction.getCount(); i++) {
+ plan.add(Click.RIGHT_OUTSIDE, Click.OUTSIDE_SLOT); //drop one until goal is met
+ }
+ }
+ } else { //dropping from inventory
+ int sourceSlot = bedrockSlotToJava(dropAction.getSource());
+ int sourceAmount = plan.getItem(sourceSlot).getAmount();
+ if (dropAction.getCount() == sourceAmount && sourceAmount > 1) { //dropping all? (prefer DROP_ONE if only one)
+ plan.add(Click.DROP_ALL, sourceSlot);
+ } else { //drop some
+ for (int i = 0; i < dropAction.getCount(); i++) {
+ plan.add(Click.DROP_ONE, sourceSlot); //drop one until goal is met
+ }
+ }
+ }
+ break;
+ }
+ case CRAFT_CREATIVE: {
+ CraftCreativeStackRequestActionData creativeAction = (CraftCreativeStackRequestActionData) action;
+ System.out.println(creativeAction.getCreativeItemNetworkId());
+ }
+ default:
+ return rejectRequest(request);
+ }
+ }
+ plan.execute(false);
+ return acceptRequest(request, makeContainerEntries(session, inventory, plan.getAffectedSlots()));
+ }
+
+ public ItemStackResponsePacket.Response translateCraftingRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) {
+ System.out.println(request);
+
+ int recipeId = 0;
+ int resultSize = 0;
+ boolean autoCraft;
+ CraftState craftState = CraftState.START;
+
+ int leftover = 0;
+ ClickPlan plan = new ClickPlan(session, this, inventory);
+ for (StackRequestActionData action : request.getActions()) {
+ switch (action.getType()) {
+ case CRAFT_RECIPE: {
+ CraftRecipeStackRequestActionData craftAction = (CraftRecipeStackRequestActionData) action;
+ if (craftState != CraftState.START) {
+ return rejectRequest(request);
+ }
+ craftState = CraftState.RECIPE_ID;
+ recipeId = craftAction.getRecipeNetworkId();
+ System.out.println(session.getCraftingRecipes().get(recipeId).toString());
+ autoCraft = false;
+ break;
+ }
+ /*case CRAFT_RECIPE_AUTO: {
+ AutoCraftRecipeStackRequestActionData autoCraftAction = (AutoCraftRecipeStackRequestActionData) action;
+ if (craftState != CraftState.START) {
+ return rejectRequest(request);
+ }
+ craftState = CraftState.RECIPE_ID;
+ recipeId = autoCraftAction.getRecipeNetworkId();
+ autoCraft = true;
+ //TODO: reject transaction if crafting grid is not clear
+ break;
+ }*/
+ case CRAFT_RESULTS_DEPRECATED: {
+ CraftResultsDeprecatedStackRequestActionData deprecatedCraftAction = (CraftResultsDeprecatedStackRequestActionData) action;
+ if (craftState != CraftState.RECIPE_ID) {
+ return rejectRequest(request);
+ }
+ craftState = CraftState.DEPRECATED;
+
+ if (deprecatedCraftAction.getResultItems().length != 1) {
+ return rejectRequest(request);
+ }
+ resultSize = deprecatedCraftAction.getResultItems()[0].getCount();
+ if (resultSize <= 0) {
+ return rejectRequest(request);
+ }
+ break;
+ }
+ case CONSUME: {
+ ConsumeStackRequestActionData consumeAction = (ConsumeStackRequestActionData) action;
+ if (craftState != CraftState.DEPRECATED && craftState != CraftState.INGREDIENTS) {
+ return rejectRequest(request);
+ }
+ craftState = CraftState.INGREDIENTS;
+ break;
+ }
+ case TAKE:
+ case PLACE: {
+ TransferStackRequestActionData transferAction = (TransferStackRequestActionData) action;
+ if (craftState != CraftState.INGREDIENTS && craftState != CraftState.TRANSFER) {
+ return rejectRequest(request);
+ }
+ craftState = CraftState.TRANSFER;
+
+ if (transferAction.getSource().getContainer() != ContainerSlotType.CREATIVE_OUTPUT) {
+ return rejectRequest(request);
+ }
+ if (transferAction.getCount() <= 0) {
+ return rejectRequest(request);
+ }
+
+ int sourceSlot = bedrockSlotToJava(transferAction.getSource());
+ if (isCursor(transferAction.getDestination())) {
+ plan.add(Click.LEFT, sourceSlot);
+ craftState = CraftState.DONE;
+ } else {
+ int destSlot = bedrockSlotToJava(transferAction.getDestination());
+ if (leftover != 0) {
+ if (transferAction.getCount() > leftover) {
+ return rejectRequest(request);
+ }
+ if (transferAction.getCount() == leftover) {
+ plan.add(Click.LEFT, destSlot);
+ } else {
+ for (int i = 0; i < transferAction.getCount(); i++) {
+ plan.add(Click.RIGHT, destSlot);
+ }
+ }
+ leftover -= transferAction.getCount();
+ break;
+ }
+
+ int remainder = transferAction.getCount() % resultSize;
+ int timesToCraft = transferAction.getCount() / resultSize;
+ for (int i = 0; i < timesToCraft; i++) {
+ plan.add(Click.LEFT, sourceSlot);
+ plan.add(Click.LEFT, destSlot);
+ }
+ if (remainder > 0) {
+ plan.add(Click.LEFT, 0);
+ for (int i = 0; i < remainder; i++) {
+ plan.add(Click.RIGHT, destSlot);
+ }
+ leftover = resultSize - remainder;
+ }
+ }
+ break;
+ }
+ default:
+ return rejectRequest(request);
+ }
+ }
+ plan.execute(false);
+ Set affectedSlots = plan.getAffectedSlots();
+ affectedSlots.addAll(Arrays.asList(1, 2, 3, 4)); //TODO: crafting grid
+ return acceptRequest(request, makeContainerEntries(session, inventory, affectedSlots));
+ }
+
+ public ItemStackResponsePacket.Response translateCreativeRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) {
+ int creativeId = 0;
+ CraftState craftState = CraftState.START;
+ for (StackRequestActionData action : request.getActions()) {
+ switch (action.getType()) {
+ case CRAFT_CREATIVE: {
+ CraftCreativeStackRequestActionData creativeAction = (CraftCreativeStackRequestActionData) action;
+ if (craftState != CraftState.START) {
+ return rejectRequest(request);
+ }
+ craftState = CraftState.RECIPE_ID;
+
+ creativeId = creativeAction.getCreativeItemNetworkId();
+ break;
+ }
+ case CRAFT_RESULTS_DEPRECATED: {
+ CraftResultsDeprecatedStackRequestActionData deprecatedCraftAction = (CraftResultsDeprecatedStackRequestActionData) action;
+ if (craftState != CraftState.RECIPE_ID) {
+ return rejectRequest(request);
+ }
+ craftState = CraftState.DEPRECATED;
+ break;
+ }
+ case TAKE:
+ case PLACE: {
+ TransferStackRequestActionData transferAction = (TransferStackRequestActionData) action;
+ if (craftState != CraftState.DEPRECATED) {
+ return rejectRequest(request);
+ }
+ craftState = CraftState.TRANSFER;
+
+ if (transferAction.getSource().getContainer() != ContainerSlotType.CREATIVE_OUTPUT) {
+ return rejectRequest(request);
+ }
+ if (isCursor(transferAction.getDestination())) {
+ session.getPlayerInventory().setCursor(GeyserItemStack.from(ItemTranslator.translateToJava(ItemRegistry.CREATIVE_ITEMS[creativeId]), session.getItemNetId().getAndIncrement())); //TODO
+ return acceptRequest(request, makeContainerEntries(session, inventory, Collections.emptySet()));
+ } else {
+ int javaSlot = bedrockSlotToJava(transferAction.getDestination());
+ ItemStack javaItem = ItemTranslator.translateToJava(ItemRegistry.CREATIVE_ITEMS[creativeId - 1]); //TODO
+ inventory.setItem(javaSlot, GeyserItemStack.from(javaItem, session.getItemNetId().getAndIncrement()));
+ ClientCreativeInventoryActionPacket creativeActionPacket = new ClientCreativeInventoryActionPacket(
+ javaSlot,
+ javaItem
+ );
+ session.sendDownstreamPacket(creativeActionPacket);
+ Set affectedSlots = Collections.singleton(javaSlot);
+ return acceptRequest(request, makeContainerEntries(session, inventory, affectedSlots));
+ }
+ }
+ default:
+ return rejectRequest(request);
+ }
+ }
+ return rejectRequest(request);
+ }
+
+ public static ItemStackResponsePacket.Response acceptRequest(ItemStackRequestPacket.Request request, List containerEntries) {
+ return new ItemStackResponsePacket.Response(ItemStackResponsePacket.ResponseStatus.OK, request.getRequestId(), containerEntries);
+ }
+
+ public static ItemStackResponsePacket.Response rejectRequest(ItemStackRequestPacket.Request request) {
+ new Throwable("DEBUGGING: ItemStackRequest rejected").printStackTrace(); //TODO: temporary debugging
+ return new ItemStackResponsePacket.Response(ItemStackResponsePacket.ResponseStatus.ERROR, request.getRequestId(), Collections.emptyList());
+ }
+
+ public boolean checkNetId(GeyserSession session, Inventory inventory, StackRequestSlotInfoData slotInfoData) {
+ if (slotInfoData.getStackNetworkId() < 0)
+ return true;
+
+ GeyserItemStack currentItem = isCursor(slotInfoData) ? session.getPlayerInventory().getCursor() : inventory.getItem(bedrockSlotToJava(slotInfoData));
+ return currentItem.getNetId() == slotInfoData.getStackNetworkId();
+ }
+
+ public List makeContainerEntries(GeyserSession session, Inventory inventory, Set affectedSlots) {
+ Map> containerMap = new HashMap<>();
+ for (int slot : affectedSlots) {
+ BedrockContainerSlot bedrockSlot = javaSlotToBedrockContainer(slot);
+ List list = containerMap.computeIfAbsent(bedrockSlot.getContainer(), k -> new ArrayList<>());
+ list.add(makeItemEntry(session, bedrockSlot.getSlot(), inventory.getItem(slot)));
+ }
+
+ List containerEntries = new ArrayList<>();
+ for (Map.Entry> entry : containerMap.entrySet()) {
+ containerEntries.add(new ItemStackResponsePacket.ContainerEntry(entry.getKey(), entry.getValue()));
+ }
+
+ ItemStackResponsePacket.ItemEntry cursorEntry = makeItemEntry(session, 0, session.getPlayerInventory().getCursor());
+ containerEntries.add(new ItemStackResponsePacket.ContainerEntry(ContainerSlotType.CURSOR, Collections.singletonList(cursorEntry)));
+
+ return containerEntries;
+ }
+
+ public static ItemStackResponsePacket.ItemEntry makeItemEntry(GeyserSession session, int bedrockSlot, GeyserItemStack itemStack) {
+ ItemStackResponsePacket.ItemEntry itemEntry;
+ if (!itemStack.isEmpty()) {
+ int newNetId = session.getItemNetId().getAndIncrement();
+ itemStack.setNetId(newNetId);
+ itemEntry = new ItemStackResponsePacket.ItemEntry((byte) bedrockSlot, (byte) bedrockSlot, (byte) itemStack.getAmount(), newNetId, "");
+ } else {
+ itemEntry = new ItemStackResponsePacket.ItemEntry((byte) bedrockSlot, (byte) bedrockSlot, (byte) 0, 0, "");
+ }
+ return itemEntry;
+ }
+
+ private static boolean isCursor(StackRequestSlotInfoData slotInfoData) {
+ return slotInfoData.getContainer() == ContainerSlotType.CURSOR;
+ }
+
+ private enum CraftState {
+ START,
+ RECIPE_ID,
+ DEPRECATED,
+ INGREDIENTS,
+ TRANSFER,
+ DONE
+ }
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java
index 73f64dc6e..c4b2fc9a1 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java
@@ -25,14 +25,21 @@
package org.geysermc.connector.network.translators.inventory;
-import com.nukkitx.protocol.bedrock.data.inventory.ContainerId;
-import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData;
+import com.github.steveice10.mc.protocol.data.game.window.WindowType;
+import com.nukkitx.math.vector.Vector3f;
+import com.nukkitx.protocol.bedrock.data.entity.EntityData;
+import com.nukkitx.protocol.bedrock.data.entity.EntityDataMap;
+import com.nukkitx.protocol.bedrock.data.entity.EntityLinkData;
+import com.nukkitx.protocol.bedrock.data.inventory.*;
+import com.nukkitx.protocol.bedrock.packet.SetEntityLinkPacket;
+import org.geysermc.connector.entity.Entity;
+import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.inventory.Inventory;
+import org.geysermc.connector.inventory.MerchantContainer;
+import org.geysermc.connector.inventory.PlayerInventory;
import org.geysermc.connector.network.session.GeyserSession;
-import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater;
import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
-
-import java.util.List;
+import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater;
public class MerchantInventoryTranslator extends BaseInventoryTranslator {
@@ -40,7 +47,7 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator {
public MerchantInventoryTranslator() {
super(3);
- this.updater = new CursorInventoryUpdater();
+ this.updater = new UIInventoryUpdater();
}
@Override
@@ -57,26 +64,30 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator {
}
@Override
- public int bedrockSlotToJava(InventoryActionData action) {
- switch (action.getSource().getContainerId()) {
- case ContainerId.UI:
- switch (action.getSlot()) {
- case 4:
- return 0;
- case 5:
- return 1;
- case 50:
- return 2;
- }
- break;
- case -28: // Trading 1?
+ public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
+ switch (slot) {
+ case 0:
+ return new BedrockContainerSlot(ContainerSlotType.TRADE2_INGREDIENT1, 4);
+ case 1:
+ return new BedrockContainerSlot(ContainerSlotType.TRADE2_INGREDIENT2, 5);
+ case 2:
+ return new BedrockContainerSlot(ContainerSlotType.TRADE2_RESULT, 50);
+ }
+ return super.javaSlotToBedrockContainer(slot);
+ }
+
+ @Override
+ public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
+ switch (slotInfoData.getContainer()) {
+ case TRADE2_INGREDIENT1:
return 0;
- case -29: // Trading 2?
+ case TRADE2_INGREDIENT2:
return 1;
- case -30: // Trading Output?
+ case TRADE2_RESULT:
+ case CREATIVE_OUTPUT:
return 2;
}
- return super.bedrockSlotToJava(action);
+ return super.bedrockSlotToJava(slotInfoData);
}
@Override
@@ -89,18 +100,40 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator {
@Override
public void prepareInventory(GeyserSession session, Inventory inventory) {
+ MerchantContainer merchantInventory = (MerchantContainer) inventory;
+ if (merchantInventory.getVillager() == null) {
+ long geyserId = session.getEntityCache().getNextEntityId().incrementAndGet();
+ Vector3f pos = session.getPlayerEntity().getPosition().sub(0, 3, 0);
+ EntityDataMap metadata = new EntityDataMap();
+ metadata.put(EntityData.SCALE, 0f);
+ metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0f);
+ metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0f);
+
+ Entity villager = new Entity(0, geyserId, EntityType.VILLAGER, pos, Vector3f.ZERO, Vector3f.ZERO);
+ villager.setMetadata(metadata);
+ villager.spawnEntity(session);
+
+ SetEntityLinkPacket linkPacket = new SetEntityLinkPacket();
+ EntityLinkData.Type type = EntityLinkData.Type.PASSENGER;
+ linkPacket.setEntityLink(new EntityLinkData(session.getPlayerEntity().getGeyserId(), geyserId, type, true, false));
+ session.sendUpstreamPacket(linkPacket);
+
+ merchantInventory.setVillager(villager);
+ }
}
@Override
public void openInventory(GeyserSession session, Inventory inventory) {
-
+ //Handled in JavaTradeListTranslator
}
@Override
public void closeInventory(GeyserSession session, Inventory inventory) {
- session.setLastInteractedVillagerEid(-1);
- session.setVillagerTrades(null);
+ MerchantContainer merchantInventory = (MerchantContainer) inventory;
+ if (merchantInventory.getVillager() != null) {
+ merchantInventory.getVillager().despawnEntity(session);
+ }
}
@Override
@@ -114,11 +147,7 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator {
}
@Override
- public void translateActions(GeyserSession session, Inventory inventory, List actions) {
- if (actions.stream().anyMatch(a -> a.getSource().getContainerId() == -31)) {
- return;
- }
-
- super.translateActions(session, inventory, actions);
+ public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) {
+ return new MerchantContainer(name, windowId, windowType, this.size, playerInventory);
}
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java
index 7d7673c4e..48315fc1c 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java
@@ -25,18 +25,15 @@
package org.geysermc.connector.network.translators.inventory;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
-import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCreativeInventoryActionPacket;
-import com.nukkitx.protocol.bedrock.data.inventory.ContainerId;
-import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData;
-import com.nukkitx.protocol.bedrock.data.inventory.InventorySource;
-import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
+import com.github.steveice10.mc.protocol.data.game.window.WindowType;
+import com.nukkitx.protocol.bedrock.data.inventory.*;
import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket;
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
+import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket;
import org.geysermc.connector.inventory.Inventory;
+import org.geysermc.connector.inventory.PlayerInventory;
import org.geysermc.connector.network.session.GeyserSession;
-import org.geysermc.connector.network.translators.inventory.action.InventoryActionDataTranslator;
import org.geysermc.connector.network.translators.item.ItemTranslator;
import org.geysermc.connector.utils.InventoryUtils;
import org.geysermc.connector.utils.LanguageUtils;
@@ -59,11 +56,11 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
ItemData[] contents = new ItemData[36];
// Inventory
for (int i = 9; i < 36; i++) {
- contents[i] = ItemTranslator.translateToBedrock(session, inventory.getItem(i));
+ contents[i] = inventory.getItem(i).getItemData(session);
}
// Hotbar
for (int i = 36; i < 45; i++) {
- contents[i - 36] = ItemTranslator.translateToBedrock(session, inventory.getItem(i));
+ contents[i - 36] = inventory.getItem(i).getItemData(session);
}
inventoryContentPacket.setContents(contents);
session.sendUpstreamPacket(inventoryContentPacket);
@@ -73,7 +70,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
armorContentPacket.setContainerId(ContainerId.ARMOR);
contents = new ItemData[4];
for (int i = 5; i < 9; i++) {
- contents[i - 5] = ItemTranslator.translateToBedrock(session, inventory.getItem(i));
+ contents[i - 5] = inventory.getItem(i).getItemData(session);
}
armorContentPacket.setContents(contents);
session.sendUpstreamPacket(armorContentPacket);
@@ -81,7 +78,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
// Offhand
InventoryContentPacket offhandPacket = new InventoryContentPacket();
offhandPacket.setContainerId(ContainerId.OFFHAND);
- offhandPacket.setContents(new ItemData[]{ItemTranslator.translateToBedrock(session, inventory.getItem(45))});
+ offhandPacket.setContents(new ItemData[]{inventory.getItem(45).getItemData(session)});
session.sendUpstreamPacket(offhandPacket);
}
@@ -100,7 +97,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
if (session.getGameMode() == GameMode.CREATIVE) {
slotPacket.setItem(UNUSUABLE_CRAFTING_SPACE_BLOCK);
}else{
- slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(i)));
+ slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(i).getItemStack()));
}
session.sendUpstreamPacket(slotPacket);
@@ -125,21 +122,23 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
slotPacket.setContainerId(ContainerId.UI);
slotPacket.setSlot(slot + 27);
}
- slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(slot)));
+ slotPacket.setItem(inventory.getItem(slot).getItemData(session));
session.sendUpstreamPacket(slotPacket);
} else if (slot == 45) {
InventoryContentPacket offhandPacket = new InventoryContentPacket();
offhandPacket.setContainerId(ContainerId.OFFHAND);
- offhandPacket.setContents(new ItemData[]{ItemTranslator.translateToBedrock(session, inventory.getItem(slot))});
+ offhandPacket.setContents(new ItemData[]{inventory.getItem(slot).getItemData(session)});
session.sendUpstreamPacket(offhandPacket);
}
}
@Override
- public int bedrockSlotToJava(InventoryActionData action) {
- int slotnum = action.getSlot();
- switch (action.getSource().getContainerId()) {
- case ContainerId.INVENTORY:
+ public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
+ int slotnum = slotInfoData.getSlot();
+ switch (slotInfoData.getContainer()) {
+ case HOTBAR_AND_INVENTORY:
+ case HOTBAR:
+ case INVENTORY:
// Inventory
if (slotnum >= 9 && slotnum <= 35) {
return slotnum;
@@ -149,19 +148,19 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
return slotnum + 36;
}
break;
- case ContainerId.ARMOR:
+ case ARMOR:
if (slotnum >= 0 && slotnum <= 3) {
return slotnum + 5;
}
break;
- case ContainerId.OFFHAND:
+ case OFFHAND:
return 45;
- case ContainerId.UI:
+ case CRAFTING_INPUT:
if (slotnum >= 28 && 31 >= slotnum) {
return slotnum - 27;
}
break;
- case ContainerId.CRAFTING_RESULT:
+ case CREATIVE_OUTPUT:
return 0;
}
return slotnum;
@@ -169,7 +168,26 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
@Override
public int javaSlotToBedrock(int slot) {
- return slot;
+ return -1;
+ }
+
+ @Override
+ public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
+ if (slot >= 36 && slot <= 44) {
+ return new BedrockContainerSlot(ContainerSlotType.HOTBAR, slot - 36);
+ } else if (slot >= 9 && slot <= 35) {
+ return new BedrockContainerSlot(ContainerSlotType.INVENTORY, slot);
+ } else if (slot >= 5 && slot <= 8) {
+ return new BedrockContainerSlot(ContainerSlotType.ARMOR, slot - 5);
+ } else if (slot == 45) {
+ return new BedrockContainerSlot(ContainerSlotType.OFFHAND, 1);
+ } else if (slot >= 1 && slot <= 4) {
+ return new BedrockContainerSlot(ContainerSlotType.CRAFTING_INPUT, slot + 27);
+ } else if (slot == 0) {
+ return new BedrockContainerSlot(ContainerSlotType.CRAFTING_OUTPUT, 0);
+ } else {
+ throw new IllegalArgumentException("Unknown bedrock slot");
+ }
}
@Override
@@ -180,52 +198,13 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
}
@Override
- public void translateActions(GeyserSession session, Inventory inventory, List actions) {
- if (session.getGameMode() == GameMode.CREATIVE) {
- //crafting grid is not visible in creative mode in java edition
- for (InventoryActionData action : actions) {
- if (action.getSource().getContainerId() == ContainerId.UI && (action.getSlot() >= 28 && 31 >= action.getSlot())) {
- updateInventory(session, inventory);
- InventoryUtils.updateCursor(session);
- return;
- }
- }
+ public void translateRequests(GeyserSession session, Inventory inventory, List requests) {
+ super.translateRequests(session, inventory, requests);
+ }
- ItemStack javaItem;
- for (InventoryActionData action : actions) {
- switch (action.getSource().getContainerId()) {
- case ContainerId.INVENTORY:
- case ContainerId.ARMOR:
- case ContainerId.OFFHAND:
- int javaSlot = bedrockSlotToJava(action);
- if (action.getToItem().getId() == 0) {
- javaItem = new ItemStack(-1, 0, null);
- } else {
- javaItem = ItemTranslator.translateToJava(action.getToItem());
- }
- ClientCreativeInventoryActionPacket creativePacket = new ClientCreativeInventoryActionPacket(javaSlot, javaItem);
- session.sendDownstreamPacket(creativePacket);
- inventory.setItem(javaSlot, javaItem);
- break;
- case ContainerId.UI:
- if (action.getSlot() == 0) {
- session.getInventory().setCursor(ItemTranslator.translateToJava(action.getToItem()));
- }
- break;
- case ContainerId.NONE:
- if (action.getSource().getType() == InventorySource.Type.WORLD_INTERACTION
- && action.getSource().getFlag() == InventorySource.Flag.DROP_ITEM) {
- javaItem = ItemTranslator.translateToJava(action.getToItem());
- ClientCreativeInventoryActionPacket creativeDropPacket = new ClientCreativeInventoryActionPacket(-1, javaItem);
- session.sendDownstreamPacket(creativeDropPacket);
- }
- break;
- }
- }
- return;
- }
-
- InventoryActionDataTranslator.translate(this, session, inventory, actions);
+ @Override
+ public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) {
+ throw new UnsupportedOperationException();
}
@Override
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SmithingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SmithingInventoryTranslator.java
deleted file mode 100644
index f7f0acd8c..000000000
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SmithingInventoryTranslator.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2019-2020 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.connector.network.translators.inventory;
-
-import com.nukkitx.protocol.bedrock.data.inventory.ContainerId;
-import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
-import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData;
-import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater;
-
-public class SmithingInventoryTranslator extends BlockInventoryTranslator {
-
- public SmithingInventoryTranslator() {
- super(3, "minecraft:smithing_table", ContainerType.SMITHING_TABLE, new CursorInventoryUpdater());
- }
-
- @Override
- public int bedrockSlotToJava(InventoryActionData action) {
- final int slot = super.bedrockSlotToJava(action);
- if (action.getSource().getContainerId() == ContainerId.UI) {
- switch (slot) {
- case 51:
- return 0;
- case 52:
- return 1;
- case 50:
- return 2;
- default:
- return slot;
- }
- } return slot;
- }
-
- @Override
- public int javaSlotToBedrock(int slot) {
- switch (slot) {
- case 0:
- return 51;
- case 1:
- return 52;
- case 2:
- return 50;
- }
- return super.javaSlotToBedrock(slot);
- }
-
-}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/ClickPlan.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/ClickPlan.java
deleted file mode 100644
index a9c1eddca..000000000
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/ClickPlan.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (c) 2019-2020 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.connector.network.translators.inventory.action;
-
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
-import com.github.steveice10.mc.protocol.data.game.window.WindowAction;
-import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientConfirmTransactionPacket;
-import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientWindowActionPacket;
-import org.geysermc.connector.inventory.Inventory;
-import org.geysermc.connector.inventory.PlayerInventory;
-import org.geysermc.connector.network.session.GeyserSession;
-import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
-import org.geysermc.connector.network.translators.inventory.SlotType;
-import org.geysermc.connector.utils.InventoryUtils;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.ListIterator;
-
-class ClickPlan {
- private final List plan = new ArrayList<>();
-
- public void add(Click click, int slot) {
- plan.add(new ClickAction(click, slot));
- }
-
- public void execute(GeyserSession session, InventoryTranslator translator, Inventory inventory, boolean refresh) {
- PlayerInventory playerInventory = session.getInventory();
- ListIterator planIter = plan.listIterator();
- while (planIter.hasNext()) {
- final ClickAction action = planIter.next();
- final ItemStack cursorItem = playerInventory.getCursor();
- final ItemStack clickedItem = inventory.getItem(action.slot);
- final short actionId = (short) inventory.getTransactionId().getAndIncrement();
-
- //TODO: stop relying on refreshing the inventory for crafting to work properly
- if (translator.getSlotType(action.slot) != SlotType.NORMAL)
- refresh = true;
-
- ClientWindowActionPacket clickPacket = new ClientWindowActionPacket(inventory.getId(),
- actionId, action.slot, !planIter.hasNext() && refresh ? InventoryUtils.REFRESH_ITEM : clickedItem,
- WindowAction.CLICK_ITEM, action.click.actionParam);
-
- if (translator.getSlotType(action.slot) == SlotType.OUTPUT) {
- if (cursorItem == null && clickedItem != null) {
- playerInventory.setCursor(clickedItem);
- } else if (InventoryUtils.canStack(cursorItem, clickedItem)) {
- playerInventory.setCursor(new ItemStack(cursorItem.getId(),
- cursorItem.getAmount() + clickedItem.getAmount(), cursorItem.getNbt()));
- }
- } else {
- switch (action.click) {
- case LEFT:
- if (!InventoryUtils.canStack(cursorItem, clickedItem)) {
- playerInventory.setCursor(clickedItem);
- inventory.setItem(action.slot, cursorItem);
- } else {
- playerInventory.setCursor(null);
- inventory.setItem(action.slot, new ItemStack(clickedItem.getId(),
- clickedItem.getAmount() + cursorItem.getAmount(), clickedItem.getNbt()));
- }
- break;
- case RIGHT:
- if (cursorItem == null && clickedItem != null) {
- ItemStack halfItem = new ItemStack(clickedItem.getId(),
- clickedItem.getAmount() / 2, clickedItem.getNbt());
- inventory.setItem(action.slot, halfItem);
- playerInventory.setCursor(new ItemStack(clickedItem.getId(),
- clickedItem.getAmount() - halfItem.getAmount(), clickedItem.getNbt()));
- } else if (cursorItem != null && clickedItem == null) {
- playerInventory.setCursor(new ItemStack(cursorItem.getId(),
- cursorItem.getAmount() - 1, cursorItem.getNbt()));
- inventory.setItem(action.slot, new ItemStack(cursorItem.getId(),
- 1, cursorItem.getNbt()));
- } else if (InventoryUtils.canStack(cursorItem, clickedItem)) {
- playerInventory.setCursor(new ItemStack(cursorItem.getId(),
- cursorItem.getAmount() - 1, cursorItem.getNbt()));
- inventory.setItem(action.slot, new ItemStack(clickedItem.getId(),
- clickedItem.getAmount() + 1, clickedItem.getNbt()));
- }
- break;
- }
- }
- session.sendDownstreamPacket(clickPacket);
- session.sendDownstreamPacket(new ClientConfirmTransactionPacket(inventory.getId(), actionId, true));
- }
-
- /*if (refresh) {
- translator.updateInventory(session, inventory);
- InventoryUtils.updateCursor(session);
- }*/
- }
-
- private static class ClickAction {
- final Click click;
- final int slot;
- ClickAction(Click click, int slot) {
- this.click = click;
- this.slot = slot;
- }
- }
-}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionDataTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionDataTranslator.java
deleted file mode 100644
index 96cbd61fb..000000000
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionDataTranslator.java
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * Copyright (c) 2019-2020 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.connector.network.translators.inventory.action;
-
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
-import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
-import com.github.steveice10.mc.protocol.data.game.window.*;
-import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace;
-import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket;
-import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientWindowActionPacket;
-import com.nukkitx.protocol.bedrock.data.inventory.ContainerId;
-import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData;
-import com.nukkitx.protocol.bedrock.data.inventory.InventorySource;
-import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
-import org.geysermc.connector.inventory.Inventory;
-import org.geysermc.connector.network.session.GeyserSession;
-import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
-import org.geysermc.connector.network.translators.inventory.SlotType;
-import org.geysermc.connector.network.translators.item.ItemTranslator;
-import org.geysermc.connector.utils.InventoryUtils;
-
-import java.util.*;
-
-public class InventoryActionDataTranslator {
- public static void translate(InventoryTranslator translator, GeyserSession session, Inventory inventory, List actions) {
- if (actions.size() != 2)
- return;
-
- InventoryActionData worldAction = null;
- InventoryActionData cursorAction = null;
- InventoryActionData containerAction = null;
- boolean refresh = false;
- for (InventoryActionData action : actions) {
- if (action.getSource().getContainerId() == ContainerId.CRAFTING_USE_INGREDIENT) {
- return;
- } else if (action.getSource().getType() == InventorySource.Type.WORLD_INTERACTION) {
- worldAction = action;
- } else if (action.getSource().getContainerId() == ContainerId.UI && action.getSlot() == 0) {
- cursorAction = action;
- ItemData translatedCursor = ItemTranslator.translateToBedrock(session, session.getInventory().getCursor());
- if (!translatedCursor.equals(action.getFromItem())) {
- refresh = true;
- }
- } else {
- containerAction = action;
- ItemData translatedItem = ItemTranslator.translateToBedrock(session, inventory.getItem(translator.bedrockSlotToJava(action)));
- if (!translatedItem.equals(action.getFromItem())) {
- refresh = true;
- }
- }
- }
-
- final int craftSlot = session.getCraftSlot();
- session.setCraftSlot(0);
-
- if (worldAction != null) {
- InventoryActionData sourceAction;
- if (cursorAction != null) {
- sourceAction = cursorAction;
- } else {
- sourceAction = containerAction;
- }
-
- if (sourceAction != null) {
- if (worldAction.getSource().getFlag() == InventorySource.Flag.DROP_ITEM) {
- //quick dropping from hotbar?
- if (session.getInventoryCache().getOpenInventory() == null && sourceAction.getSource().getContainerId() == ContainerId.INVENTORY) {
- int heldSlot = session.getInventory().getHeldItemSlot();
- if (sourceAction.getSlot() == heldSlot) {
- ClientPlayerActionPacket actionPacket = new ClientPlayerActionPacket(
- sourceAction.getToItem().getCount() == 0 ? PlayerAction.DROP_ITEM_STACK : PlayerAction.DROP_ITEM,
- new Position(0, 0, 0), BlockFace.DOWN);
- session.sendDownstreamPacket(actionPacket);
- ItemStack item = session.getInventory().getItem(heldSlot);
- if (item != null) {
- session.getInventory().setItem(heldSlot, new ItemStack(item.getId(), item.getAmount() - 1, item.getNbt()));
- }
- return;
- }
- }
- int dropAmount = sourceAction.getFromItem().getCount() - sourceAction.getToItem().getCount();
- if (sourceAction != cursorAction) { //dropping directly from inventory
- int javaSlot = translator.bedrockSlotToJava(sourceAction);
- if (dropAmount == sourceAction.getFromItem().getCount()) {
- ClientWindowActionPacket dropPacket = new ClientWindowActionPacket(inventory.getId(),
- inventory.getTransactionId().getAndIncrement(),
- javaSlot, null, WindowAction.DROP_ITEM,
- DropItemParam.DROP_SELECTED_STACK);
- session.sendDownstreamPacket(dropPacket);
- } else {
- for (int i = 0; i < dropAmount; i++) {
- ClientWindowActionPacket dropPacket = new ClientWindowActionPacket(inventory.getId(),
- inventory.getTransactionId().getAndIncrement(),
- javaSlot, null, WindowAction.DROP_ITEM,
- DropItemParam.DROP_FROM_SELECTED);
- session.sendDownstreamPacket(dropPacket);
- }
- }
- ItemStack item = inventory.getItem(javaSlot);
- if (item != null) {
- inventory.setItem(javaSlot, new ItemStack(item.getId(), item.getAmount() - dropAmount, item.getNbt()));
- }
- return;
- } else { //clicking outside of inventory
- ClientWindowActionPacket dropPacket = new ClientWindowActionPacket(inventory.getId(), inventory.getTransactionId().getAndIncrement(),
- -999, null, WindowAction.CLICK_ITEM,
- dropAmount > 1 ? ClickItemParam.LEFT_CLICK : ClickItemParam.RIGHT_CLICK);
- session.sendDownstreamPacket(dropPacket);
- ItemStack cursor = session.getInventory().getCursor();
- if (cursor != null) {
- session.getInventory().setCursor(new ItemStack(cursor.getId(), dropAmount > 1 ? 0 : cursor.getAmount() - 1, cursor.getNbt()));
- }
- return;
- }
- }
- }
- } else if (cursorAction != null && containerAction != null) {
- //left/right click
- ClickPlan plan = new ClickPlan();
- int javaSlot = translator.bedrockSlotToJava(containerAction);
- if (cursorAction.getFromItem().equals(containerAction.getToItem())
- && containerAction.getFromItem().equals(cursorAction.getToItem())
- && !InventoryUtils.canStack(cursorAction.getFromItem(), containerAction.getFromItem())) { //simple swap
- plan.add(Click.LEFT, javaSlot);
- } else if (cursorAction.getFromItem().getCount() > cursorAction.getToItem().getCount()) { //release
- if (cursorAction.getToItem().getCount() == 0) {
- plan.add(Click.LEFT, javaSlot);
- } else {
- int difference = cursorAction.getFromItem().getCount() - cursorAction.getToItem().getCount();
- for (int i = 0; i < difference; i++) {
- plan.add(Click.RIGHT, javaSlot);
- }
- }
- } else { //pickup
- if (cursorAction.getFromItem().getCount() == 0) {
- if (containerAction.getToItem().getCount() == 0) { //pickup all
- plan.add(Click.LEFT, javaSlot);
- } else { //pickup some
- if (translator.getSlotType(javaSlot) == SlotType.FURNACE_OUTPUT
- || containerAction.getToItem().getCount() == containerAction.getFromItem().getCount() / 2) { //right click
- plan.add(Click.RIGHT, javaSlot);
- } else {
- plan.add(Click.LEFT, javaSlot);
- int difference = containerAction.getFromItem().getCount() - cursorAction.getToItem().getCount();
- for (int i = 0; i < difference; i++) {
- plan.add(Click.RIGHT, javaSlot);
- }
- }
- }
- } else { //pickup into non-empty cursor
- if (translator.getSlotType(javaSlot) == SlotType.FURNACE_OUTPUT) {
- if (containerAction.getToItem().getCount() == 0) {
- plan.add(Click.LEFT, javaSlot);
- } else {
- ClientWindowActionPacket shiftClickPacket = new ClientWindowActionPacket(inventory.getId(),
- inventory.getTransactionId().getAndIncrement(),
- javaSlot, InventoryUtils.REFRESH_ITEM, WindowAction.SHIFT_CLICK_ITEM,
- ShiftClickItemParam.LEFT_CLICK);
- session.sendDownstreamPacket(shiftClickPacket);
- translator.updateInventory(session, inventory);
- return;
- }
- } else if (translator.getSlotType(javaSlot) == SlotType.OUTPUT) {
- plan.add(Click.LEFT, javaSlot);
- } else {
- int cursorSlot = findTempSlot(inventory, session.getInventory().getCursor(), Collections.singletonList(javaSlot), false);
- if (cursorSlot != -1) {
- plan.add(Click.LEFT, cursorSlot);
- } else {
- translator.updateInventory(session, inventory);
- InventoryUtils.updateCursor(session);
- return;
- }
- plan.add(Click.LEFT, javaSlot);
- int difference = cursorAction.getToItem().getCount() - cursorAction.getFromItem().getCount();
- for (int i = 0; i < difference; i++) {
- plan.add(Click.RIGHT, cursorSlot);
- }
- plan.add(Click.LEFT, javaSlot);
- plan.add(Click.LEFT, cursorSlot);
- }
- }
- }
- plan.execute(session, translator, inventory, refresh);
- return;
- } else {
- ClickPlan plan = new ClickPlan();
- InventoryActionData fromAction;
- InventoryActionData toAction;
- if (actions.get(0).getFromItem().getCount() >= actions.get(0).getToItem().getCount()) {
- fromAction = actions.get(0);
- toAction = actions.get(1);
- } else {
- fromAction = actions.get(1);
- toAction = actions.get(0);
- }
- int fromSlot = translator.bedrockSlotToJava(fromAction);
- int toSlot = translator.bedrockSlotToJava(toAction);
-
- if (translator.getSlotType(fromSlot) == SlotType.OUTPUT) {
- if ((craftSlot != 0 && craftSlot != -2) && (inventory.getItem(toSlot) == null
- || InventoryUtils.canStack(session.getInventory().getCursor(), inventory.getItem(toSlot)))) {
- if (fromAction.getToItem().getCount() == 0) {
- refresh = true;
- plan.add(Click.LEFT, toSlot);
- if (craftSlot != -1) {
- plan.add(Click.LEFT, craftSlot);
- }
- } else {
- int difference = toAction.getToItem().getCount() - toAction.getFromItem().getCount();
- for (int i = 0; i < difference; i++) {
- plan.add(Click.RIGHT, toSlot);
- }
- session.setCraftSlot(craftSlot);
- }
- plan.execute(session, translator, inventory, refresh);
- return;
- } else {
- session.setCraftSlot(-2);
- }
- }
-
- int cursorSlot = -1;
- if (session.getInventory().getCursor() != null) { //move cursor contents to a temporary slot
- cursorSlot = findTempSlot(inventory,
- session.getInventory().getCursor(),
- Arrays.asList(fromSlot, toSlot),
- translator.getSlotType(fromSlot) == SlotType.OUTPUT);
- if (cursorSlot != -1) {
- plan.add(Click.LEFT, cursorSlot);
- } else {
- translator.updateInventory(session, inventory);
- InventoryUtils.updateCursor(session);
- return;
- }
- }
- if ((fromAction.getFromItem().equals(toAction.getToItem()) && !InventoryUtils.canStack(fromAction.getFromItem(), toAction.getFromItem()))
- || fromAction.getToItem().getId() == 0) { //slot swap
- plan.add(Click.LEFT, fromSlot);
- plan.add(Click.LEFT, toSlot);
- if (fromAction.getToItem().getId() != 0) {
- plan.add(Click.LEFT, fromSlot);
- }
- } else if (InventoryUtils.canStack(fromAction.getFromItem(), toAction.getToItem())) { //partial item move
- if (translator.getSlotType(fromSlot) == SlotType.FURNACE_OUTPUT) {
- ClientWindowActionPacket shiftClickPacket = new ClientWindowActionPacket(inventory.getId(),
- inventory.getTransactionId().getAndIncrement(),
- fromSlot, InventoryUtils.REFRESH_ITEM, WindowAction.SHIFT_CLICK_ITEM,
- ShiftClickItemParam.LEFT_CLICK);
- session.sendDownstreamPacket(shiftClickPacket);
- translator.updateInventory(session, inventory);
- return;
- } else if (translator.getSlotType(fromSlot) == SlotType.OUTPUT) {
- session.setCraftSlot(cursorSlot);
- plan.add(Click.LEFT, fromSlot);
- int difference = toAction.getToItem().getCount() - toAction.getFromItem().getCount();
- for (int i = 0; i < difference; i++) {
- plan.add(Click.RIGHT, toSlot);
- }
- //client will send additional packets later to finish transferring crafting output
- //translator will know how to handle this using the craftSlot variable
- } else {
- plan.add(Click.LEFT, fromSlot);
- int difference = toAction.getToItem().getCount() - toAction.getFromItem().getCount();
- for (int i = 0; i < difference; i++) {
- plan.add(Click.RIGHT, toSlot);
- }
- plan.add(Click.LEFT, fromSlot);
- }
- }
- if (cursorSlot != -1) {
- plan.add(Click.LEFT, cursorSlot);
- }
- plan.execute(session, translator, inventory, refresh);
- return;
- }
-
- translator.updateInventory(session, inventory);
- InventoryUtils.updateCursor(session);
- }
-
- private static int findTempSlot(Inventory inventory, ItemStack item, List slotBlacklist, boolean emptyOnly) {
- /*try and find a slot that can temporarily store the given item
- only look in the main inventory and hotbar
- only slots that are empty or contain a different type of item are valid*/
- int offset = inventory.getId() == 0 ? 1 : 0; //offhand is not a viable slot (some servers disable it)
- List itemBlacklist = new ArrayList<>(slotBlacklist.size() + 1);
- itemBlacklist.add(item);
- for (int slot : slotBlacklist) {
- ItemStack blacklistItem = inventory.getItem(slot);
- if (blacklistItem != null)
- itemBlacklist.add(blacklistItem);
- }
- for (int i = inventory.getSize() - (36 + offset); i < inventory.getSize() - offset; i++) {
- ItemStack testItem = inventory.getItem(i);
- boolean acceptable = true;
- if (testItem != null) {
- if (emptyOnly) {
- continue;
- }
- for (ItemStack blacklistItem : itemBlacklist) {
- if (InventoryUtils.canStack(testItem, blacklistItem)) {
- acceptable = false;
- break;
- }
- }
- }
- if (acceptable && !slotBlacklist.contains(i))
- return i;
- }
- //could not find a viable temp slot
- return -1;
- }
-}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/Click.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/Click.java
similarity index 66%
rename from connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/Click.java
rename to connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/Click.java
index 1fdfa3640..d27290bff 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/Click.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/Click.java
@@ -23,16 +23,25 @@
* @link https://github.com/GeyserMC/Geyser
*/
-package org.geysermc.connector.network.translators.inventory.action;
+package org.geysermc.connector.network.translators.inventory.click;
import com.github.steveice10.mc.protocol.data.game.window.ClickItemParam;
+import com.github.steveice10.mc.protocol.data.game.window.DropItemParam;
+import com.github.steveice10.mc.protocol.data.game.window.WindowAction;
import com.github.steveice10.mc.protocol.data.game.window.WindowActionParam;
import lombok.AllArgsConstructor;
@AllArgsConstructor
-enum Click {
- LEFT(ClickItemParam.LEFT_CLICK),
- RIGHT(ClickItemParam.RIGHT_CLICK);
+public enum Click {
+ LEFT(WindowAction.CLICK_ITEM, ClickItemParam.LEFT_CLICK),
+ RIGHT(WindowAction.CLICK_ITEM, ClickItemParam.RIGHT_CLICK),
+ DROP_ONE(WindowAction.DROP_ITEM, DropItemParam.DROP_FROM_SELECTED),
+ DROP_ALL(WindowAction.DROP_ITEM, DropItemParam.DROP_SELECTED_STACK),
+ LEFT_OUTSIDE(WindowAction.CLICK_ITEM, ClickItemParam.LEFT_CLICK),
+ RIGHT_OUTSIDE(WindowAction.CLICK_ITEM, ClickItemParam.RIGHT_CLICK);
+ public static final int OUTSIDE_SLOT = -999;
+
+ public final WindowAction windowAction;
public final WindowActionParam actionParam;
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java
new file mode 100644
index 000000000..f4cf35617
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/click/ClickPlan.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2019-2020 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.connector.network.translators.inventory.click;
+
+import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
+import com.github.steveice10.mc.protocol.data.game.window.WindowAction;
+import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientConfirmTransactionPacket;
+import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientWindowActionPacket;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
+import lombok.Value;
+import org.geysermc.connector.inventory.GeyserItemStack;
+import org.geysermc.connector.inventory.Inventory;
+import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
+import org.geysermc.connector.network.translators.inventory.SlotType;
+import org.geysermc.connector.utils.InventoryUtils;
+
+import java.util.*;
+
+public class ClickPlan {
+ private final List plan = new ArrayList<>();
+ private final Int2ObjectMap simulatedItems;
+ private GeyserItemStack simulatedCursor;
+ private boolean simulating;
+
+ private final GeyserSession session;
+ private final InventoryTranslator translator;
+ private final Inventory inventory;
+
+ public ClickPlan(GeyserSession session, InventoryTranslator translator, Inventory inventory) {
+ this.session = session;
+ this.translator = translator;
+ this.inventory = inventory;
+
+ this.simulatedItems = new Int2ObjectOpenHashMap<>(inventory.getSize());
+ this.simulatedCursor = session.getPlayerInventory().getCursor().copy();
+ this.simulating = true;
+ }
+
+ public void add(Click click, int slot) {
+ if (!simulating)
+ throw new UnsupportedOperationException("ClickPlan already executed");
+
+ if (click == Click.LEFT_OUTSIDE || click == Click.RIGHT_OUTSIDE) {
+ slot = Click.OUTSIDE_SLOT;
+ }
+
+ ClickAction action = new ClickAction(click, slot);
+ plan.add(action);
+ simulateAction(action);
+ }
+
+ public void execute(boolean refresh) {
+ simulating = false;
+ ListIterator planIter = plan.listIterator();
+ while (planIter.hasNext()) {
+ ClickAction action = planIter.next();
+
+ if (action.slot != Click.OUTSIDE_SLOT && translator.getSlotType(action.slot) != SlotType.NORMAL) {
+ refresh = true;
+ }
+
+ ItemStack clickedItemStack;
+ if (!planIter.hasNext() && refresh) {
+ clickedItemStack = InventoryUtils.REFRESH_ITEM;
+ } else if (action.click.windowAction == WindowAction.DROP_ITEM || action.slot == Click.OUTSIDE_SLOT) {
+ clickedItemStack = null;
+ } else {
+ clickedItemStack = inventory.getItem(action.slot).getItemStack();
+ }
+
+ short actionId = inventory.getNextTransactionId();
+ ClientWindowActionPacket clickPacket = new ClientWindowActionPacket(
+ inventory.getId(),
+ actionId,
+ action.slot,
+ clickedItemStack,
+ action.click.windowAction,
+ action.click.actionParam
+ );
+
+ simulateAction(action);
+
+ session.sendDownstreamPacket(clickPacket);
+ if (clickedItemStack == InventoryUtils.REFRESH_ITEM) {
+ session.sendDownstreamPacket(new ClientConfirmTransactionPacket(inventory.getId(), actionId, true));
+ }
+ System.out.println(clickPacket);
+ }
+ }
+
+ public GeyserItemStack getItem(int slot) {
+ return simulatedItems.computeIfAbsent(slot, k -> inventory.getItem(slot).copy());
+ }
+
+ public GeyserItemStack getCursor() {
+ return simulatedCursor;
+ }
+
+ private void setItem(int slot, GeyserItemStack item) {
+ if (simulating) {
+ simulatedItems.put(slot, item);
+ } else {
+ inventory.setItem(slot, item);
+ }
+ }
+
+ private void setCursor(GeyserItemStack item) {
+ if (simulating) {
+ simulatedCursor = item;
+ } else {
+ session.getPlayerInventory().setCursor(item);
+ }
+ }
+
+ private void simulateAction(ClickAction action) {
+ GeyserItemStack cursor = simulating ? getCursor() : session.getPlayerInventory().getCursor();
+ switch (action.click) {
+ case LEFT_OUTSIDE:
+ setCursor(GeyserItemStack.EMPTY);
+ return;
+ case RIGHT_OUTSIDE:
+ if (!cursor.isEmpty()) {
+ cursor.sub(1);
+ }
+ return;
+ }
+
+ GeyserItemStack clicked = simulating ? getItem(action.slot) : inventory.getItem(action.slot);
+ if (translator.getSlotType(action.slot) == SlotType.OUTPUT) {
+ if (cursor.isEmpty() && !clicked.isEmpty()) {
+ setCursor(clicked.copy());
+ } else if (InventoryUtils.canStack(cursor, clicked)) {
+ cursor.add(clicked.getAmount());
+ }
+ } else {
+ switch (action.click) {
+ case LEFT:
+ if (!InventoryUtils.canStack(cursor, clicked)) {
+ setCursor(clicked);
+ setItem(action.slot, cursor);
+ } else {
+ setCursor(GeyserItemStack.EMPTY);
+ clicked.add(cursor.getAmount());
+ }
+ break;
+ case RIGHT:
+ if (cursor.isEmpty() && !clicked.isEmpty()) {
+ int half = clicked.getAmount() / 2; //smaller half
+ setCursor(clicked.copy(clicked.getAmount() - half)); //larger half
+ clicked.setAmount(half);
+ } else if (!cursor.isEmpty() && clicked.isEmpty()) {
+ cursor.sub(1);
+ setItem(action.slot, cursor.copy(1));
+ } else if (InventoryUtils.canStack(cursor, clicked)) {
+ cursor.sub(1);
+ clicked.add(1);
+ }
+ break;
+ case DROP_ONE:
+ if (!clicked.isEmpty()) {
+ clicked.sub(1);
+ }
+ break;
+ case DROP_ALL:
+ setItem(action.slot, GeyserItemStack.EMPTY);
+ break;
+ }
+ }
+ }
+
+ public Set getAffectedSlots() {
+ Set affectedSlots = new HashSet<>();
+ for (ClickAction action : plan) {
+ if (translator.getSlotType(action.slot) == SlotType.NORMAL && action.slot != Click.OUTSIDE_SLOT) {
+ affectedSlots.add(action.slot);
+ }
+ }
+ return affectedSlots;
+ }
+
+ @Value
+ private static class ClickAction {
+ Click click;
+ int slot;
+ }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java
index e45945bc3..58e6178b4 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java
@@ -49,7 +49,7 @@ public class ChestInventoryUpdater extends InventoryUpdater {
ItemData[] bedrockItems = new ItemData[paddedSize];
for (int i = 0; i < bedrockItems.length; i++) {
if (i < translator.size) {
- bedrockItems[i] = ItemTranslator.translateToBedrock(session, inventory.getItem(i));
+ bedrockItems[i] = inventory.getItem(i).getItemData(session);
} else {
bedrockItems[i] = UNUSUABLE_SPACE_BLOCK;
}
@@ -69,7 +69,7 @@ public class ChestInventoryUpdater extends InventoryUpdater {
InventorySlotPacket slotPacket = new InventorySlotPacket();
slotPacket.setContainerId(inventory.getId());
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
- slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot)));
+ slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session));
session.sendUpstreamPacket(slotPacket);
return true;
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ContainerInventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ContainerInventoryUpdater.java
index 51f33ac43..1abc65b5b 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ContainerInventoryUpdater.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ContainerInventoryUpdater.java
@@ -40,7 +40,7 @@ public class ContainerInventoryUpdater extends InventoryUpdater {
ItemData[] bedrockItems = new ItemData[translator.size];
for (int i = 0; i < bedrockItems.length; i++) {
- bedrockItems[translator.javaSlotToBedrock(i)] = ItemTranslator.translateToBedrock(session, inventory.getItem(i));
+ bedrockItems[translator.javaSlotToBedrock(i)] = inventory.getItem(i).getItemData(session);
}
InventoryContentPacket contentPacket = new InventoryContentPacket();
@@ -57,7 +57,7 @@ public class ContainerInventoryUpdater extends InventoryUpdater {
InventorySlotPacket slotPacket = new InventorySlotPacket();
slotPacket.setContainerId(inventory.getId());
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
- slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot)));
+ slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session));
session.sendUpstreamPacket(slotPacket);
return true;
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java
index 57601a9e0..655868c9a 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java
@@ -39,7 +39,7 @@ public abstract class InventoryUpdater {
ItemData[] bedrockItems = new ItemData[36];
for (int i = 0; i < 36; i++) {
final int offset = i < 9 ? 27 : -9;
- bedrockItems[i] = ItemTranslator.translateToBedrock(session, inventory.getItem(translator.size + i + offset));
+ bedrockItems[i] = inventory.getItem(translator.size + i + offset).getItemData(session);
}
InventoryContentPacket contentPacket = new InventoryContentPacket();
contentPacket.setContainerId(ContainerId.INVENTORY);
@@ -52,7 +52,7 @@ public abstract class InventoryUpdater {
InventorySlotPacket slotPacket = new InventorySlotPacket();
slotPacket.setContainerId(ContainerId.INVENTORY);
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
- slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot)));
+ slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session));
session.sendUpstreamPacket(slotPacket);
return true;
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/UIInventoryUpdater.java
similarity index 89%
rename from connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java
rename to connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/UIInventoryUpdater.java
index 26d889900..5100ddc99 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/UIInventoryUpdater.java
@@ -32,9 +32,8 @@ import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
import org.geysermc.connector.network.translators.item.ItemTranslator;
-public class CursorInventoryUpdater extends InventoryUpdater {
+public class UIInventoryUpdater extends InventoryUpdater {
- //TODO: Consider renaming this? Since the Protocol enum updated
@Override
public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {
super.updateInventory(translator, session, inventory);
@@ -46,7 +45,7 @@ public class CursorInventoryUpdater extends InventoryUpdater {
InventorySlotPacket slotPacket = new InventorySlotPacket();
slotPacket.setContainerId(ContainerId.UI);
slotPacket.setSlot(bedrockSlot);
- slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(i)));
+ slotPacket.setItem(inventory.getItem(i).getItemData(session));
session.sendUpstreamPacket(slotPacket);
}
}
@@ -59,7 +58,7 @@ public class CursorInventoryUpdater extends InventoryUpdater {
InventorySlotPacket slotPacket = new InventorySlotPacket();
slotPacket.setContainerId(ContainerId.UI);
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
- slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot)));
+ slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session));
session.sendUpstreamPacket(slotPacket);
return true;
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/RecipeRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/RecipeRegistry.java
index bcdf7fe2b..f87450f95 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/item/RecipeRegistry.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/RecipeRegistry.java
@@ -47,6 +47,8 @@ public class RecipeRegistry {
*/
public static int LAST_RECIPE_NET_ID = 0;
+ //public static final Int2ObjectMap
+
/**
* A list of all possible leather armor dyeing recipes.
* Created manually.
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java
index b233ba59c..7442f3884 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java
@@ -34,6 +34,8 @@ import com.nukkitx.nbt.NbtMap;
import com.nukkitx.protocol.bedrock.data.inventory.CraftingData;
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
import com.nukkitx.protocol.bedrock.packet.CraftingDataPacket;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import lombok.AllArgsConstructor;
@@ -52,7 +54,8 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator recipeMap = new Int2ObjectOpenHashMap<>();
CraftingDataPacket craftingDataPacket = new CraftingDataPacket();
craftingDataPacket.setCleanRecipes(true);
for (Recipe recipe : packet.getRecipes()) {
@@ -65,7 +68,8 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator
// Max health must be divisible by two in bedrock
entity.getAttributes().put(AttributeType.HEALTH, AttributeType.HEALTH.getAttribute(maxHealth, (maxHealth % 2 == 1 ? maxHealth + 1 : maxHealth)));
- session.getInventoryCache().setOpenInventory(null);
+ session.setOpenInventory(null);
SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket();
playerGameTypePacket.setGamemode(packet.getGamemode().ordinal());
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerActionAckTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerActionAckTranslator.java
index 9ed11a23d..05cc1a418 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerActionAckTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerActionAckTranslator.java
@@ -32,6 +32,7 @@ import com.github.steveice10.opennbt.tag.builtin.*;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.LevelEventType;
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
+import org.geysermc.connector.inventory.GeyserItemStack;
import org.geysermc.connector.inventory.PlayerInventory;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
@@ -71,15 +72,9 @@ public class JavaPlayerActionAckTranslator extends PacketTranslator {
+ PlayerHotbarPacket hotbarPacket = new PlayerHotbarPacket();
+ hotbarPacket.setContainerId(0);
+ hotbarPacket.setSelectedHotbarSlot(packet.getSlot());
+ hotbarPacket.setSelectHotbarSlot(true);
+ session.sendUpstreamPacket(hotbarPacket);
- session.getInventory().setHeldItemSlot(packet.getSlot());
+ session.getPlayerInventory().setHeldItemSlot(packet.getSlot());
+ });
}
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java
index 93cfa08e4..68f1dda91 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java
@@ -26,6 +26,7 @@
package org.geysermc.connector.network.translators.java.window;
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerCloseWindowPacket;
+import org.geysermc.connector.inventory.Inventory;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
@@ -36,7 +37,8 @@ public class JavaCloseWindowTranslator extends PacketTranslator {
+ InventoryUtils.closeInventory(session, packet.getWindowId());
+ });
}
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java
index e67877536..6d6c1686c 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java
@@ -27,6 +27,7 @@ package org.geysermc.connector.network.translators.java.window;
import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientConfirmTransactionPacket;
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerConfirmTransactionPacket;
+import org.geysermc.connector.inventory.Inventory;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
@@ -36,9 +37,11 @@ public class JavaConfirmTransactionTranslator extends PacketTranslator {
+ if (!packet.isAccepted()) {
+ ClientConfirmTransactionPacket confirmPacket = new ClientConfirmTransactionPacket(packet.getWindowId(), packet.getActionId(), true);
+ session.sendDownstreamPacket(confirmPacket);
+ }
+ });
}
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java
index 1fb088717..89982dbb7 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java
@@ -41,35 +41,35 @@ public class JavaOpenWindowTranslator extends PacketTranslator {
+ if (packet.getWindowId() == 0) {
+ return;
+ }
+
+ InventoryTranslator newTranslator = InventoryTranslator.INVENTORY_TRANSLATORS.get(packet.getType());
+ Inventory openInventory = session.getOpenInventory();
+ //No translator exists for this window type. Close all windows and return.
+ if (newTranslator == null) {
+ if (openInventory != null) {
+ InventoryUtils.closeInventory(session, openInventory.getId());
+ }
+ ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(packet.getWindowId());
+ session.sendDownstreamPacket(closeWindowPacket);
+ return;
+ }
+
+ String name = MessageTranslator.convertMessageLenient(packet.getName(), session.getLocale());
+ name = LocaleUtils.getLocaleString(name, session.getLocale());
+
+ Inventory newInventory = newTranslator.createInventory(name, packet.getWindowId(), packet.getType(), session.getPlayerInventory());
if (openInventory != null) {
- InventoryUtils.closeWindow(session, openInventory.getId());
- InventoryUtils.closeInventory(session, openInventory.getId());
+ InventoryTranslator openTranslator = InventoryTranslator.INVENTORY_TRANSLATORS.get(openInventory.getWindowType());
+ if (!openTranslator.getClass().equals(newTranslator.getClass())) {
+ InventoryUtils.closeInventory(session, openInventory.getId());
+ }
}
- ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(packet.getWindowId());
- session.sendDownstreamPacket(closeWindowPacket);
- return;
- }
- String name = MessageTranslator.convertMessageLenient(packet.getName(), session.getLocale());
-
- name = LocaleUtils.getLocaleString(name, session.getLocale());
-
- Inventory newInventory = new Inventory(name, packet.getWindowId(), packet.getType(), newTranslator.size + 36);
- session.getInventoryCache().cacheInventory(newInventory);
- if (openInventory != null) {
- InventoryTranslator openTranslator = InventoryTranslator.INVENTORY_TRANSLATORS.get(openInventory.getWindowType());
- if (!openTranslator.getClass().equals(newTranslator.getClass())) {
- InventoryUtils.closeWindow(session, openInventory.getId());
- InventoryUtils.closeInventory(session, openInventory.getId());
- }
- }
-
- InventoryUtils.openInventory(session, newInventory);
+ InventoryUtils.openInventory(session, newInventory);
+ });
}
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java
index 3a2790028..22a0edcac 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java
@@ -26,6 +26,8 @@
package org.geysermc.connector.network.translators.java.window;
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerSetSlotPacket;
+import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
+import org.geysermc.connector.inventory.GeyserItemStack;
import org.geysermc.connector.inventory.Inventory;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
@@ -38,23 +40,39 @@ public class JavaSetSlotTranslator extends PacketTranslator
@Override
public void translate(ServerSetSlotPacket packet, GeyserSession session) {
- if (packet.getWindowId() == 255 && packet.getSlot() == -1) { //cursor
- if (session.getCraftSlot() != 0)
+ session.addInventoryTask(() -> {
+ if (packet.getWindowId() == 255) { //cursor
+ GeyserItemStack newItem = GeyserItemStack.from(packet.getItem());
+ GeyserItemStack oldItem = session.getPlayerInventory().getCursor();
+ if (newItem.getItemData(session).equals(oldItem.getItemData(session))) {
+ newItem.setNetId(oldItem.getNetId());
+ } else {
+ newItem.setNetId(session.getItemNetId().getAndIncrement());
+ }
+ session.getPlayerInventory().setCursor(newItem);
+ InventoryUtils.updateCursor(session);
+ return;
+ }
+
+ //TODO: support window id -2, should update player inventory
+ Inventory inventory = InventoryUtils.getInventory(session, packet.getWindowId());
+ if (inventory == null)
return;
- session.getInventory().setCursor(packet.getItem());
- InventoryUtils.updateCursor(session);
- return;
- }
-
- Inventory inventory = session.getInventoryCache().getInventories().get(packet.getWindowId());
- if (inventory == null || (packet.getWindowId() != 0 && inventory.getWindowType() == null))
- return;
-
- InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
- if (translator != null) {
- inventory.setItem(packet.getSlot(), packet.getItem());
- translator.updateSlot(session, inventory, packet.getSlot());
- }
+ InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
+ if (translator != null) {
+ GeyserItemStack newItem = GeyserItemStack.from(packet.getItem());
+ GeyserItemStack oldItem = inventory.getItem(packet.getSlot());
+ if (newItem.getItemData(session).equals(oldItem.getItemData(session), false, false, false)) {
+ newItem.setNetId(oldItem.getNetId());
+ System.out.println("OLD: " + newItem.getNetId());
+ } else {
+ newItem.setNetId(session.getItemNetId().getAndIncrement());
+ System.out.println("NEW: " + newItem.getNetId());
+ }
+ inventory.setItem(packet.getSlot(), newItem);
+ translator.updateSlot(session, inventory, packet.getSlot());
+ }
+ });
}
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java
index 2cc392f53..26aab47b3 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java
@@ -26,32 +26,40 @@
package org.geysermc.connector.network.translators.java.window;
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerWindowItemsPacket;
+import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
+import org.geysermc.connector.inventory.GeyserItemStack;
import org.geysermc.connector.inventory.Inventory;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
-
-import java.util.Arrays;
+import org.geysermc.connector.utils.InventoryUtils;
@Translator(packet = ServerWindowItemsPacket.class)
public class JavaWindowItemsTranslator extends PacketTranslator {
@Override
public void translate(ServerWindowItemsPacket packet, GeyserSession session) {
- Inventory inventory = session.getInventoryCache().getInventories().get(packet.getWindowId());
- if (inventory == null || (packet.getWindowId() != 0 && inventory.getWindowType() == null))
- return;
+ session.addInventoryTask(() -> {
+ Inventory inventory = InventoryUtils.getInventory(session, packet.getWindowId());
+ if (inventory == null)
+ return;
- if (packet.getItems().length < inventory.getSize()) {
- inventory.setItems(Arrays.copyOf(packet.getItems(), inventory.getSize()));
- } else {
- inventory.setItems(packet.getItems());
- }
+ for (int i = 0; i < packet.getItems().length; i++) {
+ GeyserItemStack newItem = GeyserItemStack.from(packet.getItems()[i]);
+ GeyserItemStack oldItem = inventory.getItem(i);
+ if (newItem.getItemData(session).equals(oldItem.getItemData(session), false, false, false)) {
+ newItem.setNetId(oldItem.getNetId());
+ } else {
+ newItem.setNetId(session.getItemNetId().getAndIncrement());
+ }
+ inventory.setItem(i, newItem);
+ }
- InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
- if (translator != null) {
- translator.updateInventory(session, inventory);
- }
+ InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
+ if (translator != null) {
+ translator.updateInventory(session, inventory);
+ }
+ });
}
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java
index daebed1b6..97c4708ff 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java
@@ -31,19 +31,22 @@ import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
+import org.geysermc.connector.utils.InventoryUtils;
@Translator(packet = ServerWindowPropertyPacket.class)
public class JavaWindowPropertyTranslator extends PacketTranslator {
@Override
public void translate(ServerWindowPropertyPacket packet, GeyserSession session) {
- Inventory inventory = session.getInventoryCache().getInventories().get(packet.getWindowId());
- if (inventory == null || (packet.getWindowId() != 0 && inventory.getWindowType() == null))
- return;
+ session.addInventoryTask(() -> {
+ Inventory inventory = InventoryUtils.getInventory(session, packet.getWindowId());
+ if (inventory == null)
+ return;
- InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
- if (translator != null) {
- translator.updateProperty(session, inventory, packet.getRawProperty(), packet.getValue());
- }
+ InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
+ if (translator != null) {
+ translator.updateProperty(session, inventory, packet.getRawProperty(), packet.getValue());
+ }
+ });
}
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java
index 8710c47ba..44c1ad9b5 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java
@@ -111,7 +111,7 @@ public class JavaNotifyClientTranslator extends PacketTranslator tags = new ArrayList<>();
- for (VillagerTrade trade : packet.getTrades()) {
+ for (int i = 0; i < packet.getTrades().length; i++) {
+ VillagerTrade trade = packet.getTrades()[i];
NbtMapBuilder recipe = NbtMap.builder();
- recipe.putInt("maxUses", trade.getMaxUses());
+ recipe.putInt("netId", i + 1);
+ recipe.putInt("maxUses", trade.isTradeDisabled() ? 0 : trade.getMaxUses());
recipe.putInt("traderExp", trade.getXp());
recipe.putFloat("priceMultiplierA", trade.getPriceMultiplier());
recipe.put("sell", getItemTag(session, trade.getOutput(), 0));
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/sound/BlockSoundInteractionHandler.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/BlockSoundInteractionHandler.java
index f3dff0cc2..ab73e6028 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/sound/BlockSoundInteractionHandler.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/sound/BlockSoundInteractionHandler.java
@@ -27,6 +27,7 @@ package org.geysermc.connector.network.translators.sound;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import com.nukkitx.math.vector.Vector3f;
+import org.geysermc.connector.inventory.GeyserItemStack;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.item.ItemRegistry;
@@ -60,12 +61,12 @@ public interface BlockSoundInteractionHandler extends SoundInteractionHandler 500) {
- ContainerClosePacket closePacket = new ContainerClosePacket();
- closePacket.setId((byte) windowId);
- session.sendUpstreamPacket(closePacket);
+ Inventory inventory = getInventory(session, windowId);
+ if (inventory != null) {
+ InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
+ translator.closeInventory(session, inventory);
session.setLastWindowCloseTime(System.currentTimeMillis());
}
- */
+ session.setOpenInventory(null);
+ }
+
+ public static Inventory getInventory(GeyserSession session, int windowId) {
+ if (windowId == 0) {
+ return session.getPlayerInventory();
+ } else {
+ Inventory openInventory = session.getOpenInventory();
+ if (openInventory != null && windowId == openInventory.getId()) {
+ return openInventory;
+ }
+ return null;
+ }
}
public static void updateCursor(GeyserSession session) {
InventorySlotPacket cursorPacket = new InventorySlotPacket();
cursorPacket.setContainerId(ContainerId.UI);
cursorPacket.setSlot(0);
- cursorPacket.setItem(ItemTranslator.translateToBedrock(session, session.getInventory().getCursor()));
+ cursorPacket.setItem(session.getPlayerInventory().getCursor().getItemData(session));
session.sendUpstreamPacket(cursorPacket);
}
+ public static boolean canStack(GeyserItemStack item1, GeyserItemStack item2) {
+ if (item1.isEmpty() || item2.isEmpty())
+ return false;
+ return item1.getId() == item2.getId() && Objects.equals(item1.getNbt(), item2.getNbt());
+ }
+
public static boolean canStack(ItemStack item1, ItemStack item2) {
if (item1 == null || item2 == null)
return false;
@@ -170,19 +162,16 @@ public class InventoryUtils {
*/
public static void findOrCreatePickedBlock(GeyserSession session, String itemName) {
// Get the inventory to choose a slot to pick
- Inventory inventory = session.getInventoryCache().getOpenInventory();
- if (inventory == null) {
- inventory = session.getInventory();
- }
+ PlayerInventory inventory = session.getPlayerInventory();
// Check hotbar for item
for (int i = 36; i < 45; i++) {
- if (inventory.getItem(i) == null) {
+ GeyserItemStack geyserItem = inventory.getItem(i);
+ if (geyserItem.isEmpty()) {
continue;
}
- ItemEntry item = ItemRegistry.getItem(inventory.getItem(i));
// If this isn't the item we're looking for
- if (!item.getJavaIdentifier().equals(itemName)) {
+ if (!geyserItem.getItemEntry().getJavaIdentifier().equals(itemName)) {
continue;
}
@@ -193,12 +182,12 @@ public class InventoryUtils {
// Check inventory for item
for (int i = 9; i < 36; i++) {
- if (inventory.getItem(i) == null) {
+ GeyserItemStack geyserItem = inventory.getItem(i);
+ if (geyserItem.isEmpty()) {
continue;
}
- ItemEntry item = ItemRegistry.getItem(inventory.getItem(i));
// If this isn't the item we're looking for
- if (!item.getJavaIdentifier().equals(itemName)) {
+ if (!geyserItem.getItemEntry().getJavaIdentifier().equals(itemName)) {
continue;
}
@@ -209,10 +198,10 @@ public class InventoryUtils {
// If we still have not found the item, and we're in creative, ask for the item from the server.
if (session.getGameMode() == GameMode.CREATIVE) {
- int slot = session.getInventory().getHeldItemSlot() + 36;
- if (session.getInventory().getItemInHand() != null) { // Otherwise we should just use the current slot
+ int slot = inventory.getHeldItemSlot() + 36;
+ if (!inventory.getItemInHand().isEmpty()) { // Otherwise we should just use the current slot
for (int i = 36; i < 45; i++) {
- if (inventory.getItem(i) == null) {
+ if (inventory.getItem(i).isEmpty()) {
slot = i;
break;
}
@@ -221,7 +210,7 @@ public class InventoryUtils {
ClientCreativeInventoryActionPacket actionPacket = new ClientCreativeInventoryActionPacket(slot,
new ItemStack(ItemRegistry.getItemEntry(itemName).getJavaId()));
- if ((slot - 36) != session.getInventory().getHeldItemSlot()) {
+ if ((slot - 36) != inventory.getHeldItemSlot()) {
setHotbarItem(session, slot);
}
session.sendDownstreamPacket(actionPacket);