diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/player/AvatarEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/AvatarEntity.java
index f8bb7f658..68625220c 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/player/AvatarEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/player/AvatarEntity.java
@@ -322,15 +322,19 @@ public class AvatarEntity extends LivingEntity {
setFlag(EntityFlag.SWIMMING, true);
} else {
setFlag(EntityFlag.CRAWLING, true);
+
// Look at https://github.com/GeyserMC/Geyser/issues/5316, we're fixing this by spoofing player pitch to 0.
- updateRotation(this.yaw, 0, this.onGround);
+ // Don't do this for session player however, as that teleport them back and messed up their rotation.
+ if (!(this instanceof SessionPlayerEntity)) {
+ updateRotation(this.yaw, 0, this.onGround);
+ }
}
}
}
@Override
public void setPitch(float pitch) {
- super.setPitch(getFlag(EntityFlag.CRAWLING) ? 0 : pitch);
+ super.setPitch(getFlag(EntityFlag.CRAWLING) && !(this instanceof SessionPlayerEntity) ? 0 : pitch);
}
@Override
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 4e1eb2dcb..71f294ccb 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
@@ -30,6 +30,7 @@ import lombok.Setter;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
+import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityLinkData;
import org.cloudburstmc.protocol.bedrock.packet.SetEntityLinkPacket;
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
@@ -40,6 +41,7 @@ import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.entity.type.living.animal.tameable.ParrotEntity;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
import java.util.Collections;
@@ -224,4 +226,19 @@ public class PlayerEntity extends AvatarEntity implements GeyserPlayerEntity {
public Vector3f position() {
return this.position.down(definition.offset());
}
+
+ // From 1.21.8 code, should be correct since some pose should be prioritized.
+ public Pose getDesiredPose() {
+ if (this.getBedPosition() != null) {
+ return Pose.SLEEPING;
+ } else if (this.getFlag(EntityFlag.SWIMMING) || this.getFlag(EntityFlag.CRAWLING)) {
+ return Pose.SWIMMING;
+ } else if (this.getFlag(EntityFlag.GLIDING)) {
+ return Pose.FALL_FLYING;
+ } else if (this.getFlag(EntityFlag.DAMAGE_NEARBY_MOBS)) {
+ return Pose.SPIN_ATTACK;
+ } else {
+ return this.getFlag(EntityFlag.SNEAKING) && !session.isFlying() ? Pose.SNEAKING : Pose.STANDING;
+ }
+ }
}
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 04117b131..e5f742d73 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
@@ -235,11 +235,6 @@ public class SessionPlayerEntity extends PlayerEntity {
}
}
- @Override
- protected void setGliding(boolean value) {
- session.setGliding(value);
- }
-
@Override
protected void setSneaking(boolean value) {
if (value) {
@@ -250,11 +245,6 @@ public class SessionPlayerEntity extends PlayerEntity {
}
}
- @Override
- protected void setSpinAttack(boolean value) {
- session.setSpinAttack(value);
- }
-
/**
* Since 1.19.40, the client must be re-informed of its bounding box on respawn
* See issue 3370
@@ -279,7 +269,11 @@ public class SessionPlayerEntity extends PlayerEntity {
@Override
public void setPose(Pose pose) {
super.setPose(pose);
- session.setPose(pose);
+
+ if (pose != session.getPose()) {
+ session.setPose(pose);
+ updateBedrockMetadata();
+ }
}
public float getMaxHealth() {
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 fdac156b6..f4e4e5bb3 100644
--- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
+++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
@@ -635,6 +635,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
/**
* If the current player is flying
*/
+ @Setter
private boolean flying = false;
/**
@@ -1320,26 +1321,13 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
public void stopSneaking(boolean updateMetaData) {
disableBlocking();
-
setSneaking(false, updateMetaData);
}
- public void setSpinAttack(boolean spinAttack) {
- switchPose(spinAttack, EntityFlag.DAMAGE_NEARBY_MOBS, Pose.SPIN_ATTACK);
- }
-
- public void setGliding(boolean gliding) {
- switchPose(gliding, EntityFlag.GLIDING, Pose.FALL_FLYING);
- }
-
private void setSneaking(boolean sneaking, boolean update) {
this.sneaking = sneaking;
- // Update pose and bounding box on our end
- if (!flying) {
- // The pose and bounding box should not be updated if the player is flying
- setSneakingPose(sneaking);
- }
+ playerEntity.setFlag(EntityFlag.SNEAKING, sneaking);
collisionManager.updateScaffoldingFlags(false);
if (update) {
@@ -1352,38 +1340,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
}
}
- private void setSneakingPose(boolean sneaking) {
- if (this.pose == Pose.SNEAKING && !sneaking) {
- this.pose = Pose.STANDING;
- playerEntity.setBoundingBoxHeight(playerEntity.getDefinition().height());
- } else if (sneaking) {
- this.pose = Pose.SNEAKING;
- playerEntity.setBoundingBoxHeight(1.5f);
- }
- playerEntity.setFlag(EntityFlag.SNEAKING, sneaking);
- }
-
- public void setSwimming(boolean swimming) {
- if (!swimming && playerEntity.getFlag(EntityFlag.CRAWLING)) {
- // Do not update bounding box.
- playerEntity.setFlag(EntityFlag.SWIMMING, false);
- playerEntity.updateBedrockMetadata();
- return;
- }
- switchPose(swimming, EntityFlag.SWIMMING, Pose.SWIMMING);
- }
-
- public void setCrawling(boolean crawling) {
- switchPose(crawling, EntityFlag.CRAWLING, Pose.SWIMMING);
- }
-
- private void switchPose(boolean value, EntityFlag flag, Pose pose) {
- this.pose = value ? pose : this.pose == pose ? Pose.STANDING : this.pose;
- playerEntity.setDimensionsFromPose(this.pose);
- playerEntity.setFlag(flag, value);
- playerEntity.updateBedrockMetadata();
- }
-
public void setNoClip(boolean noClip) {
if (this.noClip == noClip) {
return;
@@ -1393,16 +1349,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
this.sendAdventureSettings();
}
- public void setFlying(boolean flying) {
- this.flying = flying;
-
- if (sneaking) {
- // update bounding box as it is not reduced when flying
- setSneakingPose(!flying);
- playerEntity.updateBedrockMetadata();
- }
- }
-
public void setGameMode(GameMode newGamemode) {
boolean currentlySpectator = this.gameMode == GameMode.SPECTATOR;
this.gameMode = newGamemode;
@@ -2228,7 +2174,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
}
public float getEyeHeight() {
- return switch (pose) {
+ return switch (this.pose) {
case SNEAKING -> 1.27f;
case SWIMMING,
FALL_FLYING, // Elytra
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java
index 9e70f3339..96b714d45 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockPlayerAuthInputTranslator.java
@@ -83,10 +83,10 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator processItemUseTransaction(session, packet.getItemUseTransaction());
case PERFORM_ITEM_STACK_REQUEST -> session.getPlayerInventoryHolder().translateRequests(List.of(packet.getItemStackRequest()));
- case START_SWIMMING -> session.setSwimming(true);
- case STOP_SWIMMING -> session.setSwimming(false);
- case START_CRAWLING -> session.setCrawling(true);
- case STOP_CRAWLING -> session.setCrawling(false);
+ case START_SWIMMING -> entity.setFlag(EntityFlag.SWIMMING, true);
+ case STOP_SWIMMING -> entity.setFlag(EntityFlag.SWIMMING, false);
+ case START_CRAWLING -> entity.setFlag(EntityFlag.CRAWLING, true);
+ case STOP_CRAWLING -> entity.setFlag(EntityFlag.CRAWLING, false);
case START_SPRINTING -> {
if (!leftOverInputData.contains(PlayerAuthInputData.STOP_SPRINTING)) {
if (!session.isSprinting()) {
@@ -140,11 +140,11 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator session.setSpinAttack(true);
- case STOP_SPIN_ATTACK -> session.setSpinAttack(false);
+ case START_SPIN_ATTACK -> entity.setFlag(EntityFlag.DAMAGE_NEARBY_MOBS, true);
+ case STOP_SPIN_ATTACK -> entity.setFlag(EntityFlag.DAMAGE_NEARBY_MOBS, false);
case STOP_GLIDING -> {
// Java doesn't allow elytra gliding to stop mid-air.
boolean shouldBeGliding = entity.isGliding() && entity.canStartGliding();
// Always update; Bedrock can get real weird if the gliding state is mismatching
entity.forceFlagUpdate();
- session.setGliding(shouldBeGliding);
+ entity.setFlag(EntityFlag.GLIDING, shouldBeGliding);
}
case MISSED_SWING -> {
session.setLastAirHitTick(session.getTicks());
@@ -183,6 +183,10 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator