diff --git a/connector/src/main/java/org/geysermc/connector/entity/ItemEntity.java b/connector/src/main/java/org/geysermc/connector/entity/ItemEntity.java index a80323076..a28b563b4 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/ItemEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/ItemEntity.java @@ -49,7 +49,7 @@ public class ItemEntity extends Entity { itemPacket.setUniqueEntityId(geyserId); itemPacket.setFromFishing(false); itemPacket.getMetadata().putAll(metadata); - itemPacket.setItemInHand(Translators.getItemTranslator().translateToBedrock((ItemStack) entityMetadata.getValue())); + itemPacket.setItemInHand(Translators.getItemTranslator().translateToBedrock(session, (ItemStack) entityMetadata.getValue())); session.getUpstream().sendPacket(itemPacket); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/ItemRemapper.java b/connector/src/main/java/org/geysermc/connector/network/translators/ItemRemapper.java new file mode 100644 index 000000000..6c286da2f --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/ItemRemapper.java @@ -0,0 +1,34 @@ +/* + * 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; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(value = RetentionPolicy.RUNTIME) +public @interface ItemRemapper { + int priority() default 0; +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/ItemStackTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/ItemStackTranslator.java new file mode 100644 index 000000000..ac4bb2f28 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/ItemStackTranslator.java @@ -0,0 +1,250 @@ +/* + * 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; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.message.Message; +import com.github.steveice10.opennbt.tag.builtin.*; +import com.nukkitx.nbt.tag.CompoundTag; +import com.nukkitx.nbt.tag.Tag; +import com.nukkitx.protocol.bedrock.data.ItemData; +import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.utils.MessageUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public abstract class ItemStackTranslator { + + public ItemData translateToBedrock(ItemStack itemStack, ItemEntry itemEntry) { + if (itemStack == null) { + return ItemData.AIR; + } + if (itemStack.getNbt() == null) { + return ItemData.of(itemEntry.getBedrockId(), (short) itemEntry.getBedrockData(), itemStack.getAmount()); + } + return ItemData.of(itemEntry.getBedrockId(), (short) itemEntry.getBedrockData(), itemStack.getAmount(), this.translateNbtToBedrock(itemStack.getNbt())); + } + + public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) { + if (itemData == null) return null; + if (itemData.getTag() == null) { + return new ItemStack(itemEntry.getJavaId(), itemData.getCount()); + } + return new ItemStack(itemEntry.getJavaId(), itemData.getCount(), this.translateToJavaNBT(itemData.getTag())); + } + + public abstract List getAppliedItems(); + + public CompoundTag translateNbtToBedrock(com.github.steveice10.opennbt.tag.builtin.CompoundTag tag) { + Map> javaValue = new HashMap>(); + if (tag.getValue() != null && !tag.getValue().isEmpty()) { + for (String str : tag.getValue().keySet()) { + com.github.steveice10.opennbt.tag.builtin.Tag javaTag = tag.get(str); + com.nukkitx.nbt.tag.Tag translatedTag = translateToBedrockNBT(javaTag); + if (translatedTag == null) + continue; + + javaValue.put(translatedTag.getName(), translatedTag); + } + } + + com.nukkitx.nbt.tag.CompoundTag bedrockTag = new com.nukkitx.nbt.tag.CompoundTag(tag.getName(), javaValue); + return bedrockTag; + } + + private com.nukkitx.nbt.tag.Tag translateToBedrockNBT(com.github.steveice10.opennbt.tag.builtin.Tag tag) { + if (tag instanceof ByteArrayTag) { + ByteArrayTag byteArrayTag = (ByteArrayTag) tag; + return new com.nukkitx.nbt.tag.ByteArrayTag(byteArrayTag.getName(), byteArrayTag.getValue()); + } + + if (tag instanceof ByteTag) { + ByteTag byteTag = (ByteTag) tag; + return new com.nukkitx.nbt.tag.ByteTag(byteTag.getName(), byteTag.getValue()); + } + + if (tag instanceof DoubleTag) { + DoubleTag doubleTag = (DoubleTag) tag; + return new com.nukkitx.nbt.tag.DoubleTag(doubleTag.getName(), doubleTag.getValue()); + } + + if (tag instanceof FloatTag) { + FloatTag floatTag = (FloatTag) tag; + return new com.nukkitx.nbt.tag.FloatTag(floatTag.getName(), floatTag.getValue()); + } + + if (tag instanceof IntArrayTag) { + IntArrayTag intArrayTag = (IntArrayTag) tag; + return new com.nukkitx.nbt.tag.IntArrayTag(intArrayTag.getName(), intArrayTag.getValue()); + } + + if (tag instanceof IntTag) { + IntTag intTag = (IntTag) tag; + return new com.nukkitx.nbt.tag.IntTag(intTag.getName(), intTag.getValue()); + } + + if (tag instanceof LongArrayTag) { + LongArrayTag longArrayTag = (LongArrayTag) tag; + return new com.nukkitx.nbt.tag.LongArrayTag(longArrayTag.getName(), longArrayTag.getValue()); + } + + if (tag instanceof LongTag) { + LongTag longTag = (LongTag) tag; + return new com.nukkitx.nbt.tag.LongTag(longTag.getName(), longTag.getValue()); + } + + if (tag instanceof ShortTag) { + ShortTag shortTag = (ShortTag) tag; + return new com.nukkitx.nbt.tag.ShortTag(shortTag.getName(), shortTag.getValue()); + } + + if (tag instanceof StringTag) { + StringTag stringTag = (StringTag) tag; + return new com.nukkitx.nbt.tag.StringTag(stringTag.getName(), MessageUtils.getBedrockMessage(Message.fromString(stringTag.getValue()))); + } + + if (tag instanceof ListTag) { + ListTag listTag = (ListTag) tag; + + List tagList = new ArrayList<>(); + for (com.github.steveice10.opennbt.tag.builtin.Tag value : listTag) { + tagList.add(translateToBedrockNBT(value)); + } + Class clazz = CompoundTag.class; + if (!tagList.isEmpty()) { + clazz = tagList.get(0).getClass(); + } + return new com.nukkitx.nbt.tag.ListTag(listTag.getName(), clazz, tagList); + } + + if (tag instanceof com.github.steveice10.opennbt.tag.builtin.CompoundTag) { + com.github.steveice10.opennbt.tag.builtin.CompoundTag compoundTag = (com.github.steveice10.opennbt.tag.builtin.CompoundTag) tag; + + return translateNbtToBedrock(compoundTag); + } + + return null; + } + + public com.github.steveice10.opennbt.tag.builtin.CompoundTag translateToJavaNBT(com.nukkitx.nbt.tag.CompoundTag tag) { + com.github.steveice10.opennbt.tag.builtin.CompoundTag javaTag = new com.github.steveice10.opennbt.tag.builtin.CompoundTag(tag.getName()); + Map javaValue = javaTag.getValue(); + if (tag.getValue() != null && !tag.getValue().isEmpty()) { + for (String str : tag.getValue().keySet()) { + com.nukkitx.nbt.tag.Tag bedrockTag = tag.get(str); + com.github.steveice10.opennbt.tag.builtin.Tag translatedTag = translateToJavaNBT(bedrockTag); + if (translatedTag == null) + continue; + + javaValue.put(translatedTag.getName(), translatedTag); + } + } + + javaTag.setValue(javaValue); + return javaTag; + } + + private com.github.steveice10.opennbt.tag.builtin.Tag translateToJavaNBT(com.nukkitx.nbt.tag.Tag tag) { + if (tag instanceof com.nukkitx.nbt.tag.ByteArrayTag) { + com.nukkitx.nbt.tag.ByteArrayTag byteArrayTag = (com.nukkitx.nbt.tag.ByteArrayTag) tag; + return new ByteArrayTag(byteArrayTag.getName(), byteArrayTag.getValue()); + } + + if (tag instanceof com.nukkitx.nbt.tag.ByteTag) { + com.nukkitx.nbt.tag.ByteTag byteTag = (com.nukkitx.nbt.tag.ByteTag) tag; + return new ByteTag(byteTag.getName(), byteTag.getValue()); + } + + if (tag instanceof com.nukkitx.nbt.tag.DoubleTag) { + com.nukkitx.nbt.tag.DoubleTag doubleTag = (com.nukkitx.nbt.tag.DoubleTag) tag; + return new DoubleTag(doubleTag.getName(), doubleTag.getValue()); + } + + if (tag instanceof com.nukkitx.nbt.tag.FloatTag) { + com.nukkitx.nbt.tag.FloatTag floatTag = (com.nukkitx.nbt.tag.FloatTag) tag; + return new FloatTag(floatTag.getName(), floatTag.getValue()); + } + + if (tag instanceof com.nukkitx.nbt.tag.IntArrayTag) { + com.nukkitx.nbt.tag.IntArrayTag intArrayTag = (com.nukkitx.nbt.tag.IntArrayTag) tag; + return new IntArrayTag(intArrayTag.getName(), intArrayTag.getValue()); + } + + if (tag instanceof com.nukkitx.nbt.tag.IntTag) { + com.nukkitx.nbt.tag.IntTag intTag = (com.nukkitx.nbt.tag.IntTag) tag; + return new IntTag(intTag.getName(), intTag.getValue()); + } + + if (tag instanceof com.nukkitx.nbt.tag.LongArrayTag) { + com.nukkitx.nbt.tag.LongArrayTag longArrayTag = (com.nukkitx.nbt.tag.LongArrayTag) tag; + return new LongArrayTag(longArrayTag.getName(), longArrayTag.getValue()); + } + + if (tag instanceof com.nukkitx.nbt.tag.LongTag) { + com.nukkitx.nbt.tag.LongTag longTag = (com.nukkitx.nbt.tag.LongTag) tag; + return new LongTag(longTag.getName(), longTag.getValue()); + } + + if (tag instanceof com.nukkitx.nbt.tag.ShortTag) { + com.nukkitx.nbt.tag.ShortTag shortTag = (com.nukkitx.nbt.tag.ShortTag) tag; + return new ShortTag(shortTag.getName(), shortTag.getValue()); + } + + if (tag instanceof com.nukkitx.nbt.tag.StringTag) { + com.nukkitx.nbt.tag.StringTag stringTag = (com.nukkitx.nbt.tag.StringTag) tag; + return new StringTag(stringTag.getName(), stringTag.getValue()); + } + + if (tag instanceof com.nukkitx.nbt.tag.ListTag) { + com.nukkitx.nbt.tag.ListTag listTag = (com.nukkitx.nbt.tag.ListTag) tag; + + List tags = new ArrayList<>(); + + for (Object value : listTag.getValue()) { + if (!(value instanceof com.nukkitx.nbt.tag.Tag)) + continue; + + com.nukkitx.nbt.tag.Tag tagValue = (com.nukkitx.nbt.tag.Tag) value; + com.github.steveice10.opennbt.tag.builtin.Tag javaTag = translateToJavaNBT(tagValue); + if (javaTag != null) + tags.add(javaTag); + } + return new ListTag(listTag.getName(), tags); + } + + if (tag instanceof com.nukkitx.nbt.tag.CompoundTag) { + com.nukkitx.nbt.tag.CompoundTag compoundTag = (com.nukkitx.nbt.tag.CompoundTag) tag; + return translateToJavaNBT(compoundTag); + } + + return null; + } + + +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/NbtItemStackTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/NbtItemStackTranslator.java new file mode 100644 index 000000000..56c780f44 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/NbtItemStackTranslator.java @@ -0,0 +1,45 @@ +/* + * 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; + +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import org.geysermc.connector.network.translators.item.ItemEntry; + +public class NbtItemStackTranslator { + + public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) { + + } + + public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) { + + } + + public boolean acceptItem(ItemEntry itemEntry) { + return true; + } + +} 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 cffb85f19..f0a3fd28c 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 @@ -109,6 +109,7 @@ public class Translators { } itemTranslator = new ItemTranslator(); + itemTranslator.init(); BlockTranslator.init(); registerBlockEntityTranslators(); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java index 440d01dcb..c1e00d2a0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java @@ -51,7 +51,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { InventorySlotPacket slotPacket = new InventorySlotPacket(); slotPacket.setContainerId(ContainerId.CURSOR); slotPacket.setSlot(i + 27); - slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(inventory.getItem(i))); + slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(i))); session.getUpstream().sendPacket(slotPacket); } @@ -60,11 +60,11 @@ public class PlayerInventoryTranslator extends InventoryTranslator { ItemData[] contents = new ItemData[36]; // Inventory for (int i = 9; i < 36; i++) { - contents[i] = Translators.getItemTranslator().translateToBedrock(inventory.getItem(i)); + contents[i] = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(i)); } // Hotbar for (int i = 36; i < 45; i++) { - contents[i - 36] = Translators.getItemTranslator().translateToBedrock(inventory.getItem(i)); + contents[i - 36] = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(i)); } inventoryContentPacket.setContents(contents); session.getUpstream().sendPacket(inventoryContentPacket); @@ -74,7 +74,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { armorContentPacket.setContainerId(ContainerId.ARMOR); contents = new ItemData[4]; for (int i = 5; i < 9; i++) { - contents[i - 5] = Translators.getItemTranslator().translateToBedrock(inventory.getItem(i)); + contents[i - 5] = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(i)); } armorContentPacket.setContents(contents); session.getUpstream().sendPacket(armorContentPacket); @@ -82,7 +82,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { // Offhand InventoryContentPacket offhandPacket = new InventoryContentPacket(); offhandPacket.setContainerId(ContainerId.OFFHAND); - offhandPacket.setContents(new ItemData[]{Translators.getItemTranslator().translateToBedrock(inventory.getItem(45))}); + offhandPacket.setContents(new ItemData[]{Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(45))}); session.getUpstream().sendPacket(offhandPacket); } @@ -104,12 +104,12 @@ public class PlayerInventoryTranslator extends InventoryTranslator { slotPacket.setContainerId(ContainerId.CURSOR); slotPacket.setSlot(slot + 27); } - slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(inventory.getItem(slot))); + slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(slot))); session.getUpstream().sendPacket(slotPacket); } else if (slot == 45) { InventoryContentPacket offhandPacket = new InventoryContentPacket(); offhandPacket.setContainerId(ContainerId.OFFHAND); - offhandPacket.setContents(new ItemData[]{Translators.getItemTranslator().translateToBedrock(inventory.getItem(slot))}); + offhandPacket.setContents(new ItemData[]{Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(slot))}); session.getUpstream().sendPacket(offhandPacket); } } @@ -180,7 +180,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { if (action.getToItem().getId() == 0) { javaItem = new ItemStack(-1, 0, null); } else { - javaItem = Translators.getItemTranslator().translateToJava(action.getToItem()); + javaItem = Translators.getItemTranslator().translateToJava(session, action.getToItem()); } ClientCreativeInventoryActionPacket creativePacket = new ClientCreativeInventoryActionPacket(javaSlot, javaItem); session.getDownstream().getSession().send(creativePacket); @@ -188,13 +188,13 @@ public class PlayerInventoryTranslator extends InventoryTranslator { break; case ContainerId.CURSOR: if (action.getSlot() == 0) { - session.getInventory().setCursor(Translators.getItemTranslator().translateToJava(action.getToItem())); + session.getInventory().setCursor(Translators.getItemTranslator().translateToJava(session, action.getToItem())); } break; case ContainerId.NONE: if (action.getSource().getType() == InventorySource.Type.WORLD_INTERACTION && action.getSource().getFlag() == InventorySource.Flag.DROP_ITEM) { - javaItem = Translators.getItemTranslator().translateToJava(action.getToItem()); + javaItem = Translators.getItemTranslator().translateToJava(session, action.getToItem()); ClientCreativeInventoryActionPacket creativeDropPacket = new ClientCreativeInventoryActionPacket(-1, javaItem); session.getDownstream().getSession().send(creativeDropPacket); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionDataTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionDataTranslator.java index 750de5c8d..370d41777 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionDataTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionDataTranslator.java @@ -61,13 +61,13 @@ public class InventoryActionDataTranslator { worldAction = action; } else if (action.getSource().getContainerId() == ContainerId.CURSOR && action.getSlot() == 0) { cursorAction = action; - ItemData translatedCursor = Translators.getItemTranslator().translateToBedrock(session.getInventory().getCursor()); + ItemData translatedCursor = Translators.getItemTranslator().translateToBedrock(session, session.getInventory().getCursor()); if (!translatedCursor.equals(action.getFromItem())) { refresh = true; } } else { containerAction = action; - ItemData translatedItem = Translators.getItemTranslator().translateToBedrock(inventory.getItem(translator.bedrockSlotToJava(action))); + ItemData translatedItem = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(translator.bedrockSlotToJava(action))); if (!translatedItem.equals(action.getFromItem())) { refresh = true; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java index dcffcd35c..e8e0fc455 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java @@ -45,7 +45,7 @@ public class ChestInventoryUpdater extends InventoryUpdater { ItemData[] bedrockItems = new ItemData[paddedSize]; for (int i = 0; i < bedrockItems.length; i++) { if (i <= translator.size) { - bedrockItems[i] = Translators.getItemTranslator().translateToBedrock(inventory.getItem(i)); + bedrockItems[i] = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(i)); } else { bedrockItems[i] = ItemData.AIR; } @@ -65,7 +65,7 @@ public class ChestInventoryUpdater extends InventoryUpdater { InventorySlotPacket slotPacket = new InventorySlotPacket(); slotPacket.setContainerId(inventory.getId()); slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); - slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(inventory.getItem(javaSlot))); + slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(javaSlot))); session.getUpstream().sendPacket(slotPacket); return true; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ContainerInventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ContainerInventoryUpdater.java index 812ce8f86..d187ffd95 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ContainerInventoryUpdater.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ContainerInventoryUpdater.java @@ -40,7 +40,7 @@ public class ContainerInventoryUpdater extends InventoryUpdater { ItemData[] bedrockItems = new ItemData[translator.size]; for (int i = 0; i < bedrockItems.length; i++) { - bedrockItems[translator.javaSlotToBedrock(i)] = Translators.getItemTranslator().translateToBedrock(inventory.getItem(i)); + bedrockItems[translator.javaSlotToBedrock(i)] = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(i)); } InventoryContentPacket contentPacket = new InventoryContentPacket(); @@ -57,7 +57,7 @@ public class ContainerInventoryUpdater extends InventoryUpdater { InventorySlotPacket slotPacket = new InventorySlotPacket(); slotPacket.setContainerId(inventory.getId()); slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); - slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(inventory.getItem(javaSlot))); + slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(javaSlot))); session.getUpstream().sendPacket(slotPacket); return true; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java index f0c1c7607..e3dc18648 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java @@ -44,7 +44,7 @@ public class CursorInventoryUpdater extends InventoryUpdater { InventorySlotPacket slotPacket = new InventorySlotPacket(); slotPacket.setContainerId(ContainerId.CURSOR); slotPacket.setSlot(bedrockSlot); - slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(inventory.getItem(i))); + slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(i))); session.getUpstream().sendPacket(slotPacket); } } @@ -57,7 +57,7 @@ public class CursorInventoryUpdater extends InventoryUpdater { InventorySlotPacket slotPacket = new InventorySlotPacket(); slotPacket.setContainerId(ContainerId.CURSOR); slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); - slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(inventory.getItem(javaSlot))); + slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(javaSlot))); session.getUpstream().sendPacket(slotPacket); return true; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java index 32005685b..2f139e27a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java @@ -39,7 +39,7 @@ public abstract class InventoryUpdater { ItemData[] bedrockItems = new ItemData[36]; for (int i = 0; i < 36; i++) { final int offset = i < 9 ? 27 : -9; - bedrockItems[i] = Translators.getItemTranslator().translateToBedrock(inventory.getItem(translator.size + i + offset)); + bedrockItems[i] = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(translator.size + i + offset)); } InventoryContentPacket contentPacket = new InventoryContentPacket(); contentPacket.setContainerId(ContainerId.INVENTORY); @@ -52,7 +52,7 @@ public abstract class InventoryUpdater { InventorySlotPacket slotPacket = new InventorySlotPacket(); slotPacket.setContainerId(ContainerId.INVENTORY); slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); - slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(inventory.getItem(javaSlot))); + slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(javaSlot))); session.getUpstream().sendPacket(slotPacket); return true; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/Enchantment.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/Enchantment.java index c5c152a2f..b9348e25f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/Enchantment.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/Enchantment.java @@ -30,7 +30,7 @@ import lombok.Getter; import java.util.Locale; @Getter -enum Enchantment { +public enum Enchantment { PROTECTION, FIRE_PROTECTION, FEATHER_FALLING, 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 0bcbf4b73..79dae31fd 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 @@ -26,86 +26,107 @@ package org.geysermc.connector.network.translators.item; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; -import com.github.steveice10.mc.protocol.data.message.Message; -import com.github.steveice10.opennbt.tag.builtin.ByteArrayTag; -import com.github.steveice10.opennbt.tag.builtin.ByteTag; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.DoubleTag; -import com.github.steveice10.opennbt.tag.builtin.FloatTag; -import com.github.steveice10.opennbt.tag.builtin.IntArrayTag; -import com.github.steveice10.opennbt.tag.builtin.IntTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.LongArrayTag; -import com.github.steveice10.opennbt.tag.builtin.LongTag; -import com.github.steveice10.opennbt.tag.builtin.ShortTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; import com.nukkitx.protocol.bedrock.data.ItemData; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.utils.MessageUtils; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.*; import org.geysermc.connector.utils.Toolbox; +import org.reflections.Reflections; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.stream.Collectors; public class ItemTranslator { + private Int2ObjectMap itemTranslators = new Int2ObjectOpenHashMap(); + private List nbtItemTranslators; private Map javaIdentifierMap = new HashMap<>(); - public ItemStack translateToJava(ItemData data) { - ItemEntry javaItem = getItem(data); + public void init() { + Reflections ref = new Reflections("org.geysermc.connector.network.translators.item"); - if (data.getTag() == null) { - return new ItemStack(javaItem.getJavaId(), data.getCount()); - } else if (javaItem.getJavaIdentifier().equals("minecraft:enchanted_book")) { - CompoundTag javaTag = translateToJavaNBT(data.getTag()); - Map javaValue = javaTag.getValue(); - Tag enchTag = javaValue.get("Enchantments"); - if (enchTag instanceof ListTag) { - enchTag = new ListTag("StoredEnchantments", ((ListTag) enchTag).getValue()); - javaValue.remove("Enchantments"); - javaValue.put("StoredEnchantments", enchTag); - javaTag.setValue(javaValue); + Map loadedNbtItemTranslators = new HashMap<>(); + for (Class clazz : ref.getTypesAnnotatedWith(ItemRemapper.class)) { + int priority = clazz.getAnnotation(ItemRemapper.class).priority(); + + GeyserConnector.getInstance().getLogger().debug("Found annotated item translator: " + clazz.getCanonicalName()); + + try { + if (NbtItemStackTranslator.class.isAssignableFrom(clazz)) { + NbtItemStackTranslator nbtItemTranslator = (NbtItemStackTranslator) clazz.newInstance(); + loadedNbtItemTranslators.put(nbtItemTranslator, priority); + continue; + } + ItemStackTranslator itemStackTranslator = (ItemStackTranslator) clazz.newInstance(); + List appliedItems = itemStackTranslator.getAppliedItems(); + for (ItemEntry item : appliedItems) { + ItemStackTranslator registered = itemTranslators.get(item.getJavaId()); + if (registered != null) { + GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated item translator " + clazz.getCanonicalName() + "." + + " Item translator " + registered.getClass().getCanonicalName() + " is already registered for the item " + item.getJavaIdentifier()); + continue; + } + itemTranslators.put(item.getJavaId(), itemStackTranslator); + } + } catch (InstantiationException | IllegalAccessException e) { + GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated item translator " + clazz.getCanonicalName() + "."); } - return new ItemStack(javaItem.getJavaId(), data.getCount(), javaTag); } - return new ItemStack(javaItem.getJavaId(), data.getCount(), translateToJavaNBT(data.getTag())); + + nbtItemTranslators = loadedNbtItemTranslators.keySet().stream() + .sorted(Comparator.comparingInt(value -> loadedNbtItemTranslators.get(value))).collect(Collectors.toList()); } - public ItemData translateToBedrock(ItemStack stack) { + public ItemStack translateToJava(GeyserSession session, ItemData data) { + if (data == null) { + return new ItemStack(0); + } + ItemEntry javaItem = getItem(data); + + ItemStack itemStack; + + ItemStackTranslator itemStackTranslator = itemTranslators.get(javaItem.getJavaId()); + if (itemStackTranslator != null) { + itemStack = itemStackTranslator.translateToJava(data, javaItem); + } else { + itemStack = DEFAULT_TRANSLATOR.translateToJava(data, javaItem); + } + + if (itemStack != null && itemStack.getNbt() != null) { + for (NbtItemStackTranslator translator : nbtItemTranslators) { + if (translator.acceptItem(javaItem)) { + translator.translateToJava(itemStack.getNbt(), javaItem); + } + } + } + return itemStack; + } + + public ItemData translateToBedrock(GeyserSession session, ItemStack stack) { if (stack == null) { return ItemData.AIR; } ItemEntry bedrockItem = getItem(stack); - if (stack.getNbt() == null) { - return ItemData.of(bedrockItem.getBedrockId(), (short) bedrockItem.getBedrockData(), stack.getAmount()); - } else if (bedrockItem.getJavaIdentifier().endsWith("potion")) { - Tag potionTag = stack.getNbt().get("Potion"); - if (potionTag instanceof StringTag) { - Potion potion = Potion.getByJavaIdentifier(((StringTag) potionTag).getValue()); - if (potion != null) { - return ItemData.of(bedrockItem.getBedrockId(), potion.getBedrockId(), stack.getAmount(), translateToBedrockNBT(stack.getNbt())); + + if (stack != null && stack.getNbt() != null) { + for (NbtItemStackTranslator translator : nbtItemTranslators) { + if (translator.acceptItem(bedrockItem)) { + translator.translateToBedrock(stack.getNbt(), bedrockItem); } - GeyserConnector.getInstance().getLogger().debug("Unknown java potion: " + potionTag.getValue()); } } - // TODO: Create proper transformers instead of shoving everything here - CompoundTag tag = stack.getNbt(); - IntTag mapId = tag.get("map"); - - if (mapId != null) { - tag.put(new StringTag("map_uuid", mapId.getValue().toString())); - tag.put(new IntTag("map_name_index", mapId.getValue())); + ItemStackTranslator itemStackTranslator = itemTranslators.get(bedrockItem.getJavaId()); + if (itemStackTranslator != null) { + return itemStackTranslator.translateToBedrock(stack, bedrockItem); + } else { + return DEFAULT_TRANSLATOR.translateToBedrock(stack, bedrockItem); } - - - return ItemData.of(bedrockItem.getBedrockId(), (short) bedrockItem.getBedrockData(), stack.getAmount(), translateToBedrockNBT(tag)); } public ItemEntry getItem(ItemStack stack) { @@ -135,235 +156,10 @@ public class ItemTranslator { .stream().filter(itemEntry -> itemEntry.getJavaIdentifier().equals(key)).findFirst().orElse(null)); } - private CompoundTag translateToJavaNBT(com.nukkitx.nbt.tag.CompoundTag tag) { - CompoundTag javaTag = new CompoundTag(tag.getName()); - Map javaValue = javaTag.getValue(); - if (tag.getValue() != null && !tag.getValue().isEmpty()) { - for (String str : tag.getValue().keySet()) { - com.nukkitx.nbt.tag.Tag bedrockTag = tag.get(str); - Tag translatedTag = translateToJavaNBT(bedrockTag); - if (translatedTag == null) - continue; - - javaValue.put(translatedTag.getName(), translatedTag); - } + private static final ItemStackTranslator DEFAULT_TRANSLATOR = new ItemStackTranslator() { + @Override + public List getAppliedItems() { + return null; } - - javaTag.setValue(javaValue); - return javaTag; - } - - private Tag translateToJavaNBT(com.nukkitx.nbt.tag.Tag tag) { - if (tag instanceof com.nukkitx.nbt.tag.ByteArrayTag) { - com.nukkitx.nbt.tag.ByteArrayTag byteArrayTag = (com.nukkitx.nbt.tag.ByteArrayTag) tag; - return new ByteArrayTag(byteArrayTag.getName(), byteArrayTag.getValue()); - } - - if (tag instanceof com.nukkitx.nbt.tag.ByteTag) { - com.nukkitx.nbt.tag.ByteTag byteTag = (com.nukkitx.nbt.tag.ByteTag) tag; - return new ByteTag(byteTag.getName(), byteTag.getValue()); - } - - if (tag instanceof com.nukkitx.nbt.tag.DoubleTag) { - com.nukkitx.nbt.tag.DoubleTag doubleTag = (com.nukkitx.nbt.tag.DoubleTag) tag; - return new DoubleTag(doubleTag.getName(), doubleTag.getValue()); - } - - if (tag instanceof com.nukkitx.nbt.tag.FloatTag) { - com.nukkitx.nbt.tag.FloatTag floatTag = (com.nukkitx.nbt.tag.FloatTag) tag; - return new FloatTag(floatTag.getName(), floatTag.getValue()); - } - - if (tag instanceof com.nukkitx.nbt.tag.IntArrayTag) { - com.nukkitx.nbt.tag.IntArrayTag intArrayTag = (com.nukkitx.nbt.tag.IntArrayTag) tag; - return new IntArrayTag(intArrayTag.getName(), intArrayTag.getValue()); - } - - if (tag instanceof com.nukkitx.nbt.tag.IntTag) { - com.nukkitx.nbt.tag.IntTag intTag = (com.nukkitx.nbt.tag.IntTag) tag; - return new IntTag(intTag.getName(), intTag.getValue()); - } - - if (tag instanceof com.nukkitx.nbt.tag.LongArrayTag) { - com.nukkitx.nbt.tag.LongArrayTag longArrayTag = (com.nukkitx.nbt.tag.LongArrayTag) tag; - return new LongArrayTag(longArrayTag.getName(), longArrayTag.getValue()); - } - - if (tag instanceof com.nukkitx.nbt.tag.LongTag) { - com.nukkitx.nbt.tag.LongTag longTag = (com.nukkitx.nbt.tag.LongTag) tag; - return new LongTag(longTag.getName(), longTag.getValue()); - } - - if (tag instanceof com.nukkitx.nbt.tag.ShortTag) { - com.nukkitx.nbt.tag.ShortTag shortTag = (com.nukkitx.nbt.tag.ShortTag) tag; - return new ShortTag(shortTag.getName(), shortTag.getValue()); - } - - if (tag instanceof com.nukkitx.nbt.tag.StringTag) { - com.nukkitx.nbt.tag.StringTag stringTag = (com.nukkitx.nbt.tag.StringTag) tag; - return new StringTag(stringTag.getName(), stringTag.getValue()); - } - - if (tag instanceof com.nukkitx.nbt.tag.ListTag) { - com.nukkitx.nbt.tag.ListTag listTag = (com.nukkitx.nbt.tag.ListTag) tag; - - List tags = new ArrayList<>(); - - if (tag.getName().equals("ench")) { - for (Object value : listTag.getValue()) { - if (!(value instanceof com.nukkitx.nbt.tag.CompoundTag)) - continue; - - com.nukkitx.nbt.tag.CompoundTag tagValue = (com.nukkitx.nbt.tag.CompoundTag) value; - int bedrockId = tagValue.getShort("id", (short) -1); - Enchantment enchantment = Enchantment.getByBedrockId(bedrockId); - if (enchantment != null) { - CompoundTag javaTag = new CompoundTag(""); - Map javaValue = javaTag.getValue(); - javaValue.put("id", new StringTag("id", enchantment.getJavaIdentifier())); - javaValue.put("lvl", new IntTag("lvl", tagValue.getShort("lvl", (short) 1))); - javaTag.setValue(javaValue); - tags.add(javaTag); - } else { - GeyserConnector.getInstance().getLogger().debug("Unknown bedrock enchantment: " + bedrockId); - } - } - return new ListTag("Enchantments", tags); - } - - for (Object value : listTag.getValue()) { - if (!(value instanceof com.nukkitx.nbt.tag.Tag)) - continue; - - com.nukkitx.nbt.tag.Tag tagValue = (com.nukkitx.nbt.tag.Tag) value; - Tag javaTag = translateToJavaNBT(tagValue); - if (javaTag != null) - tags.add(javaTag); - } - return new ListTag(listTag.getName(), tags); - } - - if (tag instanceof com.nukkitx.nbt.tag.CompoundTag) { - return translateToJavaNBT((com.nukkitx.nbt.tag.CompoundTag) tag); - } - - return null; - } - - private com.nukkitx.nbt.tag.CompoundTag translateToBedrockNBT(CompoundTag tag) { - Map> javaValue = new HashMap>(); - if (tag.getValue() != null && !tag.getValue().isEmpty()) { - for (String str : tag.getValue().keySet()) { - Tag javaTag = tag.get(str); - com.nukkitx.nbt.tag.Tag translatedTag = translateToBedrockNBT(javaTag); - if (translatedTag == null) - continue; - - javaValue.put(translatedTag.getName(), translatedTag); - } - } - - com.nukkitx.nbt.tag.CompoundTag bedrockTag = new com.nukkitx.nbt.tag.CompoundTag(tag.getName(), javaValue); - return bedrockTag; - } - - private com.nukkitx.nbt.tag.Tag translateToBedrockNBT(Tag tag) { - if (tag instanceof ByteArrayTag) { - ByteArrayTag byteArrayTag = (ByteArrayTag) tag; - return new com.nukkitx.nbt.tag.ByteArrayTag(byteArrayTag.getName(), byteArrayTag.getValue()); - } - - if (tag instanceof ByteTag) { - ByteTag byteTag = (ByteTag) tag; - return new com.nukkitx.nbt.tag.ByteTag(byteTag.getName(), byteTag.getValue()); - } - - if (tag instanceof DoubleTag) { - DoubleTag doubleTag = (DoubleTag) tag; - return new com.nukkitx.nbt.tag.DoubleTag(doubleTag.getName(), doubleTag.getValue()); - } - - if (tag instanceof FloatTag) { - FloatTag floatTag = (FloatTag) tag; - return new com.nukkitx.nbt.tag.FloatTag(floatTag.getName(), floatTag.getValue()); - } - - if (tag instanceof IntArrayTag) { - IntArrayTag intArrayTag = (IntArrayTag) tag; - return new com.nukkitx.nbt.tag.IntArrayTag(intArrayTag.getName(), intArrayTag.getValue()); - } - - if (tag instanceof IntTag) { - IntTag intTag = (IntTag) tag; - return new com.nukkitx.nbt.tag.IntTag(intTag.getName(), intTag.getValue()); - } - - if (tag instanceof LongArrayTag) { - LongArrayTag longArrayTag = (LongArrayTag) tag; - return new com.nukkitx.nbt.tag.LongArrayTag(longArrayTag.getName(), longArrayTag.getValue()); - } - - if (tag instanceof LongTag) { - LongTag longTag = (LongTag) tag; - return new com.nukkitx.nbt.tag.LongTag(longTag.getName(), longTag.getValue()); - } - - if (tag instanceof ShortTag) { - ShortTag shortTag = (ShortTag) tag; - return new com.nukkitx.nbt.tag.ShortTag(shortTag.getName(), shortTag.getValue()); - } - - if (tag instanceof StringTag) { - StringTag stringTag = (StringTag) tag; - return new com.nukkitx.nbt.tag.StringTag(stringTag.getName(), MessageUtils.getBedrockMessage(Message.fromString(stringTag.getValue()))); - } - - if (tag instanceof ListTag) { - ListTag listTag = (ListTag) tag; - if (listTag.getName().equalsIgnoreCase("Enchantments") || listTag.getName().equalsIgnoreCase("StoredEnchantments")) { - List tags = new ArrayList<>(); - for (Object value : listTag.getValue()) { - if (!(value instanceof CompoundTag)) - continue; - - Tag javaEnchLvl = ((CompoundTag) value).get("lvl"); - if (!(javaEnchLvl instanceof ShortTag)) - continue; - - Tag javaEnchId = ((CompoundTag) value).get("id"); - if (!(javaEnchId instanceof StringTag)) - continue; - - Enchantment enchantment = Enchantment.getByJavaIdentifier(((StringTag) javaEnchId).getValue()); - if (enchantment == null) { - GeyserConnector.getInstance().getLogger().debug("Unknown java enchantment: " + javaEnchId.getValue()); - continue; - } - - com.nukkitx.nbt.CompoundTagBuilder builder = com.nukkitx.nbt.tag.CompoundTag.EMPTY.toBuilder(); - builder.shortTag("lvl", ((ShortTag) javaEnchLvl).getValue()); - builder.shortTag("id", (short) enchantment.ordinal()); - tags.add(builder.buildRootTag()); - } - return new com.nukkitx.nbt.tag.ListTag<>("ench", com.nukkitx.nbt.tag.CompoundTag.class, tags); - } else if (listTag.getName().equalsIgnoreCase("Lore")) { - List tags = new ArrayList<>(); - for (Object value : listTag.getValue()) { - if (!(value instanceof Tag)) - continue; - - com.nukkitx.nbt.tag.StringTag bedrockTag = (com.nukkitx.nbt.tag.StringTag) translateToBedrockNBT((Tag) value); - if (bedrockTag != null) - tags.add(bedrockTag); - } - return new com.nukkitx.nbt.tag.ListTag<>(listTag.getName(), com.nukkitx.nbt.tag.StringTag.class, tags); - } - } - - if (tag instanceof CompoundTag) { - return translateToBedrockNBT((CompoundTag) tag); - } - - return null; - } + }; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/Potion.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/Potion.java index f711d3ea2..51ae36e49 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/Potion.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/Potion.java @@ -30,7 +30,7 @@ import lombok.Getter; import java.util.Locale; @Getter -enum Potion { +public enum Potion { WATER(0), MUNDANE(1), THICK(3), diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/PotionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/PotionTranslator.java new file mode 100644 index 000000000..e528b448e --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/PotionTranslator.java @@ -0,0 +1,80 @@ +/* + * 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.item.translators; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.opennbt.tag.builtin.StringTag; +import com.github.steveice10.opennbt.tag.builtin.Tag; +import com.nukkitx.protocol.bedrock.data.ItemData; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.network.translators.ItemStackTranslator; +import org.geysermc.connector.network.translators.ItemRemapper; +import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.network.translators.item.Potion; +import org.geysermc.connector.utils.Toolbox; + +import java.util.List; +import java.util.stream.Collectors; + +@ItemRemapper +public class PotionTranslator extends ItemStackTranslator { + + private List appliedItems; + + public PotionTranslator() { + appliedItems = Toolbox.ITEM_ENTRIES.values().stream().filter(entry -> entry.getJavaIdentifier().endsWith("potion")).collect(Collectors.toList()); + } + + @Override + public ItemData translateToBedrock(ItemStack itemStack, ItemEntry itemEntry) { + if (itemStack.getNbt() == null) return super.translateToBedrock(itemStack, itemEntry); + Tag potionTag = itemStack.getNbt().get("Potion"); + if (potionTag instanceof StringTag) { + Potion potion = Potion.getByJavaIdentifier(((StringTag) potionTag).getValue()); + if (potion != null) { + return ItemData.of(itemEntry.getBedrockId(), potion.getBedrockId(), itemStack.getAmount(), translateNbtToBedrock(itemStack.getNbt())); + } + GeyserConnector.getInstance().getLogger().debug("Unknown java potion: " + potionTag.getValue()); + } + return super.translateToBedrock(itemStack, itemEntry); + } + + @Override + public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) { + Potion potion = Potion.getByBedrockId(itemData.getDamage()); + ItemStack itemStack = super.translateToJava(itemData, itemEntry); + if (potion != null) { + StringTag potionTag = new StringTag("Potion", potion.getJavaIdentifier()); + itemStack.getNbt().put(potionTag); + } + return itemStack; + } + + @Override + public List getAppliedItems() { + return appliedItems; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/EnchantedBookTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/EnchantedBookTranslator.java new file mode 100644 index 000000000..2ca6e35cc --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/EnchantedBookTranslator.java @@ -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.item.translators.nbt; + +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.ListTag; +import com.github.steveice10.opennbt.tag.builtin.Tag; +import org.geysermc.connector.network.translators.ItemRemapper; +import org.geysermc.connector.network.translators.NbtItemStackTranslator; +import org.geysermc.connector.network.translators.item.ItemEntry; + +@ItemRemapper(priority = 1) +public class EnchantedBookTranslator extends NbtItemStackTranslator { + + @Override + public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) { + if (itemTag.contains("StoredEnchantments")) { + Tag enchTag = itemTag.get("StoredEnchantments"); + if (enchTag instanceof ListTag) { + enchTag = new ListTag("Enchantments", ((ListTag) enchTag).getValue()); + itemTag.remove("StoredEnchantments"); + itemTag.put(enchTag); + } + } + } + + @Override + public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) { + if (itemTag.contains("Enchantments")) { + Tag enchTag = itemTag.get("Enchantments"); + if (enchTag instanceof ListTag) { + enchTag = new ListTag("StoredEnchantments", ((ListTag) enchTag).getValue()); + itemTag.remove("Enchantments"); + itemTag.put(enchTag); + } + } + } + + @Override + public boolean acceptItem(ItemEntry itemEntry) { + return "minecraft:enchanted_book".equals(itemEntry.getJavaIdentifier()); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/EnchantmentTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/EnchantmentTranslator.java new file mode 100644 index 000000000..fba206668 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/EnchantmentTranslator.java @@ -0,0 +1,140 @@ +/* + * 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.item.translators.nbt; + +import com.github.steveice10.opennbt.tag.builtin.*; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.network.translators.ItemRemapper; +import org.geysermc.connector.network.translators.NbtItemStackTranslator; +import org.geysermc.connector.network.translators.item.Enchantment; +import org.geysermc.connector.network.translators.item.ItemEntry; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@ItemRemapper +public class EnchantmentTranslator extends NbtItemStackTranslator { + + @Override + public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) { + List newTags = new ArrayList<>(); + if (itemTag.contains("Enchantments")) { + ListTag enchantmentTag = itemTag.get("Enchantments"); + for (Tag tag : enchantmentTag.getValue()) { + if (!(tag instanceof CompoundTag)) continue; + + CompoundTag bedrockTag = remapEnchantment((CompoundTag) tag); + newTags.add(bedrockTag); + } + itemTag.remove("Enchantments"); + } + if (itemTag.contains("StoredEnchantments")) { + ListTag enchantmentTag = itemTag.get("StoredEnchantments"); + for (Tag tag : enchantmentTag.getValue()) { + if (!(tag instanceof CompoundTag)) continue; + + CompoundTag bedrockTag = remapEnchantment((CompoundTag) tag); + bedrockTag.put(new ShortTag("GeyserStoredEnchantment", (short) 0)); + newTags.add(bedrockTag); + } + itemTag.remove("StoredEnchantments"); + } + + if (!newTags.isEmpty()) { + itemTag.put(new ListTag("ench", newTags)); + } + } + + @Override + public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) { + if (itemTag.contains("ench")) { + ListTag enchantmentTag = itemTag.get("ench"); + List enchantments = new ArrayList<>(); + List storedEnchantments = new ArrayList<>(); + for (Tag value : enchantmentTag.getValue()) { + if (!(value instanceof CompoundTag)) + continue; + + CompoundTag tagValue = (CompoundTag) value; + ShortTag bedrockId = tagValue.get("id"); + if (bedrockId == null) continue; + + ShortTag geyserStoredEnchantmentTag = tagValue.get("GeyserStoredEnchantment"); + + Enchantment enchantment = Enchantment.getByBedrockId(bedrockId.getValue()); + if (enchantment != null) { + CompoundTag javaTag = new CompoundTag(""); + Map javaValue = javaTag.getValue(); + javaValue.put("id", new StringTag("id", enchantment.getJavaIdentifier())); + ShortTag levelTag = tagValue.get("lvl"); + javaValue.put("lvl", new IntTag("lvl", levelTag != null ? levelTag.getValue() : 1)); + javaTag.setValue(javaValue); + + + if (geyserStoredEnchantmentTag != null) { + tagValue.remove("GeyserStoredEnchantment"); + storedEnchantments.add(javaTag); + } else { + enchantments.add(javaTag); + } + } else { + GeyserConnector.getInstance().getLogger().debug("Unknown bedrock enchantment: " + bedrockId); + } + } + if (!enchantments.isEmpty()) { + itemTag.put(new ListTag("Enchantments", enchantments)); + } + if (!storedEnchantments.isEmpty()) { + itemTag.put(new ListTag("StoredEnchantments", enchantments)); + } + itemTag.remove("ench"); + } + } + + + private CompoundTag remapEnchantment(CompoundTag tag) { + Tag javaEnchLvl = ((CompoundTag) tag).get("lvl"); + if (!(javaEnchLvl instanceof ShortTag)) + return null; + + Tag javaEnchId = ((CompoundTag) tag).get("id"); + if (!(javaEnchId instanceof StringTag)) + return null; + + Enchantment enchantment = Enchantment.getByJavaIdentifier(((StringTag) javaEnchId).getValue()); + if (enchantment == null) { + GeyserConnector.getInstance().getLogger().debug("Unknown java enchantment: " + javaEnchId.getValue()); + return null; + } + + CompoundTag bedrockTag = new CompoundTag(""); + bedrockTag.put(new ShortTag("id", (short) enchantment.ordinal())); + bedrockTag.put(new ShortTag("lvl", ((ShortTag) javaEnchLvl).getValue())); + return bedrockTag; + } + +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/LeatherArmorTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/LeatherArmorTranslator.java new file mode 100644 index 000000000..4b01d912d --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/LeatherArmorTranslator.java @@ -0,0 +1,73 @@ +/* + * 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.item.translators.nbt; + +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.IntTag; +import org.geysermc.connector.network.translators.ItemRemapper; +import org.geysermc.connector.network.translators.NbtItemStackTranslator; +import org.geysermc.connector.network.translators.item.ItemEntry; + +@ItemRemapper +public class LeatherArmorTranslator extends NbtItemStackTranslator { + + private static final String[] ITEMS = new String[]{"minecraft:leather_helmet", "minecraft:leather_chestplate", "minecraft:leather_leggings", "minecraft:leather_boots"}; + + @Override + public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) { + if (itemTag.contains("display")) { + CompoundTag displayTag = itemTag.get("display"); + if (displayTag.contains("color")) { + IntTag color = displayTag.get("color"); + if (color != null) { + itemTag.put(new IntTag("customColor", color.getValue())); + displayTag.remove("color"); + } + } + } + } + + @Override + public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) { + if (itemTag.contains("customColor")) { + IntTag color = itemTag.get("customColor"); + CompoundTag displayTag = itemTag.get("display"); + if (displayTag == null) { + displayTag = new CompoundTag("display"); + } + displayTag.put(color); + itemTag.remove("customColor"); + } + } + + @Override + public boolean acceptItem(ItemEntry itemEntry) { + for (String item : ITEMS) { + if (itemEntry.getJavaIdentifier().equals(item)) return true; + } + return false; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/MapItemTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/MapItemTranslator.java new file mode 100644 index 000000000..cdf272ece --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/MapItemTranslator.java @@ -0,0 +1,58 @@ +/* + * 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.item.translators.nbt; + +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.IntTag; +import com.github.steveice10.opennbt.tag.builtin.StringTag; +import org.geysermc.connector.network.translators.ItemRemapper; +import org.geysermc.connector.network.translators.NbtItemStackTranslator; +import org.geysermc.connector.network.translators.item.ItemEntry; + +@ItemRemapper +public class MapItemTranslator extends NbtItemStackTranslator { + + @Override + public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) { + IntTag mapId = itemTag.get("map"); + + if (mapId != null) { + itemTag.put(new StringTag("map_uuid", mapId.getValue().toString())); + itemTag.put(new IntTag("map_name_index", mapId.getValue())); + itemTag.remove("map"); + } + } + + @Override + public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) { + IntTag tag = itemTag.get("map_name_index"); + if (tag != null) { + itemTag.put(new IntTag("map", tag.getValue())); + itemTag.remove("map_name_index"); + itemTag.remove("map_uuid"); + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java index 18b155e02..c78493a36 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareRecipesTranslator.java @@ -64,9 +64,9 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator, IntSet> squashedOptions = new HashMap<>(); for (int i = 0; i < ingredients.length; i++) { if (ingredients[i].getOptions().length == 0) { @@ -103,7 +103,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator> groupedByIds = Arrays.stream(ingredient.getOptions()) - .map(item -> Translators.getItemTranslator().translateToBedrock(item)) + .map(item -> Translators.getItemTranslator().translateToBedrock(session, item)) .collect(Collectors.groupingBy(item -> new GroupedItem(item.getId(), item.getCount(), item.getTag()))); Set optionSet = new HashSet<>(groupedByIds.size()); for (Map.Entry> entry : groupedByIds.entrySet()) { @@ -136,7 +136,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator 0) { - translatedItems[i] = Translators.getItemTranslator().translateToBedrock(ingredients[i].getOptions()[0]); + translatedItems[i] = Translators.getItemTranslator().translateToBedrock(session, ingredients[i].getOptions()[0]); } else { translatedItems[i] = ItemData.AIR; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityEquipmentTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityEquipmentTranslator.java index 70c171425..a010752d4 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityEquipmentTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityEquipmentTranslator.java @@ -55,7 +55,7 @@ public class JavaEntityEquipmentTranslator extends PacketTranslator