Lerp entity steps

This commit is contained in:
Camotoy 2024-09-11 13:44:38 -04:00
parent 73f7259b6d
commit 26b7b5a73e
No known key found for this signature in database
GPG key ID: 7EEFB66FE798081F
9 changed files with 105 additions and 6 deletions

View file

@ -35,7 +35,12 @@ import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.*;
import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket;
import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket;
import org.cloudburstmc.protocol.bedrock.packet.MoveEntityDeltaPacket;
import org.cloudburstmc.protocol.bedrock.packet.RemoveEntityPacket;
import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket;
import org.geysermc.geyser.api.entity.type.GeyserEntity;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.GeyserDirtyMetadata;
@ -55,7 +60,11 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEnt
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
import java.util.*;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@Getter
@Setter
@ -218,11 +227,15 @@ public class Entity implements GeyserEntity {
valid = false;
}
public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, boolean isOnGround) {
protected void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, boolean isOnGround) {
moveRelative(relX, relY, relZ, yaw, pitch, getHeadYaw(), isOnGround);
}
public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, float headYaw, boolean isOnGround) {
moveRelativeRaw(relX, relY, relZ, yaw, pitch, headYaw, isOnGround);
}
protected void moveRelativeRaw(double relX, double relY, double relZ, float yaw, float pitch, float headYaw, boolean isOnGround) {
position = Vector3f.from(position.getX() + relX, position.getY() + relY, position.getZ() + relZ);
MoveEntityDeltaPacket moveEntityPacket = new MoveEntityDeltaPacket();
@ -266,6 +279,10 @@ public class Entity implements GeyserEntity {
}
public void moveAbsolute(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) {
moveAbsoluteRaw(position, yaw, pitch, headYaw, isOnGround, teleported);
}
protected void moveAbsoluteRaw(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) {
setPosition(position);
// Setters are intentional so it can be overridden in places like AbstractArrowEntity
setYaw(yaw);

View file

@ -38,6 +38,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.packet.MobArmorEquipmentPacket;
import org.cloudburstmc.protocol.bedrock.packet.MobEquipmentPacket;
import org.cloudburstmc.protocol.bedrock.packet.MoveEntityDeltaPacket;
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
@ -69,7 +70,7 @@ import java.util.*;
@Getter
@Setter
public class LivingEntity extends Entity {
public class LivingEntity extends Entity implements Tickable {
protected ItemData helmet = ItemData.AIR;
protected ItemData chestplate = ItemData.AIR;
@ -102,6 +103,11 @@ public class LivingEntity extends Entity {
@Setter(AccessLevel.NONE)
private float attributeScale;
private float lerpX;
private float lerpY;
private float lerpZ;
private int lerpSteps;
public LivingEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
}
@ -277,6 +283,40 @@ public class LivingEntity extends Entity {
return new AttributeData(GeyserAttributeType.HEALTH.getBedrockIdentifier(), 0f, this.maxHealth, (float) Math.ceil(this.health), this.maxHealth);
}
@Override
public void tick() {
lerpSteps();
}
protected void lerpSteps() {
if (this.lerpSteps > 0) {
float time = 1.0f / this.lerpSteps;
float lerpXTotal = lerp(time, this.position.getX(), this.lerpX);
float lerpYTotal = lerp(time, this.position.getY(), this.lerpY);
float lerpZTotal = lerp(time, this.position.getZ(), this.lerpZ);
setPosition(Vector3f.from(lerpXTotal, lerpYTotal, lerpZTotal));
MoveEntityDeltaPacket moveEntityPacket = new MoveEntityDeltaPacket();
moveEntityPacket.setRuntimeEntityId(geyserId);
moveEntityPacket.setX(position.getX());
moveEntityPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_X);
moveEntityPacket.setY(position.getY());
moveEntityPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_Y);
moveEntityPacket.setZ(position.getZ());
moveEntityPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_Z);
if (this.onGround) {
moveEntityPacket.getFlags().add(MoveEntityDeltaPacket.Flag.ON_GROUND);
}
session.sendUpstreamPacket(moveEntityPacket);
this.lerpSteps--;
}
}
private static float lerp(float time, float a, float b) {
return a + time * (b - a);
}
@Override
public boolean isAlive() {
return this.valid && health > 0f;
@ -304,7 +344,27 @@ public class LivingEntity extends Entity {
clientVehicle.getVehicleComponent().moveRelative(relX, relY, relZ);
}
super.moveRelative(relX, relY, relZ, yaw, pitch, headYaw, isOnGround);
// Logic analogous to Java Edition 1.21.
if (relX != 0 || relY != 0 || relZ != 0) {
this.lerpX = this.position.getX() + (float) relX;
this.lerpY = this.position.getY() + (float) relY;
this.lerpZ = this.position.getZ() + (float) relZ;
this.lerpSteps = 3;
}
// Rotation lerping does not seem to be an issue with Bedrock Edition as of 1.21.22
super.moveRelative(0, 0, 0, yaw, pitch, headYaw, isOnGround);
}
@Override
public void moveAbsolute(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) {
this.lerpX = position.getX();
this.lerpY = position.getY();
this.lerpZ = position.getZ();
this.lerpSteps = 3;
super.moveAbsolute(this.position, yaw, pitch, headYaw, isOnGround, teleported);
}
@Override

View file

@ -101,6 +101,8 @@ public class PigEntity extends AnimalEntity implements Tickable, ClientVehicle {
@Override
public void tick() {
super.tick();
PlayerEntity player = getPlayerPassenger();
if (player == null) {
return;

View file

@ -101,6 +101,8 @@ public class SnifferEntity extends AnimalEntity implements Tickable {
@Override
public void tick() {
super.tick();
// The java client renders digging particles on its own, but bedrock does not
if (digTicks > 0 && --digTicks < DIG_START && digTicks % 5 == 0) {
Vector3f rot = Vector3f.createDirectionDeg(0, -getYaw()).mul(2.25f);

View file

@ -148,6 +148,8 @@ public class StriderEntity extends AnimalEntity implements Tickable, ClientVehic
@Override
public void tick() {
super.tick();
PlayerEntity player = getPlayerPassenger();
if (player == null) {
return;

View file

@ -162,6 +162,8 @@ public class EnderDragonEntity extends MobEntity implements Tickable {
@Override
public void tick() {
super.tick();
effectTick();
if (!getFlag(EntityFlag.NO_AI) && isAlive()) {
pushSegment();

View file

@ -75,6 +75,18 @@ public class ShulkerEntity extends GolemEntity {
}
}
// As of 1.21, Java Edition does not lerp shulker steps.
@Override
public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, float headYaw, boolean isOnGround) {
moveRelativeRaw(relX, relY, relZ, yaw, pitch, headYaw, isOnGround);
}
@Override
public void moveAbsolute(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) {
moveAbsoluteRaw(position, yaw, pitch, headYaw, isOnGround, teleported);
}
@Override
protected boolean isEnemy() {
return true;

View file

@ -73,6 +73,8 @@ public class WardenEntity extends MonsterEntity implements Tickable {
@Override
public void tick() {
super.tick();
if (++tickCount % heartBeatDelay == 0 && !silent) {
// We have to do these calculations because they're clientside on Java Edition but we mute entities
// to prevent hearing their step sounds

View file

@ -25,7 +25,6 @@
package org.geysermc.geyser.translator.protocol.java.entity;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundSetEntityMotionPacket;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.packet.SetEntityMotionPacket;
import org.geysermc.geyser.entity.type.Entity;
@ -34,6 +33,7 @@ import org.geysermc.geyser.entity.type.living.animal.horse.AbstractHorseEntity;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundSetEntityMotionPacket;
@Translator(packet = ClientboundSetEntityMotionPacket.class)
public class JavaSetEntityMotionTranslator extends PacketTranslator<ClientboundSetEntityMotionPacket> {