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:
@@ -322,15 +322,19 @@ public class AvatarEntity extends LivingEntity {
|
|||||||
setFlag(EntityFlag.SWIMMING, true);
|
setFlag(EntityFlag.SWIMMING, true);
|
||||||
} else {
|
} else {
|
||||||
setFlag(EntityFlag.CRAWLING, true);
|
setFlag(EntityFlag.CRAWLING, true);
|
||||||
|
|
||||||
// Look at https://github.com/GeyserMC/Geyser/issues/5316, we're fixing this by spoofing player pitch to 0.
|
// 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
|
@Override
|
||||||
public void setPitch(float pitch) {
|
public void setPitch(float pitch) {
|
||||||
super.setPitch(getFlag(EntityFlag.CRAWLING) ? 0 : pitch);
|
super.setPitch(getFlag(EntityFlag.CRAWLING) && !(this instanceof SessionPlayerEntity) ? 0 : pitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import lombok.Setter;
|
|||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
import org.cloudburstmc.math.vector.Vector3f;
|
import org.cloudburstmc.math.vector.Vector3f;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
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.data.entity.EntityLinkData;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.SetEntityLinkPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.SetEntityLinkPacket;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
|
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.entity.type.living.animal.tameable.ParrotEntity;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
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.EntityMetadata;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -224,4 +226,19 @@ public class PlayerEntity extends AvatarEntity implements GeyserPlayerEntity {
|
|||||||
public Vector3f position() {
|
public Vector3f position() {
|
||||||
return this.position.down(definition.offset());
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -235,11 +235,6 @@ public class SessionPlayerEntity extends PlayerEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setGliding(boolean value) {
|
|
||||||
session.setGliding(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setSneaking(boolean value) {
|
protected void setSneaking(boolean value) {
|
||||||
if (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
|
* 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>
|
* See <a href="https://github.com/GeyserMC/Geyser/issues/3370">issue 3370</a>
|
||||||
@@ -279,7 +269,11 @@ public class SessionPlayerEntity extends PlayerEntity {
|
|||||||
@Override
|
@Override
|
||||||
public void setPose(Pose pose) {
|
public void setPose(Pose pose) {
|
||||||
super.setPose(pose);
|
super.setPose(pose);
|
||||||
session.setPose(pose);
|
|
||||||
|
if (pose != session.getPose()) {
|
||||||
|
session.setPose(pose);
|
||||||
|
updateBedrockMetadata();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getMaxHealth() {
|
public float getMaxHealth() {
|
||||||
|
|||||||
@@ -635,6 +635,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||||||
/**
|
/**
|
||||||
* If the current player is flying
|
* If the current player is flying
|
||||||
*/
|
*/
|
||||||
|
@Setter
|
||||||
private boolean flying = false;
|
private boolean flying = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1320,26 +1321,13 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||||||
|
|
||||||
public void stopSneaking(boolean updateMetaData) {
|
public void stopSneaking(boolean updateMetaData) {
|
||||||
disableBlocking();
|
disableBlocking();
|
||||||
|
|
||||||
setSneaking(false, updateMetaData);
|
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) {
|
private void setSneaking(boolean sneaking, boolean update) {
|
||||||
this.sneaking = sneaking;
|
this.sneaking = sneaking;
|
||||||
|
|
||||||
// Update pose and bounding box on our end
|
playerEntity.setFlag(EntityFlag.SNEAKING, sneaking);
|
||||||
if (!flying) {
|
|
||||||
// The pose and bounding box should not be updated if the player is flying
|
|
||||||
setSneakingPose(sneaking);
|
|
||||||
}
|
|
||||||
collisionManager.updateScaffoldingFlags(false);
|
collisionManager.updateScaffoldingFlags(false);
|
||||||
|
|
||||||
if (update) {
|
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) {
|
public void setNoClip(boolean noClip) {
|
||||||
if (this.noClip == noClip) {
|
if (this.noClip == noClip) {
|
||||||
return;
|
return;
|
||||||
@@ -1393,16 +1349,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||||||
this.sendAdventureSettings();
|
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) {
|
public void setGameMode(GameMode newGamemode) {
|
||||||
boolean currentlySpectator = this.gameMode == GameMode.SPECTATOR;
|
boolean currentlySpectator = this.gameMode == GameMode.SPECTATOR;
|
||||||
this.gameMode = newGamemode;
|
this.gameMode = newGamemode;
|
||||||
@@ -2228,7 +2174,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public float getEyeHeight() {
|
public float getEyeHeight() {
|
||||||
return switch (pose) {
|
return switch (this.pose) {
|
||||||
case SNEAKING -> 1.27f;
|
case SNEAKING -> 1.27f;
|
||||||
case SWIMMING,
|
case SWIMMING,
|
||||||
FALL_FLYING, // Elytra
|
FALL_FLYING, // Elytra
|
||||||
|
|||||||
@@ -83,10 +83,10 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator<Pla
|
|||||||
switch (input) {
|
switch (input) {
|
||||||
case PERFORM_ITEM_INTERACTION -> processItemUseTransaction(session, packet.getItemUseTransaction());
|
case PERFORM_ITEM_INTERACTION -> processItemUseTransaction(session, packet.getItemUseTransaction());
|
||||||
case PERFORM_ITEM_STACK_REQUEST -> session.getPlayerInventoryHolder().translateRequests(List.of(packet.getItemStackRequest()));
|
case PERFORM_ITEM_STACK_REQUEST -> session.getPlayerInventoryHolder().translateRequests(List.of(packet.getItemStackRequest()));
|
||||||
case START_SWIMMING -> session.setSwimming(true);
|
case START_SWIMMING -> entity.setFlag(EntityFlag.SWIMMING, true);
|
||||||
case STOP_SWIMMING -> session.setSwimming(false);
|
case STOP_SWIMMING -> entity.setFlag(EntityFlag.SWIMMING, false);
|
||||||
case START_CRAWLING -> session.setCrawling(true);
|
case START_CRAWLING -> entity.setFlag(EntityFlag.CRAWLING, true);
|
||||||
case STOP_CRAWLING -> session.setCrawling(false);
|
case STOP_CRAWLING -> entity.setFlag(EntityFlag.CRAWLING, false);
|
||||||
case START_SPRINTING -> {
|
case START_SPRINTING -> {
|
||||||
if (!leftOverInputData.contains(PlayerAuthInputData.STOP_SPRINTING)) {
|
if (!leftOverInputData.contains(PlayerAuthInputData.STOP_SPRINTING)) {
|
||||||
if (!session.isSprinting()) {
|
if (!session.isSprinting()) {
|
||||||
@@ -140,11 +140,11 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator<Pla
|
|||||||
session.setFlying(false);
|
session.setFlying(false);
|
||||||
session.sendDownstreamGamePacket(new ServerboundPlayerAbilitiesPacket(false));
|
session.sendDownstreamGamePacket(new ServerboundPlayerAbilitiesPacket(false));
|
||||||
}
|
}
|
||||||
session.setGliding(true);
|
entity.setFlag(EntityFlag.GLIDING, true);
|
||||||
session.sendDownstreamGamePacket(new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_ELYTRA_FLYING));
|
session.sendDownstreamGamePacket(new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_ELYTRA_FLYING));
|
||||||
} else {
|
} else {
|
||||||
entity.forceFlagUpdate();
|
entity.forceFlagUpdate();
|
||||||
session.setGliding(false);
|
entity.setFlag(EntityFlag.GLIDING, false);
|
||||||
// return to flying if we can't start gliding
|
// return to flying if we can't start gliding
|
||||||
if (session.isFlying()) {
|
if (session.isFlying()) {
|
||||||
session.sendAdventureSettings();
|
session.sendAdventureSettings();
|
||||||
@@ -152,14 +152,14 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator<Pla
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case START_SPIN_ATTACK -> session.setSpinAttack(true);
|
case START_SPIN_ATTACK -> entity.setFlag(EntityFlag.DAMAGE_NEARBY_MOBS, true);
|
||||||
case STOP_SPIN_ATTACK -> session.setSpinAttack(false);
|
case STOP_SPIN_ATTACK -> entity.setFlag(EntityFlag.DAMAGE_NEARBY_MOBS, false);
|
||||||
case STOP_GLIDING -> {
|
case STOP_GLIDING -> {
|
||||||
// Java doesn't allow elytra gliding to stop mid-air.
|
// Java doesn't allow elytra gliding to stop mid-air.
|
||||||
boolean shouldBeGliding = entity.isGliding() && entity.canStartGliding();
|
boolean shouldBeGliding = entity.isGliding() && entity.canStartGliding();
|
||||||
// Always update; Bedrock can get real weird if the gliding state is mismatching
|
// Always update; Bedrock can get real weird if the gliding state is mismatching
|
||||||
entity.forceFlagUpdate();
|
entity.forceFlagUpdate();
|
||||||
session.setGliding(shouldBeGliding);
|
entity.setFlag(EntityFlag.GLIDING, shouldBeGliding);
|
||||||
}
|
}
|
||||||
case MISSED_SWING -> {
|
case MISSED_SWING -> {
|
||||||
session.setLastAirHitTick(session.getTicks());
|
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
|
// Vehicle input is send before player movement
|
||||||
processVehicleInput(session, packet, wasJumping);
|
processVehicleInput(session, packet, wasJumping);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user