diff --git a/connector/src/main/java/org/geysermc/connector/entity/TippedArrowEntity.java b/connector/src/main/java/org/geysermc/connector/entity/TippedArrowEntity.java index def5715c..949764b9 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/TippedArrowEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/TippedArrowEntity.java @@ -25,12 +25,39 @@ package org.geysermc.connector.entity; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.entity.EntityData; import org.geysermc.connector.entity.type.EntityType; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.item.TippedArrowPotion; +/** + * Internally this is known as TippedArrowEntity but is used with tipped arrows and normal arrows + */ public class TippedArrowEntity extends AbstractArrowEntity { public TippedArrowEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); } + + @Override + public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { + // Arrow potion effect color + if (entityMetadata.getId() == 9) { + int potionColor = (int) entityMetadata.getValue(); + // -1 means no color + if (potionColor == -1) { + metadata.remove(EntityData.CUSTOM_DISPLAY); + } else { + TippedArrowPotion potion = TippedArrowPotion.getByJavaColor(potionColor); + if (potion != null && potion.getJavaColor() != -1) { + metadata.put(EntityData.CUSTOM_DISPLAY, (byte) potion.getBedrockId()); + } else { + metadata.remove(EntityData.CUSTOM_DISPLAY); + } + } + } + super.updateBedrockMetadata(entityMetadata, session); + } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java index 1f3af019..850e4e05 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java @@ -197,7 +197,9 @@ public class ItemRegistry { */ public static ItemEntry getItem(ItemData data) { for (ItemEntry itemEntry : ITEM_ENTRIES.values()) { - if (itemEntry.getBedrockId() == data.getId() && (itemEntry.getBedrockData() == data.getDamage() || itemEntry.getJavaIdentifier().endsWith("potion"))) { + if (itemEntry.getBedrockId() == data.getId() && (itemEntry.getBedrockData() == data.getDamage() || + // Make exceptions for potions and tipped arrows, whose damage values can vary + (itemEntry.getJavaIdentifier().endsWith("potion") || itemEntry.getJavaIdentifier().equals("minecraft:arrow")))) { return itemEntry; } } 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 51ae36e4..b9a213d8 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 @@ -48,7 +48,7 @@ public enum Potion { STRONG_SWIFTNESS(16), LONG_SWIFTNESS(15), SLOWNESS(17), - STRONG_SLOWNESS(18), //does not exist + STRONG_SLOWNESS(42), LONG_SLOWNESS(18), WATER_BREATHING(19), LONG_WATER_BREATHING(20), diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/TippedArrowPotion.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/TippedArrowPotion.java new file mode 100644 index 00000000..7a5b576b --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/TippedArrowPotion.java @@ -0,0 +1,151 @@ +/* + * 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; + +import lombok.Getter; + +import java.util.Locale; + +/** + * Potion identifiers and their respective Bedrock IDs used with arrows. + * https://minecraft.gamepedia.com/Arrow#Item_Data + */ +@Getter +public enum TippedArrowPotion { + MUNDANE(2, ArrowParticleColors.NONE), // 3 is extended? + THICK(4, ArrowParticleColors.NONE), + AWKWARD(5, ArrowParticleColors.NONE), + NIGHT_VISION(6, ArrowParticleColors.NIGHT_VISION), + LONG_NIGHT_VISION(7, ArrowParticleColors.NIGHT_VISION), + INVISIBILITY(8, ArrowParticleColors.INVISIBILITY), + LONG_INVISIBILITY(9, ArrowParticleColors.INVISIBILITY), + LEAPING(10, ArrowParticleColors.LEAPING), + LONG_LEAPING(11, ArrowParticleColors.LEAPING), + STRONG_LEAPING(12, ArrowParticleColors.LEAPING), + FIRE_RESISTANCE(13, ArrowParticleColors.FIRE_RESISTANCE), + LONG_FIRE_RESISTANCE(14, ArrowParticleColors.FIRE_RESISTANCE), + SWIFTNESS(15, ArrowParticleColors.SWIFTNESS), + LONG_SWIFTNESS(16, ArrowParticleColors.SWIFTNESS), + STRONG_SWIFTNESS(17, ArrowParticleColors.SWIFTNESS), + SLOWNESS(18, ArrowParticleColors.SLOWNESS), + LONG_SLOWNESS(19, ArrowParticleColors.SLOWNESS), + STRONG_SLOWNESS(43, ArrowParticleColors.SLOWNESS), + WATER_BREATHING(20, ArrowParticleColors.WATER_BREATHING), + LONG_WATER_BREATHING(21, ArrowParticleColors.WATER_BREATHING), + HEALING(22, ArrowParticleColors.HEALING), + STRONG_HEALING(23, ArrowParticleColors.HEALING), + HARMING(24, ArrowParticleColors.HARMING), + STRONG_HARMING(25, ArrowParticleColors.HARMING), + POISON(26, ArrowParticleColors.POISON), + LONG_POISON(27, ArrowParticleColors.POISON), + STRONG_POISON(28, ArrowParticleColors.POISON), + REGENERATION(29, ArrowParticleColors.REGENERATION), + LONG_REGENERATION(30, ArrowParticleColors.REGENERATION), + STRONG_REGENERATION(31, ArrowParticleColors.REGENERATION), + STRENGTH(32, ArrowParticleColors.STRENGTH), + LONG_STRENGTH(33, ArrowParticleColors.STRENGTH), + STRONG_STRENGTH(34, ArrowParticleColors.STRENGTH), + WEAKNESS(35, ArrowParticleColors.WEAKNESS), + LONG_WEAKNESS(36, ArrowParticleColors.WEAKNESS), + LUCK(2, ArrowParticleColors.NONE), // does not exist in Bedrock + TURTLE_MASTER(38, ArrowParticleColors.TURTLE_MASTER), + LONG_TURTLE_MASTER(39, ArrowParticleColors.TURTLE_MASTER), + STRONG_TURTLE_MASTER(40, ArrowParticleColors.TURTLE_MASTER), + SLOW_FALLING(41, ArrowParticleColors.SLOW_FALLING), + LONG_SLOW_FALLING(42, ArrowParticleColors.SLOW_FALLING); + + private final String javaIdentifier; + private final short bedrockId; + /** + * The Java color associated with this ID. + * Used for looking up Java arrow color entity metadata as Bedrock potion IDs, which is what is used for entities in Bedrock + */ + private final int javaColor; + + TippedArrowPotion(int bedrockId, ArrowParticleColors arrowParticleColor) { + this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ENGLISH); + this.bedrockId = (short) bedrockId; + this.javaColor = arrowParticleColor.getColor(); + } + + public static TippedArrowPotion getByJavaIdentifier(String javaIdentifier) { + for (TippedArrowPotion potion : TippedArrowPotion.values()) { + if (potion.javaIdentifier.equals(javaIdentifier)) { + return potion; + } + } + return null; + } + + public static TippedArrowPotion getByBedrockId(short bedrockId) { + for (TippedArrowPotion potion : TippedArrowPotion.values()) { + if (potion.bedrockId == bedrockId) { + return potion; + } + } + return null; + } + + /** + * @param color the potion color to look up + * @return the tipped arrow potion that most closely resembles that color. + */ + public static TippedArrowPotion getByJavaColor(int color) { + for (TippedArrowPotion potion : TippedArrowPotion.values()) { + if (potion.javaColor == color) { + return potion; + } + } + return null; + } + + private enum ArrowParticleColors { + NONE(-1), + NIGHT_VISION(2039713), + INVISIBILITY(8356754), + LEAPING(2293580), + FIRE_RESISTANCE(14981690), + SWIFTNESS(8171462), + SLOWNESS(5926017), + TURTLE_MASTER(7691106), + WATER_BREATHING(3035801), + HEALING(16262179), + HARMING(4393481), + POISON(5149489), + REGENERATION(13458603), + STRENGTH(9643043), + WEAKNESS(4738376), + LUCK(3381504), + SLOW_FALLING(16773073); + + @Getter + private final int color; + + ArrowParticleColors(int color) { + this.color = color; + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java index 304ea3fb..f4bfdfb6 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java @@ -50,7 +50,7 @@ import java.util.stream.Collectors; @ItemRemapper public class BannerTranslator extends ItemTranslator { - private List appliedItems; + private final List appliedItems; public BannerTranslator() { appliedItems = ItemRegistry.ITEM_ENTRIES.values().stream().filter(entry -> entry.getJavaIdentifier().endsWith("banner")).collect(Collectors.toList()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/CompassTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/CompassTranslator.java index 675d4255..159b9ab4 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/CompassTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/CompassTranslator.java @@ -40,7 +40,7 @@ import java.util.stream.Collectors; @ItemRemapper public class CompassTranslator extends ItemTranslator { - private List appliedItems; + private final List appliedItems; public CompassTranslator() { appliedItems = ItemRegistry.ITEM_ENTRIES.values().stream().filter(entry -> entry.getJavaIdentifier().endsWith("compass")).collect(Collectors.toList()); 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 index 7cb88d70..24130a7f 100644 --- 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 @@ -42,7 +42,7 @@ import java.util.stream.Collectors; @ItemRemapper public class PotionTranslator extends ItemTranslator { - private List appliedItems; + private final List appliedItems; public PotionTranslator() { appliedItems = ItemRegistry.ITEM_ENTRIES.values().stream().filter(entry -> entry.getJavaIdentifier().endsWith("potion")).collect(Collectors.toList()); @@ -57,7 +57,7 @@ public class PotionTranslator extends ItemTranslator { if (potion != null) { return ItemData.of(itemEntry.getBedrockId(), potion.getBedrockId(), itemStack.getAmount(), translateNbtToBedrock(itemStack.getNbt())); } - GeyserConnector.getInstance().getLogger().debug("Unknown java potion: " + potionTag.getValue()); + GeyserConnector.getInstance().getLogger().debug("Unknown Java potion: " + potionTag.getValue()); } return super.translateToBedrock(itemStack, itemEntry); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/TippedArrowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/TippedArrowTranslator.java new file mode 100644 index 00000000..0b69d6a2 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/TippedArrowTranslator.java @@ -0,0 +1,87 @@ +/* + * 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.inventory.ItemData; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.network.translators.ItemRemapper; +import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.network.translators.item.ItemRegistry; +import org.geysermc.connector.network.translators.item.ItemTranslator; +import org.geysermc.connector.network.translators.item.TippedArrowPotion; + +import java.util.List; +import java.util.stream.Collectors; + +@ItemRemapper +public class TippedArrowTranslator extends ItemTranslator { + + private final List appliedItems; + + private static final int TIPPED_ARROW_JAVA_ID = ItemRegistry.getItemEntry("minecraft:tipped_arrow").getJavaId(); + + public TippedArrowTranslator() { + appliedItems = ItemRegistry.ITEM_ENTRIES.values().stream().filter(entry -> + entry.getJavaIdentifier().contains("arrow") && !entry.getJavaIdentifier().contains("spectral")).collect(Collectors.toList()); + } + + @Override + public ItemData translateToBedrock(ItemStack itemStack, ItemEntry itemEntry) { + if (!itemEntry.getJavaIdentifier().equals("minecraft:tipped_arrow") || itemStack.getNbt() == null) { + // We're only concerned about minecraft:arrow when translating Bedrock -> Java + return super.translateToBedrock(itemStack, itemEntry); + } + Tag potionTag = itemStack.getNbt().get("Potion"); + if (potionTag instanceof StringTag) { + TippedArrowPotion tippedArrowPotion = TippedArrowPotion.getByJavaIdentifier(((StringTag) potionTag).getValue()); + if (tippedArrowPotion != null) { + return ItemData.of(itemEntry.getBedrockId(), tippedArrowPotion.getBedrockId(), itemStack.getAmount(), translateNbtToBedrock(itemStack.getNbt())); + } + GeyserConnector.getInstance().getLogger().debug("Unknown Java potion (tipped arrow): " + potionTag.getValue()); + } + return super.translateToBedrock(itemStack, itemEntry); + } + + @Override + public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) { + TippedArrowPotion tippedArrowPotion = TippedArrowPotion.getByBedrockId(itemData.getDamage()); + ItemStack itemStack = super.translateToJava(itemData, itemEntry); + if (tippedArrowPotion != null) { + itemStack = new ItemStack(TIPPED_ARROW_JAVA_ID, itemStack.getAmount(), itemStack.getNbt()); + StringTag potionTag = new StringTag("Potion", tippedArrowPotion.getJavaIdentifier()); + itemStack.getNbt().put(potionTag); + } + return itemStack; + } + + @Override + public List getAppliedItems() { + return appliedItems; + } +}