3
0
Mirror von https://github.com/GeyserMC/Geyser.git synchronisiert 2024-09-08 20:43:04 +02: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).
Dieser Commit ist enthalten in:
Camotoy 2021-04-12 00:35:53 -04:00 committet von GitHub
Ursprung 7dc9c031c2
Commit 120769c7f6
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: 4AEE18F83AFDEB23
11 geänderte Dateien mit 229 neuen und 44 gelöschten Zeilen

Datei anzeigen

@ -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.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.SNEAKING, (xd & 0x02) == 0x02);
metadata.getFlags().setFlag(EntityFlag.SPRINTING, (xd & 0x08) == 0x08); 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); metadata.getFlags().setFlag(EntityFlag.GLIDING, (xd & 0x80) == 0x80);
// Armour stands are handled in their own class // Armour stands are handled in their own class
@ -297,16 +297,37 @@ public class Entity {
case 5: // no gravity case 5: // no gravity
metadata.getFlags().setFlag(EntityFlag.HAS_GRAVITY, !(boolean) entityMetadata.getValue()); metadata.getFlags().setFlag(EntityFlag.HAS_GRAVITY, !(boolean) entityMetadata.getValue());
break; break;
case 6: // Pose change case 6: // Pose change - typically used for bounding box and not animation
if (entityMetadata.getValue().equals(Pose.SLEEPING)) { Pose pose = (Pose) entityMetadata.getValue();
metadata.getFlags().setFlag(EntityFlag.SLEEPING, true);
metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.2f); metadata.getFlags().setFlag(EntityFlag.SLEEPING, pose.equals(Pose.SLEEPING));
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.2f); // Triggered when crawling
} else if (metadata.getFlags().getFlag(EntityFlag.SLEEPING)) { metadata.getFlags().setFlag(EntityFlag.SWIMMING, pose.equals(Pose.SWIMMING));
metadata.getFlags().setFlag(EntityFlag.SLEEPING, false); float width = entityType.getWidth();
metadata.put(EntityData.BOUNDING_BOX_WIDTH, getEntityType().getWidth()); float height = entityType.getHeight();
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, getEntityType().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; break;
} }
} }

Datei anzeigen

@ -26,7 +26,10 @@
package org.geysermc.connector.entity.player; package org.geysermc.connector.entity.player;
import com.github.steveice10.mc.auth.data.GameProfile; 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.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.GeyserSession;
import java.util.UUID; import java.util.UUID;
@ -35,6 +38,10 @@ import java.util.UUID;
* The entity class specifically for a {@link GeyserSession}'s player. * The entity class specifically for a {@link GeyserSession}'s player.
*/ */
public class SessionPlayerEntity extends PlayerEntity { 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; private final GeyserSession session;
@ -43,7 +50,6 @@ public class SessionPlayerEntity extends PlayerEntity {
valid = true; valid = true;
this.session = session; this.session = session;
this.session.getCollisionManager().updatePlayerBoundingBox(position);
} }
@Override @Override
@ -64,4 +70,27 @@ public class SessionPlayerEntity extends PlayerEntity {
} }
super.setPosition(position); 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;
}
}
} }

Datei anzeigen

