diff --git a/connector/pom.xml b/connector/pom.xml index 3fdd5f37a..9a202d6f5 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -105,7 +105,7 @@ com.github.steveice10 mcprotocollib - 7545884a2d + ed6e845095 compile diff --git a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java index 675c2b9a2..601421303 100644 --- a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java +++ b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java @@ -47,6 +47,7 @@ import org.geysermc.connector.network.translators.PacketTranslatorRegistry; import org.geysermc.connector.network.translators.effect.EffectRegistry; import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.item.ItemTranslator; +import org.geysermc.connector.network.translators.item.PotionMixRegistry; import org.geysermc.connector.network.translators.sound.SoundHandlerRegistry; import org.geysermc.connector.network.translators.sound.SoundRegistry; import org.geysermc.connector.network.translators.world.WorldManager; @@ -127,6 +128,7 @@ public class GeyserConnector { ItemRegistry.init(); ItemTranslator.init(); LocaleUtils.init(); + PotionMixRegistry.init(); SoundRegistry.init(); SoundHandlerRegistry.init(); diff --git a/connector/src/main/java/org/geysermc/connector/entity/Entity.java b/connector/src/main/java/org/geysermc/connector/entity/Entity.java index ffe13a50d..1618d6afa 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/Entity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/Entity.java @@ -284,11 +284,11 @@ public class Entity { // Shield code if (session.getPlayerEntity().getEntityId() == entityId && metadata.getFlags().getFlag(EntityFlag.SNEAKING)) { - if ((session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemRegistry.SHIELD) || - (session.getInventoryCache().getPlayerInventory().getItem(45) != null && session.getInventoryCache().getPlayerInventory().getItem(45).getId() == ItemRegistry.SHIELD)) { + if ((session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemRegistry.SHIELD.getJavaId()) || + (session.getInventoryCache().getPlayerInventory().getItem(45) != null && session.getInventoryCache().getPlayerInventory().getItem(45).getId() == ItemRegistry.SHIELD.getJavaId())) { ClientPlayerUseItemPacket useItemPacket; metadata.getFlags().setFlag(EntityFlag.BLOCKING, true); - if (session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemRegistry.SHIELD) { + if (session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemRegistry.SHIELD.getJavaId()) { useItemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND); } // Else we just assume it's the offhand, to simplify logic and to assure the packet gets sent diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/MagmaCubeEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/MagmaCubeEntity.java new file mode 100644 index 000000000..320f08987 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/entity/living/MagmaCubeEntity.java @@ -0,0 +1,65 @@ +/* + * 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.entity.living; + +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; + +public class MagmaCubeEntity extends SlimeEntity { + + public MagmaCubeEntity(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) { + super.updateBedrockMetadata(entityMetadata, session); + } + + @Override + public void moveRelative(GeyserSession session, double relX, double relY, double relZ, Vector3f rotation, boolean isOnGround) { + updateJump(session, isOnGround); + super.moveRelative(session, relX, relY, relZ, rotation, isOnGround); + } + + @Override + public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) { + updateJump(session, isOnGround); + super.moveAbsolute(session, position, rotation, isOnGround, teleported); + } + + public void updateJump(GeyserSession session, boolean newOnGround) { + if (newOnGround != onGround) { + // Add the jumping effect to the magma cube + metadata.put(EntityData.CLIENT_EVENT, (byte) (newOnGround ? 1 : 2)); + updateBedrockMetadata(session); + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/PiglinEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/PiglinEntity.java index 78a420b8c..83027e30e 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/PiglinEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/PiglinEntity.java @@ -31,6 +31,7 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.item.ItemRegistry; public class PiglinEntity extends MonsterEntity { @@ -56,4 +57,13 @@ public class PiglinEntity extends MonsterEntity { super.updateBedrockMetadata(entityMetadata, session); } + + @Override + public void updateEquipment(GeyserSession session) { + // Check if the Piglin is holding Gold and set the ADMIRING flag accordingly + metadata.getFlags().setFlag(EntityFlag.ADMIRING, offHand.getId() == ItemRegistry.GOLD.getBedrockId()); + super.updateBedrockMetadata(session); + + super.updateEquipment(session); + } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java b/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java index 6bc1a1b0b..e73fd7aa5 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java +++ b/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java @@ -74,7 +74,7 @@ public enum EntityType { SILVERFISH(MonsterEntity.class, 39, 0.3f, 0.4f), CAVE_SPIDER(MonsterEntity.class, 40, 0.5f, 0.7f), GHAST(FlyingEntity.class, 41, 4.0f), - MAGMA_CUBE(SlimeEntity.class, 42, 0.51f), + MAGMA_CUBE(MagmaCubeEntity.class, 42, 0.51f), BLAZE(BlazeEntity.class, 43, 1.8f, 0.6f), ZOMBIE_VILLAGER(ZombieEntity.class, 44, 1.8f, 0.6f, 0.6f, 1.62f), WITCH(RaidParticipantEntity.class, 45, 1.8f, 0.6f, 0.6f, 1.62f), diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInteractTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInteractTranslator.java index 167073273..7d03f9832 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInteractTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInteractTranslator.java @@ -60,7 +60,7 @@ public class BedrockInteractTranslator extends PacketTranslator switch (packet.getAction()) { case INTERACT: - if (session.getInventory().getItem(session.getInventory().getHeldItemSlot() + 36).getId() == ItemRegistry.SHIELD) { + if (session.getInventory().getItem(session.getInventory().getHeldItemSlot() + 36).getId() == ItemRegistry.SHIELD.getJavaId()) { break; } ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(), 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 25e1c54e2..d4168709f 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 @@ -99,7 +99,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator ITEM_ENTRIES = new Int2ObjectOpenHashMap<>(); // Shield ID, used in Entity.java - public static final int SHIELD = 829; + public static ItemEntry SHIELD; // Boat ID, used in BedrockInventoryTransactionTranslator.java - public static final int BOAT = 333; + public static ItemEntry BOAT; + // Gold ID, used in PiglinEntity.java + public static ItemEntry GOLD; public static int BARRIER_INDEX = 0; @@ -123,8 +125,21 @@ public class ItemRegistry { entry.getValue().get("bedrock_data").intValue(), entry.getValue().get("is_block") != null && entry.getValue().get("is_block").booleanValue())); } - if (entry.getKey().equals("minecraft:barrier")) { - BARRIER_INDEX = itemIndex; + switch (entry.getKey()) { + case "minecraft:barrier": + BARRIER_INDEX = itemIndex; + break; + case "minecraft:oak_boat": + BOAT = ITEM_ENTRIES.get(itemIndex); + break; + case "minecraft:gold_ingot": + GOLD = ITEM_ENTRIES.get(itemIndex); + break; + case "minecraft:shield": + SHIELD = ITEM_ENTRIES.get(itemIndex); + break; + default: + break; } itemIndex++; 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 fde799fe4..e28e8b0c8 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 @@ -157,7 +157,7 @@ public abstract class ItemTranslator { NbtMap tag = itemData.getTag(); if (tag != null) { NbtMap display = tag.getCompound("display"); - if (display != null) { + if (display != null && !display.isEmpty()) { String name = display.getString("Name"); // If its not a message convert it diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/PotionMixRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/PotionMixRegistry.java new file mode 100644 index 000000000..02e01d83c --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/PotionMixRegistry.java @@ -0,0 +1,113 @@ +/* + * 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 com.nukkitx.protocol.bedrock.data.inventory.PotionMixData; + +import java.util.*; + +/** + * Generates a {@link Collection} of {@link PotionMixData} that enables the + * Bedrock client to place brewing items into the brewing stand. + * (Does not contain actual potion mixes.) + * + * Designed to replicate Java Edition behavior. + * (Ex: Bedrock cannot normally place glass bottles or fully upgraded + * potions into the brewing stand, but Java can.) + */ +public class PotionMixRegistry { + public static final Collection POTION_MIXES; + + private PotionMixRegistry() { + } + + public static void init() { + // no-op + } + + static { + List ingredients = new ArrayList<>(); + ingredients.add(getNonNull("minecraft:nether_wart")); + ingredients.add(getNonNull("minecraft:redstone")); + ingredients.add(getNonNull("minecraft:glowstone_dust")); + ingredients.add(getNonNull("minecraft:fermented_spider_eye")); + ingredients.add(getNonNull("minecraft:gunpowder")); + ingredients.add(getNonNull("minecraft:dragon_breath")); + ingredients.add(getNonNull("minecraft:sugar")); + ingredients.add(getNonNull("minecraft:rabbit_foot")); + ingredients.add(getNonNull("minecraft:glistering_melon_slice")); + ingredients.add(getNonNull("minecraft:spider_eye")); + ingredients.add(getNonNull("minecraft:pufferfish")); + ingredients.add(getNonNull("minecraft:magma_cream")); + ingredients.add(getNonNull("minecraft:golden_carrot")); + ingredients.add(getNonNull("minecraft:blaze_powder")); + ingredients.add(getNonNull("minecraft:ghast_tear")); + ingredients.add(getNonNull("minecraft:turtle_helmet")); + ingredients.add(getNonNull("minecraft:phantom_membrane")); + + List inputs = new ArrayList<>(); + inputs.add(getNonNull("minecraft:potion")); + inputs.add(getNonNull("minecraft:splash_potion")); + inputs.add(getNonNull("minecraft:lingering_potion")); + + ItemEntry glassBottle = getNonNull("minecraft:glass_bottle"); + + Set potionMixes = new HashSet<>(); + + // Add all types of potions as inputs + ItemEntry fillerIngredient = ingredients.get(0); + for (ItemEntry input : inputs) { + for (Potion potion : Potion.values()) { + potionMixes.add(new PotionMixData( + input.getBedrockId(), potion.getBedrockId(), + fillerIngredient.getBedrockId(), fillerIngredient.getBedrockData(), + glassBottle.getBedrockId(), glassBottle.getBedrockData()) + ); + } + } + + // Add all brewing ingredients + // Also adds glass bottle as input + for (ItemEntry ingredient : ingredients) { + potionMixes.add(new PotionMixData( + glassBottle.getBedrockId(), glassBottle.getBedrockData(), + ingredient.getBedrockId(), ingredient.getBedrockData(), + glassBottle.getBedrockId(), glassBottle.getBedrockData()) + ); + } + + POTION_MIXES = potionMixes; + } + + private static ItemEntry getNonNull(String javaIdentifier) { + ItemEntry itemEntry = ItemRegistry.getItemEntry(javaIdentifier); + if (itemEntry == null) + throw new NullPointerException("No item entry exists for java identifier: " + javaIdentifier); + + return itemEntry; + } +} 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 index 51029b83d..4a36880c9 100644 --- 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 @@ -28,10 +28,10 @@ package org.geysermc.connector.network.translators.item.translators.nbt; import com.github.steveice10.opennbt.tag.builtin.ByteTag; 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 com.github.steveice10.opennbt.tag.builtin.LongTag; import org.geysermc.connector.network.translators.ItemRemapper; -import org.geysermc.connector.network.translators.item.NbtItemStackTranslator; import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.network.translators.item.NbtItemStackTranslator; @ItemRemapper public class MapItemTranslator extends NbtItemStackTranslator { @@ -41,7 +41,7 @@ public class MapItemTranslator extends NbtItemStackTranslator { IntTag mapId = itemTag.get("map"); if (mapId != null) { - itemTag.put(new StringTag("map_uuid", mapId.getValue().toString())); + itemTag.put(new LongTag("map_uuid", mapId.getValue())); itemTag.put(new IntTag("map_name_index", mapId.getValue())); itemTag.put(new ByteTag("map_display_players", (byte) 1)); itemTag.remove("map"); 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 08022640f..75ccc0a5a 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 @@ -33,7 +33,6 @@ import com.github.steveice10.mc.protocol.packet.ingame.server.ServerDeclareRecip import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.data.inventory.CraftingData; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; -import com.nukkitx.protocol.bedrock.data.inventory.PotionMixData; import com.nukkitx.protocol.bedrock.packet.CraftingDataPacket; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; @@ -45,16 +44,13 @@ import org.geysermc.connector.network.translators.Translator; 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.PotionMixRegistry; import java.util.*; import java.util.stream.Collectors; @Translator(packet = ServerDeclareRecipesPacket.class) public class JavaDeclareRecipesTranslator extends PacketTranslator { - private static final Collection POTION_MIXES = - Arrays.stream(new int[]{372, 331, 348, 376, 289, 437, 353, 414, 382, 375, 462, 378, 396, 377, 370, 469, 470}) - .mapToObj(ingredient -> new PotionMixData(0, ingredient, 0, 0, 0, 0)) //TODO: Confirm this is correct behavior. - .collect(Collectors.toList()); @Override public void translate(ServerDeclareRecipesPacket packet, GeyserSession session) { @@ -89,7 +85,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator skinParts = Arrays.asList(SkinPart.values()); - ClientSettingsPacket clientSettingsPacket = new ClientSettingsPacket(locale, (byte) session.getRenderDistance(), ChatVisibility.FULL, true, skinParts, Hand.MAIN_HAND); + ClientSettingsPacket clientSettingsPacket = new ClientSettingsPacket(locale, (byte) session.getRenderDistance(), ChatVisibility.FULL, true, skinParts, HandPreference.RIGHT_HAND); session.sendDownstreamPacket(clientSettingsPacket); if (!packet.getDimension().equals(entity.getDimension())) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BannerBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BannerBlockEntityTranslator.java index e2a555090..9e86cb4cf 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BannerBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BannerBlockEntityTranslator.java @@ -55,7 +55,7 @@ public class BannerBlockEntityTranslator extends BlockEntityTranslator implement if (tag.contains("Patterns")) { ListTag patterns = tag.get("Patterns"); - tags.put("", BannerTranslator.convertBannerPattern(patterns)); + tags.put("Patterns", BannerTranslator.convertBannerPattern(patterns)); } if (tag.contains("CustomName")) { diff --git a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java index bf1962246..44536ccf6 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java @@ -391,7 +391,8 @@ public class MessageUtils { for (Map.Entry testColor : COLORS.entrySet()) { if (testColor.getValue() == rgb) { - return testColor.getKey(); + closest = testColor.getKey(); + break; } int testR = (testColor.getValue() >> 16) & 0xFF; diff --git a/connector/src/main/resources/languages b/connector/src/main/resources/languages index fc8f930a2..37a10837d 160000 --- a/connector/src/main/resources/languages +++ b/connector/src/main/resources/languages @@ -1 +1 @@ -Subproject commit fc8f930a238a375c7e3be6e5c7ea1720b61d0cca +Subproject commit 37a10837d1cf34b4c28f4879b62fcef200d43e60