Fix some regressions in swim handling

This commit is contained in:
Camotoy 2021-12-25 22:46:16 -05:00
parent b134dd3b1c
commit 68c13c08fa
No known key found for this signature in database
GPG key ID: 7EEFB66FE798081F
6 changed files with 47 additions and 18 deletions

View file

@ -65,6 +65,8 @@ import java.util.concurrent.TimeUnit;
@Getter @Setter
public class PlayerEntity extends LivingEntity {
public static final float SNEAKING_POSE_HEIGHT = 1.5f;
private GameProfile profile;
private String username;
private boolean playerList = true; // Player is in the player list
@ -381,7 +383,7 @@ public class PlayerEntity extends LivingEntity {
protected void setDimensions(Pose pose) {
float height;
switch (pose) {
case SNEAKING -> height = 1.5f;
case SNEAKING -> height = SNEAKING_POSE_HEIGHT;
case FALL_FLYING, SPIN_ATTACK, SWIMMING -> height = 0.6f;
default -> {
super.setDimensions(pose);

View file

@ -28,21 +28,17 @@ package org.geysermc.geyser.entity.type.player;
import com.github.steveice10.mc.auth.data.GameProfile;
import com.github.steveice10.mc.protocol.data.game.entity.attribute.Attribute;
import com.github.steveice10.mc.protocol.data.game.entity.attribute.AttributeType;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.AttributeData;
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
import com.nukkitx.protocol.bedrock.packet.RespawnPacket;
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.session.GeyserSession;
import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.util.AttributeUtils;
import java.util.Collections;
@ -112,12 +108,7 @@ public class SessionPlayerEntity extends PlayerEntity {
@Override
public void setFlags(ByteEntityMetadata entityMetadata) {
super.setFlags(entityMetadata);
// Swimming/crawling is controlled by the Java server
boolean swimming = (entityMetadata.getPrimitiveValue() & 0x10) == 0x10;
if (swimming) {
setPose(Pose.SWIMMING);
}
session.setSwimmingInWater(swimming && getFlag(EntityFlag.SPRINTING));
session.setSwimmingInWater((entityMetadata.getPrimitiveValue() & 0x10) == 0x10 && getFlag(EntityFlag.SPRINTING));
refreshSpeed = true;
}

View file

@ -362,7 +362,22 @@ public class CollisionManager {
* @return true if the block located at the player's floor position plus 1 would intersect with the player,
* were they not sneaking
*/
public boolean isUnderSlab() {
public boolean mustPlayerSneakHere() {
return checkPose(EntityDefinitions.PLAYER.height());
}
/**
* @return true if the block located at the player's floor position plus 1 would intersect with the player,
* were they not crawling
*/
public boolean mustPlayerCrawlHere() {
return checkPose(PlayerEntity.SNEAKING_POSE_HEIGHT);
}
/**
* @param height check and see if this height is invalid in the current player position
*/
private boolean checkPose(float height) {
Vector3i position = session.getPlayerEntity().getPosition().toInt();
BlockCollision collision = BlockUtils.getCollisionAt(session, position);
if (collision != null) {
@ -370,7 +385,7 @@ public class CollisionManager {
// at the current location.
double originalY = playerBoundingBox.getMiddleY();
double originalHeight = playerBoundingBox.getSizeY();
double standingY = originalY - (originalHeight / 2.0) + (EntityDefinitions.PLAYER.height() / 2.0);
double standingY = originalY - (originalHeight / 2.0) + (height / 2.0);
playerBoundingBox.setSizeY(EntityDefinitions.PLAYER.height());
playerBoundingBox.setMiddleY(standingY);

View file

@ -1069,6 +1069,18 @@ public class GeyserSession implements GeyserConnection, CommandSender {
playerEntity.setFlag(EntityFlag.SNEAKING, sneaking);
}
public void setSwimming(boolean swimming) {
if (swimming) {
this.pose = Pose.SWIMMING;
playerEntity.setBoundingBoxHeight(0.6f);
} else {
this.pose = Pose.STANDING;
playerEntity.setBoundingBoxHeight(playerEntity.getDefinition().height());
}
playerEntity.setFlag(EntityFlag.SWIMMING, swimming);
playerEntity.updateBedrockMetadata();
}
public void setFlying(boolean flying) {
this.flying = flying;
@ -1087,7 +1099,7 @@ public class GeyserSession implements GeyserConnection, CommandSender {
public AttributeData adjustSpeed() {
AttributeData currentPlayerSpeed = playerEntity.getAttributes().get(GeyserAttributeType.MOVEMENT_SPEED);
if (currentPlayerSpeed != null) {
if ((pose.equals(Pose.SNEAKING) && !sneaking && collisionManager.isUnderSlab()) ||
if ((pose.equals(Pose.SNEAKING) && !sneaking && collisionManager.mustPlayerSneakHere()) ||
(!swimmingInWater && playerEntity.getFlag(EntityFlag.SWIMMING) && !collisionManager.isPlayerInWater())) {
// Either of those conditions means that Bedrock goes zoom when they shouldn't be
AttributeData speedAttribute = GeyserAttributeType.MOVEMENT_SPEED.getAttribute(originalSpeedAttribute / 3.32f);

View file

@ -44,6 +44,11 @@ public class BedrockAdventureSettingsTranslator extends PacketTranslator<Adventu
// We should always be flying in spectator mode
session.sendAdventureSettings();
return;
} else if (isFlying && session.getPlayerEntity().getFlag(EntityFlag.SWIMMING) && session.getCollisionManager().isPlayerInWater()) {
// As of 1.18.1, Java Edition cannot fly while in water, but it can fly while crawling
// If this isn't present, swimming on a 1.13.2 server and then attempting to fly will put you into a flying/swimming state that is invalid on JE
session.sendAdventureSettings();
return;
}
session.setFlying(isFlying);

View file

@ -77,16 +77,20 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
session.sendUpstreamPacket(attributesPacket);
break;
case START_SWIMMING:
if (!session.getPlayerEntity().getFlag(EntityFlag.SWIMMING)) {
if (!entity.getFlag(EntityFlag.SWIMMING)) {
ServerboundPlayerCommandPacket startSwimPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SPRINTING);
session.sendDownstreamPacket(startSwimPacket);
session.setSwimming(true);
}
break;
case STOP_SWIMMING:
// Prevent packet spam when Bedrock players are crawling near the edge of a block
if (session.isSwimmingInWater()) {
if (!session.getCollisionManager().mustPlayerCrawlHere()) {
ServerboundPlayerCommandPacket stopSwimPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SPRINTING);
session.sendDownstreamPacket(stopSwimPacket);
session.setSwimming(false);
}
break;
case START_GLIDE:
@ -135,14 +139,14 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
session.setSneaking(false);
break;
case START_SPRINT:
if (!session.getPlayerEntity().getFlag(EntityFlag.SWIMMING)) {
if (!entity.getFlag(EntityFlag.SWIMMING)) {
ServerboundPlayerCommandPacket startSprintPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SPRINTING);
session.sendDownstreamPacket(startSprintPacket);
session.setSprinting(true);
}
break;
case STOP_SPRINT:
if (!session.getPlayerEntity().getFlag(EntityFlag.SWIMMING)) {
if (!entity.getFlag(EntityFlag.SWIMMING)) {
ServerboundPlayerCommandPacket stopSprintPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SPRINTING);
session.sendDownstreamPacket(stopSprintPacket);
}