Add horse inventory support

This commit is contained in:
Camotoy 2020-12-26 12:20:59 -05:00
parent c7fade295e
commit c1f5380ed1
No known key found for this signature in database
GPG Key ID: 7EEFB66FE798081F
36 changed files with 572 additions and 59 deletions

View File

@ -30,6 +30,7 @@ import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
import org.geysermc.connector.entity.living.animal.AnimalEntity;
import org.geysermc.connector.entity.type.EntityType;
@ -40,6 +41,9 @@ public class AbstractHorseEntity extends AnimalEntity {
public AbstractHorseEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
super(entityId, geyserId, entityType, position, motion, rotation);
// Specifies the size of the entity's inventory. Required to place slots in the entity.
metadata.put(EntityData.CONTAINER_BASE_SIZE, 2);
}
@Override
@ -75,6 +79,9 @@ public class AbstractHorseEntity extends AnimalEntity {
entityEventPacket.setData(ItemRegistry.WHEAT.getBedrockId() << 16);
session.sendUpstreamPacket(entityEventPacket);
}
// Set container type if tamed
metadata.put(EntityData.CONTAINER_TYPE, ((xd & 0x02) == 0x02) ? (byte) ContainerType.HORSE.getId() : (byte) 0);
}
// Needed to control horses

View File

@ -27,6 +27,7 @@ package org.geysermc.connector.entity.living.animal.horse;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
@ -35,6 +36,8 @@ public class ChestedHorseEntity extends AbstractHorseEntity {
public ChestedHorseEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
super(entityId, geyserId, entityType, position, motion, rotation);
metadata.put(EntityData.CONTAINER_BASE_SIZE, 16);
}
@Override

View File

@ -38,6 +38,8 @@ public class LlamaEntity extends ChestedHorseEntity {
public LlamaEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
super(entityId, geyserId, entityType, position, motion, rotation);
metadata.put(EntityData.CONTAINER_STRENGTH_MODIFIER, 3); // Presumably 3 slots for every 1 strength
}
@Override
@ -56,7 +58,7 @@ public class LlamaEntity extends ChestedHorseEntity {
// The damage value is the dye color that Java sends us
// Always going to be a carpet so we can hardcode 171 in BlockTranslator
// The int then short conversion is required or we get a ClassCastException
equipmentPacket.setChestplate(ItemData.of(BlockTranslator.CARPET, (short)((int) entityMetadata.getValue()), 1));
equipmentPacket.setChestplate(ItemData.of(BlockTranslator.CARPET, (short) ((int) entityMetadata.getValue()), 1));
} else {
equipmentPacket.setChestplate(ItemData.AIR);
}

View File

@ -25,10 +25,8 @@
package org.geysermc.connector.inventory;
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
public class AnvilContainer extends Container {
public AnvilContainer(String title, int id, WindowType windowType, int size, PlayerInventory playerInventory) {
super(title, id, windowType, size, playerInventory);
public AnvilContainer(String title, int id, int size, PlayerInventory playerInventory) {
super(title, id, size, playerInventory);
}
}

View File

@ -25,7 +25,6 @@
package org.geysermc.connector.inventory;
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
import lombok.Getter;
import lombok.Setter;
@ -35,7 +34,7 @@ public class BeaconContainer extends Container {
private int primaryId;
private int secondaryId;
public BeaconContainer(String title, int id, WindowType windowType, int size, PlayerInventory playerInventory) {
super(title, id, windowType, size, playerInventory);
public BeaconContainer(String title, int id,int size, PlayerInventory playerInventory) {
super(title, id, size, playerInventory);
}
}

View File

@ -25,7 +25,6 @@
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;
@ -38,8 +37,8 @@ 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);
public Container(String title, int id, int size, PlayerInventory playerInventory) {
super(title, id, size);
this.playerInventory = playerInventory;
this.containerSize = this.size + InventoryTranslator.PLAYER_INVENTORY_SIZE;
}

View File

@ -25,7 +25,6 @@
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;
@ -41,8 +40,8 @@ public class EnchantingContainer extends Container {
@Getter
private final GeyserEnchantOption[] geyserEnchantOptions;
public EnchantingContainer(String title, int id, WindowType windowType, int size, PlayerInventory playerInventory) {
super(title, id, windowType, size, playerInventory);
public EnchantingContainer(String title, int id, int size, PlayerInventory playerInventory) {
super(title, id, size, playerInventory);
enchantOptions = new EnchantOptionData[3];
geyserEnchantOptions = new GeyserEnchantOption[3];

View File

@ -26,7 +26,6 @@
package org.geysermc.connector.inventory;
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
import lombok.Getter;
import lombok.Setter;
@ -36,7 +35,7 @@ public class FurnaceInventory extends Inventory {
@Setter
private int test;
public FurnaceInventory(String title, int id, WindowType windowType, int size) {
super(title, id, windowType, size);
public FurnaceInventory(String title, int id, int size) {
super(title, id, size);
}
}

View File

@ -25,7 +25,6 @@
package org.geysermc.connector.inventory;
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
import com.nukkitx.math.vector.Vector3i;
import lombok.Getter;
import lombok.NonNull;
@ -38,9 +37,6 @@ public class Inventory {
@Getter
protected int id;
@Getter
protected WindowType windowType;
@Getter
protected final int size;
@ -64,14 +60,13 @@ public class Inventory {
@Getter
protected short transactionId = 0;
protected Inventory(int id, WindowType windowType, int size) {
this("Inventory", id, windowType, size);
protected Inventory(int id, int size) {
this("Inventory", id, size);
}
protected Inventory(String title, int id, WindowType windowType, int size) {
protected Inventory(String title, int id, int size) {
this.title = title;
this.id = id;
this.windowType = windowType;
this.size = size;
this.items = new GeyserItemStack[size];
Arrays.fill(items, GeyserItemStack.EMPTY);

View File

@ -27,7 +27,6 @@
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;
@ -38,7 +37,7 @@ 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);
public MerchantContainer(String title, int id, int size, PlayerInventory playerInventory) {
super(title, id, size, playerInventory);
}
}

View File

@ -45,7 +45,7 @@ public class PlayerInventory extends Inventory {
private GeyserItemStack cursor = GeyserItemStack.EMPTY;
public PlayerInventory() {
super(0, null, 46);
super(0, 46);
heldItemSlot = 0;
}

View File

@ -83,6 +83,7 @@ import org.geysermc.connector.network.translators.EntityIdentifierRegistry;
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
import org.geysermc.connector.network.translators.chat.MessageTranslator;
import org.geysermc.connector.network.translators.collision.CollisionManager;
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
import org.geysermc.connector.network.translators.item.ItemRegistry;
import org.geysermc.connector.skin.SkinManager;
import org.geysermc.connector.utils.*;
@ -123,6 +124,9 @@ public class GeyserSession implements CommandSender {
@Setter
private Inventory openInventory;
@Setter
private InventoryTranslator inventoryTranslator = InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR;
private final AtomicInteger itemNetId = new AtomicInteger(1);
@Getter(AccessLevel.NONE)

View File

@ -43,7 +43,7 @@ public class BedrockItemStackRequestTranslator extends PacketTranslator<ItemStac
if (inventory == null)
return;
InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
InventoryTranslator translator = session.getInventoryTranslator();
session.addInventoryTask(() -> translator.translateRequests(session, inventory, packet.getRequests()));
}
}

View File

@ -38,6 +38,7 @@ import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
import com.nukkitx.protocol.bedrock.packet.InteractPacket;
import lombok.Getter;
import org.geysermc.connector.entity.Entity;
import org.geysermc.connector.entity.living.animal.horse.AbstractHorseEntity;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.inventory.GeyserItemStack;
import org.geysermc.connector.network.session.GeyserSession;
@ -357,14 +358,23 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket>
break;
case OPEN_INVENTORY:
if (session.getOpenInventory() == null) {
session.setOpenInventory(session.getPlayerInventory());
Entity ridingEntity = session.getRidingVehicleEntity();
if (ridingEntity instanceof AbstractHorseEntity) {
if (ridingEntity.getMetadata().getFlags().getFlag(EntityFlag.TAMED)) {
// We should request to open the horse inventory instead
ClientPlayerStatePacket openHorseWindowPacket = new ClientPlayerStatePacket((int)session.getPlayerEntity().getEntityId(), PlayerState.OPEN_HORSE_INVENTORY);
session.sendDownstreamPacket(openHorseWindowPacket);
}
} else {
session.setOpenInventory(session.getPlayerInventory());
ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket();
containerOpenPacket.setId((byte) 0);
containerOpenPacket.setType(ContainerType.INVENTORY);
containerOpenPacket.setUniqueEntityId(-1);
containerOpenPacket.setBlockPosition(entity.getPosition().toInt());
session.sendUpstreamPacket(containerOpenPacket);
ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket();
containerOpenPacket.setId((byte) 0);
containerOpenPacket.setType(ContainerType.INVENTORY);
containerOpenPacket.setUniqueEntityId(-1);
containerOpenPacket.setBlockPosition(entity.getPosition().toInt());
session.sendUpstreamPacket(containerOpenPacket);
}
}
break;
}

View File

@ -60,10 +60,11 @@ import java.util.*;
@AllArgsConstructor
public abstract class InventoryTranslator {
public static final InventoryTranslator PLAYER_INVENTORY_TRANSLATOR = new PlayerInventoryTranslator();
public static final Map<WindowType, InventoryTranslator> INVENTORY_TRANSLATORS = new HashMap<WindowType, InventoryTranslator>() {
{
/* Player Inventory */
put(null, new PlayerInventoryTranslator()); //player inventory
put(null, PLAYER_INVENTORY_TRANSLATOR);
/* Chest UIs */
put(WindowType.GENERIC_9X1, new SingleChestInventoryTranslator(9));
@ -95,9 +96,6 @@ public abstract class InventoryTranslator {
/* Generics */
put(WindowType.GENERIC_3X3, new GenericBlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER));
put(WindowType.HOPPER, new GenericBlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER));
/* todo */
// horse
}
};
@ -193,7 +191,7 @@ public abstract class InventoryTranslator {
int sourceSlot = bedrockSlotToJava(transferAction.getSource());
int destSlot = bedrockSlotToJava(transferAction.getDestination());
if (shouldRejectItemPlace(session, inventory, isCursor(transferAction.getSource()) ? -1 :sourceSlot, destSlot)) {
if (shouldRejectItemPlace(session, inventory, isCursor(transferAction.getSource()) ? -1 : sourceSlot, destSlot)) {
// This item would not be here in Java
return rejectRequest(request, false);
}

View File

@ -82,6 +82,6 @@ public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator {
@Override
public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) {
return new AnvilContainer(name, windowId, windowType, this.size, playerInventory);
return new AnvilContainer(name, windowId, this.size, playerInventory);
}
}

View File

@ -96,6 +96,6 @@ public abstract class BaseInventoryTranslator extends InventoryTranslator {
@Override
public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) {
return new Container(name, windowId, windowType, this.size, playerInventory);
return new Container(name, windowId, this.size, playerInventory);
}
}

View File

@ -129,6 +129,6 @@ public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator
@Override
public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) {
return new BeaconContainer(name, windowId, windowType, this.size, playerInventory);
return new BeaconContainer(name, windowId, this.size, playerInventory);
}
}

View File

@ -170,7 +170,7 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla
@Override
public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) {
return new EnchantingContainer(name, windowId, windowType, this.size, playerInventory);
return new EnchantingContainer(name, windowId, this.size, playerInventory);
}
/**

View File

@ -143,6 +143,7 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator {
ClientClickWindowButtonPacket packet = new ClientClickWindowButtonPacket(inventory.getId(), index);
System.out.println(packet);
session.sendDownstreamPacket(packet);
GeyserItemStack inputCopy = inventory.getItem(0).copy();
inputCopy.setNetId(session.getItemNetId().incrementAndGet());
// Add the pattern manually, for better item synchronization

View File

@ -149,6 +149,6 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator {
@Override
public Inventory createInventory(String name, int windowId, WindowType windowType, PlayerInventory playerInventory) {
return new MerchantContainer(name, windowId, windowType, this.size, playerInventory);
return new MerchantContainer(name, windowId, this.size, playerInventory);
}
}

View File

@ -57,6 +57,7 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl
@Override
public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequestPacket.Request request) {
// TODO: Also surely to change in the future
// TODO: don't spam the ClickWindowButtonPacket?
StackRequestActionData data = request.getActions()[1];
if (!(data instanceof CraftResultsDeprecatedStackRequestActionData)) {
return rejectRequest(request);

View File

@ -0,0 +1,66 @@
/*
* 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.translators.horse;
import org.geysermc.connector.inventory.Inventory;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.inventory.translators.BaseInventoryTranslator;
import org.geysermc.connector.network.translators.inventory.updater.HorseInventoryUpdater;
import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
public abstract class AbstractHorseInventoryTranslator extends BaseInventoryTranslator {
private final InventoryUpdater updater;
public AbstractHorseInventoryTranslator(int size) {
super(size);
this.updater = HorseInventoryUpdater.INSTANCE;
}
@Override
public void prepareInventory(GeyserSession session, Inventory inventory) {
}
@Override
public void openInventory(GeyserSession session, Inventory inventory) {
}
@Override
public void closeInventory(GeyserSession session, Inventory 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);
}
}

View File

@ -0,0 +1,112 @@
/*
* 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.translators.horse;
import com.nukkitx.protocol.bedrock.data.inventory.ContainerId;
import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType;
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData;
import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket;
import org.geysermc.connector.inventory.Inventory;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot;
import java.util.Arrays;
public abstract class ChestedHorseInventoryTranslator extends AbstractHorseInventoryTranslator {
private final int chestSize;
private final int equipSlot;
/**
* @param size the total Java size of the inventory
* @param equipSlot the Java equipment slot. For
*/
public ChestedHorseInventoryTranslator(int size, int equipSlot) {
super(size);
this.chestSize = size - 2;
this.equipSlot = equipSlot;
}
@Override
public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
if (slotInfoData.getContainer() == ContainerSlotType.HORSE_EQUIP) {
return this.equipSlot;
}
if (slotInfoData.getContainer() == ContainerSlotType.CONTAINER) {
return slotInfoData.getSlot() + 1;
}
return super.bedrockSlotToJava(slotInfoData);
}
@Override
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
if (slot == this.equipSlot) {
return new BedrockContainerSlot(ContainerSlotType.HORSE_EQUIP, 0);
}
if (slot <= this.size) {
return new BedrockContainerSlot(ContainerSlotType.CONTAINER, slot - 1);
}
return super.javaSlotToBedrockContainer(slot);
}
@Override
public int javaSlotToBedrock(int slot) {
if (slot == 0 && this.equipSlot == 0) {
return 0;
}
if (slot <= this.size) {
return slot - 1;
}
return super.javaSlotToBedrock(slot);
}
@Override
public void updateInventory(GeyserSession session, Inventory inventory) {
ItemData[] bedrockItems = new ItemData[36];
for (int i = 0; i < 36; i++) {
final int offset = i < 9 ? 27 : -9;
bedrockItems[i] = inventory.getItem(this.size + i + offset).getItemData(session);
}
InventoryContentPacket contentPacket = new InventoryContentPacket();
contentPacket.setContainerId(ContainerId.INVENTORY);
contentPacket.setContents(Arrays.asList(bedrockItems));
session.sendUpstreamPacket(contentPacket);
ItemData[] horseItems = new ItemData[chestSize + 1];
// Manually specify the first slot - Java always has two slots (armor and saddle) and one is invisible.
// Bedrock doesn't have this invisible slot.
horseItems[0] = inventory.getItem(this.equipSlot).getItemData(session);
for (int i = 1; i < horseItems.length; i++) {
horseItems[i] = inventory.getItem(i + 1).getItemData(session);
}
InventoryContentPacket llamaPacket = new InventoryContentPacket();
llamaPacket.setContainerId(inventory.getId());
llamaPacket.setContents(Arrays.asList(horseItems));
System.out.println(llamaPacket);
session.sendUpstreamPacket(llamaPacket);
}
}

View File

@ -0,0 +1,32 @@
/*
* 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.translators.horse;
public class DonkeyInventoryTranslator extends ChestedHorseInventoryTranslator {
public DonkeyInventoryTranslator(int size) {
super(size, 0);
}
}

View File

@ -0,0 +1,52 @@
/*
* 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.translators.horse;
import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType;
import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData;
import org.geysermc.connector.network.translators.inventory.BedrockContainerSlot;
public class HorseInventoryTranslator extends AbstractHorseInventoryTranslator {
public HorseInventoryTranslator(int size) {
super(size);
}
@Override
public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) {
if (slotInfoData.getContainer() == ContainerSlotType.HORSE_EQUIP) {
return slotInfoData.getSlot();
}
return super.bedrockSlotToJava(slotInfoData);
}
@Override
public BedrockContainerSlot javaSlotToBedrockContainer(int slot) {
if (slot == 0 || slot == 1) {
return new BedrockContainerSlot(ContainerSlotType.HORSE_EQUIP, slot);
}
return super.javaSlotToBedrockContainer(slot);
}
}

View File

@ -0,0 +1,32 @@
/*
* 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.translators.horse;
public class LlamaInventoryTranslator extends ChestedHorseInventoryTranslator {
public LlamaInventoryTranslator(int size) {
super(size, 1);
}
}

View File

@ -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.network.translators.inventory.updater;
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket;
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
import org.geysermc.connector.inventory.Inventory;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
import java.util.Arrays;
public class HorseInventoryUpdater extends InventoryUpdater {
public static final HorseInventoryUpdater INSTANCE = new HorseInventoryUpdater();
@Override
public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {
super.updateInventory(translator, session, inventory);
ItemData[] bedrockItems = new ItemData[translator.size];
for (int i = 0; i < bedrockItems.length; i++) {
bedrockItems[translator.javaSlotToBedrock(i)] = inventory.getItem(i).getItemData(session);
}
InventoryContentPacket contentPacket = new InventoryContentPacket();
contentPacket.setContainerId(inventory.getId());
contentPacket.setContents(Arrays.asList(bedrockItems));
session.sendUpstreamPacket(contentPacket);
}
@Override
public boolean updateSlot(InventoryTranslator translator, GeyserSession session, Inventory inventory, int javaSlot) {
if (super.updateSlot(translator, session, inventory, javaSlot))
return true;
InventorySlotPacket slotPacket = new InventorySlotPacket();
slotPacket.setContainerId(4); // Horse GUI?
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
slotPacket.setItem(inventory.getItem(javaSlot).getItemData(session));
session.sendUpstreamPacket(slotPacket);
System.out.println(slotPacket);
return true;
}
}

View File

@ -32,7 +32,6 @@ import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
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.item.ItemTranslator;
import java.util.Arrays;

View File

@ -26,7 +26,6 @@
package org.geysermc.connector.network.translators.java.window;
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerCloseWindowPacket;
import org.geysermc.connector.inventory.Inventory;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
@ -37,8 +36,6 @@ public class JavaCloseWindowTranslator extends PacketTranslator<ServerCloseWindo
@Override
public void translate(ServerCloseWindowPacket packet, GeyserSession session) {
session.addInventoryTask(() -> {
InventoryUtils.closeInventory(session, packet.getWindowId());
});
session.addInventoryTask(() -> InventoryUtils.closeInventory(session, packet.getWindowId()));
}
}

View File

@ -0,0 +1,139 @@
/*
* 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.java.window;
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerOpenHorseWindowPacket;
import com.nukkitx.nbt.NbtMap;
import com.nukkitx.nbt.NbtMapBuilder;
import com.nukkitx.nbt.NbtType;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
import com.nukkitx.protocol.bedrock.packet.UpdateEquipPacket;
import org.geysermc.connector.entity.Entity;
import org.geysermc.connector.entity.living.animal.horse.ChestedHorseEntity;
import org.geysermc.connector.entity.living.animal.horse.LlamaEntity;
import org.geysermc.connector.inventory.Container;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
import org.geysermc.connector.network.translators.inventory.translators.horse.DonkeyInventoryTranslator;
import org.geysermc.connector.network.translators.inventory.translators.horse.HorseInventoryTranslator;
import org.geysermc.connector.network.translators.inventory.translators.horse.LlamaInventoryTranslator;
import org.geysermc.connector.utils.InventoryUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@Translator(packet = ServerOpenHorseWindowPacket.class)
public class JavaOpenHorseWindowTranslator extends PacketTranslator<ServerOpenHorseWindowPacket> {
private static final NbtMap ARMOR_SLOT;
private static final NbtMap CARPET_SLOT;
private static final NbtMap SADDLE_SLOT;
static {
// Build the NBT mappings that Bedrock wants to lay out the GUI
String[] acceptedHorseArmorIdentifiers = new String[] {"minecraft:horsearmorleather", "minecraft:horsearmoriron",
"minecraft:horsearmorgold", "minecraft:horsearmordiamond"};
NbtMapBuilder armorBuilder = NbtMap.builder();
List<NbtMap> acceptedArmors = new ArrayList<>();
for (String identifier : acceptedHorseArmorIdentifiers) {
NbtMapBuilder acceptedItemBuilder = NbtMap.builder()
.putShort("Aux", Short.MAX_VALUE)
.putString("Name", identifier);
acceptedArmors.add(NbtMap.builder().putCompound("slotItem", acceptedItemBuilder.build()).build());
}
armorBuilder.putList("acceptedItems", NbtType.COMPOUND, acceptedArmors);
NbtMapBuilder armorItem = NbtMap.builder()
.putShort("Aux", Short.MAX_VALUE)
.putString("Name", "minecraft:horsearmoriron");
armorBuilder.putCompound("item", armorItem.build());
armorBuilder.putInt("slotNumber", 1);
ARMOR_SLOT = armorBuilder.build();
NbtMapBuilder carpetBuilder = NbtMap.builder();
NbtMapBuilder carpetItem = NbtMap.builder()
.putShort("Aux", Short.MAX_VALUE)
.putString("Name", "minecraft:carpet");
List<NbtMap> acceptedCarpet = Collections.singletonList(NbtMap.builder().putCompound("slotItem", carpetItem.build()).build());
carpetBuilder.putList("acceptedItems", NbtType.COMPOUND, acceptedCarpet);
carpetBuilder.putCompound("item", carpetItem.build());
carpetBuilder.putInt("slotNumber", 1);
CARPET_SLOT = carpetBuilder.build();
NbtMapBuilder saddleBuilder = NbtMap.builder();
NbtMapBuilder acceptedSaddle = NbtMap.builder()
.putShort("Aux", Short.MAX_VALUE)
.putString("Name", "minecraft:saddle");
List<NbtMap> acceptedItem = Collections.singletonList(NbtMap.builder().putCompound("slotItem", acceptedSaddle.build()).build());
saddleBuilder.putList("acceptedItems", NbtType.COMPOUND, acceptedItem);
saddleBuilder.putCompound("item", acceptedSaddle.build());
saddleBuilder.putInt("slotNumber", 0);
SADDLE_SLOT = saddleBuilder.build();
}
@Override
public void translate(ServerOpenHorseWindowPacket packet, GeyserSession session) {
System.out.println(packet.toString());
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
if (entity == null) {
return;
}
UpdateEquipPacket updateEquipPacket = new UpdateEquipPacket();
updateEquipPacket.setWindowId((short) packet.getWindowId());
updateEquipPacket.setWindowType((short) ContainerType.HORSE.getId());
updateEquipPacket.setUniqueEntityId(entity.getGeyserId());
NbtMapBuilder builder = NbtMap.builder();
List<NbtMap> slots = new ArrayList<>();
InventoryTranslator inventoryTranslator;
if (entity instanceof LlamaEntity) {
inventoryTranslator = new LlamaInventoryTranslator(packet.getNumberOfSlots());
slots.add(CARPET_SLOT);
} else if (entity instanceof ChestedHorseEntity) {
inventoryTranslator = new DonkeyInventoryTranslator(packet.getNumberOfSlots());
slots.add(SADDLE_SLOT);
} else {
inventoryTranslator = new HorseInventoryTranslator(packet.getNumberOfSlots());
slots.add(SADDLE_SLOT);
slots.add(ARMOR_SLOT);
}
// Build the NbtMap that sets the icons for Bedrock (e.g. sets the saddle outline on the saddle slot)
builder.putList("slots", NbtType.COMPOUND, slots);
updateEquipPacket.setTag(builder.build());
System.out.println(updateEquipPacket);
session.sendUpstreamPacket(updateEquipPacket);
session.setInventoryTranslator(inventoryTranslator);
InventoryUtils.openInventory(session, new Container(entity.getMetadata().getString(EntityData.NAMETAG), packet.getWindowId(), packet.getNumberOfSlots(), session.getPlayerInventory()));
}
}

View File

@ -63,12 +63,13 @@ public class JavaOpenWindowTranslator extends PacketTranslator<ServerOpenWindowP
Inventory newInventory = newTranslator.createInventory(name, packet.getWindowId(), packet.getType(), session.getPlayerInventory());
if (openInventory != null) {
InventoryTranslator openTranslator = InventoryTranslator.INVENTORY_TRANSLATORS.get(openInventory.getWindowType());
InventoryTranslator openTranslator = session.getInventoryTranslator();
if (!openTranslator.getClass().equals(newTranslator.getClass())) {
InventoryUtils.closeInventory(session, openInventory.getId());
}
}
session.setInventoryTranslator(newTranslator);
InventoryUtils.openInventory(session, newInventory);
});
}

View File

@ -59,7 +59,7 @@ public class JavaSetSlotTranslator extends PacketTranslator<ServerSetSlotPacket>
if (inventory == null)
return;
InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
InventoryTranslator translator = session.getInventoryTranslator();
if (translator != null) {
GeyserItemStack newItem = GeyserItemStack.from(packet.getItem());
GeyserItemStack oldItem = inventory.getItem(packet.getSlot());

View File

@ -26,7 +26,6 @@
package org.geysermc.connector.network.translators.java.window;
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerWindowItemsPacket;
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
import org.geysermc.connector.inventory.GeyserItemStack;
import org.geysermc.connector.inventory.Inventory;
import org.geysermc.connector.network.session.GeyserSession;
@ -56,7 +55,7 @@ public class JavaWindowItemsTranslator extends PacketTranslator<ServerWindowItem
inventory.setItem(i, newItem);
}
InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
InventoryTranslator translator = session.getInventoryTranslator();
if (translator != null) {
translator.updateInventory(session, inventory);
}

View File

@ -44,7 +44,7 @@ public class JavaWindowPropertyTranslator extends PacketTranslator<ServerWindowP
if (inventory == null)
return;
InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
InventoryTranslator translator = session.getInventoryTranslator();
if (translator != null) {
translator.updateProperty(session, inventory, packet.getRawProperty(), packet.getValue());
}

View File

@ -56,7 +56,7 @@ public class InventoryUtils {
public static final ItemStack REFRESH_ITEM = new ItemStack(1, 127, new CompoundTag(""));
public static void openInventory(GeyserSession session, Inventory inventory) {
InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
InventoryTranslator translator = session.getInventoryTranslator();
if (translator != null) {
session.setOpenInventory(inventory);
translator.prepareInventory(session, inventory);
@ -84,10 +84,11 @@ public class InventoryUtils {
Inventory inventory = getInventory(session, windowId);
if (inventory != null) {
InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
InventoryTranslator translator = session.getInventoryTranslator();
translator.closeInventory(session, inventory);
session.setLastWindowCloseTime(System.currentTimeMillis());
}
session.setInventoryTranslator(InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR);
session.setOpenInventory(null);
}