@ -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.MinecraftConstants;
import com.github.steveice10.mc.protocol.MinecraftProtocol; import com.github.steveice10.mc.protocol.MinecraftProtocol;
import com.github.steveice10.mc.protocol.data.SubProtocol; 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.entity.player.GameMode;
import com.github.steveice10.mc.protocol.data.game.recipe.Recipe; import com.github.steveice10.mc.protocol.data.game.recipe.Recipe;
import com.github.steveice10.mc.protocol.data.game.statistic.Statistic; 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.BedrockServerSession;
import com.nukkitx.protocol.bedrock.data.*; import com.nukkitx.protocol.bedrock.data.*;
import com.nukkitx.protocol.bedrock.data.command.CommandPermission; 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.packet.*;
import com.nukkitx.protocol.bedrock.v431.Bedrock_v431; import com.nukkitx.protocol.bedrock.v431.Bedrock_v431;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; 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.common.AuthType;
import org.geysermc.connector.entity.Entity; import org.geysermc.connector.entity.Entity;
import org.geysermc.connector.entity.Tickable; 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.SessionPlayerEntity;
import org.geysermc.connector.entity.player.SkullPlayerEntity; import org.geysermc.connector.entity.player.SkullPlayerEntity;
import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.inventory.Inventory;
@ -219,6 +224,12 @@ public class GeyserSession implements CommandSender {
private boolean sneaking; 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 @Setter
private boolean sprinting; private boolean sprinting;
@ -228,6 +239,22 @@ public class GeyserSession implements CommandSender {
@Setter @Setter
private boolean jumping; 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. * The dimension of the player.
* As all entities are in the same world, this can be safely applied to all other entities. * 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.collisionManager = new CollisionManager(this);
this.playerEntity = new SessionPlayerEntity(this); this.playerEntity = new SessionPlayerEntity(this);
this.worldCache = new WorldCache(this); collisionManager.updatePlayerBoundingBox(this.playerEntity.getPosition());
this.windowCache = new WindowCache(this);
this.playerInventory = new PlayerInventory(); this.playerInventory = new PlayerInventory();
this.openInventory = null; this.openInventory = null;
@ -829,8 +855,22 @@ public class GeyserSession implements CommandSender {
public void setSneaking(boolean sneaking) { public void setSneaking(boolean sneaking) {
this.sneaking = 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) { if (mouseoverEntity != null) {
// Horses, etc can change their property depending on if you're sneaking // 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. * Will be overwritten for GeyserConnect.
*/ */

Datei anzeigen

@ -27,6 +27,7 @@ package org.geysermc.connector.network.translators.bedrock;
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerAbilitiesPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerAbilitiesPacket;
import com.nukkitx.protocol.bedrock.data.AdventureSetting; import com.nukkitx.protocol.bedrock.data.AdventureSetting;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket; import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket;
import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.PacketTranslator;
@ -37,8 +38,13 @@ public class BedrockAdventureSettingsTranslator extends PacketTranslator<Adventu
@Override @Override
public void translate(AdventureSettingsPacket packet, GeyserSession session) { public void translate(AdventureSettingsPacket packet, GeyserSession session) {
ClientPlayerAbilitiesPacket abilitiesPacket = boolean isFlying = packet.getSettings().contains(AdventureSetting.FLYING);
new ClientPlayerAbilitiesPacket(packet.getSettings().contains(AdventureSetting.FLYING)); ClientPlayerAbilitiesPacket abilitiesPacket = new ClientPlayerAbilitiesPacket(isFlying);
session.sendDownstreamPacket(abilitiesPacket); 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);
}
} }
} }

Datei anzeigen

@ -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.Vector3f;
import com.nukkitx.math.vector.Vector3i; import com.nukkitx.math.vector.Vector3i;
import com.nukkitx.protocol.bedrock.data.LevelEventType; 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.entity.EntityFlags;
import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; import com.nukkitx.protocol.bedrock.data.inventory.ContainerId;
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
@ -150,13 +149,18 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
EntityFlags flags = session.getPlayerEntity().getMetadata().getFlags(); EntityFlags flags = session.getPlayerEntity().getMetadata().getFlags();
// Adjust position for current eye height // Adjust position for current eye height
if (flags.getFlag(EntityFlag.SNEAKING)) { switch (session.getPose()) {
playerPosition = playerPosition.sub(0, (EntityType.PLAYER.getOffset() - 1.27f), 0); case SNEAKING:
} else if (flags.getFlag(EntityFlag.SWIMMING) || flags.getFlag(EntityFlag.GLIDING) || flags.getFlag(EntityFlag.DAMAGE_NEARBY_MOBS)) { playerPosition = playerPosition.sub(0, (EntityType.PLAYER.getOffset() - 1.27f), 0);
// Swimming, gliding, or using the trident spin attack break;
playerPosition = playerPosition.sub(0, (EntityType.PLAYER.getOffset() - 0.4f), 0); case SWIMMING:
} else if (flags.getFlag(EntityFlag.SLEEPING)) { case FALL_FLYING: // Elytra
playerPosition = playerPosition.sub(0, (EntityType.PLAYER.getOffset() - 0.2f), 0); 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 } // else, we don't have to modify the position
float diffX = playerPosition.getX() - packet.getBlockPosition().getX(); float diffX = playerPosition.getX() - packet.getBlockPosition().getX();

Datei anzeigen

@ -59,8 +59,6 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
@Override @Override
public void translate(PlayerActionPacket packet, GeyserSession session) { public void translate(PlayerActionPacket packet, GeyserSession session) {
Entity entity = session.getPlayerEntity(); Entity entity = session.getPlayerEntity();
if (entity == null)
return;
// Send book update before any player action // Send book update before any player action
if (packet.getAction() != PlayerActionType.RESPAWN) { if (packet.getAction() != PlayerActionType.RESPAWN) {
@ -84,10 +82,14 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
case START_SWIMMING: case START_SWIMMING:
ClientPlayerStatePacket startSwimPacket = new ClientPlayerStatePacket((int) entity.getEntityId(), PlayerState.START_SPRINTING); ClientPlayerStatePacket startSwimPacket = new ClientPlayerStatePacket((int) entity.getEntityId(), PlayerState.START_SPRINTING);
session.sendDownstreamPacket(startSwimPacket); session.sendDownstreamPacket(startSwimPacket);
session.setSwimming(true);
break; break;
case STOP_SWIMMING: case STOP_SWIMMING:
ClientPlayerStatePacket stopSwimPacket = new ClientPlayerStatePacket((int) entity.getEntityId(), PlayerState.STOP_SPRINTING); ClientPlayerStatePacket stopSwimPacket = new ClientPlayerStatePacket((int) entity.getEntityId(), PlayerState.STOP_SPRINTING);
session.sendDownstreamPacket(stopSwimPacket); session.sendDownstreamPacket(stopSwimPacket);
session.setSwimming(false);
break; break;
case START_GLIDE: case START_GLIDE:
// Otherwise gliding will not work in creative // Otherwise gliding will not work in creative
@ -114,7 +116,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
} }
session.sendDownstreamPacket(useItemPacket); session.sendDownstreamPacket(useItemPacket);
session.getPlayerEntity().getMetadata().getFlags().setFlag(EntityFlag.BLOCKING, true); session.getPlayerEntity().getMetadata().getFlags().setFlag(EntityFlag.BLOCKING, true);
session.getPlayerEntity().updateBedrockMetadata(session); // metadata will be updated when sneaking
} }
session.setSneaking(true); 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); ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, BlockUtils.POSITION_ZERO, BlockFace.DOWN);
session.sendDownstreamPacket(releaseItemPacket); session.sendDownstreamPacket(releaseItemPacket);
session.getPlayerEntity().getMetadata().getFlags().setFlag(EntityFlag.BLOCKING, false); session.getPlayerEntity().getMetadata().getFlags().setFlag(EntityFlag.BLOCKING, false);
session.getPlayerEntity().updateBedrockMetadata(session); // metadata will be updated when sneaking
} }
session.setSneaking(false); session.setSneaking(false);

