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:
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user