From 9c0b9f19759b09193ff0c6b7bbe18c51a3988385 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 7 Mar 2022 13:58:09 -0500 Subject: [PATCH 01/11] Show attribute suggestions in commands --- .../protocol/java/JavaCommandsTranslator.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java index 28ebca926..00b60fec0 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java @@ -27,6 +27,8 @@ package org.geysermc.geyser.translator.protocol.java; import com.github.steveice10.mc.protocol.data.game.command.CommandNode; import com.github.steveice10.mc.protocol.data.game.command.CommandParser; +import com.github.steveice10.mc.protocol.data.game.command.properties.ResourceProperties; +import com.github.steveice10.mc.protocol.data.game.entity.attribute.AttributeType; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundCommandsPacket; import com.nukkitx.protocol.bedrock.data.command.CommandData; import com.nukkitx.protocol.bedrock.data.command.CommandEnumData; @@ -58,6 +60,7 @@ import java.util.*; public class JavaCommandsTranslator extends PacketTranslator { private static final String[] ALL_EFFECT_IDENTIFIERS = EntityUtils.getAllEffectIdentifiers(); + private static final String[] ATTRIBUTES = AttributeType.Builtin.BUILTIN.keySet().toArray(new String[0]); private static final String[] ENUM_BOOLEAN = {"true", "false"}; private static final String[] VALID_COLORS; private static final String[] VALID_SCOREBOARD_SLOTS; @@ -203,10 +206,11 @@ public class JavaCommandsTranslator extends PacketTranslator VALID_COLORS; case SCOREBOARD_SLOT -> VALID_SCOREBOARD_SLOTS; case MOB_EFFECT -> ALL_EFFECT_IDENTIFIERS; + case RESOURCE, RESOURCE_OR_TAG -> { + String resource = ((ResourceProperties) node.getProperties()).getRegistryKey(); + if (resource.equals("minecraft:attribute")) { + yield ATTRIBUTES; + } else { + yield CommandParam.STRING; + } + } default -> CommandParam.STRING; }; } @@ -302,7 +314,7 @@ public class JavaCommandsTranslator extends PacketTranslator Date: Wed, 9 Mar 2022 23:09:48 -0500 Subject: [PATCH 02/11] Remove unlockedRecipes storage This has been unused, and for the time being we aren't going the packet route that would use these. --- .../geyser/session/GeyserSession.java | 2 - .../protocol/java/JavaRecipeTranslator.java | 53 ------------------- .../java/JavaUpdateRecipesTranslator.java | 1 - 3 files changed, 56 deletions(-) delete mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRecipeTranslator.java diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 6452803b5..fe63b0b0c 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -349,7 +349,6 @@ public class GeyserSession implements GeyserConnection, CommandSender { @Setter private Int2ObjectMap craftingRecipes; - private final Set unlockedRecipes; private final AtomicInteger lastRecipeNetId; /** @@ -527,7 +526,6 @@ public class GeyserSession implements GeyserConnection, CommandSender { this.playerInventory = new PlayerInventory(); this.openInventory = null; this.craftingRecipes = new Int2ObjectOpenHashMap<>(); - this.unlockedRecipes = new ObjectOpenHashSet<>(); this.lastRecipeNetId = new AtomicInteger(1); this.spawned = false; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRecipeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRecipeTranslator.java deleted file mode 100644 index da35da60e..000000000 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRecipeTranslator.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2019-2022 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.geyser.translator.protocol.java; - -import com.github.steveice10.mc.protocol.data.game.UnlockRecipesAction; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundRecipePacket; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.protocol.PacketTranslator; -import org.geysermc.geyser.translator.protocol.Translator; - -import java.util.Collections; - -/** - * Used to list recipes that we can definitely use the recipe book for (and therefore save on packet usage) - */ -@Translator(packet = ClientboundRecipePacket.class) -public class JavaRecipeTranslator extends PacketTranslator { - - @Override - public void translate(GeyserSession session, ClientboundRecipePacket packet) { - if (packet.getAction() == UnlockRecipesAction.REMOVE) { - for (String identifier : packet.getRecipes()) { - session.getUnlockedRecipes().remove(identifier); - } - } else { - Collections.addAll(session.getUnlockedRecipes(), packet.getRecipes()); - } - } -} - diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index 4d7a1617a..722ce988e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -201,7 +201,6 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator Date: Thu, 10 Mar 2022 15:16:08 -0500 Subject: [PATCH 03/11] Fix inability to toggle sitting of parrots --- .../type/living/animal/tameable/TameableEntity.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/TameableEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/TameableEntity.java index 50d17eaaa..33b2144e8 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/TameableEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/TameableEntity.java @@ -61,7 +61,13 @@ public class TameableEntity extends AnimalEntity { // Note: Must be set for wolf collar color to work if (entityMetadata.getValue().isPresent()) { // Owner UUID of entity - Entity entity = session.getEntityCache().getPlayerEntity(entityMetadata.getValue().get()); + UUID uuid = entityMetadata.getValue().get(); + Entity entity; + if (uuid.equals(session.getPlayerEntity().getUuid())) { + entity = session.getPlayerEntity(); + } else { + entity = session.getEntityCache().getPlayerEntity(uuid); + } // Used as both a check since the player isn't in the entity cache and a normal fallback if (entity == null) { // Set to tame, but indicate that we are not the player that owns this From 0829b5cd4ebadd11ebef203c5c624eedad477bb3 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 15 Mar 2022 13:34:56 -0400 Subject: [PATCH 04/11] Replicate Bedrock shield behavior more accurately If the player swings, then they cannot be holding their shield at the same time. Also fixes an animation edge case with other players. --- .../geyser/entity/type/LivingEntity.java | 22 +++- .../type/player/SessionPlayerEntity.java | 11 ++ .../geyser/session/GeyserSession.java | 112 +++++++++++++++++- .../bedrock/BedrockAnimateTranslator.java | 6 +- ...BedrockInventoryTransactionTranslator.java | 20 ++-- .../player/BedrockActionTranslator.java | 36 +----- .../java/entity/JavaAnimateTranslator.java | 3 + 7 files changed, 156 insertions(+), 54 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java index a5214854e..0cce0f8df 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java @@ -99,13 +99,15 @@ public class LivingEntity extends Entity { public void setLivingEntityFlags(ByteEntityMetadata entityMetadata) { byte xd = entityMetadata.getPrimitiveValue(); - // Blocking gets triggered when using a bow, but if we set USING_ITEM for all items, it may look like - // you're "mining" with ex. a shield. + boolean isUsingItem = (xd & 0x01) == 0x01; + boolean isUsingOffhand = (xd & 0x02) == 0x02; + ItemMapping shield = session.getItemMappings().getStoredItems().shield(); - boolean isUsingShield = (getHand().getId() == shield.getBedrockId() || - getHand().equals(ItemData.AIR) && getOffHand().getId() == shield.getBedrockId()); - setFlag(EntityFlag.USING_ITEM, (xd & 0x01) == 0x01 && !isUsingShield); - setFlag(EntityFlag.BLOCKING, (xd & 0x01) == 0x01); + boolean isUsingShield = hasShield(isUsingOffhand, shield); + + setFlag(EntityFlag.USING_ITEM, isUsingItem && !isUsingShield); + // Override the blocking + setFlag(EntityFlag.BLOCKING, isUsingItem && isUsingShield); // Riptide spin attack setFlag(EntityFlag.DAMAGE_NEARBY_MOBS, (xd & 0x04) == 0x04); @@ -142,6 +144,14 @@ public class LivingEntity extends Entity { } } + protected boolean hasShield(boolean offhand, ItemMapping shieldMapping) { + if (offhand) { + return offHand.getId() == shieldMapping.getBedrockId(); + } else { + return hand.getId() == shieldMapping.getBedrockId(); + } + } + @Override protected boolean isShaking() { return isMaxFrozenState; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java index 8dd24bdb8..077f82171 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java @@ -38,6 +38,7 @@ import com.nukkitx.protocol.bedrock.packet.UpdateAttributesPacket; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import lombok.Getter; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; +import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.AttributeUtils; @@ -167,6 +168,16 @@ public class SessionPlayerEntity extends PlayerEntity { return super.createHealthAttribute(); } + @Override + protected boolean hasShield(boolean offhand, ItemMapping shieldMapping) { + // Must be overridden to point to the player's inventory cache + if (offhand) { + return session.getPlayerInventory().getOffhand().getJavaId() == shieldMapping.getJavaId(); + } else { + return session.getPlayerInventory().getItemInHand().getJavaId() == shieldMapping.getJavaId(); + } + } + @Override public void updateBedrockMetadata() { super.updateBedrockMetadata(); diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index fe63b0b0c..3cfe0e550 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -36,8 +36,11 @@ import com.github.steveice10.mc.protocol.MinecraftProtocol; import com.github.steveice10.mc.protocol.data.ProtocolState; import com.github.steveice10.mc.protocol.data.UnexpectedEncryptionException; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; +import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.github.steveice10.mc.protocol.data.game.entity.player.HandPreference; +import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction; import com.github.steveice10.mc.protocol.data.game.setting.ChatVisibility; import com.github.steveice10.mc.protocol.data.game.setting.SkinPart; import com.github.steveice10.mc.protocol.data.game.statistic.CustomStatistic; @@ -46,6 +49,8 @@ import com.github.steveice10.mc.protocol.packet.handshake.serverbound.ClientInte import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundClientInformationPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket; import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryPacket; import com.github.steveice10.packetlib.BuiltinFlags; import com.github.steveice10.packetlib.Session; @@ -97,6 +102,7 @@ import org.geysermc.geyser.level.physics.CollisionManager; import org.geysermc.geyser.network.netty.LocalSession; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.BlockMappings; +import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.session.auth.AuthData; import org.geysermc.geyser.session.auth.AuthType; @@ -107,10 +113,7 @@ import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.translator.text.MessageTranslator; -import org.geysermc.geyser.util.ChunkUtils; -import org.geysermc.geyser.util.DimensionUtils; -import org.geysermc.geyser.util.LoginEncryptionUtils; -import org.geysermc.geyser.util.MathUtils; +import org.geysermc.geyser.util.*; import javax.annotation.Nonnull; import java.net.ConnectException; @@ -422,6 +425,13 @@ public class GeyserSession implements GeyserConnection, CommandSender { @Setter private long lastVehicleMoveTimestamp = System.currentTimeMillis(); + /** + * Counts how many ticks have occurred since an arm animation started. + * -1 means there is no active arm swing. + */ + @Getter(AccessLevel.NONE) + private int armAnimationTicks = -1; + /** * Controls whether the daylight cycle gamerule has been sent to the client, so the sun/moon remain motionless. */ @@ -1107,6 +1117,34 @@ public class GeyserSession implements GeyserConnection, CommandSender { for (Tickable entity : entityCache.getTickableEntities()) { entity.tick(); } + + if (armAnimationTicks != -1) { + // As of 1.18.2 Java Edition, it appears that the swing time is dynamically updated depending on the + // player's effect status, but the animation can cut short if the duration suddenly decreases + // (from suddenly no longer having mining fatigue, for example) + // This math is referenced from Java Edition 1.18.2 + int swingTotalDuration; + int hasteLevel = Math.max(effectCache.getHaste(), effectCache.getConduitPower()); + if (hasteLevel > 0) { + swingTotalDuration = 6 - hasteLevel; + } else { + int miningFatigueLevel = effectCache.getMiningFatigue(); + if (miningFatigueLevel > 0) { + swingTotalDuration = 6 + miningFatigueLevel * 2; + } else { + swingTotalDuration = 6; + } + } + if (++armAnimationTicks >= swingTotalDuration) { + if (sneaking) { + // Attempt to re-activate blocking as our swing animation is up + if (attemptToBlock()) { + playerEntity.updateBedrockMetadata(); + } + } + armAnimationTicks = -1; + } + } } catch (Throwable throwable) { throwable.printStackTrace(); } @@ -1116,7 +1154,23 @@ public class GeyserSession implements GeyserConnection, CommandSender { this.authData = authData; } - public void setSneaking(boolean sneaking) { + public void startSneaking() { + // Toggle the shield, if there is no ongoing arm animation + // This matches Bedrock Edition behavior as of 1.18.12 + if (armAnimationTicks == -1) { + attemptToBlock(); + } + + setSneaking(true); + } + + public void stopSneaking() { + disableBlocking(); + + setSneaking(false); + } + + private void setSneaking(boolean sneaking) { this.sneaking = sneaking; // Update pose and bounding box on our end @@ -1201,6 +1255,54 @@ public class GeyserSession implements GeyserConnection, CommandSender { return null; } + /** + * Checks to see if a shield is in either hand to activate blocking. If so, it sets the Bedrock client to display + * blocking and sends a packet to the Java server. + */ + private boolean attemptToBlock() { + ItemMapping shield = itemMappings.getStoredItems().shield(); + + ServerboundUseItemPacket useItemPacket; + if (playerInventory.getItemInHand().getJavaId() == shield.getJavaId()) { + useItemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND); + } else if (playerInventory.getOffhand().getJavaId() == shield.getJavaId()) { + useItemPacket = new ServerboundUseItemPacket(Hand.OFF_HAND); + } else { + // No blocking + return false; + } + + sendDownstreamPacket(useItemPacket); + playerEntity.setFlag(EntityFlag.BLOCKING, true); + // Metadata should be updated later + return true; + } + + /** + * Starts ticking the amount of time that the Bedrock client has been swinging their arm, and disables blocking if + * blocking. + */ + public void activateArmAnimationTicking() { + armAnimationTicks = 0; + if (disableBlocking()) { + playerEntity.updateBedrockMetadata(); + } + } + + /** + * Indicates to the client to stop blocking and tells the Java server the same. + */ + private boolean disableBlocking() { + if (playerEntity.getFlag(EntityFlag.BLOCKING)) { + ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, + BlockUtils.POSITION_ZERO, Direction.DOWN); + sendDownstreamPacket(releaseItemPacket); + playerEntity.setFlag(EntityFlag.BLOCKING, false); + return true; + } + return false; + } + /** * Will be overwritten for GeyserConnect. */ diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAnimateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAnimateTranslator.java index ac4a4bb2e..670e55785 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAnimateTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAnimateTranslator.java @@ -48,8 +48,10 @@ public class BedrockAnimateTranslator extends PacketTranslator { switch (packet.getAction()) { case SWING_ARM -> // Delay so entity damage can be processed first - session.scheduleInEventLoop(() -> - session.sendDownstreamPacket(new ServerboundSwingPacket(Hand.MAIN_HAND)), + session.scheduleInEventLoop(() -> { + session.sendDownstreamPacket(new ServerboundSwingPacket(Hand.MAIN_HAND)); + session.activateArmAnimationTicking(); + }, 25, TimeUnit.MILLISECONDS ); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java index 7129c1318..f120e4a19 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java @@ -411,22 +411,20 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator processEntityInteraction(session, packet, entity); // Interact + case 1 -> { // Attack + int entityId; if (entity.getDefinition() == EntityDefinitions.ENDER_DRAGON) { // Redirects the attack to its body entity, this only happens when // attacking the underbelly of the ender dragon - ServerboundInteractPacket attackPacket = new ServerboundInteractPacket(entity.getEntityId() + 3, - InteractAction.ATTACK, session.isSneaking()); - session.sendDownstreamPacket(attackPacket); + entityId = entity.getEntityId() + 3; } else { - ServerboundInteractPacket attackPacket = new ServerboundInteractPacket(entity.getEntityId(), - InteractAction.ATTACK, session.isSneaking()); - session.sendDownstreamPacket(attackPacket); + entityId = entity.getEntityId(); } - break; + ServerboundInteractPacket attackPacket = new ServerboundInteractPacket(entityId, + InteractAction.ATTACK, session.isSneaking()); + session.sendDownstreamPacket(attackPacket); + } } break; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockActionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockActionTranslator.java index 52129797b..5429899fa 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockActionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockActionTranslator.java @@ -28,7 +28,10 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; import com.github.steveice10.mc.protocol.data.game.entity.player.*; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.*; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerCommandPacket; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.data.LevelEventType; @@ -39,10 +42,8 @@ import com.nukkitx.protocol.bedrock.packet.*; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.ItemFrameEntity; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; -import org.geysermc.geyser.inventory.PlayerInventory; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.registry.BlockRegistries; -import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -105,38 +106,13 @@ public class BedrockActionTranslator extends PacketTranslator Date: Fri, 18 Mar 2022 10:51:22 -0400 Subject: [PATCH 05/11] More descriptive disconnect messages for outdated Java servers --- .../network/session/GeyserSession.java | 4 +- .../geyser/session/GeyserSession.java | 15 -------- .../java/JavaLoginDisconnectTranslator.java | 37 ++++++++++++++++++- 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/core/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/core/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 85bfd583d..890290a01 100644 --- a/core/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -100,7 +100,7 @@ public class GeyserSession { } public void login() { - this.handle.login(); + throw new UnsupportedOperationException(); } public void authenticate(String username) { @@ -120,7 +120,7 @@ public class GeyserSession { } public void close() { - this.handle.close(); + throw new UnsupportedOperationException(); } public void executeInEventLoop(Runnable runnable) { diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 3cfe0e550..8a030c385 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -625,17 +625,6 @@ public class GeyserSession implements GeyserConnection, CommandSender { upstream.sendPacket(gamerulePacket); } - public void login() { - if (this.remoteAuthType != AuthType.ONLINE) { - if (this.remoteAuthType == AuthType.OFFLINE) { - geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.auth.login.offline")); - } else { - geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.auth.login.floodgate")); - } - authenticate(authData.name()); - } - } - public void authenticate(String username) { authenticate(username, ""); } @@ -1046,10 +1035,6 @@ public class GeyserSession implements GeyserConnection, CommandSender { closed = true; } - public void close() { - disconnect(GeyserLocale.getPlayerLocaleString("geyser.network.close", getClientData().getLanguageCode())); - } - /** * Executes a task and prints a stack trace if an error occurs. */ diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java index 2f6674727..981fa83bf 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java @@ -26,7 +26,13 @@ package org.geysermc.geyser.translator.protocol.java; import com.github.steveice10.mc.protocol.packet.login.clientbound.ClientboundLoginDisconnectPacket; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.TranslatableComponent; +import org.geysermc.common.PlatformType; +import org.geysermc.geyser.network.MinecraftProtocol; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.text.MessageTranslator; @@ -36,8 +42,37 @@ public class JavaLoginDisconnectTranslator extends PacketTranslator Date: Fri, 18 Mar 2022 10:51:36 -0400 Subject: [PATCH 06/11] Update languages submodule --- core/src/main/resources/languages | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/languages b/core/src/main/resources/languages index d2a01218d..51e0ae2b5 160000 --- a/core/src/main/resources/languages +++ b/core/src/main/resources/languages @@ -1 +1 @@ -Subproject commit d2a01218d43f5b60bd4512d5eb6ad7e03a097f8c +Subproject commit 51e0ae2b527e3548ef82b65f33541f5eaeba2308 From 9c7210ef922090adaab19a2b28b367eec944a39e Mon Sep 17 00:00:00 2001 From: Jackson_57 <49173011+jackson-57@users.noreply.github.com> Date: Fri, 18 Mar 2022 16:01:14 -0400 Subject: [PATCH 07/11] Update wiki links (#2864) --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 885ec920b..23bde93d2 100644 --- a/README.md +++ b/README.md @@ -20,13 +20,13 @@ Special thanks to the DragonProxy project for being a trailblazer in protocol tr ### Currently supporting Minecraft Bedrock 1.17.41 + 1.18.0 - 1.18.10 and Minecraft Java 1.18.2. ## Setting Up -Take a look [here](https://github.com/GeyserMC/Geyser/wiki/Setup) for how to set up Geyser. +Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. [![YouTube Video](https://img.youtube.com/vi/U7dZZ8w7Gi4/0.jpg)](https://www.youtube.com/watch?v=U7dZZ8w7Gi4) ## Links: - Website: https://geysermc.org -- Docs: https://github.com/GeyserMC/Geyser/wiki +- Docs: https://wiki.geysermc.org/geyser/ - Download: https://ci.geysermc.org - Discord: https://discord.gg/geysermc - Donate: https://opencollective.com/geysermc @@ -39,7 +39,7 @@ Take a look [here](https://github.com/GeyserMC/Geyser/wiki/Setup) for how to set - Structure block UI ## What can't be fixed -There are a few things Geyser is unable to support due to various differences between Minecraft Bedrock and Java. For a list of these limitations, see the [Current Limitations](https://github.com/GeyserMC/Geyser/wiki/Current-Limitations) page. +There are a few things Geyser is unable to support due to various differences between Minecraft Bedrock and Java. For a list of these limitations, see the [Current Limitations](https://wiki.geysermc.org/geyser/current-limitations/) page. ## Compiling 1. Clone the repo to your computer From f8e983887e96fcdc36df54c22f090afec605ab37 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Fri, 18 Mar 2022 18:59:32 -0400 Subject: [PATCH 08/11] Add method in Connection API for transferring connections (#2891) --- .../org/geysermc/api/session/Connection.java | 11 ++++++++++- .../geysermc/geyser/session/GeyserSession.java | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/api/base/src/main/java/org/geysermc/api/session/Connection.java b/api/base/src/main/java/org/geysermc/api/session/Connection.java index ccf3f7122..3e997912b 100644 --- a/api/base/src/main/java/org/geysermc/api/session/Connection.java +++ b/api/base/src/main/java/org/geysermc/api/session/Connection.java @@ -26,6 +26,7 @@ package org.geysermc.api.session; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.common.value.qual.IntRange; import java.util.UUID; @@ -55,5 +56,13 @@ public interface Connection { */ String xuid(); - + /** + * Transfer the connection to a server. A Bedrock player can successfully transfer to the same server they are + * currently playing on. + * + * @param address The address of the server + * @param port The port of the server + * @return true if the transfer was a success + */ + boolean transfer(@NonNull String address, @IntRange(from = 0, to = 65535) int port); } diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 8a030c385..1c25c2281 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -78,6 +78,7 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.NonNull; import lombok.Setter; +import org.checkerframework.common.value.qual.IntRange; import org.geysermc.common.PlatformType; import org.geysermc.cumulus.Form; import org.geysermc.cumulus.util.FormBuilder; @@ -1310,6 +1311,21 @@ public class GeyserSession implements GeyserConnection, CommandSender { return authData.xuid(); } + @SuppressWarnings("ConstantConditions") // Need to enforce the parameter annotations + @Override + public boolean transfer(@NonNull String address, @IntRange(from = 0, to = 65535) int port) { + if (address == null || address.isBlank()) { + throw new IllegalArgumentException("Server address cannot be null or blank"); + } else if (port < 0 || port > 65535) { + throw new IllegalArgumentException("Server port must be between 0 and 65535, was " + port); + } + TransferPacket transferPacket = new TransferPacket(); + transferPacket.setAddress(address); + transferPacket.setPort(port); + sendUpstreamPacket(transferPacket); + return true; + } + @Override public void sendMessage(String message) { TextPacket textPacket = new TextPacket(); From 732fd90d48ee94f97cecb40bc264da03c928cdbe Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 18 Mar 2022 23:31:25 -0400 Subject: [PATCH 09/11] Missed instance of Outdated server --- .../java/JavaLoginDisconnectTranslator.java | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java index 981fa83bf..7fca689b0 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java @@ -37,6 +37,8 @@ import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.text.MessageTranslator; +import java.util.List; + @Translator(packet = ClientboundLoginDisconnectPacket.class) public class JavaLoginDisconnectTranslator extends PacketTranslator { @@ -44,7 +46,7 @@ public class JavaLoginDisconnectTranslator extends PacketTranslator children = component.children(); + for (int i = 0; i < children.size(); i++) { + if (children.get(i) instanceof TextComponent child && child.content().startsWith("Outdated server!")) { + // Reproduced on Paper 1.17.1 + isOutdatedMessage = true; + break; + } + } + } + } } String serverDisconnectMessage = MessageTranslator.convertMessage(disconnectReason, session.getLocale()); From b81ad3f0dbd6401319fde206019054265d155091 Mon Sep 17 00:00:00 2001 From: Hancho1577 Date: Sat, 19 Mar 2022 20:45:19 +0700 Subject: [PATCH 10/11] Prevent async task pool from being full (#2894) Fixes #2883 --- core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java | 2 ++ core/src/main/java/org/geysermc/geyser/util/WebUtils.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java b/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java index 4383dc4e9..282f6875a 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java +++ b/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java @@ -601,6 +601,8 @@ public class SkinProvider { HttpURLConnection con = (HttpURLConnection) new URL(imageUrl).openConnection(); con.setRequestProperty("User-Agent", "Geyser-" + GeyserImpl.getInstance().getPlatformType().toString() + "/" + GeyserImpl.VERSION); + con.setConnectTimeout(10000); + con.setReadTimeout(10000); BufferedImage image = ImageIO.read(con.getInputStream()); if (image == null) throw new NullPointerException(); diff --git a/core/src/main/java/org/geysermc/geyser/util/WebUtils.java b/core/src/main/java/org/geysermc/geyser/util/WebUtils.java index 40daf22c7..fe479363f 100644 --- a/core/src/main/java/org/geysermc/geyser/util/WebUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/WebUtils.java @@ -52,6 +52,8 @@ public class WebUtils { HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setRequestMethod("GET"); con.setRequestProperty("User-Agent", "Geyser-" + GeyserImpl.getInstance().getPlatformType().toString() + "/" + GeyserImpl.VERSION); // Otherwise Java 8 fails on checking updates + con.setConnectTimeout(10000); + con.setReadTimeout(10000); return connectionToString(con); } catch (Exception e) { From 87d70be10d97e3f6e119e11217ad0157ed66faf6 Mon Sep 17 00:00:00 2001 From: Konicai <71294714+Konicai@users.noreply.github.com> Date: Sat, 19 Mar 2022 20:56:34 -0400 Subject: [PATCH 11/11] Register `floodgate:transfer` plugin channel (#2896) * Register floodgate:transfer channel * Don't warn on unknown channel --- .../pluginmessage/PluginMessageChannels.java | 45 +++++++++++++++++++ .../geyser/skin/FloodgateSkinUploader.java | 5 +-- .../java/JavaCustomPayloadTranslator.java | 5 ++- .../protocol/java/JavaLoginTranslator.java | 3 +- .../geyser/util/PluginMessageUtils.java | 20 --------- 5 files changed, 52 insertions(+), 26 deletions(-) create mode 100644 common/src/main/java/org/geysermc/floodgate/pluginmessage/PluginMessageChannels.java diff --git a/common/src/main/java/org/geysermc/floodgate/pluginmessage/PluginMessageChannels.java b/common/src/main/java/org/geysermc/floodgate/pluginmessage/PluginMessageChannels.java new file mode 100644 index 000000000..37c5d4015 --- /dev/null +++ b/common/src/main/java/org/geysermc/floodgate/pluginmessage/PluginMessageChannels.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2019-2022 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.floodgate.pluginmessage; + +import com.google.common.base.Charsets; + +public final class PluginMessageChannels { + public static final String SKIN = "floodgate:skin"; + public static final String FORM = "floodgate:form"; + public static final String TRANSFER = "floodgate:transfer"; + + private static final byte[] FLOODGATE_REGISTER_DATA = String.join("\0", SKIN, FORM, TRANSFER).getBytes(Charsets.UTF_8); + + /** + * Get the prebuilt register data as a byte array + * + * @return the register data of the Floodgate channels + */ + public static byte[] getFloodgateRegisterData() { + return FLOODGATE_REGISTER_DATA; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/skin/FloodgateSkinUploader.java b/core/src/main/java/org/geysermc/geyser/skin/FloodgateSkinUploader.java index 37a263312..7a800890b 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/FloodgateSkinUploader.java +++ b/core/src/main/java/org/geysermc/geyser/skin/FloodgateSkinUploader.java @@ -30,6 +30,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.Getter; +import org.geysermc.floodgate.pluginmessage.PluginMessageChannels; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.session.GeyserSession; @@ -48,8 +49,6 @@ import java.util.List; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; -import static org.geysermc.geyser.util.PluginMessageUtils.getSkinChannel; - public final class FloodgateSkinUploader { private final ObjectMapper JACKSON = new ObjectMapper(); private final List skinQueue = new ArrayList<>(); @@ -126,7 +125,7 @@ public final class FloodgateSkinUploader { byte[] bytes = (value + '\0' + signature) .getBytes(StandardCharsets.UTF_8); - PluginMessageUtils.sendMessage(session, getSkinChannel(), bytes); + PluginMessageUtils.sendMessage(session, PluginMessageChannels.SKIN, bytes); } break; case LOG_MESSAGE: diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java index 04151c07f..33fb4f15c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java @@ -29,6 +29,7 @@ import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundCu import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundCustomPayloadPacket; import com.google.common.base.Charsets; import com.nukkitx.protocol.bedrock.packet.TransferPacket; +import org.geysermc.floodgate.pluginmessage.PluginMessageChannels; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.session.auth.AuthType; @@ -54,7 +55,7 @@ public class JavaCustomPayloadTranslator extends PacketTranslator