From d4995acec694009fb512a7a9d6d5a106208f7f17 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Thu, 14 May 2020 12:30:33 -0400 Subject: [PATCH 01/73] Add support for absorption (golden hearts) (#553) Absorption is an attribute in Bedrock and an entity metadata value in Java. This commit sends an attribute update packet when the metadata value is updated. --- .../connector/entity/PlayerEntity.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java index 43891a7e..98b6b7da 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java @@ -26,14 +26,12 @@ package org.geysermc.connector.entity; import com.github.steveice10.mc.auth.data.GameProfile; +import com.github.steveice10.mc.protocol.data.game.entity.Effect; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.github.steveice10.mc.protocol.data.message.TextMessage; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.CommandPermission; -import com.nukkitx.protocol.bedrock.data.EntityData; -import com.nukkitx.protocol.bedrock.data.EntityLink; -import com.nukkitx.protocol.bedrock.data.PlayerPermission; +import com.nukkitx.protocol.bedrock.data.*; import com.nukkitx.protocol.bedrock.packet.*; import lombok.Getter; @@ -47,6 +45,8 @@ import org.geysermc.connector.utils.MessageUtils; import org.geysermc.connector.network.session.cache.EntityEffectCache; import org.geysermc.connector.utils.SkinUtils; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -205,6 +205,17 @@ public class PlayerEntity extends LivingEntity { } } + // Extra hearts - is not metadata but an attribute on Bedrock + if (entityMetadata.getId() == 14) { + UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket(); + attributesPacket.setRuntimeEntityId(geyserId); + List attributes = new ArrayList<>(); + // Setting to a higher maximum since plugins/datapacks can probably extend the Bedrock soft limit + attributes.add(new Attribute("minecraft:absorption", 0.0f, 1024f, (float) entityMetadata.getValue(), 0.0f)); + attributesPacket.setAttributes(attributes); + session.sendUpstreamPacket(attributesPacket); + } + // Parrot occupying shoulder if (entityMetadata.getId() == 18 || entityMetadata.getId() == 19) { CompoundTag tag = (CompoundTag) entityMetadata.getValue(); From 919af5203d27289af3f0e7549d2e5982958cdabf Mon Sep 17 00:00:00 2001 From: rtm516 Date: Fri, 15 May 2020 01:41:42 +0100 Subject: [PATCH 02/73] Fix banner items loosing patterns in inventory (#560) --- .../item/translators/BannerTranslator.java | 93 +++++++++++++++++++ .../entity/BannerBlockEntityTranslator.java | 39 ++------ .../geysermc/connector/utils/ItemUtils.java | 79 ++++++++++++++++ 3 files changed, 179 insertions(+), 32 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java 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 new file mode 100644 index 00000000..00ee7c0d --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java @@ -0,0 +1,93 @@ +/* + * 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.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.ListTag; +import com.nukkitx.nbt.CompoundTagBuilder; +import com.nukkitx.protocol.bedrock.data.ItemData; +import org.geysermc.connector.network.translators.ItemRemapper; +import org.geysermc.connector.network.translators.ItemStackTranslator; +import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.utils.ItemUtils; +import org.geysermc.connector.utils.Toolbox; + +import java.util.List; +import java.util.stream.Collectors; + +@ItemRemapper +public class BannerTranslator extends ItemStackTranslator { + + private List appliedItems; + + public BannerTranslator() { + appliedItems = Toolbox.ITEM_ENTRIES.values().stream().filter(entry -> entry.getJavaIdentifier().endsWith("banner")).collect(Collectors.toList()); + } + + @Override + public ItemData translateToBedrock(ItemStack itemStack, ItemEntry itemEntry) { + if (itemStack.getNbt() == null) return super.translateToBedrock(itemStack, itemEntry); + + ItemData itemData = super.translateToBedrock(itemStack, itemEntry); + + CompoundTag blockEntityTag = itemStack.getNbt().get("BlockEntityTag"); + if (blockEntityTag.contains("Patterns")) { + ListTag patterns = blockEntityTag.get("Patterns"); + + CompoundTagBuilder builder = itemData.getTag().toBuilder(); + builder.tag(ItemUtils.convertBannerPattern(patterns)); + + itemData = ItemData.of(itemData.getId(), itemData.getDamage(), itemData.getCount(), builder.buildRootTag()); + } + + return itemData; + } + + @Override + public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) { + if (itemData.getTag() == null) return super.translateToJava(itemData, itemEntry); + + ItemStack itemStack = super.translateToJava(itemData, itemEntry); + + com.nukkitx.nbt.tag.CompoundTag nbtTag = itemData.getTag(); + if (nbtTag.contains("Patterns")) { + com.nukkitx.nbt.tag.ListTag patterns = (com.nukkitx.nbt.tag.ListTag) nbtTag.get("Patterns"); + + CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag"); + blockEntityTag.put(ItemUtils.convertBannerPattern(patterns)); + + itemStack.getNbt().put(blockEntityTag); + } + + return itemStack; + } + + @Override + public List getAppliedItems() { + return appliedItems; + } +} 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 eefd8402..41f83bad 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 @@ -33,6 +33,7 @@ import com.nukkitx.nbt.tag.IntTag; import com.nukkitx.nbt.tag.StringTag; import com.nukkitx.nbt.tag.Tag; import org.geysermc.connector.network.translators.world.block.BlockStateValues; +import org.geysermc.connector.utils.ItemUtils; import java.util.ArrayList; import java.util.List; @@ -48,26 +49,21 @@ public class BannerBlockEntityTranslator extends BlockEntityTranslator implement @Override public List> translateTag(CompoundTag tag, BlockState blockState) { List> tags = new ArrayList<>(); + int bannerColor = BlockStateValues.getBannerColor(blockState); if (bannerColor != -1) { tags.add(new IntTag("Base", 15 - bannerColor)); } - ListTag patterns = tag.get("Patterns"); - List tagsList = new ArrayList<>(); + if (tag.contains("Patterns")) { - for (com.github.steveice10.opennbt.tag.builtin.Tag patternTag : patterns.getValue()) { - com.nukkitx.nbt.tag.CompoundTag newPatternTag = getPattern((CompoundTag) patternTag); - if (newPatternTag != null) { - tagsList.add(newPatternTag); - } - } - com.nukkitx.nbt.tag.ListTag bedrockPatterns = - new com.nukkitx.nbt.tag.ListTag<>("Patterns", com.nukkitx.nbt.tag.CompoundTag.class, tagsList); - tags.add(bedrockPatterns); + ListTag patterns = tag.get("Patterns"); + tags.add(ItemUtils.convertBannerPattern(patterns)); } + if (tag.contains("CustomName")) { tags.add(new StringTag("CustomName", (String) tag.get("CustomName").getValue())); } + return tags; } @@ -84,25 +80,4 @@ public class BannerBlockEntityTranslator extends BlockEntityTranslator implement tagBuilder.listTag("Patterns", com.nukkitx.nbt.tag.CompoundTag.class, new ArrayList<>()); return tagBuilder.buildRootTag(); } - - /** - * Convert the Java edition pattern nbt to Bedrock edition, null if the pattern doesn't exist - * - * @param pattern Java edition pattern nbt - * @return The Bedrock edition format pattern nbt - */ - protected com.nukkitx.nbt.tag.CompoundTag getPattern(CompoundTag pattern) { - String patternName = (String) pattern.get("Pattern").getValue(); - - // Return null if its the globe pattern as it doesn't exist on bedrock - if (patternName.equals("glb")) { - return null; - } - - return CompoundTagBuilder.builder() - .intTag("Color", 15 - (int) pattern.get("Color").getValue()) - .stringTag("Pattern", (String) pattern.get("Pattern").getValue()) - .stringTag("Pattern", patternName) - .buildRootTag(); - } } diff --git a/connector/src/main/java/org/geysermc/connector/utils/ItemUtils.java b/connector/src/main/java/org/geysermc/connector/utils/ItemUtils.java index bb3cf0ed..d3fe48d9 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/ItemUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/ItemUtils.java @@ -26,6 +26,12 @@ package org.geysermc.connector.utils; import com.github.steveice10.opennbt.tag.builtin.*; +import com.nukkitx.nbt.CompoundTagBuilder; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; public class ItemUtils { @@ -44,4 +50,77 @@ public class ItemUtils { } return 0; } + + /** + * Convert a list of patterns from Java nbt to Bedrock nbt + * + * @param patterns The patterns to convert + * @return The new converted patterns + */ + public static com.nukkitx.nbt.tag.ListTag convertBannerPattern(ListTag patterns) { + List tagsList = new ArrayList<>(); + for (com.github.steveice10.opennbt.tag.builtin.Tag patternTag : patterns.getValue()) { + com.nukkitx.nbt.tag.CompoundTag newPatternTag = getBedrockBannerPattern((CompoundTag) patternTag); + if (newPatternTag != null) { + tagsList.add(newPatternTag); + } + } + + return new com.nukkitx.nbt.tag.ListTag<>("Patterns", com.nukkitx.nbt.tag.CompoundTag.class, tagsList); + } + + /** + * Convert the Java edition banner pattern nbt to Bedrock edition, null if the pattern doesn't exist + * + * @param pattern Java edition pattern nbt + * @return The Bedrock edition format pattern nbt + */ + public static com.nukkitx.nbt.tag.CompoundTag getBedrockBannerPattern(CompoundTag pattern) { + String patternName = (String) pattern.get("Pattern").getValue(); + + // Return null if its the globe pattern as it doesn't exist on bedrock + if (patternName.equals("glb")) { + return null; + } + + return CompoundTagBuilder.builder() + .intTag("Color", 15 - (int) pattern.get("Color").getValue()) + .stringTag("Pattern", (String) pattern.get("Pattern").getValue()) + .stringTag("Pattern", patternName) + .buildRootTag(); + } + + /** + * Convert a list of patterns from Bedrock nbt to Java nbt + * + * @param patterns The patterns to convert + * @return The new converted patterns + */ + public static ListTag convertBannerPattern(com.nukkitx.nbt.tag.ListTag patterns) { + List tagsList = new ArrayList<>(); + for (Object patternTag : patterns.getValue()) { + CompoundTag newPatternTag = getJavaBannerPattern((com.nukkitx.nbt.tag.CompoundTag) patternTag); + if (newPatternTag != null) { + tagsList.add(newPatternTag); + } + } + + return new ListTag("Patterns", tagsList); + } + + /** + * Convert the Bedrock edition banner pattern nbt to Java edition + * + * @param pattern Bedorck edition pattern nbt + * @return The Java edition format pattern nbt + */ + public static CompoundTag getJavaBannerPattern(com.nukkitx.nbt.tag.CompoundTag pattern) { + String patternName = (String) pattern.get("Pattern").getValue(); + + Map tags = new HashMap<>(); + tags.put("Color", new IntTag("Color", 15 - pattern.getInt("Color"))); + tags.put("Pattern", new StringTag("Pattern", pattern.getString("Pattern"))); + + return new CompoundTag("", tags); + } } From 2830756a55e5dbe14c906d05600d2933624a9407 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Fri, 15 May 2020 17:08:44 +0100 Subject: [PATCH 03/73] Fixed unusable space being off by 1 (#561) --- .../translators/inventory/updater/ChestInventoryUpdater.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 e9541bd1..6656cc83 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 @@ -48,7 +48,7 @@ public class ChestInventoryUpdater extends InventoryUpdater { ItemData[] bedrockItems = new ItemData[paddedSize]; for (int i = 0; i < bedrockItems.length; i++) { - if (i <= translator.size) { + if (i < translator.size) { bedrockItems[i] = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(i)); } else { bedrockItems[i] = UNUSUABLE_SPACE_BLOCK; From 1b260c16d7cbe6731d5f378fc0f15fee79c4b71a Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Fri, 15 May 2020 13:50:34 -0400 Subject: [PATCH 04/73] Leash fixes (#567) * Leash fixes - Adds visuals for leash string by translating ServerEntityAttachPacket - Updates position offset for lead knots, making them properly appear on fences * Add basic description of JavaEntityAttachTranslator --- .../connector/entity/LeashKnotEntity.java | 39 +++++++++ .../connector/entity/type/EntityType.java | 2 +- .../entity/JavaEntityAttachTranslator.java | 81 +++++++++++++++++++ 3 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 connector/src/main/java/org/geysermc/connector/entity/LeashKnotEntity.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityAttachTranslator.java diff --git a/connector/src/main/java/org/geysermc/connector/entity/LeashKnotEntity.java b/connector/src/main/java/org/geysermc/connector/entity/LeashKnotEntity.java new file mode 100644 index 00000000..0bec07b0 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/entity/LeashKnotEntity.java @@ -0,0 +1,39 @@ +/* + * 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; + +import com.nukkitx.math.vector.Vector3f; +import org.geysermc.connector.entity.type.EntityType; + +public class LeashKnotEntity extends Entity { + + public LeashKnotEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { + // Position is incorrect by default + super(entityId, geyserId, entityType, position.add(0.5f, 0.25f, 0.5f), motion, rotation); + } + +} 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 c77baf0e..ed231d8c 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 @@ -121,7 +121,7 @@ public enum EntityType { FIREBALL(ItemedFireballEntity.class, 85, 1.0f), POTION(ThrowableEntity.class, 86, 0.25f), ENDER_PEARL(ThrowableEntity.class, 87, 0.25f), - LEASH_KNOT(Entity.class, 88, 0.5f, 0.375f), + LEASH_KNOT(LeashKnotEntity.class, 88, 0.5f, 0.375f), WITHER_SKULL(Entity.class, 89, 0.3125f), BOAT(Entity.class, 90, 0.7f, 1.6f, 1.6f, 0.35f), WITHER_SKULL_DANGEROUS(Entity.class, 91, 0f), diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityAttachTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityAttachTranslator.java new file mode 100644 index 00000000..6e53df27 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityAttachTranslator.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + * + */ + +package org.geysermc.connector.network.translators.java.entity; + +import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityAttachPacket; +import com.nukkitx.protocol.bedrock.data.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityEventType; +import com.nukkitx.protocol.bedrock.data.EntityFlag; +import com.nukkitx.protocol.bedrock.packet.EntityEventPacket; +import org.geysermc.connector.entity.Entity; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.network.translators.Translator; + +/** + * Called when a leash is attached, removed or updated from an entity + */ +@Translator(packet = ServerEntityAttachPacket.class) +public class JavaEntityAttachTranslator extends PacketTranslator { + + @Override + public void translate(ServerEntityAttachPacket packet, GeyserSession session) { + + Entity holderId; + if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) { + holderId = session.getPlayerEntity(); + } else { + holderId = session.getEntityCache().getEntityByJavaId(packet.getEntityId()); + if (holderId == null) { + return; + } + } + + Entity attachedToId; + if (packet.getAttachedToId() == session.getPlayerEntity().getEntityId()) { + attachedToId = session.getPlayerEntity(); + } else { + attachedToId = session.getEntityCache().getEntityByJavaId(packet.getAttachedToId()); + if ((attachedToId == null || packet.getAttachedToId() == 0)) { + // Is not being leashed + holderId.getMetadata().getFlags().setFlag(EntityFlag.LEASHED, false); + holderId.getMetadata().put(EntityData.LEAD_HOLDER_EID, 0); + holderId.updateBedrockMetadata(session); + EntityEventPacket eventPacket = new EntityEventPacket(); + eventPacket.setRuntimeEntityId(holderId.getGeyserId()); + eventPacket.setType(EntityEventType.REMOVE_LEASH); + eventPacket.setData(0); + session.sendUpstreamPacket(eventPacket); + return; + } + } + + holderId.getMetadata().getFlags().setFlag(EntityFlag.LEASHED, true); + holderId.getMetadata().put(EntityData.LEAD_HOLDER_EID, attachedToId.getGeyserId()); + holderId.updateBedrockMetadata(session); + } +} From b4ecb88d4942fa75d9d2fc1221e34695ef15c9b2 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Fri, 15 May 2020 16:29:54 -0400 Subject: [PATCH 05/73] Add air bubble UI support (#569) This commit translates entity metadata ID 1 into the AIR entity metadata. --- .../main/java/org/geysermc/connector/entity/Entity.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) 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 2fe830af..d0c1920f 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/Entity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/Entity.java @@ -98,7 +98,7 @@ public class Entity { metadata.put(EntityData.SCALE, 1f); metadata.put(EntityData.COLOR, 0); - metadata.put(EntityData.MAX_AIR, (short) 400); + metadata.put(EntityData.MAX_AIR, (short) 300); metadata.put(EntityData.AIR, (short) 0); metadata.put(EntityData.LEAD_HOLDER_EID, -1L); metadata.put(EntityData.BOUNDING_BOX_HEIGHT, entityType.getHeight()); @@ -242,6 +242,13 @@ public class Entity { } } break; + case 1: // Air/bubbles + if ((int) entityMetadata.getValue() == 300) { + metadata.put(EntityData.AIR, (short) 0); // Otherwise the bubble counter remains in the UI + } else { + metadata.put(EntityData.AIR, (short) (int) entityMetadata.getValue()); + } + break; case 2: // custom name TextMessage name = (TextMessage) entityMetadata.getValue(); if (name != null) From 3220532083982f2357c9c8c35cd2e6046c712208 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sun, 17 May 2020 05:57:18 +0100 Subject: [PATCH 06/73] Fixed fishing rod lines not connecting to other players (#580) --- .../geysermc/connector/entity/FishingHookEntity.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/entity/FishingHookEntity.java b/connector/src/main/java/org/geysermc/connector/entity/FishingHookEntity.java index 8d8d5ef2..808e1667 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/FishingHookEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/FishingHookEntity.java @@ -37,10 +37,14 @@ public class FishingHookEntity extends Entity { public FishingHookEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation, ProjectileData data) { super(entityId, geyserId, entityType, position, motion, rotation); - // TODO: Find a better way to do this for (GeyserSession session : GeyserConnector.getInstance().getPlayers().values()) { - if (session.getPlayerEntity().getEntityId() == data.getOwnerId()) { - this.metadata.put(EntityData.OWNER_EID, session.getPlayerEntity().getGeyserId()); + Entity entity = session.getEntityCache().getEntityByJavaId(data.getOwnerId()); + if (entity == null && session.getPlayerEntity().getEntityId() == data.getOwnerId()) { + entity = session.getPlayerEntity(); + } + + if (entity != null) { + this.metadata.put(EntityData.OWNER_EID, entity.getGeyserId()); return; } } From 563cde2adece3cc99702160bb5249ee45aa18268 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Sun, 17 May 2020 00:57:34 -0400 Subject: [PATCH 07/73] Switch to client's translation for jukebox song name. (#573) Just for consistency with the other part of the code. --- .../translators/java/world/JavaPlayEffectTranslator.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayEffectTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayEffectTranslator.java index 3afb79bd..79a2c920 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayEffectTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayEffectTranslator.java @@ -140,8 +140,7 @@ public class JavaPlayEffectTranslator extends PacketTranslator params = new ArrayList<>(); - // Couldn't figure out how to set this to Bedrock translation so it just uses the Java translation - String recordString = "item.minecraft." + EffectUtils.RECORDS.get(recordEffectData.getRecordId()).name().toLowerCase().replace("record_", "music_disc_") + ".desc"; + String recordString = "%item." + EffectUtils.RECORDS.get(recordEffectData.getRecordId()).name().toLowerCase() + ".desc"; params.add(LocaleUtils.getLocaleString(recordString, session.getClientData().getLanguageCode())); textPacket.setParameters(params); session.sendUpstreamPacket(textPacket); From 95b7055c10dfdce25c226b7ad5209407e75f3414 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sun, 17 May 2020 05:58:00 +0100 Subject: [PATCH 08/73] Added map icons (#572) * Added map icons * Cleaned up and moved to enum --- .../translators/nbt/MapItemTranslator.java | 2 + .../java/world/JavaMapDataTranslator.java | 14 +++ .../connector/utils/BedrockMapIcon.java | 118 ++++++++++++++++++ .../geysermc/connector/utils/MapColor.java | 26 ++++ 4 files changed, 160 insertions(+) create mode 100644 connector/src/main/java/org/geysermc/connector/utils/BedrockMapIcon.java 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 cdf272ec..7e6bc729 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 @@ -25,6 +25,7 @@ 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; @@ -42,6 +43,7 @@ public class MapItemTranslator extends NbtItemStackTranslator { if (mapId != null) { itemTag.put(new StringTag("map_uuid", mapId.getValue().toString())); 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/world/JavaMapDataTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaMapDataTranslator.java index 78681f8f..c8be3a56 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaMapDataTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaMapDataTranslator.java @@ -26,11 +26,15 @@ package org.geysermc.connector.network.translators.java.world; import com.github.steveice10.mc.protocol.data.game.world.map.MapData; +import com.github.steveice10.mc.protocol.data.game.world.map.MapIcon; import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerMapDataPacket; +import com.nukkitx.protocol.bedrock.data.MapDecoration; +import com.nukkitx.protocol.bedrock.data.MapTrackedObject; import com.nukkitx.protocol.bedrock.packet.ClientboundMapItemDataPacket; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; +import org.geysermc.connector.utils.BedrockMapIcon; import org.geysermc.connector.utils.MapColor; @Translator(packet = ServerMapDataPacket.class) @@ -62,6 +66,16 @@ public class JavaMapDataTranslator extends PacketTranslator mapItemDataPacket.setColors(colors); } + // Bedrock needs an entity id to display an icon + int id = 0; + for (MapIcon icon : packet.getIcons()) { + BedrockMapIcon bedrockMapIcon = BedrockMapIcon.fromType(icon.getIconType()); + + mapItemDataPacket.getTrackedObjects().add(new MapTrackedObject(id)); + mapItemDataPacket.getDecorations().add(new MapDecoration(bedrockMapIcon.getIconID(), icon.getIconRotation(), icon.getCenterX(), icon.getCenterZ(), "", bedrockMapIcon.toARGB())); + id++; + } + session.getUpstream().getSession().sendPacket(mapItemDataPacket); } } diff --git a/connector/src/main/java/org/geysermc/connector/utils/BedrockMapIcon.java b/connector/src/main/java/org/geysermc/connector/utils/BedrockMapIcon.java new file mode 100644 index 00000000..f3ee956b --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/utils/BedrockMapIcon.java @@ -0,0 +1,118 @@ +/* + * 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.utils; + +import com.github.steveice10.mc.protocol.data.game.world.map.MapIconType; +import lombok.Getter; + +public enum BedrockMapIcon { + ICON_WHITE_ARROW(MapIconType.WHITE_ARROW, 0), + ICON_ITEM_FRAME(MapIconType.GREEN_ARROW, 7), + ICON_RED_ARROW(MapIconType.RED_ARROW, 2), + ICON_BLUE_ARROW(MapIconType.BLUE_ARROW, 3), + ICON_TREASURE_MARKER(MapIconType.TREASURE_MARKER, 4), + ICON_RED_POINTER(MapIconType.RED_POINTER, 5), + ICON_WHITE_CIRCLE(MapIconType.WHITE_CIRCLE, 6), + ICON_SMALL_WHITE_CIRCLE(MapIconType.SMALL_WHITE_CIRCLE, 13), + ICON_MANSION(MapIconType.MANSION, 14), + ICON_TEMPLE(MapIconType.TEMPLE, 15), + ICON_WHITE_BANNER(MapIconType.WHITE_BANNER, 13, 255, 255, 255), + ICON_ORANGE_BANNER(MapIconType.ORANGE_BANNER, 13, 249, 128, 29), + ICON_MAGENTA_BANNER(MapIconType.MAGENTA_BANNER, 13, 199, 78, 189), + ICON_LIGHT_BLUE_BANNER(MapIconType.LIGHT_BLUE_BANNER, 13, 58, 179, 218), + ICON_YELLOW_BANNER(MapIconType.YELLOW_BANNER, 13, 254, 216, 61), + ICON_LIME_BANNER(MapIconType.LIME_BANNER, 13, 128, 199, 31), + ICON_PINK_BANNER(MapIconType.PINK_BANNER, 13, 243, 139, 170), + ICON_GRAY_BANNER(MapIconType.GRAY_BANNER, 13, 71, 79, 82), + ICON_LIGHT_GRAY_BANNER(MapIconType.LIGHT_GRAY_BANNER, 13, 157, 157, 151), + ICON_CYAN_BANNER(MapIconType.CYAN_BANNER, 13, 22, 156, 156), + ICON_PURPLE_BANNER(MapIconType.PURPLE_BANNER, 13, 137, 50, 184), + ICON_BLUE_BANNER(MapIconType.BLUE_BANNER, 13, 60, 68, 170), + ICON_BROWN_BANNER(MapIconType.BROWN_BANNER, 13, 131, 84, 50), + ICON_GREEN_BANNER(MapIconType.GREEN_BANNER, 13, 94, 124, 22), + ICON_RED_BANNER(MapIconType.RED_BANNER, 13, 176, 46, 38), + ICON_BLACK_BANNER(MapIconType.BLACK_BANNER, 13, 29, 29, 33); + + private static final BedrockMapIcon[] VALUES = values(); + + private MapIconType iconType; + + @Getter + private int iconID; + + private int red; + private int green; + private int blue; + + BedrockMapIcon(MapIconType iconType, int iconID) { + this.iconType = iconType; + this.iconID = iconID; + + this.red = 255; + this.green = 255; + this.blue = 255; + } + + BedrockMapIcon(MapIconType iconType, int iconID, int red, int green, int blue) { + this.iconType = iconType; + this.iconID = iconID; + + this.red = red; + this.green = green; + this.blue = blue; + } + + /** + * Get the BedrockMapIcon for the Java MapIconType + * + * @param iconType A MapIconType + * @return The mapping for a BedrockMapIcon + */ + public static BedrockMapIcon fromType(MapIconType iconType) { + for (BedrockMapIcon icon : VALUES) { + if (icon.iconType.equals(iconType)) { + return icon; + } + } + + return null; + } + + /** + * Get the ARGB value of a BedrockMapIcon + * + * @return ARGB as an int + */ + public int toARGB() { + int alpha = 255; + + return ((alpha & 0xFF) << 24) | + ((red & 0xFF) << 16) | + ((green & 0xFF) << 8) | + ((blue & 0xFF) << 0); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/utils/MapColor.java b/connector/src/main/java/org/geysermc/connector/utils/MapColor.java index b011edc7..4328d758 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/MapColor.java +++ b/connector/src/main/java/org/geysermc/connector/utils/MapColor.java @@ -1,3 +1,29 @@ +/* + * 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.utils; public enum MapColor { From 57717795a378120a9cd26495badad1e05c3b4cab Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Sun, 17 May 2020 00:59:03 -0400 Subject: [PATCH 09/73] Add enchantment table book on chunk load (#568) Java's block entity ID is enchantment_table whereas Bedrock's is EnchantTable; this commit adds an exception to the block entity regex as such. --- .../java/org/geysermc/connector/utils/BlockEntityUtils.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/connector/src/main/java/org/geysermc/connector/utils/BlockEntityUtils.java b/connector/src/main/java/org/geysermc/connector/utils/BlockEntityUtils.java index 9423a4f8..da32b12b 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/BlockEntityUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/BlockEntityUtils.java @@ -22,6 +22,10 @@ public class BlockEntityUtils { if (id.contains("EnderChest")) return "EnderChest"; + if (id.contains("enchanting_table")) { + return "EnchantTable"; + } + id = id.toLowerCase() .replace("minecraft:", "") .replace("_", " "); From b0d0c168d2b9837f484863fb8aa24498c5741af7 Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sun, 17 May 2020 01:06:07 -0500 Subject: [PATCH 10/73] Fix bossbar causing players to be unable to break blocks or interact in small areas (Closes #537) --- .../geysermc/connector/network/session/cache/BossBar.java | 7 +++++-- .../network/translators/java/JavaBossBarTranslator.java | 2 -- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/BossBar.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/BossBar.java index 1fde179d..267f3cb1 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/cache/BossBar.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/BossBar.java @@ -104,10 +104,13 @@ public class BossBar { addEntityPacket.setRuntimeEntityId(entityId); addEntityPacket.setIdentifier("minecraft:creeper"); addEntityPacket.setEntityType(33); - addEntityPacket.setPosition(session.getPlayerEntity().getPosition()); + addEntityPacket.setPosition(session.getPlayerEntity().getPosition().sub(0D, -10D, 0D)); addEntityPacket.setRotation(Vector3f.ZERO); addEntityPacket.setMotion(Vector3f.ZERO); - addEntityPacket.getMetadata().put(EntityData.SCALE, 0.01F); // scale = 0 doesn't work? + addEntityPacket.getMetadata() + .putFloat(EntityData.SCALE, 0F) + .putFloat(EntityData.BOUNDING_BOX_WIDTH, 0F) + .putFloat(EntityData.BOUNDING_BOX_HEIGHT, 0F); session.sendUpstreamPacket(addEntityPacket); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaBossBarTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaBossBarTranslator.java index 2c32ef6f..3da76a22 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaBossBarTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaBossBarTranslator.java @@ -32,8 +32,6 @@ import org.geysermc.connector.network.translators.Translator; import com.github.steveice10.mc.protocol.packet.ingame.server.ServerBossBarPacket; -import java.awt.*; - @Translator(packet = ServerBossBarPacket.class) public class JavaBossBarTranslator extends PacketTranslator { @Override From 43ee7d602765c2ef0f75f3ad467efd23b1162531 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sun, 17 May 2020 07:26:13 +0100 Subject: [PATCH 11/73] Fixed creepers, giants and eye of ender (#578) --- .../entity/living/monster/CreeperEntity.java | 4 +- .../entity/living/monster/GiantEntity.java | 39 +++++++++++++++++++ .../connector/entity/type/EntityType.java | 3 +- 3 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/entity/living/monster/GiantEntity.java diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/CreeperEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/CreeperEntity.java index e99e1a63..9b5c3822 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/CreeperEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/CreeperEntity.java @@ -39,8 +39,8 @@ public class CreeperEntity extends MonsterEntity { @Override public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getId() == 15 && (int) entityMetadata.getValue() > 0) { - metadata.getFlags().setFlag(EntityFlag.IGNITED, true); + if (entityMetadata.getId() == 15) { + metadata.getFlags().setFlag(EntityFlag.IGNITED, (int) entityMetadata.getValue() == 1); } if (entityMetadata.getId() == 16) { metadata.getFlags().setFlag(EntityFlag.POWERED, (boolean) entityMetadata.getValue()); diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/GiantEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/GiantEntity.java new file mode 100644 index 00000000..b9dc9e66 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/GiantEntity.java @@ -0,0 +1,39 @@ +/* + * 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.monster; + +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.EntityData; +import org.geysermc.connector.entity.type.EntityType; + +public class GiantEntity extends MonsterEntity { + + public GiantEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { + super(entityId, geyserId, entityType, position, motion, rotation); + + metadata.put(EntityData.SCALE, 6f); + } +} 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 ed231d8c..d08c5e33 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 @@ -64,6 +64,7 @@ public enum EntityType { PARROT(ParrotEntity.class, 30, 0.9f, 0.5f), DOLPHIN(WaterEntity.class, 31, 0.6f, 0.9f), ZOMBIE(ZombieEntity.class, 32, 1.8f, 0.6f, 0.6f, 1.62f), + GIANT(GiantEntity.class, 32, 1.8f, 0.6f, 0.6f, 1.62f, "minecraft:zombie"), CREEPER(CreeperEntity.class, 33, 1.7f, 0.6f, 0.6f, 1.62f), SKELETON(AbstractSkeletonEntity.class, 34, 1.8f, 0.6f, 0.6f, 1.62f), SPIDER(SpiderEntity.class, 35, 0.9f, 1.4f, 1.4f, 1f), @@ -103,7 +104,7 @@ public enum EntityType { MOVING_BLOCK(Entity.class, 67, 0f), EXPERIENCE_BOTTLE(ThrowableEntity.class, 68, 0.25f, 0.25f, 0f, 0f, "minecraft:xp_bottle"), EXPERIENCE_ORB(ExpOrbEntity.class, 69, 0f, 0f, 0f, 0f, "minecraft:xp_orb"), - EYE_OF_ENDER(Entity.class, 70, 0.25f), + EYE_OF_ENDER(Entity.class, 70, 0.25f, 0.25f, 0f, 0f, "minecraft:eye_of_ender_signal"), END_CRYSTAL(EnderCrystalEntity.class, 71, 0f, 0f, 0f, 0f, "minecraft:ender_crystal"), FIREWORK_ROCKET(Entity.class, 72, 0.25f), TRIDENT(ArrowEntity.class, 73, 0f), From 405ffb2666203bb2c6f17eed3f151881bd27cbf1 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Mon, 18 May 2020 05:35:01 +0100 Subject: [PATCH 12/73] Added mob spawner block entity data (#587) --- .../connector/entity/type/EntityType.java | 12 ++ .../entity/SpawnerBlockEntityTranslator.java | 105 ++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SpawnerBlockEntityTranslator.java 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 d08c5e33..ad3ac105 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 @@ -160,6 +160,8 @@ public enum EntityType { */ ILLUSIONER(AbstractIllagerEntity.class, 114, 1.8f, 0.6f, 0.6f, 1.62f, "minecraft:pillager"); + private static final EntityType[] VALUES = values(); + private Class entityClass; private final int type; private final float height; @@ -195,4 +197,14 @@ public enum EntityType { this.offset = offset + 0.00001f; this.identifier = identifier; } + + public static EntityType getFromIdentifier(String identifier) { + for (EntityType type : VALUES) { + if (type.identifier.equals(identifier)) { + return type; + } + } + + return null; + } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SpawnerBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SpawnerBlockEntityTranslator.java new file mode 100644 index 00000000..100dbddd --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SpawnerBlockEntityTranslator.java @@ -0,0 +1,105 @@ +/* + * 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.world.block.entity; + +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.nukkitx.nbt.CompoundTagBuilder; +import com.nukkitx.nbt.tag.*; +import org.geysermc.connector.entity.type.EntityType; + +import java.util.ArrayList; +import java.util.List; + +@BlockEntity(name = "MobSpawner", regex = "mob_spawner") +public class SpawnerBlockEntityTranslator extends BlockEntityTranslator { + + @Override + public List> translateTag(CompoundTag tag, BlockState blockState) { + List> tags = new ArrayList<>(); + + if (tag.get("MaxNearbyEntities") != null) { + tags.add(new ShortTag("MaxNearbyEntities", (short) tag.get("MaxNearbyEntities").getValue())); + } + + if (tag.get("RequiredPlayerRange") != null) { + tags.add(new ShortTag("RequiredPlayerRange", (short) tag.get("RequiredPlayerRange").getValue())); + } + + if (tag.get("SpawnCount") != null) { + tags.add(new ShortTag("SpawnCount", (short) tag.get("SpawnCount").getValue())); + } + + if (tag.get("MaxSpawnDelay") != null) { + tags.add(new ShortTag("MaxSpawnDelay", (short) tag.get("MaxSpawnDelay").getValue())); + } + + if (tag.get("Delay") != null) { + tags.add(new ShortTag("Delay", (short) tag.get("Delay").getValue())); + } + + if (tag.get("SpawnRange") != null) { + tags.add(new ShortTag("SpawnRange", (short) tag.get("SpawnRange").getValue())); + } + + if (tag.get("MinSpawnDelay") != null) { + tags.add(new ShortTag("MinSpawnDelay", (short) tag.get("MinSpawnDelay").getValue())); + } + + if (tag.get("SpawnData") != null) { + CompoundTag spawnData = tag.get("SpawnData"); + String entityID = (String) spawnData.get("id").getValue(); + tags.add(new StringTag("EntityIdentifier", entityID)); + + EntityType type = EntityType.getFromIdentifier(entityID); + if (type != null) { + tags.add(new FloatTag("DisplayEntityWidth", type.getWidth())); + tags.add(new FloatTag("DisplayEntityHeight", type.getHeight())); + tags.add(new FloatTag("DisplayEntityScale", 1.0f)); + } + } + + tags.add(new StringTag("id", "MobSpawner")); + tags.add(new ByteTag("isMovable", (byte) 1)); + + return tags; + } + + @Override + public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) { + return null; + } + + @Override + public com.nukkitx.nbt.tag.CompoundTag getDefaultBedrockTag(String bedrockId, int x, int y, int z) { + CompoundTagBuilder tagBuilder = getConstantBedrockTag(bedrockId, x, y, z).toBuilder(); + tagBuilder.byteTag("isMovable", (byte) 1) + .stringTag("id", "MobSpawner"); + + return tagBuilder.buildRootTag(); + } +} From 31d3d2e289c9a9bca6826b333acc86788ea4de0b Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Mon, 18 May 2020 00:35:26 -0400 Subject: [PATCH 13/73] Add some elder guardian properties (#586) - Adds the ELDER flag to all elder guardians, so they look like elder guardians and not giant regular guardians. - Translates AFFECTED_BY_ELDER_GUARDIAN in JavaNotifyClientTranslator to add the elder guardian curse event. --- .../living/monster/ElderGuardianEntity.java | 41 +++++++++++++++++++ .../connector/entity/type/EntityType.java | 2 +- .../world/JavaNotifyClientTranslator.java | 11 +++-- 3 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/entity/living/monster/ElderGuardianEntity.java diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/ElderGuardianEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/ElderGuardianEntity.java new file mode 100644 index 00000000..fedd7980 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/ElderGuardianEntity.java @@ -0,0 +1,41 @@ +/* + * 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.monster; + +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.EntityFlag; +import org.geysermc.connector.entity.type.EntityType; + +public class ElderGuardianEntity extends GuardianEntity { + + public ElderGuardianEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { + super(entityId, geyserId, entityType, position, motion, rotation); + // Otherwise it just looks like a normal guardian but bigger + metadata.getFlags().setFlag(EntityFlag.ELDER, true); + } + +} 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 ad3ac105..f2b66280 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 @@ -82,7 +82,7 @@ public enum EntityType { HUSK(ZombieEntity.class, 47, 1.8f, 0.6f, 0.6f, 1.62f), WITHER_SKELETON(AbstractSkeletonEntity.class, 48, 2.4f, 0.7f), GUARDIAN(GuardianEntity.class, 49, 0.85f), - ELDER_GUARDIAN(GuardianEntity.class, 50, 1.9975f), + ELDER_GUARDIAN(ElderGuardianEntity.class, 50, 1.9975f), NPC(PlayerEntity.class, 51, 1.8f, 0.6f, 0.6f, 1.62f), WITHER(WitherEntity.class, 52, 3.5f, 0.9f), ENDER_DRAGON(EnderDragonEntity.class, 53, 4f, 13f), diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java index 0db343b2..de1066c0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java @@ -31,10 +31,7 @@ import com.github.steveice10.mc.protocol.data.game.world.notify.EnterCreditsValu import com.github.steveice10.mc.protocol.packet.ingame.client.ClientRequestPacket; import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerNotifyClientPacket; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.EntityDataMap; -import com.nukkitx.protocol.bedrock.data.EntityFlag; -import com.nukkitx.protocol.bedrock.data.LevelEventType; -import com.nukkitx.protocol.bedrock.data.PlayerPermission; +import com.nukkitx.protocol.bedrock.data.*; import com.nukkitx.protocol.bedrock.packet.*; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import org.geysermc.connector.entity.Entity; @@ -124,6 +121,12 @@ public class JavaNotifyClientTranslator extends PacketTranslator Date: Mon, 18 May 2020 10:46:35 -0400 Subject: [PATCH 14/73] Add firework boost for elytras (#552) * Add firework boost for elytras! * Change how to detect player glide * Add comments explaining code * Remove unused ID --- .../connector/entity/FireworkEntity.java | 64 +++++++++++++++++++ .../connector/entity/type/EntityType.java | 2 +- 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java diff --git a/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java b/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java new file mode 100644 index 00000000..25128d48 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java @@ -0,0 +1,64 @@ +/* + * 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; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket; +import org.geysermc.connector.entity.type.EntityType; +import org.geysermc.connector.network.session.GeyserSession; + +import java.util.OptionalInt; + +public class FireworkEntity extends Entity { + + public FireworkEntity(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) { + if (entityMetadata.getId() == 8 && !entityMetadata.getValue().equals(OptionalInt.empty()) && ((OptionalInt) entityMetadata.getValue()).getAsInt() == session.getPlayerEntity().getEntityId()) { + //Checks if the firework has an entity ID (used when a player is gliding) and checks to make sure the player that is gliding is the one getting sent the packet or else every player near the gliding player will boost too. + PlayerEntity entity = session.getPlayerEntity(); + float yaw = entity.getRotation().getX(); + float pitch = entity.getRotation().getY(); + //Uses math from NukkitX + entity.setMotion(Vector3f.from( + -Math.sin(Math.toRadians(yaw)) * Math.cos(Math.toRadians(pitch)) * 2, + -Math.sin(Math.toRadians(pitch)) * 2, + Math.cos(Math.toRadians(yaw)) * Math.cos(Math.toRadians(pitch)) * 2)); + //Need to update the EntityMotionPacket or else the player won't boost + SetEntityMotionPacket entityMotionPacket = new SetEntityMotionPacket(); + entityMotionPacket.setRuntimeEntityId(entity.getGeyserId()); + entityMotionPacket.setMotion(entity.getMotion()); + + session.sendUpstreamPacket(entityMotionPacket); + } + super.updateBedrockMetadata(entityMetadata, session); + } +} \ No newline at end of file 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 f2b66280..6cfda74a 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 @@ -106,7 +106,7 @@ public enum EntityType { EXPERIENCE_ORB(ExpOrbEntity.class, 69, 0f, 0f, 0f, 0f, "minecraft:xp_orb"), EYE_OF_ENDER(Entity.class, 70, 0.25f, 0.25f, 0f, 0f, "minecraft:eye_of_ender_signal"), END_CRYSTAL(EnderCrystalEntity.class, 71, 0f, 0f, 0f, 0f, "minecraft:ender_crystal"), - FIREWORK_ROCKET(Entity.class, 72, 0.25f), + FIREWORK_ROCKET(FireworkEntity.class, 72, 0.25f), TRIDENT(ArrowEntity.class, 73, 0f), TURTLE(AnimalEntity.class, 74, 0.4f, 1.2f), CAT(CatEntity.class, 75, 0.35f, 0.3f), From fd36930502d45302b64a1658ef1b435ddb77dae1 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Mon, 18 May 2020 23:26:27 -0400 Subject: [PATCH 15/73] Add entity event for drowning. (#588) This commit translates Java's LIVING_DROWN entity status to Bedrock's HURT_ANIMATION. --- .../translators/java/entity/JavaEntityStatusTranslator.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityStatusTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityStatusTranslator.java index 06d06695..3032785a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityStatusTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityStatusTranslator.java @@ -49,6 +49,8 @@ public class JavaEntityStatusTranslator extends PacketTranslator Date: Tue, 19 May 2020 04:27:35 +0100 Subject: [PATCH 16/73] Added a docker container IP warning (#584) * Added a docker container IP warning * Corrected messages * Moved to normal java file read instead of starting cat * Fixed capitalisation on method name --- .../geysermc/connector/GeyserConnector.java | 5 ++ .../geysermc/connector/utils/DockerCheck.java | 58 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 connector/src/main/java/org/geysermc/connector/utils/DockerCheck.java diff --git a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java index 72995293..58307682 100644 --- a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java +++ b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java @@ -40,6 +40,7 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.Translators; import org.geysermc.connector.network.translators.world.WorldManager; import org.geysermc.connector.thread.PingPassthroughThread; +import org.geysermc.connector.utils.DockerCheck; import org.geysermc.connector.utils.Toolbox; import java.net.InetSocketAddress; @@ -102,6 +103,10 @@ public class GeyserConnector { Toolbox.init(); Translators.start(); + if (platformType != PlatformType.STANDALONE) { + DockerCheck.check(bootstrap); + } + remoteServer = new RemoteServer(config.getRemote().getAddress(), config.getRemote().getPort()); authType = AuthType.getByName(config.getRemote().getAuthType()); diff --git a/connector/src/main/java/org/geysermc/connector/utils/DockerCheck.java b/connector/src/main/java/org/geysermc/connector/utils/DockerCheck.java new file mode 100644 index 00000000..0a5a2278 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/utils/DockerCheck.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.utils; + +import org.geysermc.connector.bootstrap.GeyserBootstrap; + +import java.net.InetAddress; +import java.nio.file.Files; +import java.nio.file.Paths; + +public class DockerCheck { + public static void check(GeyserBootstrap bootstrap) { + try { + String OS = System.getProperty("os.name").toLowerCase(); + String ipAddress = InetAddress.getLocalHost().getHostAddress(); + + // Check if the user is already using the recommended IP + if (ipAddress.equals(bootstrap.getGeyserConfig().getRemote().getAddress())) { + return; + } + + if (OS.indexOf("nix") >= 0 || OS.indexOf("nux") >= 0 || OS.indexOf("aix") > 0) { + bootstrap.getGeyserLogger().debug("We are on a Unix system, checking for Docker..."); + + String output = new String(Files.readAllBytes(Paths.get("/proc/1/cgroup"))); + + if (output.contains("docker")) { + bootstrap.getGeyserLogger().warning("You are most likely in a Docker container, this may cause connection issues from Geyser to the Java server"); + bootstrap.getGeyserLogger().warning("We recommended using the following IP as the remote address: " + ipAddress); + } + } + } catch (Exception e) { } // Ignore any errors, inc ip failed to fetch, process could not run or access denied + } +} From 3ab5c697c1376acfef80b4e17100f9e28227868f Mon Sep 17 00:00:00 2001 From: rtm516 Date: Tue, 19 May 2020 21:39:10 +0100 Subject: [PATCH 17/73] Updated mappings submodule (#596) --- connector/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connector/src/main/resources/mappings b/connector/src/main/resources/mappings index a7963d0a..a67cc940 160000 --- a/connector/src/main/resources/mappings +++ b/connector/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit a7963d0a0236b1c47eea21718ac50706139d90cc +Subproject commit a67cc940c0d47874c833ffeb58f38e33eabfcc33 From 5fe38fa83f0494fc979ea9751d6387f3a78fab72 Mon Sep 17 00:00:00 2001 From: Creeperface01 Date: Wed, 20 May 2020 17:12:03 +0200 Subject: [PATCH 18/73] Show form window immediately after spawn (#606) --- .../connector/network/UpstreamPacketHandler.java | 7 ++++++- .../connector/utils/LoginEncryptionUtils.java | 11 +++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java index dfc3112b..2fbd487d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java @@ -110,7 +110,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { } @Override - public boolean handle(MovePlayerPacket packet) { + public boolean handle(SetLocalPlayerAsInitializedPacket packet) { if (!session.isLoggedIn() && !session.isLoggingIn() && session.getConnector().getAuthType() == AuthType.ONLINE) { // TODO it is safer to key authentication on something that won't change (UUID, not username) if (!couldLoginUserByName(session.getAuthData().getName())) { @@ -119,6 +119,11 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { // else we were able to log the user in return true; } + return translateAndDefault(packet); + } + + @Override + public boolean handle(MovePlayerPacket packet) { if (session.isLoggingIn()) { session.sendMessage("Please wait until you are logged in..."); } diff --git a/connector/src/main/java/org/geysermc/connector/utils/LoginEncryptionUtils.java b/connector/src/main/java/org/geysermc/connector/utils/LoginEncryptionUtils.java index 7f6c4760..f9a7fec2 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/LoginEncryptionUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/LoginEncryptionUtils.java @@ -34,7 +34,6 @@ import com.nukkitx.network.util.Preconditions; import com.nukkitx.protocol.bedrock.packet.LoginPacket; import com.nukkitx.protocol.bedrock.packet.ServerToClientHandshakePacket; import com.nukkitx.protocol.bedrock.util.EncryptionUtils; - import org.geysermc.common.window.CustomFormBuilder; import org.geysermc.common.window.CustomFormWindow; import org.geysermc.common.window.FormWindow; @@ -193,18 +192,22 @@ public class LoginEncryptionUtils { String password = response.getInputResponses().get(2); session.authenticate(email, password); + } else { + showLoginDetailsWindow(session); } // Clear windows so authentication data isn't accidentally cached windowCache.getWindows().clear(); } else if (formId == AUTH_FORM_ID && window instanceof SimpleFormWindow) { SimpleFormResponse response = (SimpleFormResponse) window.getResponse(); - if(response != null) { - if(response.getClickedButtonId() == 0) { + if (response != null) { + if (response.getClickedButtonId() == 0) { showLoginDetailsWindow(session); - } else if(response.getClickedButtonId() == 1) { + } else if (response.getClickedButtonId() == 1) { session.disconnect("Login is required"); } + } else { + showLoginWindow(session); } } } From 1395b719cb929a956622c8dabbb24a26e1dcf497 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Wed, 20 May 2020 11:12:31 -0400 Subject: [PATCH 19/73] Add missing break to JavaEntityStatusTranslator (#600) --- .../translators/java/entity/JavaEntityStatusTranslator.java | 1 + 1 file changed, 1 insertion(+) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityStatusTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityStatusTranslator.java index 3032785a..b8675dbf 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityStatusTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityStatusTranslator.java @@ -72,6 +72,7 @@ public class JavaEntityStatusTranslator extends PacketTranslator Date: Wed, 20 May 2020 18:39:58 +0100 Subject: [PATCH 20/73] Fixed trident display and some arrow related cleanup (#609) * Fixed trident display and some arrow related cleanup * Renamed trident entity --- .../connector/entity/AbstractArrowEntity.java | 50 +++++++++++++++++++ ...rrowEntity.java => TippedArrowEntity.java} | 4 +- .../connector/entity/TridentEntity.java | 48 ++++++++++++++++++ .../connector/entity/type/EntityType.java | 5 +- 4 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/entity/AbstractArrowEntity.java rename connector/src/main/java/org/geysermc/connector/entity/{ArrowEntity.java => TippedArrowEntity.java} (87%) create mode 100644 connector/src/main/java/org/geysermc/connector/entity/TridentEntity.java diff --git a/connector/src/main/java/org/geysermc/connector/entity/AbstractArrowEntity.java b/connector/src/main/java/org/geysermc/connector/entity/AbstractArrowEntity.java new file mode 100644 index 00000000..fa089707 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/entity/AbstractArrowEntity.java @@ -0,0 +1,50 @@ +/* + * 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; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.EntityFlag; +import org.geysermc.connector.entity.type.EntityType; +import org.geysermc.connector.network.session.GeyserSession; + +public class AbstractArrowEntity extends Entity { + + public AbstractArrowEntity(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) { + if (entityMetadata.getId() == 7) { + byte data = (byte) entityMetadata.getValue(); + + metadata.getFlags().setFlag(EntityFlag.CRITICAL, (data & 0x01) == 0x01); + } + + super.updateBedrockMetadata(entityMetadata, session); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/entity/ArrowEntity.java b/connector/src/main/java/org/geysermc/connector/entity/TippedArrowEntity.java similarity index 87% rename from connector/src/main/java/org/geysermc/connector/entity/ArrowEntity.java rename to connector/src/main/java/org/geysermc/connector/entity/TippedArrowEntity.java index 961908a2..def5715c 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/ArrowEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/TippedArrowEntity.java @@ -28,9 +28,9 @@ package org.geysermc.connector.entity; import com.nukkitx.math.vector.Vector3f; import org.geysermc.connector.entity.type.EntityType; -public class ArrowEntity extends Entity { +public class TippedArrowEntity extends AbstractArrowEntity { - public ArrowEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { + public TippedArrowEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/TridentEntity.java b/connector/src/main/java/org/geysermc/connector/entity/TridentEntity.java new file mode 100644 index 00000000..7c2442b0 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/entity/TridentEntity.java @@ -0,0 +1,48 @@ +/* + * 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; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.EntityFlag; +import org.geysermc.connector.entity.type.EntityType; +import org.geysermc.connector.network.session.GeyserSession; + +public class TridentEntity extends AbstractArrowEntity { + + public TridentEntity(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) { + if (entityMetadata.getId() == 11) { + metadata.getFlags().setFlag(EntityFlag.ENCHANTED, (boolean) entityMetadata.getValue()); + } + + super.updateBedrockMetadata(entityMetadata, 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 6cfda74a..99d659d1 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 @@ -107,14 +107,15 @@ public enum EntityType { EYE_OF_ENDER(Entity.class, 70, 0.25f, 0.25f, 0f, 0f, "minecraft:eye_of_ender_signal"), END_CRYSTAL(EnderCrystalEntity.class, 71, 0f, 0f, 0f, 0f, "minecraft:ender_crystal"), FIREWORK_ROCKET(FireworkEntity.class, 72, 0.25f), - TRIDENT(ArrowEntity.class, 73, 0f), + TRIDENT(TridentEntity.class, 73, 0f, 0f, 0f, 0f, "minecraft:thrown_trident"), TURTLE(AnimalEntity.class, 74, 0.4f, 1.2f), CAT(CatEntity.class, 75, 0.35f, 0.3f), SHULKER_BULLET(Entity.class, 76, 0.3125f), FISHING_BOBBER(FishingHookEntity.class, 77, 0f, 0f, 0f, 0f, "minecraft:fishing_hook"), CHALKBOARD(Entity.class, 78, 0f), DRAGON_FIREBALL(ItemedFireballEntity.class, 79, 1.0f), - ARROW(ArrowEntity.class, 80, 0.25f, 0.25f), + ARROW(TippedArrowEntity.class, 80, 0.25f, 0.25f), + SPECTRAL_ARROW(AbstractArrowEntity.class, 80, 0.25f, 0.25f, 0.25f, 0f, "minecraft:arrow"), SNOWBALL(ThrowableEntity.class, 81, 0.25f), EGG(ThrowableEntity.class, 82, 0.25f), PAINTING(PaintingEntity.class, 83, 0f), From fbfc987d2b2e3e60f3cfc169d53ac20c7f0d05ae Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Wed, 20 May 2020 13:40:07 -0400 Subject: [PATCH 21/73] Fix mapping for Burning Skull painting type (#608) Otherwise, painting shows up as a 1x1 painting of another kind. --- .../main/java/org/geysermc/connector/utils/PaintingType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connector/src/main/java/org/geysermc/connector/utils/PaintingType.java b/connector/src/main/java/org/geysermc/connector/utils/PaintingType.java index 00993522..63f1119c 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/PaintingType.java +++ b/connector/src/main/java/org/geysermc/connector/utils/PaintingType.java @@ -57,7 +57,7 @@ public enum PaintingType { DONKEY_KONG("DonkeyKong", 4, 3), POINTER("Pointer", 4, 4), PIG_SCENE("Pigscene", 4, 4), - BURNING_SKULL("Flaming Skull", 4, 4); // burning skull on java edition, flaming skull on bedrock + BURNING_SKULL("BurningSkull", 4, 4); private static final PaintingType[] VALUES = values(); private String bedrockName; From 83c7858a8ca73b0703d34caa2e8faf73e4033227 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Wed, 20 May 2020 13:43:17 -0400 Subject: [PATCH 22/73] Fix bug where online mode players couldn't move after logging in (#610) --- .../org/geysermc/connector/network/UpstreamPacketHandler.java | 1 - 1 file changed, 1 deletion(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java index 2fbd487d..3d2ded44 100644 --- a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java @@ -117,7 +117,6 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { LoginEncryptionUtils.showLoginWindow(session); } // else we were able to log the user in - return true; } return translateAndDefault(packet); } From a7f363ec09a4f0410888cf669c4cc9130e7dbac6 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Wed, 20 May 2020 23:43:22 -0400 Subject: [PATCH 23/73] Add option for disabling command suggestions; add config version (#598) * Add option for disabling command suggestions; add config version This commit adds an option for disabling command suggestions. If enabled, command suggestions will not be sent to the server so as to remove command freezing. This commit also adds a config version variable so users are notified when to regenerate their configs. * Rename GeyserConfiguration.checkGeyserConfiguration() --- .../bukkit/GeyserBukkitConfiguration.java | 10 ++++++++++ .../platform/bukkit/GeyserBukkitPlugin.java | 2 ++ .../bungeecord/GeyserBungeeConfiguration.java | 10 ++++++++++ .../platform/bungeecord/GeyserBungeePlugin.java | 2 ++ .../sponge/GeyserSpongeConfiguration.java | 10 ++++++++++ .../platform/sponge/GeyserSpongePlugin.java | 2 ++ .../standalone/GeyserStandaloneBootstrap.java | 1 + .../standalone/GeyserStandaloneConfiguration.java | 6 ++++++ .../velocity/GeyserVelocityConfiguration.java | 6 ++++++ .../platform/velocity/GeyserVelocityPlugin.java | 2 ++ .../geysermc/connector/GeyserConfiguration.java | 15 +++++++++++++++ ...or.java => JavaDeclareCommandsTranslator.java} | 7 ++++++- connector/src/main/resources/config.yml | 7 +++++++ 13 files changed, 79 insertions(+), 1 deletion(-) rename connector/src/main/java/org/geysermc/connector/network/translators/java/{JavaServerDeclareCommandsTranslator.java => JavaDeclareCommandsTranslator.java} (97%) diff --git a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java index 2213f90b..10b06a39 100644 --- a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java +++ b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java @@ -86,6 +86,11 @@ public class GeyserBukkitConfiguration implements GeyserConfiguration { return userAuthInfo; } + @Override + public boolean isCommandSuggestions() { + return config.getBoolean("command-suggestions", true); + } + @Override public boolean isPingPassthrough() { return config.getBoolean("ping-passthrough", false); @@ -203,4 +208,9 @@ public class GeyserBukkitConfiguration implements GeyserConfiguration { return config.getString("metrics.uuid", "generateduuid"); } } + + @Override + public int getConfigVersion() { + return config.getInt("config-version", 0); + } } diff --git a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPlugin.java b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPlugin.java index dda804b7..254b5285 100644 --- a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPlugin.java +++ b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPlugin.java @@ -28,6 +28,7 @@ package org.geysermc.platform.bukkit; import org.bukkit.Bukkit; import org.bukkit.plugin.java.JavaPlugin; import org.geysermc.common.PlatformType; +import org.geysermc.connector.GeyserConfiguration; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.bootstrap.GeyserBootstrap; import org.geysermc.connector.command.CommandManager; @@ -55,6 +56,7 @@ public class GeyserBukkitPlugin extends JavaPlugin implements GeyserBootstrap { saveDefaultConfig(); this.geyserConfig = new GeyserBukkitConfiguration(getDataFolder(), getConfig()); + GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); if (geyserConfig.getMetrics().getUniqueId().equals("generateduuid")) { getConfig().set("metrics.uuid", UUID.randomUUID().toString()); saveConfig(); diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java index f8e40141..dc5c0fc4 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java @@ -85,6 +85,11 @@ public class GeyserBungeeConfiguration implements GeyserConfiguration { return userAuthInfo; } + @Override + public boolean isCommandSuggestions() { + return config.getBoolean("command-suggestions", true); + } + @Override public boolean isPingPassthrough() { return config.getBoolean("ping-passthrough", false); @@ -202,4 +207,9 @@ public class GeyserBungeeConfiguration implements GeyserConfiguration { return config.getString("metrics.uuid", "generateduuid"); } } + + @Override + public int getConfigVersion() { + return config.getInt("config-version", 0); + } } diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePlugin.java index 488854c9..270fbd1c 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePlugin.java @@ -31,6 +31,7 @@ import net.md_5.bungee.config.Configuration; import net.md_5.bungee.config.ConfigurationProvider; import net.md_5.bungee.config.YamlConfiguration; import org.geysermc.common.PlatformType; +import org.geysermc.connector.GeyserConfiguration; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.bootstrap.GeyserBootstrap; import org.geysermc.connector.command.CommandManager; @@ -116,6 +117,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { } this.geyserLogger = new GeyserBungeeLogger(getLogger(), geyserConfig.isDebugMode()); + GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); geyserConfig.loadFloodgate(this); diff --git a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java index e8459550..96a12399 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java @@ -79,6 +79,11 @@ public class GeyserSpongeConfiguration implements GeyserConfiguration { return userAuthInfo; } + @Override + public boolean isCommandSuggestions() { + return node.getNode("command-suggestions").getBoolean(true); + } + @Override public boolean isPingPassthrough() { return node.getNode("ping-passthrough").getBoolean(false); @@ -202,4 +207,9 @@ public class GeyserSpongeConfiguration implements GeyserConfiguration { return node.getNode("metrics").getNode("uuid").getString("generateduuid"); } } + + @Override + public int getConfigVersion() { + return node.getNode("config-version").getInt(0); + } } diff --git a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePlugin.java b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePlugin.java index 0c323a5e..04a80adf 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePlugin.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePlugin.java @@ -30,6 +30,7 @@ import ninja.leaping.configurate.ConfigurationNode; import ninja.leaping.configurate.loader.ConfigurationLoader; import ninja.leaping.configurate.yaml.YAMLConfigurationLoader; import org.geysermc.common.PlatformType; +import org.geysermc.connector.GeyserConfiguration; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.bootstrap.GeyserBootstrap; import org.geysermc.connector.command.CommandManager; @@ -105,6 +106,7 @@ public class GeyserSpongePlugin implements GeyserBootstrap { } this.geyserLogger = new GeyserSpongeLogger(logger, geyserConfig.isDebugMode()); + GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); this.connector = GeyserConnector.start(PlatformType.SPONGE, this); this.geyserCommandManager = new GeyserSpongeCommandManager(Sponge.getCommandManager(), connector); diff --git a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneBootstrap.java b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneBootstrap.java index 9d249363..0916f212 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneBootstrap.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneBootstrap.java @@ -62,6 +62,7 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { geyserLogger.severe("Failed to read/create config.yml! Make sure it's up to date and/or readable+writable!", ex); System.exit(0); } + GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); connector = GeyserConnector.start(PlatformType.STANDALONE, this); geyserCommandManager = new GeyserCommandManager(connector); diff --git a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneConfiguration.java b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneConfiguration.java index 8ae83d02..10e1fe0b 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneConfiguration.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneConfiguration.java @@ -47,6 +47,9 @@ public class GeyserStandaloneConfiguration implements GeyserConfiguration { private Map userAuths; + @JsonProperty("command-suggestions") + private boolean isCommandSuggestions; + @JsonProperty("ping-passthrough") private boolean pingPassthrough; @@ -112,4 +115,7 @@ public class GeyserStandaloneConfiguration implements GeyserConfiguration { @JsonProperty("uuid") private String uniqueId; } + + @JsonProperty("config-version") + private int configVersion; } diff --git a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java index b9b3b379..bc29f20d 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java @@ -52,6 +52,9 @@ public class GeyserVelocityConfiguration implements GeyserConfiguration { private Map userAuths; + @JsonProperty("command-suggestions") + private boolean commandSuggestions; + @JsonProperty("ping-passthrough") private boolean pingPassthrough; @@ -127,4 +130,7 @@ public class GeyserVelocityConfiguration implements GeyserConfiguration { @JsonProperty("uuid") private String uniqueId; } + + @JsonProperty("config-version") + private int configVersion; } diff --git a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityPlugin.java b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityPlugin.java index 0269d933..9ad8ea9a 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityPlugin.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityPlugin.java @@ -35,6 +35,7 @@ import com.velocitypowered.api.plugin.Plugin; import com.velocitypowered.api.proxy.ProxyServer; import org.geysermc.common.PlatformType; +import org.geysermc.connector.GeyserConfiguration; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.bootstrap.GeyserBootstrap; import org.geysermc.connector.utils.FileUtils; @@ -90,6 +91,7 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { geyserConfig.getRemote().setPort(javaAddr.getPort()); this.geyserLogger = new GeyserVelocityLogger(logger, geyserConfig.isDebugMode()); + GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); geyserConfig.loadFloodgate(this, proxyServer, configDir); diff --git a/connector/src/main/java/org/geysermc/connector/GeyserConfiguration.java b/connector/src/main/java/org/geysermc/connector/GeyserConfiguration.java index cbbd507a..423a3600 100644 --- a/connector/src/main/java/org/geysermc/connector/GeyserConfiguration.java +++ b/connector/src/main/java/org/geysermc/connector/GeyserConfiguration.java @@ -31,12 +31,17 @@ import java.util.Map; public interface GeyserConfiguration { + // Modify this when you update the config + int CURRENT_CONFIG_VERSION = 1; + IBedrockConfiguration getBedrock(); IRemoteConfiguration getRemote(); Map getUserAuths(); + boolean isCommandSuggestions(); + boolean isPingPassthrough(); int getMaxPlayers(); @@ -87,4 +92,14 @@ public interface GeyserConfiguration { String getUniqueId(); } + + int getConfigVersion(); + + static void checkGeyserConfiguration(GeyserConfiguration geyserConfig, GeyserLogger geyserLogger) { + if (geyserConfig.getConfigVersion() < CURRENT_CONFIG_VERSION) { + geyserLogger.warning("Your Geyser config is out of date! Please regenerate your config when possible."); + } else if (geyserConfig.getConfigVersion() > CURRENT_CONFIG_VERSION) { + geyserLogger.warning("Your Geyser config is too new! Errors may occur."); + } + } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaServerDeclareCommandsTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareCommandsTranslator.java similarity index 97% rename from connector/src/main/java/org/geysermc/connector/network/translators/java/JavaServerDeclareCommandsTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareCommandsTranslator.java index 6f16f8b4..053630d5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaServerDeclareCommandsTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareCommandsTranslator.java @@ -43,9 +43,14 @@ import org.geysermc.connector.network.translators.Translator; import java.util.*; @Translator(packet = ServerDeclareCommandsPacket.class) -public class JavaServerDeclareCommandsTranslator extends PacketTranslator { +public class JavaDeclareCommandsTranslator extends PacketTranslator { @Override public void translate(ServerDeclareCommandsPacket packet, GeyserSession session) { + // Don't send command suggestions if they are disabled + if (!session.getConnector().getConfig().isCommandSuggestions()) { + session.getConnector().getLogger().debug("Not sending command suggestions as they are disabled."); + return; + } List commandData = new ArrayList<>(); Int2ObjectMap commands = new Int2ObjectOpenHashMap<>(); Int2ObjectMap> commandArgs = new Int2ObjectOpenHashMap<>(); diff --git a/connector/src/main/resources/config.yml b/connector/src/main/resources/config.yml index b1e1e2f9..221707f2 100644 --- a/connector/src/main/resources/config.yml +++ b/connector/src/main/resources/config.yml @@ -41,6 +41,10 @@ floodgate-key-file: public-key.pem # email: herpderp@derpherp.com # password: dooooo +# Bedrock clients can freeze when opening up the command prompt for the first time if given a lot of commands. +# Disabling this will prevent command suggestions from being sent and solve freezing for Bedrock clients. +command-suggestions: true + # Relay the MOTD, player count and max players from the remote server ping-passthrough: false @@ -78,3 +82,6 @@ metrics: enabled: true # UUID of server, don't change! uuid: generateduuid + +# DO NOT TOUCH! +config-version: 1 From 93d15c16f523ab0bca55c4228bf43c23d91f82ad Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Thu, 21 May 2020 10:29:32 -0400 Subject: [PATCH 24/73] Fix NPE if Bukkit configuration is out of date. (#614) --- .../java/org/geysermc/platform/bukkit/GeyserBukkitPlugin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPlugin.java b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPlugin.java index 254b5285..ad1f6194 100644 --- a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPlugin.java +++ b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPlugin.java @@ -56,7 +56,6 @@ public class GeyserBukkitPlugin extends JavaPlugin implements GeyserBootstrap { saveDefaultConfig(); this.geyserConfig = new GeyserBukkitConfiguration(getDataFolder(), getConfig()); - GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); if (geyserConfig.getMetrics().getUniqueId().equals("generateduuid")) { getConfig().set("metrics.uuid", UUID.randomUUID().toString()); saveConfig(); @@ -72,6 +71,7 @@ public class GeyserBukkitPlugin extends JavaPlugin implements GeyserBootstrap { saveConfig(); this.geyserLogger = new GeyserBukkitLogger(getLogger(), geyserConfig.isDebugMode()); + GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); geyserConfig.loadFloodgate(this); From 61e0e796daf7dceacccf509e3ce19c96eafcb895 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Thu, 21 May 2020 18:48:24 -0400 Subject: [PATCH 25/73] Fix /geyser offhand command on Bukkit (#611) If CommandSender is not an instance of GeyserSession, we iterate through all GeyserSessions in order to find the sender. --- .../connector/command/defaults/OffhandCommand.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/connector/src/main/java/org/geysermc/connector/command/defaults/OffhandCommand.java b/connector/src/main/java/org/geysermc/connector/command/defaults/OffhandCommand.java index 5392baed..a49506b0 100644 --- a/connector/src/main/java/org/geysermc/connector/command/defaults/OffhandCommand.java +++ b/connector/src/main/java/org/geysermc/connector/command/defaults/OffhandCommand.java @@ -56,6 +56,16 @@ public class OffhandCommand extends GeyserCommand { ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.SWAP_HANDS, new Position(0,0,0), BlockFace.DOWN); session.sendDownstreamPacket(releaseItemPacket); + return; + } + // Needed for Bukkit - sender is not an instance of GeyserSession + for (GeyserSession session : connector.getPlayers().values()) { + if (sender.getName().equals(session.getPlayerEntity().getUsername())) { + ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.SWAP_HANDS, new Position(0,0,0), + BlockFace.DOWN); + session.sendDownstreamPacket(releaseItemPacket); + break; + } } } } From 81d3b0ef105fc9b07645169a281d8b2764e1e2dd Mon Sep 17 00:00:00 2001 From: OnlyBMan <27742182+OnlyBMan@users.noreply.github.com> Date: Thu, 21 May 2020 19:45:35 -0400 Subject: [PATCH 26/73] Fix painting rotation (#597) * Fix painting rotation * add comment and spacing * Dont sleep everything :P * Fix whitespace * Remove whitespace * Fix underlying issue Instead of adding a delay, exclude Painting in HeadLookTranslator.java. Thanks AJ! * Remove unneeded import Co-authored-by: Camotoy <20743703+DoctorMacc@users.noreply.github.com> --- .../translators/java/entity/JavaEntityHeadLookTranslator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityHeadLookTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityHeadLookTranslator.java index 09dd75f6..e26a5880 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityHeadLookTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityHeadLookTranslator.java @@ -50,7 +50,7 @@ public class JavaEntityHeadLookTranslator extends PacketTranslator Date: Sat, 23 May 2020 21:56:49 +0100 Subject: [PATCH 27/73] Updated to support latest MCProtocolLib (#623) * Updated to support latest MCProtocolLib * Cleaned up names and imports * Fixed minecarts * Fixed throwables * Fixed tnt --- .../connector/entity/FishingHookEntity.java | 2 +- .../connector/entity/ItemFrameEntity.java | 2 +- .../connector/entity/type/EntityType.java | 18 ++++++------- ...or.java => JavaSpawnEntityTranslator.java} | 27 +++++++++---------- ...a => JavaSpawnLivingEntityTranslator.java} | 15 +++++------ ... => JavaSpawnWeatherEntityTranslator.java} | 10 +++---- .../geysermc/connector/utils/EntityUtils.java | 18 +------------ 7 files changed, 37 insertions(+), 55 deletions(-) rename connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/{JavaSpawnObjectTranslator.java => JavaSpawnEntityTranslator.java} (80%) rename connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/{JavaSpawnMobTranslator.java => JavaSpawnLivingEntityTranslator.java} (91%) rename connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/{JavaSpawnGlobalEntityTranslator.java => JavaSpawnWeatherEntityTranslator.java} (85%) diff --git a/connector/src/main/java/org/geysermc/connector/entity/FishingHookEntity.java b/connector/src/main/java/org/geysermc/connector/entity/FishingHookEntity.java index 808e1667..1b648f7c 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/FishingHookEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/FishingHookEntity.java @@ -26,7 +26,7 @@ package org.geysermc.connector.entity; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.type.object.ProjectileData; +import com.github.steveice10.mc.protocol.data.game.entity.object.ProjectileData; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.EntityData; import org.geysermc.connector.GeyserConnector; diff --git a/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java b/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java index 16942898..f100704f 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java @@ -27,7 +27,7 @@ package org.geysermc.connector.entity; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; -import com.github.steveice10.mc.protocol.data.game.entity.type.object.HangingDirection; +import com.github.steveice10.mc.protocol.data.game.entity.object.HangingDirection; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.CompoundTagBuilder; 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 99d659d1..43beca9b 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 @@ -99,10 +99,10 @@ public enum EntityType { TRIPOD_CAMERA(Entity.class, 62, 0f), PLAYER(PlayerEntity.class, 63, 1.8f, 0.6f, 0.6f, 1.62f), ITEM(ItemEntity.class, 64, 0.25f, 0.25f), - TNT(TNTEntity.class, 65, 0.98f, 0.98f), + PRIMED_TNT(TNTEntity.class, 65, 0.98f, 0.98f, 0.98f, 0f, "minecraft:tnt"), FALLING_BLOCK(FallingBlockEntity.class, 66, 0.98f, 0.98f), MOVING_BLOCK(Entity.class, 67, 0f), - EXPERIENCE_BOTTLE(ThrowableEntity.class, 68, 0.25f, 0.25f, 0f, 0f, "minecraft:xp_bottle"), + THROWN_EXP_BOTTLE(ThrowableEntity.class, 68, 0.25f, 0.25f, 0f, 0f, "minecraft:xp_bottle"), EXPERIENCE_ORB(ExpOrbEntity.class, 69, 0f, 0f, 0f, 0f, "minecraft:xp_orb"), EYE_OF_ENDER(Entity.class, 70, 0.25f, 0.25f, 0f, 0f, "minecraft:eye_of_ender_signal"), END_CRYSTAL(EnderCrystalEntity.class, 71, 0f, 0f, 0f, 0f, "minecraft:ender_crystal"), @@ -117,12 +117,12 @@ public enum EntityType { ARROW(TippedArrowEntity.class, 80, 0.25f, 0.25f), SPECTRAL_ARROW(AbstractArrowEntity.class, 80, 0.25f, 0.25f, 0.25f, 0f, "minecraft:arrow"), SNOWBALL(ThrowableEntity.class, 81, 0.25f), - EGG(ThrowableEntity.class, 82, 0.25f), + THROWN_EGG(ThrowableEntity.class, 82, 0.25f, 0.25f, 0.25f, 0f, "minecraft:egg"), PAINTING(PaintingEntity.class, 83, 0f), MINECART(MinecartEntity.class, 84, 0.7f, 0.98f), FIREBALL(ItemedFireballEntity.class, 85, 1.0f), - POTION(ThrowableEntity.class, 86, 0.25f), - ENDER_PEARL(ThrowableEntity.class, 87, 0.25f), + THROWN_POTION(ThrowableEntity.class, 86, 0.25f, 0.25f, 0.25f, 0f, "minecraft:splash_potion"), + THROWN_ENDERPEARL(ThrowableEntity.class, 87, 0.25f, 0.25f, 0.25f, 0f, "minecraft:ender_pearl"), LEASH_KNOT(LeashKnotEntity.class, 88, 0.5f, 0.375f), WITHER_SKULL(Entity.class, 89, 0.3125f), BOAT(Entity.class, 90, 0.7f, 1.6f, 1.6f, 0.35f), @@ -130,11 +130,11 @@ public enum EntityType { LIGHTNING_BOLT(Entity.class, 93, 0f), SMALL_FIREBALL(ItemedFireballEntity.class, 94, 0.3125f), AREA_EFFECT_CLOUD(AreaEffectCloudEntity.class, 95, 0.5f, 1.0f), - HOPPER_MINECART(MinecartEntity.class, 96, 0.7f, 0.98f), - TNT_MINECART(MinecartEntity.class, 97, 0.7f, 0.98f), - CHEST_MINECART(MinecartEntity.class, 98, 0.7f, 0.98f), + MINECART_HOPPER(MinecartEntity.class, 96, 0.7f, 0.98f, 0.98f, 0f, "minecraft:hopper_minecart"), + MINECART_TNT(MinecartEntity.class, 97, 0.7f, 0.98f, 0.98f, 0f, "minecraft:tnt_minecart"), + MINECART_CHEST(MinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0f, "minecraft:chest_minecart"), - COMMAND_BLOCK_MINECART(MinecartEntity.class, 100, 0.7f, 0.98f), + MINECART_COMMAND_BLOCK(MinecartEntity.class, 100, 0.7f, 0.98f, 0.98f, 0f, "minecraft:command_block_minecart"), LINGERING_POTION(ThrowableEntity.class, 101, 0f), LLAMA_SPIT(Entity.class, 102, 0.25f), EVOKER_FANGS(Entity.class, 103, 0.8f, 0.5f), diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnObjectTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnEntityTranslator.java similarity index 80% rename from connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnObjectTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnEntityTranslator.java index 419f1e46..920969a7 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnObjectTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnEntityTranslator.java @@ -25,17 +25,16 @@ package org.geysermc.connector.network.translators.java.entity.spawn; -import com.github.steveice10.mc.protocol.data.game.entity.type.object.FallingBlockData; -import com.github.steveice10.mc.protocol.data.game.entity.type.object.HangingDirection; -import com.github.steveice10.mc.protocol.data.game.entity.type.object.ObjectType; -import com.github.steveice10.mc.protocol.data.game.entity.type.object.ProjectileData; -import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnObjectPacket; +import com.github.steveice10.mc.protocol.data.game.entity.object.FallingBlockData; +import com.github.steveice10.mc.protocol.data.game.entity.object.HangingDirection; +import com.github.steveice10.mc.protocol.data.game.entity.object.ProjectileData; +import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType; +import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnEntityPacket; import com.nukkitx.math.vector.Vector3f; import org.geysermc.connector.entity.Entity; import org.geysermc.connector.entity.FallingBlockEntity; import org.geysermc.connector.entity.FishingHookEntity; import org.geysermc.connector.entity.ItemFrameEntity; -import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; @@ -44,17 +43,17 @@ import org.geysermc.connector.utils.EntityUtils; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; -@Translator(packet = ServerSpawnObjectPacket.class) -public class JavaSpawnObjectTranslator extends PacketTranslator { +@Translator(packet = ServerSpawnEntityPacket.class) +public class JavaSpawnEntityTranslator extends PacketTranslator { @Override - public void translate(ServerSpawnObjectPacket packet, GeyserSession session) { + public void translate(ServerSpawnEntityPacket packet, GeyserSession session) { Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ()); Vector3f motion = Vector3f.from(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ()); Vector3f rotation = Vector3f.from(packet.getYaw(), packet.getPitch(), 0); - EntityType type = EntityUtils.toBedrockEntity(packet.getType()); + org.geysermc.connector.entity.type.EntityType type = EntityUtils.toBedrockEntity(packet.getType()); if (type == null) { session.getConnector().getLogger().warning("Entity type " + packet.getType() + " was null."); return; @@ -63,19 +62,19 @@ public class JavaSpawnObjectTranslator extends PacketTranslator entityClass = type.getEntityClass(); try { Entity entity; - if (packet.getType() == ObjectType.FALLING_BLOCK) { + if (packet.getType() == EntityType.FALLING_BLOCK) { entity = new FallingBlockEntity(packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(), type, position, motion, rotation, ((FallingBlockData) packet.getData()).getId()); - } else if (packet.getType() == ObjectType.ITEM_FRAME) { + } else if (packet.getType() == EntityType.ITEM_FRAME) { // Item frames need the hanging direction entity = new ItemFrameEntity(packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(), type, position, motion, rotation, (HangingDirection) packet.getData()); - } else if (packet.getType() == ObjectType.FISHING_BOBBER) { + } else if (packet.getType() == EntityType.FISHING_BOBBER) { // Fishing bobbers need the owner for the line entity = new FishingHookEntity(packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(), type, position, motion, rotation, (ProjectileData) packet.getData()); } else { - Constructor entityConstructor = entityClass.getConstructor(long.class, long.class, EntityType.class, + Constructor entityConstructor = entityClass.getConstructor(long.class, long.class, org.geysermc.connector.entity.type.EntityType.class, Vector3f.class, Vector3f.class, Vector3f.class); entity = entityConstructor.newInstance(packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(), diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnMobTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnLivingEntityTranslator.java similarity index 91% rename from connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnMobTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnLivingEntityTranslator.java index d955ecfd..8c246e51 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnMobTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnLivingEntityTranslator.java @@ -25,9 +25,8 @@ package org.geysermc.connector.network.translators.java.entity.spawn; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; - +import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnLivingEntityPacket; +import com.nukkitx.math.vector.Vector3f; import org.geysermc.connector.entity.Entity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; @@ -35,14 +34,14 @@ import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; import org.geysermc.connector.utils.EntityUtils; -import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnMobPacket; -import com.nukkitx.math.vector.Vector3f; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; -@Translator(packet = ServerSpawnMobPacket.class) -public class JavaSpawnMobTranslator extends PacketTranslator { +@Translator(packet = ServerSpawnLivingEntityPacket.class) +public class JavaSpawnLivingEntityTranslator extends PacketTranslator { @Override - public void translate(ServerSpawnMobPacket packet, GeyserSession session) { + public void translate(ServerSpawnLivingEntityPacket packet, GeyserSession session) { Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ()); Vector3f motion = Vector3f.from(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ()); Vector3f rotation = Vector3f.from(packet.getYaw(), packet.getPitch(), packet.getHeadYaw()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnGlobalEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnWeatherEntityTranslator.java similarity index 85% rename from connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnGlobalEntityTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnWeatherEntityTranslator.java index da2e59af..c50686a0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnGlobalEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnWeatherEntityTranslator.java @@ -31,17 +31,17 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnGlobalEntityPacket; +import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnWeatherEntityPacket; import com.nukkitx.math.vector.Vector3f; -@Translator(packet = ServerSpawnGlobalEntityPacket.class) -public class JavaSpawnGlobalEntityTranslator extends PacketTranslator { +@Translator(packet = ServerSpawnWeatherEntityPacket.class) +public class JavaSpawnWeatherEntityTranslator extends PacketTranslator { @Override - public void translate(ServerSpawnGlobalEntityPacket packet, GeyserSession session) { + public void translate(ServerSpawnWeatherEntityPacket packet, GeyserSession session) { Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ()); - // Currently GlobalEntityType only has a lightning bolt + // Currently WeatherEntityType only has a lightning bolt Entity entity = new Entity( packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(), EntityType.LIGHTNING_BOLT, position, Vector3f.ZERO, Vector3f.ZERO diff --git a/connector/src/main/java/org/geysermc/connector/utils/EntityUtils.java b/connector/src/main/java/org/geysermc/connector/utils/EntityUtils.java index 79ce9e8b..b5033c94 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/EntityUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/EntityUtils.java @@ -26,8 +26,6 @@ package org.geysermc.connector.utils; import com.github.steveice10.mc.protocol.data.game.entity.Effect; -import com.github.steveice10.mc.protocol.data.game.entity.type.MobType; -import com.github.steveice10.mc.protocol.data.game.entity.type.object.ObjectType; import org.geysermc.connector.entity.type.EntityType; public class EntityUtils { @@ -64,21 +62,7 @@ public class EntityUtils { * @param type The MobType to convert * @return Converted EntityType */ - public static EntityType toBedrockEntity(MobType type) { - try { - return EntityType.valueOf(type.name()); - } catch (IllegalArgumentException ex) { - return null; - } - } - - /** - * Converts a ObjectType to a Bedrock edition EntityType, returns null if the EntityType is not found - * - * @param type The ObjectType to convert - * @return Converted EntityType - */ - public static EntityType toBedrockEntity(ObjectType type) { + public static EntityType toBedrockEntity(com.github.steveice10.mc.protocol.data.game.entity.type.EntityType type) { try { return EntityType.valueOf(type.name()); } catch (IllegalArgumentException ex) { From 1664221fa9c000b711fab012ab177afb78918a08 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Sat, 23 May 2020 17:02:51 -0400 Subject: [PATCH 28/73] Add optional workaround for >Y128 Nether building (#615) * Add optional workaround for >Y128 Nether building This commit adds a config option for building above the Nether by changing the Nether's dimension ID to match the End's. * Only check for workaround application once * Fix mappings? * Include a bit more for the above bedrock nether building config option Co-authored-by: Redned --- .../platform/bukkit/GeyserBukkitConfiguration.java | 5 +++++ .../bungeecord/GeyserBungeeConfiguration.java | 5 +++++ .../platform/sponge/GeyserSpongeConfiguration.java | 5 +++++ .../standalone/GeyserStandaloneConfiguration.java | 3 +++ .../velocity/GeyserVelocityConfiguration.java | 3 +++ .../org/geysermc/connector/GeyserConfiguration.java | 4 +++- .../java/org/geysermc/connector/GeyserConnector.java | 4 ++++ .../org/geysermc/connector/utils/DimensionUtils.java | 11 ++++++++++- connector/src/main/resources/config.yml | 6 ++++++ 9 files changed, 44 insertions(+), 2 deletions(-) diff --git a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java index 10b06a39..aeaa912e 100644 --- a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java +++ b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java @@ -131,6 +131,11 @@ public class GeyserBukkitConfiguration implements GeyserConfiguration { return true; // We override this as with Bukkit, we have direct access to the server implementation } + @Override + public boolean isAboveBedrockNetherBuilding() { + return config.getBoolean("above-bedrock-nether-building", false); + } + @Override public IMetricsInfo getMetrics() { return metricsInfo; diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java index dc5c0fc4..b097501f 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java @@ -130,6 +130,11 @@ public class GeyserBungeeConfiguration implements GeyserConfiguration { return config.getBoolean("cache-chunks", false); } + @Override + public boolean isAboveBedrockNetherBuilding() { + return config.getBoolean("above-bedrock-nether-building", false); + } + @Override public BungeeMetricsInfo getMetrics() { return metricsInfo; diff --git a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java index 96a12399..eb660b86 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java @@ -124,6 +124,11 @@ public class GeyserSpongeConfiguration implements GeyserConfiguration { return node.getNode("cache-chunks").getBoolean(false); } + @Override + public boolean isAboveBedrockNetherBuilding() { + return node.getNode("above-bedrock-nether-building").getBoolean(false); + } + @Override public SpongeMetricsInfo getMetrics() { return metricsInfo; diff --git a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneConfiguration.java b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneConfiguration.java index 10e1fe0b..a856f8a5 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneConfiguration.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneConfiguration.java @@ -71,6 +71,9 @@ public class GeyserStandaloneConfiguration implements GeyserConfiguration { @JsonProperty("cache-chunks") private boolean cacheChunks; + @JsonProperty("above-bedrock-nether-building") + private boolean isAboveBedrockNetherBuilding; + private MetricsInfo metrics; @Override diff --git a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java index bc29f20d..aec4ccf9 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java @@ -76,6 +76,9 @@ public class GeyserVelocityConfiguration implements GeyserConfiguration { @JsonProperty("cache-chunks") private boolean cacheChunks; + @JsonProperty("above-bedrock-nether-building") + private boolean aboveBedrockNetherBuilding; + private MetricsInfo metrics; private Path floodgateKey; diff --git a/connector/src/main/java/org/geysermc/connector/GeyserConfiguration.java b/connector/src/main/java/org/geysermc/connector/GeyserConfiguration.java index 423a3600..938d25ef 100644 --- a/connector/src/main/java/org/geysermc/connector/GeyserConfiguration.java +++ b/connector/src/main/java/org/geysermc/connector/GeyserConfiguration.java @@ -32,7 +32,7 @@ import java.util.Map; public interface GeyserConfiguration { // Modify this when you update the config - int CURRENT_CONFIG_VERSION = 1; + int CURRENT_CONFIG_VERSION = 2; IBedrockConfiguration getBedrock(); @@ -56,6 +56,8 @@ public interface GeyserConfiguration { Path getFloodgateKeyFile(); + boolean isAboveBedrockNetherBuilding(); + boolean isCacheChunks(); IMetricsInfo getMetrics(); diff --git a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java index 58307682..75c17b29 100644 --- a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java +++ b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java @@ -40,6 +40,7 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.Translators; import org.geysermc.connector.network.translators.world.WorldManager; import org.geysermc.connector.thread.PingPassthroughThread; +import org.geysermc.connector.utils.DimensionUtils; import org.geysermc.connector.utils.DockerCheck; import org.geysermc.connector.utils.Toolbox; @@ -114,6 +115,9 @@ public class GeyserConnector { if (config.isPingPassthrough()) generalThreadPool.scheduleAtFixedRate(passthroughThread, 1, 1, TimeUnit.SECONDS); + if (config.isAboveBedrockNetherBuilding()) + DimensionUtils.changeBedrockNetherId(); // Apply End dimension ID workaround to Nether + bedrockServer = new BedrockServer(new InetSocketAddress(config.getBedrock().getAddress(), config.getBedrock().getPort())); bedrockServer.setHandler(new ConnectorServerEventHandler(this)); bedrockServer.bind().whenComplete((avoid, throwable) -> { diff --git a/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java b/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java index 2c3933e2..bc7745ca 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java @@ -31,6 +31,10 @@ import org.geysermc.connector.entity.Entity; import org.geysermc.connector.network.session.GeyserSession; public class DimensionUtils { + + // Changes if the above-bedrock Nether building workaround is applied + private static int BEDROCK_NETHER_ID = 1; + public static void switchDimension(GeyserSession session, int javaDimension) { int bedrockDimension = javaToBedrock(javaDimension); Entity player = session.getPlayerEntity(); @@ -71,11 +75,16 @@ public class DimensionUtils { public static int javaToBedrock(int javaDimension) { switch (javaDimension) { case -1: - return 1; + return BEDROCK_NETHER_ID; case 1: return 2; default: return javaDimension; } } + + public static void changeBedrockNetherId() { + // Change dimension ID to the End to allow for building above Bedrock + BEDROCK_NETHER_ID = 2; + } } diff --git a/connector/src/main/resources/config.yml b/connector/src/main/resources/config.yml index 221707f2..70fcad4a 100644 --- a/connector/src/main/resources/config.yml +++ b/connector/src/main/resources/config.yml @@ -73,6 +73,12 @@ default-locale: en_us # Geyser has direct access to the server itself. cache-chunks: false +# Bedrock prevents building and displaying blocks above Y127 in the Nether - +# enabling this config option works around that by changing the Nether dimension ID +# to the End ID. The main downside to this is that the sky will resemble that of +# the end sky in the nether, but ultimately it's the only way for this feature to work. +above-bedrock-nether-building: false + # bStats is a stat tracker that is entirely anonymous and tracks only basic information # about Geyser, such as how many people are online, how many servers are using Geyser, # what OS is being used, etc. You can learn more about bStats here: https://bstats.org/. From fc6532732da3d7ac6a1b067b4faf632f238c546e Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sat, 23 May 2020 22:06:34 +0100 Subject: [PATCH 29/73] Adds skin ears from MinecraftCapes.co.uk + Clientside linked account skins + Elytra textures (#539) * Added ears geometry support * Added ear fetching from mc capes * Added support for deadmau5 * Commented, documented and cleaned code * Allow bedrock players to see their java skin/cape/ears when joining * Optimised Imports * Fix missing else statement * Moved ears and fixed elytra skins * Added ears config option * Fixed cape/elytra transparency * Fixed slim skin geometry * Fixed async ears request and added alex skin * Fixed default elytra not showing with no cape * Moved to normal Base64 functions Co-authored-by: James Harrison --- .../bukkit/GeyserBukkitConfiguration.java | 5 + .../bungeecord/GeyserBungeeConfiguration.java | 5 + .../sponge/GeyserSpongeConfiguration.java | 5 + .../GeyserStandaloneConfiguration.java | 3 + .../velocity/GeyserVelocityConfiguration.java | 3 + .../connector/GeyserConfiguration.java | 2 + .../network/session/GeyserSession.java | 11 + .../player/JavaPlayerListEntryTranslator.java | 9 +- .../connector/utils/SkinProvider.java | 278 ++++++++++++++++-- .../geysermc/connector/utils/SkinUtils.java | 58 ++-- .../bedrock/skin/geometry.humanoid.ears.json | 249 ++++++++++++++++ .../skin/geometry.humanoid.earsSlim.json | 249 ++++++++++++++++ .../main/resources/bedrock/skin/skin_alex.png | Bin 0 -> 2105 bytes connector/src/main/resources/config.yml | 4 + 14 files changed, 838 insertions(+), 43 deletions(-) create mode 100644 connector/src/main/resources/bedrock/skin/geometry.humanoid.ears.json create mode 100644 connector/src/main/resources/bedrock/skin/geometry.humanoid.earsSlim.json create mode 100644 connector/src/main/resources/bedrock/skin/skin_alex.png diff --git a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java index aeaa912e..9ea2da2b 100644 --- a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java +++ b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java @@ -116,6 +116,11 @@ public class GeyserBukkitConfiguration implements GeyserConfiguration { return config.getBoolean("allow-third-party-capes", true); } + @Override + public boolean isAllowThirdPartyEars() { + return config.getBoolean("allow-third-party-ears", false); + } + @Override public String getDefaultLocale() { return config.getString("default-locale", "en_us"); diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java index b097501f..cb9d1fbf 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java @@ -115,6 +115,11 @@ public class GeyserBungeeConfiguration implements GeyserConfiguration { return config.getBoolean("allow-third-party-capes", true); } + @Override + public boolean isAllowThirdPartyEars() { + return config.getBoolean("allow-third-party-ears", false); + } + @Override public String getDefaultLocale() { return config.getString("default-locale", "en_us"); diff --git a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java index eb660b86..c84f2dfc 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java @@ -109,6 +109,11 @@ public class GeyserSpongeConfiguration implements GeyserConfiguration { return node.getNode("allow-third-party-capes").getBoolean(true); } + @Override + public boolean isAllowThirdPartyEars() { + return node.getNode("allow-third-party-ears").getBoolean(false); + } + @Override public String getDefaultLocale() { return node.getNode("default-locale").getString("en_us"); diff --git a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneConfiguration.java b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneConfiguration.java index a856f8a5..8c8ce376 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneConfiguration.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneConfiguration.java @@ -65,6 +65,9 @@ public class GeyserStandaloneConfiguration implements GeyserConfiguration { @JsonProperty("allow-third-party-capes") private boolean allowThirdPartyCapes; + @JsonProperty("allow-third-party-ears") + private boolean allowThirdPartyEars; + @JsonProperty("default-locale") private String defaultLocale; diff --git a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java index aec4ccf9..685c21a3 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java @@ -70,6 +70,9 @@ public class GeyserVelocityConfiguration implements GeyserConfiguration { @JsonProperty("allow-third-party-capes") private boolean allowThirdPartyCapes; + @JsonProperty("allow-third-party-ears") + private boolean allowThirdPartyEars; + @JsonProperty("default-locale") private String defaultLocale; diff --git a/connector/src/main/java/org/geysermc/connector/GeyserConfiguration.java b/connector/src/main/java/org/geysermc/connector/GeyserConfiguration.java index 938d25ef..34edd8e0 100644 --- a/connector/src/main/java/org/geysermc/connector/GeyserConfiguration.java +++ b/connector/src/main/java/org/geysermc/connector/GeyserConfiguration.java @@ -52,6 +52,8 @@ public interface GeyserConfiguration { boolean isAllowThirdPartyCapes(); + boolean isAllowThirdPartyEars(); + String getDefaultLocale(); Path getFloodgateKeyFile(); diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index fa9960f2..cec38f20 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -207,6 +207,17 @@ public class GeyserSession implements CommandSender { upstream.sendPacket(playStatusPacket); } + public void fetchOurSkin(PlayerListPacket.Entry entry) { + PlayerSkinPacket playerSkinPacket = new PlayerSkinPacket(); + playerSkinPacket.setUuid(authData.getUUID()); + playerSkinPacket.setSkin(entry.getSkin()); + playerSkinPacket.setOldSkinName("OldName"); + playerSkinPacket.setNewSkinName("NewName"); + playerSkinPacket.setTrustedSkin(true); + upstream.sendPacket(playerSkinPacket); + getConnector().getLogger().debug("Sending skin for " + playerEntity.getUsername() + " " + authData.getUUID()); + } + public void login() { if (connector.getAuthType() != AuthType.ONLINE) { connector.getLogger().info( diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerListEntryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerListEntryTranslator.java index 2f71d683..96dc6050 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerListEntryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerListEntryTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.connector.network.translators.java.entity.player; +import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.entity.PlayerEntity; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; @@ -51,8 +52,12 @@ public class JavaPlayerListEntryTranslator extends PacketTranslator { + GeyserConnector.getInstance().getLogger().debug("Loading Local Bedrock Java Skin Data"); + }); + } else { playerEntity = new PlayerEntity( entry.getProfile(), -1, diff --git a/connector/src/main/java/org/geysermc/connector/utils/SkinProvider.java b/connector/src/main/java/org/geysermc/connector/utils/SkinProvider.java index 469ae758..b14a9901 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/SkinProvider.java +++ b/connector/src/main/java/org/geysermc/connector/utils/SkinProvider.java @@ -35,10 +35,10 @@ import org.geysermc.connector.GeyserConnector; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; +import java.io.*; import java.net.URL; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Base64; import java.util.Map; @@ -51,6 +51,8 @@ public class SkinProvider { public static final byte[] STEVE_SKIN = new ProvidedSkin("bedrock/skin/skin_steve.png").getSkin(); public static final Skin EMPTY_SKIN = new Skin(-1, "steve", STEVE_SKIN); + public static final byte[] ALEX_SKIN = new ProvidedSkin("bedrock/skin/skin_alex.png").getSkin(); + public static final Skin EMPTY_SKIN_ALEX = new Skin(-1, "alex", ALEX_SKIN); private static Map cachedSkins = new ConcurrentHashMap<>(); private static Map> requestedSkins = new ConcurrentHashMap<>(); @@ -58,12 +60,49 @@ public class SkinProvider { private static Map cachedCapes = new ConcurrentHashMap<>(); private static Map> requestedCapes = new ConcurrentHashMap<>(); - public static final SkinGeometry EMPTY_GEOMETRY = SkinProvider.SkinGeometry.getLegacy("geometry.humanoid"); + public static final SkinGeometry EMPTY_GEOMETRY = SkinProvider.SkinGeometry.getLegacy(false); private static Map cachedGeometry = new ConcurrentHashMap<>(); + public static final boolean ALLOW_THIRD_PARTY_EARS = GeyserConnector.getInstance().getConfig().isAllowThirdPartyEars(); + public static String EARS_GEOMETRY; + public static String EARS_GEOMETRY_SLIM; + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); private static final int CACHE_INTERVAL = 8 * 60 * 1000; // 8 minutes + static { + /* Load in the normal ears geometry */ + InputStream earsStream = Toolbox.getResource("bedrock/skin/geometry.humanoid.ears.json"); + + StringBuilder earsDataBuilder = new StringBuilder(); + try (Reader reader = new BufferedReader(new InputStreamReader(earsStream, Charset.forName(StandardCharsets.UTF_8.name())))) { + int c = 0; + while ((c = reader.read()) != -1) { + earsDataBuilder.append((char) c); + } + } catch (IOException e) { + throw new AssertionError("Unable to load ears geometry", e); + } + + EARS_GEOMETRY = earsDataBuilder.toString(); + + + /* Load in the slim ears geometry */ + earsStream = Toolbox.getResource("bedrock/skin/geometry.humanoid.earsSlim.json"); + + earsDataBuilder = new StringBuilder(); + try (Reader reader = new BufferedReader(new InputStreamReader(earsStream, Charset.forName(StandardCharsets.UTF_8.name())))) { + int c = 0; + while ((c = reader.read()) != -1) { + earsDataBuilder.append((char) c); + } + } catch (IOException e) { + throw new AssertionError("Unable to load ears geometry", e); + } + + EARS_GEOMETRY_SLIM = earsDataBuilder.toString(); + } + public static boolean hasSkinCached(UUID uuid) { return cachedSkins.containsKey(uuid); } @@ -167,6 +206,43 @@ public class SkinProvider { return CompletableFuture.completedFuture(officialCape); } + public static CompletableFuture requestEars(String earsUrl, EarsProvider provider, boolean newThread, Skin skin) { + if (earsUrl == null || earsUrl.isEmpty()) return CompletableFuture.completedFuture(skin); + + CompletableFuture future; + if (newThread) { + future = CompletableFuture.supplyAsync(() -> supplyEars(skin, earsUrl, provider), EXECUTOR_SERVICE) + .whenCompleteAsync((outSkin, throwable) -> { }); + } else { + Skin ears = supplyEars(skin, earsUrl, provider); // blocking + future = CompletableFuture.completedFuture(ears); + } + return future; + } + + /** + * Try and find an ear texture for a Java player + * + * @param officialSkin The current players skin + * @param playerId The players UUID + * @param username The players username + * @param newThread Should we start in a new thread + * @return The updated skin with ears + */ + public static CompletableFuture requestUnofficialEars(Skin officialSkin, UUID playerId, String username, boolean newThread) { + for (EarsProvider provider : EarsProvider.VALUES) { + Skin skin1 = getOrDefault( + requestEars(provider.getUrlFor(playerId, username), provider, newThread, officialSkin), + officialSkin, 4 + ); + if (skin1.isEars()) { + return CompletableFuture.completedFuture(skin1); + } + } + + return CompletableFuture.completedFuture(officialSkin); + } + public static CompletableFuture requestBedrockCape(UUID playerID, boolean newThread) { Cape bedrockCape = cachedCapes.getOrDefault(playerID.toString() + ".Bedrock", EMPTY_CAPE); return CompletableFuture.completedFuture(bedrockCape); @@ -178,7 +254,7 @@ public class SkinProvider { } public static void storeBedrockSkin(UUID playerID, String skinID, byte[] skinData) { - Skin skin = new Skin(playerID, skinID, skinData, System.currentTimeMillis(), true); + Skin skin = new Skin(playerID, skinID, skinData, System.currentTimeMillis(), true, false); cachedSkins.put(playerID, skin); } @@ -188,16 +264,36 @@ public class SkinProvider { } public static void storeBedrockGeometry(UUID playerID, byte[] geometryName, byte[] geometryData) { - SkinGeometry geometry = new SkinGeometry(new String(geometryName), new String(geometryData)); + SkinGeometry geometry = new SkinGeometry(new String(geometryName), new String(geometryData), false); cachedGeometry.put(playerID, geometry); } + /** + * Stores the ajusted skin with the ear texture to the cache + * + * @param playerID The UUID to cache it against + * @param skin The skin to cache + */ + public static void storeEarSkin(UUID playerID, Skin skin) { + cachedSkins.put(playerID, skin); + } + + /** + * Stores the geometry for a Java player with ears + * + * @param playerID The UUID to cache it against + * @param isSlim If the player is using an slim base + */ + public static void storeEarGeometry(UUID playerID, boolean isSlim) { + cachedGeometry.put(playerID, SkinGeometry.getEars(isSlim)); + } + private static Skin supplySkin(UUID uuid, String textureUrl) { byte[] skin = EMPTY_SKIN.getSkinData(); try { skin = requestImage(textureUrl, null); } catch (Exception ignored) {} // just ignore I guess - return new Skin(uuid, textureUrl, skin, System.currentTimeMillis(), false); + return new Skin(uuid, textureUrl, skin, System.currentTimeMillis(), false, false); } private static Cape supplyCape(String capeUrl, CapeProvider provider) { @@ -217,6 +313,48 @@ public class SkinProvider { ); } + /** + * Get the ears texture and place it on the skin from the given URL + * + * @param existingSkin The players current skin + * @param earsUrl The URL to get the ears texture from + * @param provider The ears texture provider + * @return The updated skin with ears + */ + private static Skin supplyEars(Skin existingSkin, String earsUrl, EarsProvider provider) { + try { + // Get the ears texture + BufferedImage ears = ImageIO.read(new URL(earsUrl)); + if (ears == null) throw new NullPointerException(); + + // Convert the skin data to a BufferedImage + int height = (existingSkin.getSkinData().length / 4 / 64); + BufferedImage skinImage = imageDataToBufferedImage(existingSkin.getSkinData(), 64, height); + + // Create a new image with the ears texture over it + BufferedImage newSkin = new BufferedImage(skinImage.getWidth(), skinImage.getHeight(), BufferedImage.TYPE_INT_ARGB); + Graphics2D g = (Graphics2D) newSkin.getGraphics(); + g.drawImage(skinImage, 0, 0, null); + g.drawImage(ears, 24, 0, null); + + // Turn the buffered image back into an array of bytes + byte[] data = bufferedImageToImageData(newSkin); + skinImage.flush(); + + // Create a new skin object with the new infomation + return new Skin( + existingSkin.getSkinOwner(), + existingSkin.getTextureUrl(), + data, + System.currentTimeMillis(), + true, + true + ); + } catch (Exception ignored) {} // just ignore I guess + + return existingSkin; + } + private static byte[] requestImage(String imageUrl, CapeProvider provider) throws Exception { BufferedImage image = downloadImage(imageUrl, provider); GeyserConnector.getInstance().getLogger().debug("Downloaded " + imageUrl); @@ -226,26 +364,16 @@ public class SkinProvider { while(image.getWidth() > 64) { image = scale(image); } - BufferedImage newImage = new BufferedImage(64, 32, BufferedImage.TYPE_INT_RGB); + BufferedImage newImage = new BufferedImage(64, 32, BufferedImage.TYPE_INT_ARGB); Graphics g = newImage.createGraphics(); g.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null); g.dispose(); image = newImage; } - try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream(image.getWidth() * 4 + image.getHeight() * 4)) { - for (int y = 0; y < image.getHeight(); y++) { - for (int x = 0; x < image.getWidth(); x++) { - int rgba = image.getRGB(x, y); - outputStream.write((rgba >> 16) & 0xFF); - outputStream.write((rgba >> 8) & 0xFF); - outputStream.write(rgba & 0xFF); - outputStream.write((rgba >> 24) & 0xFF); - } - } - image.flush(); - return outputStream.toByteArray(); - } + byte[] data = bufferedImageToImageData(image); + image.flush(); + return data; } private static BufferedImage downloadImage(String imageUrl, CapeProvider provider) throws IOException { @@ -267,7 +395,7 @@ public class SkinProvider { } private static BufferedImage scale(BufferedImage bufferedImage) { - BufferedImage resized = new BufferedImage(bufferedImage.getWidth() / 2, bufferedImage.getHeight() / 2, BufferedImage.TYPE_INT_RGB); + BufferedImage resized = new BufferedImage(bufferedImage.getWidth() / 2, bufferedImage.getHeight() / 2, BufferedImage.TYPE_INT_ARGB); Graphics2D g2 = resized.createGraphics(); g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g2.drawImage(bufferedImage, 0, 0, bufferedImage.getWidth() / 2, bufferedImage.getHeight() / 2, null); @@ -275,6 +403,60 @@ public class SkinProvider { return resized; } + /** + * Get the RGBA int for a given index in some image data + * + * @param index Index to get + * @param data Image data to find in + * @return An int representing RGBA + */ + private static int getRGBA(int index, byte[] data) { + return (data[index] & 0xFF) << 16 | (data[index + 1] & 0xFF) << 8 | + data[index + 2] & 0xFF | (data[index + 3] & 0xFF) << 24; + } + + /** + * Convert a byte[] to a BufferedImage + * + * @param imageData The byte[] to convert + * @param imageWidth The width of the target image + * @param imageHeight The height of the target image + * @return The converted BufferedImage + */ + public static BufferedImage imageDataToBufferedImage(byte[] imageData, int imageWidth, int imageHeight) { + BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_ARGB); + int index = 0; + for (int y = 0; y < imageHeight; y++) { + for (int x = 0; x < imageWidth; x++) { + image.setRGB(x, y, getRGBA(index, imageData)); + index += 4; + } + } + + return image; + } + + /** + * Convert a BufferedImage to a byte[] + * + * @param image The BufferedImage to convert + * @return The converted byte[] + */ + public static byte[] bufferedImageToImageData(BufferedImage image) { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(image.getWidth() * 4 + image.getHeight() * 4); + for (int y = 0; y < image.getHeight(); y++) { + for (int x = 0; x < image.getWidth(); x++) { + int rgba = image.getRGB(x, y); + outputStream.write((rgba >> 16) & 0xFF); + outputStream.write((rgba >> 8) & 0xFF); + outputStream.write(rgba & 0xFF); + outputStream.write((rgba >> 24) & 0xFF); + } + } + + return outputStream.toByteArray(); + } + public static T getOrDefault(CompletableFuture future, T defaultValue, int timeoutInSeconds) { try { return future.get(timeoutInSeconds, TimeUnit.SECONDS); @@ -297,6 +479,7 @@ public class SkinProvider { private byte[] skinData; private long requestedOn; private boolean updated; + private boolean ears; private Skin(long requestedOn, String textureUrl, byte[] skinData) { this.requestedOn = requestedOn; @@ -320,9 +503,26 @@ public class SkinProvider { public static class SkinGeometry { private String geometryName; private String geometryData; + private boolean failed; - public static SkinGeometry getLegacy(String name) { - return new SkinProvider.SkinGeometry("{\"geometry\" :{\"default\" :\"" + name + "\"}}", ""); + /** + * Generate generic geometry + * + * @param isSlim Should it be the alex model + * @return The generic geometry object + */ + public static SkinGeometry getLegacy(boolean isSlim) { + return new SkinProvider.SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.custom" + (isSlim ? "Slim" : "") + "\"}}", "", true); + } + + /** + * Generate basic geometry with ears + * + * @param isSlim Should it be the alex model + * @return The generated geometry for the ears model + */ + public static SkinGeometry getEars(boolean isSlim) { + return new SkinProvider.SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.ears" + (isSlim ? "Slim" : "") + "\"}}", (isSlim ? EARS_GEOMETRY_SLIM : EARS_GEOMETRY), false); } } @@ -365,4 +565,34 @@ public class SkinProvider { UUID, UUID_DASHED } + + /* + * Sorted by 'priority' + */ + @AllArgsConstructor + @NoArgsConstructor + @Getter + public enum EarsProvider { + MINECRAFTCAPES("https://www.minecraftcapes.co.uk/getEars/%s", CapeUrlType.UUID); + + public static final EarsProvider[] VALUES = values(); + private String url; + private CapeUrlType type; + + public String getUrlFor(String type) { + return String.format(url, type); + } + + public String getUrlFor(UUID uuid, String username) { + return getUrlFor(toRequestedType(type, uuid, username)); + } + + public static String toRequestedType(CapeUrlType type, UUID uuid, String username) { + switch (type) { + case UUID: return uuid.toString().replace("-", ""); + case UUID_DASHED: return uuid.toString(); + default: return username; + } + } + } } diff --git a/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java b/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java index 8e68d3e1..95a3ff19 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java @@ -53,7 +53,7 @@ public class SkinUtils { GameProfileData data = GameProfileData.from(profile); SkinProvider.Cape cape = SkinProvider.getCachedCape(data.getCapeUrl()); - SkinProvider.SkinGeometry geometry = SkinProvider.SkinGeometry.getLegacy("geometry.humanoid.custom" + (data.isAlex() ? "Slim" : "")); + SkinProvider.SkinGeometry geometry = SkinProvider.SkinGeometry.getLegacy(data.isAlex()); return buildEntryManually( profile.getId(), @@ -88,7 +88,7 @@ public class SkinUtils { String geometryName, String geometryData) { SerializedSkin serializedSkin = SerializedSkin.of( skinId, geometryName, ImageData.of(skinData), Collections.emptyList(), - ImageData.of(capeData), geometryData, "", true, false, false, capeId, uuid.toString() + ImageData.of(capeData), geometryData, "", true, false, !capeId.equals(SkinProvider.EMPTY_CAPE.getCapeId()), capeId, uuid.toString() ); PlayerListPacket.Entry entry = new PlayerListPacket.Entry(uuid); @@ -115,6 +115,9 @@ public class SkinUtils { * @return The built GameProfileData */ public static GameProfileData from(GameProfile profile) { + // Fallback to the offline mode of working it out + boolean isAlex = ((profile.getId().hashCode() % 2) == 1); + try { GameProfile.Property skinProperty = profile.getProperty("textures"); @@ -124,7 +127,7 @@ public class SkinUtils { JsonNode skinTexture = textures.get("SKIN"); String skinUrl = skinTexture.get("url").asText(); - boolean isAlex = skinTexture.has("metadata"); + isAlex = skinTexture.has("metadata"); String capeUrl = null; if (textures.has("CAPE")) { @@ -138,7 +141,7 @@ public class SkinUtils { GeyserConnector.getInstance().getLogger().debug("Got invalid texture data for " + profile.getName() + " " + exception.getMessage()); } // return default skin with default cape when texture data is invalid - return new GameProfileData(SkinProvider.EMPTY_SKIN.getTextureUrl(), SkinProvider.EMPTY_CAPE.getTextureUrl(), false); + return new GameProfileData((isAlex ? SkinProvider.EMPTY_SKIN_ALEX.getTextureUrl() : SkinProvider.EMPTY_SKIN.getTextureUrl()), SkinProvider.EMPTY_CAPE.getTextureUrl(), isAlex); } } } @@ -167,11 +170,38 @@ public class SkinUtils { ), SkinProvider.EMPTY_CAPE, SkinProvider.CapeProvider.VALUES.length * 3); } - SkinProvider.SkinGeometry geometry = SkinProvider.SkinGeometry.getLegacy("geometry.humanoid.custom" + (data.isAlex() ? "Slim" : "")); + SkinProvider.SkinGeometry geometry = SkinProvider.SkinGeometry.getLegacy(data.isAlex()); geometry = SkinProvider.getOrDefault(SkinProvider.requestBedrockGeometry( geometry, entity.getUuid(), false ), geometry, 3); + // Not a bedrock player check for ears + if (geometry.isFailed() && SkinProvider.ALLOW_THIRD_PARTY_EARS) { + boolean isEars = false; + + // Its deadmau5, gotta support his skin :) + if (entity.getUuid().toString().equals("1e18d5ff-643d-45c8-b509-43b8461d8614")) { + isEars = true; + } else { + // Get the ears texture for the player + skin = SkinProvider.getOrDefault(SkinProvider.requestUnofficialEars( + skin, entity.getUuid(), entity.getUsername(), false + ), skin, 3); + + isEars = skin.isEars(); + } + + // Does the skin have an ears texture + if (isEars) { + // Get the new geometry + geometry = SkinProvider.SkinGeometry.getEars(data.isAlex()); + + // Store the skin and geometry for the ears + SkinProvider.storeEarSkin(entity.getUuid(), skin); + SkinProvider.storeEarGeometry(entity.getUuid(), data.isAlex()); + } + } + if (entity.getLastSkinUpdate() < skin.getRequestedOn()) { entity.setLastSkinUpdate(skin.getRequestedOn()); @@ -197,6 +227,10 @@ public class SkinUtils { playerAddPacket.setAction(PlayerListPacket.Action.ADD); playerAddPacket.getEntries().add(updatedEntry); session.sendUpstreamPacket(playerAddPacket); + + if(entity.getUuid().equals(session.getPlayerEntity().getUuid())) { + session.fetchOurSkin(updatedEntry); + } } } } catch (Exception e) { @@ -217,8 +251,8 @@ public class SkinUtils { byte[] skinBytes = com.github.steveice10.mc.auth.util.Base64.decode(clientData.getSkinData().getBytes("UTF-8")); byte[] capeBytes = clientData.getCapeData(); - byte[] geometryNameBytes = com.github.steveice10.mc.auth.util.Base64.decode(clientData.getGeometryName().getBytes("UTF-8")); - byte[] geometryBytes = com.github.steveice10.mc.auth.util.Base64.decode(clientData.getGeometryData().getBytes("UTF-8")); + byte[] geometryNameBytes = Base64.getDecoder().decode(clientData.getGeometryName().getBytes("UTF-8")); + byte[] geometryBytes = Base64.getDecoder().decode(clientData.getGeometryData().getBytes("UTF-8")); if (skinBytes.length <= (128 * 128 * 4) && !clientData.isPersonaSkin()) { SkinProvider.storeBedrockSkin(playerEntity.getUuid(), data.getSkinUrl(), skinBytes); @@ -235,14 +269,4 @@ public class SkinUtils { throw new AssertionError("Failed to cache skin for bedrock user (" + playerEntity.getUsername() + "): ", e); } } - - /** - * Create a basic geometry json for the given name - * - * @param geometryName Geometry name to use - * @return Geometry data as a json string - */ - private static String getLegacySkinGeometry(String geometryName) { - return "{\"geometry\" :{\"default\" :\"" + geometryName + "\"}}"; - } } diff --git a/connector/src/main/resources/bedrock/skin/geometry.humanoid.ears.json b/connector/src/main/resources/bedrock/skin/geometry.humanoid.ears.json new file mode 100644 index 00000000..5571655b --- /dev/null +++ b/connector/src/main/resources/bedrock/skin/geometry.humanoid.ears.json @@ -0,0 +1,249 @@ +{ + "format_version": "1.14.0", + "minecraft:geometry": [ + { + "bones": [ + { + "name" : "root", + "pivot" : [ 0.0, 0.0, 0.0 ] + }, + + { + "name" : "waist", + "parent" : "root", + "pivot" : [ 0.0, 12.0, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes" : [] + }, + + + { + "name": "body", + "parent" : "waist", + "pivot": [ 0.0, 24.0, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes": [ + { + "origin": [ -4.0, 12.0, -2.0 ], + "size": [ 8, 12, 4 ], + "uv": [ 16, 16 ] + } + ] + }, + + { + "name": "jacket", + "parent" : "body", + "pivot": [ 0.0, 24.0, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes": [ + { + "origin": [ -4.0, 12.0, -2.0 ], + "size": [ 8, 12, 4 ], + "uv": [ 16, 32 ], + "inflate": 0.25 + } + ] + }, + + + { + "name": "head", + "parent" : "body", + "pivot": [ 0.0, 24.0, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes": [ + { + "origin": [ -4.0, 24.0, -4.0 ], + "size": [ 8, 8, 8 ], + "uv": [ 0, 0 ] + } + ] + }, + + { + "name": "hat", + "parent" : "head", + "pivot": [ 0.0, 24.0, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes": [ + { + "origin": [ -4.0, 24.0, -4.0 ], + "size": [ 8, 8, 8 ], + "uv": [ 32, 0 ], + "inflate": 0.5 + } + ] + }, + + + { + "name": "leftArm", + "parent" : "body", + "pivot": [ 5.0, 22.0, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes": [ + { + "origin": [ 4.0, 12.0, -2.0 ], + "size": [ 4, 12, 4 ], + "uv": [ 32, 48 ] + } + ] + }, + { + "name": "rightArm", + "parent" : "body", + "pivot": [ -5.0, 22.0, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes": [ + { + "origin": [ -8.0, 12.0, -2.0 ], + "size": [ 4, 12, 4 ], + "uv": [ 40, 16 ] + } + ] + }, + + { + "name": "leftSleeve", + "parent" : "leftArm", + "pivot": [ 5.0, 22.0, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes": [ + { + "origin": [ 4.0, 12.0, -2.0 ], + "size": [ 4, 12, 4 ], + "uv": [ 48, 48 ], + "inflate": 0.25 + } + ] + }, + + { + "name": "rightSleeve", + "parent" : "rightArm", + "pivot": [ -5.0, 22.0, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes": [ + { + "origin": [ -8.0, 12.0, -2.0 ], + "size": [ 4, 12, 4 ], + "uv": [ 40, 32 ], + "inflate": 0.25 + } + ] + }, + + + { + "name": "leftLeg", + "parent" : "root", + "pivot": [ 1.9, 12.0, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes": [ + { + "origin": [ -0.1, 0.0, -2.0 ], + "size": [ 4, 12, 4 ], + "uv": [ 0, 16 ] + } + ] + }, + + { + "name": "rightLeg", + "parent" : "root", + "pivot": [ -1.9, 12.0, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes": [ + { + "origin": [ -3.9, 0.0, -2.0 ], + "size": [ 4, 12, 4 ], + "uv": [ 0, 16 ] + } + ] + }, + + { + "name": "leftPants", + "parent" : "leftLeg", + "pivot": [1.9, 12.0, 0.0], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes": [ + { + "origin": [ -0.1, 0.0, -2.0 ], + "size": [ 4, 12, 4 ], + "uv": [ 0, 48 ], + "inflate": 0.25 + } + ] + }, + + { + "name": "rightPants", + "parent" : "rightLeg", + "pivot": [ -1.9, 12.0, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes": [ + { + "origin": [ -3.9, 0.0, -2.0] , + "size": [ 4, 12, 4 ], + "uv": [ 0, 32], + "inflate": 0.25 + } + ] + }, + + + { + "name" : "rightItem", + "parent" : "rightArm", + "pivot" : [ -6.0, 15.0, 1.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes" : [] + }, + + { + "name" : "leftItem", + "parent" : "leftArm", + "pivot" : [ 6.0, 15.0, 1.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes" : [] + }, + + + { + "name": "leftEar", + "parent" : "head", + "pivot": [ -1.9, 12.0, 0.0 ], + "cubes": [ + { + "origin": [ 3.0, 31.0, -0.5 ], + "size": [ 6, 6, 1 ], + "uv": [ 24, 0 ], + "inflate": 0.5 + } + ] + }, + + { + "name": "rightEar", + "parent" : "head", + "pivot": [ -1.9, 12.0, 0.0 ], + "cubes": [ + { + "origin": [ -9.0, 31.0, -0.5 ], + "size": [ 6, 6, 1 ], + "uv": [ 24, 0 ], + "inflate": 0.5 + } + ] + } + ], + "description": { + "identifier": "geometry.humanoid.ears", + "texture_height": 64, + "texture_width": 64 + } + } + ] +} \ No newline at end of file diff --git a/connector/src/main/resources/bedrock/skin/geometry.humanoid.earsSlim.json b/connector/src/main/resources/bedrock/skin/geometry.humanoid.earsSlim.json new file mode 100644 index 00000000..70c44f85 --- /dev/null +++ b/connector/src/main/resources/bedrock/skin/geometry.humanoid.earsSlim.json @@ -0,0 +1,249 @@ +{ + "format_version": "1.14.0", + "minecraft:geometry": [ + { + "bones": [ + { + "name" : "root", + "pivot" : [ 0.0, 0.0, 0.0 ] + }, + + { + "name" : "waist", + "parent" : "root", + "pivot" : [ 0.0, 12.0, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes" : [] + }, + + + { + "name": "body", + "parent" : "waist", + "pivot": [ 0.0, 24.0, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes": [ + { + "origin": [ -4.0, 12.0, -2.0 ], + "size": [ 8, 12, 4 ], + "uv": [ 16, 16 ] + } + ] + }, + + { + "name": "jacket", + "parent" : "body", + "pivot": [ 0.0, 24.0, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes": [ + { + "origin": [ -4.0, 12.0, -2.0 ], + "size": [ 8, 12, 4 ], + "uv": [ 16, 32 ], + "inflate": 0.25 + } + ] + }, + + + { + "name": "head", + "parent" : "body", + "pivot": [ 0.0, 24.0, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes": [ + { + "origin": [ -4.0, 24.0, -4.0 ], + "size": [ 8, 8, 8 ], + "uv": [ 0, 0 ] + } + ] + }, + + { + "name": "hat", + "parent" : "head", + "pivot": [ 0.0, 24.0, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes": [ + { + "origin": [ -4.0, 24.0, -4.0 ], + "size": [ 8, 8, 8 ], + "uv": [ 32, 0 ], + "inflate": 0.5 + } + ] + }, + + + { + "name": "leftArm", + "parent" : "body", + "pivot": [ 5.0, 21.5, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes": [ + { + "origin": [ 4.0, 12, -2.0 ], + "size": [ 3, 12, 4 ], + "uv": [ 32, 48 ] + } + ] + }, + { + "name": "rightArm", + "parent" : "body", + "pivot": [ -5.0, 21.5, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes": [ + { + "origin": [ -7.0, 12, -2.0 ], + "size": [ 3, 12, 4 ], + "uv": [ 40, 16 ] + } + ] + }, + + { + "name": "leftSleeve", + "parent" : "leftArm", + "pivot": [ 5.0, 21.5, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes": [ + { + "origin": [ 4.0, 11.5, -2.0 ], + "size": [ 3, 12, 4 ], + "uv": [ 48, 48 ], + "inflate": 0.25 + } + ] + }, + + { + "name": "rightSleeve", + "parent" : "rightArm", + "pivot": [ -5.0, 21.5, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes": [ + { + "origin": [ -7.0, 11.5, -2.0 ], + "size": [ 3, 12, 4 ], + "uv": [ 40, 32 ], + "inflate": 0.25 + } + ] + }, + + + { + "name": "leftLeg", + "parent" : "root", + "pivot": [ 1.9, 12.0, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes": [ + { + "origin": [ -0.1, 0.0, -2.0 ], + "size": [ 4, 12, 4 ], + "uv": [ 0, 16 ] + } + ] + }, + + { + "name": "rightLeg", + "parent" : "root", + "pivot": [ -1.9, 12.0, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes": [ + { + "origin": [ -3.9, 0.0, -2.0 ], + "size": [ 4, 12, 4 ], + "uv": [ 0, 16 ] + } + ] + }, + + { + "name": "leftPants", + "parent" : "leftLeg", + "pivot": [1.9, 12.0, 0.0], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes": [ + { + "origin": [ -0.1, 0.0, -2.0 ], + "size": [ 4, 12, 4 ], + "uv": [ 0, 48 ], + "inflate": 0.25 + } + ] + }, + + { + "name": "rightPants", + "parent" : "rightLeg", + "pivot": [ -1.9, 12.0, 0.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes": [ + { + "origin": [ -3.9, 0.0, -2.0] , + "size": [ 4, 12, 4 ], + "uv": [ 0, 32], + "inflate": 0.25 + } + ] + }, + + + { + "name" : "rightItem", + "parent" : "rightArm", + "pivot" : [ -6.0, 15.0, 1.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes" : [] + }, + + { + "name" : "leftItem", + "parent" : "leftArm", + "pivot" : [ 6.0, 15.0, 1.0 ], + "rotation" : [ 0.0, 0.0, 0.0 ], + "cubes" : [] + }, + + + { + "name": "leftEar", + "parent" : "head", + "pivot": [ -1.9, 12.0, 0.0 ], + "cubes": [ + { + "origin": [ 3.0, 31.0, -0.5 ], + "size": [ 6, 6, 1 ], + "uv": [ 24, 0 ], + "inflate": 0.5 + } + ] + }, + + { + "name": "rightEar", + "parent" : "head", + "pivot": [ -1.9, 12.0, 0.0 ], + "cubes": [ + { + "origin": [ -9.0, 31.0, -0.5 ], + "size": [ 6, 6, 1 ], + "uv": [ 24, 0 ], + "inflate": 0.5 + } + ] + } + ], + "description": { + "identifier": "geometry.humanoid.earsSlim", + "texture_height": 64, + "texture_width": 64 + } + } + ] +} \ No newline at end of file diff --git a/connector/src/main/resources/bedrock/skin/skin_alex.png b/connector/src/main/resources/bedrock/skin/skin_alex.png new file mode 100644 index 0000000000000000000000000000000000000000..ffd8e0719a1a4fac1f58895ed3a30130d3aa4b46 GIT binary patch literal 2105 zcmV-92*&q`P)E~eMGYDf65)*| zViT=e&nSo{8jS>AST+16Bm|5oP~|Nz*84u)@ATQ{X0O-Vy|!F8`DSKkcJKE4nP+Bq zb~Xqm*sdL17K--Ohei29dba=Zk_u98mk;K~G_bTdUr0y#7M4`%O`9cvi|;Oy^shrX zXLN9PTTGb&P-Y3>^!_E1UOCk4jDEDcJ*MmcM22COAOt`Jgy!Gh-V_rdWDx-{46_6w z03skXf3T-HCPK(00%8DEH$ZvS0Yru!0M!jpJ|zGk0ie1A_5tAX&mUAB03-lZcfdXX zT>9z5Dg!Wsp6>rp)d846PxpVQ>Hu7S*LMLG1q9$z764p-*LMLG1q9$zCIIx{$5yvp zpp?@7zaIS9>b47%QrRI+qcmyzyh}Z|Mc;86oG<0?YjZlZZJ&3k=eFoOPJ{EM{QV%& zNWz7446tUBpt*8S6rn89NWz7446tUBpt*8S6rn6Ab>Y@1%>VQIuqf8j1ZG;^g3(dN z-z;_E)+o$h|1B?ywKRd5mbYMZlsN#lRoS;$#yrj6K7Ta4dh%nD9u(bg=vFq6eBHvf zs=Wi~4aWaH_if2zVy$c-`MO0A3u)8J$iwKJJ9okd*FPlYZ(sUB@+d={ekv?ACTPGq z9}DTo3|kr7%Z(2Nh5riXZ(ra{B9AiE>BnW?ZPShyIh@Fv~t0um@Vkm>94}k zbH|){NiQ4^Z=Lx@@&x5I>gg7-{epO#(KmeUf=a$rjzdzI+QfH68Ck=q~nRyQfQ0gr!09pXR@XrK5{w@K)$6@5F z0f6R_ZdyDyfMyH;H<%Wr$A&DsKqdej(TFN8;-oNL@6k6y-QxUxl*@mcYezZjgQ1~7R8EWY$6<2o(+dOu zq|GzGIX7S6KsZ)k055RQ-i5{ZmT}1#G;yc?KM9ABEJ80P!(f}B$V*bk> zZ%F$9IDiFRJ#i!^Mio@5Zm@S_08O~n)zyU*4Ziy9A`x3&AJfp#5K}Ay3Mox%Q`%e% zz)-wTYXD5GIsF)}L9mW#*#K6oSP@b%*wWGxwzjs4kVlz5X4R@y;o7xpMaWwKw)L$c z+huf%GtYAgK$|6i>%R`k{*6DrF3d^?CDo7W6#; z>FWMm41gXJP={lD$IG#wy%IYIbug$U0HVnl_FC z$Kx6s8^fliCK2*F{E@;KrOk3*4}g%Z*Ki=3gHdT^n!Nl=F@QoD>i#a|4{UxefF=cC z-MV!}5rDGE0I+?Yx3kz7;5puo8!V@BniZ3gQP#1Zg(%63TDyrTefTwA&)YB z%<|>S!(1*WLf-c{io3_QriC$~Ozr~tWB^vE6XQ`|cK}ou&{0qkfa%&gIyx#labO?_ z1_vd@=^58uzpY#u1f88@>gyYu;T<^=1cwig?L)c_A_%A^B0vLxc^aLS0MPO< zIa?xN>r;;g2cBOd+O?)G;4?mieTelef2(tiQ%wTE6P~21yk-G()IH(_AewCev`Gs< zcaNF`U|U%Ou;W8bjsX^c9s_K2^tR@lY8pV&U7#ibP%wqiM*7mSc|q^$1x_rVRsd-i zS7r6cv;1B5WQUWbXu3S*?+elb&`W3)0f6}k#I(FG$N~V?67BML*#-!pkWS0{g46(D z-tz%O*#M^ceS!Uc0N)gF@l-FX>*aO5@S$Ijvh_)E0O08>a|kgLmOEw7vPf8Q4%-t~V(fChl~ z1=#d-x!M5q(mB5{@rAz+K3joHk=@%wb1)!4e3(~It<3WiV=L3uYJ}F|W+H5iH z_XTO!|C0ddxk6O|r2W1iY5kvO_42rH{U5W%83Uk_?+dg+tO4rvf0kqYKMBB Date: Sat, 23 May 2020 17:09:11 -0400 Subject: [PATCH 30/73] Add players able to sleep in beds (#575) * Add players able to sleep in beds This commit sets the correct metadata and flags when the Java pose changes to sleeping. * Player view while sleeping now works * Fixed bed offset for other players --- .../org/geysermc/connector/entity/Entity.java | 31 +++++++++++++++++++ ...BedrockInventoryTransactionTranslator.java | 2 ++ .../java/world/JavaBlockChangeTranslator.java | 1 - 3 files changed, 33 insertions(+), 1 deletion(-) 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 d0c1920f..91686e42 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/Entity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/Entity.java @@ -27,14 +27,17 @@ package org.geysermc.connector.entity; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction; import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.github.steveice10.mc.protocol.data.message.TextMessage; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerUseItemPacket; import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.data.EntityData; import com.nukkitx.protocol.bedrock.data.EntityDataMap; import com.nukkitx.protocol.bedrock.data.EntityFlag; @@ -50,7 +53,9 @@ import org.geysermc.connector.entity.living.ArmorStandEntity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.item.ItemTranslator; +import org.geysermc.connector.network.translators.world.block.BlockTranslator; import org.geysermc.connector.utils.AttributeUtils; +import org.geysermc.connector.utils.ChunkUtils; import org.geysermc.connector.utils.MessageUtils; import java.util.ArrayList; @@ -264,6 +269,32 @@ public class Entity { case 5: // no gravity metadata.getFlags().setFlag(EntityFlag.HAS_GRAVITY, !(boolean) entityMetadata.getValue()); break; + case 6: // Pose change + if (entityMetadata.getValue().equals(Pose.SLEEPING)) { + metadata.getFlags().setFlag(EntityFlag.SLEEPING, true); + // Has to be a byte or it does not work + metadata.put(EntityData.CAN_START_SLEEP, (byte) 2); + if (entityId == session.getPlayerEntity().getEntityId()) { + Vector3i lastInteractionPos = session.getLastInteractionPosition(); + metadata.put(EntityData.BED_RESPAWN_POS, lastInteractionPos); + if (session.getConnector().getConfig().isCacheChunks()) { + BlockState bed = session.getConnector().getWorldManager().getBlockAt(session, lastInteractionPos.getX(), + lastInteractionPos.getY(), lastInteractionPos.getZ()); + // Bed has to be updated, or else player is floating in the air + ChunkUtils.updateBlock(session, bed, lastInteractionPos); + } + } else { + metadata.put(EntityData.BED_RESPAWN_POS, Vector3i.from(position.getFloorX(), position.getFloorY() - 2, position.getFloorZ())); + } + metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.2f); + metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.2f); + } else if (metadata.getFlags().getFlag(EntityFlag.SLEEPING)) { + metadata.getFlags().setFlag(EntityFlag.SLEEPING, false); + metadata.put(EntityData.BOUNDING_BOX_WIDTH, getEntityType().getWidth()); + metadata.put(EntityData.BOUNDING_BOX_HEIGHT, getEntityType().getHeight()); + metadata.put(EntityData.CAN_START_SLEEP, (byte) 0); + } + break; case 7: // blocking if (entityMetadata.getType() == MetadataType.BYTE) { byte xd = (byte) entityMetadata.getValue(); 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 71ba20e4..7a60143d 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 @@ -132,6 +132,8 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator Date: Sat, 23 May 2020 17:11:54 -0400 Subject: [PATCH 31/73] Debugging improvements (#585) * Debugging improvements - Added an ObjectArrayList of packets we don't anticipate ever translating. Currently only holds ServerUpdateLightPacket which we don't use and probably don't need. - Only print debugging logs from sounds if they failed to play. * Add space --- .../connector/network/translators/Registry.java | 11 ++++++++++- .../java/world/JavaPlayBuiltinSoundTranslator.java | 5 +---- .../java/world/JavaPlayerPlaySoundTranslator.java | 7 +------ 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/Registry.java b/connector/src/main/java/org/geysermc/connector/network/translators/Registry.java index 70201ba8..399ec1a6 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/Registry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/Registry.java @@ -28,6 +28,8 @@ package org.geysermc.connector.network.translators; import java.util.HashMap; import java.util.Map; +import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdateLightPacket; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.network.session.GeyserSession; @@ -40,6 +42,12 @@ public class Registry { public static final Registry JAVA = new Registry<>(); public static final Registry BEDROCK = new Registry<>(); + private static final ObjectArrayList> IGNORED_PACKETS = new ObjectArrayList<>(); + + static { + IGNORED_PACKETS.add(ServerUpdateLightPacket.class); + } + public static void registerJava(Class targetPacket, PacketTranslator translator) { JAVA.MAP.put(targetPacket, translator); } @@ -56,7 +64,8 @@ public class Registry { ((PacketTranslator

) MAP.get(clazz)).translate(packet, session); return true; } else { - GeyserConnector.getInstance().getLogger().debug("Could not find packet for " + (packet.toString().length() > 25 ? packet.getClass().getSimpleName() : packet)); + if (!IGNORED_PACKETS.contains(clazz)) + GeyserConnector.getInstance().getLogger().debug("Could not find packet for " + (packet.toString().length() > 25 ? packet.getClass().getSimpleName() : packet)); } } catch (Throwable ex) { GeyserConnector.getInstance().getLogger().error("Could not translate packet " + packet.getClass().getSimpleName(), ex); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayBuiltinSoundTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayBuiltinSoundTranslator.java index e060e095..0a5274db 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayBuiltinSoundTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayBuiltinSoundTranslator.java @@ -45,10 +45,8 @@ public class JavaPlayBuiltinSoundTranslator extends PacketTranslator " - + soundMapping + (soundMapping == null ? "[not found]" : "") - + " - " + packet.toString()); if (soundMapping == null) { + session.getConnector().getLogger().debug("[Builtin] Sound mapping " + packetSound + " not found - " + packet.toString()); return; } @@ -93,6 +91,5 @@ public class JavaPlayBuiltinSoundTranslator extends PacketTranslator " + soundPacket.toString()); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayerPlaySoundTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayerPlaySoundTranslator.java index 97274a72..c349c628 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayerPlaySoundTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayerPlaySoundTranslator.java @@ -52,15 +52,11 @@ public class JavaPlayerPlaySoundTranslator extends PacketTranslator " - + soundMapping + (soundMapping == null ? "[not found]" : "") - + " - " + packet.toString()); String playsound; if(soundMapping == null || soundMapping.getPlaysound() == null) { // no mapping session.getConnector().getLogger() - .debug("[PlaySound] Defaulting to sound server gave us."); + .debug("[PlaySound] Defaulting to sound server gave us for " + packet.toString()); playsound = packetSound; } else { playsound = soundMapping.getPlaysound(); @@ -73,6 +69,5 @@ public class JavaPlayerPlaySoundTranslator extends PacketTranslator " + playSoundPacket); } } From d8d9fb7190167e24b60ed04285782b63f64f3a54 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sat, 23 May 2020 22:33:39 +0100 Subject: [PATCH 32/73] Fireworks! (#579) * Fixed firework entity * Added firework item translator * Fixed mappings submodule --- .../connector/entity/FireworkEntity.java | 200 ++++++++++++------ .../connector/entity/type/EntityType.java | 2 +- .../translators/nbt/FireworkTranslator.java | 143 +++++++++++++ .../connector/utils/FireworkColor.java | 80 +++++++ 4 files changed, 360 insertions(+), 65 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/utils/FireworkColor.java diff --git a/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java b/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java index 25128d48..a074a53c 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java @@ -1,64 +1,136 @@ -/* - * 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; - -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket; -import org.geysermc.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; - -import java.util.OptionalInt; - -public class FireworkEntity extends Entity { - - public FireworkEntity(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) { - if (entityMetadata.getId() == 8 && !entityMetadata.getValue().equals(OptionalInt.empty()) && ((OptionalInt) entityMetadata.getValue()).getAsInt() == session.getPlayerEntity().getEntityId()) { - //Checks if the firework has an entity ID (used when a player is gliding) and checks to make sure the player that is gliding is the one getting sent the packet or else every player near the gliding player will boost too. - PlayerEntity entity = session.getPlayerEntity(); - float yaw = entity.getRotation().getX(); - float pitch = entity.getRotation().getY(); - //Uses math from NukkitX - entity.setMotion(Vector3f.from( - -Math.sin(Math.toRadians(yaw)) * Math.cos(Math.toRadians(pitch)) * 2, - -Math.sin(Math.toRadians(pitch)) * 2, - Math.cos(Math.toRadians(yaw)) * Math.cos(Math.toRadians(pitch)) * 2)); - //Need to update the EntityMotionPacket or else the player won't boost - SetEntityMotionPacket entityMotionPacket = new SetEntityMotionPacket(); - entityMotionPacket.setRuntimeEntityId(entity.getGeyserId()); - entityMotionPacket.setMotion(entity.getMotion()); - - session.sendUpstreamPacket(entityMotionPacket); - } - super.updateBedrockMetadata(entityMetadata, session); - } -} \ No newline at end of file +/* + * 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; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +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 com.nukkitx.math.vector.Vector3f; +import com.nukkitx.nbt.CompoundTagBuilder; +import com.nukkitx.protocol.bedrock.data.EntityData; +import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.entity.type.EntityType; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.utils.FireworkColor; + +import java.util.ArrayList; +import java.util.List; +import java.util.OptionalInt; + +public class FireworkEntity extends Entity { + + public FireworkEntity(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) { + if (entityMetadata.getId() == 7) { + ItemStack item = (ItemStack) entityMetadata.getValue(); + CompoundTag tag = item.getNbt(); + CompoundTag fireworks = tag.get("Fireworks"); + + CompoundTagBuilder fireworksBuilder = CompoundTagBuilder.builder(); + fireworksBuilder.byteTag("Flight", (Byte) fireworks.get("Flight").getValue()); + + List explosions = new ArrayList<>(); + for (Tag effect : ((ListTag) fireworks.get("Explosions")).getValue()) { + CompoundTag effectData = (CompoundTag) effect; + + try { + GeyserConnector.getInstance().getLogger().debug("Effect: " + new ObjectMapper().writeValueAsString(effect)); + } catch (JsonProcessingException e) { } + + CompoundTagBuilder effectBuilder = CompoundTagBuilder.builder(); + if (effectData.get("Type") != null) { + effectBuilder.byteTag("FireworkType", (Byte) effectData.get("Type").getValue()); + } + + if (effectData.get("Colors") != null) { + int[] oldColors = (int[]) effectData.get("Colors").getValue(); + byte[] colors = new byte[oldColors.length]; + + int i = 0; + for (int color : oldColors) { + colors[i++] = FireworkColor.fromJavaID(color).getBedrockID(); + } + + effectBuilder.byteArrayTag("FireworkColor", colors); + } + + if (effectData.get("FadeColors") != null) { + int[] oldColors = (int[]) effectData.get("FadeColors").getValue(); + byte[] colors = new byte[oldColors.length]; + + int i = 0; + for (int color : oldColors) { + colors[i++] = FireworkColor.fromJavaID(color).getBedrockID(); + } + + effectBuilder.byteArrayTag("FireworkFade", colors); + } + + if (effectData.get("Trail") != null) { + effectBuilder.byteTag("FireworkTrail", (Byte) effectData.get("Trail").getValue()); + } + + if (effectData.get("Flicker") != null) { + effectBuilder.byteTag("FireworkFlicker", (Byte) effectData.get("Flicker").getValue()); + } + + explosions.add(effectBuilder.buildRootTag()); + } + + fireworksBuilder.tag(new com.nukkitx.nbt.tag.ListTag<>("Explosions", com.nukkitx.nbt.tag.CompoundTag.class, explosions)); + + metadata.put(EntityData.DISPLAY_ITEM, CompoundTagBuilder.builder().tag(fireworksBuilder.build("Fireworks")).buildRootTag()); + } else if (entityMetadata.getId() == 8 && !entityMetadata.getValue().equals(OptionalInt.empty()) && ((OptionalInt) entityMetadata.getValue()).getAsInt() == session.getPlayerEntity().getEntityId()) { + //Checks if the firework has an entity ID (used when a player is gliding) and checks to make sure the player that is gliding is the one getting sent the packet or else every player near the gliding player will boost too. + PlayerEntity entity = session.getPlayerEntity(); + float yaw = entity.getRotation().getX(); + float pitch = entity.getRotation().getY(); + //Uses math from NukkitX + entity.setMotion(Vector3f.from( + -Math.sin(Math.toRadians(yaw)) * Math.cos(Math.toRadians(pitch)) * 2, + -Math.sin(Math.toRadians(pitch)) * 2, + Math.cos(Math.toRadians(yaw)) * Math.cos(Math.toRadians(pitch)) * 2)); + //Need to update the EntityMotionPacket or else the player won't boost + SetEntityMotionPacket entityMotionPacket = new SetEntityMotionPacket(); + entityMotionPacket.setRuntimeEntityId(entity.getGeyserId()); + entityMotionPacket.setMotion(entity.getMotion()); + + session.sendUpstreamPacket(entityMotionPacket); + } + + super.updateBedrockMetadata(entityMetadata, 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 43beca9b..2e910a63 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 @@ -106,7 +106,7 @@ public enum EntityType { EXPERIENCE_ORB(ExpOrbEntity.class, 69, 0f, 0f, 0f, 0f, "minecraft:xp_orb"), EYE_OF_ENDER(Entity.class, 70, 0.25f, 0.25f, 0f, 0f, "minecraft:eye_of_ender_signal"), END_CRYSTAL(EnderCrystalEntity.class, 71, 0f, 0f, 0f, 0f, "minecraft:ender_crystal"), - FIREWORK_ROCKET(FireworkEntity.class, 72, 0.25f), + FIREWORK_ROCKET(FireworkEntity.class, 72, 0.25f, 0.25f, 0.25f, 0f, "minecraft:fireworks_rocket"), TRIDENT(TridentEntity.class, 73, 0f, 0f, 0f, 0f, "minecraft:thrown_trident"), TURTLE(AnimalEntity.class, 74, 0.4f, 1.2f), CAT(CatEntity.class, 75, 0.35f, 0.3f), diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkTranslator.java new file mode 100644 index 00000000..77e14e5a --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkTranslator.java @@ -0,0 +1,143 @@ +/* + * 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.network.translators.ItemRemapper; +import org.geysermc.connector.network.translators.NbtItemStackTranslator; +import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.utils.FireworkColor; + +@ItemRemapper +public class FireworkTranslator extends NbtItemStackTranslator { + + @Override + public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) { + CompoundTag fireworks = itemTag.get("Fireworks"); + + ListTag explosions = fireworks.get("Explosions"); + for (Tag effect : explosions.getValue()) { + CompoundTag effectData = (CompoundTag) effect; + + CompoundTag newEffectData = new CompoundTag(""); + + if (effectData.get("Type") != null) { + newEffectData.put(new ByteTag("FireworkType", (Byte) effectData.get("Type").getValue())); + } + + if (effectData.get("Colors") != null) { + int[] oldColors = (int[]) effectData.get("Colors").getValue(); + byte[] colors = new byte[oldColors.length]; + + int i = 0; + for (int color : oldColors) { + colors[i++] = FireworkColor.fromJavaID(color).getBedrockID(); + } + + newEffectData.put(new ByteArrayTag("FireworkColor", colors)); + } + + if (effectData.get("FadeColors") != null) { + int[] oldColors = (int[]) effectData.get("FadeColors").getValue(); + byte[] colors = new byte[oldColors.length]; + + int i = 0; + for (int color : oldColors) { + colors[i++] = FireworkColor.fromJavaID(color).getBedrockID(); + } + + newEffectData.put(new ByteArrayTag("FireworkFade", colors)); + } + + if (effectData.get("Trail") != null) { + newEffectData.put(new ByteTag("FireworkTrail", (Byte) effectData.get("Trail").getValue())); + } + + if (effectData.get("Flicker") != null) { + newEffectData.put(new ByteTag("FireworkFlicker", (Byte) effectData.get("Flicker").getValue())); + } + + explosions.remove(effect); + explosions.add(newEffectData); + } + } + + @Override + public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) { + CompoundTag fireworks = itemTag.get("Fireworks"); + + ListTag explosions = fireworks.get("Explosions"); + for (Tag effect : explosions.getValue()) { + CompoundTag effectData = (CompoundTag) effect; + + CompoundTag newEffectData = new CompoundTag(""); + + if (effectData.get("FireworkType") != null) { + newEffectData.put(new ByteTag("Type", (Byte) effectData.get("FireworkType").getValue())); + } + + if (effectData.get("FireworkColor") != null) { + byte[] oldColors = (byte[]) effectData.get("FireworkColor").getValue(); + int[] colors = new int[oldColors.length]; + + int i = 0; + for (byte color : oldColors) { + colors[i++] = FireworkColor.fromBedrockID(color).getJavaID(); + } + + newEffectData.put(new IntArrayTag("Colors", colors)); + } + + if (effectData.get("FireworkFade") != null) { + byte[] oldColors = (byte[]) effectData.get("FireworkFade").getValue(); + int[] colors = new int[oldColors.length]; + + int i = 0; + for (byte color : oldColors) { + colors[i++] = FireworkColor.fromBedrockID(color).getJavaID(); + } + + newEffectData.put(new IntArrayTag("FadeColors", colors)); + } + + if (effectData.get("FireworkTrail") != null) { + newEffectData.put(new ByteTag("Trail", (Byte) effectData.get("FireworkTrail").getValue())); + } + + if (effectData.get("FireworkFlicker") != null) { + newEffectData.put(new ByteTag("Flicker", (Byte) effectData.get("FireworkFlicker").getValue())); + } + + explosions.remove(effect); + explosions.add(newEffectData); + } + } + + @Override + public boolean acceptItem(ItemEntry itemEntry) { + return "minecraft:firework_rocket".equals(itemEntry.getJavaIdentifier()); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/utils/FireworkColor.java b/connector/src/main/java/org/geysermc/connector/utils/FireworkColor.java new file mode 100644 index 00000000..2f393934 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/utils/FireworkColor.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.utils; + +import lombok.Getter; + +public enum FireworkColor { + BLACK((byte) 0, 1973019), + RED((byte) 1, 11743532), + GREEN((byte) 2, 3887386), + BROWN((byte) 3, 5320730), + BLUE((byte) 4, 2437522), + PURPLE((byte) 5, 8073150), + CYAN((byte) 6, 2651799), + LIGHT_GRAY((byte) 7, 11250603), + GRAY((byte) 8, 4408131), + PINK((byte) 9, 14188952), + LIME((byte) 10, 4312372), + YELLOW((byte) 11, 14602026), + LIGHT_BLUE((byte) 12, 6719955), + MAGENTA((byte) 13, 12801229), + ORANGE((byte) 14, 15435844), + WHITE((byte) 15, 15790320); + + private static final FireworkColor[] VALUES = values(); + + @Getter + private byte bedrockID; + @Getter + private int javaID; + + FireworkColor(byte bedrockID, int javaID) { + this.bedrockID = bedrockID; + this.javaID = javaID; + } + + public static FireworkColor fromJavaID(int id) { + for (FireworkColor color : VALUES) { + if (color.javaID == id) { + return color; + } + } + + return null; + } + + public static FireworkColor fromBedrockID(int id) { + for (FireworkColor color : VALUES) { + if (color.bedrockID == id) { + return color; + } + } + + return null; + } +} From 59da87a10f5ec854396c45378b0d1ca17b0f39e9 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Sat, 23 May 2020 17:39:17 -0400 Subject: [PATCH 33/73] Merge entity mounts branch to master (#589) * Initial support for entity mounts* * This only works for viewing other players on mounts/vehicles. Currently, mounting on vehicles through Geyser with bedrock does not work at all, though, you can see other Java players on mounts just fine. * Fix Bedrock player mounting; add minecart offset * Remove debug code * Fix boat animation * Remove debug code * Add notice of possible steering flip * Add translator for PlayerInputPacket * Upload WIP code for BoatEntity.java * Add animation for rowing on Bedrock side * Clean up debug code, start on boat movement * Add notice about flying horses * Rename BedrockPlayerInputPacket.java to BedrockPlayerInputTranslator.java * Delete BedrockPlayerInputPacket.java * Use Translator Annotation again; Thanks to LegacyGamerHD * Upload ineffective mount-on-login code * Upload current changes with no debug code * Change case where applicable * Change Integer[] to int[]; Change schedule() to execute() * Don't use Thread.Sleep() and instead call itself again * Fix players not being linked on login/chunk load * Little changes * Minor improvements/fixes to boats * Remove empty file * Fix horse flying. * Various entity mounting fixes * Add mounting offsets for skeleton and zombie horses * Another round of entity mount-related fixes - Add offsets for skeleton and zombie horses (Thanks to tester DirtNasty) - Boats can now be placed in survival (Thanks again to tester DirtNasty) - Boats and minecarts can now shake * Add translating for ServerVehicleMovePacket * Cleaning up * More cleaning up * Add interactive tag support for mountable entities * Boats move far more nicely * Add horse heart visuals * Update interactive tags Co-authored-by: RednedEpic --- .../geysermc/connector/entity/BoatEntity.java | 138 ++++++++++++++++ .../org/geysermc/connector/entity/Entity.java | 3 +- .../connector/entity/MinecartEntity.java | 30 +++- .../connector/entity/PlayerEntity.java | 5 + .../entity/attribute/AttributeType.java | 1 + .../animal/horse/AbstractHorseEntity.java | 44 +++++ .../living/animal/horse/HorseEntity.java | 4 +- .../connector/entity/type/EntityType.java | 12 +- .../network/session/GeyserSession.java | 4 + .../network/session/cache/EntityCache.java | 11 +- .../bedrock/BedrockAnimateTranslator.java | 16 ++ .../bedrock/BedrockInteractTranslator.java | 56 +++++++ ...BedrockInventoryTransactionTranslator.java | 7 + .../BedrockMoveEntityAbsoluteTranslator.java | 48 ++++++ .../bedrock/BedrockPlayerInputTranslator.java | 21 +++ .../translators/item/ItemTranslator.java | 2 + .../JavaEntityPositionRotationTranslator.java | 8 +- .../JavaEntityPropertiesTranslator.java | 3 + .../JavaEntitySetPassengersTranslator.java | 153 ++++++++++++++++++ .../java/world/JavaVehicleMoveTranslator.java | 47 ++++++ 20 files changed, 599 insertions(+), 14 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/entity/BoatEntity.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMoveEntityAbsoluteTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockPlayerInputTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntitySetPassengersTranslator.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaVehicleMoveTranslator.java diff --git a/connector/src/main/java/org/geysermc/connector/entity/BoatEntity.java b/connector/src/main/java/org/geysermc/connector/entity/BoatEntity.java new file mode 100644 index 00000000..8f79526d --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/entity/BoatEntity.java @@ -0,0 +1,138 @@ +/* + * 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; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.EntityData; +import org.geysermc.connector.entity.type.EntityType; +import org.geysermc.connector.network.session.GeyserSession; + +import java.util.concurrent.TimeUnit; + +public class BoatEntity extends Entity { + + private boolean isPaddlingLeft; + private float paddleTimeLeft; + private boolean isPaddlingRight; + private float paddleTimeRight; + + // Looks too fast and too choppy with 0.1f, which is how I believe the Microsoftian client handles it + private final float ROWING_SPEED = 0.05f; + + public BoatEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { + super(entityId, geyserId, entityType, position.add(0d, entityType.getOffset(), 0d), motion, rotation.add(0, 0, 90)); + } + + @Override + public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) { + // Rotation is basically only called when entering/exiting a boat. + // We don't include the rotation (y) as it causes the boat to appear sideways + super.moveAbsolute(session, position.add(0d, this.entityType.getOffset(), 0d), Vector3f.from(0, 0, rotation.getZ() + 90), isOnGround, teleported); + } + + @Override + public void moveRelative(GeyserSession session, double relX, double relY, double relZ, Vector3f rotation, boolean isOnGround) { + super.moveRelative(session, relX, relY, relZ, Vector3f.from(0, 0, rotation.getZ()), isOnGround); + } + + @Override + public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { + + // Time since last hit + if (entityMetadata.getId() == 7) { + metadata.put(EntityData.HURT_TIME, entityMetadata.getValue()); + } + + // Rocking direction + if (entityMetadata.getId() == 8) { + metadata.put(EntityData.HURT_DIRECTION, entityMetadata.getValue()); + } + + // 'Health' in Bedrock, damage taken in Java + if (entityMetadata.getId() == 9) { + // Not exactly health but it makes motion in Bedrock + metadata.put(EntityData.HEALTH, 40 - ((int) (float) entityMetadata.getValue())); + } + + if (entityMetadata.getId() == 10) { + metadata.put(EntityData.VARIANT, entityMetadata.getValue()); + } else if (entityMetadata.getId() == 11) { + isPaddlingLeft = (boolean) entityMetadata.getValue(); + if (!isPaddlingLeft) { + metadata.put(EntityData.PADDLE_TIME_LEFT, 0f); + } + else { + // Java sends simply "true" and "false" (is_paddling_left), Bedrock keeps sending packets as you're rowing + // This is an asynchronous method that emulates Bedrock rowing until "false" is sent. + paddleTimeLeft = 0f; + session.getConnector().getGeneralThreadPool().execute(() -> + updateLeftPaddle(session, entityMetadata) + ); + } + } + else if (entityMetadata.getId() == 12) { + isPaddlingRight = (boolean) entityMetadata.getValue(); + if (!isPaddlingRight) { + metadata.put(EntityData.PADDLE_TIME_RIGHT, 0f); + } else { + paddleTimeRight = 0f; + session.getConnector().getGeneralThreadPool().execute(() -> + updateRightPaddle(session, entityMetadata) + ); + } + } else if (entityMetadata.getId() == 13) { + // Possibly - I don't think this does anything? + metadata.put(EntityData.BOAT_BUBBLE_TIME, entityMetadata.getValue()); + } + + super.updateBedrockMetadata(entityMetadata, session); + } + + public void updateLeftPaddle(GeyserSession session, EntityMetadata entityMetadata) { + if (isPaddlingLeft) { + paddleTimeLeft += ROWING_SPEED; + metadata.put(EntityData.PADDLE_TIME_LEFT, paddleTimeLeft); + super.updateBedrockMetadata(entityMetadata, session); + session.getConnector().getGeneralThreadPool().schedule(() -> + updateLeftPaddle(session, entityMetadata), + 100, + TimeUnit.MILLISECONDS + ); + }} + + public void updateRightPaddle(GeyserSession session, EntityMetadata entityMetadata) { + if (isPaddlingRight) { + paddleTimeRight += ROWING_SPEED; + metadata.put(EntityData.PADDLE_TIME_RIGHT, paddleTimeRight); + super.updateBedrockMetadata(entityMetadata, session); + session.getConnector().getGeneralThreadPool().schedule(() -> + updateRightPaddle(session, entityMetadata), + 100, + TimeUnit.MILLISECONDS + ); + }} +} 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 91686e42..30df1085 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/Entity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/Entity.java @@ -44,7 +44,6 @@ import com.nukkitx.protocol.bedrock.data.EntityFlag; import com.nukkitx.protocol.bedrock.data.EntityFlags; import com.nukkitx.protocol.bedrock.packet.*; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; -import it.unimi.dsi.fastutil.longs.LongSet; import lombok.Getter; import lombok.Setter; import org.geysermc.connector.entity.attribute.Attribute; @@ -85,7 +84,7 @@ public class Entity { protected boolean valid; - protected LongSet passengers = new LongOpenHashSet(); + protected LongOpenHashSet passengers = new LongOpenHashSet(); protected Map attributes = new HashMap<>(); protected EntityDataMap metadata = new EntityDataMap(); diff --git a/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java b/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java index 58c887ee..ee004a25 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java @@ -25,12 +25,40 @@ 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.EntityData; import org.geysermc.connector.entity.type.EntityType; +import org.geysermc.connector.network.session.GeyserSession; public class MinecartEntity extends Entity { public MinecartEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { - super(entityId, geyserId, entityType, position, motion, rotation); + super(entityId, geyserId, entityType, position.add(0d, entityType.getOffset(), 0d), motion, rotation); + } + + @Override + public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { + + if (entityMetadata.getId() == 7) { + metadata.put(EntityData.HEALTH, entityMetadata.getValue()); + } + + // Direction in which the minecart is shaking + if (entityMetadata.getId() == 8) { + metadata.put(EntityData.HURT_DIRECTION, entityMetadata.getValue()); + } + + // Power in Java, time in Bedrock + if (entityMetadata.getId() == 9) { + metadata.put(EntityData.HURT_TIME, Math.min((int) (float) entityMetadata.getValue(), 15)); + } + + super.updateBedrockMetadata(entityMetadata, session); + } + + @Override + public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) { + super.moveAbsolute(session, position.add(0d, this.entityType.getOffset(), 0d), rotation, isOnGround, teleported); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java index 98b6b7da..5db3fdec 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java @@ -97,6 +97,11 @@ public class PlayerEntity extends LivingEntity { addPlayerPacket.setPlatformChatId(""); addPlayerPacket.getMetadata().putAll(metadata); + long linkedEntityId = session.getEntityCache().getCachedPlayerEntityLink(entityId); + if (linkedEntityId != -1) { + addPlayerPacket.getEntityLinks().add(new EntityLink(session.getEntityCache().getEntityByJavaId(linkedEntityId).getGeyserId(), geyserId, EntityLink.Type.RIDER, false)); + } + valid = true; session.sendUpstreamPacket(addPlayerPacket); diff --git a/connector/src/main/java/org/geysermc/connector/entity/attribute/AttributeType.java b/connector/src/main/java/org/geysermc/connector/entity/attribute/AttributeType.java index 9166fc8a..2061b895 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/attribute/AttributeType.java +++ b/connector/src/main/java/org/geysermc/connector/entity/attribute/AttributeType.java @@ -38,6 +38,7 @@ public enum AttributeType { MOVEMENT_SPEED("generic.movementSpeed", "minecraft:movement", 0f, 1024f, 0.1f), FLYING_SPEED("generic.flyingSpeed", "minecraft:movement", 0.0f, 1024.0f, 0.4000000059604645f), ATTACK_DAMAGE("generic.attackDamage", "minecraft:attack_damage", 0f, 2048f, 1f), + HORSE_JUMP_STRENGTH("horse.jumpStrength", "minecraft:horse.jump_strength", 0.0f, 2.0f, 0.7f), // Java Attributes ARMOR("generic.armor", null, 0f, 30f, 0f), diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/AbstractHorseEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/AbstractHorseEntity.java index 396ad684..3773011a 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/AbstractHorseEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/AbstractHorseEntity.java @@ -27,25 +27,69 @@ package org.geysermc.connector.entity.living.animal.horse; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.Attribute; import com.nukkitx.protocol.bedrock.data.EntityFlag; +import com.nukkitx.protocol.bedrock.packet.UpdateAttributesPacket; +import org.geysermc.connector.entity.attribute.AttributeType; import org.geysermc.connector.entity.living.animal.AnimalEntity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.utils.AttributeUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; public class AbstractHorseEntity extends AnimalEntity { + // For updating the horse visual easier + private float health = 20f; + public AbstractHorseEntity(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) { + + if (entityMetadata.getId() == 8) { + health = (float) entityMetadata.getValue(); + updateBedrockAttributes(session); + } + if (entityMetadata.getId() == 16) { byte xd = (byte) entityMetadata.getValue(); metadata.getFlags().setFlag(EntityFlag.TAMED, (xd & 0x02) == 0x02); metadata.getFlags().setFlag(EntityFlag.SADDLED, (xd & 0x04) == 0x04); metadata.getFlags().setFlag(EntityFlag.EATING, (xd & 0x10) == 0x10); + metadata.getFlags().setFlag(EntityFlag.STANDING, (xd & 0x20) == 0x20); } + + // Needed to control horses + metadata.getFlags().setFlag(EntityFlag.CAN_POWER_JUMP, true); + metadata.getFlags().setFlag(EntityFlag.WASD_CONTROLLED, true); + super.updateBedrockMetadata(entityMetadata, session); } + + @Override + public void updateBedrockAttributes(GeyserSession session) { + if (!valid) return; + + float maxHealth = attributes.containsKey(AttributeType.MAX_HEALTH) ? attributes.get(AttributeType.MAX_HEALTH).getValue() : 20f; + + List attributesLocal = new ArrayList<>(); + for (Map.Entry entry : this.attributes.entrySet()) { + if (!entry.getValue().getType().isBedrockAttribute()) + continue; + + attributesLocal.add(AttributeUtils.getBedrockAttribute(entry.getValue())); + } + attributesLocal.add(new Attribute("minecraft:health", 0.0f, maxHealth, health, maxHealth)); + + UpdateAttributesPacket updateAttributesPacket = new UpdateAttributesPacket(); + updateAttributesPacket.setRuntimeEntityId(geyserId); + updateAttributesPacket.setAttributes(attributesLocal); + session.sendUpstreamPacket(updateAttributesPacket); + } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/HorseEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/HorseEntity.java index b6a50520..27f4b83c 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/HorseEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/HorseEntity.java @@ -28,6 +28,7 @@ package org.geysermc.connector.entity.living.animal.horse; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; @@ -41,8 +42,9 @@ public class HorseEntity extends AbstractHorseEntity { public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { if (entityMetadata.getId() == 18) { metadata.put(EntityData.VARIANT, (int) entityMetadata.getValue()); + metadata.put(EntityData.MARK_VARIANT, (((int) entityMetadata.getValue()) >> 8) % 5); } - super.updateBedrockMetadata(entityMetadata, session); } + } \ No newline at end of file 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 2e910a63..88934196 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 @@ -119,22 +119,22 @@ public enum EntityType { SNOWBALL(ThrowableEntity.class, 81, 0.25f), THROWN_EGG(ThrowableEntity.class, 82, 0.25f, 0.25f, 0.25f, 0f, "minecraft:egg"), PAINTING(PaintingEntity.class, 83, 0f), - MINECART(MinecartEntity.class, 84, 0.7f, 0.98f), + MINECART(MinecartEntity.class, 84, 0.7f, 0.98f, 0.98f, 0.35f), FIREBALL(ItemedFireballEntity.class, 85, 1.0f), THROWN_POTION(ThrowableEntity.class, 86, 0.25f, 0.25f, 0.25f, 0f, "minecraft:splash_potion"), THROWN_ENDERPEARL(ThrowableEntity.class, 87, 0.25f, 0.25f, 0.25f, 0f, "minecraft:ender_pearl"), LEASH_KNOT(LeashKnotEntity.class, 88, 0.5f, 0.375f), WITHER_SKULL(Entity.class, 89, 0.3125f), - BOAT(Entity.class, 90, 0.7f, 1.6f, 1.6f, 0.35f), + BOAT(BoatEntity.class, 90, 0.7f, 1.6f, 1.6f, 0.35f), WITHER_SKULL_DANGEROUS(Entity.class, 91, 0f), LIGHTNING_BOLT(Entity.class, 93, 0f), SMALL_FIREBALL(ItemedFireballEntity.class, 94, 0.3125f), AREA_EFFECT_CLOUD(AreaEffectCloudEntity.class, 95, 0.5f, 1.0f), - MINECART_HOPPER(MinecartEntity.class, 96, 0.7f, 0.98f, 0.98f, 0f, "minecraft:hopper_minecart"), - MINECART_TNT(MinecartEntity.class, 97, 0.7f, 0.98f, 0.98f, 0f, "minecraft:tnt_minecart"), - MINECART_CHEST(MinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0f, "minecraft:chest_minecart"), + MINECART_HOPPER(MinecartEntity.class, 96, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:hopper_minecart"), + MINECART_TNT(MinecartEntity.class, 97, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:tnt_minecart"), + MINECART_CHEST(MinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:chest_minecart"), - MINECART_COMMAND_BLOCK(MinecartEntity.class, 100, 0.7f, 0.98f, 0.98f, 0f, "minecraft:command_block_minecart"), + MINECART_COMMAND_BLOCK(MinecartEntity.class, 100, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:command_block_minecart"), LINGERING_POTION(ThrowableEntity.class, 101, 0f), LLAMA_SPIT(Entity.class, 102, 0.25f), EVOKER_FANGS(Entity.class, 103, 0.8f, 0.5f), diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index cec38f20..90ca1344 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -58,6 +58,7 @@ import org.geysermc.common.AuthType; import org.geysermc.common.window.FormWindow; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.command.CommandSender; +import org.geysermc.connector.entity.Entity; import org.geysermc.connector.entity.PlayerEntity; import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.network.remote.RemoteServer; @@ -157,6 +158,9 @@ public class GeyserSession implements CommandSender { private boolean manyDimPackets = false; private ServerRespawnPacket lastDimPacket = null; + @Setter + private Entity ridingVehicleEntity; + @Setter private int craftSlot = 0; diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java index 80d10b1a..0bc51ac7 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java @@ -26,8 +26,6 @@ package org.geysermc.connector.network.session.cache; import it.unimi.dsi.fastutil.longs.*; -import it.unimi.dsi.fastutil.objects.Object2LongMap; -import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import lombok.Getter; import org.geysermc.connector.entity.Entity; @@ -49,6 +47,7 @@ public class EntityCache { private Long2LongMap entityIdTranslations = Long2LongMaps.synchronize(new Long2LongOpenHashMap()); private Map playerEntities = Collections.synchronizedMap(new HashMap<>()); private Map bossBars = Collections.synchronizedMap(new HashMap<>()); + private Long2LongMap cachedPlayerEntityLinks = Long2LongMaps.synchronize(new Long2LongOpenHashMap()); @Getter private AtomicLong nextEntityId = new AtomicLong(2L); @@ -148,4 +147,12 @@ public class EntityCache { playerEntities = null; bossBars = null; } + + public long getCachedPlayerEntityLink(long playerId) { + return cachedPlayerEntityLinks.getOrDefault(playerId, -1); + } + + public void addCachedPlayerEntityLink(long playerId, long linkedEntityId) { + cachedPlayerEntityLinks.put(playerId, linkedEntityId); + } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAnimateTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAnimateTranslator.java index 35f710bd..012582da 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAnimateTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAnimateTranslator.java @@ -31,6 +31,7 @@ import org.geysermc.connector.network.translators.Translator; import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerSwingArmPacket; +import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientSteerBoatPacket; import com.nukkitx.protocol.bedrock.packet.AnimatePacket; import java.util.concurrent.TimeUnit; @@ -38,6 +39,9 @@ import java.util.concurrent.TimeUnit; @Translator(packet = AnimatePacket.class) public class BedrockAnimateTranslator extends PacketTranslator { + private boolean isSteeringLeft; + private boolean isSteeringRight; + @Override public void translate(AnimatePacket packet, GeyserSession session) { // Stop the player sending animations before they have fully spawned into the server @@ -54,6 +58,18 @@ public class BedrockAnimateTranslator extends PacketTranslator { TimeUnit.MILLISECONDS ); break; + // These two might need to be flipped, but my recommendation is getting moving working first + case ROW_LEFT: + // Packet value is a float of how long one has been rowing, so we convert that into a boolean + isSteeringLeft = packet.getRowingTime() > 0.0; + ClientSteerBoatPacket steerLeftPacket = new ClientSteerBoatPacket(isSteeringRight, isSteeringLeft); + session.sendDownstreamPacket(steerLeftPacket); + break; + case ROW_RIGHT: + isSteeringRight = packet.getRowingTime() > 0.0; + ClientSteerBoatPacket steerRightPacket = new ClientSteerBoatPacket(isSteeringRight, isSteeringLeft); + session.sendDownstreamPacket(steerRightPacket); + break; } } } 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 a40558a2..b2fd957d 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 @@ -25,6 +25,8 @@ package org.geysermc.connector.network.translators.bedrock; +import com.nukkitx.protocol.bedrock.data.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.Entity; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; @@ -32,7 +34,9 @@ import org.geysermc.connector.network.translators.Translator; import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction; +import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerState; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerInteractEntityPacket; +import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerStatePacket; import com.nukkitx.protocol.bedrock.packet.InteractPacket; import org.geysermc.connector.network.translators.item.ItemTranslator; @@ -59,6 +63,58 @@ public class BedrockInteractTranslator extends PacketTranslator InteractAction.ATTACK, Hand.MAIN_HAND); session.sendDownstreamPacket(attackPacket); break; + case LEAVE_VEHICLE: + ClientPlayerStatePacket sneakPacket = new ClientPlayerStatePacket((int) entity.getEntityId(), PlayerState.START_SNEAKING); + session.sendDownstreamPacket(sneakPacket); + session.setRidingVehicleEntity(null); + break; + case MOUSEOVER: + // Handle the buttons for mobile - "Mount", etc; and the suggestions for console - "ZL: Mount", etc + if (packet.getRuntimeEntityId() != 0) { + Entity interactEntity = session.getEntityCache().getEntityByGeyserId(packet.getRuntimeEntityId()); + if (interactEntity == null) + return; + + String interactiveTag; + switch (interactEntity.getEntityType()) { + case PIG: + if (interactEntity.getMetadata().getFlags().getFlag(EntityFlag.SADDLED)) { + interactiveTag = "action.interact.mount"; + } else interactiveTag = ""; + break; + case HORSE: + case SKELETON_HORSE: + case ZOMBIE_HORSE: + case DONKEY: + case MULE: + case LLAMA: + case TRADER_LLAMA: + if (interactEntity.getMetadata().getFlags().getFlag(EntityFlag.TAMED)) { + interactiveTag = "action.interact.ride.horse"; + } else { + interactiveTag = "action.interact.mount"; + } + break; + case BOAT: + interactiveTag = "action.interact.ride.boat"; + break; + case MINECART: + interactiveTag = "action.interact.ride.minecart"; + break; + default: + return; // No need to process any further since there is no interactive tag + } + session.getPlayerEntity().getMetadata().put(EntityData.INTERACTIVE_TAG, interactiveTag); + session.getPlayerEntity().updateBedrockMetadata(session); + } else { + if (!(session.getPlayerEntity().getMetadata().get(EntityData.INTERACTIVE_TAG) == null) || + !(session.getPlayerEntity().getMetadata().get(EntityData.INTERACTIVE_TAG) == "")) { + // No interactive tag should be sent + session.getPlayerEntity().getMetadata().remove(EntityData.INTERACTIVE_TAG); + session.getPlayerEntity().updateBedrockMetadata(session); + } + } + break; } } } 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 7a60143d..e4e654f0 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 @@ -96,6 +96,13 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator { + + @Override + public void translate(MoveEntityAbsolutePacket packet, GeyserSession session) { + + ClientVehicleMovePacket clientVehicleMovePacket = new ClientVehicleMovePacket( + packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ(), + packet.getRotation().getY() - 90, packet.getRotation().getX() + ); + session.sendDownstreamPacket(clientVehicleMovePacket); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockPlayerInputTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockPlayerInputTranslator.java new file mode 100644 index 00000000..960fbf48 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockPlayerInputTranslator.java @@ -0,0 +1,21 @@ +package org.geysermc.connector.network.translators.bedrock; + +import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientSteerVehiclePacket; +import com.nukkitx.protocol.bedrock.packet.PlayerInputPacket; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.network.translators.Translator; + +// Makes minecarts respond to player input +@Translator(packet = PlayerInputPacket.class) +public class BedrockPlayerInputTranslator extends PacketTranslator { + + @Override + public void translate(PlayerInputPacket packet, GeyserSession session) { + ClientSteerVehiclePacket clientSteerVehiclePacket = new ClientSteerVehiclePacket( + packet.getInputMotion().getX(), packet.getInputMotion().getY(), packet.isJumping(), packet.isSneaking() + ); + + session.sendDownstreamPacket(clientSteerVehiclePacket); + } +} 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 f59b82ba..28766971 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 @@ -48,6 +48,8 @@ public class ItemTranslator { // Shield ID, used in Entity.java public static final int SHIELD = 829; + // Boat ID, used in BedrockInventoryTransactionTranslator.java + public static final int BOAT = 333; public void init() { Reflections ref = new Reflections("org.geysermc.connector.network.translators.item"); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityPositionRotationTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityPositionRotationTranslator.java index 581f16e3..477c8f26 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityPositionRotationTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityPositionRotationTranslator.java @@ -26,6 +26,7 @@ package org.geysermc.connector.network.translators.java.entity; import org.geysermc.connector.entity.Entity; +import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; @@ -42,7 +43,10 @@ public class JavaEntityPositionRotationTranslator extends PacketTranslator { + + @Override + public void translate(ServerEntitySetPassengersPacket packet, GeyserSession session) { + Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId()); + if (entity == null) return; + + LongOpenHashSet passengers = entity.getPassengers().clone(); + boolean rider = true; + for (long passengerId : packet.getPassengerIds()) { + Entity passenger = session.getEntityCache().getEntityByJavaId(passengerId); + if (passengerId == session.getPlayerEntity().getEntityId()) { + passenger = session.getPlayerEntity(); + session.setRidingVehicleEntity(entity); + } + // Passenger hasn't loaded in and entity link needs to be set later + if (passenger == null && passengerId != 0) { + session.getEntityCache().addCachedPlayerEntityLink(passengerId, packet.getEntityId()); + } + if (passenger == null) { + continue; + } + + EntityLink.Type type = rider ? EntityLink.Type.RIDER : EntityLink.Type.PASSENGER; + SetEntityLinkPacket linkPacket = new SetEntityLinkPacket(); + linkPacket.setEntityLink(new EntityLink(entity.getGeyserId(), passenger.getGeyserId(), type, false)); + session.sendUpstreamPacket(linkPacket); + passengers.add(passengerId); + + // Head rotation on boats + if (entity.getEntityType() == EntityType.BOAT) { + passenger.getMetadata().put(EntityData.RIDER_ROTATION_LOCKED, (byte) 1); + passenger.getMetadata().put(EntityData.RIDER_MAX_ROTATION, 90f); + passenger.getMetadata().put(EntityData.RIDER_MIN_ROTATION, !passengers.isEmpty() ? -90f : 0f); + } else { + passenger.getMetadata().remove(EntityData.RIDER_ROTATION_LOCKED); + passenger.getMetadata().remove(EntityData.RIDER_MAX_ROTATION); + passenger.getMetadata().remove(EntityData.RIDER_MIN_ROTATION); + } + + passenger.updateBedrockMetadata(session); + this.updateOffset(passenger, entity.getEntityType(), session, rider, true); + rider = false; + } + + entity.setPassengers(passengers); + + for (long passengerId : entity.getPassengers()) { + Entity passenger = session.getEntityCache().getEntityByJavaId(passengerId); + if (passenger == null) { + continue; + } + if (Arrays.stream(packet.getPassengerIds()).noneMatch(id -> id == passengerId)) { + SetEntityLinkPacket linkPacket = new SetEntityLinkPacket(); + linkPacket.setEntityLink(new EntityLink(entity.getGeyserId(), passenger.getGeyserId(), EntityLink.Type.REMOVE, false)); + session.sendUpstreamPacket(linkPacket); + passengers.remove(passenger.getEntityId()); + + this.updateOffset(passenger, entity.getEntityType(), session, false, false); + } + } + + if (entity.getEntityType() == EntityType.HORSE) { + entity.getMetadata().put(EntityData.RIDER_SEAT_POSITION, Vector3f.from(0.0f, 2.3200102f, -0.2f)); + entity.getMetadata().put(EntityData.RIDER_MAX_ROTATION, 181.0f); + + entity.updateBedrockMetadata(session); + } + } + + private void updateOffset(Entity passenger, EntityType mountType, GeyserSession session, boolean rider, boolean riding) { + // Without these, Bedrock players will find themselves in the floor when mounting + float yOffset = 0; + switch (mountType) { + case BOAT: + yOffset = passenger.getEntityType() == EntityType.PLAYER ? 1.02001f : -0.2f; + break; + case MINECART: + yOffset = passenger.getEntityType() == EntityType.PLAYER ? 1.02001f : 0f; + break; + case DONKEY: + yOffset = 2.1f; + break; + case HORSE: + case SKELETON_HORSE: + case ZOMBIE_HORSE: + case MULE: + yOffset = 2.3f; + break; + case LLAMA: + case TRADER_LLAMA: + yOffset = 2.5f; + break; + case PIG: + yOffset = 1.85001f; + break; + } + Vector3f offset = Vector3f.from(0f, yOffset, 0f); + if (rider) { + offset.add(Vector3f.from(0.2, 0, 0)); + } else { + offset.add(Vector3f.from(-0.6, 0, 0)); + } + passenger.getMetadata().getFlags().setFlag(EntityFlag.RIDING, riding); + if (riding) { + passenger.getMetadata().put(EntityData.RIDER_SEAT_POSITION, offset); + } + passenger.updateBedrockMetadata(session); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaVehicleMoveTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaVehicleMoveTranslator.java new file mode 100644 index 00000000..1bcd9919 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaVehicleMoveTranslator.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + * + */ + +package org.geysermc.connector.network.translators.java.world; + +import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerVehicleMovePacket; +import com.nukkitx.math.vector.Vector3f; +import org.geysermc.connector.entity.Entity; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.network.translators.Translator; + +@Translator(packet = ServerVehicleMovePacket.class) +public class JavaVehicleMoveTranslator extends PacketTranslator { + + @Override + public void translate(ServerVehicleMovePacket packet, GeyserSession session) { + Entity entity = session.getRidingVehicleEntity(); + if (entity == null) return; + + entity.moveAbsolute(session, Vector3f.from(packet.getX(), packet.getY(), packet.getZ()), packet.getYaw(), packet.getPitch(), false, false); + + } +} From 99f69b3a7d0a3cad0e345e489e5151c4aaffaaa0 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Sat, 23 May 2020 17:50:04 -0400 Subject: [PATCH 34/73] Rewrite Ping Passthrough (#468) * Fix ping passthrough on BungeeCord * Initial implementation of direct ping passthrough * Finished implementation of direct ping passthrough * Remove test for something else entirely * Fix standalone * Add config option for ping passthrough interval * Use GeyserPingInfo to reduce methods * Add querying; modify ping passthrough * Add separate config options for passthrough MOTD and player counts * Convert all plugin bootstraps to use internal ping events to that other plugins can handle ping modifications * Small changes * Fix invalid packet spawm * Add legacy ping passthrough option * Fix BungeeCord * Proper UUID for BungeeCord, thanks @theminecoder * Update config version and messages * Merge master... again * Add missing javadocs and minor changes Co-authored-by: James Harrison Co-authored-by: theminecoder Co-authored-by: Redned --- .../bukkit/GeyserBukkitConfiguration.java | 19 +- .../bukkit/GeyserBukkitPingPassthrough.java | 79 ++++++ .../platform/bukkit/GeyserBukkitPlugin.java | 14 + bootstrap/bungeecord/pom.xml | 4 +- .../bungeecord/GeyserBungeeConfiguration.java | 19 +- .../GeyserBungeePingPassthrough.java | 180 ++++++++++++ .../bungeecord/GeyserBungeePlugin.java | 14 + .../sponge/GeyserSpongeConfiguration.java | 19 +- .../sponge/GeyserSpongePingPassthrough.java | 99 +++++++ .../platform/sponge/GeyserSpongePlugin.java | 16 +- .../standalone/GeyserStandaloneBootstrap.java | 13 +- .../GeyserStandaloneConfiguration.java | 13 +- .../velocity/GeyserVelocityConfiguration.java | 13 +- .../GeyserVelocityPingPassthrough.java | 98 +++++++ .../velocity/GeyserVelocityPlugin.java | 13 + .../geysermc/common/ping/GeyserPingInfo.java | 48 ++++ .../connector/GeyserConfiguration.java | 10 +- .../geysermc/connector/GeyserConnector.java | 6 - .../connector/bootstrap/GeyserBootstrap.java | 8 + .../network/ConnectorServerEventHandler.java | 44 ++- .../connector/network/QueryPacketHandler.java | 268 ++++++++++++++++++ .../ping/GeyserLegacyPingPassthrough.java | 91 ++++++ .../ping/IGeyserPingPassthrough.java | 42 +++ .../thread/PingPassthroughThread.java | 65 ----- connector/src/main/resources/config.yml | 17 +- connector/src/main/resources/mappings | 2 +- 26 files changed, 1108 insertions(+), 106 deletions(-) create mode 100644 bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPingPassthrough.java create mode 100644 bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePingPassthrough.java create mode 100644 bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePingPassthrough.java create mode 100644 bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityPingPassthrough.java create mode 100644 common/src/main/java/org/geysermc/common/ping/GeyserPingInfo.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/QueryPacketHandler.java create mode 100644 connector/src/main/java/org/geysermc/connector/ping/GeyserLegacyPingPassthrough.java create mode 100644 connector/src/main/java/org/geysermc/connector/ping/IGeyserPingPassthrough.java delete mode 100644 connector/src/main/java/org/geysermc/connector/thread/PingPassthroughThread.java diff --git a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java index 9ea2da2b..df98b408 100644 --- a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java +++ b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java @@ -92,8 +92,23 @@ public class GeyserBukkitConfiguration implements GeyserConfiguration { } @Override - public boolean isPingPassthrough() { - return config.getBoolean("ping-passthrough", false); + public boolean isPassthroughMotd() { + return config.getBoolean("passthrough-motd", false); + } + + @Override + public boolean isPassthroughPlayerCounts() { + return config.getBoolean("passthrough-player-counts", false); + } + + @Override + public boolean isLegacyPingPassthrough() { + return config.getBoolean("legacy-ping-passthrough", false); + } + + @Override + public int getPingPassthroughInterval() { + return config.getInt("ping-passthrough-interval", 3); } @Override diff --git a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPingPassthrough.java b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPingPassthrough.java new file mode 100644 index 00000000..812467be --- /dev/null +++ b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPingPassthrough.java @@ -0,0 +1,79 @@ +/* + * 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.platform.bukkit; + +import lombok.AllArgsConstructor; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.server.ServerListPingEvent; +import org.bukkit.util.CachedServerIcon; +import org.geysermc.common.ping.GeyserPingInfo; +import org.geysermc.connector.ping.IGeyserPingPassthrough; + +import java.net.InetAddress; +import java.util.Collections; +import java.util.Iterator; + +@AllArgsConstructor +public class GeyserBukkitPingPassthrough implements IGeyserPingPassthrough { + + private final GeyserBukkitLogger logger; + + @Override + public GeyserPingInfo getPingInformation() { + try { + ServerListPingEvent event = new GeyserPingEvent(InetAddress.getLocalHost(), Bukkit.getMotd(), Bukkit.getOnlinePlayers().size(), Bukkit.getMaxPlayers()); + Bukkit.getPluginManager().callEvent(event); + GeyserPingInfo geyserPingInfo = new GeyserPingInfo(event.getMotd(), event.getNumPlayers(), event.getMaxPlayers()); + Bukkit.getOnlinePlayers().forEach(player -> { + geyserPingInfo.addPlayer(player.getName()); + }); + return geyserPingInfo; + } catch (Exception e) { + logger.debug("Error while getting Bukkit ping passthrough: " + e.toString()); + return new GeyserPingInfo(null, 0, 0); + } + } + + // These methods are unimplemented on spigot api by default so we add stubs so plugins don't complain + private static class GeyserPingEvent extends ServerListPingEvent { + + public GeyserPingEvent(InetAddress address, String motd, int numPlayers, int maxPlayers) { + super(address, motd, numPlayers, maxPlayers); + } + + @Override + public void setServerIcon(CachedServerIcon icon) throws IllegalArgumentException, UnsupportedOperationException { + } + + @Override + public Iterator iterator() throws UnsupportedOperationException { + return Collections.EMPTY_LIST.iterator(); + } + } + +} diff --git a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPlugin.java b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPlugin.java index ad1f6194..5f0e967a 100644 --- a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPlugin.java +++ b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPlugin.java @@ -33,6 +33,8 @@ import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.bootstrap.GeyserBootstrap; import org.geysermc.connector.command.CommandManager; import org.geysermc.connector.network.translators.world.WorldManager; +import org.geysermc.connector.ping.GeyserLegacyPingPassthrough; +import org.geysermc.connector.ping.IGeyserPingPassthrough; import org.geysermc.platform.bukkit.command.GeyserBukkitCommandExecutor; import org.geysermc.platform.bukkit.command.GeyserBukkitCommandManager; import org.geysermc.platform.bukkit.world.GeyserBukkitBlockPlaceListener; @@ -46,6 +48,7 @@ public class GeyserBukkitPlugin extends JavaPlugin implements GeyserBootstrap { private GeyserBukkitCommandManager geyserCommandManager; private GeyserBukkitConfiguration geyserConfig; private GeyserBukkitLogger geyserLogger; + private IGeyserPingPassthrough geyserBukkitPingPassthrough; private GeyserBukkitBlockPlaceListener blockPlaceListener; private GeyserBukkitWorldManager geyserWorldManager; @@ -77,6 +80,12 @@ public class GeyserBukkitPlugin extends JavaPlugin implements GeyserBootstrap { this.connector = GeyserConnector.start(PlatformType.BUKKIT, this); + if (geyserConfig.isLegacyPingPassthrough()) { + this.geyserBukkitPingPassthrough = GeyserLegacyPingPassthrough.init(connector); + } else { + this.geyserBukkitPingPassthrough = new GeyserBukkitPingPassthrough(geyserLogger); + } + this.geyserCommandManager = new GeyserBukkitCommandManager(this, connector); boolean isViaVersion = false; @@ -122,6 +131,11 @@ public class GeyserBukkitPlugin extends JavaPlugin implements GeyserBootstrap { return this.geyserCommandManager; } + @Override + public IGeyserPingPassthrough getGeyserPingPassthrough() { + return geyserBukkitPingPassthrough; + } + @Override public WorldManager getWorldManager() { return this.geyserWorldManager; diff --git a/bootstrap/bungeecord/pom.xml b/bootstrap/bungeecord/pom.xml index b9f06916..dd66db32 100644 --- a/bootstrap/bungeecord/pom.xml +++ b/bootstrap/bungeecord/pom.xml @@ -20,7 +20,7 @@ net.md-5 bungeecord-api - 1.14-SNAPSHOT + 1.15-SNAPSHOT provided @@ -80,4 +80,4 @@ - \ No newline at end of file + diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java index cb9d1fbf..d983aec1 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java @@ -91,8 +91,23 @@ public class GeyserBungeeConfiguration implements GeyserConfiguration { } @Override - public boolean isPingPassthrough() { - return config.getBoolean("ping-passthrough", false); + public boolean isPassthroughMotd() { + return config.getBoolean("passthrough-motd", false); + } + + @Override + public boolean isPassthroughPlayerCounts() { + return config.getBoolean("passthrough-player-counts", false); + } + + @Override + public boolean isLegacyPingPassthrough() { + return config.getBoolean("legacy-ping-passthrough", false); + } + + @Override + public int getPingPassthroughInterval() { + return config.getInt("ping-passthrough-interval", 3); } @Override diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePingPassthrough.java b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePingPassthrough.java new file mode 100644 index 00000000..c7f8f276 --- /dev/null +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePingPassthrough.java @@ -0,0 +1,180 @@ +/* + * 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.platform.bungeecord; + +import lombok.AllArgsConstructor; +import net.md_5.bungee.api.ProxyServer; +import net.md_5.bungee.api.ServerPing; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.config.ListenerInfo; +import net.md_5.bungee.api.connection.PendingConnection; +import net.md_5.bungee.api.event.ProxyPingEvent; +import net.md_5.bungee.api.plugin.Listener; +import net.md_5.bungee.protocol.ProtocolConstants; +import org.geysermc.common.ping.GeyserPingInfo; +import org.geysermc.connector.ping.IGeyserPingPassthrough; + +import java.net.Inet4Address; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.Arrays; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; + +@AllArgsConstructor +public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, Listener { + + private static final GeyserPendingConnection PENDING_CONNECTION = new GeyserPendingConnection(); + + private final ProxyServer proxyServer; + + @Override + public GeyserPingInfo getPingInformation() { + CompletableFuture future = new CompletableFuture<>(); + proxyServer.getPluginManager().callEvent(new ProxyPingEvent(PENDING_CONNECTION, getPingInfo(), (event, throwable) -> { + if (throwable != null) future.completeExceptionally(throwable); + else future.complete(event); + })); + ProxyPingEvent event = future.join(); + GeyserPingInfo geyserPingInfo = new GeyserPingInfo( + event.getResponse().getDescription(), + event.getResponse().getPlayers().getOnline(), + event.getResponse().getPlayers().getMax() + ); + if (event.getResponse().getPlayers().getSample() != null) { + Arrays.stream(event.getResponse().getPlayers().getSample()).forEach(proxiedPlayer -> { + geyserPingInfo.addPlayer(proxiedPlayer.getName()); + }); + } + return geyserPingInfo; + } + + // This is static so pending connection can use it + private static ListenerInfo getDefaultListener() { + return ProxyServer.getInstance().getConfig().getListeners().iterator().next(); + } + + private ServerPing getPingInfo() { + return new ServerPing( + new ServerPing.Protocol(proxyServer.getName() + " " + proxyServer.getGameVersion(), ProtocolConstants.SUPPORTED_VERSION_IDS.get(ProtocolConstants.SUPPORTED_VERSION_IDS.size() - 1)), + new ServerPing.Players(getDefaultListener().getMaxPlayers(), proxyServer.getOnlineCount(), null), + getDefaultListener().getMotd(), proxyServer.getConfig().getFaviconObject() + ); + } + + private static class GeyserPendingConnection implements PendingConnection { + + private static final UUID FAKE_UUID = UUID.nameUUIDFromBytes("geyser!internal".getBytes()); + private static final InetSocketAddress FAKE_REMOTE = new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69); + + @Override + public String getName() { + throw new UnsupportedOperationException(); + } + + @Override + public int getVersion() { + return ProtocolConstants.SUPPORTED_VERSION_IDS.get(ProtocolConstants.SUPPORTED_VERSION_IDS.size() - 1); + } + + @Override + public InetSocketAddress getVirtualHost() { + return null; + } + + @Override + public ListenerInfo getListener() { + return getDefaultListener(); + } + + @Override + public String getUUID() { + return FAKE_UUID.toString(); + } + + @Override + public UUID getUniqueId() { + return FAKE_UUID; + } + + @Override + public void setUniqueId(UUID uuid) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isOnlineMode() { + return true; + } + + @Override + public void setOnlineMode(boolean b) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isLegacy() { + return false; + } + + @Override + public InetSocketAddress getAddress() { + return FAKE_REMOTE; + } + + @Override + public SocketAddress getSocketAddress() { + return getAddress(); + } + + @Override + public void disconnect(String s) { + throw new UnsupportedOperationException(); + } + + @Override + public void disconnect(BaseComponent... baseComponents) { + throw new UnsupportedOperationException(); + } + + @Override + public void disconnect(BaseComponent baseComponent) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isConnected() { + return false; + } + + @Override + public Unsafe unsafe() { + throw new UnsupportedOperationException(); + } + } + +} diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePlugin.java index 270fbd1c..525b9b6d 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePlugin.java @@ -35,6 +35,8 @@ import org.geysermc.connector.GeyserConfiguration; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.bootstrap.GeyserBootstrap; import org.geysermc.connector.command.CommandManager; +import org.geysermc.connector.ping.GeyserLegacyPingPassthrough; +import org.geysermc.connector.ping.IGeyserPingPassthrough; import org.geysermc.platform.bungeecord.command.GeyserBungeeCommandExecutor; import org.geysermc.platform.bungeecord.command.GeyserBungeeCommandManager; @@ -51,6 +53,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { private GeyserBungeeCommandManager geyserCommandManager; private GeyserBungeeConfiguration geyserConfig; private GeyserBungeeLogger geyserLogger; + private IGeyserPingPassthrough geyserBungeePingPassthrough; private GeyserConnector connector; @@ -125,6 +128,12 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { this.geyserCommandManager = new GeyserBungeeCommandManager(connector); + if (geyserConfig.isLegacyPingPassthrough()) { + this.geyserBungeePingPassthrough = GeyserLegacyPingPassthrough.init(connector); + } else { + this.geyserBungeePingPassthrough = new GeyserBungeePingPassthrough(getProxy()); + } + this.getProxy().getPluginManager().registerCommand(this, new GeyserBungeeCommandExecutor(connector)); } @@ -147,4 +156,9 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { public CommandManager getGeyserCommandManager() { return this.geyserCommandManager; } + + @Override + public IGeyserPingPassthrough getGeyserPingPassthrough() { + return geyserBungeePingPassthrough; + } } diff --git a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java index c84f2dfc..fc148470 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java @@ -85,8 +85,23 @@ public class GeyserSpongeConfiguration implements GeyserConfiguration { } @Override - public boolean isPingPassthrough() { - return node.getNode("ping-passthrough").getBoolean(false); + public boolean isPassthroughMotd() { + return node.getNode("passthrough-motd").getBoolean(false); + } + + @Override + public boolean isPassthroughPlayerCounts() { + return node.getNode("passthrough-player-counts").getBoolean(false); + } + + @Override + public boolean isLegacyPingPassthrough() { + return node.getNode("legacy-ping-passthrough").getBoolean(false); + } + + @Override + public int getPingPassthroughInterval() { + return node.getNode("ping-passthrough-interval").getInt(3); } @Override diff --git a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePingPassthrough.java b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePingPassthrough.java new file mode 100644 index 00000000..31b6dc7f --- /dev/null +++ b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePingPassthrough.java @@ -0,0 +1,99 @@ +/* + * 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.platform.sponge; + +import org.geysermc.common.ping.GeyserPingInfo; +import org.geysermc.connector.ping.IGeyserPingPassthrough; +import org.spongepowered.api.MinecraftVersion; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.event.SpongeEventFactory; +import org.spongepowered.api.event.cause.Cause; +import org.spongepowered.api.event.cause.EventContext; +import org.spongepowered.api.event.server.ClientPingServerEvent; +import org.spongepowered.api.network.status.StatusClient; + +import java.lang.reflect.Method; +import java.net.Inet4Address; +import java.net.InetSocketAddress; +import java.util.Optional; + +public class GeyserSpongePingPassthrough implements IGeyserPingPassthrough { + + private static final GeyserStatusClient STATUS_CLIENT = new GeyserStatusClient(); + private static final Cause CAUSE = Cause.of(EventContext.empty(), Sponge.getServer()); + + private static Method SpongeStatusResponse_create; + + @SuppressWarnings({"unchecked", "rawtypes"}) + @Override + public GeyserPingInfo getPingInformation() { + // come on Sponge, this is in commons, why not expose it :( + ClientPingServerEvent event; + try { + if(SpongeStatusResponse_create == null) { + Class SpongeStatusResponse = Class.forName("org.spongepowered.common.network.status.SpongeStatusResponse"); + Class MinecraftServer = Class.forName("net.minecraft.server.MinecraftServer"); + SpongeStatusResponse_create = SpongeStatusResponse.getDeclaredMethod("create", MinecraftServer); + } + + Object response = SpongeStatusResponse_create.invoke(null, Sponge.getServer()); + event = SpongeEventFactory.createClientPingServerEvent(CAUSE, STATUS_CLIENT, (ClientPingServerEvent.Response) response); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + Sponge.getEventManager().post(event); + GeyserPingInfo geyserPingInfo = new GeyserPingInfo( + event.getResponse().getDescription().toPlain(), + event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getOnline(), + event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getMax()); + event.getResponse().getPlayers().get().getProfiles().forEach(player -> { + geyserPingInfo.addPlayer(player.getName().orElseThrow(IllegalStateException::new)); + }); + return geyserPingInfo; + } + + @SuppressWarnings("NullableProblems") + private static class GeyserStatusClient implements StatusClient { + + private static final InetSocketAddress FAKE_REMOTE = new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69); + + @Override + public InetSocketAddress getAddress() { + return FAKE_REMOTE; + } + + @Override + public MinecraftVersion getVersion() { + return Sponge.getPlatform().getMinecraftVersion(); + } + + @Override + public Optional getVirtualHost() { + return Optional.empty(); + } + } +} diff --git a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePlugin.java b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePlugin.java index 04a80adf..d226add7 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePlugin.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePlugin.java @@ -34,6 +34,8 @@ import org.geysermc.connector.GeyserConfiguration; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.bootstrap.GeyserBootstrap; import org.geysermc.connector.command.CommandManager; +import org.geysermc.connector.ping.GeyserLegacyPingPassthrough; +import org.geysermc.connector.ping.IGeyserPingPassthrough; import org.geysermc.connector.utils.FileUtils; import org.geysermc.platform.sponge.command.GeyserSpongeCommandExecutor; import org.geysermc.platform.sponge.command.GeyserSpongeCommandManager; @@ -63,6 +65,7 @@ public class GeyserSpongePlugin implements GeyserBootstrap { private GeyserSpongeCommandManager geyserCommandManager; private GeyserSpongeConfiguration geyserConfig; private GeyserSpongeLogger geyserLogger; + private IGeyserPingPassthrough geyserSpongePingPassthrough; private GeyserConnector connector; @@ -108,8 +111,14 @@ public class GeyserSpongePlugin implements GeyserBootstrap { this.geyserLogger = new GeyserSpongeLogger(logger, geyserConfig.isDebugMode()); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); this.connector = GeyserConnector.start(PlatformType.SPONGE, this); - this.geyserCommandManager = new GeyserSpongeCommandManager(Sponge.getCommandManager(), connector); + if (geyserConfig.isLegacyPingPassthrough()) { + this.geyserSpongePingPassthrough = GeyserLegacyPingPassthrough.init(connector); + } else { + this.geyserSpongePingPassthrough = new GeyserSpongePingPassthrough(); + } + + this.geyserCommandManager = new GeyserSpongeCommandManager(Sponge.getCommandManager(), connector); Sponge.getCommandManager().register(this, new GeyserSpongeCommandExecutor(connector), "geyser"); } @@ -133,6 +142,11 @@ public class GeyserSpongePlugin implements GeyserBootstrap { return this.geyserCommandManager; } + @Override + public IGeyserPingPassthrough getGeyserPingPassthrough() { + return geyserSpongePingPassthrough; + } + @Listener public void onServerStart(GameStartedServerEvent event) { onEnable(); diff --git a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneBootstrap.java b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneBootstrap.java index 0916f212..aa0d2392 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneBootstrap.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneBootstrap.java @@ -26,10 +26,12 @@ package org.geysermc.platform.standalone; import org.geysermc.common.PlatformType; +import org.geysermc.connector.ping.GeyserLegacyPingPassthrough; import org.geysermc.connector.GeyserConfiguration; import org.geysermc.connector.bootstrap.GeyserBootstrap; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.command.CommandManager; +import org.geysermc.connector.ping.IGeyserPingPassthrough; import org.geysermc.connector.utils.FileUtils; import org.geysermc.platform.standalone.command.GeyserCommandManager; @@ -40,8 +42,9 @@ import java.util.UUID; public class GeyserStandaloneBootstrap implements GeyserBootstrap { private GeyserCommandManager geyserCommandManager; - private GeyserConfiguration geyserConfig; + private GeyserStandaloneConfiguration geyserConfig; private GeyserStandaloneLogger geyserLogger; + private IGeyserPingPassthrough geyserPingPassthrough; private GeyserConnector connector; @@ -66,6 +69,9 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { connector = GeyserConnector.start(PlatformType.STANDALONE, this); geyserCommandManager = new GeyserCommandManager(connector); + + geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector); + geyserLogger.start(); } @@ -89,4 +95,9 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { public CommandManager getGeyserCommandManager() { return geyserCommandManager; } + + @Override + public IGeyserPingPassthrough getGeyserPingPassthrough() { + return geyserPingPassthrough; + } } diff --git a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneConfiguration.java b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneConfiguration.java index 8c8ce376..bd029204 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneConfiguration.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneConfiguration.java @@ -50,8 +50,17 @@ public class GeyserStandaloneConfiguration implements GeyserConfiguration { @JsonProperty("command-suggestions") private boolean isCommandSuggestions; - @JsonProperty("ping-passthrough") - private boolean pingPassthrough; + @JsonProperty("passthrough-motd") + private boolean isPassthroughMotd; + + @JsonProperty("passthrough-player-counts") + private boolean isPassthroughPlayerCounts; + + @JsonProperty("legacy-ping-passthrough") + private boolean isLegacyPingPassthrough; + + @JsonProperty("ping-passthrough-interval") + private int pingPassthroughInterval; @JsonProperty("max-players") private int maxPlayers; diff --git a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java index 685c21a3..aef0edaa 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java @@ -55,8 +55,17 @@ public class GeyserVelocityConfiguration implements GeyserConfiguration { @JsonProperty("command-suggestions") private boolean commandSuggestions; - @JsonProperty("ping-passthrough") - private boolean pingPassthrough; + @JsonProperty("passthrough-motd") + private boolean isPassthroughMotd; + + @JsonProperty("passthrough-player-counts") + private boolean isPassthroughPlayerCounts; + + @JsonProperty("legacy-ping-passthrough") + private boolean isLegacyPingPassthrough; + + @JsonProperty("ping-passthrough-interval") + private int pingPassthroughInterval; @JsonProperty("max-players") private int maxPlayers; diff --git a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityPingPassthrough.java b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityPingPassthrough.java new file mode 100644 index 00000000..01be949b --- /dev/null +++ b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityPingPassthrough.java @@ -0,0 +1,98 @@ +/* + * 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.platform.velocity; + +import com.velocitypowered.api.event.proxy.ProxyPingEvent; +import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.api.proxy.InboundConnection; +import com.velocitypowered.api.proxy.ProxyServer; +import com.velocitypowered.api.proxy.server.ServerPing; +import lombok.AllArgsConstructor; +import net.kyori.text.TextComponent; +import net.kyori.text.serializer.legacy.LegacyComponentSerializer; +import org.geysermc.common.ping.GeyserPingInfo; +import org.geysermc.connector.ping.IGeyserPingPassthrough; + +import java.net.Inet4Address; +import java.net.InetSocketAddress; +import java.util.Optional; +import java.util.concurrent.ExecutionException; + +@AllArgsConstructor +public class GeyserVelocityPingPassthrough implements IGeyserPingPassthrough { + + private static final GeyserInboundConnection FAKE_INBOUND_CONNECTION = new GeyserInboundConnection(); + + private final ProxyServer server; + + @Override + public GeyserPingInfo getPingInformation() { + ProxyPingEvent event; + try { + event = server.getEventManager().fire(new ProxyPingEvent(FAKE_INBOUND_CONNECTION, ServerPing.builder() + .description(server.getConfiguration().getMotdComponent()).onlinePlayers(server.getPlayerCount()) + .maximumPlayers(server.getConfiguration().getShowMaxPlayers()).build())).get(); + } catch (ExecutionException | InterruptedException e) { + throw new RuntimeException(e); + } + GeyserPingInfo geyserPingInfo = new GeyserPingInfo( + LegacyComponentSerializer.INSTANCE.serialize(event.getPing().getDescription(), '§'), + event.getPing().getPlayers().orElseThrow(IllegalStateException::new).getOnline(), + event.getPing().getPlayers().orElseThrow(IllegalStateException::new).getMax() + ); + event.getPing().getPlayers().get().getSample().forEach(player -> { + geyserPingInfo.addPlayer(player.getName()); + }); + return geyserPingInfo; + } + + private static class GeyserInboundConnection implements InboundConnection { + + private static final InetSocketAddress FAKE_REMOTE = new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69); + + @Override + public InetSocketAddress getRemoteAddress() { + return FAKE_REMOTE; + } + + @Override + public Optional getVirtualHost() { + return Optional.empty(); + } + + @Override + public boolean isActive() { + return false; + } + + @Override + public ProtocolVersion getProtocolVersion() { + return ProtocolVersion.MAXIMUM_VERSION; + } + } + +} diff --git a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityPlugin.java b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityPlugin.java index 9ad8ea9a..e7b44da5 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityPlugin.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityPlugin.java @@ -38,6 +38,8 @@ import org.geysermc.common.PlatformType; import org.geysermc.connector.GeyserConfiguration; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.bootstrap.GeyserBootstrap; +import org.geysermc.connector.ping.GeyserLegacyPingPassthrough; +import org.geysermc.connector.ping.IGeyserPingPassthrough; import org.geysermc.connector.utils.FileUtils; import org.geysermc.platform.velocity.command.GeyserVelocityCommandExecutor; import org.geysermc.platform.velocity.command.GeyserVelocityCommandManager; @@ -63,6 +65,7 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { private GeyserVelocityCommandManager geyserCommandManager; private GeyserVelocityConfiguration geyserConfig; private GeyserVelocityLogger geyserLogger; + private IGeyserPingPassthrough geyserPingPassthrough; private GeyserConnector connector; @@ -99,6 +102,11 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { this.geyserCommandManager = new GeyserVelocityCommandManager(connector); this.commandManager.register(new GeyserVelocityCommandExecutor(connector), "geyser"); + if (geyserConfig.isLegacyPingPassthrough()) { + this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector); + } else { + this.geyserPingPassthrough = new GeyserVelocityPingPassthrough(proxyServer); + } } @Override @@ -121,6 +129,11 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { return this.geyserCommandManager; } + @Override + public IGeyserPingPassthrough getGeyserPingPassthrough() { + return geyserPingPassthrough; + } + @Subscribe public void onInit(ProxyInitializeEvent event) { onEnable(); diff --git a/common/src/main/java/org/geysermc/common/ping/GeyserPingInfo.java b/common/src/main/java/org/geysermc/common/ping/GeyserPingInfo.java new file mode 100644 index 00000000..40ef6da6 --- /dev/null +++ b/common/src/main/java/org/geysermc/common/ping/GeyserPingInfo.java @@ -0,0 +1,48 @@ +/* + * 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.common.ping; + +import lombok.Data; +import lombok.Getter; + +import java.util.ArrayList; +import java.util.Collection; + +@Data +public class GeyserPingInfo { + + public final String motd; + public final int currentPlayerCount; + public final int maxPlayerCount; + + @Getter + private Collection players = new ArrayList<>(); + + public void addPlayer(String username) { + players.add(username); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/GeyserConfiguration.java b/connector/src/main/java/org/geysermc/connector/GeyserConfiguration.java index 34edd8e0..8a39323b 100644 --- a/connector/src/main/java/org/geysermc/connector/GeyserConfiguration.java +++ b/connector/src/main/java/org/geysermc/connector/GeyserConfiguration.java @@ -32,7 +32,7 @@ import java.util.Map; public interface GeyserConfiguration { // Modify this when you update the config - int CURRENT_CONFIG_VERSION = 2; + int CURRENT_CONFIG_VERSION = 3; IBedrockConfiguration getBedrock(); @@ -42,7 +42,13 @@ public interface GeyserConfiguration { boolean isCommandSuggestions(); - boolean isPingPassthrough(); + boolean isPassthroughMotd(); + + boolean isPassthroughPlayerCounts(); + + boolean isLegacyPingPassthrough(); + + int getPingPassthroughInterval(); int getMaxPlayers(); diff --git a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java index 75c17b29..43b10053 100644 --- a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java +++ b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java @@ -39,7 +39,6 @@ import org.geysermc.connector.network.remote.RemoteServer; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.Translators; import org.geysermc.connector.network.translators.world.WorldManager; -import org.geysermc.connector.thread.PingPassthroughThread; import org.geysermc.connector.utils.DimensionUtils; import org.geysermc.connector.utils.DockerCheck; import org.geysermc.connector.utils.Toolbox; @@ -71,7 +70,6 @@ public class GeyserConnector { private boolean shuttingDown = false; private final ScheduledExecutorService generalThreadPool; - private PingPassthroughThread passthroughThread; private BedrockServer bedrockServer; private PlatformType platformType; @@ -111,10 +109,6 @@ public class GeyserConnector { remoteServer = new RemoteServer(config.getRemote().getAddress(), config.getRemote().getPort()); authType = AuthType.getByName(config.getRemote().getAuthType()); - passthroughThread = new PingPassthroughThread(this); - if (config.isPingPassthrough()) - generalThreadPool.scheduleAtFixedRate(passthroughThread, 1, 1, TimeUnit.SECONDS); - if (config.isAboveBedrockNetherBuilding()) DimensionUtils.changeBedrockNetherId(); // Apply End dimension ID workaround to Nether diff --git a/connector/src/main/java/org/geysermc/connector/bootstrap/GeyserBootstrap.java b/connector/src/main/java/org/geysermc/connector/bootstrap/GeyserBootstrap.java index 24b338c8..24ce81cf 100644 --- a/connector/src/main/java/org/geysermc/connector/bootstrap/GeyserBootstrap.java +++ b/connector/src/main/java/org/geysermc/connector/bootstrap/GeyserBootstrap.java @@ -26,6 +26,7 @@ package org.geysermc.connector.bootstrap; +import org.geysermc.connector.ping.IGeyserPingPassthrough; import org.geysermc.connector.GeyserConfiguration; import org.geysermc.connector.GeyserLogger; import org.geysermc.connector.command.CommandManager; @@ -67,6 +68,13 @@ public interface GeyserBootstrap { */ CommandManager getGeyserCommandManager(); + /** + * Returns the current PingPassthrough manager + * + * @return The current PingPassthrough manager + */ + IGeyserPingPassthrough getGeyserPingPassthrough(); + /** * Returns the current WorldManager * diff --git a/connector/src/main/java/org/geysermc/connector/network/ConnectorServerEventHandler.java b/connector/src/main/java/org/geysermc/connector/network/ConnectorServerEventHandler.java index 8810cffb..29ba1567 100644 --- a/connector/src/main/java/org/geysermc/connector/network/ConnectorServerEventHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/ConnectorServerEventHandler.java @@ -25,11 +25,12 @@ package org.geysermc.connector.network; -import com.github.steveice10.mc.protocol.data.status.ServerStatusInfo; -import com.nukkitx.protocol.bedrock.BedrockPong; -import com.nukkitx.protocol.bedrock.BedrockServerEventHandler; -import com.nukkitx.protocol.bedrock.BedrockServerSession; - +import com.github.steveice10.mc.protocol.data.message.Message; +import com.nukkitx.protocol.bedrock.*; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.socket.DatagramPacket; +import org.geysermc.common.ping.GeyserPingInfo; +import org.geysermc.connector.ping.IGeyserPingPassthrough; import org.geysermc.connector.GeyserConfiguration; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.network.session.GeyserSession; @@ -39,7 +40,7 @@ import java.net.InetSocketAddress; public class ConnectorServerEventHandler implements BedrockServerEventHandler { - private GeyserConnector connector; + private final GeyserConnector connector; public ConnectorServerEventHandler(GeyserConnector connector) { this.connector = connector; @@ -56,29 +57,39 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler { connector.getLogger().debug(inetSocketAddress + " has pinged you!"); GeyserConfiguration config = connector.getConfig(); - ServerStatusInfo serverInfo = connector.getPassthroughThread().getInfo(); + + GeyserPingInfo pingInfo = null; + if (config.isPassthroughMotd() || config.isPassthroughPlayerCounts()) { + IGeyserPingPassthrough pingPassthrough = connector.getBootstrap().getGeyserPingPassthrough(); + pingInfo = pingPassthrough.getPingInformation(); + } BedrockPong pong = new BedrockPong(); pong.setEdition("MCPE"); pong.setGameType("Default"); pong.setNintendoLimited(false); pong.setProtocolVersion(GeyserConnector.BEDROCK_PACKET_CODEC.getProtocolVersion()); - pong.setVersion(GeyserConnector.BEDROCK_PACKET_CODEC.getMinecraftVersion()); + pong.setVersion(null); // Server tries to connect either way and it looks better pong.setIpv4Port(config.getBedrock().getPort()); - if (connector.getConfig().isPingPassthrough() && serverInfo != null) { - String[] motd = MessageUtils.getBedrockMessage(serverInfo.getDescription()).split("\n"); + + if (config.isPassthroughMotd() && pingInfo != null && pingInfo.motd != null) { + String[] motd = MessageUtils.getBedrockMessage(Message.fromString(pingInfo.motd)).split("\n"); String mainMotd = motd[0]; // First line of the motd. String subMotd = (motd.length != 1) ? motd[1] : ""; // Second line of the motd if present, otherwise blank. pong.setMotd(mainMotd.trim()); pong.setSubMotd(subMotd.trim()); // Trimmed to shift it to the left, prevents the universe from collapsing on us just because we went 2 characters over the text box's limit. - pong.setPlayerCount(serverInfo.getPlayerInfo().getOnlinePlayers()); - pong.setMaximumPlayerCount(serverInfo.getPlayerInfo().getMaxPlayers()); + } else { + pong.setMotd(config.getBedrock().getMotd1()); + pong.setSubMotd(config.getBedrock().getMotd2()); + } + + if (config.isPassthroughPlayerCounts() && pingInfo != null) { + pong.setPlayerCount(pingInfo.currentPlayerCount); + pong.setMaximumPlayerCount(pingInfo.maxPlayerCount); } else { pong.setPlayerCount(connector.getPlayers().size()); pong.setMaximumPlayerCount(config.getMaxPlayers()); - pong.setMotd(config.getBedrock().getMotd1()); - pong.setMotd(config.getBedrock().getMotd2()); } //Bedrock will not even attempt a connection if the client thinks the server is full @@ -105,4 +116,9 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler { }); bedrockServerSession.setPacketCodec(GeyserConnector.BEDROCK_PACKET_CODEC); } + + @Override + public void onUnhandledDatagram(ChannelHandlerContext ctx, DatagramPacket packet) { + new QueryPacketHandler(connector, packet.sender(), packet.content()); + } } \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/network/QueryPacketHandler.java b/connector/src/main/java/org/geysermc/connector/network/QueryPacketHandler.java new file mode 100644 index 00000000..061e0f86 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/QueryPacketHandler.java @@ -0,0 +1,268 @@ +/* + * 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; + +import com.github.steveice10.mc.protocol.data.message.Message; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import org.geysermc.common.ping.GeyserPingInfo; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.utils.MessageUtils; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; + +public class QueryPacketHandler { + + public static final byte HANDSHAKE = 0x09; + public static final byte STATISTICS = 0x00; + + private GeyserConnector connector; + private InetSocketAddress sender; + private byte type; + private int sessionId; + private byte[] token; + + /** + * The Query packet handler instance + * @param connector Geyser Connector + * @param sender The Sender IP/Port for the Query + * @param buffer The Query data + */ + public QueryPacketHandler(GeyserConnector connector, InetSocketAddress sender, ByteBuf buffer) { + if(!isQueryPacket(buffer)) + return; + + this.connector = connector; + this.sender = sender; + this.type = buffer.readByte(); + this.sessionId = buffer.readInt(); + + regenerateToken(); + handle(); + } + + /** + * Checks the packet is in fact a query packet + * @param buffer Query data + * @return if the packet is a query packet + */ + private boolean isQueryPacket(ByteBuf buffer) { + return (buffer.readableBytes() >= 2) ? buffer.readUnsignedShort() == 65277 : false; + } + + /** + * Handles the query + */ + private void handle() { + switch (type) { + case HANDSHAKE: + sendToken(); + case STATISTICS: + sendQueryData(); + } + } + + /** + * Sends the token to the sender + */ + private void sendToken() { + ByteBuf reply = ByteBufAllocator.DEFAULT.ioBuffer(10); + reply.writeByte(HANDSHAKE); + reply.writeInt(sessionId); + reply.writeBytes(getTokenString(this.token, this.sender.getAddress())); + reply.writeByte(0); + + sendPacket(reply); + } + + /** + * Sends the query data to the sender + */ + private void sendQueryData() { + ByteBuf reply = ByteBufAllocator.DEFAULT.ioBuffer(64); + reply.writeByte(STATISTICS); + reply.writeInt(sessionId); + + // Game Info + reply.writeBytes(getGameData()); + + // Players + reply.writeBytes(getPlayers()); + + sendPacket(reply); + } + + /** + * Gets the game data for the query + * @return the game data for the query + */ + private byte[] getGameData() { + ByteArrayOutputStream query = new ByteArrayOutputStream(); + + GeyserPingInfo pingInfo = null; + String motd; + String currentPlayerCount; + String maxPlayerCount; + + if (connector.getConfig().isPassthroughMotd() || connector.getConfig().isPassthroughPlayerCounts()) { + pingInfo = connector.getBootstrap().getGeyserPingPassthrough().getPingInformation(); + } + + if (connector.getConfig().isPassthroughMotd() && pingInfo != null) { + String[] javaMotd = MessageUtils.getBedrockMessage(Message.fromString(pingInfo.motd)).split("\n"); + motd = javaMotd[0].trim(); // First line of the motd. + } else { + motd = connector.getConfig().getBedrock().getMotd1(); + } + + // If passthrough player counts is enabled lets get players from the server + if (connector.getConfig().isPassthroughPlayerCounts() && pingInfo != null) { + currentPlayerCount = String.valueOf(pingInfo.currentPlayerCount); + maxPlayerCount = String.valueOf(pingInfo.maxPlayerCount); + } else { + currentPlayerCount = String.valueOf(connector.getPlayers().size()); + maxPlayerCount = String.valueOf(connector.getConfig().getMaxPlayers()); + } + + // Create a hashmap of all game data needed in the query + Map gameData = new HashMap(); + gameData.put("hostname", motd); + gameData.put("gametype", "SMP"); + gameData.put("game_id", "MINECRAFT"); + gameData.put("version", GeyserConnector.BEDROCK_PACKET_CODEC.getMinecraftVersion()); + gameData.put("plugins", ""); + gameData.put("map", GeyserConnector.NAME); + gameData.put("numplayers", currentPlayerCount); + gameData.put("maxplayers", maxPlayerCount); + gameData.put("hostport", String.valueOf(connector.getConfig().getBedrock().getPort())); + gameData.put("hostip", connector.getConfig().getBedrock().getAddress()); + + try { + // Blank Buffer Bytes + query.write("GeyserMC".getBytes()); + query.write((byte) 0x00); + query.write((byte) 128); + query.write((byte) 0x00); + + // Fills the game data + for(Map.Entry entry : gameData.entrySet()) { + query.write(entry.getKey().getBytes()); + query.write((byte) 0x00); + query.write(entry.getValue().getBytes()); + query.write((byte) 0x00); + } + + // Final byte to show the end of the game data + query.write(new byte[]{0x00, 0x01}); + return query.toByteArray(); + } catch (IOException e) { + e.printStackTrace(); + return new byte[0]; + } + } + + private byte[] getPlayers() { + ByteArrayOutputStream query = new ByteArrayOutputStream(); + + GeyserPingInfo pingInfo = null; + if (connector.getConfig().isPassthroughMotd() || connector.getConfig().isPassthroughPlayerCounts()) { + pingInfo = connector.getBootstrap().getGeyserPingPassthrough().getPingInformation(); + } + + try { + // Start the player section + query.write("player_".getBytes()); + query.write(new byte[]{0x00, 0x00}); + + // Fill player names + if(pingInfo != null) { + for (String username : pingInfo.getPlayers()) { + query.write(username.getBytes()); + query.write((byte) 0x00); + } + } + + // Final byte to show the end of the player data + query.write((byte) 0x00); + return query.toByteArray(); + } catch (IOException e) { + e.printStackTrace(); + return new byte[0]; + } + } + + /** + * Sends a packet to the sender + * @param data packet data + */ + private void sendPacket(ByteBuf data) { + connector.getBedrockServer().getRakNet().send(sender, data); + } + + /** + * Regenerates a token + */ + public void regenerateToken() { + byte[] token = new byte[16]; + for (int i = 0; i < 16; i++) { + token[i] = (byte) new Random().nextInt(255); + } + + this.token = token; + } + + /** + * Gets an MD5 token for the current IP/Port. + * This should reset every 30 seconds but a new one is generated per instance + * Seems wasteful to code something in to clear it when it has no use. + * @param token the token + * @param address the address + * @return an MD5 token for the current IP/Port + */ + public static byte[] getTokenString(byte[] token, InetAddress address) { + try { + MessageDigest digest = MessageDigest.getInstance("MD5"); + digest.update(address.toString().getBytes(StandardCharsets.UTF_8)); + digest.update(token); + return Arrays.copyOf(digest.digest(), 4); + } catch (NoSuchAlgorithmException e) { + return ByteBuffer.allocate(4).putInt(ThreadLocalRandom.current().nextInt()).array(); + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/ping/GeyserLegacyPingPassthrough.java b/connector/src/main/java/org/geysermc/connector/ping/GeyserLegacyPingPassthrough.java new file mode 100644 index 00000000..ea0d67c2 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/ping/GeyserLegacyPingPassthrough.java @@ -0,0 +1,91 @@ +/* + * 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.ping; + +import com.github.steveice10.mc.protocol.MinecraftConstants; +import com.github.steveice10.mc.protocol.MinecraftProtocol; +import com.github.steveice10.mc.protocol.data.SubProtocol; +import com.github.steveice10.mc.protocol.data.status.handler.ServerInfoHandler; +import com.github.steveice10.packetlib.Client; +import com.github.steveice10.packetlib.tcp.TcpSessionFactory; +import org.geysermc.common.ping.GeyserPingInfo; +import org.geysermc.connector.GeyserConfiguration; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.GeyserLogger; + +import java.util.concurrent.TimeUnit; + +public class GeyserLegacyPingPassthrough implements IGeyserPingPassthrough, Runnable { + + private GeyserConnector connector; + + public GeyserLegacyPingPassthrough(GeyserConnector connector) { + this.connector = connector; + this.pingInfo = new GeyserPingInfo(null, 0, 0); + } + + private GeyserPingInfo pingInfo; + + private Client client; + + /** + * Start legacy ping passthrough thread + * @param connector GeyserConnector + * @return GeyserPingPassthrough, or null if not initialized + */ + public static IGeyserPingPassthrough init(GeyserConnector connector) { + if (connector.getConfig().isPassthroughMotd() || connector.getConfig().isPassthroughPlayerCounts()) { + GeyserLegacyPingPassthrough pingPassthrough = new GeyserLegacyPingPassthrough(connector); + // Ensure delay is not zero + int interval = (connector.getConfig().getPingPassthroughInterval() == 0) ? 1 : connector.getConfig().getPingPassthroughInterval(); + connector.getLogger().debug("Scheduling ping passthrough at an interval of " + interval + " second(s)."); + connector.getGeneralThreadPool().scheduleAtFixedRate(pingPassthrough, 1, interval, TimeUnit.SECONDS); + return pingPassthrough; + } + return null; + } + + @Override + public GeyserPingInfo getPingInformation() { + return pingInfo; + } + + @Override + public void run() { + try { + this.client = new Client(connector.getConfig().getRemote().getAddress(), connector.getConfig().getRemote().getPort(), new MinecraftProtocol(SubProtocol.STATUS), new TcpSessionFactory()); + this.client.getSession().setFlag(MinecraftConstants.SERVER_INFO_HANDLER_KEY, (ServerInfoHandler) (session, info) -> { + this.pingInfo = new GeyserPingInfo(info.getDescription().getFullText(), info.getPlayerInfo().getOnlinePlayers(), info.getPlayerInfo().getMaxPlayers()); + this.client.getSession().disconnect(null); + }); + + client.getSession().connect(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/ping/IGeyserPingPassthrough.java b/connector/src/main/java/org/geysermc/connector/ping/IGeyserPingPassthrough.java new file mode 100644 index 00000000..7bc842df --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/ping/IGeyserPingPassthrough.java @@ -0,0 +1,42 @@ +/* + * 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.ping; + +import org.geysermc.common.ping.GeyserPingInfo; + +/** + * Interface that retrieves ping passthrough information from the Java server + */ +public interface IGeyserPingPassthrough { + + /** + * Get the MOTD of the server displayed on the multiplayer screen + * @return string of the MOTD + */ + GeyserPingInfo getPingInformation(); + +} diff --git a/connector/src/main/java/org/geysermc/connector/thread/PingPassthroughThread.java b/connector/src/main/java/org/geysermc/connector/thread/PingPassthroughThread.java deleted file mode 100644 index fa87809b..00000000 --- a/connector/src/main/java/org/geysermc/connector/thread/PingPassthroughThread.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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.thread; - -import com.github.steveice10.mc.protocol.MinecraftConstants; -import com.github.steveice10.mc.protocol.MinecraftProtocol; -import com.github.steveice10.mc.protocol.data.SubProtocol; -import com.github.steveice10.mc.protocol.data.status.ServerStatusInfo; -import com.github.steveice10.mc.protocol.data.status.handler.ServerInfoHandler; -import com.github.steveice10.packetlib.Client; -import com.github.steveice10.packetlib.tcp.TcpSessionFactory; -import lombok.Getter; -import org.geysermc.connector.GeyserConnector; - -public class PingPassthroughThread implements Runnable { - - private GeyserConnector connector; - - public PingPassthroughThread(GeyserConnector connector) { - this.connector = connector; - } - - @Getter - private ServerStatusInfo info; - - private Client client; - - @Override - public void run() { - try { - this.client = new Client(connector.getConfig().getRemote().getAddress(), connector.getConfig().getRemote().getPort(), new MinecraftProtocol(SubProtocol.STATUS), new TcpSessionFactory()); - this.client.getSession().setFlag(MinecraftConstants.SERVER_INFO_HANDLER_KEY, (ServerInfoHandler) (session, info) -> { - this.info = info; - this.client.getSession().disconnect(null); - }); - - client.getSession().connect(); - } catch (Exception ex) { - ex.printStackTrace(); - } - } -} diff --git a/connector/src/main/resources/config.yml b/connector/src/main/resources/config.yml index d12b7648..931e0a8d 100644 --- a/connector/src/main/resources/config.yml +++ b/connector/src/main/resources/config.yml @@ -12,7 +12,7 @@ bedrock: address: 0.0.0.0 # The port that will listen for connections port: 19132 - # The MOTD that will be broadcasted to Minecraft: Bedrock Edition clients + # The MOTD that will be broadcasted to Minecraft: Bedrock Edition clients. Irrelevant if "passthrough-motd" is set to true motd1: "GeyserMC" motd2: "Another GeyserMC forced host." remote: @@ -45,8 +45,17 @@ floodgate-key-file: public-key.pem # Disabling this will prevent command suggestions from being sent and solve freezing for Bedrock clients. command-suggestions: true -# Relay the MOTD, player count and max players from the remote server -ping-passthrough: false +# The following two options enable "ping passthrough" - the MOTD and/or player count gets retrieved from the Java server. +# Relay the MOTD from the remote server to Bedrock players. +passthrough-motd: false +# Relay the player count and max players from the remote server to Bedrock players. +passthrough-player-counts: false +# Enable LEGACY ping passthrough. There is no need to enable this unless your MOTD or player count does not appear properly. +# This option does nothing on standalone. +legacy-ping-passthrough: false +# How often to ping the remote server, in seconds. Only relevant for standalone or legacy ping passthrough. +# Increase if you are getting BrokenPipe errors. +ping-passthrough-interval: 3 # Maximum amount of players that can connect max-players: 100 @@ -94,4 +103,4 @@ metrics: uuid: generateduuid # DO NOT TOUCH! -config-version: 1 +config-version: 3 diff --git a/connector/src/main/resources/mappings b/connector/src/main/resources/mappings index a67cc940..a7963d0a 160000 --- a/connector/src/main/resources/mappings +++ b/connector/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit a67cc940c0d47874c833ffeb58f38e33eabfcc33 +Subproject commit a7963d0a0236b1c47eea21718ac50706139d90cc From 0574feb87e23784b4cd771ae0ff4d52972d5af3c Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sat, 23 May 2020 18:26:20 -0500 Subject: [PATCH 35/73] Fix block breaking animations when in water (Closes #494) --- .../connector/entity/PlayerEntity.java | 5 +++ .../bedrock/BedrockMovePlayerTranslator.java | 1 + .../player/JavaPlayerActionAckTranslator.java | 2 +- .../translators/world/WorldManager.java | 24 +++++++++++ .../geysermc/connector/utils/BlockUtils.java | 41 +++++++++++-------- 5 files changed, 56 insertions(+), 17 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java index 5db3fdec..aa7848da 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java @@ -57,6 +57,7 @@ public class PlayerEntity extends LivingEntity { private String username; private long lastSkinUpdate = -1; private boolean playerList = true; + private boolean onGround; private final EntityEffectCache effectCache; private Entity leftParrot; @@ -143,6 +144,8 @@ public class PlayerEntity extends LivingEntity { setPosition(position); setRotation(rotation); + this.onGround = isOnGround; + MovePlayerPacket movePlayerPacket = new MovePlayerPacket(); movePlayerPacket.setRuntimeEntityId(geyserId); movePlayerPacket.setPosition(this.position); @@ -168,6 +171,8 @@ public class PlayerEntity extends LivingEntity { setRotation(rotation); this.position = Vector3f.from(position.getX() + relX, position.getY() + relY, position.getZ() + relZ); + this.onGround = isOnGround; + MovePlayerPacket movePlayerPacket = new MovePlayerPacket(); movePlayerPacket.setRuntimeEntityId(geyserId); movePlayerPacket.setPosition(position); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMovePlayerTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMovePlayerTranslator.java index d61461cc..14d597fd 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMovePlayerTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMovePlayerTranslator.java @@ -85,6 +85,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator l >= 1).orElse(false); - //boolean outOfWaterButNotOnGround = (!player.isInsideOfWater()) && (!player.isOnGround()); - return calculateBreakTime(blockHardness, toolTier, canHarvestWithHand, correctTool, toolType, isWoolBlock, isCobweb, toolEfficiencyLevel, hasteLevel, miningFatigueLevel); + + hasteLevel = session.getPlayerEntity().getEffectCache().getEffectLevel(Effect.FASTER_DIG); + miningFatigueLevel = session.getPlayerEntity().getEffectCache().getEffectLevel(Effect.SLOWER_DIG); + + boolean isInWater = session.getConnector().getConfig().isCacheChunks() + && BlockTranslator.getBedrockBlockId(session.getConnector().getWorldManager().getBlockAt(session, session.getPlayerEntity().getPosition().toInt())) == BlockTranslator.BEDROCK_WATER_ID; + + boolean insideOfWaterWithoutAquaAffinity = isInWater && + ItemUtils.getEnchantmentLevel(Optional.ofNullable(session.getInventory().getItem(5)).map(ItemStack::getNbt).orElse(null), "minecraft:aqua_affinity") < 1; + + boolean outOfWaterButNotOnGround = (!isInWater) && (!session.getPlayerEntity().isOnGround()); + boolean insideWaterNotOnGround = isInWater && !session.getPlayerEntity().isOnGround(); + return calculateBreakTime(blockHardness, toolTier, canHarvestWithHand, correctTool, toolType, isWoolBlock, isCobweb, toolEfficiencyLevel, hasteLevel, miningFatigueLevel, insideOfWaterWithoutAquaAffinity, outOfWaterButNotOnGround, insideWaterNotOnGround); } } From a49f6fe0e372d754ebc6f80cb1fbb923ff0cb968 Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sat, 23 May 2020 18:58:36 -0500 Subject: [PATCH 36/73] Specify API version for Bukkit to stop legacy material loading (Closes #595) --- bootstrap/bukkit/src/main/resources/plugin.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/bootstrap/bukkit/src/main/resources/plugin.yml b/bootstrap/bukkit/src/main/resources/plugin.yml index 7e32f0e1..89c90789 100644 --- a/bootstrap/bukkit/src/main/resources/plugin.yml +++ b/bootstrap/bukkit/src/main/resources/plugin.yml @@ -4,6 +4,7 @@ author: ${project.organization.name} website: ${project.organization.url} version: ${project.version} softdepend: ["ViaVersion"] +api-version: 1.13 commands: geyser: description: The main command for Geyser. From fe6257bb38c417c78dea9d2e1b229c32443c7b70 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Sat, 23 May 2020 21:16:11 -0400 Subject: [PATCH 37/73] Check if firework item explosions tag is null (#626) --- .../translators/nbt/FireworkTranslator.java | 66 ++++++++++--------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkTranslator.java index 77e14e5a..849df3a4 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkTranslator.java @@ -39,49 +39,51 @@ public class FireworkTranslator extends NbtItemStackTranslator { CompoundTag fireworks = itemTag.get("Fireworks"); ListTag explosions = fireworks.get("Explosions"); - for (Tag effect : explosions.getValue()) { - CompoundTag effectData = (CompoundTag) effect; + if (explosions != null) { + for (Tag effect : explosions.getValue()) { + CompoundTag effectData = (CompoundTag) effect; - CompoundTag newEffectData = new CompoundTag(""); + CompoundTag newEffectData = new CompoundTag(""); - if (effectData.get("Type") != null) { - newEffectData.put(new ByteTag("FireworkType", (Byte) effectData.get("Type").getValue())); - } - - if (effectData.get("Colors") != null) { - int[] oldColors = (int[]) effectData.get("Colors").getValue(); - byte[] colors = new byte[oldColors.length]; - - int i = 0; - for (int color : oldColors) { - colors[i++] = FireworkColor.fromJavaID(color).getBedrockID(); + if (effectData.get("Type") != null) { + newEffectData.put(new ByteTag("FireworkType", (Byte) effectData.get("Type").getValue())); } - newEffectData.put(new ByteArrayTag("FireworkColor", colors)); - } + if (effectData.get("Colors") != null) { + int[] oldColors = (int[]) effectData.get("Colors").getValue(); + byte[] colors = new byte[oldColors.length]; - if (effectData.get("FadeColors") != null) { - int[] oldColors = (int[]) effectData.get("FadeColors").getValue(); - byte[] colors = new byte[oldColors.length]; + int i = 0; + for (int color : oldColors) { + colors[i++] = FireworkColor.fromJavaID(color).getBedrockID(); + } - int i = 0; - for (int color : oldColors) { - colors[i++] = FireworkColor.fromJavaID(color).getBedrockID(); + newEffectData.put(new ByteArrayTag("FireworkColor", colors)); } - newEffectData.put(new ByteArrayTag("FireworkFade", colors)); - } + if (effectData.get("FadeColors") != null) { + int[] oldColors = (int[]) effectData.get("FadeColors").getValue(); + byte[] colors = new byte[oldColors.length]; - if (effectData.get("Trail") != null) { - newEffectData.put(new ByteTag("FireworkTrail", (Byte) effectData.get("Trail").getValue())); - } + int i = 0; + for (int color : oldColors) { + colors[i++] = FireworkColor.fromJavaID(color).getBedrockID(); + } - if (effectData.get("Flicker") != null) { - newEffectData.put(new ByteTag("FireworkFlicker", (Byte) effectData.get("Flicker").getValue())); - } + newEffectData.put(new ByteArrayTag("FireworkFade", colors)); + } - explosions.remove(effect); - explosions.add(newEffectData); + if (effectData.get("Trail") != null) { + newEffectData.put(new ByteTag("FireworkTrail", (Byte) effectData.get("Trail").getValue())); + } + + if (effectData.get("Flicker") != null) { + newEffectData.put(new ByteTag("FireworkFlicker", (Byte) effectData.get("Flicker").getValue())); + } + + explosions.remove(effect); + explosions.add(newEffectData); + } } } From 681cbeeae5d47bd37e72c067deb546cb858bf539 Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sat, 23 May 2020 22:45:34 -0500 Subject: [PATCH 38/73] Add armor stand entity offset (Fixes #627) --- .../java/entity/JavaEntitySetPassengersTranslator.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntitySetPassengersTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntitySetPassengersTranslator.java index 0ec79bc0..ad0d0f9e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntitySetPassengersTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntitySetPassengersTranslator.java @@ -137,6 +137,9 @@ public class JavaEntitySetPassengersTranslator extends PacketTranslator Date: Sat, 23 May 2020 23:14:29 -0500 Subject: [PATCH 39/73] Don't delay item frame interactions Causes interacting (moving) an item in an item frame to delay by about half a second. This delay is still present on chunk load where this delay is absolutely needed in order to the item frame to show up. --- .../connector/entity/ItemFrameEntity.java | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java b/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java index f100704f..5954e77e 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java @@ -87,9 +87,12 @@ public class ItemFrameEntity extends Entity { @Override public void spawnEntity(GeyserSession session) { session.getItemFrameCache().put(bedrockPosition, entityId); - updateBlock(session); + // Delay is required, or else loading in frames on chunk load is sketchy at best + session.getConnector().getGeneralThreadPool().schedule(() -> { + updateBlock(session); + session.getConnector().getLogger().debug("Spawned item frame at location " + bedrockPosition + " with java id " + entityId); + }, 500, TimeUnit.MILLISECONDS); valid = true; - session.getConnector().getLogger().debug("Spawned item frame at location " + bedrockPosition + " with java id " + entityId); } @Override @@ -170,27 +173,24 @@ public class ItemFrameEntity extends Entity { * @param session GeyserSession. */ public void updateBlock(GeyserSession session) { - // Delay is required, or else loading in frames on chunk load is sketchy at best - session.getConnector().getGeneralThreadPool().schedule(() -> { - UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); - updateBlockPacket.setDataLayer(0); - updateBlockPacket.setBlockPosition(bedrockPosition); - updateBlockPacket.setRuntimeId(bedrockRuntimeId); - updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); - updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NONE); - updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS); - session.sendUpstreamPacket(updateBlockPacket); + UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); + updateBlockPacket.setDataLayer(0); + updateBlockPacket.setBlockPosition(bedrockPosition); + updateBlockPacket.setRuntimeId(bedrockRuntimeId); + updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); + updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NONE); + updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS); + session.sendUpstreamPacket(updateBlockPacket); - BlockEntityDataPacket blockEntityDataPacket = new BlockEntityDataPacket(); - blockEntityDataPacket.setBlockPosition(bedrockPosition); - if (cachedTag != null) { - blockEntityDataPacket.setData(cachedTag); - } else { - blockEntityDataPacket.setData(getDefaultTag()); - } + BlockEntityDataPacket blockEntityDataPacket = new BlockEntityDataPacket(); + blockEntityDataPacket.setBlockPosition(bedrockPosition); + if (cachedTag != null) { + blockEntityDataPacket.setData(cachedTag); + } else { + blockEntityDataPacket.setData(getDefaultTag()); + } - session.sendUpstreamPacket(blockEntityDataPacket); - }, 500, TimeUnit.MILLISECONDS); + session.sendUpstreamPacket(blockEntityDataPacket); } /** From 7f5414cdef44e5a9587a636d76ab9bb7c1265dfd Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sat, 23 May 2020 23:27:16 -0500 Subject: [PATCH 40/73] Fix painting offset if height is equal to 3 (Fixes #629) --- .../main/java/org/geysermc/connector/entity/PaintingEntity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connector/src/main/java/org/geysermc/connector/entity/PaintingEntity.java b/connector/src/main/java/org/geysermc/connector/entity/PaintingEntity.java index 56e07733..1711fd38 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/PaintingEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/PaintingEntity.java @@ -67,7 +67,7 @@ public class PaintingEntity extends Entity { Vector3f position = super.position; position = position.add(0.5, 0.5, 0.5); double widthOffset = paintingName.getWidth() > 1 ? 0.5 : 0; - double heightOffset = paintingName.getHeight() > 1 ? 0.5 : 0; + double heightOffset = paintingName.getHeight() > 1 && paintingName.getHeight() != 3 ? 0.5 : 0; switch (direction) { case 0: return position.add(widthOffset, heightOffset, OFFSET); From 3d0dbff87b002a2a7409cb771ddc07c8e880f070 Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sat, 23 May 2020 23:45:39 -0500 Subject: [PATCH 41/73] Remove effects on world/server change (Fixes #467) The server re-sends these effects upon joining the new world or server. --- .../org/geysermc/connector/utils/DimensionUtils.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java b/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java index bc7745ca..6c8d9f94 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java @@ -25,6 +25,7 @@ package org.geysermc.connector.utils; +import com.github.steveice10.mc.protocol.data.game.entity.Effect; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.packet.*; import org.geysermc.connector.entity.Entity; @@ -59,6 +60,16 @@ public class DimensionUtils { session.setSpawned(false); session.setLastChunkPosition(null); + for (Effect effect : session.getPlayerEntity().getEffectCache().getEntityEffects().keySet()) { + MobEffectPacket mobEffectPacket = new MobEffectPacket(); + mobEffectPacket.setEvent(MobEffectPacket.Event.REMOVE); + mobEffectPacket.setRuntimeEntityId(session.getPlayerEntity().getGeyserId()); + mobEffectPacket.setEffectId(EntityUtils.toBedrockEffectId(effect)); + session.sendUpstreamPacket(mobEffectPacket); + } + // Effects are re-sent from server + session.getPlayerEntity().getEffectCache().getEntityEffects().clear(); + //let java server handle portal travel sound StopSoundPacket stopSoundPacket = new StopSoundPacket(); stopSoundPacket.setStoppingAllSound(true); From 259be966529a3a5f4eb09a61b624257039b0a251 Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sun, 24 May 2020 12:51:56 -0500 Subject: [PATCH 42/73] Update mappings submodule (Fixes #630) --- connector/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connector/src/main/resources/mappings b/connector/src/main/resources/mappings index a7963d0a..a67cc940 160000 --- a/connector/src/main/resources/mappings +++ b/connector/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit a7963d0a0236b1c47eea21718ac50706139d90cc +Subproject commit a67cc940c0d47874c833ffeb58f38e33eabfcc33 From 286970676bc0b13d8363b61d42f4774dd723b072 Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sun, 24 May 2020 13:06:25 -0500 Subject: [PATCH 43/73] Add null check for shield code (Fixes #644) --- .../bedrock/BedrockInventoryTransactionTranslator.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 e4e654f0..03f7a112 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 @@ -25,6 +25,7 @@ package org.geysermc.connector.network.translators.bedrock; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; @@ -134,7 +135,8 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator Date: Sun, 24 May 2020 14:15:02 -0400 Subject: [PATCH 44/73] Check if firework item explosions tag is null (corresponding entity fix) (#633) * Check if firework item explosions tag is null (corresponding entity fix) * Add null check on flight * Add null check around Flight * Fix newline on if statement * Fix newline on if statement, add null check on flight, remove debug code. * fix missing space.. --- .../connector/entity/FireworkEntity.java | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java b/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java index a074a53c..55d9c790 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java @@ -60,54 +60,54 @@ public class FireworkEntity extends Entity { CompoundTag fireworks = tag.get("Fireworks"); CompoundTagBuilder fireworksBuilder = CompoundTagBuilder.builder(); - fireworksBuilder.byteTag("Flight", (Byte) fireworks.get("Flight").getValue()); + if (fireworks.get("Flight") != null) { + fireworksBuilder.byteTag("Flight", (Byte) fireworks.get("Flight").getValue()); + } List explosions = new ArrayList<>(); - for (Tag effect : ((ListTag) fireworks.get("Explosions")).getValue()) { - CompoundTag effectData = (CompoundTag) effect; + if (fireworks.get("Explosions") != null) { + for (Tag effect : ((ListTag) fireworks.get("Explosions")).getValue()) { + CompoundTag effectData = (CompoundTag) effect; + CompoundTagBuilder effectBuilder = CompoundTagBuilder.builder(); - try { - GeyserConnector.getInstance().getLogger().debug("Effect: " + new ObjectMapper().writeValueAsString(effect)); - } catch (JsonProcessingException e) { } - - CompoundTagBuilder effectBuilder = CompoundTagBuilder.builder(); - if (effectData.get("Type") != null) { - effectBuilder.byteTag("FireworkType", (Byte) effectData.get("Type").getValue()); - } - - if (effectData.get("Colors") != null) { - int[] oldColors = (int[]) effectData.get("Colors").getValue(); - byte[] colors = new byte[oldColors.length]; - - int i = 0; - for (int color : oldColors) { - colors[i++] = FireworkColor.fromJavaID(color).getBedrockID(); + if (effectData.get("Type") != null) { + effectBuilder.byteTag("FireworkType", (Byte) effectData.get("Type").getValue()); } - effectBuilder.byteArrayTag("FireworkColor", colors); - } + if (effectData.get("Colors") != null) { + int[] oldColors = (int[]) effectData.get("Colors").getValue(); + byte[] colors = new byte[oldColors.length]; - if (effectData.get("FadeColors") != null) { - int[] oldColors = (int[]) effectData.get("FadeColors").getValue(); - byte[] colors = new byte[oldColors.length]; + int i = 0; + for (int color : oldColors) { + colors[i++] = FireworkColor.fromJavaID(color).getBedrockID(); + } - int i = 0; - for (int color : oldColors) { - colors[i++] = FireworkColor.fromJavaID(color).getBedrockID(); + effectBuilder.byteArrayTag("FireworkColor", colors); } - effectBuilder.byteArrayTag("FireworkFade", colors); - } + if (effectData.get("FadeColors") != null) { + int[] oldColors = (int[]) effectData.get("FadeColors").getValue(); + byte[] colors = new byte[oldColors.length]; - if (effectData.get("Trail") != null) { - effectBuilder.byteTag("FireworkTrail", (Byte) effectData.get("Trail").getValue()); - } + int i = 0; + for (int color : oldColors) { + colors[i++] = FireworkColor.fromJavaID(color).getBedrockID(); + } - if (effectData.get("Flicker") != null) { - effectBuilder.byteTag("FireworkFlicker", (Byte) effectData.get("Flicker").getValue()); - } + effectBuilder.byteArrayTag("FireworkFade", colors); + } - explosions.add(effectBuilder.buildRootTag()); + if (effectData.get("Trail") != null) { + effectBuilder.byteTag("FireworkTrail", (Byte) effectData.get("Trail").getValue()); + } + + if (effectData.get("Flicker") != null) { + effectBuilder.byteTag("FireworkFlicker", (Byte) effectData.get("Flicker").getValue()); + } + + explosions.add(effectBuilder.buildRootTag()); + } } fireworksBuilder.tag(new com.nukkitx.nbt.tag.ListTag<>("Explosions", com.nukkitx.nbt.tag.CompoundTag.class, explosions)); From 6dabc22d22b6deb4db633026b1f9e06b44351a92 Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sun, 24 May 2020 13:20:19 -0500 Subject: [PATCH 45/73] Add null check for fireworks tag (Closes #636) --- .../translators/nbt/FireworkTranslator.java | 90 ++++++++++--------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkTranslator.java index 849df3a4..573e520e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkTranslator.java @@ -36,54 +36,58 @@ public class FireworkTranslator extends NbtItemStackTranslator { @Override public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) { + if (!itemTag.contains("Fireworks")) { + return; + } + CompoundTag fireworks = itemTag.get("Fireworks"); - ListTag explosions = fireworks.get("Explosions"); - if (explosions != null) { - for (Tag effect : explosions.getValue()) { - CompoundTag effectData = (CompoundTag) effect; + if (explosions == null) { + return; + } + for (Tag effect : explosions.getValue()) { + CompoundTag effectData = (CompoundTag) effect; - CompoundTag newEffectData = new CompoundTag(""); + CompoundTag newEffectData = new CompoundTag(""); - if (effectData.get("Type") != null) { - newEffectData.put(new ByteTag("FireworkType", (Byte) effectData.get("Type").getValue())); - } - - if (effectData.get("Colors") != null) { - int[] oldColors = (int[]) effectData.get("Colors").getValue(); - byte[] colors = new byte[oldColors.length]; - - int i = 0; - for (int color : oldColors) { - colors[i++] = FireworkColor.fromJavaID(color).getBedrockID(); - } - - newEffectData.put(new ByteArrayTag("FireworkColor", colors)); - } - - if (effectData.get("FadeColors") != null) { - int[] oldColors = (int[]) effectData.get("FadeColors").getValue(); - byte[] colors = new byte[oldColors.length]; - - int i = 0; - for (int color : oldColors) { - colors[i++] = FireworkColor.fromJavaID(color).getBedrockID(); - } - - newEffectData.put(new ByteArrayTag("FireworkFade", colors)); - } - - if (effectData.get("Trail") != null) { - newEffectData.put(new ByteTag("FireworkTrail", (Byte) effectData.get("Trail").getValue())); - } - - if (effectData.get("Flicker") != null) { - newEffectData.put(new ByteTag("FireworkFlicker", (Byte) effectData.get("Flicker").getValue())); - } - - explosions.remove(effect); - explosions.add(newEffectData); + if (effectData.get("Type") != null) { + newEffectData.put(new ByteTag("FireworkType", (Byte) effectData.get("Type").getValue())); } + + if (effectData.get("Colors") != null) { + int[] oldColors = (int[]) effectData.get("Colors").getValue(); + byte[] colors = new byte[oldColors.length]; + + int i = 0; + for (int color : oldColors) { + colors[i++] = FireworkColor.fromJavaID(color).getBedrockID(); + } + + newEffectData.put(new ByteArrayTag("FireworkColor", colors)); + } + + if (effectData.get("FadeColors") != null) { + int[] oldColors = (int[]) effectData.get("FadeColors").getValue(); + byte[] colors = new byte[oldColors.length]; + + int i = 0; + for (int color : oldColors) { + colors[i++] = FireworkColor.fromJavaID(color).getBedrockID(); + } + + newEffectData.put(new ByteArrayTag("FireworkFade", colors)); + } + + if (effectData.get("Trail") != null) { + newEffectData.put(new ByteTag("FireworkTrail", (Byte) effectData.get("Trail").getValue())); + } + + if (effectData.get("Flicker") != null) { + newEffectData.put(new ByteTag("FireworkFlicker", (Byte) effectData.get("Flicker").getValue())); + } + + explosions.remove(effect); + explosions.add(newEffectData); } } From 56d84c24d3df95b7c1db26c71f31fca505a1cab6 Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sun, 24 May 2020 14:21:06 -0500 Subject: [PATCH 46/73] Reduce nesting in item nbt translators --- .../translators/nbt/BasicItemTranslator.java | 66 ++++++++------- .../translators/nbt/BookPagesTranslator.java | 66 ++++++++------- .../nbt/EnchantedBookTranslator.java | 30 +++---- .../nbt/EnchantmentTranslator.java | 84 ++++++++++--------- .../nbt/LeatherArmorTranslator.java | 34 ++++---- 5 files changed, 145 insertions(+), 135 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BasicItemTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BasicItemTranslator.java index 9458ec4f..418f97da 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BasicItemTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BasicItemTranslator.java @@ -46,49 +46,51 @@ public class BasicItemTranslator extends NbtItemStackTranslator { @Override public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) { - if (itemTag.contains("display")) { - CompoundTag displayTag = itemTag.get("display"); - if (displayTag.contains("Name")) { - StringTag nameTag = displayTag.get("Name"); + if (!itemTag.contains("display")) { + return; + } + CompoundTag displayTag = itemTag.get("display"); + if (displayTag.contains("Name")) { + StringTag nameTag = displayTag.get("Name"); + try { + displayTag.put(new StringTag("Name", toBedrockMessage(nameTag))); + } catch (Exception ex) { + } + } + + if (displayTag.contains("Lore")) { + ListTag loreTag = displayTag.get("Lore"); + List lore = new ArrayList<>(); + for (Tag tag : loreTag.getValue()) { + if (!(tag instanceof StringTag)) return; try { - displayTag.put(new StringTag("Name", toBedrockMessage(nameTag))); + lore.add(new StringTag("", toBedrockMessage((StringTag) tag))); } catch (Exception ex) { } } - - if (displayTag.contains("Lore")) { - ListTag loreTag = displayTag.get("Lore"); - List lore = new ArrayList<>(); - for (Tag tag : loreTag.getValue()) { - if (!(tag instanceof StringTag)) return; - try { - lore.add(new StringTag("", toBedrockMessage((StringTag) tag))); - } catch (Exception ex) { - } - } - displayTag.put(new ListTag("Lore", lore)); - } + displayTag.put(new ListTag("Lore", lore)); } } @Override public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) { - if (itemTag.contains("display")) { - CompoundTag displayTag = itemTag.get("display"); - if (displayTag.contains("Name")) { - StringTag nameTag = displayTag.get("Name"); - displayTag.put(new StringTag("Name", toJavaMessage(nameTag))); - } + if (!itemTag.contains("display")) { + return; + } + CompoundTag displayTag = itemTag.get("display"); + if (displayTag.contains("Name")) { + StringTag nameTag = displayTag.get("Name"); + displayTag.put(new StringTag("Name", toJavaMessage(nameTag))); + } - if (displayTag.contains("Lore")) { - ListTag loreTag = displayTag.get("Lore"); - List lore = new ArrayList<>(); - for (Tag tag : loreTag.getValue()) { - if (!(tag instanceof StringTag)) return; - lore.add(new StringTag("", "§r" + toJavaMessage((StringTag) tag))); - } - displayTag.put(new ListTag("Lore", lore)); + if (displayTag.contains("Lore")) { + ListTag loreTag = displayTag.get("Lore"); + List lore = new ArrayList<>(); + for (Tag tag : loreTag.getValue()) { + if (!(tag instanceof StringTag)) return; + lore.add(new StringTag("", "§r" + toJavaMessage((StringTag) tag))); } + displayTag.put(new ListTag("Lore", lore)); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BookPagesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BookPagesTranslator.java index f29f16fe..d9c48a19 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BookPagesTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BookPagesTranslator.java @@ -42,43 +42,45 @@ public class BookPagesTranslator extends NbtItemStackTranslator { @Override public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) { - if (itemTag.contains("pages")) { - List pages = new ArrayList<>(); - ListTag pagesTag = itemTag.get("pages"); - for (Tag tag : pagesTag.getValue()) { - if (!(tag instanceof StringTag)) - continue; - - StringTag textTag = (StringTag) tag; - - CompoundTag pageTag = new CompoundTag(""); - pageTag.put(new StringTag("photoname", "")); - pageTag.put(new StringTag("text", MessageUtils.getBedrockMessage(textTag.getValue()))); - pages.add(pageTag); - } - - itemTag.remove("pages"); - itemTag.put(new ListTag("pages", pages)); + if (!itemTag.contains("pages")) { + return; } + List pages = new ArrayList<>(); + ListTag pagesTag = itemTag.get("pages"); + for (Tag tag : pagesTag.getValue()) { + if (!(tag instanceof StringTag)) + continue; + + StringTag textTag = (StringTag) tag; + + CompoundTag pageTag = new CompoundTag(""); + pageTag.put(new StringTag("photoname", "")); + pageTag.put(new StringTag("text", MessageUtils.getBedrockMessage(textTag.getValue()))); + pages.add(pageTag); + } + + itemTag.remove("pages"); + itemTag.put(new ListTag("pages", pages)); } @Override public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) { - if (itemTag.contains("pages")) { - List pages = new ArrayList<>(); - ListTag pagesTag = itemTag.get("pages"); - for (Tag tag : pagesTag.getValue()) { - if (!(tag instanceof CompoundTag)) - continue; - - CompoundTag pageTag = (CompoundTag) tag; - - StringTag textTag = pageTag.get("text"); - pages.add(new StringTag(MessageUtils.getJavaMessage(textTag.getValue()))); - } - - itemTag.remove("pages"); - itemTag.put(new ListTag("pages", pages)); + if (!itemTag.contains("pages")) { + return; } + List pages = new ArrayList<>(); + ListTag pagesTag = itemTag.get("pages"); + for (Tag tag : pagesTag.getValue()) { + if (!(tag instanceof CompoundTag)) + continue; + + CompoundTag pageTag = (CompoundTag) tag; + + StringTag textTag = pageTag.get("text"); + pages.add(new StringTag(MessageUtils.getJavaMessage(textTag.getValue()))); + } + + itemTag.remove("pages"); + itemTag.put(new ListTag("pages", pages)); } } 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 index 2ca6e35c..38df1ee3 100644 --- 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 @@ -37,25 +37,27 @@ 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); - } + if (!itemTag.contains("StoredEnchantments")) { + return; + } + 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); - } + if (!itemTag.contains("Enchantments")) { + return; + } + Tag enchTag = itemTag.get("Enchantments"); + if (enchTag instanceof ListTag) { + enchTag = new ListTag("StoredEnchantments", ((ListTag) enchTag).getValue()); + itemTag.remove("Enchantments"); + itemTag.put(enchTag); } } 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 index 41e1ae36..5dbb926c 100644 --- 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 @@ -73,48 +73,50 @@ public class EnchantmentTranslator extends NbtItemStackTranslator { @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"); + if (!itemTag.contains("ench")) { + return; } + + 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"); } 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 index 4b01d912..5b283ef5 100644 --- 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 @@ -38,29 +38,31 @@ public class LeatherArmorTranslator extends NbtItemStackTranslator { @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"); - } + if (!itemTag.contains("display")) { + return; + } + 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"); + if (!itemTag.contains("customColor")) { + return; } + IntTag color = itemTag.get("customColor"); + CompoundTag displayTag = itemTag.get("display"); + if (displayTag == null) { + displayTag = new CompoundTag("display"); + } + displayTag.put(color); + itemTag.remove("customColor"); } @Override From 0215220ac1dbfaf39fc504280896aaecec7c09e9 Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sun, 24 May 2020 14:46:36 -0500 Subject: [PATCH 47/73] Fix spectator mode --- .../world/JavaNotifyClientTranslator.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java index de1066c0..781018b2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java @@ -42,6 +42,7 @@ import org.geysermc.connector.network.translators.inventory.PlayerInventoryTrans import java.util.Set; import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; @Translator(packet = ServerNotifyClientPacket.class) public class JavaNotifyClientTranslator extends PacketTranslator { @@ -80,6 +81,7 @@ public class JavaNotifyClientTranslator extends PacketTranslator { + AdventureSettingsPacket adventureSettingsPacket = new AdventureSettingsPacket(); + adventureSettingsPacket.setPlayerPermission(PlayerPermission.MEMBER); + adventureSettingsPacket.setCommandPermission(CommandPermission.NORMAL); + adventureSettingsPacket.setUniqueEntityId(entity.getGeyserId()); + adventureSettingsPacket.getFlags().addAll(playerFlags); + session.sendUpstreamPacket(adventureSettingsPacket); + }, 50, TimeUnit.MILLISECONDS); EntityDataMap metadata = entity.getMetadata(); - metadata.getFlags().setFlag(EntityFlag.CAN_FLY, gameMode == GameMode.CREATIVE || gameMode == GameMode.SPECTATOR); + metadata.getFlags().setFlag(EntityFlag.CAN_FLY, gameMode == GameMode.CREATIVE); SetEntityDataPacket entityDataPacket = new SetEntityDataPacket(); entityDataPacket.setRuntimeEntityId(entity.getGeyserId()); @@ -105,7 +111,6 @@ public class JavaNotifyClientTranslator extends PacketTranslator Date: Sun, 24 May 2020 20:51:30 +0100 Subject: [PATCH 48/73] Added Crossbow nbt translator (#590) They still infinitely reload but they correctly track if they have data in now. --- .../translators/nbt/CrossbowTranslator.java | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/CrossbowTranslator.java diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/CrossbowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/CrossbowTranslator.java new file mode 100644 index 00000000..75701103 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/CrossbowTranslator.java @@ -0,0 +1,78 @@ +/* + * 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.ByteTag; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.ListTag; +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 CrossbowTranslator extends NbtItemStackTranslator { + + @Override + public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) { + if (itemTag.get("ChargedProjectiles") != null) { + ListTag chargedProjectiles = itemTag.get("ChargedProjectiles"); + if (!chargedProjectiles.getValue().isEmpty()) { + CompoundTag projectile = (CompoundTag) chargedProjectiles.getValue().get(0); + + CompoundTag newProjectile = new CompoundTag("chargedItem"); + newProjectile.put(new ByteTag("Count", (byte) projectile.get("Count").getValue())); + newProjectile.put(new StringTag("Name", (String) projectile.get("id").getValue())); + + // Not sure what this is for + newProjectile.put(new ByteTag("Damage", (byte) 0)); + + itemTag.put(newProjectile); + } + } + } + + @Override + public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) { + if (itemTag.get("chargedItem") != null) { + CompoundTag chargedItem = itemTag.get("chargedItem"); + + CompoundTag newProjectile = new CompoundTag(""); + newProjectile.put(new ByteTag("Count", (byte) chargedItem.get("Count").getValue())); + newProjectile.put(new StringTag("id", (String) chargedItem.get("Name").getValue())); + + ListTag chargedProjectiles = new ListTag("ChargedProjectiles"); + chargedProjectiles.add(newProjectile); + + itemTag.put(chargedProjectiles); + } + } + + @Override + public boolean acceptItem(ItemEntry itemEntry) { + return "minecraft:crossbow".equals(itemEntry.getJavaIdentifier()); + } +} From 7154e1c816470cade4a8d4250c04f86515cc4f93 Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sun, 24 May 2020 14:55:48 -0500 Subject: [PATCH 49/73] Strip Minecraft identifier when playing non-mapped sounds to allow for bedrock-exclusive sounds to be played --- .../translators/java/world/JavaPlayerPlaySoundTranslator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayerPlaySoundTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayerPlaySoundTranslator.java index c349c628..58386841 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayerPlaySoundTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayerPlaySoundTranslator.java @@ -57,7 +57,7 @@ public class JavaPlayerPlaySoundTranslator extends PacketTranslator Date: Sun, 24 May 2020 20:07:05 -0500 Subject: [PATCH 50/73] Large refactoring to item translator and registry/util classes - Merged ItemTranslator and ItemStackTranslator together. - Split ItemTranslator into two classes: ItemTranslator and ItemRegistry. The registry is where items are registered, and the translator class is where item translation takes place. - Made most of ItemTranslator's methods static and removed the initialization in Toolbox. - Moved a handful of registry classes previously ending with 'Utils' to a 'Registry' class to be more fitting for the term. - Moved inventory and block entity registration out of Translators. - Renamed Translators to PacketTranslatorRegistry. - Yeeted Toolbox. - Minor cleanups and small refactors. --- .../geysermc/connector/GeyserConnector.java | 32 +- .../entity/AreaEffectCloudEntity.java | 4 +- .../org/geysermc/connector/entity/Entity.java | 9 +- .../geysermc/connector/entity/ItemEntity.java | 4 +- .../connector/entity/ItemFrameEntity.java | 10 +- .../network/UpstreamPacketHandler.java | 4 +- .../network/session/GeyserSession.java | 18 +- .../network/translators/BiomeTranslator.java | 70 +++- .../translators/EntityIdentifierRegistry.java | 60 ++++ .../translators/ItemStackTranslator.java | 250 ------------- .../translators/NbtItemStackTranslator.java | 45 --- ...try.java => PacketTranslatorRegistry.java} | 46 ++- .../network/translators/Translators.java | 175 ---------- ...drockBlockPickRequestPacketTranslator.java | 9 +- .../bedrock/BedrockInteractTranslator.java | 4 +- ...BedrockInventoryTransactionTranslator.java | 14 +- .../translators/effect/EffectRegistry.java} | 68 ++-- .../inventory/InventoryTranslator.java | 35 ++ .../inventory/PlayerInventoryTranslator.java | 23 +- .../action/InventoryActionDataTranslator.java | 6 +- .../updater/ChestInventoryUpdater.java | 6 +- .../updater/ContainerInventoryUpdater.java | 6 +- .../updater/CursorInventoryUpdater.java | 6 +- .../inventory/updater/InventoryUpdater.java | 6 +- .../translators/item/ItemRegistry.java} | 178 +++++----- .../translators/item/ItemTranslator.java | 330 ++++++++++++++---- .../item/NbtItemStackTranslator.java | 45 +++ .../item/translators/BannerTranslator.java | 90 ++++- .../item/translators/PotionTranslator.java | 8 +- .../translators/nbt/BasicItemTranslator.java | 2 +- .../translators/nbt/BookPagesTranslator.java | 2 +- .../translators/nbt/CrossbowTranslator.java | 2 +- .../nbt/EnchantedBookTranslator.java | 2 +- .../nbt/EnchantmentTranslator.java | 2 +- .../translators/nbt/FireworkTranslator.java | 2 +- .../nbt/LeatherArmorTranslator.java | 2 +- .../translators/nbt/MapItemTranslator.java | 2 +- .../java/JavaDeclareRecipesTranslator.java | 14 +- .../entity/JavaEntityEquipmentTranslator.java | 4 +- .../player/JavaPlayerActionAckTranslator.java | 4 +- .../player/JavaPlayerStopSoundTranslator.java | 4 +- .../java/window/JavaOpenWindowTranslator.java | 7 +- .../java/window/JavaSetSlotTranslator.java | 3 +- .../window/JavaWindowItemsTranslator.java | 3 +- .../window/JavaWindowPropertyTranslator.java | 3 +- .../world/JavaPlayBuiltinSoundTranslator.java | 10 +- .../java/world/JavaPlayEffectTranslator.java | 12 +- .../world/JavaPlayerPlaySoundTranslator.java | 4 +- .../world/JavaSpawnParticleTranslator.java | 10 +- .../sound/BlockSoundInteractionHandler.java | 4 +- .../sound/EntitySoundInteractionHandler.java | 4 +- .../translators/sound/SoundRegistry.java} | 57 +-- .../block/BucketSoundInteractionHandler.java | 4 +- .../MilkCowSoundInteractionHandler.java | 4 +- .../world/block/BlockTranslator.java | 8 +- .../entity/BannerBlockEntityTranslator.java | 4 +- .../block/entity/BlockEntityTranslator.java | 37 ++ .../entity/CampfireBlockEntityTranslator.java | 5 +- .../connector/utils/BlockEntityUtils.java | 5 +- .../geysermc/connector/utils/ChunkUtils.java | 27 +- .../geysermc/connector/utils/FileUtils.java | 14 + .../connector/utils/InventoryUtils.java | 13 +- .../geysermc/connector/utils/ItemUtils.java | 73 ---- .../geysermc/connector/utils/LocaleUtils.java | 10 +- .../connector/utils/SkinProvider.java | 4 +- 65 files changed, 980 insertions(+), 948 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/EntityIdentifierRegistry.java delete mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/ItemStackTranslator.java delete mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/NbtItemStackTranslator.java rename connector/src/main/java/org/geysermc/connector/network/translators/{Registry.java => PacketTranslatorRegistry.java} (55%) delete mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/Translators.java rename connector/src/main/java/org/geysermc/connector/{utils/EffectUtils.java => network/translators/effect/EffectRegistry.java} (64%) rename connector/src/main/java/org/geysermc/connector/{utils/Toolbox.java => network/translators/item/ItemRegistry.java} (52%) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/item/NbtItemStackTranslator.java rename connector/src/main/java/org/geysermc/connector/{utils/SoundUtils.java => network/translators/sound/SoundRegistry.java} (65%) diff --git a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java index 43b10053..02e0c500 100644 --- a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java +++ b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java @@ -25,6 +25,8 @@ package org.geysermc.connector; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; import com.nukkitx.protocol.bedrock.BedrockPacketCodec; import com.nukkitx.protocol.bedrock.BedrockServer; import com.nukkitx.protocol.bedrock.v390.Bedrock_v390; @@ -37,11 +39,20 @@ import org.geysermc.connector.metrics.Metrics; import org.geysermc.connector.network.ConnectorServerEventHandler; import org.geysermc.connector.network.remote.RemoteServer; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.Translators; +import org.geysermc.connector.network.translators.BiomeTranslator; +import org.geysermc.connector.network.translators.EntityIdentifierRegistry; +import org.geysermc.connector.network.translators.PacketTranslatorRegistry; +import org.geysermc.connector.network.translators.item.ItemRegistry; +import org.geysermc.connector.network.translators.item.ItemTranslator; +import org.geysermc.connector.network.translators.sound.SoundHandlerRegistry; import org.geysermc.connector.network.translators.world.WorldManager; +import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.network.translators.effect.EffectRegistry; +import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator; import org.geysermc.connector.utils.DimensionUtils; import org.geysermc.connector.utils.DockerCheck; -import org.geysermc.connector.utils.Toolbox; +import org.geysermc.connector.utils.LocaleUtils; +import org.geysermc.connector.network.translators.sound.SoundRegistry; import java.net.InetSocketAddress; import java.text.DecimalFormat; @@ -55,6 +66,8 @@ import java.util.concurrent.TimeUnit; @Getter public class GeyserConnector { + public static final ObjectMapper JSON_MAPPER = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES); + public static final BedrockPacketCodec BEDROCK_PACKET_CODEC = Bedrock_v390.V390_CODEC; public static final String NAME = "Geyser"; @@ -99,8 +112,19 @@ public class GeyserConnector { logger.setDebug(config.isDebugMode()); - Toolbox.init(); - Translators.start(); + PacketTranslatorRegistry.init(); + + /* Initialize translators and registries */ + BiomeTranslator.init(); + BlockTranslator.init(); + BlockEntityTranslator.init(); + EffectRegistry.init(); + EntityIdentifierRegistry.init(); + ItemRegistry.init(); + ItemTranslator.init(); + LocaleUtils.init(); + SoundRegistry.init(); + SoundHandlerRegistry.init(); if (platformType != PlatformType.STANDALONE) { DockerCheck.check(bootstrap); diff --git a/connector/src/main/java/org/geysermc/connector/entity/AreaEffectCloudEntity.java b/connector/src/main/java/org/geysermc/connector/entity/AreaEffectCloudEntity.java index 2808b093..79e67f34 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/AreaEffectCloudEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/AreaEffectCloudEntity.java @@ -31,7 +31,7 @@ import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.EntityData; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.utils.EffectUtils; +import org.geysermc.connector.network.translators.effect.EffectRegistry; public class AreaEffectCloudEntity extends Entity { @@ -52,7 +52,7 @@ public class AreaEffectCloudEntity extends Entity { metadata.put(EntityData.BOUNDING_BOX_WIDTH, 2.0f * (float) entityMetadata.getValue()); } else if (entityMetadata.getId() == 10) { Particle particle = (Particle) entityMetadata.getValue(); - metadata.put(EntityData.AREA_EFFECT_CLOUD_PARTICLE_ID, EffectUtils.getParticleString(particle.getType())); + metadata.put(EntityData.AREA_EFFECT_CLOUD_PARTICLE_ID, EffectRegistry.getParticleString(particle.getType())); } else if (entityMetadata.getId() == 8) { metadata.put(EntityData.POTION_COLOR, entityMetadata.getValue()); } 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 30df1085..434c983b 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/Entity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/Entity.java @@ -51,8 +51,7 @@ import org.geysermc.connector.entity.attribute.AttributeType; import org.geysermc.connector.entity.living.ArmorStandEntity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemTranslator; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.utils.AttributeUtils; import org.geysermc.connector.utils.ChunkUtils; import org.geysermc.connector.utils.MessageUtils; @@ -225,11 +224,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() == ItemTranslator.SHIELD) || - (session.getInventoryCache().getPlayerInventory().getItem(45) != null && session.getInventoryCache().getPlayerInventory().getItem(45).getId() == ItemTranslator.SHIELD)) { + 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)) { ClientPlayerUseItemPacket useItemPacket; metadata.getFlags().setFlag(EntityFlag.BLOCKING, true); - if (session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemTranslator.SHIELD) { + if (session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemRegistry.SHIELD) { 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/ItemEntity.java b/connector/src/main/java/org/geysermc/connector/entity/ItemEntity.java index b321213e..bd18dc46 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/ItemEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/ItemEntity.java @@ -31,7 +31,7 @@ import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.packet.AddItemEntityPacket; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.Translators; +import org.geysermc.connector.network.translators.item.ItemTranslator; public class ItemEntity extends Entity { @@ -49,7 +49,7 @@ public class ItemEntity extends Entity { itemPacket.setUniqueEntityId(geyserId); itemPacket.setFromFishing(false); itemPacket.getMetadata().putAll(metadata); - itemPacket.setItemInHand(Translators.getItemTranslator().translateToBedrock(session, (ItemStack) entityMetadata.getValue())); + itemPacket.setItemInHand(ItemTranslator.translateToBedrock((ItemStack) entityMetadata.getValue())); session.sendUpstreamPacket(itemPacket); } diff --git a/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java b/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java index 5954e77e..a6d8af15 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java @@ -38,10 +38,10 @@ import com.nukkitx.protocol.bedrock.packet.StartGamePacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.Translators; 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.world.block.BlockTranslator; -import org.geysermc.connector.utils.Toolbox; import java.util.concurrent.TimeUnit; @@ -98,12 +98,12 @@ public class ItemFrameEntity extends Entity { @Override public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { if (entityMetadata.getId() == 7 && entityMetadata.getValue() != null) { - ItemData itemData = Translators.getItemTranslator().translateToBedrock(session, (ItemStack) entityMetadata.getValue()); - ItemEntry itemEntry = Translators.getItemTranslator().getItem((ItemStack) entityMetadata.getValue()); + ItemData itemData = ItemTranslator.translateToBedrock((ItemStack) entityMetadata.getValue()); + ItemEntry itemEntry = ItemRegistry.getItem((ItemStack) entityMetadata.getValue()); CompoundTagBuilder builder = CompoundTag.builder(); String blockName = ""; - for (StartGamePacket.ItemEntry startGamePacketItemEntry: Toolbox.ITEMS) { + for (StartGamePacket.ItemEntry startGamePacketItemEntry : ItemRegistry.ITEMS) { if (startGamePacketItemEntry.getId() == (short) itemEntry.getBedrockId()) { blockName = startGamePacketItemEntry.getIdentifier(); break; diff --git a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java index 3d2ded44..67862d0e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java @@ -31,7 +31,7 @@ import org.geysermc.common.AuthType; import org.geysermc.connector.GeyserConfiguration; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.Registry; +import org.geysermc.connector.network.translators.PacketTranslatorRegistry; import org.geysermc.connector.utils.LoginEncryptionUtils; public class UpstreamPacketHandler extends LoggingPacketHandler { @@ -41,7 +41,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { } private boolean translateAndDefault(BedrockPacket packet) { - return Registry.BEDROCK.translate(packet.getClass(), packet, session); + return PacketTranslatorRegistry.BEDROCK_TRANSLATOR.translate(packet.getClass(), packet, session); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 90ca1344..cc052509 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -65,12 +65,14 @@ import org.geysermc.connector.network.remote.RemoteServer; import org.geysermc.connector.network.session.auth.AuthData; import org.geysermc.connector.network.session.auth.BedrockClientData; import org.geysermc.connector.network.session.cache.*; -import org.geysermc.connector.network.translators.Registry; +import org.geysermc.connector.network.translators.BiomeTranslator; +import org.geysermc.connector.network.translators.EntityIdentifierRegistry; +import org.geysermc.connector.network.translators.PacketTranslatorRegistry; +import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.world.block.BlockTranslator; import org.geysermc.connector.utils.ChunkUtils; import org.geysermc.connector.utils.LocaleUtils; import org.geysermc.connector.utils.SkinUtils; -import org.geysermc.connector.utils.Toolbox; import org.geysermc.floodgate.util.BedrockData; import org.geysermc.floodgate.util.EncryptionUtil; @@ -194,16 +196,16 @@ public class GeyserSession implements CommandSender { ChunkUtils.sendEmptyChunks(this, playerEntity.getPosition().toInt(), 0, false); BiomeDefinitionListPacket biomeDefinitionListPacket = new BiomeDefinitionListPacket(); - biomeDefinitionListPacket.setTag(Toolbox.BIOMES); + biomeDefinitionListPacket.setTag(BiomeTranslator.BIOMES); upstream.sendPacket(biomeDefinitionListPacket); AvailableEntityIdentifiersPacket entityPacket = new AvailableEntityIdentifiersPacket(); - entityPacket.setTag(Toolbox.ENTITY_IDENTIFIERS); + entityPacket.setTag(EntityIdentifierRegistry.ENTITY_IDENTIFIERS); upstream.sendPacket(entityPacket); InventoryContentPacket creativePacket = new InventoryContentPacket(); creativePacket.setContainerId(ContainerId.CREATIVE); - creativePacket.setContents(Toolbox.CREATIVE_ITEMS); + creativePacket.setContents(ItemRegistry.CREATIVE_ITEMS); upstream.sendPacket(creativePacket); PlayStatusPacket playStatusPacket = new PlayStatusPacket(); @@ -345,7 +347,7 @@ public class GeyserSession implements CommandSender { lastDimPacket = event.getPacket(); return; } else if (lastDimPacket != null) { - Registry.JAVA.translate(lastDimPacket.getClass(), lastDimPacket, GeyserSession.this); + PacketTranslatorRegistry.JAVA_TRANSLATOR.translate(lastDimPacket.getClass(), lastDimPacket, GeyserSession.this); lastDimPacket = null; } @@ -361,7 +363,7 @@ public class GeyserSession implements CommandSender { } } - Registry.JAVA.translate(event.getPacket().getClass(), event.getPacket(), GeyserSession.this); + PacketTranslatorRegistry.JAVA_TRANSLATOR.translate(event.getPacket().getClass(), event.getPacket(), GeyserSession.this); } } }); @@ -497,7 +499,7 @@ public class GeyserSession implements CommandSender { startGamePacket.setEnchantmentSeed(0); startGamePacket.setMultiplayerCorrelationId(""); startGamePacket.setBlockPalette(BlockTranslator.BLOCKS); - startGamePacket.setItemEntries(Toolbox.ITEMS); + startGamePacket.setItemEntries(ItemRegistry.ITEMS); startGamePacket.setVanillaVersion("*"); // startGamePacket.setMovementServerAuthoritative(true); upstream.sendPacket(startGamePacket); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/BiomeTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/BiomeTranslator.java index 12278841..c12cc513 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/BiomeTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/BiomeTranslator.java @@ -1,14 +1,72 @@ +/* + * 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.nukkitx.nbt.NbtUtils; +import com.nukkitx.nbt.stream.NBTInputStream; +import com.nukkitx.nbt.tag.CompoundTag; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.utils.FileUtils; + +import java.io.InputStream; import java.util.Arrays; -//Based off of ProtocolSupport's LegacyBiomeData.java https://github.com/ProtocolSupport/ProtocolSupport/blob/b2cad35977f3fcb65bee57b9e14fc9c975f71d32/src/protocolsupport/protocol/typeremapper/legacy/LegacyBiomeData.java -//Array index formula by https://wiki.vg/Chunk_Format - +// Based off of ProtocolSupport's LegacyBiomeData.java: +// https://github.com/ProtocolSupport/ProtocolSupport/blob/b2cad35977f3fcb65bee57b9e14fc9c975f71d32/src/protocolsupport/protocol/typeremapper/legacy/LegacyBiomeData.java +// Array index formula by https://wiki.vg/Chunk_Format public class BiomeTranslator { + public static final CompoundTag BIOMES; + + private BiomeTranslator() { + } + + public static void init() { + // no-op + } + + static { + /* Load biomes */ + InputStream stream = FileUtils.getResource("bedrock/biome_definitions.dat"); + + CompoundTag biomesTag; + + try (NBTInputStream biomenbtInputStream = NbtUtils.createNetworkReader(stream)){ + biomesTag = (CompoundTag) biomenbtInputStream.readTag(); + BIOMES = biomesTag; + } catch (Exception ex) { + GeyserConnector.getInstance().getLogger().warning("Failed to get biomes from biome definitions, is there something wrong with the file?"); + throw new AssertionError(ex); + } + } + public static byte[] toBedrockBiome(int[] biomeData) { byte[] bedrockData = new byte[256]; - if(biomeData == null) { + if (biomeData == null) { return bedrockData; } @@ -24,12 +82,12 @@ public class BiomeTranslator { return bedrockData; } - protected static void fillArray(int z, int x, byte[] legacyBiomeData, int biomeId) { + private static void fillArray(int z, int x, byte[] legacyBiomeData, int biomeId) { int offset = (z << 4) | x; Arrays.fill(legacyBiomeData, offset, offset + 4, (byte) biomeId); } - protected static byte biomeID(int[] biomeData, int x, int z) { + private static byte biomeID(int[] biomeData, int x, int z) { return (byte) biomeData[((z >> 2) & 3) << 2 | ((x >> 2) & 3)]; } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/EntityIdentifierRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/EntityIdentifierRegistry.java new file mode 100644 index 00000000..cc9b2cd8 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/EntityIdentifierRegistry.java @@ -0,0 +1,60 @@ +/* + * 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.nukkitx.nbt.NbtUtils; +import com.nukkitx.nbt.stream.NBTInputStream; +import com.nukkitx.nbt.tag.CompoundTag; +import org.geysermc.connector.utils.FileUtils; + +import java.io.InputStream; + +/** + * Registry for entity identifiers. + */ +public class EntityIdentifierRegistry { + + public static CompoundTag ENTITY_IDENTIFIERS; + + private EntityIdentifierRegistry() { + } + + public static void init() { + // no-op + } + + static { + /* Load entity identifiers */ + InputStream stream = FileUtils.getResource("bedrock/entity_identifiers.dat"); + + try (NBTInputStream nbtInputStream = NbtUtils.createNetworkReader(stream)) { + ENTITY_IDENTIFIERS = (CompoundTag) nbtInputStream.readTag(); + } catch (Exception e) { + throw new AssertionError("Unable to get entities from entity identifiers", e); + } + } +} 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 deleted file mode 100644 index 423ffd39..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/ItemStackTranslator.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * 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(), new com.github.steveice10.opennbt.tag.builtin.CompoundTag("")); - } - 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(), 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 deleted file mode 100644 index 56c780f4..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/NbtItemStackTranslator.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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/Registry.java b/connector/src/main/java/org/geysermc/connector/network/translators/PacketTranslatorRegistry.java similarity index 55% rename from connector/src/main/java/org/geysermc/connector/network/translators/Registry.java rename to connector/src/main/java/org/geysermc/connector/network/translators/PacketTranslatorRegistry.java index 399ec1a6..13136331 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/Registry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/PacketTranslatorRegistry.java @@ -35,33 +35,59 @@ import org.geysermc.connector.network.session.GeyserSession; import com.github.steveice10.packetlib.packet.Packet; import com.nukkitx.protocol.bedrock.BedrockPacket; +import org.reflections.Reflections; -public class Registry { - private final Map, PacketTranslator> MAP = new HashMap<>(); +public class PacketTranslatorRegistry { + private final Map, PacketTranslator> translators = new HashMap<>(); - public static final Registry JAVA = new Registry<>(); - public static final Registry BEDROCK = new Registry<>(); + public static final PacketTranslatorRegistry JAVA_TRANSLATOR = new PacketTranslatorRegistry<>(); + public static final PacketTranslatorRegistry BEDROCK_TRANSLATOR = new PacketTranslatorRegistry<>(); private static final ObjectArrayList> IGNORED_PACKETS = new ObjectArrayList<>(); static { + Reflections ref = new Reflections("org.geysermc.connector.network.translators"); + + for (Class clazz : ref.getTypesAnnotatedWith(Translator.class)) { + Class packet = clazz.getAnnotation(Translator.class).packet(); + + GeyserConnector.getInstance().getLogger().debug("Found annotated translator: " + clazz.getCanonicalName() + " : " + packet.getSimpleName()); + + try { + if (Packet.class.isAssignableFrom(packet)) { + Class targetPacket = (Class) packet; + PacketTranslator translator = (PacketTranslator) clazz.newInstance(); + + JAVA_TRANSLATOR.translators.put(targetPacket, translator); + } else if (BedrockPacket.class.isAssignableFrom(packet)) { + Class targetPacket = (Class) packet; + PacketTranslator translator = (PacketTranslator) clazz.newInstance(); + + BEDROCK_TRANSLATOR.translators.put(targetPacket, translator); + } else { + GeyserConnector.getInstance().getLogger().error("Class " + clazz.getCanonicalName() + " is annotated as a translator but has an invalid target packet."); + } + } catch (InstantiationException | IllegalAccessException e) { + GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated translator " + clazz.getCanonicalName() + "."); + } + } + IGNORED_PACKETS.add(ServerUpdateLightPacket.class); } - public static void registerJava(Class targetPacket, PacketTranslator translator) { - JAVA.MAP.put(targetPacket, translator); + private PacketTranslatorRegistry() { } - public static void registerBedrock(Class targetPacket, PacketTranslator translator) { - BEDROCK.MAP.put(targetPacket, translator); + public static void init() { + // no-op } @SuppressWarnings("unchecked") public

boolean translate(Class clazz, P packet, GeyserSession session) { if (!session.getUpstream().isClosed() && !session.isClosed()) { try { - if (MAP.containsKey(clazz)) { - ((PacketTranslator

) MAP.get(clazz)).translate(packet, session); + if (translators.containsKey(clazz)) { + ((PacketTranslator

) translators.get(clazz)).translate(packet, session); return true; } else { if (!IGNORED_PACKETS.contains(clazz)) 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 deleted file mode 100644 index 03042e3a..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/Translators.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 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.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -import com.github.steveice10.mc.protocol.data.game.window.WindowType; -import com.nukkitx.protocol.bedrock.data.ContainerType; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; -import org.geysermc.connector.network.translators.world.block.entity.*; -import org.geysermc.connector.network.translators.inventory.*; -import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater; -import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; -import org.geysermc.connector.network.translators.item.ItemTranslator; -import org.reflections.Reflections; - -import com.github.steveice10.packetlib.packet.Packet; -import com.nukkitx.nbt.CompoundTagBuilder; -import com.nukkitx.nbt.NbtUtils; -import com.nukkitx.nbt.stream.NBTOutputStream; -import com.nukkitx.nbt.tag.CompoundTag; -import com.nukkitx.protocol.bedrock.BedrockPacket; - -import lombok.Getter; - -public class Translators { - - @Getter - private static ItemTranslator itemTranslator; - - @Getter - private static Map inventoryTranslators = new HashMap<>(); - - @Getter - private static Map blockEntityTranslators = new HashMap<>(); - - @Getter - private static ObjectArrayList requiresBlockStateMap = new ObjectArrayList<>(); - - private static final CompoundTag EMPTY_TAG = CompoundTagBuilder.builder().buildRootTag(); - public static final byte[] EMPTY_LEVEL_CHUNK_DATA; - - static { - try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { - outputStream.write(new byte[258]); // Biomes + Border Size + Extra Data Size - - try (NBTOutputStream stream = NbtUtils.createNetworkWriter(outputStream)) { - stream.write(EMPTY_TAG); - } - - EMPTY_LEVEL_CHUNK_DATA = outputStream.toByteArray(); - }catch (IOException e) { - throw new AssertionError("Unable to generate empty level chunk data"); - } - } - - @SuppressWarnings("unchecked") - public static void start() { - Reflections ref = new Reflections("org.geysermc.connector.network.translators"); - - for (Class clazz : ref.getTypesAnnotatedWith(Translator.class)) { - Class packet = clazz.getAnnotation(Translator.class).packet(); - - GeyserConnector.getInstance().getLogger().debug("Found annotated translator: " + clazz.getCanonicalName() + " : " + packet.getSimpleName()); - - try { - if (Packet.class.isAssignableFrom(packet)) { - Class targetPacket = (Class) packet; - PacketTranslator translator = (PacketTranslator) clazz.newInstance(); - - Registry.registerJava(targetPacket, translator); - - } else if (BedrockPacket.class.isAssignableFrom(packet)) { - Class targetPacket = (Class) packet; - PacketTranslator translator = (PacketTranslator) clazz.newInstance(); - - Registry.registerBedrock(targetPacket, translator); - - } else { - GeyserConnector.getInstance().getLogger().error("Class " + clazz.getCanonicalName() + " is annotated as a translator but has an invalid target packet."); - } - } catch (InstantiationException | IllegalAccessException e) { - GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated translator " + clazz.getCanonicalName() + "."); - } - } - - itemTranslator = new ItemTranslator(); - itemTranslator.init(); - BlockTranslator.init(); - - registerBlockEntityTranslators(); - registerInventoryTranslators(); - } - - private static void registerBlockEntityTranslators() { - Reflections ref = new Reflections("org.geysermc.connector.network.translators.world.block.entity"); - - for (Class clazz : ref.getTypesAnnotatedWith(BlockEntity.class)) { - - GeyserConnector.getInstance().getLogger().debug("Found annotated block entity: " + clazz.getCanonicalName()); - - try { - blockEntityTranslators.put(clazz.getAnnotation(BlockEntity.class).name(), (BlockEntityTranslator) clazz.newInstance()); - } catch (InstantiationException | IllegalAccessException e) { - GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated block entity " + clazz.getCanonicalName() + "."); - } - } - - for (Class clazz : ref.getSubTypesOf(RequiresBlockState.class)) { - - GeyserConnector.getInstance().getLogger().debug("Found block entity that requires block state: " + clazz.getCanonicalName()); - - try { - requiresBlockStateMap.add((RequiresBlockState) clazz.newInstance()); - } catch (InstantiationException | IllegalAccessException e) { - GeyserConnector.getInstance().getLogger().error("Could not instantiate required block state " + clazz.getCanonicalName() + "."); - } - - } - } - - private static void registerInventoryTranslators() { - inventoryTranslators.put(null, new PlayerInventoryTranslator()); //player inventory - inventoryTranslators.put(WindowType.GENERIC_9X1, new SingleChestInventoryTranslator(9)); - inventoryTranslators.put(WindowType.GENERIC_9X2, new SingleChestInventoryTranslator(18)); - inventoryTranslators.put(WindowType.GENERIC_9X3, new SingleChestInventoryTranslator(27)); - inventoryTranslators.put(WindowType.GENERIC_9X4, new DoubleChestInventoryTranslator(36)); - inventoryTranslators.put(WindowType.GENERIC_9X5, new DoubleChestInventoryTranslator(45)); - inventoryTranslators.put(WindowType.GENERIC_9X6, new DoubleChestInventoryTranslator(54)); - inventoryTranslators.put(WindowType.BREWING_STAND, new BrewingInventoryTranslator()); - inventoryTranslators.put(WindowType.ANVIL, new AnvilInventoryTranslator()); - inventoryTranslators.put(WindowType.CRAFTING, new CraftingInventoryTranslator()); - inventoryTranslators.put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator()); - //inventoryTranslators.put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator()); //TODO - - InventoryTranslator furnace = new FurnaceInventoryTranslator(); - inventoryTranslators.put(WindowType.FURNACE, furnace); - inventoryTranslators.put(WindowType.BLAST_FURNACE, furnace); - inventoryTranslators.put(WindowType.SMOKER, furnace); - - InventoryUpdater containerUpdater = new ContainerInventoryUpdater(); - inventoryTranslators.put(WindowType.GENERIC_3X3, new BlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER, containerUpdater)); - inventoryTranslators.put(WindowType.HOPPER, new BlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, containerUpdater)); - inventoryTranslators.put(WindowType.SHULKER_BOX, new BlockInventoryTranslator(27, "minecraft:shulker_box[facing=north]", ContainerType.CONTAINER, containerUpdater)); - //inventoryTranslators.put(WindowType.BEACON, new BlockInventoryTranslator(1, "minecraft:beacon", ContainerType.BEACON)); //TODO - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockPickRequestPacketTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockPickRequestPacketTranslator.java index 288b99d3..04fe8dbf 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockPickRequestPacketTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockPickRequestPacketTranslator.java @@ -31,15 +31,13 @@ import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientMoveI import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.packet.BlockPickRequestPacket; import com.nukkitx.protocol.bedrock.packet.PlayerHotbarPacket; -import org.geysermc.connector.entity.Entity; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; 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.world.block.BlockTranslator; -import org.geysermc.connector.network.translators.item.ItemTranslator; -import org.geysermc.connector.network.translators.Translators; @Translator(packet = BlockPickRequestPacket.class) public class BedrockBlockPickRequestPacketTranslator extends PacketTranslator { @@ -61,14 +59,13 @@ public class BedrockBlockPickRequestPacketTranslator extends PacketTranslator { @@ -51,7 +51,7 @@ public class BedrockInteractTranslator extends PacketTranslator switch (packet.getAction()) { case INTERACT: - if (session.getInventory().getItem(session.getInventory().getHeldItemSlot() + 36).getId() == ItemTranslator.SHIELD) { + if (session.getInventory().getItem(session.getInventory().getHeldItemSlot() + 36).getId() == ItemRegistry.SHIELD) { 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 03f7a112..8f96b800 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 @@ -49,9 +49,9 @@ import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.network.translators.Translators; +import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.item.ItemTranslator; +import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.sound.EntitySoundInteractionHandler; import org.geysermc.connector.network.translators.world.block.BlockTranslator; import org.geysermc.connector.utils.InventoryUtils; @@ -65,12 +65,12 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator EFFECTS = new HashMap<>(); public static final Int2ObjectMap RECORDS = new Int2ObjectOpenHashMap<>(); @@ -57,10 +58,10 @@ public class EffectUtils { static { /* Load particles */ - InputStream particleStream = Toolbox.getResource("mappings/particles.json"); + InputStream particleStream = FileUtils.getResource("mappings/particles.json"); JsonNode particleEntries; try { - particleEntries = Toolbox.JSON_MAPPER.readTree(particleStream); + particleEntries = GeyserConnector.JSON_MAPPER.readTree(particleStream); } catch (Exception e) { throw new AssertionError("Unable to load particle map", e); } @@ -69,10 +70,10 @@ public class EffectUtils { while (particlesIterator.hasNext()) { Map.Entry entry = particlesIterator.next(); try { - setIdentifier(ParticleType.valueOf(entry.getKey().toUpperCase()), LevelEventType.valueOf(entry.getValue().asText().toUpperCase())); + particleTypeMap.put(ParticleType.valueOf(entry.getKey().toUpperCase()), LevelEventType.valueOf(entry.getValue().asText().toUpperCase())); } catch (IllegalArgumentException e1) { try { - setIdentifier(ParticleType.valueOf(entry.getKey().toUpperCase()), entry.getValue().asText()); + particleStringMap.put(ParticleType.valueOf(entry.getKey().toUpperCase()), entry.getValue().asText()); GeyserConnector.getInstance().getLogger().debug("Force to map particle " + entry.getKey() + "=>" @@ -85,10 +86,10 @@ public class EffectUtils { } /* Load effects */ - InputStream effectsStream = Toolbox.getResource("mappings/effects.json"); + InputStream effectsStream = FileUtils.getResource("mappings/effects.json"); JsonNode effects; try { - effects = Toolbox.JSON_MAPPER.readTree(effectsStream); + effects = GeyserConnector.JSON_MAPPER.readTree(effectsStream); } catch (Exception e) { throw new AssertionError("Unable to load effects mappings", e); } @@ -112,14 +113,6 @@ public class EffectUtils { } } - public static void setIdentifier(ParticleType type, LevelEventType identifier) { - particleTypeMap.put(type, identifier); - } - - public static void setIdentifier(ParticleType type, String identifier) { - particleStringMap.put(type, identifier); - } - public static LevelEventType getParticleLevelEventType(@NonNull ParticleType type) { return particleTypeMap.getOrDefault(type, null); } @@ -127,5 +120,4 @@ public class EffectUtils { public static String getParticleString(@NonNull ParticleType type){ return particleStringMap.getOrDefault(type, null); } - } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index 2a5afb8c..7b4b26e6 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -25,15 +25,50 @@ package org.geysermc.connector.network.translators.inventory; +import com.github.steveice10.mc.protocol.data.game.window.WindowType; +import com.nukkitx.protocol.bedrock.data.ContainerType; import com.nukkitx.protocol.bedrock.data.InventoryActionData; import lombok.AllArgsConstructor; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater; +import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; +import java.util.HashMap; import java.util.List; +import java.util.Map; @AllArgsConstructor public abstract class InventoryTranslator { + + public static final Map INVENTORY_TRANSLATORS = new HashMap() { + { + put(null, new PlayerInventoryTranslator()); //player inventory + put(WindowType.GENERIC_9X1, new SingleChestInventoryTranslator(9)); + put(WindowType.GENERIC_9X2, new SingleChestInventoryTranslator(18)); + put(WindowType.GENERIC_9X3, new SingleChestInventoryTranslator(27)); + put(WindowType.GENERIC_9X4, new DoubleChestInventoryTranslator(36)); + put(WindowType.GENERIC_9X5, new DoubleChestInventoryTranslator(45)); + put(WindowType.GENERIC_9X6, new DoubleChestInventoryTranslator(54)); + put(WindowType.BREWING_STAND, new BrewingInventoryTranslator()); + put(WindowType.ANVIL, new AnvilInventoryTranslator()); + put(WindowType.CRAFTING, new CraftingInventoryTranslator()); + put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator()); + //put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator()); //TODO + + InventoryTranslator furnace = new FurnaceInventoryTranslator(); + put(WindowType.FURNACE, furnace); + put(WindowType.BLAST_FURNACE, furnace); + put(WindowType.SMOKER, furnace); + + InventoryUpdater containerUpdater = new ContainerInventoryUpdater(); + put(WindowType.GENERIC_3X3, new BlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER, containerUpdater)); + put(WindowType.HOPPER, new BlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, containerUpdater)); + put(WindowType.SHULKER_BOX, new BlockInventoryTranslator(27, "minecraft:shulker_box[facing=north]", ContainerType.CONTAINER, containerUpdater)); + //put(WindowType.BEACON, new BlockInventoryTranslator(1, "minecraft:beacon", ContainerType.BEACON)); //TODO + } + }; + public final int size; public abstract void prepareInventory(GeyserSession session, Inventory inventory); 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 5beea2a2..055b69ef 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 @@ -36,10 +36,9 @@ import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.Translators; import org.geysermc.connector.network.translators.inventory.action.InventoryActionDataTranslator; +import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.utils.InventoryUtils; -import org.geysermc.connector.utils.Toolbox; import java.util.List; @@ -60,11 +59,11 @@ public class PlayerInventoryTranslator extends InventoryTranslator { ItemData[] contents = new ItemData[36]; // Inventory for (int i = 9; i < 36; i++) { - contents[i] = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(i)); + contents[i] = ItemTranslator.translateToBedrock(inventory.getItem(i)); } // Hotbar for (int i = 36; i < 45; i++) { - contents[i - 36] = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(i)); + contents[i - 36] = ItemTranslator.translateToBedrock(inventory.getItem(i)); } inventoryContentPacket.setContents(contents); session.sendUpstreamPacket(inventoryContentPacket); @@ -74,7 +73,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(session, inventory.getItem(i)); + contents[i - 5] = ItemTranslator.translateToBedrock(inventory.getItem(i)); } armorContentPacket.setContents(contents); session.sendUpstreamPacket(armorContentPacket); @@ -82,7 +81,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { // Offhand InventoryContentPacket offhandPacket = new InventoryContentPacket(); offhandPacket.setContainerId(ContainerId.OFFHAND); - offhandPacket.setContents(new ItemData[]{Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(45))}); + offhandPacket.setContents(new ItemData[]{ItemTranslator.translateToBedrock(inventory.getItem(45))}); session.sendUpstreamPacket(offhandPacket); } @@ -101,7 +100,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { if (session.getGameMode() == GameMode.CREATIVE) { slotPacket.setItem(UNUSUABLE_CRAFTING_SPACE_BLOCK); }else{ - slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(i))); + slotPacket.setItem(ItemTranslator.translateToBedrock(inventory.getItem(i))); } session.sendUpstreamPacket(slotPacket); @@ -126,12 +125,12 @@ public class PlayerInventoryTranslator extends InventoryTranslator { slotPacket.setContainerId(ContainerId.CURSOR); slotPacket.setSlot(slot + 27); } - slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(slot))); + slotPacket.setItem(ItemTranslator.translateToBedrock(inventory.getItem(slot))); session.sendUpstreamPacket(slotPacket); } else if (slot == 45) { InventoryContentPacket offhandPacket = new InventoryContentPacket(); offhandPacket.setContainerId(ContainerId.OFFHAND); - offhandPacket.setContents(new ItemData[]{Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(slot))}); + offhandPacket.setContents(new ItemData[]{ItemTranslator.translateToBedrock(inventory.getItem(slot))}); session.sendUpstreamPacket(offhandPacket); } } @@ -202,7 +201,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { if (action.getToItem().getId() == 0) { javaItem = new ItemStack(-1, 0, null); } else { - javaItem = Translators.getItemTranslator().translateToJava(session, action.getToItem()); + javaItem = ItemTranslator.translateToJava(action.getToItem()); } ClientCreativeInventoryActionPacket creativePacket = new ClientCreativeInventoryActionPacket(javaSlot, javaItem); session.sendDownstreamPacket(creativePacket); @@ -210,13 +209,13 @@ public class PlayerInventoryTranslator extends InventoryTranslator { break; case ContainerId.CURSOR: if (action.getSlot() == 0) { - session.getInventory().setCursor(Translators.getItemTranslator().translateToJava(session, action.getToItem())); + session.getInventory().setCursor(ItemTranslator.translateToJava(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(session, action.getToItem()); + javaItem = ItemTranslator.translateToJava(action.getToItem()); ClientCreativeInventoryActionPacket creativeDropPacket = new ClientCreativeInventoryActionPacket(-1, javaItem); session.sendDownstreamPacket(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 0c267775..9139da1f 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 @@ -38,9 +38,9 @@ import com.nukkitx.protocol.bedrock.data.InventorySource; import com.nukkitx.protocol.bedrock.data.ItemData; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.Translators; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.network.translators.inventory.SlotType; +import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.utils.InventoryUtils; import java.util.*; @@ -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, session.getInventory().getCursor()); + ItemData translatedCursor = ItemTranslator.translateToBedrock(session.getInventory().getCursor()); if (!translatedCursor.equals(action.getFromItem())) { refresh = true; } } else { containerAction = action; - ItemData translatedItem = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(translator.bedrockSlotToJava(action))); + ItemData translatedItem = ItemTranslator.translateToBedrock(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 6656cc83..61bbda50 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 @@ -31,8 +31,8 @@ import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import lombok.AllArgsConstructor; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.Translators; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; +import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.utils.InventoryUtils; @AllArgsConstructor @@ -49,7 +49,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(session, inventory.getItem(i)); + bedrockItems[i] = ItemTranslator.translateToBedrock(inventory.getItem(i)); } else { bedrockItems[i] = UNUSUABLE_SPACE_BLOCK; } @@ -69,7 +69,7 @@ public class ChestInventoryUpdater extends InventoryUpdater { InventorySlotPacket slotPacket = new InventorySlotPacket(); slotPacket.setContainerId(inventory.getId()); slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); - slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(javaSlot))); + slotPacket.setItem(ItemTranslator.translateToBedrock(inventory.getItem(javaSlot))); session.sendUpstreamPacket(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 d25705e2..e84c2931 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 @@ -30,8 +30,8 @@ import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.Translators; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; +import org.geysermc.connector.network.translators.item.ItemTranslator; public class ContainerInventoryUpdater extends InventoryUpdater { @Override @@ -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(session, inventory.getItem(i)); + bedrockItems[translator.javaSlotToBedrock(i)] = ItemTranslator.translateToBedrock(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(session, inventory.getItem(javaSlot))); + slotPacket.setItem(ItemTranslator.translateToBedrock(inventory.getItem(javaSlot))); session.sendUpstreamPacket(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 6a93ecd3..aa7a0174 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 @@ -29,8 +29,8 @@ import com.nukkitx.protocol.bedrock.data.ContainerId; import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.Translators; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; +import org.geysermc.connector.network.translators.item.ItemTranslator; public class CursorInventoryUpdater extends InventoryUpdater { @Override @@ -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(session, inventory.getItem(i))); + slotPacket.setItem(ItemTranslator.translateToBedrock(inventory.getItem(i))); session.sendUpstreamPacket(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(session, inventory.getItem(javaSlot))); + slotPacket.setItem(ItemTranslator.translateToBedrock(inventory.getItem(javaSlot))); session.sendUpstreamPacket(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 ebca038a..9710d805 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 @@ -31,15 +31,15 @@ import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.Translators; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; +import org.geysermc.connector.network.translators.item.ItemTranslator; public abstract class InventoryUpdater { public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { ItemData[] bedrockItems = new ItemData[36]; for (int i = 0; i < 36; i++) { final int offset = i < 9 ? 27 : -9; - bedrockItems[i] = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(translator.size + i + offset)); + bedrockItems[i] = ItemTranslator.translateToBedrock(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(session, inventory.getItem(javaSlot))); + slotPacket.setItem(ItemTranslator.translateToBedrock(inventory.getItem(javaSlot))); session.sendUpstreamPacket(slotPacket); return true; } diff --git a/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java similarity index 52% rename from connector/src/main/java/org/geysermc/connector/utils/Toolbox.java rename to connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java index 953b70a8..ed99ece3 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/Toolbox.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java @@ -1,91 +1,85 @@ /* * 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: + * 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 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.utils; +package org.geysermc.connector.network.translators.item; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.nukkitx.nbt.NbtUtils; -import com.nukkitx.nbt.stream.NBTInputStream; -import com.nukkitx.nbt.tag.CompoundTag; import com.nukkitx.protocol.bedrock.data.ItemData; import com.nukkitx.protocol.bedrock.packet.StartGamePacket; - import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; - import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.item.ToolItemEntry; -import org.geysermc.connector.network.translators.sound.SoundHandlerRegistry; +import org.geysermc.connector.utils.FileUtils; -import java.io.*; -import java.util.*; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Base64; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; -public class Toolbox { +/** + * Registry for anything item related. + */ +public class ItemRegistry { + + private static final Map JAVA_IDENTIFIER_MAP = new HashMap<>(); - public static final ObjectMapper JSON_MAPPER = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES); - public static final CompoundTag BIOMES; public static final ItemData[] CREATIVE_ITEMS; public static final List ITEMS = new ArrayList<>(); - public static final Int2ObjectMap ITEM_ENTRIES = new Int2ObjectOpenHashMap<>(); - public static CompoundTag ENTITY_IDENTIFIERS; + // Shield ID, used in Entity.java + public static final int SHIELD = 829; + // Boat ID, used in BedrockInventoryTransactionTranslator.java + public static final int BOAT = 333; public static int BARRIER_INDEX = 0; + public static void init() { + // no-op + } + static { - /* Load biomes */ - InputStream biomestream = GeyserConnector.class.getClassLoader().getResourceAsStream("bedrock/biome_definitions.dat"); - if (biomestream == null) { - throw new AssertionError("Unable to find bedrock/biome_definitions.dat"); - } - - CompoundTag biomesTag; - - try (NBTInputStream biomenbtInputStream = NbtUtils.createNetworkReader(biomestream)){ - biomesTag = (CompoundTag) biomenbtInputStream.readTag(); - BIOMES = biomesTag; - } catch (Exception ex) { - GeyserConnector.getInstance().getLogger().warning("Failed to get biomes from biome definitions, is there something wrong with the file?"); - throw new AssertionError(ex); - } - /* Load item palette */ - InputStream stream = getResource("bedrock/items.json"); + InputStream stream = FileUtils.getResource("bedrock/items.json"); TypeReference> itemEntriesType = new TypeReference>() { }; List itemEntries; try { - itemEntries = JSON_MAPPER.readValue(stream, itemEntriesType); + itemEntries = GeyserConnector.JSON_MAPPER.readValue(stream, itemEntriesType); } catch (Exception e) { throw new AssertionError("Unable to load Bedrock runtime item IDs", e); } @@ -94,11 +88,11 @@ public class Toolbox { ITEMS.add(new StartGamePacket.ItemEntry(entry.get("name").textValue(), (short) entry.get("id").intValue())); } - stream = getResource("mappings/items.json"); + stream = FileUtils.getResource("mappings/items.json"); JsonNode items; try { - items = JSON_MAPPER.readTree(stream); + items = GeyserConnector.JSON_MAPPER.readTree(stream); } catch (Exception e) { throw new AssertionError("Unable to load Java runtime item IDs", e); } @@ -139,22 +133,12 @@ public class Toolbox { itemIndex++; } - // Load particle/effect mappings - EffectUtils.init(); - // Load sound mappings - SoundUtils.init(); - // Load the locale data - LocaleUtils.init(); - - // Load sound handlers - SoundHandlerRegistry.init(); - /* Load creative items */ - stream = getResource("bedrock/creative_items.json"); + stream = FileUtils.getResource("bedrock/creative_items.json"); JsonNode creativeItemEntries; try { - creativeItemEntries = JSON_MAPPER.readTree(stream).get("items"); + creativeItemEntries = GeyserConnector.JSON_MAPPER.readTree(stream).get("items"); } catch (Exception e) { throw new AssertionError("Unable to load creative items", e); } @@ -179,33 +163,51 @@ public class Toolbox { } } CREATIVE_ITEMS = creativeItems.toArray(new ItemData[0]); - - - /* Load entity identifiers */ - stream = Toolbox.getResource("bedrock/entity_identifiers.dat"); - - try (NBTInputStream nbtInputStream = NbtUtils.createNetworkReader(stream)) { - ENTITY_IDENTIFIERS = (CompoundTag) nbtInputStream.readTag(); - } catch (Exception e) { - throw new AssertionError("Unable to get entities from entity identifiers", e); - } } /** - * Get an InputStream for the given resource path, throws AssertionError if resource is not found + * Gets an {@link ItemEntry} from the given {@link ItemStack}. * - * @param resource Resource to get - * @return InputStream of the given resource + * @param stack the item stack + * @return an item entry from the given item stack */ - public static InputStream getResource(String resource) { - InputStream stream = Toolbox.class.getClassLoader().getResourceAsStream(resource); - if (stream == null) { - throw new AssertionError("Unable to find resource: " + resource); - } - return stream; + public static ItemEntry getItem(ItemStack stack) { + return ITEM_ENTRIES.get(stack.getId()); } - public static void init() { - // no-op + /** + * Gets an {@link ItemEntry} from the given {@link ItemData}. + * + * @param data the item data + * @return an item entry from the given item data + */ + 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"))) { + return itemEntry; + } + } + // If item find was unsuccessful first time, we try again while ignoring damage + // Fixes piston, sticky pistons, dispensers and droppers turning into air from creative inventory + for (ItemEntry itemEntry : ITEM_ENTRIES.values()) { + if (itemEntry.getBedrockId() == data.getId()) { + return itemEntry; + } + } + + GeyserConnector.getInstance().getLogger().debug("Missing mapping for bedrock item " + data.getId() + ":" + data.getDamage()); + return ItemEntry.AIR; } -} \ No newline at end of file + + /** + * Gets an {@link ItemEntry} from the given Minecraft: Java Edition + * block state identifier. + * + * @param javaIdentifier the block state identifier + * @return an item entry from the given java edition identifier + */ + public static ItemEntry getItemEntry(String javaIdentifier) { + return JAVA_IDENTIFIER_MAP.computeIfAbsent(javaIdentifier, key -> ITEM_ENTRIES.values() + .stream().filter(itemEntry -> itemEntry.getJavaIdentifier().equals(key)).findFirst().orElse(null)); + } +} 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 28766971..490681d8 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 @@ -1,57 +1,63 @@ /* * 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: + * 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 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.item; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +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 it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import org.geysermc.connector.GeyserConnector; - -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.*; -import org.geysermc.connector.utils.Toolbox; +import org.geysermc.connector.network.translators.ItemRemapper; import org.reflections.Reflections; -import java.util.*; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.stream.Collectors; -public class ItemTranslator { +public abstract class ItemTranslator { - private Int2ObjectMap itemTranslators = new Int2ObjectOpenHashMap(); - private List nbtItemTranslators; - private Map javaIdentifierMap = new HashMap<>(); + private static final Int2ObjectMap ITEM_STACK_TRANSLATORS = new Int2ObjectOpenHashMap<>(); + private static final List NBT_TRANSLATORS; - // Shield ID, used in Entity.java - public static final int SHIELD = 829; - // Boat ID, used in BedrockInventoryTransactionTranslator.java - public static final int BOAT = 333; + protected ItemTranslator() { + } - public void init() { + public static void init() { + // no-op + } + + static { + /* Load item translators */ Reflections ref = new Reflections("org.geysermc.connector.network.translators.item"); Map loadedNbtItemTranslators = new HashMap<>(); @@ -66,34 +72,33 @@ public class ItemTranslator { loadedNbtItemTranslators.put(nbtItemTranslator, priority); continue; } - ItemStackTranslator itemStackTranslator = (ItemStackTranslator) clazz.newInstance(); + ItemTranslator itemStackTranslator = (ItemTranslator) clazz.newInstance(); List appliedItems = itemStackTranslator.getAppliedItems(); for (ItemEntry item : appliedItems) { - ItemStackTranslator registered = itemTranslators.get(item.getJavaId()); + ItemTranslator registered = ITEM_STACK_TRANSLATORS.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); + ITEM_STACK_TRANSLATORS.put(item.getJavaId(), itemStackTranslator); } } catch (InstantiationException | IllegalAccessException e) { GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated item translator " + clazz.getCanonicalName() + "."); } } - nbtItemTranslators = loadedNbtItemTranslators.keySet().stream() - .sorted(Comparator.comparingInt(value -> loadedNbtItemTranslators.get(value))).collect(Collectors.toList()); + NBT_TRANSLATORS = loadedNbtItemTranslators.keySet().stream().sorted(Comparator.comparingInt(loadedNbtItemTranslators::get)).collect(Collectors.toList()); } - public ItemStack translateToJava(GeyserSession session, ItemData data) { + public static ItemStack translateToJava(ItemData data) { if (data == null) { return new ItemStack(0); } - ItemEntry javaItem = getItem(data); + ItemEntry javaItem = ItemRegistry.getItem(data); ItemStack itemStack; - ItemStackTranslator itemStackTranslator = itemTranslators.get(javaItem.getJavaId()); + ItemTranslator itemStackTranslator = ITEM_STACK_TRANSLATORS.get(javaItem.getJavaId()); if (itemStackTranslator != null) { itemStack = itemStackTranslator.translateToJava(data, javaItem); } else { @@ -101,7 +106,7 @@ public class ItemTranslator { } if (itemStack != null && itemStack.getNbt() != null) { - for (NbtItemStackTranslator translator : nbtItemTranslators) { + for (NbtItemStackTranslator translator : NBT_TRANSLATORS) { if (translator.acceptItem(javaItem)) { translator.translateToJava(itemStack.getNbt(), javaItem); } @@ -110,24 +115,24 @@ public class ItemTranslator { return itemStack; } - public ItemData translateToBedrock(GeyserSession session, ItemStack stack) { + public static ItemData translateToBedrock(ItemStack stack) { if (stack == null) { return ItemData.AIR; } - ItemEntry bedrockItem = getItem(stack); + ItemEntry bedrockItem = ItemRegistry.getItem(stack); ItemStack itemStack = new ItemStack(stack.getId(), stack.getAmount(), stack.getNbt() != null ? stack.getNbt().clone() : null); if (itemStack.getNbt() != null) { - for (NbtItemStackTranslator translator : nbtItemTranslators) { + for (NbtItemStackTranslator translator : NBT_TRANSLATORS) { if (translator.acceptItem(bedrockItem)) { translator.translateToBedrock(itemStack.getNbt(), bedrockItem); } } } - ItemStackTranslator itemStackTranslator = itemTranslators.get(bedrockItem.getJavaId()); + ItemTranslator itemStackTranslator = ITEM_STACK_TRANSLATORS.get(bedrockItem.getJavaId()); if (itemStackTranslator != null) { return itemStackTranslator.translateToBedrock(itemStack, bedrockItem); } else { @@ -135,37 +140,216 @@ public class ItemTranslator { } } - public ItemEntry getItem(ItemStack stack) { - return Toolbox.ITEM_ENTRIES.get(stack.getId()); - } - - public ItemEntry getItem(ItemData data) { - for (ItemEntry itemEntry : Toolbox.ITEM_ENTRIES.values()) { - if (itemEntry.getBedrockId() == data.getId() && (itemEntry.getBedrockData() == data.getDamage() || itemEntry.getJavaIdentifier().endsWith("potion"))) { - return itemEntry; - } - } - // If item find was unsuccessful first time, we try again while ignoring damage - // Fixes piston, sticky pistons, dispensers and droppers turning into air from creative inventory - for (ItemEntry itemEntry : Toolbox.ITEM_ENTRIES.values()) { - if (itemEntry.getBedrockId() == data.getId()) { - return itemEntry; - } - } - - GeyserConnector.getInstance().getLogger().debug("Missing mapping for bedrock item " + data.getId() + ":" + data.getDamage()); - return ItemEntry.AIR; - } - - public ItemEntry getItemEntry(String javaIdentifier) { - return javaIdentifierMap.computeIfAbsent(javaIdentifier, key -> Toolbox.ITEM_ENTRIES.values() - .stream().filter(itemEntry -> itemEntry.getJavaIdentifier().equals(key)).findFirst().orElse(null)); - } - - private static final ItemStackTranslator DEFAULT_TRANSLATOR = new ItemStackTranslator() { + private static final ItemTranslator DEFAULT_TRANSLATOR = new ItemTranslator() { @Override public List getAppliedItems() { return null; } }; + + 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(), new com.github.steveice10.opennbt.tag.builtin.CompoundTag("")); + } + 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); + } + } + + return new CompoundTag(tag.getName(), javaValue); + } + + private 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(), 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()) { + 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/item/NbtItemStackTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/NbtItemStackTranslator.java new file mode 100644 index 00000000..d8fcbc4a --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/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.item; + +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; + +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/item/translators/BannerTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java index 00ee7c0d..f4f545ff 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 @@ -27,25 +27,30 @@ 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.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; +import com.github.steveice10.opennbt.tag.builtin.StringTag; +import com.github.steveice10.opennbt.tag.builtin.Tag; import com.nukkitx.nbt.CompoundTagBuilder; import com.nukkitx.protocol.bedrock.data.ItemData; import org.geysermc.connector.network.translators.ItemRemapper; -import org.geysermc.connector.network.translators.ItemStackTranslator; +import org.geysermc.connector.network.translators.item.ItemRegistry; +import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.utils.ItemUtils; -import org.geysermc.connector.utils.Toolbox; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; @ItemRemapper -public class BannerTranslator extends ItemStackTranslator { +public class BannerTranslator extends ItemTranslator { private List appliedItems; public BannerTranslator() { - appliedItems = Toolbox.ITEM_ENTRIES.values().stream().filter(entry -> entry.getJavaIdentifier().endsWith("banner")).collect(Collectors.toList()); + appliedItems = ItemRegistry.ITEM_ENTRIES.values().stream().filter(entry -> entry.getJavaIdentifier().endsWith("banner")).collect(Collectors.toList()); } @Override @@ -59,7 +64,7 @@ public class BannerTranslator extends ItemStackTranslator { ListTag patterns = blockEntityTag.get("Patterns"); CompoundTagBuilder builder = itemData.getTag().toBuilder(); - builder.tag(ItemUtils.convertBannerPattern(patterns)); + builder.tag(convertBannerPattern(patterns)); itemData = ItemData.of(itemData.getId(), itemData.getDamage(), itemData.getCount(), builder.buildRootTag()); } @@ -75,10 +80,10 @@ public class BannerTranslator extends ItemStackTranslator { com.nukkitx.nbt.tag.CompoundTag nbtTag = itemData.getTag(); if (nbtTag.contains("Patterns")) { - com.nukkitx.nbt.tag.ListTag patterns = (com.nukkitx.nbt.tag.ListTag) nbtTag.get("Patterns"); + com.nukkitx.nbt.tag.ListTag patterns = nbtTag.get("Patterns"); CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag"); - blockEntityTag.put(ItemUtils.convertBannerPattern(patterns)); + blockEntityTag.put(convertBannerPattern(patterns)); itemStack.getNbt().put(blockEntityTag); } @@ -90,4 +95,73 @@ public class BannerTranslator extends ItemStackTranslator { public List getAppliedItems() { return appliedItems; } + + /** + * Convert a list of patterns from Java nbt to Bedrock nbt + * + * @param patterns The patterns to convert + * @return The new converted patterns + */ + public static com.nukkitx.nbt.tag.ListTag convertBannerPattern(ListTag patterns) { + List tagsList = new ArrayList<>(); + for (com.github.steveice10.opennbt.tag.builtin.Tag patternTag : patterns.getValue()) { + com.nukkitx.nbt.tag.CompoundTag newPatternTag = getBedrockBannerPattern((CompoundTag) patternTag); + if (newPatternTag != null) { + tagsList.add(newPatternTag); + } + } + + return new com.nukkitx.nbt.tag.ListTag<>("Patterns", com.nukkitx.nbt.tag.CompoundTag.class, tagsList); + } + + /** + * Convert the Java edition banner pattern nbt to Bedrock edition, null if the pattern doesn't exist + * + * @param pattern Java edition pattern nbt + * @return The Bedrock edition format pattern nbt + */ + public static com.nukkitx.nbt.tag.CompoundTag getBedrockBannerPattern(CompoundTag pattern) { + String patternName = (String) pattern.get("Pattern").getValue(); + + // Return null if its the globe pattern as it doesn't exist on bedrock + if (patternName.equals("glb")) { + return null; + } + + return CompoundTagBuilder.builder() + .intTag("Color", 15 - (int) pattern.get("Color").getValue()) + .stringTag("Pattern", (String) pattern.get("Pattern").getValue()) + .stringTag("Pattern", patternName) + .buildRootTag(); + } + + /** + * Convert a list of patterns from Bedrock nbt to Java nbt + * + * @param patterns The patterns to convert + * @return The new converted patterns + */ + public static ListTag convertBannerPattern(com.nukkitx.nbt.tag.ListTag patterns) { + List tagsList = new ArrayList<>(); + for (Object patternTag : patterns.getValue()) { + CompoundTag newPatternTag = getJavaBannerPattern((com.nukkitx.nbt.tag.CompoundTag) patternTag); + tagsList.add(newPatternTag); + } + + return new ListTag("Patterns", tagsList); + } + + /** + * Convert the Bedrock edition banner pattern nbt to Java edition + * + * @param pattern Bedorck edition pattern nbt + * @return The Java edition format pattern nbt + */ + public static CompoundTag getJavaBannerPattern(com.nukkitx.nbt.tag.CompoundTag pattern) { + Map tags = new HashMap<>(); + tags.put("Color", new IntTag("Color", 15 - pattern.getInt("Color"))); + tags.put("Pattern", new StringTag("Pattern", pattern.getString("Pattern"))); + + return new CompoundTag("", tags); + } } 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 e528b448..2fdde31d 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 @@ -30,22 +30,22 @@ 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.item.ItemRegistry; +import org.geysermc.connector.network.translators.item.ItemTranslator; 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 { +public class PotionTranslator extends ItemTranslator { private List appliedItems; public PotionTranslator() { - appliedItems = Toolbox.ITEM_ENTRIES.values().stream().filter(entry -> entry.getJavaIdentifier().endsWith("potion")).collect(Collectors.toList()); + appliedItems = ItemRegistry.ITEM_ENTRIES.values().stream().filter(entry -> entry.getJavaIdentifier().endsWith("potion")).collect(Collectors.toList()); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BasicItemTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BasicItemTranslator.java index 418f97da..776cec72 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BasicItemTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BasicItemTranslator.java @@ -34,7 +34,7 @@ import net.kyori.text.TextComponent; import net.kyori.text.serializer.gson.GsonComponentSerializer; import net.kyori.text.serializer.legacy.LegacyComponentSerializer; import org.geysermc.connector.network.translators.ItemRemapper; -import org.geysermc.connector.network.translators.NbtItemStackTranslator; +import org.geysermc.connector.network.translators.item.NbtItemStackTranslator; import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.utils.MessageUtils; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BookPagesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BookPagesTranslator.java index d9c48a19..15279c7a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BookPagesTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BookPagesTranslator.java @@ -30,7 +30,7 @@ import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; 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.NbtItemStackTranslator; import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.utils.MessageUtils; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/CrossbowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/CrossbowTranslator.java index 75701103..3c5271eb 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/CrossbowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/CrossbowTranslator.java @@ -30,7 +30,7 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; 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.NbtItemStackTranslator; import org.geysermc.connector.network.translators.item.ItemEntry; @ItemRemapper 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 index 38df1ee3..63ac6c51 100644 --- 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 @@ -29,7 +29,7 @@ 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.NbtItemStackTranslator; import org.geysermc.connector.network.translators.item.ItemEntry; @ItemRemapper(priority = 1) 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 index 5dbb926c..404d7824 100644 --- 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 @@ -28,7 +28,7 @@ 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.NbtItemStackTranslator; import org.geysermc.connector.network.translators.item.Enchantment; import org.geysermc.connector.network.translators.item.ItemEntry; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkTranslator.java index 573e520e..268fe393 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkTranslator.java @@ -27,7 +27,7 @@ package org.geysermc.connector.network.translators.item.translators.nbt; import com.github.steveice10.opennbt.tag.builtin.*; import org.geysermc.connector.network.translators.ItemRemapper; -import org.geysermc.connector.network.translators.NbtItemStackTranslator; +import org.geysermc.connector.network.translators.item.NbtItemStackTranslator; import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.utils.FireworkColor; 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 index 5b283ef5..9f864ccf 100644 --- 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 @@ -28,7 +28,7 @@ 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.NbtItemStackTranslator; import org.geysermc.connector.network.translators.item.ItemEntry; @ItemRemapper 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 7e6bc729..8c418c0f 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 @@ -30,7 +30,7 @@ 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.NbtItemStackTranslator; import org.geysermc.connector.network.translators.item.ItemEntry; @ItemRemapper 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 b6a25e54..7763a2c1 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 @@ -42,9 +42,9 @@ import lombok.EqualsAndHashCode; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.network.translators.Translators; import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.utils.Toolbox; +import org.geysermc.connector.network.translators.item.ItemRegistry; +import org.geysermc.connector.network.translators.item.ItemTranslator; import java.util.*; import java.util.stream.Collectors; @@ -64,7 +64,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator> groupedByIds = Arrays.stream(ingredient.getOptions()) - .map(item -> Translators.getItemTranslator().translateToBedrock(session, item)) + .map(ItemTranslator::translateToBedrock) .collect(Collectors.groupingBy(item -> new GroupedItem(item.getId(), item.getCount(), item.getTag()))); Set optionSet = new HashSet<>(groupedByIds.size()); for (Map.Entry> entry : groupedByIds.entrySet()) { @@ -111,7 +111,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator 0) { - translatedItems[i] = Translators.getItemTranslator().translateToBedrock(session, ingredients[i].getOptions()[0]); + translatedItems[i] = ItemTranslator.translateToBedrock(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 a010752d..e977e9b0 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 @@ -30,10 +30,10 @@ import org.geysermc.connector.entity.LivingEntity; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.network.translators.Translators; import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityEquipmentPacket; import com.nukkitx.protocol.bedrock.data.ItemData; +import org.geysermc.connector.network.translators.item.ItemTranslator; @Translator(packet = ServerEntityEquipmentPacket.class) public class JavaEntityEquipmentTranslator extends PacketTranslator { @@ -55,7 +55,7 @@ public class JavaEntityEquipmentTranslator extends PacketTranslator { @@ -48,7 +48,7 @@ public class JavaPlayerStopSoundTranslator extends PacketTranslator " + soundMapping + (soundMapping == null ? "[not found]" : "") diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java index 6c0e3406..e2c64510 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java @@ -35,7 +35,6 @@ import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.network.translators.Translators; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.utils.InventoryUtils; @@ -49,14 +48,14 @@ public class JavaOpenWindowTranslator extends PacketTranslator InventoryUtils.openInventory(session, newInventory), 500, TimeUnit.MILLISECONDS); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java index 6fafa2a4..5d44069f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java @@ -29,7 +29,6 @@ import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerSetSl import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.Translators; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.network.translators.Translator; import org.geysermc.connector.utils.InventoryUtils; @@ -56,7 +55,7 @@ public class JavaSetSlotTranslator extends PacketTranslator if (inventory == null || (packet.getWindowId() != 0 && inventory.getWindowType() == null)) return; - InventoryTranslator translator = Translators.getInventoryTranslators().get(inventory.getWindowType()); + InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType()); if (translator != null) { inventory.setItem(packet.getSlot(), packet.getItem()); translator.updateSlot(session, inventory, packet.getSlot()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java index eab57a64..2cc392f5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java @@ -30,7 +30,6 @@ import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.network.translators.Translators; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import java.util.Arrays; @@ -50,7 +49,7 @@ public class JavaWindowItemsTranslator extends PacketTranslator { @@ -44,7 +44,7 @@ public class JavaPlayBuiltinSoundTranslator extends PacketTranslator params = new ArrayList<>(); - String recordString = "%item." + EffectUtils.RECORDS.get(recordEffectData.getRecordId()).name().toLowerCase() + ".desc"; + String recordString = "%item." + EffectRegistry.RECORDS.get(recordEffectData.getRecordId()).name().toLowerCase() + ".desc"; params.add(LocaleUtils.getLocaleString(recordString, session.getClientData().getLanguageCode())); textPacket.setParameters(params); session.sendUpstreamPacket(textPacket); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayerPlaySoundTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayerPlaySoundTranslator.java index 58386841..c99de3e3 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayerPlaySoundTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayerPlaySoundTranslator.java @@ -34,7 +34,7 @@ import com.nukkitx.protocol.bedrock.packet.*; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.utils.SoundUtils; +import org.geysermc.connector.network.translators.sound.SoundRegistry; @Translator(packet = ServerPlaySoundPacket.class) public class JavaPlayerPlaySoundTranslator extends PacketTranslator { @@ -51,7 +51,7 @@ public class JavaPlayerPlaySoundTranslator extends PacketTranslator { @@ -64,7 +64,7 @@ public class JavaSpawnParticleTranslator extends PacketTranslator SOUNDS; + private SoundRegistry() { + } + public static void init() { // no-op } static { /* Load sound mappings */ - InputStream stream = Toolbox.getResource("mappings/sounds.json"); + InputStream stream = FileUtils.getResource("mappings/sounds.json"); JsonNode soundsTree; try { - soundsTree = Toolbox.JSON_MAPPER.readTree(stream); + soundsTree = GeyserConnector.JSON_MAPPER.readTree(stream); } catch (IOException e) { throw new AssertionError("Unable to load sound mappings", e); } @@ -83,6 +87,13 @@ public class SoundUtils { return SOUNDS.get(java); } + /** + * Maps a sound name to a sound event, null if one + * does not exist. + * + * @param sound the sound name + * @return a sound event from the given sound + */ public static SoundEvent toSoundEvent(String sound) { try { return SoundEvent.valueOf(sound.toUpperCase().replaceAll("\\.", "_")); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/BucketSoundInteractionHandler.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/BucketSoundInteractionHandler.java index 031782c1..367f9beb 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/BucketSoundInteractionHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/BucketSoundInteractionHandler.java @@ -30,7 +30,7 @@ import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.SoundEvent; import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.Translators; +import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.sound.BlockSoundInteractionHandler; import org.geysermc.connector.network.translators.sound.SoundHandler; @@ -39,7 +39,7 @@ public class BucketSoundInteractionHandler implements BlockSoundInteractionHandl @Override public void handleInteraction(GeyserSession session, Vector3f position, String identifier) { - String handItemIdentifier = Translators.getItemTranslator().getItem(session.getInventory().getItemInHand()).getJavaIdentifier(); + String handItemIdentifier = ItemRegistry.getItem(session.getInventory().getItemInHand()).getJavaIdentifier(); LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); soundEventPacket.setPosition(position); soundEventPacket.setIdentifier(":"); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/sound/entity/MilkCowSoundInteractionHandler.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/entity/MilkCowSoundInteractionHandler.java index 42e2e601..d33d68af 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/sound/entity/MilkCowSoundInteractionHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/sound/entity/MilkCowSoundInteractionHandler.java @@ -31,7 +31,7 @@ import com.nukkitx.protocol.bedrock.data.SoundEvent; import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; import org.geysermc.connector.entity.Entity; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.Translators; +import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.sound.EntitySoundInteractionHandler; import org.geysermc.connector.network.translators.sound.SoundHandler; @@ -40,7 +40,7 @@ public class MilkCowSoundInteractionHandler implements EntitySoundInteractionHan @Override public void handleInteraction(GeyserSession session, Vector3f position, Entity value) { - if (!Translators.getItemTranslator().getItem(session.getInventory().getItemInHand()).getJavaIdentifier().equals("minecraft:bucket")) { + if (!ItemRegistry.getItem(session.getInventory().getItemInHand()).getJavaIdentifier().equals("minecraft:bucket")) { return; } LevelSoundEventPacket levelSoundEventPacket = new LevelSoundEventPacket(); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java index e614900c..a40dd15f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java @@ -39,7 +39,7 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.network.translators.world.block.entity.BlockEntity; -import org.geysermc.connector.utils.Toolbox; +import org.geysermc.connector.utils.FileUtils; import org.reflections.Reflections; import java.io.InputStream; @@ -73,7 +73,7 @@ public class BlockTranslator { static { /* Load block palette */ - InputStream stream = Toolbox.getResource("bedrock/runtime_block_states.dat"); + InputStream stream = FileUtils.getResource("bedrock/runtime_block_states.dat"); ListTag blocksTag; try (NBTInputStream nbtInputStream = NbtUtils.createNetworkReader(stream)) { @@ -90,10 +90,10 @@ public class BlockTranslator { } } - stream = Toolbox.getResource("mappings/blocks.json"); + stream = FileUtils.getResource("mappings/blocks.json"); JsonNode blocks; try { - blocks = Toolbox.JSON_MAPPER.readTree(stream); + blocks = GeyserConnector.JSON_MAPPER.readTree(stream); } catch (Exception e) { throw new AssertionError("Unable to load Java block mappings", e); } 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 41f83bad..3e2c0a95 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 @@ -32,8 +32,8 @@ import com.nukkitx.nbt.CompoundTagBuilder; import com.nukkitx.nbt.tag.IntTag; import com.nukkitx.nbt.tag.StringTag; import com.nukkitx.nbt.tag.Tag; +import org.geysermc.connector.network.translators.item.translators.BannerTranslator; import org.geysermc.connector.network.translators.world.block.BlockStateValues; -import org.geysermc.connector.utils.ItemUtils; import java.util.ArrayList; import java.util.List; @@ -57,7 +57,7 @@ public class BannerBlockEntityTranslator extends BlockEntityTranslator implement if (tag.contains("Patterns")) { ListTag patterns = tag.get("Patterns"); - tags.add(ItemUtils.convertBannerPattern(patterns)); + tags.add(BannerTranslator.convertBannerPattern(patterns)); } if (tag.contains("CustomName")) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntityTranslator.java index 4545aed5..3d663926 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntityTranslator.java @@ -32,12 +32,49 @@ import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.nukkitx.nbt.CompoundTagBuilder; import com.nukkitx.nbt.tag.Tag; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.utils.BlockEntityUtils; +import org.reflections.Reflections; +import java.util.HashMap; import java.util.List; +import java.util.Map; public abstract class BlockEntityTranslator { + public static final Map BLOCK_ENTITY_TRANSLATORS = new HashMap<>(); + public static ObjectArrayList REQUIRES_BLOCK_STATE_LIST = new ObjectArrayList<>(); + + protected BlockEntityTranslator() { + } + + public static void init() { + // no-op + } + + static { + Reflections ref = new Reflections("org.geysermc.connector.network.translators.world.block.entity"); + for (Class clazz : ref.getTypesAnnotatedWith(BlockEntity.class)) { + GeyserConnector.getInstance().getLogger().debug("Found annotated block entity: " + clazz.getCanonicalName()); + + try { + BLOCK_ENTITY_TRANSLATORS.put(clazz.getAnnotation(BlockEntity.class).name(), (BlockEntityTranslator) clazz.newInstance()); + } catch (InstantiationException | IllegalAccessException e) { + GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated block entity " + clazz.getCanonicalName() + "."); + } + } + for (Class clazz : ref.getSubTypesOf(RequiresBlockState.class)) { + GeyserConnector.getInstance().getLogger().debug("Found block entity that requires block state: " + clazz.getCanonicalName()); + + try { + REQUIRES_BLOCK_STATE_LIST.add((RequiresBlockState) clazz.newInstance()); + } catch (InstantiationException | IllegalAccessException e) { + GeyserConnector.getInstance().getLogger().error("Could not instantiate required block state " + clazz.getCanonicalName() + "."); + } + } + } + public abstract List> translateTag(CompoundTag tag, BlockState blockState); public abstract CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CampfireBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CampfireBlockEntityTranslator.java index eac87b04..cd31636c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CampfireBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CampfireBlockEntityTranslator.java @@ -30,9 +30,8 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.nukkitx.nbt.CompoundTagBuilder; import com.nukkitx.nbt.tag.Tag; - -import org.geysermc.connector.network.translators.Translators; import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.network.translators.item.ItemRegistry; import java.util.ArrayList; import java.util.HashMap; @@ -71,7 +70,7 @@ public class CampfireBlockEntityTranslator extends BlockEntityTranslator { } protected com.nukkitx.nbt.tag.CompoundTag getItem(CompoundTag tag) { - ItemEntry entry = Translators.getItemTranslator().getItemEntry((String) tag.get("id").getValue()); + ItemEntry entry = ItemRegistry.getItemEntry((String) tag.get("id").getValue()); CompoundTagBuilder tagBuilder = CompoundTagBuilder.builder() .shortTag("id", (short) entry.getBedrockId()) .byteTag("Count", (byte) tag.get("Count").getValue()) diff --git a/connector/src/main/java/org/geysermc/connector/utils/BlockEntityUtils.java b/connector/src/main/java/org/geysermc/connector/utils/BlockEntityUtils.java index da32b12b..038084c3 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/BlockEntityUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/BlockEntityUtils.java @@ -4,12 +4,11 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.Translators; import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator; public class BlockEntityUtils { - private static final BlockEntityTranslator EMPTY_TRANSLATOR = Translators.getBlockEntityTranslators().get("Empty"); + private static final BlockEntityTranslator EMPTY_TRANSLATOR = BlockEntityTranslator.BLOCK_ENTITY_TRANSLATORS.get("Empty"); public static String getBedrockBlockEntityId(String id) { // These are the only exceptions when it comes to block entity ids @@ -39,7 +38,7 @@ public class BlockEntityUtils { } public static BlockEntityTranslator getBlockEntityTranslator(String name) { - BlockEntityTranslator blockEntityTranslator = Translators.getBlockEntityTranslators().get(name); + BlockEntityTranslator blockEntityTranslator = BlockEntityTranslator.BLOCK_ENTITY_TRANSLATORS.get(name); if (blockEntityTranslator == null) { return EMPTY_TRANSLATOR; } diff --git a/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java b/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java index 41d0dc2d..010a87af 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java @@ -32,6 +32,9 @@ import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.nukkitx.math.vector.Vector2i; import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.nbt.CompoundTagBuilder; +import com.nukkitx.nbt.NbtUtils; +import com.nukkitx.nbt.stream.NBTOutputStream; import com.nukkitx.protocol.bedrock.packet.*; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; @@ -43,11 +46,12 @@ import org.geysermc.connector.entity.ItemFrameEntity; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.world.block.BlockStateValues; import org.geysermc.connector.network.translators.world.block.entity.*; -import org.geysermc.connector.network.translators.Translators; import org.geysermc.connector.network.translators.world.block.BlockTranslator; import org.geysermc.connector.network.translators.world.chunk.ChunkPosition; import org.geysermc.connector.network.translators.world.chunk.ChunkSection; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.util.HashMap; import java.util.Map; @@ -61,6 +65,23 @@ public class ChunkUtils { */ public static final Map CACHED_BLOCK_ENTITIES = new HashMap<>(); + private static final com.nukkitx.nbt.tag.CompoundTag EMPTY_TAG = CompoundTagBuilder.builder().buildRootTag(); + public static final byte[] EMPTY_LEVEL_CHUNK_DATA; + + static { + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + outputStream.write(new byte[258]); // Biomes + Border Size + Extra Data Size + + try (NBTOutputStream stream = NbtUtils.createNetworkWriter(outputStream)) { + stream.write(EMPTY_TAG); + } + + EMPTY_LEVEL_CHUNK_DATA = outputStream.toByteArray(); + }catch (IOException e) { + throw new AssertionError("Unable to generate empty level chunk data"); + } + } + public static ChunkData translateToBedrock(Column column) { ChunkData chunkData = new ChunkData(); Chunk[] chunks = column.getChunks(); @@ -194,7 +215,7 @@ public class ChunkUtils { // Since Java stores bed colors/skull information as part of the namespaced ID and Bedrock stores it as a tag // This is the only place I could find that interacts with the Java block state and block updates // Iterates through all block entity translators and determines if the block state needs to be saved - for (RequiresBlockState requiresBlockState : Translators.getRequiresBlockStateMap()) { + for (RequiresBlockState requiresBlockState : BlockEntityTranslator.REQUIRES_BLOCK_STATE_LIST) { if (requiresBlockState.isBlock(blockState)) { // Flower pots are block entities only in Bedrock and are not updated anywhere else like note blocks if (requiresBlockState instanceof BedrockOnlyBlockEntity) { @@ -217,7 +238,7 @@ public class ChunkUtils { data.setChunkX(chunkX + x); data.setChunkZ(chunkZ + z); data.setSubChunksLength(0); - data.setData(Translators.EMPTY_LEVEL_CHUNK_DATA); + data.setData(EMPTY_LEVEL_CHUNK_DATA); data.setCachingEnabled(false); session.sendUpstreamPacket(data); diff --git a/connector/src/main/java/org/geysermc/connector/utils/FileUtils.java b/connector/src/main/java/org/geysermc/connector/utils/FileUtils.java index dea42728..04b6ecc4 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/FileUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/FileUtils.java @@ -125,4 +125,18 @@ public class FileUtils { public static void writeFile(String name, char[] data) throws IOException { writeFile(new File(name), data); } + + /** + * Get an InputStream for the given resource path, throws AssertionError if resource is not found + * + * @param resource Resource to get + * @return InputStream of the given resource + */ + public static InputStream getResource(String resource) { + InputStream stream = FileUtils.class.getClassLoader().getResourceAsStream(resource); + if (stream == null) { + throw new AssertionError("Unable to find resource: " + resource); + } + return stream; + } } diff --git a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java index c0311b64..fd4c5e4e 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java @@ -36,9 +36,10 @@ import org.geysermc.common.ChatColor; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.Translators; import org.geysermc.connector.network.translators.inventory.DoubleChestInventoryTranslator; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; +import org.geysermc.connector.network.translators.item.ItemRegistry; +import org.geysermc.connector.network.translators.item.ItemTranslator; import java.util.Collections; import java.util.Objects; @@ -48,7 +49,7 @@ public class InventoryUtils { public static final ItemStack REFRESH_ITEM = new ItemStack(1, 127, new CompoundTag("")); //TODO: stop using this public static void openInventory(GeyserSession session, Inventory inventory) { - InventoryTranslator translator = Translators.getInventoryTranslators().get(inventory.getWindowType()); + InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType()); if (translator != null) { session.getInventoryCache().setOpenInventory(inventory); translator.prepareInventory(session, inventory); @@ -69,14 +70,14 @@ public class InventoryUtils { if (windowId != 0) { Inventory inventory = session.getInventoryCache().getInventories().get(windowId); if (inventory != null) { - InventoryTranslator translator = Translators.getInventoryTranslators().get(inventory.getWindowType()); + InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType()); translator.closeInventory(session, inventory); session.getInventoryCache().uncacheInventory(windowId); session.getInventoryCache().setOpenInventory(null); } } else { Inventory inventory = session.getInventory(); - InventoryTranslator translator = Translators.getInventoryTranslators().get(inventory.getWindowType()); + InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType()); translator.updateInventory(session, inventory); } session.setCraftSlot(0); @@ -87,7 +88,7 @@ public class InventoryUtils { InventorySlotPacket cursorPacket = new InventorySlotPacket(); cursorPacket.setContainerId(ContainerId.CURSOR); cursorPacket.setSlot(0); - cursorPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, session.getInventory().getCursor())); + cursorPacket.setItem(ItemTranslator.translateToBedrock(session.getInventory().getCursor())); session.sendUpstreamPacket(cursorPacket); } @@ -115,6 +116,6 @@ public class InventoryUtils { display.listTag("Lore", StringTag.class, Collections.singletonList(new StringTag("", ChatColor.RESET + ChatColor.DARK_PURPLE + description))); root.tag(display.build("display")); - return ItemData.of(Toolbox.ITEM_ENTRIES.get(Toolbox.BARRIER_INDEX).getBedrockId(), (short) 0, 1, root.buildRootTag()); + return ItemData.of(ItemRegistry.ITEM_ENTRIES.get(ItemRegistry.BARRIER_INDEX).getBedrockId(), (short) 0, 1, root.buildRootTag()); } } diff --git a/connector/src/main/java/org/geysermc/connector/utils/ItemUtils.java b/connector/src/main/java/org/geysermc/connector/utils/ItemUtils.java index d3fe48d9..b9600222 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/ItemUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/ItemUtils.java @@ -50,77 +50,4 @@ public class ItemUtils { } return 0; } - - /** - * Convert a list of patterns from Java nbt to Bedrock nbt - * - * @param patterns The patterns to convert - * @return The new converted patterns - */ - public static com.nukkitx.nbt.tag.ListTag convertBannerPattern(ListTag patterns) { - List tagsList = new ArrayList<>(); - for (com.github.steveice10.opennbt.tag.builtin.Tag patternTag : patterns.getValue()) { - com.nukkitx.nbt.tag.CompoundTag newPatternTag = getBedrockBannerPattern((CompoundTag) patternTag); - if (newPatternTag != null) { - tagsList.add(newPatternTag); - } - } - - return new com.nukkitx.nbt.tag.ListTag<>("Patterns", com.nukkitx.nbt.tag.CompoundTag.class, tagsList); - } - - /** - * Convert the Java edition banner pattern nbt to Bedrock edition, null if the pattern doesn't exist - * - * @param pattern Java edition pattern nbt - * @return The Bedrock edition format pattern nbt - */ - public static com.nukkitx.nbt.tag.CompoundTag getBedrockBannerPattern(CompoundTag pattern) { - String patternName = (String) pattern.get("Pattern").getValue(); - - // Return null if its the globe pattern as it doesn't exist on bedrock - if (patternName.equals("glb")) { - return null; - } - - return CompoundTagBuilder.builder() - .intTag("Color", 15 - (int) pattern.get("Color").getValue()) - .stringTag("Pattern", (String) pattern.get("Pattern").getValue()) - .stringTag("Pattern", patternName) - .buildRootTag(); - } - - /** - * Convert a list of patterns from Bedrock nbt to Java nbt - * - * @param patterns The patterns to convert - * @return The new converted patterns - */ - public static ListTag convertBannerPattern(com.nukkitx.nbt.tag.ListTag patterns) { - List tagsList = new ArrayList<>(); - for (Object patternTag : patterns.getValue()) { - CompoundTag newPatternTag = getJavaBannerPattern((com.nukkitx.nbt.tag.CompoundTag) patternTag); - if (newPatternTag != null) { - tagsList.add(newPatternTag); - } - } - - return new ListTag("Patterns", tagsList); - } - - /** - * Convert the Bedrock edition banner pattern nbt to Java edition - * - * @param pattern Bedorck edition pattern nbt - * @return The Java edition format pattern nbt - */ - public static CompoundTag getJavaBannerPattern(com.nukkitx.nbt.tag.CompoundTag pattern) { - String patternName = (String) pattern.get("Pattern").getValue(); - - Map tags = new HashMap<>(); - tags.put("Color", new IntTag("Color", 15 - pattern.getInt("Color"))); - tags.put("Pattern", new StringTag("Pattern", pattern.getString("Pattern"))); - - return new CompoundTag("", tags); - } } diff --git a/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java b/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java index 726ad1c1..f55cb261 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java @@ -63,7 +63,7 @@ public class LocaleUtils { private static void generateAssetCache() { try { // Get the version manifest from Mojang - VersionManifest versionManifest = Toolbox.JSON_MAPPER.readValue(WebUtils.getBody("https://launchermeta.mojang.com/mc/game/version_manifest.json"), VersionManifest.class); + VersionManifest versionManifest = GeyserConnector.JSON_MAPPER.readValue(WebUtils.getBody("https://launchermeta.mojang.com/mc/game/version_manifest.json"), VersionManifest.class); // Get the url for the latest version of the games manifest String latestInfoURL = ""; @@ -80,7 +80,7 @@ public class LocaleUtils { } // Get the individual version manifest - VersionInfo versionInfo = Toolbox.JSON_MAPPER.readValue(WebUtils.getBody(latestInfoURL), VersionInfo.class); + VersionInfo versionInfo = GeyserConnector.JSON_MAPPER.readValue(WebUtils.getBody(latestInfoURL), VersionInfo.class); // Get the smallest jar for use when downloading the en_us locale, will be either the server or client int currentSize = Integer.MAX_VALUE; @@ -92,13 +92,13 @@ public class LocaleUtils { } // Get the assets list - JsonNode assets = Toolbox.JSON_MAPPER.readTree(WebUtils.getBody(versionInfo.getAssetIndex().getUrl())).get("objects"); + JsonNode assets = GeyserConnector.JSON_MAPPER.readTree(WebUtils.getBody(versionInfo.getAssetIndex().getUrl())).get("objects"); // Put each asset into an array for use later Iterator> assetIterator = assets.fields(); while (assetIterator.hasNext()) { Map.Entry entry = assetIterator.next(); - Asset asset = Toolbox.JSON_MAPPER.treeToValue(entry.getValue(), Asset.class); + Asset asset = GeyserConnector.JSON_MAPPER.treeToValue(entry.getValue(), Asset.class); ASSET_MAP.put(entry.getKey(), asset); } } catch (Exception e) { @@ -173,7 +173,7 @@ public class LocaleUtils { // Parse the file as json JsonNode localeObj; try { - localeObj = Toolbox.JSON_MAPPER.readTree(localeStream); + localeObj = GeyserConnector.JSON_MAPPER.readTree(localeStream); } catch (Exception e) { throw new AssertionError("Unable to load Java edition lang map for " + locale, e); } diff --git a/connector/src/main/java/org/geysermc/connector/utils/SkinProvider.java b/connector/src/main/java/org/geysermc/connector/utils/SkinProvider.java index b14a9901..aea9ba18 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/SkinProvider.java +++ b/connector/src/main/java/org/geysermc/connector/utils/SkinProvider.java @@ -72,7 +72,7 @@ public class SkinProvider { static { /* Load in the normal ears geometry */ - InputStream earsStream = Toolbox.getResource("bedrock/skin/geometry.humanoid.ears.json"); + InputStream earsStream = FileUtils.getResource("bedrock/skin/geometry.humanoid.ears.json"); StringBuilder earsDataBuilder = new StringBuilder(); try (Reader reader = new BufferedReader(new InputStreamReader(earsStream, Charset.forName(StandardCharsets.UTF_8.name())))) { @@ -88,7 +88,7 @@ public class SkinProvider { /* Load in the slim ears geometry */ - earsStream = Toolbox.getResource("bedrock/skin/geometry.humanoid.earsSlim.json"); + earsStream = FileUtils.getResource("bedrock/skin/geometry.humanoid.earsSlim.json"); earsDataBuilder = new StringBuilder(); try (Reader reader = new BufferedReader(new InputStreamReader(earsStream, Charset.forName(StandardCharsets.UTF_8.name())))) { From d0545c57c454f72d639e27caa7339b1679a8d701 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Mon, 25 May 2020 22:57:10 +0100 Subject: [PATCH 51/73] Fix some fireworks colors and NPE of there is no NBT (#650) Adds Bukkit colors and an additional NPE check --- .../connector/entity/FireworkEntity.java | 8 +++--- .../connector/utils/FireworkColor.java | 27 ++++++++++++++++--- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java b/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java index 55d9c790..cb050e86 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java @@ -25,8 +25,6 @@ package org.geysermc.connector.entity; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; @@ -36,7 +34,6 @@ import com.nukkitx.math.vector.Vector3f; import com.nukkitx.nbt.CompoundTagBuilder; import com.nukkitx.protocol.bedrock.data.EntityData; import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket; -import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.utils.FireworkColor; @@ -57,6 +54,11 @@ public class FireworkEntity extends Entity { if (entityMetadata.getId() == 7) { ItemStack item = (ItemStack) entityMetadata.getValue(); CompoundTag tag = item.getNbt(); + + if (tag == null) { + return; + } + CompoundTag fireworks = tag.get("Fireworks"); CompoundTagBuilder fireworksBuilder = CompoundTagBuilder.builder(); diff --git a/connector/src/main/java/org/geysermc/connector/utils/FireworkColor.java b/connector/src/main/java/org/geysermc/connector/utils/FireworkColor.java index 2f393934..d729e3a1 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/FireworkColor.java +++ b/connector/src/main/java/org/geysermc/connector/utils/FireworkColor.java @@ -29,6 +29,7 @@ package org.geysermc.connector.utils; import lombok.Getter; public enum FireworkColor { + // Vanilla colors BLACK((byte) 0, 1973019), RED((byte) 1, 11743532), GREEN((byte) 2, 3887386), @@ -44,7 +45,27 @@ public enum FireworkColor { LIGHT_BLUE((byte) 12, 6719955), MAGENTA((byte) 13, 12801229), ORANGE((byte) 14, 15435844), - WHITE((byte) 15, 15790320); + WHITE((byte) 15, 15790320), + + // Bukkit colors + // https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Color.html + BUKKIT_WHITE((byte) 15, 0xFFFFFF), + BUKKIT_SILVER((byte) 7, 0xC0C0C0), + BUKKIT_GRAY((byte) 8, 0x808080), + BUKKIT_BLACK((byte) 0, 0x000000), + BUKKIT_RED((byte) 1, 0xFF0000), + BUKKIT_MAROON((byte) 1, 0x800000), // No perfect map but this is as close as it can be + BUKKIT_YELLOW((byte) 11, 0xFFFF00), + BUKKIT_OLIVE((byte) 2, 0x808000), // No perfect map but this is as close as it can be + BUKKIT_LIME((byte) 10, 0x00FF00), + BUKKIT_GREEN((byte) 2, 0x008000), + BUKKIT_AQUA((byte) 12, 0x00FFFF), + BUKKIT_TEAL((byte) 6, 0x008080), + BUKKIT_BLUE((byte) 4, 0x0000FF), + BUKKIT_NAVY((byte) 4, 0x000080), // No perfect map but this is as close as it can be + BUKKIT_FUCHSIA((byte) 9, 0xFF00FF), // No perfect map but this is as close as it can be + BUKKIT_PURPLE((byte) 5, 0x800080), + BUKKIT_ORANGE((byte) 14, 0xFFA500); private static final FireworkColor[] VALUES = values(); @@ -65,7 +86,7 @@ public enum FireworkColor { } } - return null; + return WHITE; } public static FireworkColor fromBedrockID(int id) { @@ -75,6 +96,6 @@ public enum FireworkColor { } } - return null; + return WHITE; } } From 0178492b593bab466d948409077c71e298cee051 Mon Sep 17 00:00:00 2001 From: Arktisfox <65837019+Arktisfox@users.noreply.github.com> Date: Mon, 25 May 2020 21:19:37 -0400 Subject: [PATCH 52/73] Fix some book translation failures (#661) Book pages can be sent as plain text rather than JSON. The text library doesn't use lenient parsing, so this fails, and the book isn't visible in the inventory. This will convert the text into JSON if it's not already, before feeding it to the text library. --- .../translators/nbt/BookPagesTranslator.java | 2 +- .../geysermc/connector/utils/MessageUtils.java | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BookPagesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BookPagesTranslator.java index 15279c7a..e802f017 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BookPagesTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BookPagesTranslator.java @@ -55,7 +55,7 @@ public class BookPagesTranslator extends NbtItemStackTranslator { CompoundTag pageTag = new CompoundTag(""); pageTag.put(new StringTag("photoname", "")); - pageTag.put(new StringTag("text", MessageUtils.getBedrockMessage(textTag.getValue()))); + pageTag.put(new StringTag("text", MessageUtils.getBedrockMessageLenient(textTag.getValue()))); pages.add(pageTag); } 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 3c924912..d79cdab8 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java @@ -137,6 +137,23 @@ public class MessageUtils { } } + /** + * Verifies the message is valid JSON in case it's plaintext. Works around GsonComponentSeraializer not using lenient mode. + * See https://wiki.vg/Chat for messages sent in lenient mode, and for a description on leniency. + * + * @param message Potentially lenient JSON message + * @return Bedrock formatted message + */ + public static String getBedrockMessageLenient(String message) { + if (isMessage(message)) { + return getBedrockMessage(message); + } else { + final JsonObject obj = new JsonObject(); + obj.addProperty("text", message); + return getBedrockMessage(obj.toString()); + } + } + public static String getBedrockMessage(String message) { Component component = phraseJavaMessage(message); return LegacyComponentSerializer.legacy().serialize(component); From cc6c7fe78dbb738985085312c721bbabc957ddcf Mon Sep 17 00:00:00 2001 From: bundabrg Date: Tue, 26 May 2020 11:35:26 +0800 Subject: [PATCH 53/73] When spawning don't add the player offset (#655) Fixes falling when logging in --- .../entity/player/JavaPlayerPositionRotationTranslator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java index ff6d41a1..37fb96fb 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java @@ -54,7 +54,7 @@ public class JavaPlayerPositionRotationTranslator extends PacketTranslator Date: Tue, 26 May 2020 11:39:57 +0800 Subject: [PATCH 54/73] Use authData UUID when sending playerlist packets to the client (#654) Bedrock knows its own UUID and when it receives the Java uuid it will either crash (MCEE) or add a ghost player onto the playerlist (Bedrock). This change will check if an entity is the client and if so replace the entities UUID with the AuthData UUID. A refactor of JavaPlayerListEntryTranslator was also done as I got confused each time what it was doing so it is now hopefully a bit clearer and also fixes the case where an entity is removed but still exists on the server (Vanished). --- .../player/JavaPlayerListEntryTranslator.java | 94 ++++++++++++------- .../geysermc/connector/utils/SkinUtils.java | 13 +++ 2 files changed, 75 insertions(+), 32 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerListEntryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerListEntryTranslator.java index 96dc6050..f387daec 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerListEntryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerListEntryTranslator.java @@ -42,47 +42,77 @@ import com.nukkitx.protocol.bedrock.packet.PlayerListPacket; public class JavaPlayerListEntryTranslator extends PacketTranslator { @Override public void translate(ServerPlayerListEntryPacket packet, GeyserSession session) { - if (packet.getAction() != PlayerListEntryAction.ADD_PLAYER && packet.getAction() != PlayerListEntryAction.REMOVE_PLAYER) return; + if (packet.getAction() != PlayerListEntryAction.ADD_PLAYER && packet.getAction() != PlayerListEntryAction.REMOVE_PLAYER) + return; PlayerListPacket translate = new PlayerListPacket(); translate.setAction(packet.getAction() == PlayerListEntryAction.ADD_PLAYER ? PlayerListPacket.Action.ADD : PlayerListPacket.Action.REMOVE); for (PlayerListEntry entry : packet.getEntries()) { - if (packet.getAction() == PlayerListEntryAction.ADD_PLAYER) { - boolean self = entry.getProfile().getId().equals(session.getPlayerEntity().getUuid()); + switch (packet.getAction()) { + case ADD_PLAYER: + PlayerEntity playerEntity; + boolean self = entry.getProfile().getId().equals(session.getPlayerEntity().getUuid()); + + if (self) { + // Entity is ourself + playerEntity = session.getPlayerEntity(); + SkinUtils.requestAndHandleSkinAndCape(playerEntity, session, skinAndCape -> { + GeyserConnector.getInstance().getLogger().debug("Loading Local Bedrock Java Skin Data"); + }); + } else { + playerEntity = session.getEntityCache().getPlayerEntity(entry.getProfile().getId()); + } + + if (playerEntity == null) { + // It's a new player + playerEntity = new PlayerEntity( + entry.getProfile(), + -1, + session.getEntityCache().getNextEntityId().incrementAndGet(), + Vector3f.ZERO, + Vector3f.ZERO, + Vector3f.ZERO + ); + } + + session.getEntityCache().addPlayerEntity(playerEntity); - PlayerEntity playerEntity = session.getPlayerEntity(); - if (self) { playerEntity.setProfile(entry.getProfile()); - SkinUtils.requestAndHandleSkinAndCape(playerEntity, session, skinAndCape -> { - GeyserConnector.getInstance().getLogger().debug("Loading Local Bedrock Java Skin Data"); - }); - } else { - playerEntity = new PlayerEntity( - entry.getProfile(), - -1, - session.getEntityCache().getNextEntityId().incrementAndGet(), - Vector3f.ZERO, - Vector3f.ZERO, - Vector3f.ZERO - ); - } + playerEntity.setPlayerList(true); + playerEntity.setValid(true); - playerEntity.setPlayerList(true); - playerEntity.setValid(true); - session.getEntityCache().addPlayerEntity(playerEntity); + PlayerListPacket.Entry playerListEntry = SkinUtils.buildCachedEntry(entry.getProfile(), playerEntity.getGeyserId()); + if (self) { + // Copy the entry with our identity instead. + PlayerListPacket.Entry copy = new PlayerListPacket.Entry(session.getAuthData().getUUID()); + copy.setName(playerListEntry.getName()); + copy.setEntityId(playerListEntry.getEntityId()); + copy.setSkin(playerListEntry.getSkin()); + copy.setXuid(playerListEntry.getXuid()); + copy.setPlatformChatId(playerListEntry.getPlatformChatId()); + copy.setTeacher(playerListEntry.isTeacher()); + playerListEntry = copy; + } - translate.getEntries().add(SkinUtils.buildCachedEntry(entry.getProfile(), playerEntity.getGeyserId())); - } else { - PlayerEntity entity = session.getEntityCache().getPlayerEntity(entry.getProfile().getId()); - if (entity != null && entity.isValid()) { - // remove from tablist but player entity is still there - entity.setPlayerList(false); - } else { - // just remove it from caching - session.getEntityCache().removePlayerEntity(entry.getProfile().getId()); - } - translate.getEntries().add(new PlayerListPacket.Entry(entry.getProfile().getId())); + translate.getEntries().add(playerListEntry); + break; + case REMOVE_PLAYER: + PlayerEntity entity = session.getEntityCache().getPlayerEntity(entry.getProfile().getId()); + if (entity != null && entity.isValid()) { + // remove from tablist but player entity is still there + entity.setPlayerList(false); + } else { + // just remove it from caching + if (entity == null) { + session.getEntityCache().removePlayerEntity(entry.getProfile().getId()); + } else { + entity.setPlayerList(false); + session.getEntityCache().removeEntity(entity, false); + } + } + translate.getEntries().add(new PlayerListPacket.Entry(entry.getProfile().getId())); + break; } } diff --git a/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java b/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java index 95a3ff19..48e4c4c8 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java @@ -218,6 +218,19 @@ public class SkinUtils { geometry.getGeometryData() ); + // If it is our skin we replace the UUID with the authdata UUID + if (session.getPlayerEntity() == entity) { + // Copy the entry with our identity instead. + PlayerListPacket.Entry copy = new PlayerListPacket.Entry(session.getAuthData().getUUID()); + copy.setName(updatedEntry.getName()); + copy.setEntityId(updatedEntry.getEntityId()); + copy.setSkin(updatedEntry.getSkin()); + copy.setXuid(updatedEntry.getXuid()); + copy.setPlatformChatId(updatedEntry.getPlatformChatId()); + copy.setTeacher(updatedEntry.isTeacher()); + updatedEntry = copy; + } + PlayerListPacket playerRemovePacket = new PlayerListPacket(); playerRemovePacket.setAction(PlayerListPacket.Action.REMOVE); playerRemovePacket.getEntries().add(updatedEntry); From 14fcd77925f2246ad5e526038d21a521c141dd8d Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Mon, 25 May 2020 23:43:29 -0400 Subject: [PATCH 55/73] Fix entities stacking on top of each other when mounted (#660) The offset was being called but not properly saved to a variable. The check will also not apply if there is only one mounted entity. --- .../JavaEntitySetPassengersTranslator.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntitySetPassengersTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntitySetPassengersTranslator.java index ad0d0f9e..912ee832 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntitySetPassengersTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntitySetPassengersTranslator.java @@ -82,7 +82,7 @@ public class JavaEntitySetPassengersTranslator extends PacketTranslator 1)); rider = false; } @@ -99,7 +99,7 @@ public class JavaEntitySetPassengersTranslator extends PacketTranslator 1)); } } @@ -111,8 +111,8 @@ public class JavaEntitySetPassengersTranslator extends PacketTranslator Date: Thu, 28 May 2020 16:38:23 +0100 Subject: [PATCH 56/73] Add byte conversion to allow int NBT values for Fireworks (#681) Firework NBT data might be either an int or byte and bedrock only takes it as a byte. Co-authored-by: Arktisfox <65837019+Arktisfox@users.noreply.github.com> --- .../connector/entity/FireworkEntity.java | 9 ++++---- .../translators/nbt/FireworkTranslator.java | 22 +++++++++++++------ .../geysermc/connector/utils/MathUtils.java | 15 +++++++++++++ 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java b/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java index cb050e86..1db4f757 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java @@ -37,6 +37,7 @@ import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.utils.FireworkColor; +import org.geysermc.connector.utils.MathUtils; import java.util.ArrayList; import java.util.List; @@ -63,7 +64,7 @@ public class FireworkEntity extends Entity { CompoundTagBuilder fireworksBuilder = CompoundTagBuilder.builder(); if (fireworks.get("Flight") != null) { - fireworksBuilder.byteTag("Flight", (Byte) fireworks.get("Flight").getValue()); + fireworksBuilder.byteTag("Flight", MathUtils.convertByte(fireworks.get("Flight").getValue())); } List explosions = new ArrayList<>(); @@ -73,7 +74,7 @@ public class FireworkEntity extends Entity { CompoundTagBuilder effectBuilder = CompoundTagBuilder.builder(); if (effectData.get("Type") != null) { - effectBuilder.byteTag("FireworkType", (Byte) effectData.get("Type").getValue()); + effectBuilder.byteTag("FireworkType", MathUtils.convertByte(effectData.get("Type").getValue())); } if (effectData.get("Colors") != null) { @@ -101,11 +102,11 @@ public class FireworkEntity extends Entity { } if (effectData.get("Trail") != null) { - effectBuilder.byteTag("FireworkTrail", (Byte) effectData.get("Trail").getValue()); + effectBuilder.byteTag("FireworkTrail", MathUtils.convertByte(effectData.get("Trail").getValue())); } if (effectData.get("Flicker") != null) { - effectBuilder.byteTag("FireworkFlicker", (Byte) effectData.get("Flicker").getValue()); + effectBuilder.byteTag("FireworkFlicker", MathUtils.convertByte(effectData.get("Flicker").getValue())); } explosions.add(effectBuilder.buildRootTag()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkTranslator.java index 268fe393..5b5182a5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkTranslator.java @@ -27,9 +27,10 @@ package org.geysermc.connector.network.translators.item.translators.nbt; import com.github.steveice10.opennbt.tag.builtin.*; 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; import org.geysermc.connector.utils.FireworkColor; +import org.geysermc.connector.utils.MathUtils; @ItemRemapper public class FireworkTranslator extends NbtItemStackTranslator { @@ -41,6 +42,10 @@ public class FireworkTranslator extends NbtItemStackTranslator { } CompoundTag fireworks = itemTag.get("Fireworks"); + if (fireworks.get("Flight") != null) { + fireworks.put(new ByteTag("Flight", MathUtils.convertByte(fireworks.get("Flight").getValue()))); + } + ListTag explosions = fireworks.get("Explosions"); if (explosions == null) { return; @@ -51,7 +56,7 @@ public class FireworkTranslator extends NbtItemStackTranslator { CompoundTag newEffectData = new CompoundTag(""); if (effectData.get("Type") != null) { - newEffectData.put(new ByteTag("FireworkType", (Byte) effectData.get("Type").getValue())); + newEffectData.put(new ByteTag("FireworkType", MathUtils.convertByte(effectData.get("Type").getValue()))); } if (effectData.get("Colors") != null) { @@ -79,11 +84,11 @@ public class FireworkTranslator extends NbtItemStackTranslator { } if (effectData.get("Trail") != null) { - newEffectData.put(new ByteTag("FireworkTrail", (Byte) effectData.get("Trail").getValue())); + newEffectData.put(new ByteTag("FireworkTrail", MathUtils.convertByte(effectData.get("Trail").getValue()))); } if (effectData.get("Flicker") != null) { - newEffectData.put(new ByteTag("FireworkFlicker", (Byte) effectData.get("Flicker").getValue())); + newEffectData.put(new ByteTag("FireworkFlicker", MathUtils.convertByte(effectData.get("Flicker").getValue()))); } explosions.remove(effect); @@ -94,6 +99,9 @@ public class FireworkTranslator extends NbtItemStackTranslator { @Override public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) { CompoundTag fireworks = itemTag.get("Fireworks"); + if (fireworks.get("Flight") != null) { + fireworks.put(new ByteTag("Flight", MathUtils.convertByte(fireworks.get("Flight").getValue()))); + } ListTag explosions = fireworks.get("Explosions"); for (Tag effect : explosions.getValue()) { @@ -102,7 +110,7 @@ public class FireworkTranslator extends NbtItemStackTranslator { CompoundTag newEffectData = new CompoundTag(""); if (effectData.get("FireworkType") != null) { - newEffectData.put(new ByteTag("Type", (Byte) effectData.get("FireworkType").getValue())); + newEffectData.put(new ByteTag("Type", MathUtils.convertByte(effectData.get("FireworkType").getValue()))); } if (effectData.get("FireworkColor") != null) { @@ -130,11 +138,11 @@ public class FireworkTranslator extends NbtItemStackTranslator { } if (effectData.get("FireworkTrail") != null) { - newEffectData.put(new ByteTag("Trail", (Byte) effectData.get("FireworkTrail").getValue())); + newEffectData.put(new ByteTag("Trail", MathUtils.convertByte(effectData.get("FireworkTrail").getValue()))); } if (effectData.get("FireworkFlicker") != null) { - newEffectData.put(new ByteTag("Flicker", (Byte) effectData.get("FireworkFlicker").getValue())); + newEffectData.put(new ByteTag("Flicker", MathUtils.convertByte(effectData.get("FireworkFlicker").getValue()))); } explosions.remove(effect); diff --git a/connector/src/main/java/org/geysermc/connector/utils/MathUtils.java b/connector/src/main/java/org/geysermc/connector/utils/MathUtils.java index 4e8497c6..f66e869d 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/MathUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/MathUtils.java @@ -37,4 +37,19 @@ public class MathUtils { int truncated = (int) floatNumber; return floatNumber > truncated ? truncated + 1 : truncated; } + + /** + * Converts the given object from an int or byte to byte. + * This is used for NBT data that might be either an int + * or byte and bedrock only takes it as an byte + * + * @param value The value to convert + * @return The converted byte + */ + public static Byte convertByte(Object value) { + if (value instanceof Integer) { + return ((Integer) value).byteValue(); + } + return (Byte) value; + } } From 3f76ae1d48e27f111ea91bc955af557d386eed0d Mon Sep 17 00:00:00 2001 From: rtm516 Date: Thu, 28 May 2020 16:43:31 +0100 Subject: [PATCH 57/73] Add ignore for ServerKeepAlivePacket (#664) This packet is already handled by MCProtocolLib for us. Co-authored-by: Camotoy <20743703+DoctorMacc@users.noreply.github.com> --- .../translators/PacketTranslatorRegistry.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/PacketTranslatorRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/PacketTranslatorRegistry.java index 13136331..c3ec8ff2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/PacketTranslatorRegistry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/PacketTranslatorRegistry.java @@ -25,18 +25,18 @@ package org.geysermc.connector.network.translators; -import java.util.HashMap; -import java.util.Map; - +import com.github.steveice10.mc.protocol.packet.ingame.server.ServerKeepAlivePacket; import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdateLightPacket; +import com.github.steveice10.packetlib.packet.Packet; +import com.nukkitx.protocol.bedrock.BedrockPacket; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.network.session.GeyserSession; - -import com.github.steveice10.packetlib.packet.Packet; -import com.nukkitx.protocol.bedrock.BedrockPacket; import org.reflections.Reflections; +import java.util.HashMap; +import java.util.Map; + public class PacketTranslatorRegistry { private final Map, PacketTranslator> translators = new HashMap<>(); @@ -72,7 +72,8 @@ public class PacketTranslatorRegistry { } } - IGNORED_PACKETS.add(ServerUpdateLightPacket.class); + IGNORED_PACKETS.add(ServerKeepAlivePacket.class); // Handled by MCProtocolLib + IGNORED_PACKETS.add(ServerUpdateLightPacket.class); // Light is handled on Bedrock for us } private PacketTranslatorRegistry() { From 5c8f6eb184d77eed8f82c83c46e9e15c793f4c88 Mon Sep 17 00:00:00 2001 From: Heath123 Date: Fri, 29 May 2020 20:11:38 +0100 Subject: [PATCH 58/73] Fix relative teleports (#688) --- .../JavaPlayerPositionRotationTranslator.java | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java index 37fb96fb..a44b200e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.connector.network.translators.java.entity.player; +import com.github.steveice10.mc.protocol.data.game.entity.player.PositionElement; import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientTeleportConfirmPacket; import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerPositionRotationPacket; import com.nukkitx.math.vector.Vector3f; @@ -95,20 +96,35 @@ public class JavaPlayerPositionRotationTranslator extends PacketTranslator 1.5 || (yDis < 1.45 || yDis > (session.isJumping() ? 4.3 : (session.isSprinting() ? 2.5 : 1.9))) || zDis > 1.5) { - session.setTeleportCache(new TeleportCache(packet.getX(), packet.getY(), packet.getZ(), packet.getTeleportId())); - entity.moveAbsolute(session, Vector3f.from(packet.getX(), packet.getY(), packet.getZ()), packet.getYaw(), packet.getPitch(), true, true); - } else { + if (!(xDis > 1.5 || (yDis < 1.45 || yDis > (session.isJumping() ? 4.3 : (session.isSprinting() ? 2.5 : 1.9))) || zDis > 1.5)) { + // Fake confirm the teleport but don't send it to the client ClientTeleportConfirmPacket teleportConfirmPacket = new ClientTeleportConfirmPacket(packet.getTeleportId()); session.sendDownstreamPacket(teleportConfirmPacket); + return; } } + + // If coordinates are relative, then add to the existing coordinate + double newX = packet.getX() + + (packet.getRelative().contains(PositionElement.X) ? entity.getPosition().getX() : 0); + double newY = packet.getY() + + (packet.getRelative().contains(PositionElement.Y) ? entity.getPosition().getY() - EntityType.PLAYER.getOffset() : 0); + double newZ = packet.getZ() + + (packet.getRelative().contains(PositionElement.Z) ? entity.getPosition().getZ() : 0); + + double newPitch = packet.getPitch() + + (packet.getRelative().contains(PositionElement.PITCH) ? entity.getBedrockRotation().getX() : 0); + double newYaw = packet.getYaw() + + (packet.getRelative().contains(PositionElement.YAW) ? entity.getBedrockRotation().getY() : 0); + + + session.setTeleportCache(new TeleportCache(newX, newY, newZ, packet.getTeleportId())); + entity.moveAbsolute(session, Vector3f.from(newX, newY, newZ), (float) newYaw, (float) newPitch, true, true); } } From 64e32046113e87bf37884c47e558a9f50317cb80 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Fri, 29 May 2020 19:56:21 -0400 Subject: [PATCH 59/73] Implement translator for AdventureSettingsPacket (#691) * Implement translator for AdventureSettingsPacket The AdventureSettingsPacket is translated into ClientSettingsPacket so the MAY_FLY and FLYING flags are sent to the server. This fixes double-jumping on some servers that rely on the client sending their flying information through this packet. * Remove top-secret code analysis --- .../BedrockAdventureSettingsTranslator.java | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAdventureSettingsTranslator.java diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAdventureSettingsTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAdventureSettingsTranslator.java new file mode 100644 index 00000000..75a1547f --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAdventureSettingsTranslator.java @@ -0,0 +1,51 @@ +/* + * 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.bedrock; + +import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; +import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerAbilitiesPacket; +import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.network.translators.Translator; + +@Translator(packet = AdventureSettingsPacket.class) +public class BedrockAdventureSettingsTranslator extends PacketTranslator { + + @Override + public void translate(AdventureSettingsPacket packet, GeyserSession session) { + // Only canFly and flying are used by the server + // https://wiki.vg/Protocol#Player_Abilities_.28serverbound.29 + boolean canFly = packet.getFlags().contains(AdventureSettingsPacket.Flag.MAY_FLY); + boolean flying = packet.getFlags().contains(AdventureSettingsPacket.Flag.FLYING); + boolean creative = session.getGameMode() == GameMode.CREATIVE; + ClientPlayerAbilitiesPacket abilitiesPacket = new ClientPlayerAbilitiesPacket( + false, canFly, flying, creative, 0.05f, 0.1f + ); + session.sendDownstreamPacket(abilitiesPacket); + } +} From b8a3009c9d763b5efb6098bd1f8f7d54521d15f8 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Sat, 30 May 2020 18:31:20 -0400 Subject: [PATCH 60/73] Ignore all downstream packet errors (#693) * Ignore all downstream packet errors Instead of kicking the client off because of an error, we simply display a logger warning and suppress the error. * If debug mode, print stacktrace --- connector/pom.xml | 2 +- .../geysermc/connector/network/session/GeyserSession.java | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/connector/pom.xml b/connector/pom.xml index 229761ad..5743c0c6 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -105,7 +105,7 @@ com.github.steveice10 packetlib - 1.5-SNAPSHOT + 1.6-SNAPSHOT compile diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index cc052509..ad5caf14 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -366,6 +366,14 @@ public class GeyserSession implements CommandSender { PacketTranslatorRegistry.JAVA_TRANSLATOR.translate(event.getPacket().getClass(), event.getPacket(), GeyserSession.this); } } + + @Override + public void packetError(PacketErrorEvent event) { + connector.getLogger().warning("Downstream packet error! " + event.getCause().getMessage()); + if (connector.getConfig().isDebugMode()) + event.getCause().printStackTrace(); + event.setSuppress(true); + } }); downstream.getSession().connect(); From b8615874f9b4b601b5fe39b36c2a242618d19406 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Mon, 1 Jun 2020 02:46:36 +0100 Subject: [PATCH 61/73] Add furnace minecart (#712) Adds the display of the furnace minecart, functions as expected. --- .../entity/FurnaceMinecartEntity.java | 54 +++++++++++++++++++ .../connector/entity/type/EntityType.java | 2 +- .../world/block/BlockTranslator.java | 23 ++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 connector/src/main/java/org/geysermc/connector/entity/FurnaceMinecartEntity.java diff --git a/connector/src/main/java/org/geysermc/connector/entity/FurnaceMinecartEntity.java b/connector/src/main/java/org/geysermc/connector/entity/FurnaceMinecartEntity.java new file mode 100644 index 00000000..ad2db877 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/entity/FurnaceMinecartEntity.java @@ -0,0 +1,54 @@ +/* + * 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; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.EntityData; +import org.geysermc.connector.entity.type.EntityType; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.world.block.BlockTranslator; + +public class FurnaceMinecartEntity extends MinecartEntity { + + public FurnaceMinecartEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { + super(entityId, geyserId, entityType, position, motion, rotation); + + metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(BlockTranslator.JAVA_RUNTIME_FURNACE_ID)); + metadata.put(EntityData.HAS_DISPLAY, (byte) 1); + } + + @Override + public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { + if (entityMetadata.getId() == 13) { + boolean hasFuel = (boolean) entityMetadata.getValue(); + + metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(hasFuel ? BlockTranslator.JAVA_RUNTIME_FURNACE_LIT_ID : BlockTranslator.JAVA_RUNTIME_FURNACE_ID)); + } + + super.updateBedrockMetadata(entityMetadata, 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 88934196..cbe8e4cc 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 @@ -133,7 +133,7 @@ public enum EntityType { MINECART_HOPPER(MinecartEntity.class, 96, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:hopper_minecart"), MINECART_TNT(MinecartEntity.class, 97, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:tnt_minecart"), MINECART_CHEST(MinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:chest_minecart"), - + MINECART_FURNACE(FurnaceMinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:minecart"), MINECART_COMMAND_BLOCK(MinecartEntity.class, 100, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:command_block_minecart"), LINGERING_POTION(ThrowableEntity.class, 101, 0f), LLAMA_SPIT(Entity.class, 102, 0.25f), diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java index a40dd15f..781dc326 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java @@ -69,6 +69,9 @@ public class BlockTranslator { public static final IntSet JAVA_RUNTIME_WOOL_IDS = new IntOpenHashSet(); public static final int JAVA_RUNTIME_COBWEB_ID; + public static final int JAVA_RUNTIME_FURNACE_ID; + public static final int JAVA_RUNTIME_FURNACE_LIT_ID; + private static final int BLOCK_STATE_VERSION = 17760256; static { @@ -108,6 +111,8 @@ public class BlockTranslator { int javaRuntimeId = -1; int bedrockRuntimeId = 0; int cobwebRuntimeId = -1; + int furnaceRuntimeId = -1; + int furnaceLitRuntimeId = -1; Iterator> blocksIterator = blocks.fields(); while (blocksIterator.hasNext()) { javaRuntimeId++; @@ -186,6 +191,14 @@ public class BlockTranslator { } JAVA_TO_BEDROCK_BLOCK_MAP.put(javaRuntimeId, bedrockRuntimeId); + if (javaId.startsWith("minecraft:furnace[facing=north")) { + if (javaId.contains("lit=true")) { + furnaceLitRuntimeId = javaRuntimeId; + } else { + furnaceRuntimeId = javaRuntimeId; + } + } + bedrockRuntimeId++; } @@ -194,6 +207,16 @@ public class BlockTranslator { } JAVA_RUNTIME_COBWEB_ID = cobwebRuntimeId; + if (furnaceRuntimeId == -1) { + throw new AssertionError("Unable to find furnace in palette"); + } + JAVA_RUNTIME_FURNACE_ID = furnaceRuntimeId; + + if (furnaceLitRuntimeId == -1) { + throw new AssertionError("Unable to find lit furnace in palette"); + } + JAVA_RUNTIME_FURNACE_LIT_ID = furnaceLitRuntimeId; + if (waterRuntimeId == -1) { throw new AssertionError("Unable to find water in palette"); } From 215e5a7e214f3cc429f077c37b83674c34210c39 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Sun, 31 May 2020 21:47:54 -0400 Subject: [PATCH 62/73] Add custom minecart metadata (#713) Adds display item, offset, and enable values. --- .../connector/entity/MinecartEntity.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java b/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java index ee004a25..c2d7d47d 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java @@ -30,6 +30,7 @@ import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.EntityData; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.world.block.BlockTranslator; public class MinecartEntity extends Entity { @@ -54,6 +55,22 @@ public class MinecartEntity extends Entity { metadata.put(EntityData.HURT_TIME, Math.min((int) (float) entityMetadata.getValue(), 15)); } + // Custom block + if (entityMetadata.getId() == 10) { + metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId((int) entityMetadata.getValue())); + } + + // Custom block offset + if (entityMetadata.getId() == 11) { + metadata.put(EntityData.DISPLAY_OFFSET, entityMetadata.getValue()); + } + + // If the custom block should be enabled + if (entityMetadata.getId() == 12) { + // Needs a byte based off of Java's boolean + metadata.put(EntityData.HAS_DISPLAY, (byte) ((boolean) entityMetadata.getValue() ? 1 : 0)); + } + super.updateBedrockMetadata(entityMetadata, session); } From ac5ab229f977176b078edbe21d682a8c32e8a92d Mon Sep 17 00:00:00 2001 From: rtm516 Date: Mon, 1 Jun 2020 20:57:27 +0100 Subject: [PATCH 63/73] Fix Ender Crystal collision and explosion effects (#716) Fixed the collision box being non-existent for ender crystals and fixed explosion effects not being displayed properly --- .../connector/entity/type/EntityType.java | 2 +- .../java/world/JavaExplosionTranslator.java | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) 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 cbe8e4cc..2cfe54c6 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 @@ -105,7 +105,7 @@ public enum EntityType { THROWN_EXP_BOTTLE(ThrowableEntity.class, 68, 0.25f, 0.25f, 0f, 0f, "minecraft:xp_bottle"), EXPERIENCE_ORB(ExpOrbEntity.class, 69, 0f, 0f, 0f, 0f, "minecraft:xp_orb"), EYE_OF_ENDER(Entity.class, 70, 0.25f, 0.25f, 0f, 0f, "minecraft:eye_of_ender_signal"), - END_CRYSTAL(EnderCrystalEntity.class, 71, 0f, 0f, 0f, 0f, "minecraft:ender_crystal"), + END_CRYSTAL(EnderCrystalEntity.class, 71, 2.0f, 2.0f, 2.0f, 0f, "minecraft:ender_crystal"), FIREWORK_ROCKET(FireworkEntity.class, 72, 0.25f, 0.25f, 0.25f, 0f, "minecraft:fireworks_rocket"), TRIDENT(TridentEntity.class, 73, 0f, 0f, 0f, 0f, "minecraft:thrown_trident"), TURTLE(AnimalEntity.class, 74, 0.4f, 1.2f), diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaExplosionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaExplosionTranslator.java index 49a17f98..79b27f6a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaExplosionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaExplosionTranslator.java @@ -46,14 +46,17 @@ public class JavaExplosionTranslator extends PacketTranslator= 2.0f ? LevelEventType.PARTICLE_HUGE_EXPLODE : LevelEventType.PARTICLE_LARGE_EXPLOSION); + levelEventPacket.setData(0); + levelEventPacket.setPosition(pos.toFloat()); + session.sendUpstreamPacket(levelEventPacket); + LevelSoundEventPacket levelSoundEventPacket = new LevelSoundEventPacket(); levelSoundEventPacket.setRelativeVolumeDisabled(false); levelSoundEventPacket.setBabySound(false); From 5bb345daa683ec0e755afc9ee0ab59f4087db337 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Mon, 1 Jun 2020 20:59:46 +0100 Subject: [PATCH 64/73] Fix new minecart with block breaking furnace minecart display (#717) This handles DISPLAY_ITEM and related properties separately on furnace minecarts in order to prevent overwriting furnace minecart graphics. Co-authored-by: DoctorMacc --- .../entity/FurnaceMinecartEntity.java | 38 +++++++++++++++++-- .../connector/entity/MinecartEntity.java | 26 +++++++------ 2 files changed, 49 insertions(+), 15 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/entity/FurnaceMinecartEntity.java b/connector/src/main/java/org/geysermc/connector/entity/FurnaceMinecartEntity.java index ad2db877..ad9be77f 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/FurnaceMinecartEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/FurnaceMinecartEntity.java @@ -34,6 +34,11 @@ import org.geysermc.connector.network.translators.world.block.BlockTranslator; public class FurnaceMinecartEntity extends MinecartEntity { + private int customBlock = 0; + private int customBlockOffset = 0; + private boolean showCustomBlock = false; + private boolean hasFuel = false; + public FurnaceMinecartEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); @@ -43,12 +48,39 @@ public class FurnaceMinecartEntity extends MinecartEntity { @Override public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getId() == 13) { - boolean hasFuel = (boolean) entityMetadata.getValue(); - metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(hasFuel ? BlockTranslator.JAVA_RUNTIME_FURNACE_LIT_ID : BlockTranslator.JAVA_RUNTIME_FURNACE_ID)); + // Custom block + if (entityMetadata.getId() == 10) { + customBlock = (int) entityMetadata.getValue(); + } + + // Custom block offset + if (entityMetadata.getId() == 11) { + customBlockOffset = (int) entityMetadata.getValue(); + } + + // If the custom block should be enabled + if (entityMetadata.getId() == 12) { + if ((boolean) entityMetadata.getValue()) { + showCustomBlock = true; + metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(customBlock)); + metadata.put(EntityData.DISPLAY_OFFSET, customBlockOffset); + } else { + showCustomBlock = false; + updateFurnaceMetadata(); + } + } + + if (entityMetadata.getId() == 13 && !showCustomBlock) { + hasFuel = (boolean) entityMetadata.getValue(); + updateFurnaceMetadata(); } super.updateBedrockMetadata(entityMetadata, session); } + + private void updateFurnaceMetadata() { + metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(hasFuel ? BlockTranslator.JAVA_RUNTIME_FURNACE_LIT_ID : BlockTranslator.JAVA_RUNTIME_FURNACE_ID)); + metadata.put(EntityData.DISPLAY_OFFSET, 6); + } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java b/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java index c2d7d47d..cdc3d8f2 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java @@ -55,20 +55,22 @@ public class MinecartEntity extends Entity { metadata.put(EntityData.HURT_TIME, Math.min((int) (float) entityMetadata.getValue(), 15)); } - // Custom block - if (entityMetadata.getId() == 10) { - metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId((int) entityMetadata.getValue())); - } + if (!(this instanceof FurnaceMinecartEntity)) { // Handled in FurnaceMinecartEntity.java + // Custom block + if (entityMetadata.getId() == 10) { + metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId((int) entityMetadata.getValue())); + } - // Custom block offset - if (entityMetadata.getId() == 11) { - metadata.put(EntityData.DISPLAY_OFFSET, entityMetadata.getValue()); - } + // Custom block offset + if (entityMetadata.getId() == 11) { + metadata.put(EntityData.DISPLAY_OFFSET, entityMetadata.getValue()); + } - // If the custom block should be enabled - if (entityMetadata.getId() == 12) { - // Needs a byte based off of Java's boolean - metadata.put(EntityData.HAS_DISPLAY, (byte) ((boolean) entityMetadata.getValue() ? 1 : 0)); + // If the custom block should be enabled + if (entityMetadata.getId() == 12) { + // Needs a byte based off of Java's boolean + metadata.put(EntityData.HAS_DISPLAY, (byte) ((boolean) entityMetadata.getValue() ? 1 : 0)); + } } super.updateBedrockMetadata(entityMetadata, session); From 05024dde8c9181209bccf8db5e3ccd986926f1e2 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Mon, 1 Jun 2020 18:19:16 -0800 Subject: [PATCH 65/73] Don't manually grab MCProtocolLib's dependencies (#720) * Don't manually grab MCProtocolLib's dependencies * Add netty-resolver-dns and exclude netty-all --- connector/pom.xml | 36 +++++------------------------------- 1 file changed, 5 insertions(+), 31 deletions(-) diff --git a/connector/pom.xml b/connector/pom.xml index 5743c0c6..9c503dcc 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -98,14 +98,8 @@ com.github.steveice10 - opennbt - 1.4-SNAPSHOT - compile - - - com.github.steveice10 - packetlib - 1.6-SNAPSHOT + mcprotocollib + 1.15.2-1-SNAPSHOT compile @@ -115,31 +109,11 @@ - com.github.steveice10 - mcauthlib - 1.3-SNAPSHOT + io.netty + netty-resolver-dns + 4.1.43.Final compile - - com.github.steveice10 - mcprotocollib - 1.15.2-1-SNAPSHOT - compile - - - com.github.steveice10 - opennbt - - - com.github.steveice10 - packetlib - - - com.github.steveice10 - mcauthlib - - - org.reflections reflections From 18891a22f1f2e1fba0b5c9fe38570a186c1480b3 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Tue, 2 Jun 2020 10:45:33 -0400 Subject: [PATCH 66/73] Check for instance of TranslationMessage (#722) Checks for class of custom name ID in case it's translation message. --- .../java/org/geysermc/connector/entity/Entity.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) 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 434c983b..06679934 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/Entity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/Entity.java @@ -34,6 +34,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction; import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace; import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.github.steveice10.mc.protocol.data.message.TextMessage; +import com.github.steveice10.mc.protocol.data.message.TranslationMessage; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerUseItemPacket; import com.nukkitx.math.vector.Vector3f; @@ -253,9 +254,15 @@ public class Entity { } break; case 2: // custom name - TextMessage name = (TextMessage) entityMetadata.getValue(); - if (name != null) - metadata.put(EntityData.NAMETAG, MessageUtils.getBedrockMessage(name)); + if (entityMetadata.getValue() instanceof TextMessage) { + TextMessage name = (TextMessage) entityMetadata.getValue(); + if (name != null) + metadata.put(EntityData.NAMETAG, MessageUtils.getBedrockMessage(name)); + } else if (entityMetadata.getValue() instanceof TranslationMessage) { + TranslationMessage message = (TranslationMessage) entityMetadata.getValue(); + if (message != null) + metadata.put(EntityData.NAMETAG, MessageUtils.getTranslatedBedrockMessage(message, session.getClientData().getLanguageCode(), true)); + } break; case 3: // is custom name visible if (!this.is(PlayerEntity.class)) From 3d357af739747fcb1afa9bcbd21f52861a6402d5 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Tue, 2 Jun 2020 08:48:26 -0800 Subject: [PATCH 67/73] Inventory Fixes (#602) * Fix edge case when shift clicking an output slot * Don't send window close packet if window is already closed * Limit amount of window close packets sent to the client Fixes hidden inventory bar bug * Restrict user from unusable chest inventory slots * Fix crafting table slot mappings * Always send cursor update --- .../network/session/GeyserSession.java | 3 + .../BedrockContainerCloseTranslator.java | 14 ++-- .../inventory/ChestInventoryTranslator.java | 69 +++++++++++++++++++ .../CraftingInventoryTranslator.java | 5 +- .../DoubleChestInventoryTranslator.java | 16 +---- .../SingleChestInventoryTranslator.java | 30 +++++++- .../action/InventoryActionDataTranslator.java | 14 +++- .../window/JavaCloseWindowTranslator.java | 5 +- .../java/window/JavaOpenWindowTranslator.java | 7 +- .../java/window/JavaSetSlotTranslator.java | 2 - .../connector/utils/InventoryUtils.java | 20 +++++- 11 files changed, 149 insertions(+), 36 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index ad5caf14..a40443a5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -166,6 +166,9 @@ public class GeyserSession implements CommandSender { @Setter private int craftSlot = 0; + @Setter + private long lastWindowCloseTime = 0; + private MinecraftProtocol protocol; public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServerSession) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java index 6f4a243f..05eac203 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java @@ -38,17 +38,23 @@ public class BedrockContainerCloseTranslator extends PacketTranslator actions) { + for (InventoryActionData action : actions) { + if (action.getSource().getContainerId() == inventory.getId()) { + if (action.getSlot() >= size) { + updateInventory(session, inventory); + InventoryUtils.updateCursor(session); + return; + } + } + } + + super.translateActions(session, inventory, actions); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java index 3f887001..e31eb1e3 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java @@ -92,7 +92,10 @@ public class CraftingInventoryTranslator extends BaseInventoryTranslator { @Override public int javaSlotToBedrock(int slot) { - return slot == 0 ? 50 : slot + 31; + if (slot < size) { + return slot == 0 ? 50 : slot + 31; + } + return super.javaSlotToBedrock(slot); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java index 8c5b2cf2..6d6cadd7 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java @@ -39,15 +39,13 @@ import org.geysermc.connector.network.translators.world.block.BlockTranslator; import org.geysermc.connector.network.translators.inventory.updater.ChestInventoryUpdater; import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; -public class DoubleChestInventoryTranslator extends BaseInventoryTranslator { +public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { private final int blockId; - private final InventoryUpdater updater; public DoubleChestInventoryTranslator(int size) { - super(size); + super(size, 54); BlockState javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]"); this.blockId = BlockTranslator.getBedrockBlockId(javaBlockState); - this.updater = new ChestInventoryUpdater(54); } @Override @@ -128,14 +126,4 @@ public class DoubleChestInventoryTranslator extends BaseInventoryTranslator { blockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(realBlock)); session.sendUpstreamPacket(blockPacket); } - - @Override - public void updateInventory(GeyserSession session, Inventory inventory) { - updater.updateInventory(this, session, inventory); - } - - @Override - public void updateSlot(GeyserSession session, Inventory inventory, int slot) { - updater.updateSlot(this, session, inventory, slot); - } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java index 5c99b012..3f1a58f4 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java @@ -25,11 +25,35 @@ package org.geysermc.connector.network.translators.inventory; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.nukkitx.protocol.bedrock.data.ContainerType; -import org.geysermc.connector.network.translators.inventory.updater.ChestInventoryUpdater; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.inventory.holder.BlockInventoryHolder; +import org.geysermc.connector.network.translators.inventory.holder.InventoryHolder; +import org.geysermc.connector.network.translators.world.block.BlockTranslator; + +public class SingleChestInventoryTranslator extends ChestInventoryTranslator { + private final InventoryHolder holder; -public class SingleChestInventoryTranslator extends BlockInventoryTranslator { public SingleChestInventoryTranslator(int size) { - super(size, "minecraft:chest[facing=north,type=single,waterlogged=false]", ContainerType.CONTAINER, new ChestInventoryUpdater(27)); + super(size, 27); + BlockState javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]"); + this.holder = new BlockInventoryHolder(BlockTranslator.getBedrockBlockId(javaBlockState), ContainerType.CONTAINER); + } + + @Override + public void prepareInventory(GeyserSession session, Inventory inventory) { + holder.prepareInventory(this, session, inventory); + } + + @Override + public void openInventory(GeyserSession session, Inventory inventory) { + holder.openInventory(this, session, inventory); + } + + @Override + public void closeInventory(GeyserSession session, Inventory inventory) { + holder.closeInventory(this, session, inventory); } } 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 9139da1f..41b218b0 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 @@ -187,11 +187,12 @@ public class InventoryActionDataTranslator { } else if (translator.getSlotType(javaSlot) == SlotType.OUTPUT) { plan.add(Click.LEFT, javaSlot); } else { - int cursorSlot = findTempSlot(inventory, session.getInventory().getCursor(), Collections.singletonList(javaSlot)); + int cursorSlot = findTempSlot(inventory, session.getInventory().getCursor(), Collections.singletonList(javaSlot), false); if (cursorSlot != -1) { plan.add(Click.LEFT, cursorSlot); } else { translator.updateInventory(session, inventory); + InventoryUtils.updateCursor(session); return; } plan.add(Click.LEFT, javaSlot); @@ -245,11 +246,15 @@ public class InventoryActionDataTranslator { int cursorSlot = -1; if (session.getInventory().getCursor() != null) { //move cursor contents to a temporary slot - cursorSlot = findTempSlot(inventory, session.getInventory().getCursor(), Arrays.asList(fromSlot, toSlot)); + cursorSlot = findTempSlot(inventory, + session.getInventory().getCursor(), + Arrays.asList(fromSlot, toSlot), + translator.getSlotType(fromSlot) == SlotType.OUTPUT); if (cursorSlot != -1) { plan.add(Click.LEFT, cursorSlot); } else { translator.updateInventory(session, inventory); + InventoryUtils.updateCursor(session); return; } } @@ -298,7 +303,7 @@ public class InventoryActionDataTranslator { InventoryUtils.updateCursor(session); } - private static int findTempSlot(Inventory inventory, ItemStack item, List slotBlacklist) { + private static int findTempSlot(Inventory inventory, ItemStack item, List slotBlacklist, boolean emptyOnly) { /*try and find a slot that can temporarily store the given item only look in the main inventory and hotbar only slots that are empty or contain a different type of item are valid*/ @@ -314,6 +319,9 @@ public class InventoryActionDataTranslator { ItemStack testItem = inventory.getItem(i); boolean acceptable = true; if (testItem != null) { + if (emptyOnly) { + continue; + } for (ItemStack blacklistItem : itemBlacklist) { if (InventoryUtils.canStack(testItem, blacklistItem)) { acceptable = false; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java index 7360cbb2..93cfa08e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java @@ -26,7 +26,6 @@ package org.geysermc.connector.network.translators.java.window; import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerCloseWindowPacket; -import com.nukkitx.protocol.bedrock.packet.ContainerClosePacket; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; @@ -37,9 +36,7 @@ public class JavaCloseWindowTranslator extends PacketTranslator { @@ -80,8 +78,11 @@ public class JavaOpenWindowTranslator extends PacketTranslator InventoryUtils.openInventory(session, newInventory), 500, TimeUnit.MILLISECONDS); + session.getInventoryCache().setOpenInventory(newInventory); + //The new window will be opened when the bedrock client sends the + //window close confirmation in BedrockContainerCloseTranslator return; } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java index 5d44069f..19d7db21 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java @@ -41,8 +41,6 @@ public class JavaSetSlotTranslator extends PacketTranslator @Override public void translate(ServerSetSlotPacket packet, GeyserSession session) { if (packet.getWindowId() == 255 && packet.getSlot() == -1) { //cursor - if (Objects.equals(session.getInventory().getCursor(), packet.getItem())) - return; if (session.getCraftSlot() != 0) return; diff --git a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java index fd4c5e4e..187d0951 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java @@ -31,6 +31,7 @@ import com.nukkitx.nbt.CompoundTagBuilder; import com.nukkitx.nbt.tag.StringTag; import com.nukkitx.protocol.bedrock.data.ContainerId; import com.nukkitx.protocol.bedrock.data.ItemData; +import com.nukkitx.protocol.bedrock.packet.ContainerClosePacket; import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import org.geysermc.common.ChatColor; import org.geysermc.connector.GeyserConnector; @@ -69,19 +70,34 @@ public class InventoryUtils { public static void closeInventory(GeyserSession session, int windowId) { if (windowId != 0) { Inventory inventory = session.getInventoryCache().getInventories().get(windowId); - if (inventory != null) { + Inventory openInventory = session.getInventoryCache().getOpenInventory(); + session.getInventoryCache().uncacheInventory(windowId); + if (inventory != null && openInventory != null && inventory.getId() == openInventory.getId()) { InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType()); translator.closeInventory(session, inventory); - session.getInventoryCache().uncacheInventory(windowId); session.getInventoryCache().setOpenInventory(null); + } else { + return; } } else { Inventory inventory = session.getInventory(); InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType()); translator.updateInventory(session, inventory); } + session.setCraftSlot(0); session.getInventory().setCursor(null); + updateCursor(session); + } + + public static void closeWindow(GeyserSession session, int windowId) { + //Spamming close window packets can bug the client + if (System.currentTimeMillis() - session.getLastWindowCloseTime() > 500) { + ContainerClosePacket closePacket = new ContainerClosePacket(); + closePacket.setWindowId((byte) windowId); + session.sendUpstreamPacket(closePacket); + session.setLastWindowCloseTime(System.currentTimeMillis()); + } } public static void updateCursor(GeyserSession session) { From a91eaa7821f0db4d00a6b6216dca93f543510d66 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Tue, 2 Jun 2020 21:33:37 +0100 Subject: [PATCH 68/73] Add item name translation (#559) * Added item name translation * Change to more appropriate NPE catch * Remove whitespace * Switch from try/catch to null checking * Update mappings Co-authored-by: DoctorMacc --- .../geysermc/connector/entity/ItemEntity.java | 2 +- .../connector/entity/ItemFrameEntity.java | 2 +- .../inventory/PlayerInventoryTranslator.java | 14 +++---- .../action/InventoryActionDataTranslator.java | 4 +- .../updater/ChestInventoryUpdater.java | 4 +- .../updater/ContainerInventoryUpdater.java | 4 +- .../updater/CursorInventoryUpdater.java | 4 +- .../inventory/updater/InventoryUpdater.java | 4 +- .../translators/item/ItemTranslator.java | 40 +++++++++++++++++-- .../java/JavaDeclareRecipesTranslator.java | 8 ++-- .../entity/JavaEntityEquipmentTranslator.java | 2 +- .../world/JavaSpawnParticleTranslator.java | 2 +- .../connector/utils/InventoryUtils.java | 2 +- 13 files changed, 63 insertions(+), 29 deletions(-) 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 bd18dc46..41308a0d 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(ItemTranslator.translateToBedrock((ItemStack) entityMetadata.getValue())); + itemPacket.setItemInHand(ItemTranslator.translateToBedrock(session, (ItemStack) entityMetadata.getValue())); session.sendUpstreamPacket(itemPacket); } diff --git a/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java b/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java index a6d8af15..3680945c 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java @@ -98,7 +98,7 @@ public class ItemFrameEntity extends Entity { @Override public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { if (entityMetadata.getId() == 7 && entityMetadata.getValue() != null) { - ItemData itemData = ItemTranslator.translateToBedrock((ItemStack) entityMetadata.getValue()); + ItemData itemData = ItemTranslator.translateToBedrock(session, (ItemStack) entityMetadata.getValue()); ItemEntry itemEntry = ItemRegistry.getItem((ItemStack) entityMetadata.getValue()); CompoundTagBuilder builder = CompoundTag.builder(); 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 055b69ef..28986e58 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 @@ -59,11 +59,11 @@ public class PlayerInventoryTranslator extends InventoryTranslator { ItemData[] contents = new ItemData[36]; // Inventory for (int i = 9; i < 36; i++) { - contents[i] = ItemTranslator.translateToBedrock(inventory.getItem(i)); + contents[i] = ItemTranslator.translateToBedrock(session, inventory.getItem(i)); } // Hotbar for (int i = 36; i < 45; i++) { - contents[i - 36] = ItemTranslator.translateToBedrock(inventory.getItem(i)); + contents[i - 36] = ItemTranslator.translateToBedrock(session, inventory.getItem(i)); } inventoryContentPacket.setContents(contents); session.sendUpstreamPacket(inventoryContentPacket); @@ -73,7 +73,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { armorContentPacket.setContainerId(ContainerId.ARMOR); contents = new ItemData[4]; for (int i = 5; i < 9; i++) { - contents[i - 5] = ItemTranslator.translateToBedrock(inventory.getItem(i)); + contents[i - 5] = ItemTranslator.translateToBedrock(session, inventory.getItem(i)); } armorContentPacket.setContents(contents); session.sendUpstreamPacket(armorContentPacket); @@ -81,7 +81,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { // Offhand InventoryContentPacket offhandPacket = new InventoryContentPacket(); offhandPacket.setContainerId(ContainerId.OFFHAND); - offhandPacket.setContents(new ItemData[]{ItemTranslator.translateToBedrock(inventory.getItem(45))}); + offhandPacket.setContents(new ItemData[]{ItemTranslator.translateToBedrock(session, inventory.getItem(45))}); session.sendUpstreamPacket(offhandPacket); } @@ -100,7 +100,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { if (session.getGameMode() == GameMode.CREATIVE) { slotPacket.setItem(UNUSUABLE_CRAFTING_SPACE_BLOCK); }else{ - slotPacket.setItem(ItemTranslator.translateToBedrock(inventory.getItem(i))); + slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(i))); } session.sendUpstreamPacket(slotPacket); @@ -125,12 +125,12 @@ public class PlayerInventoryTranslator extends InventoryTranslator { slotPacket.setContainerId(ContainerId.CURSOR); slotPacket.setSlot(slot + 27); } - slotPacket.setItem(ItemTranslator.translateToBedrock(inventory.getItem(slot))); + slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(slot))); session.sendUpstreamPacket(slotPacket); } else if (slot == 45) { InventoryContentPacket offhandPacket = new InventoryContentPacket(); offhandPacket.setContainerId(ContainerId.OFFHAND); - offhandPacket.setContents(new ItemData[]{ItemTranslator.translateToBedrock(inventory.getItem(slot))}); + offhandPacket.setContents(new ItemData[]{ItemTranslator.translateToBedrock(session, inventory.getItem(slot))}); session.sendUpstreamPacket(offhandPacket); } } 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 41b218b0..209df074 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 = ItemTranslator.translateToBedrock(session.getInventory().getCursor()); + ItemData translatedCursor = ItemTranslator.translateToBedrock(session, session.getInventory().getCursor()); if (!translatedCursor.equals(action.getFromItem())) { refresh = true; } } else { containerAction = action; - ItemData translatedItem = ItemTranslator.translateToBedrock(inventory.getItem(translator.bedrockSlotToJava(action))); + ItemData translatedItem = ItemTranslator.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 61bbda50..6ec8d481 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 @@ -49,7 +49,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] = ItemTranslator.translateToBedrock(inventory.getItem(i)); + bedrockItems[i] = ItemTranslator.translateToBedrock(session, inventory.getItem(i)); } else { bedrockItems[i] = UNUSUABLE_SPACE_BLOCK; } @@ -69,7 +69,7 @@ public class ChestInventoryUpdater extends InventoryUpdater { InventorySlotPacket slotPacket = new InventorySlotPacket(); slotPacket.setContainerId(inventory.getId()); slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); - slotPacket.setItem(ItemTranslator.translateToBedrock(inventory.getItem(javaSlot))); + slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot))); session.sendUpstreamPacket(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 e84c2931..ec6175c3 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)] = ItemTranslator.translateToBedrock(inventory.getItem(i)); + bedrockItems[translator.javaSlotToBedrock(i)] = ItemTranslator.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(ItemTranslator.translateToBedrock(inventory.getItem(javaSlot))); + slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot))); session.sendUpstreamPacket(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 aa7a0174..adbbdbac 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(ItemTranslator.translateToBedrock(inventory.getItem(i))); + slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(i))); session.sendUpstreamPacket(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(ItemTranslator.translateToBedrock(inventory.getItem(javaSlot))); + slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot))); session.sendUpstreamPacket(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 9710d805..88157df0 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] = ItemTranslator.translateToBedrock(inventory.getItem(translator.size + i + offset)); + bedrockItems[i] = ItemTranslator.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(ItemTranslator.translateToBedrock(inventory.getItem(javaSlot))); + slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot))); session.sendUpstreamPacket(slotPacket); return true; } 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 490681d8..273226fe 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 @@ -27,6 +27,8 @@ 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.nukkitx.nbt.CompoundTagBuilder; import com.github.steveice10.opennbt.tag.builtin.*; import com.nukkitx.nbt.tag.CompoundTag; import com.nukkitx.nbt.tag.Tag; @@ -34,7 +36,9 @@ 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.network.session.GeyserSession; import org.geysermc.connector.network.translators.ItemRemapper; +import org.geysermc.connector.utils.MessageUtils; import org.reflections.Reflections; import java.util.ArrayList; @@ -115,7 +119,7 @@ public abstract class ItemTranslator { return itemStack; } - public static ItemData translateToBedrock(ItemStack stack) { + public static ItemData translateToBedrock(GeyserSession session, ItemStack stack) { if (stack == null) { return ItemData.AIR; } @@ -132,12 +136,42 @@ public abstract class ItemTranslator { } } + ItemData itemData; ItemTranslator itemStackTranslator = ITEM_STACK_TRANSLATORS.get(bedrockItem.getJavaId()); if (itemStackTranslator != null) { - return itemStackTranslator.translateToBedrock(itemStack, bedrockItem); + itemData = itemStackTranslator.translateToBedrock(itemStack, bedrockItem); } else { - return DEFAULT_TRANSLATOR.translateToBedrock(itemStack, bedrockItem); + itemData = DEFAULT_TRANSLATOR.translateToBedrock(itemStack, bedrockItem); } + + + // Get the display name of the item + CompoundTag tag = itemData.getTag(); + if (tag != null) { + CompoundTag display = tag.getCompound("display"); + if (display != null) { + String name = display.getString("Name"); + + // Check if its a message to translate + if (MessageUtils.isMessage(name)) { + // Get the translated name + name = MessageUtils.getTranslatedBedrockMessage(Message.fromString(name), session.getClientData().getLanguageCode()); + + // Build the new display tag + CompoundTagBuilder displayBuilder = display.toBuilder(); + displayBuilder.stringTag("Name", name); + + // Build the new root tag + CompoundTagBuilder builder = tag.toBuilder(); + builder.tag(displayBuilder.build("display")); + + // Create a new item with the original data + updated name + itemData = ItemData.of(itemData.getId(), itemData.getDamage(), itemData.getCount(), builder.buildRootTag()); + } + } + } + + return itemData; } private static final ItemTranslator DEFAULT_TRANSLATOR = new ItemTranslator() { 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 7763a2c1..b0637722 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,7 +64,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator> groupedByIds = Arrays.stream(ingredient.getOptions()) - .map(ItemTranslator::translateToBedrock) + .map(item -> ItemTranslator.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] = ItemTranslator.translateToBedrock(ingredients[i].getOptions()[0]); + translatedItems[i] = ItemTranslator.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 e977e9b0..8918217a 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 Date: Wed, 3 Jun 2020 00:16:04 +0100 Subject: [PATCH 69/73] Fix display of some more entities (#726) * Fix display of Evoker and Evoker Fangs * Fix spawner minecart display * Centeralise custom blocks for spawner and furnace minecarts * Add comment explaining class --- .../entity/DefaultBlockMinecartEntity.java | 88 +++++++++++++++++++ .../entity/FurnaceMinecartEntity.java | 36 +------- .../connector/entity/MinecartEntity.java | 2 +- .../entity/SpawnerMinecartEntity.java | 44 ++++++++++ .../connector/entity/type/EntityType.java | 5 +- .../world/block/BlockTranslator.java | 12 +++ 6 files changed, 152 insertions(+), 35 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/entity/DefaultBlockMinecartEntity.java create mode 100644 connector/src/main/java/org/geysermc/connector/entity/SpawnerMinecartEntity.java diff --git a/connector/src/main/java/org/geysermc/connector/entity/DefaultBlockMinecartEntity.java b/connector/src/main/java/org/geysermc/connector/entity/DefaultBlockMinecartEntity.java new file mode 100644 index 00000000..b774af98 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/entity/DefaultBlockMinecartEntity.java @@ -0,0 +1,88 @@ +/* + * 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; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.EntityData; +import org.geysermc.connector.entity.type.EntityType; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.world.block.BlockTranslator; + +/** + * This class is used as a base for minecarts with a default block to display like furnaces and spawners + */ +public class DefaultBlockMinecartEntity extends MinecartEntity { + + public int customBlock = 0; + public int customBlockOffset = 0; + public boolean showCustomBlock = false; + + public DefaultBlockMinecartEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { + super(entityId, geyserId, entityType, position, motion, rotation); + + updateDefaultBlockMetadata(); + metadata.put(EntityData.HAS_DISPLAY, (byte) 1); + } + + @Override + public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { + + // Custom block + if (entityMetadata.getId() == 10) { + customBlock = (int) entityMetadata.getValue(); + + if (showCustomBlock) { + metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(customBlock)); + } + } + + // Custom block offset + if (entityMetadata.getId() == 11) { + customBlockOffset = (int) entityMetadata.getValue(); + + if (showCustomBlock) { + metadata.put(EntityData.DISPLAY_OFFSET, customBlockOffset); + } + } + + // If the custom block should be enabled + if (entityMetadata.getId() == 12) { + if ((boolean) entityMetadata.getValue()) { + showCustomBlock = true; + metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(customBlock)); + metadata.put(EntityData.DISPLAY_OFFSET, customBlockOffset); + } else { + showCustomBlock = false; + updateDefaultBlockMetadata(); + } + } + + super.updateBedrockMetadata(entityMetadata, session); + } + + public void updateDefaultBlockMetadata() { } +} diff --git a/connector/src/main/java/org/geysermc/connector/entity/FurnaceMinecartEntity.java b/connector/src/main/java/org/geysermc/connector/entity/FurnaceMinecartEntity.java index ad9be77f..29ade193 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/FurnaceMinecartEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/FurnaceMinecartEntity.java @@ -32,54 +32,26 @@ import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.world.block.BlockTranslator; -public class FurnaceMinecartEntity extends MinecartEntity { +public class FurnaceMinecartEntity extends DefaultBlockMinecartEntity { - private int customBlock = 0; - private int customBlockOffset = 0; - private boolean showCustomBlock = false; private boolean hasFuel = false; public FurnaceMinecartEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); - - metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(BlockTranslator.JAVA_RUNTIME_FURNACE_ID)); - metadata.put(EntityData.HAS_DISPLAY, (byte) 1); } @Override public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - - // Custom block - if (entityMetadata.getId() == 10) { - customBlock = (int) entityMetadata.getValue(); - } - - // Custom block offset - if (entityMetadata.getId() == 11) { - customBlockOffset = (int) entityMetadata.getValue(); - } - - // If the custom block should be enabled - if (entityMetadata.getId() == 12) { - if ((boolean) entityMetadata.getValue()) { - showCustomBlock = true; - metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(customBlock)); - metadata.put(EntityData.DISPLAY_OFFSET, customBlockOffset); - } else { - showCustomBlock = false; - updateFurnaceMetadata(); - } - } - if (entityMetadata.getId() == 13 && !showCustomBlock) { hasFuel = (boolean) entityMetadata.getValue(); - updateFurnaceMetadata(); + updateDefaultBlockMetadata(); } super.updateBedrockMetadata(entityMetadata, session); } - private void updateFurnaceMetadata() { + @Override + public void updateDefaultBlockMetadata() { metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(hasFuel ? BlockTranslator.JAVA_RUNTIME_FURNACE_LIT_ID : BlockTranslator.JAVA_RUNTIME_FURNACE_ID)); metadata.put(EntityData.DISPLAY_OFFSET, 6); } diff --git a/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java b/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java index cdc3d8f2..a67c0be5 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java @@ -55,7 +55,7 @@ public class MinecartEntity extends Entity { metadata.put(EntityData.HURT_TIME, Math.min((int) (float) entityMetadata.getValue(), 15)); } - if (!(this instanceof FurnaceMinecartEntity)) { // Handled in FurnaceMinecartEntity.java + if (!(this instanceof DefaultBlockMinecartEntity)) { // Handled in the DefaultBlockMinecartEntity class // Custom block if (entityMetadata.getId() == 10) { metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId((int) entityMetadata.getValue())); diff --git a/connector/src/main/java/org/geysermc/connector/entity/SpawnerMinecartEntity.java b/connector/src/main/java/org/geysermc/connector/entity/SpawnerMinecartEntity.java new file mode 100644 index 00000000..6be138c0 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/entity/SpawnerMinecartEntity.java @@ -0,0 +1,44 @@ +/* + * 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; + +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.EntityData; +import org.geysermc.connector.entity.type.EntityType; +import org.geysermc.connector.network.translators.world.block.BlockTranslator; + +public class SpawnerMinecartEntity extends DefaultBlockMinecartEntity { + + public SpawnerMinecartEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { + super(entityId, geyserId, entityType, position, motion, rotation); + } + + @Override + public void updateDefaultBlockMetadata() { + metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(BlockTranslator.JAVA_RUNTIME_SPAWNER_ID)); + metadata.put(EntityData.DISPLAY_OFFSET, 6); + } +} 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 2cfe54c6..3acc17c3 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 @@ -134,11 +134,12 @@ public enum EntityType { MINECART_TNT(MinecartEntity.class, 97, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:tnt_minecart"), MINECART_CHEST(MinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:chest_minecart"), MINECART_FURNACE(FurnaceMinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:minecart"), + MINECART_SPAWNER(SpawnerMinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:minecart"), MINECART_COMMAND_BLOCK(MinecartEntity.class, 100, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:command_block_minecart"), LINGERING_POTION(ThrowableEntity.class, 101, 0f), LLAMA_SPIT(Entity.class, 102, 0.25f), - EVOKER_FANGS(Entity.class, 103, 0.8f, 0.5f), - EVOKER(SpellcasterIllagerEntity.class, 104, 1.95f, 0.5f), + EVOKER_FANGS(Entity.class, 103, 0.8f, 0.5f, 0.5f, 0f, "minecraft:evocation_fang"), + EVOKER(SpellcasterIllagerEntity.class, 104, 1.95f, 0.6f, 0.6f, 0f, "minecraft:evocation_illager"), VEX(MonsterEntity.class, 105, 0.8f, 0.4f), ICE_BOMB(Entity.class, 106, 0f), BALLOON(Entity.class, 107, 0f), //TODO diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java index 781dc326..d6f446f0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java @@ -72,6 +72,8 @@ public class BlockTranslator { public static final int JAVA_RUNTIME_FURNACE_ID; public static final int JAVA_RUNTIME_FURNACE_LIT_ID; + public static final int JAVA_RUNTIME_SPAWNER_ID; + private static final int BLOCK_STATE_VERSION = 17760256; static { @@ -113,6 +115,7 @@ public class BlockTranslator { int cobwebRuntimeId = -1; int furnaceRuntimeId = -1; int furnaceLitRuntimeId = -1; + int spawnerRuntimeId = -1; Iterator> blocksIterator = blocks.fields(); while (blocksIterator.hasNext()) { javaRuntimeId++; @@ -199,6 +202,10 @@ public class BlockTranslator { } } + if (javaId.startsWith("minecraft:spawner")) { + spawnerRuntimeId = javaRuntimeId; + } + bedrockRuntimeId++; } @@ -217,6 +224,11 @@ public class BlockTranslator { } JAVA_RUNTIME_FURNACE_LIT_ID = furnaceLitRuntimeId; + if (spawnerRuntimeId == -1) { + throw new AssertionError("Unable to find spawner in palette"); + } + JAVA_RUNTIME_SPAWNER_ID = spawnerRuntimeId; + if (waterRuntimeId == -1) { throw new AssertionError("Unable to find water in palette"); } From 5fca5d5ef50c04dcfc0932e997f10bac6f7269dd Mon Sep 17 00:00:00 2001 From: rtm516 Date: Wed, 3 Jun 2020 21:12:16 +0100 Subject: [PATCH 70/73] Fix position of non-marker invisible armour stands (#697) This adds the height of the armour stand to the position if its invisible and not a marker to counteract the scale being 0 therefore having a wrong nametag position --- .../org/geysermc/connector/entity/Entity.java | 5 ++-- .../entity/living/ArmorStandEntity.java | 30 +++++++++++++++++-- 2 files changed, 30 insertions(+), 5 deletions(-) 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 06679934..16e9c0a1 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/Entity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/Entity.java @@ -214,9 +214,8 @@ public class Entity { metadata.getFlags().setFlag(EntityFlag.GLIDING, (xd & 0x80) == 0x80); if ((xd & 0x20) == 0x20) { - if (this.is(ArmorStandEntity.class)) { - metadata.put(EntityData.SCALE, 0.0f); - } else { + // Armour stands are handled in their own class + if (!this.is(ArmorStandEntity.class)) { metadata.getFlags().setFlag(EntityFlag.INVISIBLE, true); } } else { diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/ArmorStandEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/ArmorStandEntity.java index 8d3c8f8f..47faad36 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/ArmorStandEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/ArmorStandEntity.java @@ -35,17 +35,42 @@ import org.geysermc.connector.network.session.GeyserSession; public class ArmorStandEntity extends LivingEntity { + // These are used to store the state of the armour stand for use when handling invisibility + private boolean isMarker = false; + private boolean isInvisible = false; + private boolean isSmall = false; + public ArmorStandEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); } + @Override + public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) { + // Fake the height to be above where it is so the nametag appears in the right location for invisible non-marker armour stands + if (!isMarker && isInvisible) { + position = position.add(0d, entityType.getHeight() * (isSmall ? 0.55d : 1d), 0d); + } + + super.moveAbsolute(session, position, rotation, isOnGround, teleported); + } + @Override public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getType() == MetadataType.BYTE) { + if (entityMetadata.getId() == 0 && entityMetadata.getType() == MetadataType.BYTE) { + byte xd = (byte) entityMetadata.getValue(); + + // Check if the armour stand is invisible and store accordingly + if ((xd & 0x20) == 0x20) { + metadata.put(EntityData.SCALE, 0.0f); + isInvisible = true; + } + } else if (entityMetadata.getId() == 14 && entityMetadata.getType() == MetadataType.BYTE) { byte xd = (byte) entityMetadata.getValue(); // isSmall if ((xd & 0x01) == 0x01) { + isSmall = true; + if (metadata.getFloat(EntityData.SCALE) != 0.55f && metadata.getFloat(EntityData.SCALE) != 0.0f) { metadata.put(EntityData.SCALE, 0.55f); } @@ -60,9 +85,10 @@ public class ArmorStandEntity extends LivingEntity { } // setMarker - if ((xd & 0x10) == 0x10 && (metadata.get(EntityData.BOUNDING_BOX_WIDTH) != null && !metadata.get(EntityData.BOUNDING_BOX_WIDTH).equals(0.0f))) { + if ((xd & 0x10) == 0x10 && (metadata.get(EntityData.BOUNDING_BOX_WIDTH) == null || !metadata.get(EntityData.BOUNDING_BOX_WIDTH).equals(0.0f))) { metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.0f); metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.0f); + isMarker = true; } } super.updateBedrockMetadata(entityMetadata, session); From 69a4cd386047e3b94dc3a35d1bb3df9651820782 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Wed, 3 Jun 2020 22:57:36 -0400 Subject: [PATCH 71/73] Use static commit of MCProtocolLib (#734) This prevents changes upstream from immediately affecting Geyser workflow. This also removes the CodeMC repository in favor of Jitpack (which can use the commit hash as a version). --- connector/pom.xml | 2 +- pom.xml | 10 ++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/connector/pom.xml b/connector/pom.xml index 9c503dcc..91cf6f3d 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -99,7 +99,7 @@ com.github.steveice10 mcprotocollib - 1.15.2-1-SNAPSHOT + 4c315aa206 compile diff --git a/pom.xml b/pom.xml index a82d6217..3e119eb1 100644 --- a/pom.xml +++ b/pom.xml @@ -38,14 +38,8 @@ - CodeMC-repo - https://repo.codemc.org/repository/maven-public - - true - - - true - + jitpack.io + https://jitpack.io nukkitx-release-repo From 1d8995efe6d8457e9e2809a0112e06a579ca70a8 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Thu, 4 Jun 2020 10:49:32 -0800 Subject: [PATCH 72/73] Add minimum delay between closing and opening a new window (#735) Should fix new windows not showing up with some plugins like Lottery. --- .../bedrock/BedrockContainerCloseTranslator.java | 2 -- .../java/window/JavaOpenWindowTranslator.java | 10 ++-------- .../org/geysermc/connector/utils/InventoryUtils.java | 8 +++++++- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java index 05eac203..4c531c48 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java @@ -53,8 +53,6 @@ public class BedrockContainerCloseTranslator extends PacketTranslator 0) { GeyserConnector.getInstance().getGeneralThreadPool().schedule(() -> { translator.openInventory(session, inventory); translator.updateInventory(session, inventory); - }, 200, TimeUnit.MILLISECONDS); + }, delay, TimeUnit.MILLISECONDS); } else { translator.openInventory(session, inventory); translator.updateInventory(session, inventory); From ccb44f604e9fd12c1850c035c87f709bb1a3c8b5 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Fri, 5 Jun 2020 01:04:38 +0100 Subject: [PATCH 73/73] Fix query not following normal MC standards (#736) Changed the query token generation to generate a 4 byte int represented as a null terminated string --- .../connector/network/QueryPacketHandler.java | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/QueryPacketHandler.java b/connector/src/main/java/org/geysermc/connector/network/QueryPacketHandler.java index 061e0f86..6ad206b3 100644 --- a/connector/src/main/java/org/geysermc/connector/network/QueryPacketHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/QueryPacketHandler.java @@ -60,6 +60,7 @@ public class QueryPacketHandler { /** * The Query packet handler instance + * * @param connector Geyser Connector * @param sender The Sender IP/Port for the Query * @param buffer The Query data @@ -79,11 +80,12 @@ public class QueryPacketHandler { /** * Checks the packet is in fact a query packet + * * @param buffer Query data * @return if the packet is a query packet */ private boolean isQueryPacket(ByteBuf buffer) { - return (buffer.readableBytes() >= 2) ? buffer.readUnsignedShort() == 65277 : false; + return (buffer.readableBytes() >= 2) ? buffer.readUnsignedShort() == 0xFEFD : false; } /** @@ -130,6 +132,7 @@ public class QueryPacketHandler { /** * Gets the game data for the query + * * @return the game data for the query */ private byte[] getGameData() { @@ -177,7 +180,7 @@ public class QueryPacketHandler { // Blank Buffer Bytes query.write("GeyserMC".getBytes()); query.write((byte) 0x00); - query.write((byte) 128); + query.write((byte) 0x80); query.write((byte) 0x00); // Fills the game data @@ -189,7 +192,7 @@ public class QueryPacketHandler { } // Final byte to show the end of the game data - query.write(new byte[]{0x00, 0x01}); + query.write(new byte[] { 0x00, 0x01 }); return query.toByteArray(); } catch (IOException e) { e.printStackTrace(); @@ -197,6 +200,11 @@ public class QueryPacketHandler { } } + /** + * Generate a byte[] storing the player names + * + * @return The byte[] representation of players + */ private byte[] getPlayers() { ByteArrayOutputStream query = new ByteArrayOutputStream(); @@ -208,7 +216,7 @@ public class QueryPacketHandler { try { // Start the player section query.write("player_".getBytes()); - query.write(new byte[]{0x00, 0x00}); + query.write(new byte[] { 0x00, 0x00 }); // Fill player names if(pingInfo != null) { @@ -229,6 +237,7 @@ public class QueryPacketHandler { /** * Sends a packet to the sender + * * @param data packet data */ private void sendPacket(ByteBuf data) { @@ -251,18 +260,28 @@ public class QueryPacketHandler { * Gets an MD5 token for the current IP/Port. * This should reset every 30 seconds but a new one is generated per instance * Seems wasteful to code something in to clear it when it has no use. + * * @param token the token * @param address the address * @return an MD5 token for the current IP/Port */ public static byte[] getTokenString(byte[] token, InetAddress address) { try { + // Generate an MD5 hash from the address MessageDigest digest = MessageDigest.getInstance("MD5"); digest.update(address.toString().getBytes(StandardCharsets.UTF_8)); digest.update(token); - return Arrays.copyOf(digest.digest(), 4); + + // Get the first 4 bytes of the digest + byte[] digestBytes = Arrays.copyOf(digest.digest(), 4); + + // Convert the bytes to a buffer + ByteBuffer byteBuffer = ByteBuffer.wrap(digestBytes); + + // Turn the number into a null terminated string + return (byteBuffer.getInt() + "\0").getBytes(); } catch (NoSuchAlgorithmException e) { - return ByteBuffer.allocate(4).putInt(ThreadLocalRandom.current().nextInt()).array(); + return (ByteBuffer.allocate(4).putInt(ThreadLocalRandom.current().nextInt()).getInt() + "\0").getBytes(); } } }