1
0
mirror of https://github.com/GeyserMC/Geyser.git synced 2025-12-29 03:39:22 +00:00

Don't attempt to use shield while climbing down scaffolding, resolve https://github.com/GeyserMC/Geyser/issues/5552

This commit is contained in:
onebeastchris
2025-05-29 22:25:44 +02:00
parent ccba72afe2
commit 8555fdeb84
5 changed files with 78 additions and 14 deletions

View File

@@ -401,12 +401,10 @@ public class Entity implements GeyserEntity {
public void setFlags(ByteEntityMetadata entityMetadata) {
byte xd = entityMetadata.getPrimitiveValue();
setFlag(EntityFlag.ON_FIRE, ((xd & 0x01) == 0x01) && !getFlag(EntityFlag.FIRE_IMMUNE)); // Otherwise immune entities sometimes flicker onfire
setFlag(EntityFlag.SNEAKING, (xd & 0x02) == 0x02);
setFlag(EntityFlag.SPRINTING, (xd & 0x08) == 0x08);
setSneaking((xd & 0x02) == 0x02);
setSprinting((xd & 0x08) == 0x08);
// Swimming is ignored here and instead we rely on the pose
setGliding((xd & 0x80) == 0x80);
setInvisible((xd & 0x20) == 0x20);
}
@@ -426,6 +424,14 @@ public class Entity implements GeyserEntity {
setFlag(EntityFlag.GLIDING, value);
}
protected void setSprinting(boolean value) {
setFlag(EntityFlag.SPRINTING, value);
}
protected void setSneaking(boolean value) {
setFlag(EntityFlag.SNEAKING, value);
}
/**
* Set an int from 0 - this entity's maximum air - (air / maxAir) represents the percentage of bubbles left
*/

View File

@@ -100,6 +100,9 @@ public class SessionPlayerEntity extends PlayerEntity {
private int lastAirSupply = getMaxAir();
@Getter @Setter
private boolean insideScaffolding = false;
/**
* The client last tick end velocity, used for calculating player onGround.
*/
@@ -206,11 +209,26 @@ public class SessionPlayerEntity extends PlayerEntity {
}
}
@Override
protected void setSprinting(boolean value) {
super.setSprinting(value);
session.setSprinting(value);
}
@Override
protected void setGliding(boolean value) {
session.setGliding(value);
}
@Override
protected void setSneaking(boolean value) {
if (value) {
session.startSneaking();
} else {
session.stopSneaking();
}
}
@Override
protected void setSpinAttack(boolean value) {
session.setSpinAttack(value);

View File

@@ -37,8 +37,8 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket;
import org.geysermc.erosion.util.BlockPositionIterator;
import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.entity.type.player.PlayerEntity;
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
import org.geysermc.geyser.entity.vehicle.ClientVehicle;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.Blocks;
@@ -451,7 +451,8 @@ public class CollisionManager {
* @param updateMetadata whether we should update metadata if something changed
*/
public void updateScaffoldingFlags(boolean updateMetadata) {
Entity entity = session.getPlayerEntity();
SessionPlayerEntity entity = session.getPlayerEntity();
entity.setInsideScaffolding(touchingScaffolding);
boolean isSneakingWithScaffolding = (touchingScaffolding || onScaffolding) && session.isSneaking();
entity.setFlag(EntityFlag.OVER_DESCENDABLE_BLOCK, onScaffolding);

View File

@@ -1359,6 +1359,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
* blocking and sends a packet to the Java server.
*/
private boolean attemptToBlock() {
// Don't try to block while in scaffolding
if (playerEntity.isInsideScaffolding()) {
return false;
}
if (playerInventoryHolder.inventory().getItemInHand().asItem() == Items.SHIELD) {
useItem(Hand.MAIN_HAND);
} else if (playerInventoryHolder.inventory().getOffhand().asItem() == Items.SHIELD) {

View File

@@ -91,14 +91,9 @@ public final class InputCache {
.withShift(bedrockInput.contains(PlayerAuthInputData.SNEAK_CURRENT_RAW) || bedrockInput.contains(PlayerAuthInputData.SNEAK_DOWN))
.withSprint(bedrockInput.contains(PlayerAuthInputData.SPRINT_DOWN));
// Send sneaking state before inputs, matches Java client
boolean sneaking = bedrockInput.contains(PlayerAuthInputData.SNEAKING) ||
// DESCEND_BLOCK is ONLY sent while mobile clients are descending scaffolding.
// PERSIST_SNEAK is ALWAYS sent by mobile clients.
// While we could use SNEAK_CURRENT_RAW, that would also be sent with locked inputs.
// fixes https://github.com/GeyserMC/Geyser/issues/5384
(bedrockInput.contains(PlayerAuthInputData.DESCEND_BLOCK) && bedrockInput.contains(PlayerAuthInputData.PERSIST_SNEAK));
if (oldInputPacket.isShift() != sneaking) {
// Send sneaking before inputs; matches Java edition
boolean sneaking = isSneaking(bedrockInput);
if (session.isSneaking() != sneaking) {
if (sneaking) {
session.sendDownstreamGamePacket(new ServerboundPlayerCommandPacket(entity.javaId(), PlayerState.START_SNEAKING));
session.startSneaking();
@@ -129,4 +124,43 @@ public final class InputCache {
public boolean lastHorizontalCollision() {
return lastHorizontalCollision;
}
/*
As of 1.21.80: relying on the SNEAKING flag will also cause the player to be sneaking after opening chests while sneaking,
even after the client sent STOP_SNEAKING. See https://github.com/GeyserMC/Geyser/issues/5552
Hence, we do not rely on the SNEAKING flag altogether :)
This method is designed to detect changes in sneaking to return the new sneaking state.
*/
public boolean isSneaking(Set<PlayerAuthInputData> authInputData) {
// Flying doesn't send start / stop fly cases; might as well return early
if (session.isFlying()) {
// Of course e.g. mobile handles it differently with a descend case, while
// e.g. Win10 sends SNEAK_DOWN. Why? We'll never know.
return authInputData.contains(PlayerAuthInputData.DESCEND) || authInputData.contains(PlayerAuthInputData.SNEAK_DOWN);
}
boolean sneaking = session.isSneaking();
// Looping through input data as e.g. stop/start sneaking can be sent in the same packet
// and then, the last sent instruction matters
for (PlayerAuthInputData authInput : authInputData) {
switch (authInput) {
case STOP_SNEAKING -> sneaking = false;
case START_SNEAKING -> sneaking = true;
// DESCEND_BLOCK is ONLY sent while mobile clients are descending scaffolding.
// PERSIST_SNEAK is ALWAYS sent by mobile clients.
// fixes https://github.com/GeyserMC/Geyser/issues/5384
case PERSIST_SNEAK -> {
// Ignoring start/stop sneaking while in scaffolding on purpose to ensure
// that we don't spam both cases for every block we went down
if (session.getPlayerEntity().isInsideScaffolding()) {
return authInputData.contains(PlayerAuthInputData.DESCEND_BLOCK) &&
authInputData.contains(PlayerAuthInputData.SNEAK_CURRENT_RAW);
}
}
}
}
return sneaking;
}
}