1
0
mirror of https://github.com/GeyserMC/Geyser.git synced 2025-12-19 14:59:27 +00:00

Fix: Player pose switching behaviour (#5987)

* More accurate pose switching behaviour.

* Revert some change.
This commit is contained in:
oryxel
2025-11-16 21:49:32 +07:00
committed by GitHub
parent 659369a913
commit a58fa79805
5 changed files with 44 additions and 79 deletions

View File

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

View File

@@ -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;
}
}
}

View File

@@ -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 <a href="https://github.com/GeyserMC/Geyser/issues/3370">issue 3370</a>
@@ -279,7 +269,11 @@ public class SessionPlayerEntity extends PlayerEntity {
@Override
public void setPose(Pose pose) {
super.setPose(pose);
if (pose != session.getPose()) {
session.setPose(pose);
updateBedrockMetadata();
}
}
public float getMaxHealth() {

View File

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

View File

@@ -83,10 +83,10 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator<Pla
switch (input) {
case PERFORM_ITEM_INTERACTION -> 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<Pla
session.setFlying(false);
session.sendDownstreamGamePacket(new ServerboundPlayerAbilitiesPacket(false));
}
session.setGliding(true);
entity.setFlag(EntityFlag.GLIDING, true);
session.sendDownstreamGamePacket(new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_ELYTRA_FLYING));
} else {
entity.forceFlagUpdate();
session.setGliding(false);
entity.setFlag(EntityFlag.GLIDING, false);
// return to flying if we can't start gliding
if (session.isFlying()) {
session.sendAdventureSettings();
@@ -152,14 +152,14 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator<Pla
}
}
}
case START_SPIN_ATTACK -> 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<Pla
}
}
// The player will calculate the "desired" pose at the end of every tick, if this pose still invalid then
// it will consider the smaller pose, but we don't need to calculate that, we can go off what the client sent us.
entity.setPose(entity.getDesiredPose());
// Vehicle input is send before player movement
processVehicleInput(session, packet, wasJumping);