Initial support for 1.19.10 Bedrock

This commit is contained in:
Camotoy 2022-07-10 13:33:39 -04:00
parent 2ce7ff850a
commit 4d0952c224
No known key found for this signature in database
GPG key ID: 7EEFB66FE798081F
8 changed files with 151 additions and 13 deletions

View file

@ -128,8 +128,8 @@
</dependency>
<dependency>
<groupId>com.github.CloudburstMC.Protocol</groupId>
<artifactId>bedrock-v527</artifactId>
<version>977a9a1</version>
<artifactId>bedrock-v534</artifactId>
<version>a78a64b</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@ -145,7 +145,7 @@
<dependency>
<groupId>com.nukkitx.network</groupId>
<artifactId>raknet</artifactId>
<version>1.6.28-20211202.034102-5</version>
<version>1.6.28-20220125.214016-6</version>
<scope>compile</scope>
<exclusions>
<exclusion>

View file

@ -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<AbilityLayer> 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());

View file

@ -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.

View file

@ -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());

View file

@ -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.
*

View file

@ -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<Ability> 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<AdventureSetting> flags = adventureSettingsPacket.getSettings();
if (canFly || spectator) {
flags.add(AdventureSetting.MAY_FLY);

View file

@ -38,6 +38,8 @@ public class JavaPlayerAbilitiesTranslator extends PacketTranslator<ClientboundP
session.setCanFly(packet.isCanFly());
session.setFlying(packet.isFlying());
session.setInstabuild(packet.isCreative());
session.setFlySpeed(packet.getFlySpeed());
session.setWalkSpeed(packet.getWalkSpeed());
session.sendAdventureSettings();
}
}

View file

@ -0,0 +1,50 @@
/*
* 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.entity.player;
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.player.ClientboundPlayerCombatKillPacket;
import com.nukkitx.protocol.bedrock.packet.DeathInfoPacket;
import net.kyori.adventure.text.Component;
import org.geysermc.geyser.network.MinecraftProtocol;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.translator.text.MessageTranslator;
@Translator(packet = ClientboundPlayerCombatKillPacket.class)
public class JavaPlayerCombatKillTranslator extends PacketTranslator<ClientboundPlayerCombatKillPacket> {
@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);
}
}
}