Piston support

This commit is contained in:
AJ Ferguson 2024-06-14 21:19:37 -04:00
parent e1aebca67c
commit 1a6c70feed
4 changed files with 139 additions and 57 deletions

View file

@ -35,7 +35,6 @@ import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.MoveEntityDeltaPacket; import org.cloudburstmc.protocol.bedrock.packet.MoveEntityDeltaPacket;
import org.geysermc.erosion.util.BlockPositionIterator; import org.geysermc.erosion.util.BlockPositionIterator;
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
import org.geysermc.geyser.entity.type.LivingEntity; import org.geysermc.geyser.entity.type.LivingEntity;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.level.block.Blocks;
@ -81,8 +80,8 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
this.moveSpeed = (float) AttributeType.Builtin.GENERIC_MOVEMENT_SPEED.getDef(); this.moveSpeed = (float) AttributeType.Builtin.GENERIC_MOVEMENT_SPEED.getDef();
this.gravity = AttributeType.Builtin.GENERIC_GRAVITY.getDef(); this.gravity = AttributeType.Builtin.GENERIC_GRAVITY.getDef();
double width = Double.parseDouble(Float.toString(vehicle.getBoundingBoxWidth())); double width = vehicle.getBoundingBoxWidth();
double height = Double.parseDouble(Float.toString(vehicle.getBoundingBoxHeight())); double height = vehicle.getBoundingBoxHeight();
this.boundingBox = new BoundingBox( this.boundingBox = new BoundingBox(
vehicle.getPosition().getX(), vehicle.getPosition().getX(),
vehicle.getPosition().getY() + height / 2, vehicle.getPosition().getY() + height / 2,
@ -92,15 +91,13 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
} }
public void setWidth(float width) { public void setWidth(float width) {
double doubleWidth = Double.parseDouble(Float.toString(width)); boundingBox.setSizeX(width);
boundingBox.setSizeX(doubleWidth); boundingBox.setSizeZ(width);
boundingBox.setSizeZ(doubleWidth);
} }
public void setHeight(float height) { public void setHeight(float height) {
double doubleHeight = Double.parseDouble(Float.toString(height)); boundingBox.translate(0, (height - boundingBox.getSizeY()) / 2, 0);
boundingBox.translate(0, (doubleHeight - boundingBox.getSizeY()) / 2, 0); boundingBox.setSizeY(height);
boundingBox.setSizeY(doubleHeight);
} }
public void moveAbsolute(double x, double y, double z) { public void moveAbsolute(double x, double y, double z) {
@ -113,6 +110,14 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
boundingBox.translate(x, y, z); boundingBox.translate(x, y, z);
} }
public void moveRelative(Vector3d vec) {
boundingBox.translate(vec);
}
public BoundingBox getBoundingBox() {
return this.boundingBox;
}
public void setEffect(Effect effect, int effectAmplifier) { public void setEffect(Effect effect, int effectAmplifier) {
switch (effect) { switch (effect) {
case LEVITATION -> effectLevitation = effectAmplifier + 1; case LEVITATION -> effectLevitation = effectAmplifier + 1;
@ -129,6 +134,12 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
} }
} }
public Vector3d correctMovement(Vector3d movement) {
return vehicle.getSession().getCollisionManager().correctMovement(
movement, boundingBox, vehicle.isOnGround(), this.stepHeight, true, vehicle.canWalkOnLava()
);
}
public void setMoveSpeed(float moveSpeed) { public void setMoveSpeed(float moveSpeed) {
this.moveSpeed = moveSpeed; this.moveSpeed = moveSpeed;
} }
@ -382,7 +393,7 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
protected void landMovement(VehicleContext ctx) { protected void landMovement(VehicleContext ctx) {
double gravity = getGravity(); double gravity = getGravity();
float slipperiness = BlockStateValues.getSlipperiness(ctx.velocityAffectingBlock()); float slipperiness = BlockStateValues.getSlipperiness(getVelocityBlock(ctx));
float drag = vehicle.isOnGround() ? 0.91f * slipperiness : 0.91f; float drag = vehicle.isOnGround() ? 0.91f * slipperiness : 0.91f;
float speed = vehicle.getVehicleSpeed() * (vehicle.isOnGround() ? BASE_SLIPPERINESS_CUBED / (slipperiness * slipperiness * slipperiness) : 0.1f); float speed = vehicle.getVehicleSpeed() * (vehicle.isOnGround() ? BASE_SLIPPERINESS_CUBED / (slipperiness * slipperiness * slipperiness) : 0.1f);
@ -556,13 +567,12 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
// Non-zero values indicate a collision on that axis // Non-zero values indicate a collision on that axis
Vector3d moveDiff = motion.toDouble().sub(correctedMovement); Vector3d moveDiff = motion.toDouble().sub(correctedMovement);
boolean onGround = moveDiff.getY() != 0 && motion.getY() < 0; vehicle.setOnGround(moveDiff.getY() != 0 && motion.getY() < 0);
boolean horizontalCollision = moveDiff.getX() != 0 || moveDiff.getZ() != 0; boolean horizontalCollision = moveDiff.getX() != 0 || moveDiff.getZ() != 0;
boolean bounced = false; boolean bounced = false;
if (onGround) { if (vehicle.isOnGround()) {
Vector3i landingPos = ctx.centerPos().sub(0, 0.2f, 0).toInt(); Block landingBlock = getLandingBlock(ctx).block();
Block landingBlock = ctx.getBlock(landingPos).block();
if (landingBlock == Blocks.SLIME_BLOCK) { if (landingBlock == Blocks.SLIME_BLOCK) {
motion = Vector3f.from(motion.getX(), -motion.getY(), motion.getZ()); motion = Vector3f.from(motion.getX(), -motion.getY(), motion.getZ());
@ -592,7 +602,7 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
} }
// Send the new position to the bedrock client and java server // Send the new position to the bedrock client and java server
moveVehicle(ctx.centerPos(), onGround); moveVehicle(ctx.centerPos());
vehicle.setMotion(motion); vehicle.setMotion(motion);
applyBlockCollisionEffects(ctx); applyBlockCollisionEffects(ctx);
@ -651,17 +661,16 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
return Vector2f.from(player.getYaw(), player.getPitch() * 0.5f); return Vector2f.from(player.getYaw(), player.getPitch() * 0.5f);
} }
protected void moveVehicle(Vector3d javaPos, boolean isOnGround) { protected void moveVehicle(Vector3d javaPos) {
Vector3f bedrockPos = javaPos.toFloat(); Vector3f bedrockPos = javaPos.toFloat();
Vector2f rotation = getVehicleRotation(); Vector2f rotation = getVehicleRotation();
MoveEntityDeltaPacket moveEntityDeltaPacket = new MoveEntityDeltaPacket(); MoveEntityDeltaPacket moveEntityDeltaPacket = new MoveEntityDeltaPacket();
moveEntityDeltaPacket.setRuntimeEntityId(vehicle.getGeyserId()); moveEntityDeltaPacket.setRuntimeEntityId(vehicle.getGeyserId());
if (isOnGround) { if (vehicle.isOnGround()) {
moveEntityDeltaPacket.getFlags().add(MoveEntityDeltaPacket.Flag.ON_GROUND); moveEntityDeltaPacket.getFlags().add(MoveEntityDeltaPacket.Flag.ON_GROUND);
} }
vehicle.setOnGround(isOnGround);
if (vehicle.getPosition().getX() != bedrockPos.getX()) { if (vehicle.getPosition().getX() != bedrockPos.getX()) {
moveEntityDeltaPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_X); moveEntityDeltaPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_X);
@ -714,7 +723,16 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
return this.gravity; return this.gravity;
} }
protected @Nullable Vector3i getSupportingBlockPos(VehicleContext ctx) { /**
* Finds the position of the main block supporting the vehicle.
* Used when determining slipperiness, speed, etc.
* <p>
* Should use {@link VehicleContext#supportingBlockPos()}, instead of calling this directly.
*
* @param ctx context
* @return position of the main block supporting this entity
*/
private @Nullable Vector3i getSupportingBlockPos(VehicleContext ctx) {
Vector3i result = null; Vector3i result = null;
if (vehicle.isOnGround()) { if (vehicle.isOnGround()) {
@ -752,13 +770,25 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
return result; return result;
} }
protected Vector3i getVelocityAffectingPos(VehicleContext ctx) { protected BlockState getBlockUnder(VehicleContext ctx, float dist) {
Vector3i blockPos = getSupportingBlockPos(ctx); Vector3i supportingBlockPos = ctx.supportingBlockPos();
if (blockPos != null) {
return Vector3i.from(blockPos.getX(), Math.floor(ctx.centerPos().getY() - 0.500001f), blockPos.getZ()); Vector3i blockPos;
if (supportingBlockPos != null) {
blockPos = Vector3i.from(supportingBlockPos.getX(), Math.floor(ctx.centerPos().getY() - dist), supportingBlockPos.getZ());
} else { } else {
return ctx.centerPos().sub(0, 0.500001f, 0).toInt(); blockPos = ctx.centerPos().sub(0, dist, 0).toInt();
} }
return ctx.getBlock(blockPos);
}
protected BlockState getLandingBlock(VehicleContext ctx) {
return getBlockUnder(ctx, 0.2f);
}
protected BlockState getVelocityBlock(VehicleContext ctx) {
return getBlockUnder(ctx, 0.500001f);
} }
protected float getVelocityMultiplier(VehicleContext ctx) { protected float getVelocityMultiplier(VehicleContext ctx) {
@ -771,7 +801,7 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
return 0.4f; return 0.4f;
} }
block = ctx.velocityAffectingBlock().block(); block = getVelocityBlock(ctx).block();
if (block == Blocks.SOUL_SAND || block == Blocks.HONEY_BLOCK) { if (block == Blocks.SOUL_SAND || block == Blocks.HONEY_BLOCK) {
return 0.4f; return 0.4f;
} }
@ -785,7 +815,7 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
return 0.5f; return 0.5f;
} }
block = ctx.velocityAffectingBlock().block(); block = getVelocityBlock(ctx).block();
if (block == Blocks.HONEY_BLOCK) { if (block == Blocks.HONEY_BLOCK) {
return 0.5f; return 0.5f;
} }
@ -796,7 +826,7 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
protected class VehicleContext { protected class VehicleContext {
private Vector3d centerPos; private Vector3d centerPos;
private BlockState centerBlock; private BlockState centerBlock;
private BlockState velocityAffectingBlock; private Vector3i supportingBlockPos;
private BlockPositionIterator blockIter; private BlockPositionIterator blockIter;
private int[] blocks; private int[] blocks;
@ -811,7 +841,7 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
this.centerPos = boundingBox.getBottomCenter(); this.centerPos = boundingBox.getBottomCenter();
this.centerBlock = getBlock(this.centerPos.toInt()); this.centerBlock = getBlock(this.centerPos.toInt());
this.velocityAffectingBlock = null; this.supportingBlockPos = null;
} }
protected Vector3d centerPos() { protected Vector3d centerPos() {
@ -822,12 +852,12 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
return this.centerBlock; return this.centerBlock;
} }
protected BlockState velocityAffectingBlock() { protected Vector3i supportingBlockPos() {
if (this.velocityAffectingBlock == null) { if (this.supportingBlockPos == null) {
this.velocityAffectingBlock = getBlock(getVelocityAffectingPos(this)); this.supportingBlockPos = getSupportingBlockPos(this);
} }
return this.velocityAffectingBlock; return this.supportingBlockPos;
} }
protected int getBlockId(int x, int y, int z) { protected int getBlockId(int x, int y, int z) {

View file

@ -177,7 +177,8 @@ public class CollisionManager {
// Send corrected position to Bedrock if they differ by too much to prevent de-syncs // Send corrected position to Bedrock if they differ by too much to prevent de-syncs
if (onGround != newOnGround || movement.distanceSquared(adjustedMovement) > INCORRECT_MOVEMENT_THRESHOLD) { if (onGround != newOnGround || movement.distanceSquared(adjustedMovement) > INCORRECT_MOVEMENT_THRESHOLD) {
PlayerEntity playerEntity = session.getPlayerEntity(); PlayerEntity playerEntity = session.getPlayerEntity();
if (pistonCache.getPlayerMotion().equals(Vector3f.ZERO) && !pistonCache.isPlayerSlimeCollision()) { // Client will dismount if on a vehicle
if (playerEntity.getVehicle() == null && pistonCache.getPlayerMotion().equals(Vector3f.ZERO) && !pistonCache.isPlayerSlimeCollision()) {
playerEntity.moveAbsolute(position.toFloat(), playerEntity.getYaw(), playerEntity.getPitch(), playerEntity.getHeadYaw(), newOnGround, true); playerEntity.moveAbsolute(position.toFloat(), playerEntity.getYaw(), playerEntity.getPitch(), playerEntity.getHeadYaw(), newOnGround, true);
} }
} }

View file

@ -33,7 +33,9 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
import org.geysermc.geyser.entity.vehicle.ClientVehicle;
import org.geysermc.geyser.level.physics.Axis; import org.geysermc.geyser.level.physics.Axis;
import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.level.physics.BoundingBox;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
@ -119,6 +121,12 @@ public class PistonCache {
private void sendPlayerMovement() { private void sendPlayerMovement() {
if (!playerDisplacement.equals(Vector3d.ZERO) && playerMotion.equals(Vector3f.ZERO)) { if (!playerDisplacement.equals(Vector3d.ZERO) && playerMotion.equals(Vector3f.ZERO)) {
SessionPlayerEntity playerEntity = session.getPlayerEntity(); SessionPlayerEntity playerEntity = session.getPlayerEntity();
Entity vehicle = playerEntity.getVehicle();
if (vehicle instanceof ClientVehicle clientVehicle && clientVehicle.isClientControlled()) {
return;
}
boolean isOnGround = playerDisplacement.getY() > 0 || playerEntity.isOnGround(); boolean isOnGround = playerDisplacement.getY() > 0 || playerEntity.isOnGround();
Vector3d position = session.getCollisionManager().getPlayerBoundingBox().getBottomCenter(); Vector3d position = session.getCollisionManager().getPlayerBoundingBox().getBottomCenter();
playerEntity.moveAbsolute(position.toFloat(), playerEntity.getYaw(), playerEntity.getPitch(), playerEntity.getHeadYaw(), isOnGround, true); playerEntity.moveAbsolute(position.toFloat(), playerEntity.getYaw(), playerEntity.getPitch(), playerEntity.getHeadYaw(), isOnGround, true);
@ -128,6 +136,13 @@ public class PistonCache {
private void sendPlayerMotion() { private void sendPlayerMotion() {
if (!playerMotion.equals(Vector3f.ZERO)) { if (!playerMotion.equals(Vector3f.ZERO)) {
SessionPlayerEntity playerEntity = session.getPlayerEntity(); SessionPlayerEntity playerEntity = session.getPlayerEntity();
Entity vehicle = playerEntity.getVehicle();
if (vehicle instanceof ClientVehicle clientVehicle && clientVehicle.isClientControlled()) {
vehicle.setMotion(playerMotion);
return;
}
playerEntity.setMotion(playerMotion); playerEntity.setMotion(playerMotion);
SetEntityMotionPacket setEntityMotionPacket = new SetEntityMotionPacket(); SetEntityMotionPacket setEntityMotionPacket = new SetEntityMotionPacket();
@ -149,10 +164,15 @@ public class PistonCache {
totalDisplacement = totalDisplacement.max(-0.51d, -0.51d, -0.51d).min(0.51d, 0.51d, 0.51d); totalDisplacement = totalDisplacement.max(-0.51d, -0.51d, -0.51d).min(0.51d, 0.51d, 0.51d);
Vector3d delta = totalDisplacement.sub(playerDisplacement); Vector3d delta = totalDisplacement.sub(playerDisplacement);
// Check if the piston is pushing a player into collision
delta = session.getCollisionManager().correctPlayerMovement(delta, true, false);
session.getCollisionManager().getPlayerBoundingBox().translate(delta.getX(), delta.getY(), delta.getZ()); // Check if the piston is pushing a player into collision
if (session.getPlayerEntity().getVehicle() instanceof ClientVehicle clientVehicle && clientVehicle.isClientControlled()) {
delta = clientVehicle.getVehicleComponent().correctMovement(delta);
clientVehicle.getVehicleComponent().moveRelative(delta);
} else {
delta = session.getCollisionManager().correctPlayerMovement(delta, true, false);
session.getCollisionManager().getPlayerBoundingBox().translate(delta.getX(), delta.getY(), delta.getZ());
}
playerDisplacement = totalDisplacement; playerDisplacement = totalDisplacement;
} }

View file

@ -38,6 +38,7 @@ import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.api.util.PlatformType;
import org.geysermc.geyser.entity.vehicle.ClientVehicle;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.property.Properties;
@ -348,18 +349,31 @@ public class PistonBlockEntity {
blockMovement = 1f - lastProgress; blockMovement = 1f - lastProgress;
} }
BoundingBox playerBoundingBox = session.getCollisionManager().getPlayerBoundingBox(); boolean onGround;
BoundingBox playerBoundingBox;
if (session.getPlayerEntity().getVehicle() instanceof ClientVehicle clientVehicle && clientVehicle.isClientControlled()) {
onGround = session.getPlayerEntity().getVehicle().isOnGround();
playerBoundingBox = clientVehicle.getVehicleComponent().getBoundingBox();
} else {
onGround = session.getPlayerEntity().isOnGround();
playerBoundingBox = session.getCollisionManager().getPlayerBoundingBox();
}
// Shrink the collision in the other axes slightly, to avoid false positives when pressed up against the side of blocks // Shrink the collision in the other axes slightly, to avoid false positives when pressed up against the side of blocks
Vector3d shrink = Vector3i.ONE.sub(direction.abs()).toDouble().mul(CollisionManager.COLLISION_TOLERANCE * 2); Vector3d shrink = Vector3i.ONE.sub(direction.abs()).toDouble().mul(CollisionManager.COLLISION_TOLERANCE * 2);
playerBoundingBox.setSizeX(playerBoundingBox.getSizeX() - shrink.getX()); double sizeX = playerBoundingBox.getSizeX();
playerBoundingBox.setSizeY(playerBoundingBox.getSizeY() - shrink.getY()); double sizeY = playerBoundingBox.getSizeY();
playerBoundingBox.setSizeZ(playerBoundingBox.getSizeZ() - shrink.getZ()); double sizeZ = playerBoundingBox.getSizeZ();
playerBoundingBox.setSizeX(sizeX - shrink.getX());
playerBoundingBox.setSizeY(sizeY - shrink.getY());
playerBoundingBox.setSizeZ(sizeZ - shrink.getZ());
// Resolve collision with the piston head // Resolve collision with the piston head
BlockState pistonHeadId = Blocks.PISTON_HEAD.defaultBlockState() BlockState pistonHeadId = Blocks.PISTON_HEAD.defaultBlockState()
.withValue(Properties.SHORT, false) .withValue(Properties.SHORT, false)
.withValue(Properties.FACING, orientation); .withValue(Properties.FACING, orientation);
pushPlayerBlock(pistonHeadId, getPistonHeadPos().toDouble(), blockMovement, playerBoundingBox); pushPlayerBlock(pistonHeadId, getPistonHeadPos().toDouble(), blockMovement, playerBoundingBox, onGround);
// Resolve collision with any attached moving blocks, but skip slime blocks // Resolve collision with any attached moving blocks, but skip slime blocks
// This prevents players from being launched by slime blocks covered by other blocks // This prevents players from being launched by slime blocks covered by other blocks
@ -367,7 +381,7 @@ public class PistonBlockEntity {
BlockState state = entry.getValue(); BlockState state = entry.getValue();
if (!state.is(Blocks.SLIME_BLOCK)) { if (!state.is(Blocks.SLIME_BLOCK)) {
Vector3d blockPos = entry.getKey().toDouble(); Vector3d blockPos = entry.getKey().toDouble();
pushPlayerBlock(state, blockPos, blockMovement, playerBoundingBox); pushPlayerBlock(state, blockPos, blockMovement, playerBoundingBox, onGround);
} }
} }
// Resolve collision with slime blocks // Resolve collision with slime blocks
@ -375,14 +389,14 @@ public class PistonBlockEntity {
BlockState state = entry.getValue(); BlockState state = entry.getValue();
if (state.is(Blocks.SLIME_BLOCK)) { if (state.is(Blocks.SLIME_BLOCK)) {
Vector3d blockPos = entry.getKey().toDouble(); Vector3d blockPos = entry.getKey().toDouble();
pushPlayerBlock(state, blockPos, blockMovement, playerBoundingBox); pushPlayerBlock(state, blockPos, blockMovement, playerBoundingBox, onGround);
} }
} }
// Undo shrink // Undo shrink
playerBoundingBox.setSizeX(playerBoundingBox.getSizeX() + shrink.getX()); playerBoundingBox.setSizeX(sizeX);
playerBoundingBox.setSizeY(playerBoundingBox.getSizeY() + shrink.getY()); playerBoundingBox.setSizeY(sizeY);
playerBoundingBox.setSizeZ(playerBoundingBox.getSizeZ() + shrink.getZ()); playerBoundingBox.setSizeZ(sizeZ);
} }
/** /**
@ -392,20 +406,22 @@ public class PistonBlockEntity {
* @param playerBoundingBox The player's bounding box * @param playerBoundingBox The player's bounding box
* @return True if the player attached, otherwise false * @return True if the player attached, otherwise false
*/ */
private boolean isPlayerAttached(Vector3d blockPos, BoundingBox playerBoundingBox) { private boolean isPlayerAttached(Vector3d blockPos, BoundingBox playerBoundingBox, boolean onGround) {
if (orientation.isVertical()) { if (orientation.isVertical()) {
return false; return false;
} }
return session.getPlayerEntity().isOnGround() && HONEY_BOUNDING_BOX.checkIntersection(blockPos, playerBoundingBox); return onGround && HONEY_BOUNDING_BOX.checkIntersection(blockPos, playerBoundingBox);
} }
/** /**
* Launches a player if the player is on the pushing side of the slime block * Launches a player if the player is on the pushing side of the slime block
* *
* @param blockPos The position of the slime block * @param blockPos The position of the slime block
* @param playerPos The player's position * @param playerBoundingBox The player's bounding box
*/ */
private void applySlimeBlockMotion(Vector3d blockPos, Vector3d playerPos) { private void applySlimeBlockMotion(Vector3d blockPos, BoundingBox playerBoundingBox) {
Vector3d playerPos = Vector3d.from(playerBoundingBox.getMiddleX(), playerBoundingBox.getMiddleY(), playerBoundingBox.getMiddleZ());
Direction movementDirection = orientation; Direction movementDirection = orientation;
// Invert direction when pulling // Invert direction when pulling
if (action == PistonValueType.PULLING) { if (action == PistonValueType.PULLING) {
@ -471,7 +487,7 @@ public class PistonBlockEntity {
return maxIntersection; return maxIntersection;
} }
private void pushPlayerBlock(BlockState state, Vector3d startingPos, double blockMovement, BoundingBox playerBoundingBox) { private void pushPlayerBlock(BlockState state, Vector3d startingPos, double blockMovement, BoundingBox playerBoundingBox, boolean onGround) {
PistonCache pistonCache = session.getPistonCache(); PistonCache pistonCache = session.getPistonCache();
Vector3d movement = getMovement().toDouble(); Vector3d movement = getMovement().toDouble();
// Check if the player collides with the movingBlock block entity // Check if the player collides with the movingBlock block entity
@ -481,12 +497,12 @@ public class PistonBlockEntity {
if (state.is(Blocks.SLIME_BLOCK)) { if (state.is(Blocks.SLIME_BLOCK)) {
pistonCache.setPlayerSlimeCollision(true); pistonCache.setPlayerSlimeCollision(true);
applySlimeBlockMotion(finalBlockPos, Vector3d.from(playerBoundingBox.getMiddleX(), playerBoundingBox.getMiddleY(), playerBoundingBox.getMiddleZ())); applySlimeBlockMotion(finalBlockPos, playerBoundingBox);
} }
} }
Vector3d blockPos = startingPos.add(movement.mul(blockMovement)); Vector3d blockPos = startingPos.add(movement.mul(blockMovement));
if (state.is(Blocks.HONEY_BLOCK) && isPlayerAttached(blockPos, playerBoundingBox)) { if (state.is(Blocks.HONEY_BLOCK) && isPlayerAttached(blockPos, playerBoundingBox, onGround)) {
pistonCache.setPlayerCollided(true); pistonCache.setPlayerCollided(true);
pistonCache.setPlayerAttachedToHoney(true); pistonCache.setPlayerAttachedToHoney(true);
@ -509,7 +525,7 @@ public class PistonBlockEntity {
if (state.is(Blocks.SLIME_BLOCK)) { if (state.is(Blocks.SLIME_BLOCK)) {
pistonCache.setPlayerSlimeCollision(true); pistonCache.setPlayerSlimeCollision(true);
applySlimeBlockMotion(blockPos, Vector3d.from(playerBoundingBox.getMiddleX(), playerBoundingBox.getMiddleY(), playerBoundingBox.getMiddleZ())); applySlimeBlockMotion(blockPos, playerBoundingBox);
} }
} }
} }
@ -585,7 +601,14 @@ public class PistonBlockEntity {
movingBlockMap.put(getPistonHeadPos(), this); movingBlockMap.put(getPistonHeadPos(), this);
Vector3i movement = getMovement(); Vector3i movement = getMovement();
BoundingBox playerBoundingBox = session.getCollisionManager().getPlayerBoundingBox().clone();
BoundingBox playerBoundingBox;
if (session.getPlayerEntity().getVehicle() instanceof ClientVehicle clientVehicle && clientVehicle.isClientControlled()) {
playerBoundingBox = clientVehicle.getVehicleComponent().getBoundingBox().clone();
} else {
playerBoundingBox = session.getCollisionManager().getPlayerBoundingBox().clone();
}
if (orientation == Direction.UP) { if (orientation == Direction.UP) {
// Extend the bounding box down, to catch collisions when the player is falling down // Extend the bounding box down, to catch collisions when the player is falling down
playerBoundingBox.extend(0, -256, 0); playerBoundingBox.extend(0, -256, 0);
@ -629,17 +652,25 @@ public class PistonBlockEntity {
return; return;
} }
placedFinalBlocks = true; placedFinalBlocks = true;
BoundingBox playerBoundingBox;
if (session.getPlayerEntity().getVehicle() instanceof ClientVehicle clientVehicle && clientVehicle.isClientControlled()) {
playerBoundingBox = clientVehicle.getVehicleComponent().getBoundingBox().clone();
} else {
playerBoundingBox = session.getCollisionManager().getPlayerBoundingBox().clone();
}
Vector3i movement = getMovement(); Vector3i movement = getMovement();
attachedBlocks.forEach((blockPos, state) -> { attachedBlocks.forEach((blockPos, state) -> {
blockPos = blockPos.add(movement); blockPos = blockPos.add(movement);
// Don't place blocks that collide with the player // Don't place blocks that collide with the player
if (!SOLID_BOUNDING_BOX.checkIntersection(blockPos.toDouble(), session.getCollisionManager().getPlayerBoundingBox())) { if (!SOLID_BOUNDING_BOX.checkIntersection(blockPos.toDouble(), playerBoundingBox)) {
ChunkUtils.updateBlock(session, state, blockPos); ChunkUtils.updateBlock(session, state, blockPos);
} }
}); });
if (action == PistonValueType.PUSHING) { if (action == PistonValueType.PUSHING) {
Vector3i pistonHeadPos = getPistonHeadPos().add(movement); Vector3i pistonHeadPos = getPistonHeadPos().add(movement);
if (!SOLID_BOUNDING_BOX.checkIntersection(pistonHeadPos.toDouble(), session.getCollisionManager().getPlayerBoundingBox())) { if (!SOLID_BOUNDING_BOX.checkIntersection(pistonHeadPos.toDouble(), playerBoundingBox)) {
ChunkUtils.updateBlock(session, Blocks.PISTON_HEAD.defaultBlockState() ChunkUtils.updateBlock(session, Blocks.PISTON_HEAD.defaultBlockState()
.withValue(Properties.SHORT, false) .withValue(Properties.SHORT, false)
.withValue(Properties.FACING, orientation), pistonHeadPos); .withValue(Properties.FACING, orientation), pistonHeadPos);