From 4d0952c22449f8e672f4c357fbf5bab955c49393 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 10 Jul 2022 13:33:39 -0400 Subject: [PATCH] Initial support for 1.19.10 Bedrock --- core/pom.xml | 6 +- .../entity/type/player/PlayerEntity.java | 16 ++++- .../type/player/SessionPlayerEntity.java | 5 +- .../entity/type/player/SkullPlayerEntity.java | 1 + .../geyser/network/MinecraftProtocol.java | 13 +++- .../geyser/session/GeyserSession.java | 71 +++++++++++++++++-- .../player/JavaPlayerAbilitiesTranslator.java | 2 + .../JavaPlayerCombatKillTranslator.java | 50 +++++++++++++ 8 files changed, 151 insertions(+), 13 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerCombatKillTranslator.java diff --git a/core/pom.xml b/core/pom.xml index 408a2b761..e264531a9 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -128,8 +128,8 @@ com.github.CloudburstMC.Protocol - bedrock-v527 - 977a9a1 + bedrock-v534 + a78a64b compile @@ -145,7 +145,7 @@ com.nukkitx.network raknet - 1.6.28-20211202.034102-5 + 1.6.28-20220125.214016-6 compile diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java index 6f2958ffd..8e600b1a8 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java @@ -35,9 +35,7 @@ import com.github.steveice10.mc.protocol.data.game.scoreboard.TeamColor; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3i; -import com.nukkitx.protocol.bedrock.data.AttributeData; -import com.nukkitx.protocol.bedrock.data.GameType; -import com.nukkitx.protocol.bedrock.data.PlayerPermission; +import com.nukkitx.protocol.bedrock.data.*; import com.nukkitx.protocol.bedrock.data.command.CommandPermission; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; @@ -59,6 +57,7 @@ import org.geysermc.geyser.translator.text.MessageTranslator; import javax.annotation.Nullable; import java.util.Collections; +import java.util.List; import java.util.Optional; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -66,6 +65,16 @@ import java.util.concurrent.TimeUnit; @Getter @Setter public class PlayerEntity extends LivingEntity { public static final float SNEAKING_POSE_HEIGHT = 1.5f; + protected static final List BASE_ABILITY_LAYER; + + static { + AbilityLayer abilityLayer = new AbilityLayer(); + abilityLayer.setLayerType(AbilityLayer.Type.BASE); + Ability[] abilities = Ability.values(); + Collections.addAll(abilityLayer.getAbilitiesSet(), abilities); // Apparently all the abilities you're working with + Collections.addAll(abilityLayer.getAbilityValues(), abilities); // Apparently all the abilities the player can work with + BASE_ABILITY_LAYER = Collections.singletonList(abilityLayer); + } private String username; private boolean playerList = true; // Player is in the player list @@ -127,6 +136,7 @@ public class PlayerEntity extends LivingEntity { addPlayerPacket.setDeviceId(""); addPlayerPacket.setPlatformChatId(""); addPlayerPacket.setGameType(GameType.SURVIVAL); //TODO + addPlayerPacket.setAbilityLayers(BASE_ABILITY_LAYER); // Recommended to be added since 1.19.10, but only needed here for permissions viewing addPlayerPacket.getMetadata().putFlags(flags); dirtyMetadata.apply(addPlayerPacket.getMetadata()); 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 d4b703c40..f16f46e2e 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 @@ -44,7 +44,10 @@ import org.geysermc.geyser.util.AttributeUtils; import org.geysermc.geyser.util.DimensionUtils; import javax.annotation.Nullable; -import java.util.*; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.UUID; /** * The entity class specifically for a {@link GeyserSession}'s player. diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java index 6c15a4d3e..176d171de 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java @@ -81,6 +81,7 @@ public class SkullPlayerEntity extends PlayerEntity { addPlayerPacket.setDeviceId(""); addPlayerPacket.setPlatformChatId(""); addPlayerPacket.setGameType(GameType.SURVIVAL); + addPlayerPacket.setAbilityLayers(BASE_ABILITY_LAYER); addPlayerPacket.getMetadata().putFlags(flags); dirtyMetadata.apply(addPlayerPacket.getMetadata()); diff --git a/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java b/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java index 30f5e80fa..4d8ef680c 100644 --- a/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java @@ -29,6 +29,8 @@ import com.github.steveice10.mc.protocol.codec.MinecraftCodec; import com.github.steveice10.mc.protocol.codec.PacketCodec; import com.nukkitx.protocol.bedrock.BedrockPacketCodec; import com.nukkitx.protocol.bedrock.v527.Bedrock_v527; +import com.nukkitx.protocol.bedrock.v534.Bedrock_v534; +import org.geysermc.geyser.session.GeyserSession; import java.util.ArrayList; import java.util.Collections; @@ -43,7 +45,7 @@ public final class MinecraftProtocol { * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v527.V527_CODEC; + public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v534.V534_CODEC; /** * A list of all supported Bedrock versions that can join Geyser */ @@ -56,9 +58,10 @@ public final class MinecraftProtocol { private static final PacketCodec DEFAULT_JAVA_CODEC = MinecraftCodec.CODEC; static { - SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v527.V527_CODEC.toBuilder() .minecraftVersion("1.19.0/1.19.2") .build()); + SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); } /** @@ -75,6 +78,12 @@ public final class MinecraftProtocol { return null; } + /* Bedrock convenience methods to gatekeep features and easily remove the check on version removal */ + + public static boolean supports1_19_10(GeyserSession session) { + return session.getUpstream().getProtocolVersion() >= Bedrock_v534.V534_CODEC.getProtocolVersion(); + } + /** * Gets the {@link PacketCodec} for Minecraft: Java Edition. * 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 0a916fbf5..087cd0d8c 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -487,6 +487,11 @@ public class GeyserSession implements GeyserConnection, CommandSender { @Setter private boolean instabuild = false; + @Setter + private float flySpeed; + @Setter + private float walkSpeed; + /** * Caches current rain status. */ @@ -1623,23 +1628,81 @@ public class GeyserSession implements GeyserConnection, CommandSender { return geyser.getWorldManager().hasPermission(this, permission); } + private static final Ability[] USED_ABILITIES = Ability.values(); + /** * Send an AdventureSettingsPacket to the client with the latest flags */ public void sendAdventureSettings() { - AdventureSettingsPacket adventureSettingsPacket = new AdventureSettingsPacket(); - adventureSettingsPacket.setUniqueEntityId(playerEntity.getGeyserId()); + long bedrockId = playerEntity.getGeyserId(); // Set command permission if OP permission level is high enough // This allows mobile players access to a GUI for doing commands. The commands there do not change above OPERATOR // and all commands there are accessible with OP permission level 2 - adventureSettingsPacket.setCommandPermission(opPermissionLevel >= 2 ? CommandPermission.OPERATOR : CommandPermission.NORMAL); + CommandPermission commandPermission = opPermissionLevel >= 2 ? CommandPermission.OPERATOR : CommandPermission.NORMAL; // Required to make command blocks destroyable - adventureSettingsPacket.setPlayerPermission(opPermissionLevel >= 2 ? PlayerPermission.OPERATOR : PlayerPermission.MEMBER); + PlayerPermission playerPermission = opPermissionLevel >= 2 ? PlayerPermission.OPERATOR : PlayerPermission.MEMBER; // Update the noClip and worldImmutable values based on the current gamemode boolean spectator = gameMode == GameMode.SPECTATOR; boolean worldImmutable = gameMode == GameMode.ADVENTURE || spectator; + if (org.geysermc.geyser.network.MinecraftProtocol.supports1_19_10(this)) { + UpdateAdventureSettingsPacket adventureSettingsPacket = new UpdateAdventureSettingsPacket(); + adventureSettingsPacket.setNoMvP(false); + adventureSettingsPacket.setNoMvP(false); + adventureSettingsPacket.setImmutableWorld(worldImmutable); + adventureSettingsPacket.setShowNameTags(false); + adventureSettingsPacket.setAutoJump(true); + sendUpstreamPacket(adventureSettingsPacket); + + UpdateAbilitiesPacket updateAbilitiesPacket = new UpdateAbilitiesPacket(); + updateAbilitiesPacket.setUniqueEntityId(bedrockId); + updateAbilitiesPacket.setCommandPermission(commandPermission); + updateAbilitiesPacket.setPlayerPermission(playerPermission); + + AbilityLayer abilityLayer = new AbilityLayer(); + Set abilities = abilityLayer.getAbilityValues(); + if (canFly || spectator) { + abilities.add(Ability.MAY_FLY); + } + + // Default stuff we have to fill in + abilities.add(Ability.BUILD); + abilities.add(Ability.MINE); + if (gameMode == GameMode.CREATIVE) { + // Needed so the client doesn't attempt to take away items + abilities.add(Ability.INSTABUILD); + } + + if (flying || spectator) { + if (spectator && !flying) { + // We're "flying locked" in this gamemode + flying = true; + ServerboundPlayerAbilitiesPacket abilitiesPacket = new ServerboundPlayerAbilitiesPacket(true); + sendDownstreamPacket(abilitiesPacket); + } + abilities.add(Ability.FLYING); + } + + if (spectator) { + abilities.add(Ability.NO_CLIP); + } + + abilityLayer.setLayerType(AbilityLayer.Type.BASE); + abilityLayer.setFlySpeed(flySpeed); + abilityLayer.setWalkSpeed(walkSpeed); + Collections.addAll(abilityLayer.getAbilitiesSet(), USED_ABILITIES); + + updateAbilitiesPacket.getAbilityLayers().add(abilityLayer); + sendUpstreamPacket(updateAbilitiesPacket); + return; + } + + AdventureSettingsPacket adventureSettingsPacket = new AdventureSettingsPacket(); + adventureSettingsPacket.setUniqueEntityId(bedrockId); + adventureSettingsPacket.setCommandPermission(commandPermission); + adventureSettingsPacket.setPlayerPermission(playerPermission); + Set flags = adventureSettingsPacket.getSettings(); if (canFly || spectator) { flags.add(AdventureSetting.MAY_FLY); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerAbilitiesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerAbilitiesTranslator.java index 44ae7f425..783f4e824 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerAbilitiesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerAbilitiesTranslator.java @@ -38,6 +38,8 @@ public class JavaPlayerAbilitiesTranslator extends PacketTranslator { + + @Override + public void translate(GeyserSession session, ClientboundPlayerCombatKillPacket packet) { + if (packet.getPlayerId() == session.getPlayerEntity().getEntityId() && MinecraftProtocol.supports1_19_10(session)) { + Component deathMessage = packet.getMessage(); + // TODO - could inject score in, but as of 1.19.10 newlines don't center and start at the left of the first text + DeathInfoPacket deathInfoPacket = new DeathInfoPacket(); + deathInfoPacket.setCauseAttackName(MessageTranslator.convertMessage(deathMessage, session.getLocale())); + session.sendUpstreamPacket(deathInfoPacket); + } + } +}