mirror of
https://github.com/GeyserMC/Geyser.git
synced 2025-03-14 11:43:48 +01:00
Allow for crawling and moving in one-block spaces where possible (#1814)
This commit brings full support for crawling, sneaking under 1.5-block-tall spaces, and swimming in one-block areas. There is a check in place that decreases the player's speed to something comparable to Java if they are in a situation where they would otherwise go at normal walking speed (for example: without the check, a Bedrock player would go at full walking speed while crawling).
This commit is contained in:
parent
7dc9c031c2
commit
120769c7f6
11 changed files with 229 additions and 44 deletions
|
@ -263,7 +263,7 @@ public class Entity {
|
|||
metadata.getFlags().setFlag(EntityFlag.ON_FIRE, ((xd & 0x01) == 0x01) && !metadata.getFlags().getFlag(EntityFlag.FIRE_IMMUNE)); // Otherwise immune entities sometimes flicker onfire
|
||||
metadata.getFlags().setFlag(EntityFlag.SNEAKING, (xd & 0x02) == 0x02);
|
||||
metadata.getFlags().setFlag(EntityFlag.SPRINTING, (xd & 0x08) == 0x08);
|
||||
metadata.getFlags().setFlag(EntityFlag.SWIMMING, ((xd & 0x10) == 0x10) && metadata.getFlags().getFlag(EntityFlag.SPRINTING)); // Otherwise swimming is enabled on older servers
|
||||
// Swimming is ignored here and instead we rely on the pose
|
||||
metadata.getFlags().setFlag(EntityFlag.GLIDING, (xd & 0x80) == 0x80);
|
||||
|
||||
// Armour stands are handled in their own class
|
||||
|
@ -297,16 +297,37 @@ public class Entity {
|
|||
case 5: // no gravity
|
||||
metadata.getFlags().setFlag(EntityFlag.HAS_GRAVITY, !(boolean) entityMetadata.getValue());
|
||||
break;
|
||||
case 6: // Pose change
|
||||
if (entityMetadata.getValue().equals(Pose.SLEEPING)) {
|
||||
metadata.getFlags().setFlag(EntityFlag.SLEEPING, true);
|
||||
metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.2f);
|
||||
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.2f);
|
||||
} else if (metadata.getFlags().getFlag(EntityFlag.SLEEPING)) {
|
||||
metadata.getFlags().setFlag(EntityFlag.SLEEPING, false);
|
||||
metadata.put(EntityData.BOUNDING_BOX_WIDTH, getEntityType().getWidth());
|
||||
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, getEntityType().getHeight());
|
||||
case 6: // Pose change - typically used for bounding box and not animation
|
||||
Pose pose = (Pose) entityMetadata.getValue();
|
||||
|
||||
metadata.getFlags().setFlag(EntityFlag.SLEEPING, pose.equals(Pose.SLEEPING));
|
||||
// Triggered when crawling
|
||||
metadata.getFlags().setFlag(EntityFlag.SWIMMING, pose.equals(Pose.SWIMMING));
|
||||
float width = entityType.getWidth();
|
||||
float height = entityType.getHeight();
|
||||
switch (pose) {
|
||||
case SLEEPING:
|
||||
if (this instanceof LivingEntity) {
|
||||
width = 0.2f;
|
||||
height = 0.2f;
|
||||
}
|
||||
break;
|
||||
case SNEAKING:
|
||||
if (entityType == EntityType.PLAYER) {
|
||||
height = 1.5f;
|
||||
}
|
||||
break;
|
||||
case FALL_FLYING:
|
||||
case SPIN_ATTACK:
|
||||
case SWIMMING:
|
||||
if (entityType == EntityType.PLAYER) {
|
||||
// Seems like this is only cared about for players; nothing else
|
||||
height = 0.6f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
metadata.put(EntityData.BOUNDING_BOX_WIDTH, width);
|
||||
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, height);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,10 @@
|
|||
package org.geysermc.connector.entity.player;
|
||||
|
||||
import com.github.steveice10.mc.auth.data.GameProfile;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
@ -35,6 +38,10 @@ import java.util.UUID;
|
|||
* The entity class specifically for a {@link GeyserSession}'s player.
|
||||
*/
|
||||
public class SessionPlayerEntity extends PlayerEntity {
|
||||
/**
|
||||
* Whether to check for updated speed after all entity metadata has been processed
|
||||
*/
|
||||
private boolean refreshSpeed = false;
|
||||
|
||||
private final GeyserSession session;
|
||||
|
||||
|
@ -43,7 +50,6 @@ public class SessionPlayerEntity extends PlayerEntity {
|
|||
|
||||
valid = true;
|
||||
this.session = session;
|
||||
this.session.getCollisionManager().updatePlayerBoundingBox(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -64,4 +70,27 @@ public class SessionPlayerEntity extends PlayerEntity {
|
|||
}
|
||||
super.setPosition(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
if (entityMetadata.getId() == 0) {
|
||||
session.setSwimmingInWater((((byte) entityMetadata.getValue()) & 0x10) == 0x10 && metadata.getFlags().getFlag(EntityFlag.SPRINTING));
|
||||
refreshSpeed = true;
|
||||
} else if (entityMetadata.getId() == 6) {
|
||||
session.setPose((Pose) entityMetadata.getValue());
|
||||
refreshSpeed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(GeyserSession session) {
|
||||
super.updateBedrockMetadata(session);
|
||||
if (refreshSpeed) {
|
||||
if (session.adjustSpeed()) {
|
||||
updateBedrockAttributes(session);
|
||||
}
|
||||
refreshSpeed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ import com.github.steveice10.mc.auth.service.MsaAuthenticationService;
|
|||
import com.github.steveice10.mc.protocol.MinecraftConstants;
|
||||
import com.github.steveice10.mc.protocol.MinecraftProtocol;
|
||||
import com.github.steveice10.mc.protocol.data.SubProtocol;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
||||
import com.github.steveice10.mc.protocol.data.game.recipe.Recipe;
|
||||
import com.github.steveice10.mc.protocol.data.game.statistic.Statistic;
|
||||
|
@ -55,6 +56,8 @@ import com.nukkitx.protocol.bedrock.BedrockPacket;
|
|||
import com.nukkitx.protocol.bedrock.BedrockServerSession;
|
||||
import com.nukkitx.protocol.bedrock.data.*;
|
||||
import com.nukkitx.protocol.bedrock.data.command.CommandPermission;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.packet.*;
|
||||
import com.nukkitx.protocol.bedrock.v431.Bedrock_v431;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
|
@ -78,6 +81,8 @@ import org.geysermc.connector.command.CommandSender;
|
|||
import org.geysermc.connector.common.AuthType;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.Tickable;
|
||||
import org.geysermc.connector.entity.attribute.Attribute;
|
||||
import org.geysermc.connector.entity.attribute.AttributeType;
|
||||
import org.geysermc.connector.entity.player.SessionPlayerEntity;
|
||||
import org.geysermc.connector.entity.player.SkullPlayerEntity;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
|
@ -219,6 +224,12 @@ public class GeyserSession implements CommandSender {
|
|||
|
||||
private boolean sneaking;
|
||||
|
||||
/**
|
||||
* Stores the Java pose that the server and/or Geyser believes the player currently has.
|
||||
*/
|
||||
@Setter
|
||||
private Pose pose = Pose.STANDING;
|
||||
|
||||
@Setter
|
||||
private boolean sprinting;
|
||||
|
||||
|
@ -228,6 +239,22 @@ public class GeyserSession implements CommandSender {
|
|||
@Setter
|
||||
private boolean jumping;
|
||||
|
||||
/**
|
||||
* Whether the player is swimming in water.
|
||||
* Used to update speed when crawling.
|
||||
*/
|
||||
@Setter
|
||||
private boolean swimmingInWater;
|
||||
|
||||
/**
|
||||
* Tracks the original speed attribute.
|
||||
*
|
||||
* We need to do this in order to emulate speeds when sneaking under 1.5-blocks-tall areas if the player isn't sneaking,
|
||||
* and when crawling.
|
||||
*/
|
||||
@Setter
|
||||
private float originalSpeedAttribute;
|
||||
|
||||
/**
|
||||
* The dimension of the player.
|
||||
* As all entities are in the same world, this can be safely applied to all other entities.
|
||||
|
@ -427,8 +454,7 @@ public class GeyserSession implements CommandSender {
|
|||
this.collisionManager = new CollisionManager(this);
|
||||
|
||||
this.playerEntity = new SessionPlayerEntity(this);
|
||||
this.worldCache = new WorldCache(this);
|
||||
this.windowCache = new WindowCache(this);
|
||||
collisionManager.updatePlayerBoundingBox(this.playerEntity.getPosition());
|
||||
|
||||
this.playerInventory = new PlayerInventory();
|
||||
this.openInventory = null;
|
||||
|
@ -829,8 +855,22 @@ public class GeyserSession implements CommandSender {
|
|||
|
||||
public void setSneaking(boolean sneaking) {
|
||||
this.sneaking = sneaking;
|
||||
collisionManager.updatePlayerBoundingBox();
|
||||
collisionManager.updateScaffoldingFlags();
|
||||
|
||||
// Update pose and bounding box on our end
|
||||
if (!sneaking && adjustSpeed()) {
|
||||
// Update attributes since we're still "sneaking" under a 1.5-block-tall area
|
||||
playerEntity.updateBedrockAttributes(this);
|
||||
// the server *should* update our pose once it has returned to normal
|
||||
} else {
|
||||
this.pose = sneaking ? Pose.SNEAKING : Pose.STANDING;
|
||||
playerEntity.getMetadata().put(EntityData.BOUNDING_BOX_HEIGHT, sneaking ? 1.5f : playerEntity.getEntityType().getHeight());
|
||||
playerEntity.getMetadata().getFlags().setFlag(EntityFlag.SNEAKING, sneaking);
|
||||
|
||||
collisionManager.updatePlayerBoundingBox();
|
||||
collisionManager.updateScaffoldingFlags(false);
|
||||
}
|
||||
|
||||
playerEntity.updateBedrockMetadata(this);
|
||||
|
||||
if (mouseoverEntity != null) {
|
||||
// Horses, etc can change their property depending on if you're sneaking
|
||||
|
@ -838,6 +878,35 @@ public class GeyserSession implements CommandSender {
|
|||
}
|
||||
}
|
||||
|
||||
public void setSwimming(boolean swimming) {
|
||||
this.pose = swimming ? Pose.SWIMMING : Pose.STANDING;
|
||||
playerEntity.getMetadata().put(EntityData.BOUNDING_BOX_HEIGHT, swimming ? 0.6f : playerEntity.getEntityType().getHeight());
|
||||
playerEntity.getMetadata().getFlags().setFlag(EntityFlag.SWIMMING, swimming);
|
||||
playerEntity.updateBedrockMetadata(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts speed if the player is crawling.
|
||||
*
|
||||
* @return true if attributes should be updated.
|
||||
*/
|
||||
public boolean adjustSpeed() {
|
||||
Attribute currentPlayerSpeed = playerEntity.getAttributes().get(AttributeType.MOVEMENT_SPEED);
|
||||
if (currentPlayerSpeed != null) {
|
||||
if ((pose.equals(Pose.SNEAKING) && !sneaking && collisionManager.isUnderSlab()) ||
|
||||
(!swimmingInWater && playerEntity.getMetadata().getFlags().getFlag(EntityFlag.SWIMMING) && !collisionManager.isPlayerInWater())) {
|
||||
// Either of those conditions means that Bedrock goes zoom when they shouldn't be
|
||||
currentPlayerSpeed.setValue(originalSpeedAttribute / 3.32f);
|
||||
return true;
|
||||
} else if (originalSpeedAttribute != currentPlayerSpeed.getValue()) {
|
||||
// Speed has reset to normal
|
||||
currentPlayerSpeed.setValue(originalSpeedAttribute);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be overwritten for GeyserConnect.
|
||||
*/
|
||||
|
|
|
@ -27,6 +27,7 @@ package org.geysermc.connector.network.translators.bedrock;
|
|||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerAbilitiesPacket;
|
||||
import com.nukkitx.protocol.bedrock.data.AdventureSetting;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
|
@ -37,8 +38,13 @@ public class BedrockAdventureSettingsTranslator extends PacketTranslator<Adventu
|
|||
|
||||
@Override
|
||||
public void translate(AdventureSettingsPacket packet, GeyserSession session) {
|
||||
ClientPlayerAbilitiesPacket abilitiesPacket =
|
||||
new ClientPlayerAbilitiesPacket(packet.getSettings().contains(AdventureSetting.FLYING));
|
||||
boolean isFlying = packet.getSettings().contains(AdventureSetting.FLYING);
|
||||
ClientPlayerAbilitiesPacket abilitiesPacket = new ClientPlayerAbilitiesPacket(isFlying);
|
||||
session.sendDownstreamPacket(abilitiesPacket);
|
||||
|
||||
if (isFlying && session.getPlayerEntity().getMetadata().getFlags().getFlag(EntityFlag.SWIMMING)) {
|
||||
// Bedrock can fly and swim at the same time? Make sure that can't happen
|
||||
session.setSwimming(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,6 @@ import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlaye
|
|||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlags;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.ContainerId;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
|
||||
|
@ -150,13 +149,18 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
EntityFlags flags = session.getPlayerEntity().getMetadata().getFlags();
|
||||
|
||||
// Adjust position for current eye height
|
||||
if (flags.getFlag(EntityFlag.SNEAKING)) {
|
||||
playerPosition = playerPosition.sub(0, (EntityType.PLAYER.getOffset() - 1.27f), 0);
|
||||
} else if (flags.getFlag(EntityFlag.SWIMMING) || flags.getFlag(EntityFlag.GLIDING) || flags.getFlag(EntityFlag.DAMAGE_NEARBY_MOBS)) {
|
||||
// Swimming, gliding, or using the trident spin attack
|
||||
playerPosition = playerPosition.sub(0, (EntityType.PLAYER.getOffset() - 0.4f), 0);
|
||||
} else if (flags.getFlag(EntityFlag.SLEEPING)) {
|
||||
playerPosition = playerPosition.sub(0, (EntityType.PLAYER.getOffset() - 0.2f), 0);
|
||||
switch (session.getPose()) {
|
||||
case SNEAKING:
|
||||
playerPosition = playerPosition.sub(0, (EntityType.PLAYER.getOffset() - 1.27f), 0);
|
||||
break;
|
||||
case SWIMMING:
|
||||
case FALL_FLYING: // Elytra
|
||||
case SPIN_ATTACK: // Trident spin attack
|
||||
playerPosition = playerPosition.sub(0, (EntityType.PLAYER.getOffset() - 0.4f), 0);
|
||||
break;
|
||||
case SLEEPING:
|
||||
playerPosition = playerPosition.sub(0, (EntityType.PLAYER.getOffset() - 0.2f), 0);
|
||||
break;
|
||||
} // else, we don't have to modify the position
|
||||
|
||||
float diffX = playerPosition.getX() - packet.getBlockPosition().getX();
|
||||
|
|
|
@ -59,8 +59,6 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
|
|||
@Override
|
||||
public void translate(PlayerActionPacket packet, GeyserSession session) {
|
||||
Entity entity = session.getPlayerEntity();
|
||||
if (entity == null)
|
||||
return;
|
||||
|
||||
// Send book update before any player action
|
||||
if (packet.getAction() != PlayerActionType.RESPAWN) {
|
||||
|
@ -84,10 +82,14 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
|
|||
case START_SWIMMING:
|
||||
ClientPlayerStatePacket startSwimPacket = new ClientPlayerStatePacket((int) entity.getEntityId(), PlayerState.START_SPRINTING);
|
||||
session.sendDownstreamPacket(startSwimPacket);
|
||||
|
||||
session.setSwimming(true);
|
||||
break;
|
||||
case STOP_SWIMMING:
|
||||
ClientPlayerStatePacket stopSwimPacket = new ClientPlayerStatePacket((int) entity.getEntityId(), PlayerState.STOP_SPRINTING);
|
||||
session.sendDownstreamPacket(stopSwimPacket);
|
||||
|
||||
session.setSwimming(false);
|
||||
break;
|
||||
case START_GLIDE:
|
||||
// Otherwise gliding will not work in creative
|
||||
|
@ -114,7 +116,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
|
|||
}
|
||||
session.sendDownstreamPacket(useItemPacket);
|
||||
session.getPlayerEntity().getMetadata().getFlags().setFlag(EntityFlag.BLOCKING, true);
|
||||
session.getPlayerEntity().updateBedrockMetadata(session);
|
||||
// metadata will be updated when sneaking
|
||||
}
|
||||
|
||||
session.setSneaking(true);
|
||||
|
@ -128,7 +130,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
|
|||
ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, BlockUtils.POSITION_ZERO, BlockFace.DOWN);
|
||||
session.sendDownstreamPacket(releaseItemPacket);
|
||||
session.getPlayerEntity().getMetadata().getFlags().setFlag(EntityFlag.BLOCKING, false);
|
||||
session.getPlayerEntity().updateBedrockMetadata(session);
|
||||
// metadata will be updated when sneaking
|
||||
}
|
||||
|
||||
session.setSneaking(false);
|
||||
|
|
|
@ -28,6 +28,7 @@ package org.geysermc.connector.network.translators.collision;
|
|||
import com.nukkitx.math.vector.Vector3d;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlags;
|
||||
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
|
||||
|
@ -38,7 +39,9 @@ import org.geysermc.connector.entity.player.PlayerEntity;
|
|||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.collision.translators.BlockCollision;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -66,6 +69,10 @@ public class CollisionManager {
|
|||
* This check doesn't allow players right up against the block, so they must be pushed slightly away.
|
||||
*/
|
||||
public static final double COLLISION_TOLERANCE = 0.00001;
|
||||
/**
|
||||
* Trims Y coordinates when jumping to prevent rounding issues being sent to the server.
|
||||
*/
|
||||
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.#####");
|
||||
|
||||
public CollisionManager(GeyserSession session) {
|
||||
this.session = session;
|
||||
|
@ -104,17 +111,14 @@ public class CollisionManager {
|
|||
} else {
|
||||
playerPosition = session.getPlayerEntity().getPosition();
|
||||
}
|
||||
playerBoundingBox = new BoundingBox(playerPosition.getX(), playerPosition.getY() + 0.9, playerPosition.getZ(), 0.6, 1.8, 0.6);
|
||||
playerBoundingBox = new BoundingBox(playerPosition.getX(), playerPosition.getY() + 0.9, playerPosition.getZ(),
|
||||
EntityType.PLAYER.getWidth(), EntityType.PLAYER.getHeight(), EntityType.PLAYER.getLength());
|
||||
} else {
|
||||
// According to the Minecraft Wiki, when sneaking:
|
||||
// - In Bedrock Edition, the height becomes 1.65 blocks, allowing movement through spaces as small as 1.75 (2 - 1⁄4) blocks high.
|
||||
// - In Java Edition, the height becomes 1.5 blocks.
|
||||
// TODO: Have this depend on the player's literal bounding box variable
|
||||
if (session.isSneaking()) {
|
||||
playerBoundingBox.setSizeY(1.5);
|
||||
} else {
|
||||
playerBoundingBox.setSizeY(1.8);
|
||||
}
|
||||
// Other instances have the player's bounding box become as small as 0.6 or 0.2.
|
||||
playerBoundingBox.setSizeY(session.getPlayerEntity().getMetadata().getFloat(EntityData.BOUNDING_BOX_HEIGHT));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,6 +152,11 @@ public class CollisionManager {
|
|||
position = Vector3d.from(playerBoundingBox.getMiddleX(),
|
||||
playerBoundingBox.getMiddleY() - (playerBoundingBox.getSizeY() / 2),
|
||||
playerBoundingBox.getMiddleZ());
|
||||
|
||||
if (!onGround) {
|
||||
// Trim the position to prevent rounding errors that make Java think we are clipping into a block
|
||||
position = Vector3d.from(position.getX(), Double.parseDouble(DECIMAL_FORMAT.format(position.getY())), position.getZ());
|
||||
}
|
||||
} else {
|
||||
// When chunk caching is off, we have to rely on this
|
||||
// It rounds the Y position up to the nearest 0.5
|
||||
|
@ -246,16 +255,48 @@ public class CollisionManager {
|
|||
}
|
||||
}
|
||||
|
||||
updateScaffoldingFlags();
|
||||
updateScaffoldingFlags(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the block located at the player's floor position plus 1 would intersect with the player,
|
||||
* were they not sneaking
|
||||
*/
|
||||
public boolean isUnderSlab() {
|
||||
if (!session.getConnector().getConfig().isCacheChunks()) {
|
||||
// We can't reliably determine this
|
||||
return false;
|
||||
}
|
||||
Vector3i position = session.getPlayerEntity().getPosition().toInt();
|
||||
BlockCollision collision = CollisionTranslator.getCollisionAt(session, position.getX(), position.getY(), position.getZ());
|
||||
if (collision != null) {
|
||||
// Determine, if the player's bounding box *were* at full height, if it would intersect with the block
|
||||
// at the current location.
|
||||
playerBoundingBox.setSizeY(EntityType.PLAYER.getHeight());
|
||||
boolean result = collision.checkIntersection(playerBoundingBox);
|
||||
playerBoundingBox.setSizeY(session.getPlayerEntity().getMetadata().getFloat(EntityData.BOUNDING_BOX_HEIGHT));
|
||||
return result;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if the player is currently in a water block
|
||||
*/
|
||||
public boolean isPlayerInWater() {
|
||||
return session.getConnector().getConfig().isCacheChunks()
|
||||
&& session.getConnector().getWorldManager().getBlockAt(session, session.getPlayerEntity().getPosition().toInt()) == BlockTranslator.JAVA_WATER_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates scaffolding entity flags
|
||||
* Scaffolding needs to be checked per-move since it's a flag in Bedrock but Java does it client-side
|
||||
*
|
||||
* @param updateMetadata whether we should update metadata if something changed
|
||||
*/
|
||||
public void updateScaffoldingFlags() {
|
||||
public void updateScaffoldingFlags(boolean updateMetadata) {
|
||||
EntityFlags flags = session.getPlayerEntity().getMetadata().getFlags();
|
||||
boolean flagsChanged;
|
||||
boolean isSneakingWithScaffolding = (touchingScaffolding || onScaffolding) && session.isSneaking();
|
||||
|
@ -269,7 +310,7 @@ public class CollisionManager {
|
|||
flagsChanged |= flags.getFlag(EntityFlag.IN_SCAFFOLDING) != touchingScaffolding;
|
||||
flags.setFlag(EntityFlag.IN_SCAFFOLDING, touchingScaffolding);
|
||||
|
||||
if (flagsChanged) {
|
||||
if (flagsChanged && updateMetadata) {
|
||||
session.getPlayerEntity().updateBedrockMetadata(session);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,13 +25,12 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.java.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityPositionPacket;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityPositionPacket;
|
||||
|
||||
@Translator(packet = ServerEntityPositionPacket.class)
|
||||
public class JavaEntityPositionTranslator extends PacketTranslator<ServerEntityPositionPacket> {
|
||||
|
||||
|
|
|
@ -67,7 +67,12 @@ public class JavaEntityPropertiesTranslator extends PacketTranslator<ServerEntit
|
|||
entity.getAttributes().put(AttributeType.MOVEMENT_SPEED, AttributeType.MOVEMENT_SPEED.getAttribute((float) AttributeUtils.calculateValue(attribute)));
|
||||
break;
|
||||
case GENERIC_MOVEMENT_SPEED:
|
||||
entity.getAttributes().put(AttributeType.MOVEMENT_SPEED, AttributeType.MOVEMENT_SPEED.getAttribute((float) AttributeUtils.calculateValue(attribute)));
|
||||
float value = (float) AttributeUtils.calculateValue(attribute);
|
||||
entity.getAttributes().put(AttributeType.MOVEMENT_SPEED, AttributeType.MOVEMENT_SPEED.getAttribute(value));
|
||||
if (isSessionPlayer) {
|
||||
session.setOriginalSpeedAttribute(value);
|
||||
session.adjustSpeed();
|
||||
}
|
||||
break;
|
||||
case GENERIC_FOLLOW_RANGE:
|
||||
entity.getAttributes().put(AttributeType.FOLLOW_RANGE, AttributeType.FOLLOW_RANGE.getAttribute((float) AttributeUtils.calculateValue(attribute)));
|
||||
|
|
|
@ -52,6 +52,7 @@ public abstract class BlockTranslator {
|
|||
* The Java block runtime ID of air
|
||||
*/
|
||||
public static final int JAVA_AIR_ID = 0;
|
||||
public static final int JAVA_WATER_ID;
|
||||
/**
|
||||
* The Bedrock block runtime ID of air
|
||||
*/
|
||||
|
@ -134,6 +135,7 @@ public abstract class BlockTranslator {
|
|||
int furnaceLitRuntimeId = -1;
|
||||
int spawnerRuntimeId = -1;
|
||||
int uniqueJavaId = -1;
|
||||
int waterRuntimeId = -1;
|
||||
Iterator<Map.Entry<String, JsonNode>> blocksIterator = BLOCKS_JSON.fields();
|
||||
while (blocksIterator.hasNext()) {
|
||||
javaRuntimeId++;
|
||||
|
@ -199,6 +201,9 @@ public abstract class BlockTranslator {
|
|||
|
||||
} else if (javaId.startsWith("minecraft:spawner")) {
|
||||
spawnerRuntimeId = javaRuntimeId;
|
||||
|
||||
} else if ("minecraft:water[level=0]".equals(javaId)) {
|
||||
waterRuntimeId = javaRuntimeId;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -222,6 +227,11 @@ public abstract class BlockTranslator {
|
|||
}
|
||||
JAVA_RUNTIME_SPAWNER_ID = spawnerRuntimeId;
|
||||
|
||||
if (waterRuntimeId == -1) {
|
||||
throw new AssertionError("Unable to find Java water in palette");
|
||||
}
|
||||
JAVA_WATER_ID = waterRuntimeId;
|
||||
|
||||
BlockTranslator1_16_100.init();
|
||||
BlockTranslator1_16_210.init();
|
||||
BLOCKS_JSON = null; // We no longer require this so let it garbage collect away
|
||||
|
|
|
@ -133,8 +133,7 @@ public class BlockUtils {
|
|||
hasteLevel = session.getEffectCache().getEffectLevel(Effect.FASTER_DIG);
|
||||
miningFatigueLevel = session.getEffectCache().getEffectLevel(Effect.SLOWER_DIG);
|
||||
|
||||
boolean isInWater = session.getConnector().getConfig().isCacheChunks()
|
||||
&& session.getBlockTranslator().getBedrockBlockId(session.getConnector().getWorldManager().getBlockAt(session, session.getPlayerEntity().getPosition().toInt())) == session.getBlockTranslator().getBedrockWaterId();
|
||||
boolean isInWater = session.getCollisionManager().isPlayerInWater();
|
||||
|
||||
boolean insideOfWaterWithoutAquaAffinity = isInWater &&
|
||||
ItemUtils.getEnchantmentLevel(session.getPlayerInventory().getItem(5).getNbt(), "minecraft:aqua_affinity") < 1;
|
||||
|
|
Loading…
Add table
Reference in a new issue