Datei anzeigen

@ -28,6 +28,7 @@ package org.geysermc.connector.network.translators.collision;
import com.nukkitx.math.vector.Vector3d; import com.nukkitx.math.vector.Vector3d;
import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.math.vector.Vector3i; 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.EntityFlag;
import com.nukkitx.protocol.bedrock.data.entity.EntityFlags; import com.nukkitx.protocol.bedrock.data.entity.EntityFlags;
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket; 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.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.collision.translators.BlockCollision; 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.ArrayList;
import java.util.List; 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. * 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; 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) { public CollisionManager(GeyserSession session) {
this.session = session; this.session = session;
@ -104,17 +111,14 @@ public class CollisionManager {
} else { } else {
playerPosition = session.getPlayerEntity().getPosition(); 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 { } else {
// According to the Minecraft Wiki, when sneaking: // 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 - 14) blocks high. // - In Bedrock Edition, the height becomes 1.65 blocks, allowing movement through spaces as small as 1.75 (2 - 14) blocks high.
// - In Java Edition, the height becomes 1.5 blocks. // - In Java Edition, the height becomes 1.5 blocks.
// TODO: Have this depend on the player's literal bounding box variable // Other instances have the player's bounding box become as small as 0.6 or 0.2.
if (session.isSneaking()) { playerBoundingBox.setSizeY(session.getPlayerEntity().getMetadata().getFloat(EntityData.BOUNDING_BOX_HEIGHT));
playerBoundingBox.setSizeY(1.5);
} else {
playerBoundingBox.setSizeY(1.8);
}
} }
} }
@ -148,6 +152,11 @@ public class CollisionManager {
position = Vector3d.from(playerBoundingBox.getMiddleX(), position = Vector3d.from(playerBoundingBox.getMiddleX(),
playerBoundingBox.getMiddleY() - (playerBoundingBox.getSizeY() / 2), playerBoundingBox.getMiddleY() - (playerBoundingBox.getSizeY() / 2),
playerBoundingBox.getMiddleZ()); 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 { } else {
// When chunk caching is off, we have to rely on this // When chunk caching is off, we have to rely on this
// It rounds the Y position up to the nearest 0.5 // 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;
} }
/**
* @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 * Updates scaffolding entity flags
* Scaffolding needs to be checked per-move since it's a flag in Bedrock but Java does it client-side * 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(); EntityFlags flags = session.getPlayerEntity().getMetadata().getFlags();
boolean flagsChanged; boolean flagsChanged;
boolean isSneakingWithScaffolding = (touchingScaffolding || onScaffolding) && session.isSneaking(); boolean isSneakingWithScaffolding = (touchingScaffolding || onScaffolding) && session.isSneaking();
@ -269,7 +310,7 @@ public class CollisionManager {
flagsChanged |= flags.getFlag(EntityFlag.IN_SCAFFOLDING) != touchingScaffolding; flagsChanged |= flags.getFlag(EntityFlag.IN_SCAFFOLDING) != touchingScaffolding;
flags.setFlag(EntityFlag.IN_SCAFFOLDING, touchingScaffolding); flags.setFlag(EntityFlag.IN_SCAFFOLDING, touchingScaffolding);
if (flagsChanged) { if (flagsChanged && updateMetadata) {
session.getPlayerEntity().updateBedrockMetadata(session); session.getPlayerEntity().updateBedrockMetadata(session);
} }
} }

Datei anzeigen

@ -25,13 +25,12 @@
package org.geysermc.connector.network.translators.java.entity; 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.entity.Entity;
import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator; import org.geysermc.connector.network.translators.Translator;
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityPositionPacket;
@Translator(packet = ServerEntityPositionPacket.class) @Translator(packet = ServerEntityPositionPacket.class)
public class JavaEntityPositionTranslator extends PacketTranslator<ServerEntityPositionPacket> { public class JavaEntityPositionTranslator extends PacketTranslator<ServerEntityPositionPacket> {

Datei anzeigen

@ -67,7 +67,12 @@ public class JavaEntityPropertiesTranslator extends PacketTranslator<ServerEntit
entity.getAttributes().put(AttributeType.MOVEMENT_SPEED, AttributeType.MOVEMENT_SPEED.getAttribute((float) AttributeUtils.calculateValue(attribute))); entity.getAttributes().put(AttributeType.MOVEMENT_SPEED, AttributeType.MOVEMENT_SPEED.getAttribute((float) AttributeUtils.calculateValue(attribute)));
break; break;
case GENERIC_MOVEMENT_SPEED: 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; break;
case GENERIC_FOLLOW_RANGE: case GENERIC_FOLLOW_RANGE:
entity.getAttributes().put(AttributeType.FOLLOW_RANGE, AttributeType.FOLLOW_RANGE.getAttribute((float) AttributeUtils.calculateValue(attribute))); entity.getAttributes().put(AttributeType.FOLLOW_RANGE, AttributeType.FOLLOW_RANGE.getAttribute((float) AttributeUtils.calculateValue(attribute)));

Datei anzeigen

@ -52,6 +52,7 @@ public abstract class BlockTranslator {
* The Java block runtime ID of air * The Java block runtime ID of air
*/ */
public static final int JAVA_AIR_ID = 0; public static final int JAVA_AIR_ID = 0;
public static final int JAVA_WATER_ID;
/** /**
* The Bedrock block runtime ID of air * The Bedrock block runtime ID of air
*/ */
@ -134,6 +135,7 @@ public abstract class BlockTranslator {
int furnaceLitRuntimeId = -1; int furnaceLitRuntimeId = -1;
int spawnerRuntimeId = -1; int spawnerRuntimeId = -1;
int uniqueJavaId = -1; int uniqueJavaId = -1;
int waterRuntimeId = -1;
Iterator<Map.Entry<String, JsonNode>> blocksIterator = BLOCKS_JSON.fields(); Iterator<Map.Entry<String, JsonNode>> blocksIterator = BLOCKS_JSON.fields();
while (blocksIterator.hasNext()) { while (blocksIterator.hasNext()) {
javaRuntimeId++; javaRuntimeId++;
@ -199,6 +201,9 @@ public abstract class BlockTranslator {
} else if (javaId.startsWith("minecraft:spawner")) { } else if (javaId.startsWith("minecraft:spawner")) {
spawnerRuntimeId = javaRuntimeId; 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; 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_100.init();
BlockTranslator1_16_210.init(); BlockTranslator1_16_210.init();
BLOCKS_JSON = null; // We no longer require this so let it garbage collect away BLOCKS_JSON = null; // We no longer require this so let it garbage collect away

Datei anzeigen

@ -133,8 +133,7 @@ public class BlockUtils {
hasteLevel = session.getEffectCache().getEffectLevel(Effect.FASTER_DIG); hasteLevel = session.getEffectCache().getEffectLevel(Effect.FASTER_DIG);
miningFatigueLevel = session.getEffectCache().getEffectLevel(Effect.SLOWER_DIG); miningFatigueLevel = session.getEffectCache().getEffectLevel(Effect.SLOWER_DIG);
boolean isInWater = session.getConnector().getConfig().isCacheChunks() boolean isInWater = session.getCollisionManager().isPlayerInWater();
&& session.getBlockTranslator().getBedrockBlockId(session.getConnector().getWorldManager().getBlockAt(session, session.getPlayerEntity().getPosition().toInt())) == session.getBlockTranslator().getBedrockWaterId();
boolean insideOfWaterWithoutAquaAffinity = isInWater && boolean insideOfWaterWithoutAquaAffinity = isInWater &&
ItemUtils.getEnchantmentLevel(session.getPlayerInventory().getItem(5).getNbt(), "minecraft:aqua_affinity") < 1; ItemUtils.getEnchantmentLevel(session.getPlayerInventory().getItem(5).getNbt(), "minecraft:aqua_affinity") < 1;