Add comments

This commit is contained in:
AJ Ferguson 2024-07-17 00:40:11 -04:00
parent dae371fbbf
commit 64415144c2
3 changed files with 110 additions and 41 deletions

View file

@ -51,6 +51,8 @@ public class CamelVehicleComponent extends VehicleComponent<CamelEntity> {
}
public void startDashCooldown() {
// tickVehicle is only called while the vehicle is mounted. Use session ticks to keep
// track of time instead of counting down
this.dashTick = vehicle.getSession().getTicks() + DASH_TICKS;
}
@ -72,6 +74,7 @@ public class CamelVehicleComponent extends VehicleComponent<CamelEntity> {
@Override
public void onDismount() {
// Prevent camel from getting stuck in dash animation
vehicle.setFlag(EntityFlag.HAS_DASH_COOLDOWN, false);
vehicle.updateBedrockMetadata();
super.onDismount();

View file

@ -62,7 +62,6 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
private static final float MAX_LOGICAL_FLUID_HEIGHT = 8.0f / BlockStateValues.NUM_FLUID_LEVELS;
private static final float BASE_SLIPPERINESS_CUBED = 0.6f * 0.6f * 0.6f;
private static final float MIN_VELOCITY = 0.003f;
private static final float CLIMB_SPEED = 0.15f;
protected final T vehicle;
protected final BoundingBox boundingBox;
@ -134,12 +133,6 @@ 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) {
this.moveSpeed = moveSpeed;
}
@ -156,6 +149,12 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
this.gravity = MathUtils.constrain(gravity, -1.0, 1.0);
}
public Vector3d correctMovement(Vector3d movement) {
return vehicle.getSession().getCollisionManager().correctMovement(
movement, boundingBox, vehicle.isOnGround(), this.stepHeight, true, vehicle.canWalkOnLava()
);
}
public void onMount() {
vehicle.getSession().getPlayerEntity().setVehicleInput(Vector2f.ZERO);
vehicle.getSession().getPlayerEntity().setVehicleJumpStrength(0);
@ -165,6 +164,9 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
//
}
/**
* Called every session tick while the player is mounted on the vehicle.
*/
public void tickVehicle() {
if (!vehicle.isClientControlled()) {
return;
@ -187,6 +189,12 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
}
}
/**
* Adds velocity of all colliding fluids to the vehicle, and returns the height of the fluid to use for movement.
*
* @param ctx context
* @return type and height of fluid to use for movement
*/
protected ObjectDoublePair<Fluid> updateFluidMovement(VehicleContext ctx) {
BoundingBox box = boundingBox.clone();
box.expand(-0.001);
@ -199,10 +207,10 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
double waterHeight = getFluidHeightAndApplyMovement(ctx, iter, Fluid.WATER, 0.014, min.getY());
double lavaHeight = getFluidHeightAndApplyMovement(ctx, iter, Fluid.LAVA, vehicle.getSession().getDimensionType().ultrawarm() ? 0.007 : 0.007 / 3, min.getY());
// Apply upward motion if the vehicle is a Strider, and it is submerged in lava
if (lavaHeight > 0 && vehicle.getDefinition().entityType() == EntityType.STRIDER) {
Vector3i blockPos = ctx.centerPos().toInt();
if (!CollisionManager.FLUID_COLLISION.isBelow(blockPos.getY(), boundingBox)
|| ctx.getBlock(blockPos.up()).is(Blocks.LAVA)) {
if (!CollisionManager.FLUID_COLLISION.isBelow(blockPos.getY(), boundingBox) || ctx.getBlock(blockPos.up()).is(Blocks.LAVA)) {
vehicle.setMotion(vehicle.getMotion().mul(0.5f).add(0, 0.05f, 0));
} else {
vehicle.setOnGround(true);
@ -221,6 +229,16 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
return EMPTY_FLUID_PAIR;
}
/**
* Calculates how deep the vehicle is in a fluid, and applies its velocity.
*
* @param ctx context
* @param iter iterator of colliding blocks
* @param fluid type of fluid
* @param speed multiplier for fluid motion
* @param minY minY of the bounding box used to check for fluid collision; not exactly the same as the vehicle's bounding box
* @return height of fluid compared to minY
*/
protected double getFluidHeightAndApplyMovement(VehicleContext ctx, BlockPositionIterator iter, Fluid fluid, double speed, double minY) {
Vector3d totalVelocity = Vector3d.ZERO;
double maxFluidHeight = 0;
@ -237,10 +255,14 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
double vehicleFluidHeight = blockPos.getY() + worldFluidHeight - minY;
if (vehicleFluidHeight < 0) {
// Vehicle is not submerged in this fluid block
continue;
}
boolean flowBlocked = worldFluidHeight != 1; // This is only used for determining if a falling fluid should drag the vehicle downwards
// flowBlocked is only used when determining if a falling fluid should drag the vehicle downwards.
// If this block is not a falling fluid, set to true to avoid unnecessary checks.
boolean flowBlocked = worldFluidHeight != 1;
Vector3d velocity = Vector3d.ZERO;
for (Direction direction : Direction.HORIZONTAL) {
Vector3i adjacentBlockPos = blockPos.add(direction.getUnitVector());
@ -260,6 +282,7 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
fluidHeightDiff = getLogicalFluidHeight(fluid, blockId) - (adjacentFluidHeight - MAX_LOGICAL_FLUID_HEIGHT);
}
} else if (!flowBlocked) {
// No need to check if flow is already blocked from another direction, or if this isn't a falling fluid.
flowBlocked = isFlowBlocked(fluid, adjacentBlockId);
}
}
@ -398,7 +421,14 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
boolean horizontalCollision = travel(ctx, speed);
if (isClimbing(ctx)) {
vehicle.setMotion(getClimbingSpeed(horizontalCollision));
Vector3f motion = vehicle.getMotion();
vehicle.setMotion(
Vector3f.from(
MathUtils.clamp(motion.getX(), -0.15f, 0.15f),
horizontalCollision ? 0.2f : Math.max(motion.getY(), -0.15f),
MathUtils.clamp(motion.getZ(), -0.15f, 0.15f)
)
);
// NOT IMPLEMENTED: climbing in powdered snow
}
@ -435,15 +465,6 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
return true;
}
protected Vector3f getClimbingSpeed(boolean horizontalCollision) {
Vector3f motion = vehicle.getMotion();
return Vector3f.from(
MathUtils.clamp(motion.getX(), -CLIMB_SPEED, CLIMB_SPEED),
horizontalCollision ? 0.2f : Math.max(motion.getY(), -CLIMB_SPEED),
MathUtils.clamp(motion.getZ(), -CLIMB_SPEED, CLIMB_SPEED)
);
}
protected Vector3f getFluidGravity(double gravity, boolean falling) {
Vector3f motion = vehicle.getMotion();
if (gravity != 0 && !vehicle.getFlag(EntityFlag.SPRINTING)) {
@ -456,6 +477,14 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
return motion;
}
/**
* Check if any blocks the vehicle is colliding with should multiply movement. (Cobweb, powder snow, berry bush)
* <p>
* This is different from the speed factor of a block the vehicle is standing on, such as soul sand.
*
* @param ctx context
* @return the multiplier
*/
protected @Nullable Vector3f getBlockMovementMultiplier(VehicleContext ctx) {
BoundingBox box = boundingBox.clone();
box.expand(-1.0E-7);
@ -464,6 +493,7 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
Vector3i max = box.getMax().toInt();
// Iterate xyz backwards
// Minecraft iterates forwards but only the last multiplier affects movement
for (int x = max.getX(); x >= min.getX(); x--) {
for (int y = max.getY(); y >= min.getY(); y--) {
for (int z = max.getZ(); z >= min.getZ(); z--) {
@ -532,7 +562,9 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
}
/**
* @return True if there was a horizontal collision
* Calculates the next position of the vehicle while checking for collision and adjusting velocity.
*
* @return true if there was a horizontal collision
*/
protected boolean travel(VehicleContext ctx, float speed) {
Vector3f motion = vehicle.getMotion();
@ -546,22 +578,24 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
Math.abs(motion.getZ()) < MIN_VELOCITY ? 0 : motion.getZ()
);
// TODO: isImmobile? set input to 0 and jump to false
// !isImmobile
if (vehicle.isAlive()) {
motion = motion.add(getInputVelocity(ctx, speed));
}
Vector3f movementMultiplier = getBlockMovementMultiplier(ctx);
if (movementMultiplier != null) {
motion = motion.mul(movementMultiplier);
}
// Check world border before blocks
Vector3d correctedMovement = vehicle.getSession().getWorldBorder().correctMovement(boundingBox, motion.toDouble());
correctedMovement = vehicle.getSession().getCollisionManager().correctMovement(
correctedMovement, boundingBox, vehicle.isOnGround(), this.stepHeight, true, vehicle.canWalkOnLava()
);
boundingBox.translate(correctedMovement);
ctx.loadSurroundingBlocks();
ctx.loadSurroundingBlocks(); // Context must be reloaded after vehicle is moved
// Non-zero values indicate a collision on that axis
Vector3d moveDiff = motion.toDouble().sub(correctedMovement);
@ -632,6 +666,27 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
return false;
}
/**
* Translates the player's input into velocity.
*
* @param ctx context
* @param speed multiplier for input
* @return velocity
*/
protected Vector3f getInputVelocity(VehicleContext ctx, float speed) {
Vector2f input = vehicle.getSession().getPlayerEntity().getVehicleInput();
input = input.mul(0.98f);
input = vehicle.getAdjustedInput(input);
input = normalizeInput(input);
input = input.mul(speed);
// Match player rotation
float yaw = vehicle.getSession().getPlayerEntity().getYaw();
float sin = TrigMath.sin(yaw * TrigMath.DEG_TO_RAD);
float cos = TrigMath.cos(yaw * TrigMath.DEG_TO_RAD);
return Vector3f.from(input.getX() * cos - input.getY() * sin, 0, input.getY() * cos + input.getX() * sin);
}
protected Vector2f normalizeInput(Vector2f input) {
float lenSquared = input.lengthSquared();
if (lenSquared < 1.0E-7) {
@ -642,24 +697,20 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
return input;
}
protected Vector3f getInputVelocity(VehicleContext ctx, float speed) {
Vector2f input = vehicle.getSession().getPlayerEntity().getVehicleInput();
input = input.mul(0.98f);
input = vehicle.getAdjustedInput(input);
input = normalizeInput(input);
input = input.mul(speed);
float yaw = vehicle.getSession().getPlayerEntity().getYaw();
float sin = TrigMath.sin(yaw * TrigMath.DEG_TO_RAD);
float cos = TrigMath.cos(yaw * TrigMath.DEG_TO_RAD);
return Vector3f.from(input.getX() * cos - input.getY() * sin, 0, input.getY() * cos + input.getX() * sin);
}
/**
* Gets the rotation to use for the vehicle. This is based on the player's head rotation.
*/
protected Vector2f getVehicleRotation() {
LivingEntity player = vehicle.getSession().getPlayerEntity();
return Vector2f.from(player.getYaw(), player.getPitch() * 0.5f);
}
/**
* Sets the new position for the vehicle and sends packets to both the java server and bedrock client.
* <p>
* This also updates the session's last vehicle move timestamp.
* @param javaPos the new java position of the vehicle
*/
protected void moveVehicle(Vector3d javaPos) {
Vector3f bedrockPos = javaPos.toFloat();
Vector2f rotation = getVehicleRotation();
@ -769,7 +820,10 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
return result;
}
protected BlockState getBlockUnder(VehicleContext ctx, float dist) {
/**
* Returns the block that is x amount of blocks under the main supporting block.
*/
protected BlockState getBlockUnderSupport(VehicleContext ctx, float dist) {
Vector3i supportingBlockPos = ctx.supportingBlockPos();
Vector3i blockPos;
@ -782,12 +836,18 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
return ctx.getBlock(blockPos);
}
/**
* The block to use when determining if the vehicle should bounce after landing. Currently just slime and bed blocks.
*/
protected BlockState getLandingBlock(VehicleContext ctx) {
return getBlockUnder(ctx, 0.2f);
return getBlockUnderSupport(ctx, 0.2f);
}
/**
* The block to use when calculating slipperiness and speed. If on a slab, this will be the block under the slab.
*/
protected BlockState getVelocityBlock(VehicleContext ctx) {
return getBlockUnder(ctx, 0.500001f);
return getBlockUnderSupport(ctx, 0.500001f);
}
protected float getVelocityMultiplier(VehicleContext ctx) {
@ -830,6 +890,11 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
private BlockPositionIterator blockIter;
private int[] blocks;
/**
* Cache frequently used data and blocks used in movement calculations.
* <p>
* Can be called multiple times, and must be called at least once before using the VehicleContext.
*/
protected void loadSurroundingBlocks() {
this.centerPos = boundingBox.getBottomCenter();

View file

@ -85,6 +85,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
session.sendDownstreamGamePacket(playerRotationPacket);
} else {
// World border collision will be handled by client vehicle
if (!(entity.getVehicle() instanceof ClientVehicle clientVehicle && clientVehicle.isClientControlled())
&& session.getWorldBorder().isPassingIntoBorderBoundaries(packet.getPosition(), true)) {
return;