Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-11-08 17:20:20 +01:00
server inventory. WORK IN PROGRESS
wip commit of implementing server authoritative inventories. there is a lot of experimental and debug code. this is NOT ready for testing or review.
Dieser Commit ist enthalten in:
Ursprung
64f2233581
Commit
7f4b588cdf
@ -50,6 +50,7 @@ import org.geysermc.connector.entity.attribute.Attribute;
|
|||||||
import org.geysermc.connector.entity.attribute.AttributeType;
|
import org.geysermc.connector.entity.attribute.AttributeType;
|
||||||
import org.geysermc.connector.entity.living.ArmorStandEntity;
|
import org.geysermc.connector.entity.living.ArmorStandEntity;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
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.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||||
import org.geysermc.connector.utils.AttributeUtils;
|
import org.geysermc.connector.utils.AttributeUtils;
|
||||||
@ -288,11 +289,12 @@ public class Entity {
|
|||||||
|
|
||||||
// Shield code
|
// Shield code
|
||||||
if (session.getPlayerEntity().getEntityId() == entityId && metadata.getFlags().getFlag(EntityFlag.SNEAKING)) {
|
if (session.getPlayerEntity().getEntityId() == entityId && metadata.getFlags().getFlag(EntityFlag.SNEAKING)) {
|
||||||
if ((session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemRegistry.SHIELD.getJavaId()) ||
|
PlayerInventory playerInv = session.getPlayerInventory();
|
||||||
(session.getInventoryCache().getPlayerInventory().getItem(45) != null && session.getInventoryCache().getPlayerInventory().getItem(45).getId() == ItemRegistry.SHIELD.getJavaId())) {
|
if ((playerInv.getItemInHand().getId() == ItemRegistry.SHIELD.getJavaId()) ||
|
||||||
|
(playerInv.getOffhand().getId() == ItemRegistry.SHIELD.getJavaId())) {
|
||||||
ClientPlayerUseItemPacket useItemPacket;
|
ClientPlayerUseItemPacket useItemPacket;
|
||||||
metadata.getFlags().setFlag(EntityFlag.BLOCKING, true);
|
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);
|
useItemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
|
||||||
}
|
}
|
||||||
// Else we just assume it's the offhand, to simplify logic and to assure the packet gets sent
|
// Else we just assume it's the offhand, to simplify logic and to assure the packet gets sent
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -25,23 +25,19 @@
|
|||||||
|
|
||||||
package org.geysermc.connector.inventory;
|
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.github.steveice10.mc.protocol.data.game.window.WindowType;
|
||||||
import com.nukkitx.math.vector.Vector3i;
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.Arrays;
|
||||||
|
|
||||||
public class Inventory {
|
public class Inventory {
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
protected int id;
|
protected int id;
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
protected boolean open;
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
protected WindowType windowType;
|
protected WindowType windowType;
|
||||||
|
|
||||||
@ -52,8 +48,7 @@ public class Inventory {
|
|||||||
@Setter
|
@Setter
|
||||||
protected String title;
|
protected String title;
|
||||||
|
|
||||||
@Setter
|
protected GeyserItemStack[] items;
|
||||||
protected ItemStack[] items;
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@ -64,27 +59,30 @@ public class Inventory {
|
|||||||
protected long holderId = -1;
|
protected long holderId = -1;
|
||||||
|
|
||||||
@Getter
|
@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);
|
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.title = title;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.windowType = windowType;
|
this.windowType = windowType;
|
||||||
this.size = size;
|
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];
|
return items[slot];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setItem(int slot, ItemStack item) {
|
public void setItem(int slot, @NonNull GeyserItemStack item) {
|
||||||
if (item != null && (item.getId() == 0 || item.getAmount() < 1))
|
|
||||||
item = null;
|
|
||||||
items[slot] = item;
|
items[slot] = item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public short getNextTransactionId() {
|
||||||
|
return ++transactionId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -25,8 +25,8 @@
|
|||||||
|
|
||||||
package org.geysermc.connector.inventory;
|
package org.geysermc.connector.inventory;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
public class PlayerInventory extends Inventory {
|
public class PlayerInventory extends Inventory {
|
||||||
@ -40,20 +40,24 @@ public class PlayerInventory extends Inventory {
|
|||||||
private int heldItemSlot;
|
private int heldItemSlot;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private ItemStack cursor;
|
@Setter
|
||||||
|
@NonNull
|
||||||
|
private GeyserItemStack cursor = GeyserItemStack.EMPTY;
|
||||||
|
|
||||||
public PlayerInventory() {
|
public PlayerInventory() {
|
||||||
super(0, null, 46);
|
super(0, null, 46);
|
||||||
heldItemSlot = 0;
|
heldItemSlot = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCursor(ItemStack stack) {
|
public GeyserItemStack getItemInHand() {
|
||||||
if (stack != null && (stack.getId() == 0 || stack.getAmount() < 1))
|
|
||||||
stack = null;
|
|
||||||
cursor = stack;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ItemStack getItemInHand() {
|
|
||||||
return items[36 + heldItemSlot];
|
return items[36 + heldItemSlot];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setItemInHand(@NonNull GeyserItemStack item) {
|
||||||
|
items[36 + heldItemSlot] = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GeyserItemStack getOffhand() {
|
||||||
|
return items[45];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ import com.github.steveice10.mc.protocol.MinecraftConstants;
|
|||||||
import com.github.steveice10.mc.protocol.MinecraftProtocol;
|
import com.github.steveice10.mc.protocol.MinecraftProtocol;
|
||||||
import com.github.steveice10.mc.protocol.data.SubProtocol;
|
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.entity.player.GameMode;
|
||||||
|
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.data.game.window.VillagerTrade;
|
||||||
import com.github.steveice10.mc.protocol.data.message.MessageSerializer;
|
import com.github.steveice10.mc.protocol.data.message.MessageSerializer;
|
||||||
import com.github.steveice10.mc.protocol.packet.handshake.client.HandshakePacket;
|
import com.github.steveice10.mc.protocol.packet.handshake.client.HandshakePacket;
|
||||||
@ -49,11 +50,14 @@ import com.nukkitx.protocol.bedrock.BedrockServerSession;
|
|||||||
import com.nukkitx.protocol.bedrock.data.*;
|
import com.nukkitx.protocol.bedrock.data.*;
|
||||||
import com.nukkitx.protocol.bedrock.data.command.CommandPermission;
|
import com.nukkitx.protocol.bedrock.data.command.CommandPermission;
|
||||||
import com.nukkitx.protocol.bedrock.packet.*;
|
import com.nukkitx.protocol.bedrock.packet.*;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMaps;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMaps;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2LongMap;
|
import it.unimi.dsi.fastutil.objects.Object2LongMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
|
||||||
|
import lombok.AccessLevel;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.geysermc.common.window.CustomFormWindow;
|
import org.geysermc.common.window.CustomFormWindow;
|
||||||
@ -63,6 +67,7 @@ import org.geysermc.connector.command.CommandSender;
|
|||||||
import org.geysermc.connector.common.AuthType;
|
import org.geysermc.connector.common.AuthType;
|
||||||
import org.geysermc.connector.entity.Entity;
|
import org.geysermc.connector.entity.Entity;
|
||||||
import org.geysermc.connector.entity.PlayerEntity;
|
import org.geysermc.connector.entity.PlayerEntity;
|
||||||
|
import org.geysermc.connector.inventory.Inventory;
|
||||||
import org.geysermc.connector.inventory.PlayerInventory;
|
import org.geysermc.connector.inventory.PlayerInventory;
|
||||||
import org.geysermc.connector.network.remote.RemoteServer;
|
import org.geysermc.connector.network.remote.RemoteServer;
|
||||||
import org.geysermc.connector.network.session.auth.AuthData;
|
import org.geysermc.connector.network.session.auth.AuthData;
|
||||||
@ -71,7 +76,6 @@ import org.geysermc.connector.network.session.cache.*;
|
|||||||
import org.geysermc.connector.network.translators.BiomeTranslator;
|
import org.geysermc.connector.network.translators.BiomeTranslator;
|
||||||
import org.geysermc.connector.network.translators.EntityIdentifierRegistry;
|
import org.geysermc.connector.network.translators.EntityIdentifierRegistry;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
|
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
|
||||||
import org.geysermc.connector.network.translators.inventory.EnchantmentInventoryTranslator;
|
|
||||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
import org.geysermc.connector.utils.*;
|
import org.geysermc.connector.utils.*;
|
||||||
@ -83,6 +87,12 @@ import java.net.InetSocketAddress;
|
|||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.security.spec.InvalidKeySpecException;
|
import java.security.spec.InvalidKeySpecException;
|
||||||
|
import java.util.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.*;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
@ -100,11 +110,20 @@ public class GeyserSession implements CommandSender {
|
|||||||
private BedrockClientData clientData;
|
private BedrockClientData clientData;
|
||||||
|
|
||||||
private PlayerEntity playerEntity;
|
private PlayerEntity playerEntity;
|
||||||
private PlayerInventory inventory;
|
|
||||||
|
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<Void> inventoryFuture;
|
||||||
|
|
||||||
private ChunkCache chunkCache;
|
private ChunkCache chunkCache;
|
||||||
private EntityCache entityCache;
|
private EntityCache entityCache;
|
||||||
private InventoryCache inventoryCache;
|
|
||||||
private WorldCache worldCache;
|
private WorldCache worldCache;
|
||||||
private WindowCache windowCache;
|
private WindowCache windowCache;
|
||||||
@Setter
|
@Setter
|
||||||
@ -170,9 +189,6 @@ public class GeyserSession implements CommandSender {
|
|||||||
@Setter
|
@Setter
|
||||||
private Entity ridingVehicleEntity;
|
private Entity ridingVehicleEntity;
|
||||||
|
|
||||||
@Setter
|
|
||||||
private int craftSlot = 0;
|
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private long lastWindowCloseTime = 0;
|
private long lastWindowCloseTime = 0;
|
||||||
|
|
||||||
@ -187,10 +203,8 @@ public class GeyserSession implements CommandSender {
|
|||||||
@Setter
|
@Setter
|
||||||
private long lastInteractedVillagerEid;
|
private long lastInteractedVillagerEid;
|
||||||
|
|
||||||
/**
|
@Setter
|
||||||
* Stores the enchantment information the client has received if they are in an enchantment table GUI
|
private Int2ObjectMap<Recipe> craftingRecipes;
|
||||||
*/
|
|
||||||
private final EnchantmentInventoryTranslator.EnchantmentSlotData[] enchantmentSlotData = new EnchantmentInventoryTranslator.EnchantmentSlotData[3];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current attack speed of the player. Used for sending proper cooldown timings.
|
* The current attack speed of the player. Used for sending proper cooldown timings.
|
||||||
@ -282,18 +296,19 @@ public class GeyserSession implements CommandSender {
|
|||||||
|
|
||||||
this.chunkCache = new ChunkCache(this);
|
this.chunkCache = new ChunkCache(this);
|
||||||
this.entityCache = new EntityCache(this);
|
this.entityCache = new EntityCache(this);
|
||||||
this.inventoryCache = new InventoryCache(this);
|
|
||||||
this.worldCache = new WorldCache(this);
|
this.worldCache = new WorldCache(this);
|
||||||
this.windowCache = new WindowCache(this);
|
this.windowCache = new WindowCache(this);
|
||||||
|
|
||||||
this.playerEntity = new PlayerEntity(new GameProfile(UUID.randomUUID(), "unknown"), 1, 1, Vector3f.ZERO, Vector3f.ZERO, Vector3f.ZERO);
|
this.playerEntity = new PlayerEntity(new GameProfile(UUID.randomUUID(), "unknown"), 1, 1, Vector3f.ZERO, Vector3f.ZERO, Vector3f.ZERO);
|
||||||
this.inventory = new PlayerInventory();
|
|
||||||
|
this.playerInventory = new PlayerInventory();
|
||||||
|
this.openInventory = null;
|
||||||
|
this.inventoryFuture = CompletableFuture.completedFuture(null);
|
||||||
|
this.craftingRecipes = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
this.spawned = false;
|
this.spawned = false;
|
||||||
this.loggedIn = false;
|
this.loggedIn = false;
|
||||||
|
|
||||||
this.inventoryCache.getInventories().put(0, inventory);
|
|
||||||
|
|
||||||
bedrockServerSession.addDisconnectHandler(disconnectReason -> {
|
bedrockServerSession.addDisconnectHandler(disconnectReason -> {
|
||||||
connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.disconnect", bedrockServerSession.getAddress().getAddress(), disconnectReason));
|
connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.disconnect", bedrockServerSession.getAddress().getAddress(), disconnectReason));
|
||||||
|
|
||||||
@ -529,7 +544,6 @@ public class GeyserSession implements CommandSender {
|
|||||||
this.chunkCache = null;
|
this.chunkCache = null;
|
||||||
this.entityCache = null;
|
this.entityCache = null;
|
||||||
this.worldCache = null;
|
this.worldCache = null;
|
||||||
this.inventoryCache = null;
|
|
||||||
this.windowCache = null;
|
this.windowCache = null;
|
||||||
|
|
||||||
closed = true;
|
closed = true;
|
||||||
@ -638,10 +652,47 @@ public class GeyserSession implements CommandSender {
|
|||||||
startGamePacket.setBlockPalette(BlockTranslator.BLOCKS);
|
startGamePacket.setBlockPalette(BlockTranslator.BLOCKS);
|
||||||
startGamePacket.setItemEntries(ItemRegistry.ITEMS);
|
startGamePacket.setItemEntries(ItemRegistry.ITEMS);
|
||||||
startGamePacket.setVanillaVersion("*");
|
startGamePacket.setVanillaVersion("*");
|
||||||
|
// startGamePacket.setMovementServerAuthoritative(true);
|
||||||
|
startGamePacket.setInventoriesServerAuthoritative(true);
|
||||||
startGamePacket.setAuthoritativeMovementMode(AuthoritativeMovementMode.CLIENT);
|
startGamePacket.setAuthoritativeMovementMode(AuthoritativeMovementMode.CLIENT);
|
||||||
upstream.sendPacket(startGamePacket);
|
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 boolean confirmTeleport(Vector3d position) {
|
public boolean confirmTeleport(Vector3d position) {
|
||||||
if (teleportCache != null) {
|
if (teleportCache != null) {
|
||||||
if (!teleportCache.canConfirm(position)) {
|
if (!teleportCache.canConfirm(position)) {
|
||||||
|
@ -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<Inventory> 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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -38,18 +38,17 @@ public class BedrockContainerCloseTranslator extends PacketTranslator<ContainerC
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ContainerClosePacket packet, GeyserSession session) {
|
public void translate(ContainerClosePacket packet, GeyserSession session) {
|
||||||
|
session.addInventoryTask(() -> {
|
||||||
session.setLastWindowCloseTime(0);
|
session.setLastWindowCloseTime(0);
|
||||||
byte windowId = packet.getId();
|
byte windowId = packet.getId();
|
||||||
Inventory openInventory = session.getInventoryCache().getOpenInventory();
|
|
||||||
if (windowId == -1) { //player inventory or crafting table
|
if (windowId == -1 && session.getOpenInventory() != null) {
|
||||||
if (openInventory != null) {
|
windowId = (byte) session.getOpenInventory().getId();
|
||||||
windowId = (byte) openInventory.getId();
|
|
||||||
} else {
|
|
||||||
windowId = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (windowId == 0 || (openInventory != null && openInventory.getId() == windowId)) {
|
Inventory openInventory = session.getOpenInventory();
|
||||||
|
if (openInventory != null && windowId == openInventory.getId()) {
|
||||||
|
System.out.println(packet);
|
||||||
ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(windowId);
|
ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(windowId);
|
||||||
session.getDownstream().getSession().send(closeWindowPacket);
|
session.getDownstream().getSession().send(closeWindowPacket);
|
||||||
InventoryUtils.closeInventory(session, windowId);
|
InventoryUtils.closeInventory(session, windowId);
|
||||||
@ -57,5 +56,6 @@ public class BedrockContainerCloseTranslator extends PacketTranslator<ContainerC
|
|||||||
|
|
||||||
//Client wants close confirmation
|
//Client wants close confirmation
|
||||||
session.sendUpstreamPacket(packet);
|
session.sendUpstreamPacket(packet);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
package org.geysermc.connector.network.translators.bedrock;
|
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.metadata.Position;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
|
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
|
||||||
@ -43,23 +42,23 @@ import com.nukkitx.protocol.bedrock.data.inventory.ContainerId;
|
|||||||
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
|
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
|
||||||
import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
|
import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
|
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.InventoryTransactionPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
||||||
import org.geysermc.connector.entity.CommandBlockMinecartEntity;
|
import org.geysermc.connector.entity.CommandBlockMinecartEntity;
|
||||||
import org.geysermc.connector.entity.Entity;
|
import org.geysermc.connector.entity.Entity;
|
||||||
import org.geysermc.connector.entity.ItemFrameEntity;
|
import org.geysermc.connector.entity.ItemFrameEntity;
|
||||||
import org.geysermc.connector.entity.living.merchant.AbstractMerchantEntity;
|
import org.geysermc.connector.entity.living.merchant.AbstractMerchantEntity;
|
||||||
import org.geysermc.connector.inventory.Inventory;
|
import org.geysermc.connector.inventory.GeyserItemStack;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
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.ItemEntry;
|
||||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||||
import org.geysermc.connector.network.translators.sound.EntitySoundInteractionHandler;
|
import org.geysermc.connector.network.translators.sound.EntitySoundInteractionHandler;
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
import org.geysermc.connector.utils.BlockUtils;
|
import org.geysermc.connector.utils.BlockUtils;
|
||||||
import org.geysermc.connector.utils.InventoryUtils;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@ -70,15 +69,36 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||||||
public void translate(InventoryTransactionPacket packet, GeyserSession session) {
|
public void translate(InventoryTransactionPacket packet, GeyserSession session) {
|
||||||
switch (packet.getTransactionType()) {
|
switch (packet.getTransactionType()) {
|
||||||
case NORMAL:
|
case NORMAL:
|
||||||
Inventory inventory = session.getInventoryCache().getOpenInventory();
|
System.out.println(packet);
|
||||||
if (inventory == null) inventory = session.getInventory();
|
if (packet.getActions().size() == 2) {
|
||||||
InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType()).translateActions(session, inventory, packet.getActions());
|
InventoryActionData worldAction = packet.getActions().get(0);
|
||||||
|
InventoryActionData containerAction = packet.getActions().get(1);
|
||||||
|
if (worldAction.getSource().getType() == InventorySource.Type.WORLD_INTERACTION
|
||||||
|
&& worldAction.getSource().getFlag() == InventorySource.Flag.DROP_ITEM) {
|
||||||
|
session.addInventoryTask(() -> {
|
||||||
|
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;
|
break;
|
||||||
case INVENTORY_MISMATCH:
|
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;
|
break;
|
||||||
case ITEM_USE:
|
case ITEM_USE:
|
||||||
switch (packet.getActionType()) {
|
switch (packet.getActionType()) {
|
||||||
@ -164,9 +184,8 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||||||
session.setInteracting(true);
|
session.setInteracting(true);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
ItemStack shieldSlot = session.getInventory().getItem(session.getInventory().getHeldItemSlot() + 36);
|
|
||||||
// Handled in Entity.java
|
// Handled in Entity.java
|
||||||
if (shieldSlot != null && shieldSlot.getId() == ItemRegistry.SHIELD.getJavaId()) {
|
if (session.getPlayerInventory().getItemInHand().getId() == ItemRegistry.SHIELD.getJavaId()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* 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.bedrock;
|
||||||
|
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.ItemStackRequestPacket;
|
||||||
|
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 org.geysermc.connector.utils.InventoryUtils;
|
||||||
|
|
||||||
|
@Translator(packet = ItemStackRequestPacket.class)
|
||||||
|
public class BedrockItemStackRequestTranslator extends PacketTranslator<ItemStackRequestPacket> {
|
||||||
|
|
||||||
|
@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()));
|
||||||
|
}
|
||||||
|
}
|
@ -40,12 +40,12 @@ public class BedrockMobEquipmentTranslator extends PacketTranslator<MobEquipment
|
|||||||
@Override
|
@Override
|
||||||
public void translate(MobEquipmentPacket packet, GeyserSession session) {
|
public void translate(MobEquipmentPacket packet, GeyserSession session) {
|
||||||
if (!session.isSpawned() || packet.getHotbarSlot() > 8 ||
|
if (!session.isSpawned() || packet.getHotbarSlot() > 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
|
// 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
session.getInventory().setHeldItemSlot(packet.getHotbarSlot());
|
session.getPlayerInventory().setHeldItemSlot(packet.getHotbarSlot());
|
||||||
|
|
||||||
ClientPlayerChangeHeldItemPacket changeHeldItemPacket = new ClientPlayerChangeHeldItemPacket(packet.getHotbarSlot());
|
ClientPlayerChangeHeldItemPacket changeHeldItemPacket = new ClientPlayerChangeHeldItemPacket(packet.getHotbarSlot());
|
||||||
session.sendDownstreamPacket(changeHeldItemPacket);
|
session.sendDownstreamPacket(changeHeldItemPacket);
|
||||||
|
@ -26,12 +26,13 @@
|
|||||||
package org.geysermc.connector.network.translators.bedrock.entity;
|
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.VillagerTrade;
|
||||||
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
|
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientSelectTradePacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientSelectTradePacket;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
|
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
|
||||||
import org.geysermc.connector.entity.Entity;
|
import org.geysermc.connector.entity.Entity;
|
||||||
|
import org.geysermc.connector.inventory.GeyserItemStack;
|
||||||
import org.geysermc.connector.inventory.Inventory;
|
import org.geysermc.connector.inventory.Inventory;
|
||||||
|
import org.geysermc.connector.inventory.MerchantContainer;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
@ -47,20 +48,25 @@ public class BedrockEntityEventTranslator extends PacketTranslator<EntityEventPa
|
|||||||
session.sendUpstreamPacket(packet);
|
session.sendUpstreamPacket(packet);
|
||||||
return;
|
return;
|
||||||
case COMPLETE_TRADE:
|
case COMPLETE_TRADE:
|
||||||
|
session.addInventoryTask(() -> {
|
||||||
ClientSelectTradePacket selectTradePacket = new ClientSelectTradePacket(packet.getData());
|
ClientSelectTradePacket selectTradePacket = new ClientSelectTradePacket(packet.getData());
|
||||||
session.getDownstream().getSession().send(selectTradePacket);
|
session.getDownstream().getSession().send(selectTradePacket);
|
||||||
|
});
|
||||||
|
|
||||||
|
session.addInventoryTask(() -> {
|
||||||
Entity villager = session.getPlayerEntity();
|
Entity villager = session.getPlayerEntity();
|
||||||
Inventory openInventory = session.getInventoryCache().getOpenInventory();
|
Inventory openInventory = session.getOpenInventory();
|
||||||
if (openInventory != null && openInventory.getWindowType() == WindowType.MERCHANT) {
|
if (openInventory instanceof MerchantContainer) {
|
||||||
VillagerTrade[] trades = session.getVillagerTrades();
|
MerchantContainer merchantInventory = (MerchantContainer) openInventory;
|
||||||
|
VillagerTrade[] trades = merchantInventory.getVillagerTrades();
|
||||||
if (trades != null && packet.getData() >= 0 && packet.getData() < trades.length) {
|
if (trades != null && packet.getData() >= 0 && packet.getData() < trades.length) {
|
||||||
VillagerTrade trade = session.getVillagerTrades()[packet.getData()];
|
VillagerTrade trade = merchantInventory.getVillagerTrades()[packet.getData()];
|
||||||
openInventory.setItem(2, trade.getOutput());
|
openInventory.setItem(2, GeyserItemStack.from(trade.getOutput()));
|
||||||
villager.getMetadata().put(EntityData.TRADE_XP, trade.getXp() + villager.getMetadata().getInt(EntityData.TRADE_XP));
|
villager.getMetadata().put(EntityData.TRADE_XP, trade.getXp() + villager.getMetadata().getInt(EntityData.TRADE_XP));
|
||||||
villager.updateBedrockMetadata(session);
|
villager.updateBedrockMetadata(session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}, 100);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
session.getConnector().getLogger().debug("Did not translate incoming EntityEventPacket: " + packet.toString());
|
session.getConnector().getLogger().debug("Did not translate incoming EntityEventPacket: " + packet.toString());
|
||||||
|
@ -60,7 +60,7 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket>
|
|||||||
|
|
||||||
switch (packet.getAction()) {
|
switch (packet.getAction()) {
|
||||||
case INTERACT:
|
case INTERACT:
|
||||||
if (session.getInventory().getItem(session.getInventory().getHeldItemSlot() + 36).getId() == ItemRegistry.SHIELD.getJavaId()) {
|
if (session.getPlayerInventory().getItemInHand().getId() == ItemRegistry.SHIELD.getJavaId()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
|
ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
|
||||||
@ -135,14 +135,15 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket>
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OPEN_INVENTORY:
|
case OPEN_INVENTORY:
|
||||||
if (!session.getInventory().isOpen()) {
|
if (session.getOpenInventory() == null) {
|
||||||
|
session.setOpenInventory(session.getPlayerInventory());
|
||||||
|
|
||||||
ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket();
|
ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket();
|
||||||
containerOpenPacket.setId((byte) 0);
|
containerOpenPacket.setId((byte) 0);
|
||||||
containerOpenPacket.setType(ContainerType.INVENTORY);
|
containerOpenPacket.setType(ContainerType.INVENTORY);
|
||||||
containerOpenPacket.setUniqueEntityId(-1);
|
containerOpenPacket.setUniqueEntityId(-1);
|
||||||
containerOpenPacket.setBlockPosition(entity.getPosition().toInt());
|
containerOpenPacket.setBlockPosition(entity.getPosition().toInt());
|
||||||
session.sendUpstreamPacket(containerOpenPacket);
|
session.sendUpstreamPacket(containerOpenPacket);
|
||||||
session.getInventory().setOpen(true);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -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<InventoryActionData> 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<InventoryActionData> 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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -25,15 +25,15 @@
|
|||||||
|
|
||||||
package org.geysermc.connector.network.translators.inventory;
|
package org.geysermc.connector.network.translators.inventory;
|
||||||
|
|
||||||
import com.nukkitx.protocol.bedrock.data.inventory.ContainerId;
|
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
|
||||||
import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData;
|
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.Inventory;
|
||||||
|
import org.geysermc.connector.inventory.PlayerInventory;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
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) {
|
BaseInventoryTranslator(int size) {
|
||||||
super(size);
|
super(size);
|
||||||
}
|
}
|
||||||
@ -44,9 +44,12 @@ public abstract class BaseInventoryTranslator extends InventoryTranslator{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int bedrockSlotToJava(InventoryActionData action) {
|
public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
|
||||||
int slotnum = action.getSlot();
|
int slotnum = slotInfoData.getSlot();
|
||||||
if (action.getSource().getContainerId() == ContainerId.INVENTORY) {
|
switch (slotInfoData.getContainer()) {
|
||||||
|
case HOTBAR_AND_INVENTORY:
|
||||||
|
case HOTBAR:
|
||||||
|
case INVENTORY:
|
||||||
//hotbar
|
//hotbar
|
||||||
if (slotnum >= 9) {
|
if (slotnum >= 9) {
|
||||||
return slotnum + this.size - 9;
|
return slotnum + this.size - 9;
|
||||||
@ -70,13 +73,26 @@ public abstract class BaseInventoryTranslator extends InventoryTranslator{
|
|||||||
return slot;
|
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
|
@Override
|
||||||
public SlotType getSlotType(int javaSlot) {
|
public SlotType getSlotType(int javaSlot) {
|
||||||
return SlotType.NORMAL;
|
return SlotType.NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translateActions(GeyserSession session, Inventory inventory, List<InventoryActionData> actions) {
|
public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) {
|
||||||
InventoryActionDataTranslator.translate(this, session, inventory, actions);
|
return new Container(name, windowId, windowType, this.size, playerInventory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -25,14 +25,11 @@
|
|||||||
|
|
||||||
package org.geysermc.connector.network.translators.inventory;
|
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.inventory.Inventory;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.inventory.updater.ChestInventoryUpdater;
|
import org.geysermc.connector.network.translators.inventory.updater.ChestInventoryUpdater;
|
||||||
import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
|
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 {
|
public abstract class ChestInventoryTranslator extends BaseInventoryTranslator {
|
||||||
private final InventoryUpdater updater;
|
private final InventoryUpdater updater;
|
||||||
@ -53,17 +50,10 @@ public abstract class ChestInventoryTranslator extends BaseInventoryTranslator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translateActions(GeyserSession session, Inventory inventory, List<InventoryActionData> actions) {
|
public BedrockContainerSlot javaSlotToBedrockContainer(int javaSlot) {
|
||||||
for (InventoryActionData action : actions) {
|
if (javaSlot < this.size) {
|
||||||
if (action.getSource().getContainerId() == inventory.getId()) {
|
return new BedrockContainerSlot(ContainerSlotType.CONTAINER, javaSlot);
|
||||||
if (action.getSlot() >= size) {
|
|
||||||
updateInventory(session, inventory);
|
|
||||||
InventoryUtils.updateCursor(session);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
return super.javaSlotToBedrockContainer(javaSlot);
|
||||||
}
|
|
||||||
|
|
||||||
super.translateActions(session, inventory, actions);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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<InventoryActionData> 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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,267 +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.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 = 351;
|
|
||||||
private static final short LAPIS_DAMAGE = 4;
|
|
||||||
private static final int ENCHANTED_BOOK_ID = 403;
|
|
||||||
|
|
||||||
public EnchantmentInventoryTranslator(InventoryUpdater updater) {
|
|
||||||
super(2, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, updater);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void translateActions(GeyserSession session, Inventory inventory, List<InventoryActionData> 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().getDamage() != LAPIS_DAMAGE) && 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.getClientData().getLanguageCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.getClientData().getLanguageCode());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -25,18 +25,26 @@
|
|||||||
|
|
||||||
package org.geysermc.connector.network.translators.inventory;
|
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.github.steveice10.mc.protocol.data.game.window.WindowType;
|
||||||
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
|
import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCreativeInventoryActionPacket;
|
||||||
import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData;
|
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 lombok.AllArgsConstructor;
|
||||||
|
import org.geysermc.connector.inventory.GeyserItemStack;
|
||||||
import org.geysermc.connector.inventory.Inventory;
|
import org.geysermc.connector.inventory.Inventory;
|
||||||
|
import org.geysermc.connector.inventory.PlayerInventory;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater;
|
import org.geysermc.connector.network.translators.inventory.click.Click;
|
||||||
import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
|
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.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public abstract class InventoryTranslator {
|
public abstract class InventoryTranslator {
|
||||||
@ -50,12 +58,13 @@ public abstract class InventoryTranslator {
|
|||||||
put(WindowType.GENERIC_9X4, new DoubleChestInventoryTranslator(36));
|
put(WindowType.GENERIC_9X4, new DoubleChestInventoryTranslator(36));
|
||||||
put(WindowType.GENERIC_9X5, new DoubleChestInventoryTranslator(45));
|
put(WindowType.GENERIC_9X5, new DoubleChestInventoryTranslator(45));
|
||||||
put(WindowType.GENERIC_9X6, new DoubleChestInventoryTranslator(54));
|
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.ANVIL, new AnvilInventoryTranslator());
|
||||||
put(WindowType.CRAFTING, new CraftingInventoryTranslator());
|
put(WindowType.CRAFTING, new CraftingInventoryTranslator());
|
||||||
put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator());
|
put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator());*/
|
||||||
put(WindowType.MERCHANT, new MerchantInventoryTranslator());
|
put(WindowType.MERCHANT, new MerchantInventoryTranslator());
|
||||||
put(WindowType.SMITHING, new SmithingInventoryTranslator());
|
/*put(WindowType.SMITHING, new SmithingInventoryTranslator());
|
||||||
|
//put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator()); //TODO
|
||||||
|
|
||||||
InventoryTranslator furnace = new FurnaceInventoryTranslator();
|
InventoryTranslator furnace = new FurnaceInventoryTranslator();
|
||||||
put(WindowType.FURNACE, furnace);
|
put(WindowType.FURNACE, furnace);
|
||||||
@ -63,14 +72,15 @@ public abstract class InventoryTranslator {
|
|||||||
put(WindowType.SMOKER, furnace);
|
put(WindowType.SMOKER, furnace);
|
||||||
|
|
||||||
InventoryUpdater containerUpdater = new ContainerInventoryUpdater();
|
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.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.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.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 final int size;
|
||||||
|
|
||||||
public abstract void prepareInventory(GeyserSession session, Inventory inventory);
|
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 updateProperty(GeyserSession session, Inventory inventory, int key, int value);
|
||||||
public abstract void updateInventory(GeyserSession session, Inventory inventory);
|
public abstract void updateInventory(GeyserSession session, Inventory inventory);
|
||||||
public abstract void updateSlot(GeyserSession session, Inventory inventory, int slot);
|
public abstract void updateSlot(GeyserSession session, Inventory inventory, int slot);
|
||||||
public abstract int bedrockSlotToJava(InventoryActionData action);
|
public abstract int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData);
|
||||||
public abstract int javaSlotToBedrock(int slot);
|
public abstract int javaSlotToBedrock(int javaSlot); //TODO
|
||||||
|
public abstract BedrockContainerSlot javaSlotToBedrockContainer(int javaSlot); //TODO
|
||||||
public abstract SlotType getSlotType(int javaSlot);
|
public abstract SlotType getSlotType(int javaSlot);
|
||||||
public abstract void translateActions(GeyserSession session, Inventory inventory, List<InventoryActionData> actions);
|
public abstract Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory);
|
||||||
|
|
||||||
|
public void translateRequests(GeyserSession session, Inventory inventory, List<ItemStackRequestPacket.Request> 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<Integer> 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<Integer> 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<ItemStackResponsePacket.ContainerEntry> containerEntries) {
|
||||||
|
return new ItemStackResponsePacket.Response(true, request.getRequestId(), containerEntries);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ItemStackResponsePacket.Response rejectRequest(ItemStackRequestPacket.Request request) {
|
||||||
|
new Throwable("DEBUGGING: ItemStackRequest rejected").printStackTrace(); //TODO: temporary debugging
|
||||||
|
return new ItemStackResponsePacket.Response(false, 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<ItemStackResponsePacket.ContainerEntry> makeContainerEntries(GeyserSession session, Inventory inventory, Set<Integer> affectedSlots) {
|
||||||
|
Map<ContainerSlotType, List<ItemStackResponsePacket.ItemEntry>> containerMap = new HashMap<>();
|
||||||
|
for (int slot : affectedSlots) {
|
||||||
|
BedrockContainerSlot bedrockSlot = javaSlotToBedrockContainer(slot);
|
||||||
|
List<ItemStackResponsePacket.ItemEntry> list = containerMap.computeIfAbsent(bedrockSlot.getContainer(), k -> new ArrayList<>());
|
||||||
|
list.add(makeItemEntry(session, bedrockSlot.getSlot(), inventory.getItem(slot)));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ItemStackResponsePacket.ContainerEntry> containerEntries = new ArrayList<>();
|
||||||
|
for (Map.Entry<ContainerSlotType, List<ItemStackResponsePacket.ItemEntry>> 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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,15 +25,21 @@
|
|||||||
|
|
||||||
package org.geysermc.connector.network.translators.inventory;
|
package org.geysermc.connector.network.translators.inventory;
|
||||||
|
|
||||||
import com.nukkitx.protocol.bedrock.data.inventory.ContainerId;
|
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
|
||||||
import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.inventory.InventorySource;
|
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.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.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater;
|
|
||||||
import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
|
import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
|
||||||
|
import org.geysermc.connector.network.translators.inventory.updater.UIInventoryUpdater;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class MerchantInventoryTranslator extends BaseInventoryTranslator {
|
public class MerchantInventoryTranslator extends BaseInventoryTranslator {
|
||||||
|
|
||||||
@ -41,7 +47,7 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator {
|
|||||||
|
|
||||||
public MerchantInventoryTranslator() {
|
public MerchantInventoryTranslator() {
|
||||||
super(3);
|
super(3);
|
||||||
this.updater = new CursorInventoryUpdater();
|
this.updater = new UIInventoryUpdater();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -58,26 +64,30 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int bedrockSlotToJava(InventoryActionData action) {
|
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
|
||||||
switch (action.getSource().getContainerId()) {
|
switch (slot) {
|
||||||
case ContainerId.UI:
|
case 0:
|
||||||
switch (action.getSlot()) {
|
return new BedrockContainerSlot(ContainerSlotType.TRADE2_INGREDIENT1, 4);
|
||||||
case 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;
|
return 0;
|
||||||
case 5:
|
case TRADE2_INGREDIENT2:
|
||||||
return 1;
|
return 1;
|
||||||
case 50:
|
case TRADE2_RESULT:
|
||||||
|
case CREATIVE_OUTPUT:
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
break;
|
return super.bedrockSlotToJava(slotInfoData);
|
||||||
case -28: // Trading 1?
|
|
||||||
return 0;
|
|
||||||
case -29: // Trading 2?
|
|
||||||
return 1;
|
|
||||||
case -30: // Trading Output?
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
return super.bedrockSlotToJava(action);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -90,18 +100,40 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void prepareInventory(GeyserSession session, Inventory inventory) {
|
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
|
@Override
|
||||||
public void openInventory(GeyserSession session, Inventory inventory) {
|
public void openInventory(GeyserSession session, Inventory inventory) {
|
||||||
|
//Handled in JavaTradeListTranslator
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void closeInventory(GeyserSession session, Inventory inventory) {
|
public void closeInventory(GeyserSession session, Inventory inventory) {
|
||||||
session.setLastInteractedVillagerEid(-1);
|
MerchantContainer merchantInventory = (MerchantContainer) inventory;
|
||||||
session.setVillagerTrades(null);
|
if (merchantInventory.getVillager() != null) {
|
||||||
|
merchantInventory.getVillager().despawnEntity(session);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -115,11 +147,7 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translateActions(GeyserSession session, Inventory inventory, List<InventoryActionData> actions) {
|
public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) {
|
||||||
if (actions.stream().anyMatch(a -> a.getSource().getContainerId() == -31)) {
|
return new MerchantContainer(name, windowId, windowType, this.size, playerInventory);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
super.translateActions(session, inventory, actions);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,18 +25,15 @@
|
|||||||
|
|
||||||
package org.geysermc.connector.network.translators.inventory;
|
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.data.game.entity.player.GameMode;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCreativeInventoryActionPacket;
|
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
|
||||||
import com.nukkitx.protocol.bedrock.data.inventory.ContainerId;
|
import com.nukkitx.protocol.bedrock.data.inventory.*;
|
||||||
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.nukkitx.protocol.bedrock.packet.InventoryContentPacket;
|
import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
|
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.Inventory;
|
||||||
|
import org.geysermc.connector.inventory.PlayerInventory;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
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.network.translators.item.ItemTranslator;
|
||||||
import org.geysermc.connector.utils.InventoryUtils;
|
import org.geysermc.connector.utils.InventoryUtils;
|
||||||
import org.geysermc.connector.utils.LanguageUtils;
|
import org.geysermc.connector.utils.LanguageUtils;
|
||||||
@ -59,11 +56,11 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||||||
ItemData[] contents = new ItemData[36];
|
ItemData[] contents = new ItemData[36];
|
||||||
// Inventory
|
// Inventory
|
||||||
for (int i = 9; i < 36; i++) {
|
for (int i = 9; i < 36; i++) {
|
||||||
contents[i] = ItemTranslator.translateToBedrock(session, inventory.getItem(i));
|
contents[i] = inventory.getItem(i).getItemData(session);
|
||||||
}
|
}
|
||||||
// Hotbar
|
// Hotbar
|
||||||
for (int i = 36; i < 45; i++) {
|
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);
|
inventoryContentPacket.setContents(contents);
|
||||||
session.sendUpstreamPacket(inventoryContentPacket);
|
session.sendUpstreamPacket(inventoryContentPacket);
|
||||||
@ -73,7 +70,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||||||
armorContentPacket.setContainerId(ContainerId.ARMOR);
|
armorContentPacket.setContainerId(ContainerId.ARMOR);
|
||||||
contents = new ItemData[4];
|
contents = new ItemData[4];
|
||||||
for (int i = 5; i < 9; i++) {
|
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);
|
armorContentPacket.setContents(contents);
|
||||||
session.sendUpstreamPacket(armorContentPacket);
|
session.sendUpstreamPacket(armorContentPacket);
|
||||||
@ -81,7 +78,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||||||
// Offhand
|
// Offhand
|
||||||
InventoryContentPacket offhandPacket = new InventoryContentPacket();
|
InventoryContentPacket offhandPacket = new InventoryContentPacket();
|
||||||
offhandPacket.setContainerId(ContainerId.OFFHAND);
|
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);
|
session.sendUpstreamPacket(offhandPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +97,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||||||
if (session.getGameMode() == GameMode.CREATIVE) {
|
if (session.getGameMode() == GameMode.CREATIVE) {
|
||||||
slotPacket.setItem(UNUSUABLE_CRAFTING_SPACE_BLOCK);
|
slotPacket.setItem(UNUSUABLE_CRAFTING_SPACE_BLOCK);
|
||||||
}else{
|
}else{
|
||||||
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(i)));
|
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(i).getItemStack()));
|
||||||
}
|
}
|
||||||
|
|
||||||
session.sendUpstreamPacket(slotPacket);
|
session.sendUpstreamPacket(slotPacket);
|
||||||
@ -125,21 +122,23 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||||||
slotPacket.setContainerId(ContainerId.UI);
|
slotPacket.setContainerId(ContainerId.UI);
|
||||||
slotPacket.setSlot(slot + 27);
|
slotPacket.setSlot(slot + 27);
|
||||||
}
|
}
|
||||||
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(slot)));
|
slotPacket.setItem(inventory.getItem(slot).getItemData(session));
|
||||||
session.sendUpstreamPacket(slotPacket);
|
session.sendUpstreamPacket(slotPacket);
|
||||||
} else if (slot == 45) {
|
} else if (slot == 45) {
|
||||||
InventoryContentPacket offhandPacket = new InventoryContentPacket();
|
InventoryContentPacket offhandPacket = new InventoryContentPacket();
|
||||||
offhandPacket.setContainerId(ContainerId.OFFHAND);
|
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);
|
session.sendUpstreamPacket(offhandPacket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int bedrockSlotToJava(InventoryActionData action) {
|
public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
|
||||||
int slotnum = action.getSlot();
|
int slotnum = slotInfoData.getSlot();
|
||||||
switch (action.getSource().getContainerId()) {
|
switch (slotInfoData.getContainer()) {
|
||||||
case ContainerId.INVENTORY:
|
case HOTBAR_AND_INVENTORY:
|
||||||
|
case HOTBAR:
|
||||||
|
case INVENTORY:
|
||||||
// Inventory
|
// Inventory
|
||||||
if (slotnum >= 9 && slotnum <= 35) {
|
if (slotnum >= 9 && slotnum <= 35) {
|
||||||
return slotnum;
|
return slotnum;
|
||||||
@ -149,19 +148,19 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||||||
return slotnum + 36;
|
return slotnum + 36;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ContainerId.ARMOR:
|
case ARMOR:
|
||||||
if (slotnum >= 0 && slotnum <= 3) {
|
if (slotnum >= 0 && slotnum <= 3) {
|
||||||
return slotnum + 5;
|
return slotnum + 5;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ContainerId.OFFHAND:
|
case OFFHAND:
|
||||||
return 45;
|
return 45;
|
||||||
case ContainerId.UI:
|
case CRAFTING_INPUT:
|
||||||
if (slotnum >= 28 && 31 >= slotnum) {
|
if (slotnum >= 28 && 31 >= slotnum) {
|
||||||
return slotnum - 27;
|
return slotnum - 27;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ContainerId.CRAFTING_RESULT:
|
case CREATIVE_OUTPUT:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return slotnum;
|
return slotnum;
|
||||||
@ -169,7 +168,26 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int javaSlotToBedrock(int slot) {
|
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
|
@Override
|
||||||
@ -180,52 +198,13 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translateActions(GeyserSession session, Inventory inventory, List<InventoryActionData> actions) {
|
public void translateRequests(GeyserSession session, Inventory inventory, List<ItemStackRequestPacket.Request> requests) {
|
||||||
if (session.getGameMode() == GameMode.CREATIVE) {
|
super.translateRequests(session, inventory, requests);
|
||||||
//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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemStack javaItem;
|
@Override
|
||||||
for (InventoryActionData action : actions) {
|
public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) {
|
||||||
switch (action.getSource().getContainerId()) {
|
throw new UnsupportedOperationException();
|
||||||
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
|
@Override
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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<ClickAction> 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<ClickAction> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<InventoryActionData> 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<Integer> 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<ItemStack> 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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -23,16 +23,25 @@
|
|||||||
* @link https://github.com/GeyserMC/Geyser
|
* @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.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 com.github.steveice10.mc.protocol.data.game.window.WindowActionParam;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
enum Click {
|
public enum Click {
|
||||||
LEFT(ClickItemParam.LEFT_CLICK),
|
LEFT(WindowAction.CLICK_ITEM, ClickItemParam.LEFT_CLICK),
|
||||||
RIGHT(ClickItemParam.RIGHT_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;
|
public final WindowActionParam actionParam;
|
||||||
}
|
}
|
@ -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<ClickAction> plan = new ArrayList<>();
|
||||||
|
private final Int2ObjectMap<GeyserItemStack> 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<ClickAction> 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<Integer> getAffectedSlots() {
|
||||||
|
Set<Integer> 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;
|
||||||
|
}
|
||||||
|
}
|
@ -49,7 +49,7 @@ public class ChestInventoryUpdater extends InventoryUpdater {
|
|||||||
ItemData[] bedrockItems = new ItemData[paddedSize];
|
ItemData[] bedrockItems = new ItemData[paddedSize];
|
||||||
for (int i = 0; i < bedrockItems.length; i++) {
|
for (int i = 0; i < bedrockItems.length; i++) {
|
||||||
if (i < translator.size) {
|
if (i < translator.size) {
|
||||||
bedrockItems[i] = ItemTranslator.translateToBedrock(session, inventory.getItem(i));
|
bedrockItems[i] = inventory.getItem(i).getItemData(session);
|
||||||
} else {
|
} else {
|
||||||
bedrockItems[i] = UNUSUABLE_SPACE_BLOCK;
|
bedrockItems[i] = UNUSUABLE_SPACE_BLOCK;
|
||||||
}
|
}
|
||||||
@ -69,7 +69,7 @@ public class ChestInventoryUpdater extends InventoryUpdater {
|
|||||||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||||
slotPacket.setContainerId(inventory.getId());
|
slotPacket.setContainerId(inventory.getId());
|
||||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||||
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot)));
|
slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session));
|
||||||
session.sendUpstreamPacket(slotPacket);
|
session.sendUpstreamPacket(slotPacket);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ public class ContainerInventoryUpdater extends InventoryUpdater {
|
|||||||
|
|
||||||
ItemData[] bedrockItems = new ItemData[translator.size];
|
ItemData[] bedrockItems = new ItemData[translator.size];
|
||||||
for (int i = 0; i < bedrockItems.length; i++) {
|
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();
|
InventoryContentPacket contentPacket = new InventoryContentPacket();
|
||||||
@ -57,7 +57,7 @@ public class ContainerInventoryUpdater extends InventoryUpdater {
|
|||||||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||||
slotPacket.setContainerId(inventory.getId());
|
slotPacket.setContainerId(inventory.getId());
|
||||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||||
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot)));
|
slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session));
|
||||||
session.sendUpstreamPacket(slotPacket);
|
session.sendUpstreamPacket(slotPacket);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ public abstract class InventoryUpdater {
|
|||||||
ItemData[] bedrockItems = new ItemData[36];
|
ItemData[] bedrockItems = new ItemData[36];
|
||||||
for (int i = 0; i < 36; i++) {
|
for (int i = 0; i < 36; i++) {
|
||||||
final int offset = i < 9 ? 27 : -9;
|
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();
|
InventoryContentPacket contentPacket = new InventoryContentPacket();
|
||||||
contentPacket.setContainerId(ContainerId.INVENTORY);
|
contentPacket.setContainerId(ContainerId.INVENTORY);
|
||||||
@ -52,7 +52,7 @@ public abstract class InventoryUpdater {
|
|||||||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||||
slotPacket.setContainerId(ContainerId.INVENTORY);
|
slotPacket.setContainerId(ContainerId.INVENTORY);
|
||||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||||
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot)));
|
slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session));
|
||||||
session.sendUpstreamPacket(slotPacket);
|
session.sendUpstreamPacket(slotPacket);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -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.inventory.InventoryTranslator;
|
||||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
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
|
@Override
|
||||||
public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {
|
public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {
|
||||||
super.updateInventory(translator, session, inventory);
|
super.updateInventory(translator, session, inventory);
|
||||||
@ -46,7 +45,7 @@ public class CursorInventoryUpdater extends InventoryUpdater {
|
|||||||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||||
slotPacket.setContainerId(ContainerId.UI);
|
slotPacket.setContainerId(ContainerId.UI);
|
||||||
slotPacket.setSlot(bedrockSlot);
|
slotPacket.setSlot(bedrockSlot);
|
||||||
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(i)));
|
slotPacket.setItem(inventory.getItem(i).getItemData(session));
|
||||||
session.sendUpstreamPacket(slotPacket);
|
session.sendUpstreamPacket(slotPacket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,7 +58,7 @@ public class CursorInventoryUpdater extends InventoryUpdater {
|
|||||||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||||
slotPacket.setContainerId(ContainerId.UI);
|
slotPacket.setContainerId(ContainerId.UI);
|
||||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||||
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot)));
|
slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session));
|
||||||
session.sendUpstreamPacket(slotPacket);
|
session.sendUpstreamPacket(slotPacket);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
@ -34,6 +34,8 @@ import com.nukkitx.nbt.NbtMap;
|
|||||||
import com.nukkitx.protocol.bedrock.data.inventory.CraftingData;
|
import com.nukkitx.protocol.bedrock.data.inventory.CraftingData;
|
||||||
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
||||||
import com.nukkitx.protocol.bedrock.packet.CraftingDataPacket;
|
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.IntOpenHashSet;
|
||||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
@ -51,8 +53,10 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator<ServerDeclare
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerDeclareRecipesPacket packet, GeyserSession session) {
|
public void translate(ServerDeclareRecipesPacket packet, GeyserSession session) {
|
||||||
|
Int2ObjectMap<Recipe> recipeMap = new Int2ObjectOpenHashMap<>();
|
||||||
CraftingDataPacket craftingDataPacket = new CraftingDataPacket();
|
CraftingDataPacket craftingDataPacket = new CraftingDataPacket();
|
||||||
craftingDataPacket.setCleanRecipes(true);
|
craftingDataPacket.setCleanRecipes(true);
|
||||||
|
int netId = 1;
|
||||||
for (Recipe recipe : packet.getRecipes()) {
|
for (Recipe recipe : packet.getRecipes()) {
|
||||||
switch (recipe.getType()) {
|
switch (recipe.getType()) {
|
||||||
case CRAFTING_SHAPELESS: {
|
case CRAFTING_SHAPELESS: {
|
||||||
@ -63,7 +67,8 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator<ServerDeclare
|
|||||||
for (ItemData[] inputs : inputCombinations) {
|
for (ItemData[] inputs : inputCombinations) {
|
||||||
UUID uuid = UUID.randomUUID();
|
UUID uuid = UUID.randomUUID();
|
||||||
craftingDataPacket.getCraftingData().add(CraftingData.fromShapeless(uuid.toString(),
|
craftingDataPacket.getCraftingData().add(CraftingData.fromShapeless(uuid.toString(),
|
||||||
inputs, new ItemData[]{output}, uuid, "crafting_table", 0));
|
inputs, new ItemData[]{output}, uuid, "crafting_table", 0, netId));
|
||||||
|
recipeMap.put(netId++, recipe);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -76,7 +81,8 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator<ServerDeclare
|
|||||||
UUID uuid = UUID.randomUUID();
|
UUID uuid = UUID.randomUUID();
|
||||||
craftingDataPacket.getCraftingData().add(CraftingData.fromShaped(uuid.toString(),
|
craftingDataPacket.getCraftingData().add(CraftingData.fromShaped(uuid.toString(),
|
||||||
shapedRecipeData.getWidth(), shapedRecipeData.getHeight(), inputs,
|
shapedRecipeData.getWidth(), shapedRecipeData.getHeight(), inputs,
|
||||||
new ItemData[]{output}, uuid, "crafting_table", 0));
|
new ItemData[]{output}, uuid, "crafting_table", 0, netId));
|
||||||
|
recipeMap.put(netId++, recipe);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -102,6 +108,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator<ServerDeclare
|
|||||||
}
|
}
|
||||||
craftingDataPacket.getPotionMixData().addAll(PotionMixRegistry.POTION_MIXES);
|
craftingDataPacket.getPotionMixData().addAll(PotionMixRegistry.POTION_MIXES);
|
||||||
session.sendUpstreamPacket(craftingDataPacket);
|
session.sendUpstreamPacket(craftingDataPacket);
|
||||||
|
session.setCraftingRecipes(recipeMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: rewrite
|
//TODO: rewrite
|
||||||
|
@ -50,7 +50,7 @@ public class JavaRespawnTranslator extends PacketTranslator<ServerRespawnPacket>
|
|||||||
// Max health must be divisible by two in bedrock
|
// Max health must be divisible by two in bedrock
|
||||||
entity.getAttributes().put(AttributeType.HEALTH, AttributeType.HEALTH.getAttribute(maxHealth, (maxHealth % 2 == 1 ? maxHealth + 1 : maxHealth)));
|
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();
|
SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket();
|
||||||
playerGameTypePacket.setGamemode(packet.getGamemode().ordinal());
|
playerGameTypePacket.setGamemode(packet.getGamemode().ordinal());
|
||||||
|
@ -32,6 +32,7 @@ import com.github.steveice10.opennbt.tag.builtin.*;
|
|||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
||||||
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
||||||
|
import org.geysermc.connector.inventory.GeyserItemStack;
|
||||||
import org.geysermc.connector.inventory.PlayerInventory;
|
import org.geysermc.connector.inventory.PlayerInventory;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
@ -71,15 +72,9 @@ public class JavaPlayerActionAckTranslator extends PacketTranslator<ServerPlayer
|
|||||||
packet.getPosition().getY(),
|
packet.getPosition().getY(),
|
||||||
packet.getPosition().getZ()
|
packet.getPosition().getZ()
|
||||||
));
|
));
|
||||||
PlayerInventory inventory = session.getInventory();
|
PlayerInventory inventory = session.getPlayerInventory();
|
||||||
ItemStack item = inventory.getItemInHand();
|
GeyserItemStack item = inventory.getItemInHand();
|
||||||
ItemEntry itemEntry = null;
|
double breakTime = Math.ceil(BlockUtils.getBreakTime(blockHardness, packet.getNewState(), item.getItemEntry(), item.getNbt(), session) * 20);
|
||||||
CompoundTag nbtData = new CompoundTag("");
|
|
||||||
if (item != null) {
|
|
||||||
itemEntry = ItemRegistry.getItem(item);
|
|
||||||
nbtData = item.getNbt();
|
|
||||||
}
|
|
||||||
double breakTime = Math.ceil(BlockUtils.getBreakTime(blockHardness, packet.getNewState(), itemEntry, nbtData, session) * 20);
|
|
||||||
levelEvent.setData((int) (65535 / breakTime));
|
levelEvent.setData((int) (65535 / breakTime));
|
||||||
session.setBreakingBlock(packet.getNewState());
|
session.setBreakingBlock(packet.getNewState());
|
||||||
session.sendUpstreamPacket(levelEvent);
|
session.sendUpstreamPacket(levelEvent);
|
||||||
|
@ -36,12 +36,14 @@ public class JavaPlayerChangeHeldItemTranslator extends PacketTranslator<ServerP
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerPlayerChangeHeldItemPacket packet, GeyserSession session) {
|
public void translate(ServerPlayerChangeHeldItemPacket packet, GeyserSession session) {
|
||||||
|
session.addInventoryTask(() -> {
|
||||||
PlayerHotbarPacket hotbarPacket = new PlayerHotbarPacket();
|
PlayerHotbarPacket hotbarPacket = new PlayerHotbarPacket();
|
||||||
hotbarPacket.setContainerId(0);
|
hotbarPacket.setContainerId(0);
|
||||||
hotbarPacket.setSelectedHotbarSlot(packet.getSlot());
|
hotbarPacket.setSelectedHotbarSlot(packet.getSlot());
|
||||||
hotbarPacket.setSelectHotbarSlot(true);
|
hotbarPacket.setSelectHotbarSlot(true);
|
||||||
session.sendUpstreamPacket(hotbarPacket);
|
session.sendUpstreamPacket(hotbarPacket);
|
||||||
|
|
||||||
session.getInventory().setHeldItemSlot(packet.getSlot());
|
session.getPlayerInventory().setHeldItemSlot(packet.getSlot());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
package org.geysermc.connector.network.translators.java.window;
|
package org.geysermc.connector.network.translators.java.window;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerCloseWindowPacket;
|
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.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
@ -36,7 +37,8 @@ public class JavaCloseWindowTranslator extends PacketTranslator<ServerCloseWindo
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerCloseWindowPacket packet, GeyserSession session) {
|
public void translate(ServerCloseWindowPacket packet, GeyserSession session) {
|
||||||
InventoryUtils.closeWindow(session, packet.getWindowId());
|
session.addInventoryTask(() -> {
|
||||||
InventoryUtils.closeInventory(session, packet.getWindowId());
|
InventoryUtils.closeInventory(session, packet.getWindowId());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.client.window.ClientConfirmTransactionPacket;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerConfirmTransactionPacket;
|
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.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
@ -36,9 +37,11 @@ public class JavaConfirmTransactionTranslator extends PacketTranslator<ServerCon
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerConfirmTransactionPacket packet, GeyserSession session) {
|
public void translate(ServerConfirmTransactionPacket packet, GeyserSession session) {
|
||||||
|
session.addInventoryTask(() -> {
|
||||||
if (!packet.isAccepted()) {
|
if (!packet.isAccepted()) {
|
||||||
ClientConfirmTransactionPacket confirmPacket = new ClientConfirmTransactionPacket(packet.getWindowId(), packet.getActionId(), true);
|
ClientConfirmTransactionPacket confirmPacket = new ClientConfirmTransactionPacket(packet.getWindowId(), packet.getActionId(), true);
|
||||||
session.sendDownstreamPacket(confirmPacket);
|
session.sendDownstreamPacket(confirmPacket);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,14 +43,16 @@ public class JavaOpenWindowTranslator extends PacketTranslator<ServerOpenWindowP
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerOpenWindowPacket packet, GeyserSession session) {
|
public void translate(ServerOpenWindowPacket packet, GeyserSession session) {
|
||||||
|
session.addInventoryTask(() -> {
|
||||||
if (packet.getWindowId() == 0) {
|
if (packet.getWindowId() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
InventoryTranslator newTranslator = InventoryTranslator.INVENTORY_TRANSLATORS.get(packet.getType());
|
InventoryTranslator newTranslator = InventoryTranslator.INVENTORY_TRANSLATORS.get(packet.getType());
|
||||||
Inventory openInventory = session.getInventoryCache().getOpenInventory();
|
Inventory openInventory = session.getOpenInventory();
|
||||||
|
//No translator exists for this window type. Close all windows and return.
|
||||||
if (newTranslator == null) {
|
if (newTranslator == null) {
|
||||||
if (openInventory != null) {
|
if (openInventory != null) {
|
||||||
InventoryUtils.closeWindow(session, openInventory.getId());
|
|
||||||
InventoryUtils.closeInventory(session, openInventory.getId());
|
InventoryUtils.closeInventory(session, openInventory.getId());
|
||||||
}
|
}
|
||||||
ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(packet.getWindowId());
|
ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(packet.getWindowId());
|
||||||
@ -73,16 +75,15 @@ public class JavaOpenWindowTranslator extends PacketTranslator<ServerOpenWindowP
|
|||||||
|
|
||||||
name = LocaleUtils.getLocaleString(name, session.getClientData().getLanguageCode());
|
name = LocaleUtils.getLocaleString(name, session.getClientData().getLanguageCode());
|
||||||
|
|
||||||
Inventory newInventory = new Inventory(name, packet.getWindowId(), packet.getType(), newTranslator.size + 36);
|
Inventory newInventory = newTranslator.createInventory(name, packet.getWindowId(), packet.getType(), session.getPlayerInventory());
|
||||||
session.getInventoryCache().cacheInventory(newInventory);
|
|
||||||
if (openInventory != null) {
|
if (openInventory != null) {
|
||||||
InventoryTranslator openTranslator = InventoryTranslator.INVENTORY_TRANSLATORS.get(openInventory.getWindowType());
|
InventoryTranslator openTranslator = InventoryTranslator.INVENTORY_TRANSLATORS.get(openInventory.getWindowType());
|
||||||
if (!openTranslator.getClass().equals(newTranslator.getClass())) {
|
if (!openTranslator.getClass().equals(newTranslator.getClass())) {
|
||||||
InventoryUtils.closeWindow(session, openInventory.getId());
|
|
||||||
InventoryUtils.closeInventory(session, openInventory.getId());
|
InventoryUtils.closeInventory(session, openInventory.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InventoryUtils.openInventory(session, newInventory);
|
InventoryUtils.openInventory(session, newInventory);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,37 +26,53 @@
|
|||||||
package org.geysermc.connector.network.translators.java.window;
|
package org.geysermc.connector.network.translators.java.window;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerSetSlotPacket;
|
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.inventory.Inventory;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
|
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||||
import org.geysermc.connector.utils.InventoryUtils;
|
import org.geysermc.connector.utils.InventoryUtils;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
@Translator(packet = ServerSetSlotPacket.class)
|
@Translator(packet = ServerSetSlotPacket.class)
|
||||||
public class JavaSetSlotTranslator extends PacketTranslator<ServerSetSlotPacket> {
|
public class JavaSetSlotTranslator extends PacketTranslator<ServerSetSlotPacket> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerSetSlotPacket packet, GeyserSession session) {
|
public void translate(ServerSetSlotPacket packet, GeyserSession session) {
|
||||||
if (packet.getWindowId() == 255 && packet.getSlot() == -1) { //cursor
|
session.addInventoryTask(() -> {
|
||||||
if (session.getCraftSlot() != 0)
|
if (packet.getWindowId() == 255) { //cursor
|
||||||
return;
|
GeyserItemStack newItem = GeyserItemStack.from(packet.getItem());
|
||||||
|
GeyserItemStack oldItem = session.getPlayerInventory().getCursor();
|
||||||
session.getInventory().setCursor(packet.getItem());
|
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);
|
InventoryUtils.updateCursor(session);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Inventory inventory = session.getInventoryCache().getInventories().get(packet.getWindowId());
|
//TODO: support window id -2, should update player inventory
|
||||||
if (inventory == null || (packet.getWindowId() != 0 && inventory.getWindowType() == null))
|
Inventory inventory = InventoryUtils.getInventory(session, packet.getWindowId());
|
||||||
|
if (inventory == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
|
InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
|
||||||
if (translator != null) {
|
if (translator != null) {
|
||||||
inventory.setItem(packet.getSlot(), packet.getItem());
|
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());
|
translator.updateSlot(session, inventory, packet.getSlot());
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,32 +26,40 @@
|
|||||||
package org.geysermc.connector.network.translators.java.window;
|
package org.geysermc.connector.network.translators.java.window;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerWindowItemsPacket;
|
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.inventory.Inventory;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||||
|
import org.geysermc.connector.utils.InventoryUtils;
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
@Translator(packet = ServerWindowItemsPacket.class)
|
@Translator(packet = ServerWindowItemsPacket.class)
|
||||||
public class JavaWindowItemsTranslator extends PacketTranslator<ServerWindowItemsPacket> {
|
public class JavaWindowItemsTranslator extends PacketTranslator<ServerWindowItemsPacket> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerWindowItemsPacket packet, GeyserSession session) {
|
public void translate(ServerWindowItemsPacket packet, GeyserSession session) {
|
||||||
Inventory inventory = session.getInventoryCache().getInventories().get(packet.getWindowId());
|
session.addInventoryTask(() -> {
|
||||||
if (inventory == null || (packet.getWindowId() != 0 && inventory.getWindowType() == null))
|
Inventory inventory = InventoryUtils.getInventory(session, packet.getWindowId());
|
||||||
|
if (inventory == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (packet.getItems().length < inventory.getSize()) {
|
for (int i = 0; i < packet.getItems().length; i++) {
|
||||||
inventory.setItems(Arrays.copyOf(packet.getItems(), inventory.getSize()));
|
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 {
|
} else {
|
||||||
inventory.setItems(packet.getItems());
|
newItem.setNetId(session.getItemNetId().getAndIncrement());
|
||||||
|
}
|
||||||
|
inventory.setItem(i, newItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
|
InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
|
||||||
if (translator != null) {
|
if (translator != null) {
|
||||||
translator.updateInventory(session, inventory);
|
translator.updateInventory(session, inventory);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,19 +31,22 @@ import org.geysermc.connector.network.session.GeyserSession;
|
|||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||||
|
import org.geysermc.connector.utils.InventoryUtils;
|
||||||
|
|
||||||
@Translator(packet = ServerWindowPropertyPacket.class)
|
@Translator(packet = ServerWindowPropertyPacket.class)
|
||||||
public class JavaWindowPropertyTranslator extends PacketTranslator<ServerWindowPropertyPacket> {
|
public class JavaWindowPropertyTranslator extends PacketTranslator<ServerWindowPropertyPacket> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerWindowPropertyPacket packet, GeyserSession session) {
|
public void translate(ServerWindowPropertyPacket packet, GeyserSession session) {
|
||||||
Inventory inventory = session.getInventoryCache().getInventories().get(packet.getWindowId());
|
session.addInventoryTask(() -> {
|
||||||
if (inventory == null || (packet.getWindowId() != 0 && inventory.getWindowType() == null))
|
Inventory inventory = InventoryUtils.getInventory(session, packet.getWindowId());
|
||||||
|
if (inventory == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
|
InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
|
||||||
if (translator != null) {
|
if (translator != null) {
|
||||||
translator.updateProperty(session, inventory, packet.getRawProperty(), packet.getValue());
|
translator.updateProperty(session, inventory, packet.getRawProperty(), packet.getValue());
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ public class JavaNotifyClientTranslator extends PacketTranslator<ServerNotifyCli
|
|||||||
session.setGameMode(gameMode);
|
session.setGameMode(gameMode);
|
||||||
|
|
||||||
// Update the crafting grid to add/remove barriers for creative inventory
|
// Update the crafting grid to add/remove barriers for creative inventory
|
||||||
PlayerInventoryTranslator.updateCraftingGrid(session, session.getInventory());
|
PlayerInventoryTranslator.updateCraftingGrid(session, session.getPlayerInventory());
|
||||||
break;
|
break;
|
||||||
case ENTER_CREDITS:
|
case ENTER_CREDITS:
|
||||||
switch ((EnterCreditsValue) packet.getValue()) {
|
switch ((EnterCreditsValue) packet.getValue()) {
|
||||||
|
@ -38,6 +38,7 @@ import com.nukkitx.protocol.bedrock.packet.UpdateTradePacket;
|
|||||||
import org.geysermc.connector.entity.Entity;
|
import org.geysermc.connector.entity.Entity;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.inventory.Inventory;
|
import org.geysermc.connector.inventory.Inventory;
|
||||||
|
import org.geysermc.connector.inventory.MerchantContainer;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
@ -53,8 +54,14 @@ public class JavaTradeListTranslator extends PacketTranslator<ServerTradeListPac
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerTradeListPacket packet, GeyserSession session) {
|
public void translate(ServerTradeListPacket packet, GeyserSession session) {
|
||||||
Entity villager = session.getPlayerEntity();
|
Inventory openInventory = session.getOpenInventory();
|
||||||
session.setVillagerTrades(packet.getTrades());
|
if (!(openInventory instanceof MerchantContainer && openInventory.getId() == packet.getWindowId())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MerchantContainer merchantInventory = (MerchantContainer) openInventory;
|
||||||
|
merchantInventory.setVillagerTrades(packet.getTrades());
|
||||||
|
Entity villager = merchantInventory.getVillager();
|
||||||
villager.getMetadata().put(EntityData.TRADE_TIER, packet.getVillagerLevel() - 1);
|
villager.getMetadata().put(EntityData.TRADE_TIER, packet.getVillagerLevel() - 1);
|
||||||
villager.getMetadata().put(EntityData.MAX_TRADE_TIER, 4);
|
villager.getMetadata().put(EntityData.MAX_TRADE_TIER, 4);
|
||||||
villager.getMetadata().put(EntityData.TRADE_XP, packet.getExperience());
|
villager.getMetadata().put(EntityData.TRADE_XP, packet.getExperience());
|
||||||
@ -64,11 +71,8 @@ public class JavaTradeListTranslator extends PacketTranslator<ServerTradeListPac
|
|||||||
updateTradePacket.setTradeTier(packet.getVillagerLevel() - 1);
|
updateTradePacket.setTradeTier(packet.getVillagerLevel() - 1);
|
||||||
updateTradePacket.setContainerId((short) packet.getWindowId());
|
updateTradePacket.setContainerId((short) packet.getWindowId());
|
||||||
updateTradePacket.setContainerType(ContainerType.TRADE);
|
updateTradePacket.setContainerType(ContainerType.TRADE);
|
||||||
Inventory openInv = session.getInventoryCache().getOpenInventory();
|
|
||||||
String displayName;
|
String displayName;
|
||||||
if (openInv != null && openInv.getId() == packet.getWindowId()) {
|
//TODO: verify correct window title behavior
|
||||||
displayName = openInv.getTitle();
|
|
||||||
} else {
|
|
||||||
Entity realVillager = session.getEntityCache().getEntityByGeyserId(session.getLastInteractedVillagerEid());
|
Entity realVillager = session.getEntityCache().getEntityByGeyserId(session.getLastInteractedVillagerEid());
|
||||||
if (realVillager != null && realVillager.getMetadata().containsKey(EntityData.NAMETAG) && realVillager.getMetadata().getString(EntityData.NAMETAG) != null) {
|
if (realVillager != null && realVillager.getMetadata().containsKey(EntityData.NAMETAG) && realVillager.getMetadata().getString(EntityData.NAMETAG) != null) {
|
||||||
displayName = realVillager.getMetadata().getString(EntityData.NAMETAG);
|
displayName = realVillager.getMetadata().getString(EntityData.NAMETAG);
|
||||||
@ -76,18 +80,19 @@ public class JavaTradeListTranslator extends PacketTranslator<ServerTradeListPac
|
|||||||
displayName = realVillager != null &&
|
displayName = realVillager != null &&
|
||||||
realVillager.getEntityType() == EntityType.WANDERING_TRADER ? "Wandering Trader" : "Villager";
|
realVillager.getEntityType() == EntityType.WANDERING_TRADER ? "Wandering Trader" : "Villager";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
updateTradePacket.setDisplayName(displayName);
|
updateTradePacket.setDisplayName(displayName);
|
||||||
updateTradePacket.setSize(0);
|
updateTradePacket.setSize(0);
|
||||||
updateTradePacket.setNewTradingUi(true);
|
updateTradePacket.setNewTradingUi(true);
|
||||||
updateTradePacket.setUsingEconomyTrade(true);
|
updateTradePacket.setUsingEconomyTrade(true);
|
||||||
updateTradePacket.setPlayerUniqueEntityId(session.getPlayerEntity().getGeyserId());
|
updateTradePacket.setPlayerUniqueEntityId(session.getPlayerEntity().getGeyserId());
|
||||||
updateTradePacket.setTraderUniqueEntityId(session.getPlayerEntity().getGeyserId());
|
updateTradePacket.setTraderUniqueEntityId(villager.getGeyserId());
|
||||||
NbtMapBuilder builder = NbtMap.builder();
|
NbtMapBuilder builder = NbtMap.builder();
|
||||||
List<NbtMap> tags = new ArrayList<>();
|
List<NbtMap> 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();
|
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.putInt("traderExp", trade.getXp());
|
||||||
recipe.putFloat("priceMultiplierA", trade.getPriceMultiplier());
|
recipe.putFloat("priceMultiplierA", trade.getPriceMultiplier());
|
||||||
recipe.put("sell", getItemTag(session, trade.getOutput(), 0));
|
recipe.put("sell", getItemTag(session, trade.getOutput(), 0));
|
||||||
|
@ -27,6 +27,7 @@ package org.geysermc.connector.network.translators.sound;
|
|||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import org.geysermc.connector.inventory.GeyserItemStack;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||||
|
|
||||||
@ -60,12 +61,12 @@ public interface BlockSoundInteractionHandler extends SoundInteractionHandler<St
|
|||||||
}
|
}
|
||||||
if (!contains) continue;
|
if (!contains) continue;
|
||||||
}
|
}
|
||||||
ItemStack itemInHand = session.getInventory().getItemInHand();
|
GeyserItemStack itemInHand = session.getPlayerInventory().getItemInHand();
|
||||||
if (interactionEntry.getKey().items().length != 0) {
|
if (interactionEntry.getKey().items().length != 0) {
|
||||||
if (itemInHand == null || itemInHand.getId() == 0) {
|
if (itemInHand.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
String handIdentifier = ItemRegistry.getItem(session.getInventory().getItemInHand()).getJavaIdentifier();
|
String handIdentifier = itemInHand.getItemEntry().getJavaIdentifier();
|
||||||
boolean contains = false;
|
boolean contains = false;
|
||||||
for (String itemIdentifier : interactionEntry.getKey().items()) {
|
for (String itemIdentifier : interactionEntry.getKey().items()) {
|
||||||
if (handIdentifier.contains(itemIdentifier)) {
|
if (handIdentifier.contains(itemIdentifier)) {
|
||||||
@ -76,7 +77,7 @@ public interface BlockSoundInteractionHandler extends SoundInteractionHandler<St
|
|||||||
if (!contains) continue;
|
if (!contains) continue;
|
||||||
}
|
}
|
||||||
if (session.isSneaking() && !interactionEntry.getKey().ignoreSneakingWhileHolding()) {
|
if (session.isSneaking() && !interactionEntry.getKey().ignoreSneakingWhileHolding()) {
|
||||||
if (session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() != 0) {
|
if (!itemInHand.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ package org.geysermc.connector.network.translators.sound;
|
|||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import org.geysermc.connector.entity.Entity;
|
import org.geysermc.connector.entity.Entity;
|
||||||
|
import org.geysermc.connector.inventory.GeyserItemStack;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||||
|
|
||||||
@ -61,12 +62,12 @@ public interface EntitySoundInteractionHandler extends SoundInteractionHandler<E
|
|||||||
}
|
}
|
||||||
if (!contains) continue;
|
if (!contains) continue;
|
||||||
}
|
}
|
||||||
ItemStack itemInHand = session.getInventory().getItemInHand();
|
GeyserItemStack itemInHand = session.getPlayerInventory().getItemInHand();
|
||||||
if (interactionEntry.getKey().items().length != 0) {
|
if (interactionEntry.getKey().items().length != 0) {
|
||||||
if (itemInHand == null || itemInHand.getId() == 0) {
|
if (itemInHand.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
String handIdentifier = ItemRegistry.getItem(session.getInventory().getItemInHand()).getJavaIdentifier();
|
String handIdentifier = itemInHand.getItemEntry().getJavaIdentifier();
|
||||||
boolean contains = false;
|
boolean contains = false;
|
||||||
for (String itemIdentifier : interactionEntry.getKey().items()) {
|
for (String itemIdentifier : interactionEntry.getKey().items()) {
|
||||||
if (handIdentifier.contains(itemIdentifier)) {
|
if (handIdentifier.contains(itemIdentifier)) {
|
||||||
@ -77,7 +78,7 @@ public interface EntitySoundInteractionHandler extends SoundInteractionHandler<E
|
|||||||
if (!contains) continue;
|
if (!contains) continue;
|
||||||
}
|
}
|
||||||
if (session.isSneaking() && !interactionEntry.getKey().ignoreSneakingWhileHolding()) {
|
if (session.isSneaking() && !interactionEntry.getKey().ignoreSneakingWhileHolding()) {
|
||||||
if (session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() != 0) {
|
if (!itemInHand.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ public class BucketSoundInteractionHandler implements BlockSoundInteractionHandl
|
|||||||
@Override
|
@Override
|
||||||
public void handleInteraction(GeyserSession session, Vector3f position, String identifier) {
|
public void handleInteraction(GeyserSession session, Vector3f position, String identifier) {
|
||||||
if (session.getBucketScheduledFuture() == null) return; // No bucket was really interacted with
|
if (session.getBucketScheduledFuture() == null) return; // No bucket was really interacted with
|
||||||
String handItemIdentifier = ItemRegistry.getItem(session.getInventory().getItemInHand()).getJavaIdentifier();
|
String handItemIdentifier = session.getPlayerInventory().getItemInHand().getItemEntry().getJavaIdentifier();
|
||||||
LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket();
|
LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket();
|
||||||
soundEventPacket.setPosition(position);
|
soundEventPacket.setPosition(position);
|
||||||
soundEventPacket.setIdentifier(":");
|
soundEventPacket.setIdentifier(":");
|
||||||
|
@ -39,7 +39,7 @@ public class MilkCowSoundInteractionHandler implements EntitySoundInteractionHan
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleInteraction(GeyserSession session, Vector3f position, Entity value) {
|
public void handleInteraction(GeyserSession session, Vector3f position, Entity value) {
|
||||||
if (!ItemRegistry.getItem(session.getInventory().getItemInHand()).getJavaIdentifier().equals("minecraft:bucket")) {
|
if (!session.getPlayerInventory().getItemInHand().getItemEntry().getJavaIdentifier().equals("minecraft:bucket")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LevelSoundEventPacket levelSoundEventPacket = new LevelSoundEventPacket();
|
LevelSoundEventPacket levelSoundEventPacket = new LevelSoundEventPacket();
|
||||||
|
@ -132,7 +132,7 @@ public class BlockUtils {
|
|||||||
&& BlockTranslator.getBedrockBlockId(session.getConnector().getWorldManager().getBlockAt(session, session.getPlayerEntity().getPosition().toInt())) == BlockTranslator.BEDROCK_WATER_ID;
|
&& BlockTranslator.getBedrockBlockId(session.getConnector().getWorldManager().getBlockAt(session, session.getPlayerEntity().getPosition().toInt())) == BlockTranslator.BEDROCK_WATER_ID;
|
||||||
|
|
||||||
boolean insideOfWaterWithoutAquaAffinity = isInWater &&
|
boolean insideOfWaterWithoutAquaAffinity = isInWater &&
|
||||||
ItemUtils.getEnchantmentLevel(Optional.ofNullable(session.getInventory().getItem(5)).map(ItemStack::getNbt).orElse(null), "minecraft:aqua_affinity") < 1;
|
ItemUtils.getEnchantmentLevel(session.getPlayerInventory().getItem(5).getNbt(), "minecraft:aqua_affinity") < 1;
|
||||||
|
|
||||||
boolean outOfWaterButNotOnGround = (!isInWater) && (!session.getPlayerEntity().isOnGround());
|
boolean outOfWaterButNotOnGround = (!isInWater) && (!session.getPlayerEntity().isOnGround());
|
||||||
boolean insideWaterNotOnGround = isInWater && !session.getPlayerEntity().isOnGround();
|
boolean insideWaterNotOnGround = isInWater && !session.getPlayerEntity().isOnGround();
|
||||||
|
@ -38,8 +38,10 @@ import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
|||||||
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
|
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.PlayerHotbarPacket;
|
import com.nukkitx.protocol.bedrock.packet.PlayerHotbarPacket;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
|
import org.geysermc.connector.inventory.GeyserItemStack;
|
||||||
import org.geysermc.connector.common.ChatColor;
|
import org.geysermc.connector.common.ChatColor;
|
||||||
import org.geysermc.connector.inventory.Inventory;
|
import org.geysermc.connector.inventory.Inventory;
|
||||||
|
import org.geysermc.connector.inventory.PlayerInventory;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.inventory.DoubleChestInventoryTranslator;
|
import org.geysermc.connector.network.translators.inventory.DoubleChestInventoryTranslator;
|
||||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||||
@ -52,17 +54,16 @@ import java.util.Objects;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class InventoryUtils {
|
public class InventoryUtils {
|
||||||
public static final ItemStack REFRESH_ITEM = new ItemStack(1, 127, new CompoundTag("")); //TODO: stop using this
|
public static final ItemStack REFRESH_ITEM = new ItemStack(1, 127, new CompoundTag(""));
|
||||||
|
|
||||||
public static void openInventory(GeyserSession session, Inventory inventory) {
|
public static void openInventory(GeyserSession session, Inventory inventory) {
|
||||||
InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
|
InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
|
||||||
if (translator != null) {
|
if (translator != null) {
|
||||||
session.getInventoryCache().setOpenInventory(inventory);
|
session.setOpenInventory(inventory);
|
||||||
translator.prepareInventory(session, inventory);
|
translator.prepareInventory(session, inventory);
|
||||||
//Ensure at least half a second passes between closing and opening a new window
|
//Ensure at least half a second passes between closing and opening a new window
|
||||||
//The client will not open the new window if it is still closing the old one
|
//The client will not open the new window if it is still closing the old one
|
||||||
long delay = 700 - (System.currentTimeMillis() - session.getLastWindowCloseTime());
|
long delay = 700 - (System.currentTimeMillis() - session.getLastWindowCloseTime());
|
||||||
//TODO: find better way to handle double chest delay
|
|
||||||
if (translator instanceof DoubleChestInventoryTranslator) {
|
if (translator instanceof DoubleChestInventoryTranslator) {
|
||||||
delay = Math.max(delay, 200);
|
delay = Math.max(delay, 200);
|
||||||
}
|
}
|
||||||
@ -79,53 +80,44 @@ public class InventoryUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void closeInventory(GeyserSession session, int windowId) {
|
public static void closeInventory(GeyserSession session, int windowId) {
|
||||||
if (windowId != 0) {
|
session.getPlayerInventory().setCursor(GeyserItemStack.EMPTY);
|
||||||
Inventory inventory = session.getInventoryCache().getInventories().get(windowId);
|
updateCursor(session);
|
||||||
Inventory openInventory = session.getInventoryCache().getOpenInventory();
|
|
||||||
session.getInventoryCache().uncacheInventory(windowId);
|
Inventory inventory = getInventory(session, windowId);
|
||||||
if (inventory != null && openInventory != null && inventory.getId() == openInventory.getId()) {
|
if (inventory != null) {
|
||||||
InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
|
InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
|
||||||
translator.closeInventory(session, inventory);
|
translator.closeInventory(session, inventory);
|
||||||
session.getInventoryCache().setOpenInventory(null);
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Inventory inventory = session.getInventory();
|
|
||||||
inventory.setOpen(false);
|
|
||||||
InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
|
|
||||||
translator.updateInventory(session, inventory);
|
|
||||||
}
|
|
||||||
|
|
||||||
session.setCraftSlot(0);
|
|
||||||
session.getInventory().setCursor(null);
|
|
||||||
updateCursor(session);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void closeWindow(GeyserSession session, int windowId) {
|
|
||||||
//TODO: Investigate client crash when force closing window and opening a new one
|
|
||||||
//Instead, the window will eventually close by removing the fake blocks
|
|
||||||
session.setLastWindowCloseTime(System.currentTimeMillis());
|
|
||||||
|
|
||||||
/*
|
|
||||||
//Spamming close window packets can bug the client
|
|
||||||
if (System.currentTimeMillis() - session.getLastWindowCloseTime() > 500) {
|
|
||||||
ContainerClosePacket closePacket = new ContainerClosePacket();
|
|
||||||
closePacket.setId((byte) windowId);
|
|
||||||
session.sendUpstreamPacket(closePacket);
|
|
||||||
session.setLastWindowCloseTime(System.currentTimeMillis());
|
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) {
|
public static void updateCursor(GeyserSession session) {
|
||||||
InventorySlotPacket cursorPacket = new InventorySlotPacket();
|
InventorySlotPacket cursorPacket = new InventorySlotPacket();
|
||||||
cursorPacket.setContainerId(ContainerId.UI);
|
cursorPacket.setContainerId(ContainerId.UI);
|
||||||
cursorPacket.setSlot(0);
|
cursorPacket.setSlot(0);
|
||||||
cursorPacket.setItem(ItemTranslator.translateToBedrock(session, session.getInventory().getCursor()));
|
cursorPacket.setItem(session.getPlayerInventory().getCursor().getItemData(session));
|
||||||
session.sendUpstreamPacket(cursorPacket);
|
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) {
|
public static boolean canStack(ItemStack item1, ItemStack item2) {
|
||||||
if (item1 == null || item2 == null)
|
if (item1 == null || item2 == null)
|
||||||
return false;
|
return false;
|
||||||
@ -170,19 +162,16 @@ public class InventoryUtils {
|
|||||||
*/
|
*/
|
||||||
public static void findOrCreatePickedBlock(GeyserSession session, String itemName) {
|
public static void findOrCreatePickedBlock(GeyserSession session, String itemName) {
|
||||||
// Get the inventory to choose a slot to pick
|
// Get the inventory to choose a slot to pick
|
||||||
Inventory inventory = session.getInventoryCache().getOpenInventory();
|
PlayerInventory inventory = session.getPlayerInventory();
|
||||||
if (inventory == null) {
|
|
||||||
inventory = session.getInventory();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check hotbar for item
|
// Check hotbar for item
|
||||||
for (int i = 36; i < 45; i++) {
|
for (int i = 36; i < 45; i++) {
|
||||||
if (inventory.getItem(i) == null) {
|
GeyserItemStack geyserItem = inventory.getItem(i);
|
||||||
|
if (geyserItem.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ItemEntry item = ItemRegistry.getItem(inventory.getItem(i));
|
|
||||||
// If this isn't the item we're looking for
|
// If this isn't the item we're looking for
|
||||||
if (!item.getJavaIdentifier().equals(itemName)) {
|
if (!geyserItem.getItemEntry().getJavaIdentifier().equals(itemName)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,12 +182,12 @@ public class InventoryUtils {
|
|||||||
|
|
||||||
// Check inventory for item
|
// Check inventory for item
|
||||||
for (int i = 9; i < 36; i++) {
|
for (int i = 9; i < 36; i++) {
|
||||||
if (inventory.getItem(i) == null) {
|
GeyserItemStack geyserItem = inventory.getItem(i);
|
||||||
|
if (geyserItem.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ItemEntry item = ItemRegistry.getItem(inventory.getItem(i));
|
|
||||||
// If this isn't the item we're looking for
|
// If this isn't the item we're looking for
|
||||||
if (!item.getJavaIdentifier().equals(itemName)) {
|
if (!geyserItem.getItemEntry().getJavaIdentifier().equals(itemName)) {
|
||||||
continue;
|
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 we still have not found the item, and we're in creative, ask for the item from the server.
|
||||||
if (session.getGameMode() == GameMode.CREATIVE) {
|
if (session.getGameMode() == GameMode.CREATIVE) {
|
||||||
int slot = session.getInventory().getHeldItemSlot() + 36;
|
int slot = inventory.getHeldItemSlot() + 36;
|
||||||
if (session.getInventory().getItemInHand() != null) { // Otherwise we should just use the current slot
|
if (!inventory.getItemInHand().isEmpty()) { // Otherwise we should just use the current slot
|
||||||
for (int i = 36; i < 45; i++) {
|
for (int i = 36; i < 45; i++) {
|
||||||
if (inventory.getItem(i) == null) {
|
if (inventory.getItem(i).isEmpty()) {
|
||||||
slot = i;
|
slot = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -221,7 +210,7 @@ public class InventoryUtils {
|
|||||||
|
|
||||||
ClientCreativeInventoryActionPacket actionPacket = new ClientCreativeInventoryActionPacket(slot,
|
ClientCreativeInventoryActionPacket actionPacket = new ClientCreativeInventoryActionPacket(slot,
|
||||||
new ItemStack(ItemRegistry.getItemEntry(itemName).getJavaId()));
|
new ItemStack(ItemRegistry.getItemEntry(itemName).getJavaId()));
|
||||||
if ((slot - 36) != session.getInventory().getHeldItemSlot()) {
|
if ((slot - 36) != inventory.getHeldItemSlot()) {
|
||||||
setHotbarItem(session, slot);
|
setHotbarItem(session, slot);
|
||||||
}
|
}
|
||||||
session.sendDownstreamPacket(actionPacket);
|
session.sendDownstreamPacket(actionPacket);
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 5f21792264a364e32425014e0be79db93593da1e
|
Subproject commit 93b2caed3c4ecd94b3c77a87f1b2304a7bf4f062
|
@ -1 +1 @@
|
|||||||
Subproject commit 0fae8d3f0de6210a10435a36128db14cb7650ae6
|
Subproject commit ec8b68297c4d62a9e4d640a8c7e77977062628ee
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren