From 30e38b3a2f30ebd61dbd70e6cb9e1b5769eb41c4 Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sat, 16 May 2020 23:52:39 -0500 Subject: [PATCH 1/5] Add basic villager trading support (incomplete) This commit implements basic functionality for villager trading. This is still incomplete and is buggy in areas such as with villager trades that have more than one input and trade inputs and outputs containing NBT. Co-authored-by: DoctorMacc --- .../living/merchant/VillagerEntity.java | 7 + .../network/session/GeyserSession.java | 10 ++ .../network/translators/Translators.java | 1 + ...BedrockInventoryTransactionTranslator.java | 5 + .../MerchantInventoryTranslator.java | 170 ++++++++++++++++++ .../translators/item/ItemTranslator.java | 45 +++++ .../java/world/JavaTradeListTranslator.java | 115 ++++++++++++ 7 files changed, 353 insertions(+) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/merchant/VillagerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/merchant/VillagerEntity.java index 895f8cc1d41..adb362e0da7 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/merchant/VillagerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/merchant/VillagerEntity.java @@ -27,10 +27,13 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.VillagerData; +import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.EntityData; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; +import lombok.Getter; +import lombok.Setter; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; @@ -66,6 +69,10 @@ public class VillagerEntity extends AbstractMerchantEntity { VILLAGER_REGIONS.put(6, 6); } + @Getter + @Setter + private VillagerTrade[] villagerTrades; + public VillagerEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); } diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index fa9960f2e22..ea34bef6866 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -30,6 +30,7 @@ import com.github.steveice10.mc.auth.exception.request.RequestException; import com.github.steveice10.mc.protocol.MinecraftProtocol; import com.github.steveice10.mc.protocol.data.SubProtocol; +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.world.block.BlockState; import com.github.steveice10.mc.protocol.packet.handshake.client.HandshakePacket; @@ -149,9 +150,18 @@ public class GeyserSession implements CommandSender { @Setter private boolean interacting; + @Setter + private long lastInteractedVillagerEid; + @Setter private Vector3i lastInteractionPosition; + @Setter + private ItemStack firstTradeSlot; + + @Setter + private ItemStack secondTradeSlot; + @Setter private boolean switchingDimension = false; private boolean manyDimPackets = false; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/Translators.java b/connector/src/main/java/org/geysermc/connector/network/translators/Translators.java index 03042e3a4e6..376d0f43982 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/Translators.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/Translators.java @@ -159,6 +159,7 @@ private static void registerInventoryTranslators() { inventoryTranslators.put(WindowType.ANVIL, new AnvilInventoryTranslator()); inventoryTranslators.put(WindowType.CRAFTING, new CraftingInventoryTranslator()); inventoryTranslators.put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator()); + inventoryTranslators.put(WindowType.MERCHANT, new MerchantInventoryTranslator()); //inventoryTranslators.put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator()); //TODO InventoryTranslator furnace = new FurnaceInventoryTranslator(); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java index 71ba20e4805..20b19432bb2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java @@ -44,6 +44,7 @@ import org.geysermc.connector.entity.Entity; import org.geysermc.connector.entity.ItemFrameEntity; +import org.geysermc.connector.entity.living.merchant.VillagerEntity; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; @@ -187,6 +188,10 @@ public void translate(InventoryTransactionPacket packet, GeyserSession session) session.sendDownstreamPacket(interactAtPacket); EntitySoundInteractionHandler.handleEntityInteraction(session, vector, entity); + + if (entity instanceof VillagerEntity) { + session.setLastInteractedVillagerEid(packet.getRuntimeEntityId()); + } break; case 1: //Attack ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(), diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java new file mode 100644 index 00000000000..5d1ce122e92 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java @@ -0,0 +1,170 @@ +/* + * 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.data.game.window.ClickItemParam; +import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade; +import com.github.steveice10.mc.protocol.data.game.window.WindowAction; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientSelectTradePacket; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientWindowActionPacket; +import com.nukkitx.protocol.bedrock.data.ContainerId; +import com.nukkitx.protocol.bedrock.data.InventoryActionData; +import org.geysermc.connector.entity.living.merchant.VillagerEntity; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.Translators; +import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater; +import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; + +import java.util.List; + +public class MerchantInventoryTranslator extends BaseInventoryTranslator { + + private final InventoryUpdater updater; + + public MerchantInventoryTranslator() { + super(3); + this.updater = new CursorInventoryUpdater(); + } + + @Override + public int javaSlotToBedrock(int slot) { + switch (slot) { + case 0: + return 4; + case 1: + return 5; + case 2: + return 50; + } + return super.javaSlotToBedrock(slot); + } + + @Override + public int bedrockSlotToJava(InventoryActionData action) { + if (action.getSource().getContainerId() == ContainerId.CURSOR) { + switch (action.getSlot()) { + case 4: + return 0; + case 5: + return 1; + case 50: + return 2; + } + } + return super.bedrockSlotToJava(action); + } + + @Override + public void prepareInventory(GeyserSession session, Inventory inventory) { + + } + + @Override + public void openInventory(GeyserSession session, Inventory inventory) { + + } + + @Override + public void closeInventory(GeyserSession session, Inventory inventory) { + session.setLastInteractedVillagerEid(-1); + session.setFirstTradeSlot(null); + session.setSecondTradeSlot(null); + } + + @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); + } + + @Override + public void translateActions(GeyserSession session, Inventory inventory, List actions) { + InventoryActionData result = null; + + VillagerEntity villager = (VillagerEntity) session.getEntityCache().getEntityByGeyserId(session.getLastInteractedVillagerEid()); + if (villager == null) { + session.getConnector().getLogger().debug("Could not find villager with entity id: " + session.getLastInteractedVillagerEid()); + return; + } + + // We need to store the trade slot data in the session itself as data + // needs to persist beyond this translateActions method since the client + // sends multiple packets for this + for (InventoryActionData data : actions) { + if (data.getSlot() == 4 && session.getFirstTradeSlot() == null && data.getSource().getContainerId() == ContainerId.CURSOR) { + session.setFirstTradeSlot(Translators.getItemTranslator().translateToJava(session, data.getToItem())); + } + + if (data.getSlot() == 5 && session.getSecondTradeSlot() == null && data.getToItem() != null && data.getSource().getContainerId() == ContainerId.CURSOR) { + session.setSecondTradeSlot(Translators.getItemTranslator().translateToJava(session, data.getToItem())); + } + if (data.getSlot() == 50 && result == null) { + result = data; + } + } + + if (result == null || session.getFirstTradeSlot() == null) { + super.translateActions(session, inventory, actions); + return; + } + + ItemStack resultSlot = Translators.getItemTranslator().translateToJava(session, result.getToItem()); + for (int i = 0; i < villager.getVillagerTrades().length; i++) { + VillagerTrade trade = villager.getVillagerTrades()[i]; + if (!Translators.getItemTranslator().equals(session.getFirstTradeSlot(), trade.getFirstInput(), true, true, false) || !Translators.getItemTranslator().equals(resultSlot, trade.getOutput(), true, false, false)) { + continue; + } + + if (session.getSecondTradeSlot() != null && trade.getSecondInput() != null && !Translators.getItemTranslator().equals(session.getSecondTradeSlot(), trade.getSecondInput(), true, false, false)) { + continue; + } + + ClientSelectTradePacket selectTradePacket = new ClientSelectTradePacket(i); + session.sendDownstreamPacket(selectTradePacket); + + ClientWindowActionPacket tradeAction = new ClientWindowActionPacket( + inventory.getId(), + inventory.getTransactionId().getAndIncrement(), + this.bedrockSlotToJava(result), + null, + WindowAction.CLICK_ITEM, + ClickItemParam.LEFT_CLICK + ); + session.sendDownstreamPacket(tradeAction); + break; + + } + + super.translateActions(session, inventory, actions); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java index f59b82ba026..28c5345ab81 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java @@ -160,6 +160,51 @@ public ItemEntry getItemEntry(String javaIdentifier) { .stream().filter(itemEntry -> itemEntry.getJavaIdentifier().equals(key)).findFirst().orElse(null)); } + /** + * Checks if an {@link ItemStack} is equal to another item stack + * + * @param itemStack the item stack to check + * @param equalsItemStack the item stack to check if equal to + * @param checkAmount if the amount should be taken into account + * @param trueIfAmountIsGreater if this should return true if the amount of the + * first item stack is greater than that of the second + * @param checkNbt if NBT data should be checked + * @return if an item stack is equal to another item stack + */ + public boolean equals(ItemStack itemStack, ItemStack equalsItemStack, boolean checkAmount, boolean trueIfAmountIsGreater, boolean checkNbt) { + if (itemStack.getId() != equalsItemStack.getId()) { + return false; + } + if (checkAmount) { + if (trueIfAmountIsGreater) { + if (itemStack.getAmount() < equalsItemStack.getAmount()) { + return false; + } + } else { + if (itemStack.getAmount() != equalsItemStack.getAmount()) { + return false; + } + } + } + + if (!checkNbt) { + return true; + } + if ((itemStack.getNbt() == null || itemStack.getNbt().isEmpty()) && (equalsItemStack.getNbt() != null && !equalsItemStack.getNbt().isEmpty())) { + return false; + } + + if ((itemStack.getNbt() != null && !itemStack.getNbt().isEmpty() && (equalsItemStack.getNbt() == null || !equalsItemStack.getNbt().isEmpty()))) { + return false; + } + + if (itemStack.getNbt() != null && equalsItemStack.getNbt() != null) { + return itemStack.getNbt().equals(equalsItemStack.getNbt()); + } + + return true; + } + private static final ItemStackTranslator DEFAULT_TRANSLATOR = new ItemStackTranslator() { @Override public List getAppliedItems() { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java new file mode 100644 index 00000000000..b156ef83988 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java @@ -0,0 +1,115 @@ +/* + * 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.world; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade; +import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerTradeListPacket; +import com.nukkitx.nbt.CompoundTagBuilder; +import com.nukkitx.nbt.tag.CompoundTag; +import com.nukkitx.protocol.bedrock.data.ContainerType; +import com.nukkitx.protocol.bedrock.data.EntityData; +import com.nukkitx.protocol.bedrock.data.ItemData; +import com.nukkitx.protocol.bedrock.packet.UpdateTradePacket; +import org.geysermc.connector.entity.living.merchant.VillagerEntity; +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.Translators; +import org.geysermc.connector.network.translators.item.ItemEntry; + +import java.util.ArrayList; +import java.util.List; + +@Translator(packet = ServerTradeListPacket.class) +public class JavaTradeListTranslator extends PacketTranslator { + + @Override + public void translate(ServerTradeListPacket packet, GeyserSession session) { + VillagerEntity villager = (VillagerEntity) session.getEntityCache().getEntityByGeyserId(session.getLastInteractedVillagerEid()); + if (villager == null) { + session.getConnector().getLogger().debug("Could not find villager with entity id: " + session.getLastInteractedVillagerEid()); + return; + } + villager.setVillagerTrades(packet.getTrades()); + villager.getMetadata().put(EntityData.TRADE_XP, packet.getExperience()); + villager.getMetadata().put(EntityData.TRADE_TIER, packet.getVillagerLevel() - 1); + villager.updateBedrockMetadata(session); + + UpdateTradePacket updateTradePacket = new UpdateTradePacket(); + updateTradePacket.setTradeTier(packet.getVillagerLevel() + 1); + updateTradePacket.setWindowId((short) packet.getWindowId()); + updateTradePacket.setWindowType((short) ContainerType.TRADING.id()); + updateTradePacket.setDisplayName("Villager"); + updateTradePacket.setUnknownInt(0); + updateTradePacket.setScreen2(true); + updateTradePacket.setWilling(true); + updateTradePacket.setPlayerUniqueEntityId(session.getPlayerEntity().getGeyserId()); + updateTradePacket.setTraderUniqueEntityId(session.getLastInteractedVillagerEid()); + CompoundTagBuilder builder = CompoundTagBuilder.builder(); + List tags = new ArrayList<>(); + for (VillagerTrade trade : packet.getTrades()) { + CompoundTagBuilder recipe = CompoundTagBuilder.builder(); + recipe.intTag("maxUses", trade.getMaxUses()); + recipe.intTag("traderExp", packet.getExperience()); + recipe.floatTag("priceMultiplierA", trade.getPriceMultiplier()); + recipe.tag(getItemTag(session, trade.getOutput(), "sell")); + recipe.floatTag("priceMultiplierB", 0.0f); + recipe.intTag("buyCountB", 0); + recipe.intTag("buyCountA", trade.getOutput().getAmount()); + recipe.intTag("demand", trade.getDemand()); + recipe.intTag("tier", packet.getVillagerLevel() - 1); + recipe.tag(getItemTag(session, trade.getFirstInput(), "buyA")); + if (trade.getSecondInput() != null) { + recipe.tag(getItemTag(session, trade.getSecondInput(), "buyB")); + } + recipe.intTag("uses", trade.getNumUses()); + recipe.byteTag("rewardExp", (byte) trade.getXp()); + tags.add(recipe.buildRootTag()); + } + builder.listTag("Recipes", CompoundTag.class, tags); + List expTags = new ArrayList<>(); + expTags.add(CompoundTagBuilder.builder().intTag("0", 0).buildRootTag()); + expTags.add(CompoundTagBuilder.builder().intTag("1", 10).buildRootTag()); + expTags.add(CompoundTagBuilder.builder().intTag("2", 60).buildRootTag()); + expTags.add(CompoundTagBuilder.builder().intTag("3", 160).buildRootTag()); + expTags.add(CompoundTagBuilder.builder().intTag("4", 310).buildRootTag()); + builder.listTag("TierExpRequirements", CompoundTag.class, expTags); + updateTradePacket.setOffers(builder.buildRootTag()); + session.sendUpstreamPacket(updateTradePacket); + } + + private CompoundTag getItemTag(GeyserSession session, ItemStack stack, String name) { + ItemData itemData = Translators.getItemTranslator().translateToBedrock(session, stack); + ItemEntry itemEntry = Translators.getItemTranslator().getItem(stack); + CompoundTagBuilder builder = CompoundTagBuilder.builder(); + builder.byteTag("Count", (byte) itemData.getCount()); + builder.shortTag("Damage", itemData.getDamage()); + builder.stringTag("Name", itemEntry.getJavaIdentifier()); + return builder.build(name); + } +} From e2d46c3d490f62d0c5b6a8518e0f962dc7505c77 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Mon, 18 May 2020 21:15:29 -0800 Subject: [PATCH 2/5] Work on villager trading --- .../network/session/GeyserSession.java | 6 -- .../bedrock/BedrockEntityEventTranslator.java | 22 ++++++ .../MerchantInventoryTranslator.java | 75 +++---------------- .../java/world/JavaTradeListTranslator.java | 54 +++++++++---- 4 files changed, 72 insertions(+), 85 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index ea34bef6866..1bf506e7ff0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -156,12 +156,6 @@ public class GeyserSession implements CommandSender { @Setter private Vector3i lastInteractionPosition; - @Setter - private ItemStack firstTradeSlot; - - @Setter - private ItemStack secondTradeSlot; - @Setter private boolean switchingDimension = false; private boolean manyDimPackets = false; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityEventTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityEventTranslator.java index f97dc3c6b6a..c7d1ae670d0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityEventTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityEventTranslator.java @@ -26,7 +26,12 @@ package org.geysermc.connector.network.translators.bedrock; +import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade; +import com.github.steveice10.mc.protocol.data.game.window.WindowType; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientSelectTradePacket; import com.nukkitx.protocol.bedrock.packet.EntityEventPacket; +import org.geysermc.connector.entity.living.merchant.VillagerEntity; +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; @@ -41,6 +46,23 @@ public void translate(EntityEventPacket packet, GeyserSession session) { case EATING_ITEM: session.sendUpstreamPacket(packet); return; + case COMPLETE_TRADE: + ClientSelectTradePacket selectTradePacket = new ClientSelectTradePacket(packet.getData()); + session.getDownstream().getSession().send(selectTradePacket); + + VillagerEntity villager = (VillagerEntity) session.getEntityCache().getEntityByGeyserId(session.getLastInteractedVillagerEid()); + if (villager == null) { + session.getConnector().getLogger().debug("Could not find villager with entity id: " + session.getLastInteractedVillagerEid()); + return; + } + Inventory openInventory = session.getInventoryCache().getOpenInventory(); + if (openInventory != null && openInventory.getWindowType() == WindowType.MERCHANT) { + if (packet.getData() > 0 && packet.getData() < villager.getVillagerTrades().length) { + VillagerTrade trade = villager.getVillagerTrades()[packet.getData()]; + openInventory.setItem(2, trade.getOutput()); + } + } + return; } session.getConnector().getLogger().debug("Did not translate incoming EntityEventPacket: " + packet.toString()); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java index 5d1ce122e92..7e3f24bd230 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java @@ -26,18 +26,11 @@ 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.ClickItemParam; -import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade; -import com.github.steveice10.mc.protocol.data.game.window.WindowAction; -import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientSelectTradePacket; -import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientWindowActionPacket; import com.nukkitx.protocol.bedrock.data.ContainerId; import com.nukkitx.protocol.bedrock.data.InventoryActionData; -import org.geysermc.connector.entity.living.merchant.VillagerEntity; +import com.nukkitx.protocol.bedrock.data.InventorySource; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.Translators; import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater; import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; @@ -80,6 +73,14 @@ public int bedrockSlotToJava(InventoryActionData action) { return super.bedrockSlotToJava(action); } + @Override + public SlotType getSlotType(int javaSlot) { + if (javaSlot == 2) { + return SlotType.OUTPUT; + } + return SlotType.NORMAL; + } + @Override public void prepareInventory(GeyserSession session, Inventory inventory) { @@ -93,8 +94,6 @@ public void openInventory(GeyserSession session, Inventory inventory) { @Override public void closeInventory(GeyserSession session, Inventory inventory) { session.setLastInteractedVillagerEid(-1); - session.setFirstTradeSlot(null); - session.setSecondTradeSlot(null); } @Override @@ -109,62 +108,12 @@ public void updateSlot(GeyserSession session, Inventory inventory, int slot) { @Override public void translateActions(GeyserSession session, Inventory inventory, List actions) { - InventoryActionData result = null; - - VillagerEntity villager = (VillagerEntity) session.getEntityCache().getEntityByGeyserId(session.getLastInteractedVillagerEid()); - if (villager == null) { - session.getConnector().getLogger().debug("Could not find villager with entity id: " + session.getLastInteractedVillagerEid()); - return; - } - - // We need to store the trade slot data in the session itself as data - // needs to persist beyond this translateActions method since the client - // sends multiple packets for this - for (InventoryActionData data : actions) { - if (data.getSlot() == 4 && session.getFirstTradeSlot() == null && data.getSource().getContainerId() == ContainerId.CURSOR) { - session.setFirstTradeSlot(Translators.getItemTranslator().translateToJava(session, data.getToItem())); - } - - if (data.getSlot() == 5 && session.getSecondTradeSlot() == null && data.getToItem() != null && data.getSource().getContainerId() == ContainerId.CURSOR) { - session.setSecondTradeSlot(Translators.getItemTranslator().translateToJava(session, data.getToItem())); - } - if (data.getSlot() == 50 && result == null) { - result = data; + for (InventoryActionData action : actions) { + if (action.getSource().getType() == InventorySource.Type.NON_IMPLEMENTED_TODO) { + return; } } - if (result == null || session.getFirstTradeSlot() == null) { - super.translateActions(session, inventory, actions); - return; - } - - ItemStack resultSlot = Translators.getItemTranslator().translateToJava(session, result.getToItem()); - for (int i = 0; i < villager.getVillagerTrades().length; i++) { - VillagerTrade trade = villager.getVillagerTrades()[i]; - if (!Translators.getItemTranslator().equals(session.getFirstTradeSlot(), trade.getFirstInput(), true, true, false) || !Translators.getItemTranslator().equals(resultSlot, trade.getOutput(), true, false, false)) { - continue; - } - - if (session.getSecondTradeSlot() != null && trade.getSecondInput() != null && !Translators.getItemTranslator().equals(session.getSecondTradeSlot(), trade.getSecondInput(), true, false, false)) { - continue; - } - - ClientSelectTradePacket selectTradePacket = new ClientSelectTradePacket(i); - session.sendDownstreamPacket(selectTradePacket); - - ClientWindowActionPacket tradeAction = new ClientWindowActionPacket( - inventory.getId(), - inventory.getTransactionId().getAndIncrement(), - this.bedrockSlotToJava(result), - null, - WindowAction.CLICK_ITEM, - ClickItemParam.LEFT_CLICK - ); - session.sendDownstreamPacket(tradeAction); - break; - - } - super.translateActions(session, inventory, actions); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java index b156ef83988..7ba20d1a6c7 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java @@ -56,12 +56,13 @@ public void translate(ServerTradeListPacket packet, GeyserSession session) { return; } villager.setVillagerTrades(packet.getTrades()); - villager.getMetadata().put(EntityData.TRADE_XP, packet.getExperience()); villager.getMetadata().put(EntityData.TRADE_TIER, packet.getVillagerLevel() - 1); + villager.getMetadata().put(EntityData.MAX_TRADE_TIER, 4); + villager.getMetadata().put(EntityData.TRADE_XP, packet.getExperience()); villager.updateBedrockMetadata(session); UpdateTradePacket updateTradePacket = new UpdateTradePacket(); - updateTradePacket.setTradeTier(packet.getVillagerLevel() + 1); + updateTradePacket.setTradeTier(packet.getVillagerLevel() - 1); updateTradePacket.setWindowId((short) packet.getWindowId()); updateTradePacket.setWindowType((short) ContainerType.TRADING.id()); updateTradePacket.setDisplayName("Villager"); @@ -75,41 +76,62 @@ public void translate(ServerTradeListPacket packet, GeyserSession session) { for (VillagerTrade trade : packet.getTrades()) { CompoundTagBuilder recipe = CompoundTagBuilder.builder(); recipe.intTag("maxUses", trade.getMaxUses()); - recipe.intTag("traderExp", packet.getExperience()); + recipe.intTag("traderExp", trade.getXp()); recipe.floatTag("priceMultiplierA", trade.getPriceMultiplier()); - recipe.tag(getItemTag(session, trade.getOutput(), "sell")); + recipe.tag(getItemTag(session, trade.getOutput(), "sell", 0)); recipe.floatTag("priceMultiplierB", 0.0f); - recipe.intTag("buyCountB", 0); - recipe.intTag("buyCountA", trade.getOutput().getAmount()); + recipe.intTag("buyCountB", trade.getSecondInput() != null ? trade.getSecondInput().getAmount() : 0); + recipe.intTag("buyCountA", trade.getFirstInput().getAmount()); recipe.intTag("demand", trade.getDemand()); recipe.intTag("tier", packet.getVillagerLevel() - 1); - recipe.tag(getItemTag(session, trade.getFirstInput(), "buyA")); + recipe.tag(getItemTag(session, trade.getFirstInput(), "buyA", trade.getSpecialPrice())); if (trade.getSecondInput() != null) { - recipe.tag(getItemTag(session, trade.getSecondInput(), "buyB")); + recipe.tag(getItemTag(session, trade.getSecondInput(), "buyB", 0)); } recipe.intTag("uses", trade.getNumUses()); - recipe.byteTag("rewardExp", (byte) trade.getXp()); + recipe.byteTag("rewardExp", (byte) 1); tags.add(recipe.buildRootTag()); } + + //Hidden trade to fix visual experience bug + if (packet.getVillagerLevel() < 5) { + tags.add(CompoundTagBuilder.builder() + .intTag("maxUses", 0) + .intTag("traderExp", 0) + .floatTag("priceMultiplierA", 0.0f) + .floatTag("priceMultiplierB", 0.0f) + .intTag("buyCountB", 0) + .intTag("buyCountA", 0) + .intTag("demand", 0) + .intTag("tier", 5) + .intTag("uses", 0) + .byteTag("rewardExp", (byte) 0) + .buildRootTag()); + } + builder.listTag("Recipes", CompoundTag.class, tags); List expTags = new ArrayList<>(); expTags.add(CompoundTagBuilder.builder().intTag("0", 0).buildRootTag()); - expTags.add(CompoundTagBuilder.builder().intTag("1", 10).buildRootTag()); - expTags.add(CompoundTagBuilder.builder().intTag("2", 60).buildRootTag()); - expTags.add(CompoundTagBuilder.builder().intTag("3", 160).buildRootTag()); - expTags.add(CompoundTagBuilder.builder().intTag("4", 310).buildRootTag()); + expTags.add(CompoundTagBuilder.builder().intTag("1", 11).buildRootTag()); + expTags.add(CompoundTagBuilder.builder().intTag("2", 71).buildRootTag()); + expTags.add(CompoundTagBuilder.builder().intTag("3", 151).buildRootTag()); + expTags.add(CompoundTagBuilder.builder().intTag("4", 251).buildRootTag()); builder.listTag("TierExpRequirements", CompoundTag.class, expTags); updateTradePacket.setOffers(builder.buildRootTag()); session.sendUpstreamPacket(updateTradePacket); } - private CompoundTag getItemTag(GeyserSession session, ItemStack stack, String name) { + private CompoundTag getItemTag(GeyserSession session, ItemStack stack, String name, int specialPrice) { ItemData itemData = Translators.getItemTranslator().translateToBedrock(session, stack); ItemEntry itemEntry = Translators.getItemTranslator().getItem(stack); CompoundTagBuilder builder = CompoundTagBuilder.builder(); - builder.byteTag("Count", (byte) itemData.getCount()); + builder.byteTag("Count", (byte) (Math.max(itemData.getCount() + specialPrice, 1))); builder.shortTag("Damage", itemData.getDamage()); - builder.stringTag("Name", itemEntry.getJavaIdentifier()); + builder.shortTag("id", (short) itemEntry.getBedrockId()); + if (itemData.getTag() != null) { + CompoundTag tag = itemData.getTag().toBuilder().build("tag"); + builder.tag(tag); + } return builder.build(name); } } From 95297e4047a66575ae3815dd04f869f03e030d1e Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Tue, 19 May 2020 07:28:33 -0800 Subject: [PATCH 3/5] Update villager xp while trading --- .../translators/bedrock/BedrockEntityEventTranslator.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityEventTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityEventTranslator.java index c7d1ae670d0..555d1015fcf 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityEventTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityEventTranslator.java @@ -29,6 +29,7 @@ import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade; import com.github.steveice10.mc.protocol.data.game.window.WindowType; import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientSelectTradePacket; +import com.nukkitx.protocol.bedrock.data.EntityData; import com.nukkitx.protocol.bedrock.packet.EntityEventPacket; import org.geysermc.connector.entity.living.merchant.VillagerEntity; import org.geysermc.connector.inventory.Inventory; @@ -57,9 +58,11 @@ public void translate(EntityEventPacket packet, GeyserSession session) { } Inventory openInventory = session.getInventoryCache().getOpenInventory(); if (openInventory != null && openInventory.getWindowType() == WindowType.MERCHANT) { - if (packet.getData() > 0 && packet.getData() < villager.getVillagerTrades().length) { + if (packet.getData() >= 0 && packet.getData() < villager.getVillagerTrades().length) { VillagerTrade trade = villager.getVillagerTrades()[packet.getData()]; openInventory.setItem(2, trade.getOutput()); + villager.getMetadata().put(EntityData.TRADE_XP, trade.getXp() + villager.getMetadata().getInt(EntityData.TRADE_XP)); + villager.updateBedrockMetadata(session); } } return; From 2366559694cef39e13a4d73d19de6b4cd958adec Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Tue, 19 May 2020 09:41:44 -0800 Subject: [PATCH 4/5] Store villager data in the player and fix wandering trader --- .../living/merchant/VillagerEntity.java | 7 ------ .../network/session/GeyserSession.java | 7 +++--- .../bedrock/BedrockEntityEventTranslator.java | 13 +++++------ ...BedrockInventoryTransactionTranslator.java | 4 ---- .../MerchantInventoryTranslator.java | 2 +- .../java/world/JavaTradeListTranslator.java | 22 ++++++++----------- 6 files changed, 19 insertions(+), 36 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/merchant/VillagerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/merchant/VillagerEntity.java index adb362e0da7..895f8cc1d41 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/merchant/VillagerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/merchant/VillagerEntity.java @@ -27,13 +27,10 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.VillagerData; -import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.EntityData; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; -import lombok.Getter; -import lombok.Setter; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; @@ -69,10 +66,6 @@ public class VillagerEntity extends AbstractMerchantEntity { VILLAGER_REGIONS.put(6, 6); } - @Getter - @Setter - private VillagerTrade[] villagerTrades; - public VillagerEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); } diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 1bf506e7ff0..e66564f6747 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -32,6 +32,7 @@ import com.github.steveice10.mc.protocol.data.SubProtocol; 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.window.VillagerTrade; import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.github.steveice10.mc.protocol.packet.handshake.client.HandshakePacket; import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientTeleportConfirmPacket; @@ -150,9 +151,6 @@ public class GeyserSession implements CommandSender { @Setter private boolean interacting; - @Setter - private long lastInteractedVillagerEid; - @Setter private Vector3i lastInteractionPosition; @@ -164,6 +162,9 @@ public class GeyserSession implements CommandSender { @Setter private int craftSlot = 0; + @Setter + private VillagerTrade[] villagerTrades; + private MinecraftProtocol protocol; public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServerSession) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityEventTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityEventTranslator.java index 555d1015fcf..25eb85a9f16 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityEventTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityEventTranslator.java @@ -31,7 +31,7 @@ import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientSelectTradePacket; import com.nukkitx.protocol.bedrock.data.EntityData; import com.nukkitx.protocol.bedrock.packet.EntityEventPacket; -import org.geysermc.connector.entity.living.merchant.VillagerEntity; +import org.geysermc.connector.entity.Entity; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; @@ -51,15 +51,12 @@ public void translate(EntityEventPacket packet, GeyserSession session) { ClientSelectTradePacket selectTradePacket = new ClientSelectTradePacket(packet.getData()); session.getDownstream().getSession().send(selectTradePacket); - VillagerEntity villager = (VillagerEntity) session.getEntityCache().getEntityByGeyserId(session.getLastInteractedVillagerEid()); - if (villager == null) { - session.getConnector().getLogger().debug("Could not find villager with entity id: " + session.getLastInteractedVillagerEid()); - return; - } + Entity villager = session.getPlayerEntity(); Inventory openInventory = session.getInventoryCache().getOpenInventory(); if (openInventory != null && openInventory.getWindowType() == WindowType.MERCHANT) { - if (packet.getData() >= 0 && packet.getData() < villager.getVillagerTrades().length) { - VillagerTrade trade = villager.getVillagerTrades()[packet.getData()]; + VillagerTrade[] trades = session.getVillagerTrades(); + if (trades != null && packet.getData() >= 0 && packet.getData() < trades.length) { + VillagerTrade trade = session.getVillagerTrades()[packet.getData()]; openInventory.setItem(2, trade.getOutput()); villager.getMetadata().put(EntityData.TRADE_XP, trade.getXp() + villager.getMetadata().getInt(EntityData.TRADE_XP)); villager.updateBedrockMetadata(session); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java index 20b19432bb2..b067273d9b9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java @@ -188,10 +188,6 @@ public void translate(InventoryTransactionPacket packet, GeyserSession session) session.sendDownstreamPacket(interactAtPacket); EntitySoundInteractionHandler.handleEntityInteraction(session, vector, entity); - - if (entity instanceof VillagerEntity) { - session.setLastInteractedVillagerEid(packet.getRuntimeEntityId()); - } break; case 1: //Attack ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(), diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java index 7e3f24bd230..4bf8d51fec2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java @@ -93,7 +93,7 @@ public void openInventory(GeyserSession session, Inventory inventory) { @Override public void closeInventory(GeyserSession session, Inventory inventory) { - session.setLastInteractedVillagerEid(-1); + session.setVillagerTrades(null); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java index 7ba20d1a6c7..ac66af590a8 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java @@ -35,7 +35,7 @@ import com.nukkitx.protocol.bedrock.data.EntityData; import com.nukkitx.protocol.bedrock.data.ItemData; import com.nukkitx.protocol.bedrock.packet.UpdateTradePacket; -import org.geysermc.connector.entity.living.merchant.VillagerEntity; +import org.geysermc.connector.entity.Entity; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; @@ -50,12 +50,8 @@ public class JavaTradeListTranslator extends PacketTranslator tags = new ArrayList<>(); for (VillagerTrade trade : packet.getTrades()) { @@ -94,7 +90,7 @@ public void translate(ServerTradeListPacket packet, GeyserSession session) { } //Hidden trade to fix visual experience bug - if (packet.getVillagerLevel() < 5) { + if (packet.isRegularVillager() && packet.getVillagerLevel() < 5) { tags.add(CompoundTagBuilder.builder() .intTag("maxUses", 0) .intTag("traderExp", 0) @@ -112,10 +108,10 @@ public void translate(ServerTradeListPacket packet, GeyserSession session) { builder.listTag("Recipes", CompoundTag.class, tags); List expTags = new ArrayList<>(); expTags.add(CompoundTagBuilder.builder().intTag("0", 0).buildRootTag()); - expTags.add(CompoundTagBuilder.builder().intTag("1", 11).buildRootTag()); - expTags.add(CompoundTagBuilder.builder().intTag("2", 71).buildRootTag()); - expTags.add(CompoundTagBuilder.builder().intTag("3", 151).buildRootTag()); - expTags.add(CompoundTagBuilder.builder().intTag("4", 251).buildRootTag()); + expTags.add(CompoundTagBuilder.builder().intTag("1", 10).buildRootTag()); + expTags.add(CompoundTagBuilder.builder().intTag("2", 70).buildRootTag()); + expTags.add(CompoundTagBuilder.builder().intTag("3", 150).buildRootTag()); + expTags.add(CompoundTagBuilder.builder().intTag("4", 250).buildRootTag()); builder.listTag("TierExpRequirements", CompoundTag.class, expTags); updateTradePacket.setOffers(builder.buildRootTag()); session.sendUpstreamPacket(updateTradePacket); From afb12e923bd9eb3e9c48764c9951b513e501fa7f Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Sat, 6 Jun 2020 00:04:05 -0400 Subject: [PATCH 5/5] Show villager display name --- .../connector/network/session/GeyserSession.java | 3 ++- .../bedrock/BedrockInventoryTransactionTranslator.java | 5 +++++ .../inventory/MerchantInventoryTranslator.java | 1 + .../translators/java/world/JavaTradeListTranslator.java | 9 ++++++++- 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 7597e59f14b..db4d6aea359 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -30,7 +30,6 @@ import com.github.steveice10.mc.auth.exception.request.RequestException; import com.github.steveice10.mc.protocol.MinecraftProtocol; import com.github.steveice10.mc.protocol.data.SubProtocol; -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.window.VillagerTrade; import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; @@ -173,6 +172,8 @@ public class GeyserSession implements CommandSender { @Setter private VillagerTrade[] villagerTrades; + @Setter + private long lastInteractedVillagerEid; private MinecraftProtocol protocol; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java index 8f96b8004a0..777d4d9e3bd 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java @@ -45,6 +45,7 @@ import org.geysermc.connector.entity.Entity; import org.geysermc.connector.entity.ItemFrameEntity; +import org.geysermc.connector.entity.living.merchant.AbstractMerchantEntity; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; @@ -198,6 +199,10 @@ public void translate(InventoryTransactionPacket packet, GeyserSession session) session.sendDownstreamPacket(interactAtPacket); EntitySoundInteractionHandler.handleEntityInteraction(session, vector, entity); + + if (entity instanceof AbstractMerchantEntity) { + session.setLastInteractedVillagerEid(packet.getRuntimeEntityId()); + } break; case 1: //Attack ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(), diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java index 4bf8d51fec2..3f7636b9e5d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java @@ -93,6 +93,7 @@ public void openInventory(GeyserSession session, Inventory inventory) { @Override public void closeInventory(GeyserSession session, Inventory inventory) { + session.setLastInteractedVillagerEid(-1); session.setVillagerTrades(null); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java index 04cee77e691..97f04ee580d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java @@ -62,7 +62,14 @@ public void translate(ServerTradeListPacket packet, GeyserSession session) { updateTradePacket.setTradeTier(packet.getVillagerLevel() - 1); updateTradePacket.setWindowId((short) packet.getWindowId()); updateTradePacket.setWindowType((short) ContainerType.TRADING.id()); - updateTradePacket.setDisplayName("Villager"); + String displayName; + Entity realVillager = session.getEntityCache().getEntityByGeyserId(session.getLastInteractedVillagerEid()); + if (realVillager != null && realVillager.getMetadata().containsKey(EntityData.NAMETAG) && realVillager.getMetadata().getString(EntityData.NAMETAG) != null) { + displayName = realVillager.getMetadata().getString(EntityData.NAMETAG); + } else { + displayName = packet.isRegularVillager() ? "Villager" : "Wandering Trader"; + } + updateTradePacket.setDisplayName(displayName); updateTradePacket.setUnknownInt(0); updateTradePacket.setScreen2(true); updateTradePacket.setWilling(true);