mirror of
https://github.com/GeyserMC/Geyser.git
synced 2025-12-19 14:59:27 +00:00
Implement proper nautilus vehicle movement.
This commit is contained in:
@@ -1234,7 +1234,7 @@ public final class EntityDefinitions {
|
||||
{
|
||||
EntityDefinition<AbstractNautilusEntity> abstractNautilusBase = EntityDefinition.<AbstractNautilusEntity>inherited(null, tameableEntityBase) // No factory, is abstract
|
||||
.width(0.95f).height(0.875f)
|
||||
.addTranslator(null)
|
||||
.addTranslator(MetadataTypes.BOOLEAN, AbstractNautilusEntity::setBoost)
|
||||
.build();
|
||||
|
||||
NAUTILUS = EntityDefinition.inherited(NautilusEntity::new, abstractNautilusBase)
|
||||
|
||||
@@ -536,6 +536,11 @@ public class LivingEntity extends Entity {
|
||||
clientVehicle.getVehicleComponent().setWaterMovementEfficiency(AttributeUtils.calculateValue(javaAttribute));
|
||||
}
|
||||
}
|
||||
case MOVEMENT_EFFICIENCY -> {
|
||||
if (this instanceof ClientVehicle clientVehicle) {
|
||||
clientVehicle.getVehicleComponent().setMovementEfficiency(AttributeUtils.calculateValue(javaAttribute));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,16 +37,19 @@ import org.geysermc.geyser.entity.type.living.animal.tameable.TameableEntity;
|
||||
import org.geysermc.geyser.entity.vehicle.ClientVehicle;
|
||||
import org.geysermc.geyser.entity.vehicle.NautilusVehicleComponent;
|
||||
import org.geysermc.geyser.entity.vehicle.VehicleComponent;
|
||||
import org.geysermc.geyser.input.InputLocksFlag;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.item.enchantment.EnchantmentComponent;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.level.block.Fluid;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.session.cache.tags.Tag;
|
||||
import org.geysermc.geyser.util.InteractiveTag;
|
||||
import org.geysermc.geyser.util.ItemUtils;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.EquipmentSlot;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||
@@ -112,8 +115,27 @@ public abstract class AbstractNautilusEntity extends TameableEntity implements C
|
||||
return super.testMobInteraction(hand, itemInHand);
|
||||
}
|
||||
|
||||
public void setBoost(IntEntityMetadata entityMetadata) {
|
||||
vehicleComponent.startBoost(entityMetadata.getPrimitiveValue());
|
||||
@Override
|
||||
protected void updateSaddled(boolean saddled) {
|
||||
setFlag(EntityFlag.CAN_DASH, saddled);
|
||||
super.updateSaddled(saddled);
|
||||
|
||||
if (this.passengers.contains(session.getPlayerEntity())) {
|
||||
// We want to allow player to press jump again if pressing jump doesn't dismount the entity.
|
||||
this.session.setLockInput(InputLocksFlag.JUMP, this.doesJumpDismount());
|
||||
this.session.updateInputLocks();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doesJumpDismount() {
|
||||
return !this.getFlag(EntityFlag.SADDLED);
|
||||
}
|
||||
|
||||
public void setBoost(BooleanEntityMetadata entityMetadata) {
|
||||
if (entityMetadata.getPrimitiveValue()) {
|
||||
vehicleComponent.setDashCooldown(40);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -137,25 +159,16 @@ public abstract class AbstractNautilusEntity extends TameableEntity implements C
|
||||
}
|
||||
}
|
||||
|
||||
if (session.getInputCache().wasJumping()) {
|
||||
y += 0.5f;
|
||||
}
|
||||
|
||||
return Vector3f.from(x, y, z).mul(3.9f * vehicleComponent.getMoveSpeed());
|
||||
return Vector3f.from(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getVehicleSpeed() {
|
||||
return 0.0f; // Unused
|
||||
return vehicleComponent.isInWater() ? 0.0325F * vehicleComponent.getMoveSpeed() : 0.02F * vehicleComponent.getMoveSpeed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClientControlled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canClimb() {
|
||||
return false;
|
||||
return !this.passengers.isEmpty() && this.passengers.get(0) == session.getPlayerEntity();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,49 +25,76 @@
|
||||
|
||||
package org.geysermc.geyser.entity.vehicle;
|
||||
|
||||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.geyser.entity.type.living.animal.nautilus.AbstractNautilusEntity;
|
||||
import org.geysermc.geyser.level.block.Fluid;
|
||||
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
|
||||
import org.geysermc.geyser.util.MathUtils;
|
||||
|
||||
public class NautilusVehicleComponent extends BoostableVehicleComponent<AbstractNautilusEntity> {
|
||||
public class NautilusVehicleComponent extends VehicleComponent<AbstractNautilusEntity> {
|
||||
private int dashCooldown;
|
||||
|
||||
public NautilusVehicleComponent(AbstractNautilusEntity vehicle, float stepHeight, float defSpeed) {
|
||||
super(vehicle, stepHeight);
|
||||
this.moveSpeed = defSpeed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPushedByFluid() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tickVehicle() {
|
||||
vehicle.setFlag(EntityFlag.CAN_DASH, vehicle.getFlag(EntityFlag.SADDLED));
|
||||
vehicle.setFlag(EntityFlag.HAS_DASH_COOLDOWN, this.dashCooldown > 0);
|
||||
vehicle.updateBedrockMetadata();
|
||||
|
||||
super.tickVehicle();
|
||||
if (this.dashCooldown > 0) {
|
||||
this.dashCooldown--;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Vector3f getInputVector(VehicleComponent<AbstractNautilusEntity>.VehicleContext ctx, float speed, Vector3f input) {
|
||||
Vector3f inputVelocity = super.getInputVector(ctx, speed, input);
|
||||
|
||||
SessionPlayerEntity player = vehicle.getSession().getPlayerEntity();
|
||||
float jumpStrength = player.getVehicleJumpStrength();
|
||||
player.setVehicleJumpStrength(0);
|
||||
|
||||
if (this.dashCooldown <= 0 && jumpStrength > 0) {
|
||||
final Vector3f viewVector = MathUtils.calculateViewVector(vehicle.getPitch(), vehicle.getYaw());
|
||||
|
||||
float movementMultiplier = getVelocityMultiplier(ctx);
|
||||
float strength = (float) (movementMultiplier + movementEfficiency * (1 - movementMultiplier));
|
||||
float actualJumpStrength = (jumpStrength >= 90) ? 1.0F : (0.4F + 0.4F * jumpStrength / 90.0F);
|
||||
|
||||
inputVelocity = inputVelocity.add(viewVector.mul(((this.isInWater() ? 1.2F : 0.5F) * actualJumpStrength) * getMoveSpeed() * strength));
|
||||
setDashCooldown(40);
|
||||
}
|
||||
|
||||
return inputVelocity;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateRotation() {
|
||||
float yaw = vehicle.getYaw() + MathUtils.wrapDegrees(getRiddenRotation().getX() - vehicle.getYaw()) * 0.08f;
|
||||
float yaw = vehicle.getYaw() + MathUtils.wrapDegrees(getRiddenRotation().getX() - vehicle.getYaw()) * 0.5F;
|
||||
vehicle.setYaw(yaw);
|
||||
vehicle.setHeadYaw(yaw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called every session tick while the player is mounted on the vehicle.
|
||||
*/
|
||||
public void tickVehicle() {
|
||||
if (!vehicle.isClientControlled()) {
|
||||
return;
|
||||
@Override
|
||||
protected void waterMovement(VehicleComponent<AbstractNautilusEntity>.VehicleContext ctx) {
|
||||
travel(ctx, vehicle.getVehicleSpeed());
|
||||
this.vehicle.setMotion(this.vehicle.getMotion().mul(0.9f));
|
||||
}
|
||||
|
||||
VehicleContext ctx = new VehicleContext();
|
||||
ctx.loadSurroundingBlocks();
|
||||
public void setDashCooldown(int cooldown) {
|
||||
this.dashCooldown = this.dashCooldown == 0 ? cooldown : this.dashCooldown;
|
||||
|
||||
// LivingEntity#travel
|
||||
Fluid fluid = checkForFluid(ctx);
|
||||
float drag = switch (fluid) {
|
||||
case WATER -> 0.9f; // AbstractNautilus#travelInWater
|
||||
case LAVA -> 0.5f; // LivingEntity#travelInLava
|
||||
case EMPTY -> 1f; // TODO No drag it seems? Should probably check the block below, e.g. soul sand
|
||||
};
|
||||
|
||||
travel(ctx, getRiddenSpeed(fluid));
|
||||
vehicle.setMotion(vehicle.getMotion().mul(drag));
|
||||
}
|
||||
|
||||
// AbstractNautilus#getRiddenSpeed
|
||||
private float getRiddenSpeed(Fluid fluid) {
|
||||
return fluid == Fluid.WATER ? 0.0325F * this.getMoveSpeed() :
|
||||
0.02F * this.getMoveSpeed();
|
||||
vehicle.setFlag(EntityFlag.HAS_DASH_COOLDOWN, this.dashCooldown > 0);
|
||||
vehicle.updateBedrockMetadata();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
|
||||
protected float moveSpeed;
|
||||
protected double gravity;
|
||||
@Getter @Setter
|
||||
protected double waterMovementEfficiency;
|
||||
protected double waterMovementEfficiency, movementEfficiency;
|
||||
protected int effectLevitation;
|
||||
protected boolean effectSlowFalling;
|
||||
protected boolean effectWeaving;
|
||||
@@ -85,6 +85,7 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
|
||||
this.moveSpeed = (float) AttributeType.Builtin.MOVEMENT_SPEED.getDef();
|
||||
this.gravity = AttributeType.Builtin.GRAVITY.getDef();
|
||||
this.waterMovementEfficiency = AttributeType.Builtin.WATER_MOVEMENT_EFFICIENCY.getDef();
|
||||
this.movementEfficiency = AttributeType.Builtin.WATER_MOVEMENT_EFFICIENCY.getDef();
|
||||
|
||||
double width = vehicle.getBoundingBoxWidth();
|
||||
double height = vehicle.getBoundingBoxHeight();
|
||||
@@ -163,6 +164,8 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
|
||||
//
|
||||
}
|
||||
|
||||
@Getter
|
||||
private boolean inWater;
|
||||
/**
|
||||
* Called every session tick while the player is mounted on the vehicle.
|
||||
*/
|
||||
@@ -175,6 +178,7 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
|
||||
ctx.loadSurroundingBlocks();
|
||||
|
||||
ObjectDoublePair<Fluid> fluidHeight = updateFluidMovement(ctx);
|
||||
inWater = fluidHeight.left() == Fluid.WATER;
|
||||
switch (fluidHeight.left()) {
|
||||
case WATER -> waterMovement(ctx);
|
||||
case LAVA -> {
|
||||
@@ -188,6 +192,10 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPushedByFluid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the rotation of the vehicle. Should be called once per tick, and before getInputVector.
|
||||
*/
|
||||
@@ -330,7 +338,7 @@ public class VehicleComponent<T extends LivingEntity & ClientVehicle> {
|
||||
fluidBlocks++;
|
||||
}
|
||||
|
||||
if (!totalVelocity.equals(Vector3d.ZERO)) {
|
||||
if (!totalVelocity.equals(Vector3d.ZERO) && isPushedByFluid()) {
|
||||
Vector3f motion = vehicle.getMotion();
|
||||
|
||||
totalVelocity = javaNormalize(totalVelocity.mul(1.0 / fluidBlocks));
|
||||
|
||||
@@ -39,6 +39,8 @@ import org.geysermc.geyser.entity.type.BoatEntity;
|
||||
import org.geysermc.geyser.entity.type.Entity;
|
||||
import org.geysermc.geyser.entity.type.living.animal.horse.AbstractHorseEntity;
|
||||
import org.geysermc.geyser.entity.type.living.animal.horse.LlamaEntity;
|
||||
import org.geysermc.geyser.entity.type.living.animal.nautilus.AbstractNautilusEntity;
|
||||
import org.geysermc.geyser.entity.type.living.animal.nautilus.NautilusEntity;
|
||||
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
|
||||
import org.geysermc.geyser.entity.vehicle.ClientVehicle;
|
||||
import org.geysermc.geyser.level.physics.BoundingBox;
|
||||
@@ -249,7 +251,7 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator<Pla
|
||||
sendMovement = vehicle.getPassengers().size() == 1 || session.getPlayerEntity().isRidingInFront();
|
||||
}
|
||||
|
||||
if (vehicle instanceof AbstractHorseEntity && !vehicle.getFlag(EntityFlag.HAS_DASH_COOLDOWN)) {
|
||||
if ((vehicle instanceof AbstractHorseEntity || vehicle instanceof AbstractNautilusEntity) && !vehicle.getFlag(EntityFlag.HAS_DASH_COOLDOWN)) {
|
||||
// Behavior verified as of Java Edition 1.21.3
|
||||
int currentJumpingTicks = session.getInputCache().getJumpingTicks();
|
||||
if (currentJumpingTicks < 0) {
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
package org.geysermc.geyser.util;
|
||||
|
||||
import org.cloudburstmc.math.GenericMath;
|
||||
import org.cloudburstmc.math.TrigMath;
|
||||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
|
||||
@@ -47,6 +48,16 @@ public class MathUtils {
|
||||
return Vector3f.from(d1, e, i1);
|
||||
}
|
||||
|
||||
public static Vector3f calculateViewVector(float pitch, float yaw) {
|
||||
float var3 = pitch * 0.017453292F;
|
||||
float var4 = -yaw * 0.017453292F;
|
||||
float var5 = TrigMath.cos(var4);
|
||||
float var6 = TrigMath.sin(var4);
|
||||
float var7 = TrigMath.cos(var3);
|
||||
float var8 = TrigMath.sin(var3);
|
||||
return Vector3f.from(var6 * var7, -var8, var5 * var7);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the given float degrees to be between -180.0 and 180.0.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user