mirror of
https://github.com/GeyserMC/Geyser.git
synced 2025-12-21 15:59:32 +00:00
Lerp entity steps
This commit is contained in:
@@ -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.EntityDataTypes;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
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.api.entity.type.GeyserEntity;
|
||||||
import org.geysermc.geyser.entity.EntityDefinition;
|
import org.geysermc.geyser.entity.EntityDefinition;
|
||||||
import org.geysermc.geyser.entity.GeyserDirtyMetadata;
|
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.player.Hand;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
|
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
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@@ -218,11 +227,15 @@ public class Entity implements GeyserEntity {
|
|||||||
valid = false;
|
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);
|
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) {
|
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);
|
position = Vector3f.from(position.getX() + relX, position.getY() + relY, position.getZ() + relZ);
|
||||||
|
|
||||||
MoveEntityDeltaPacket moveEntityPacket = new MoveEntityDeltaPacket();
|
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) {
|
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);
|
setPosition(position);
|
||||||
// Setters are intentional so it can be overridden in places like AbstractArrowEntity
|
// Setters are intentional so it can be overridden in places like AbstractArrowEntity
|
||||||
setYaw(yaw);
|
setYaw(yaw);
|
||||||
|
|||||||
@@ -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.data.inventory.ItemData;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.MobArmorEquipmentPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.MobArmorEquipmentPacket;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.MobEquipmentPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.MobEquipmentPacket;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.packet.MoveEntityDeltaPacket;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
|
||||||
import org.geysermc.geyser.entity.EntityDefinition;
|
import org.geysermc.geyser.entity.EntityDefinition;
|
||||||
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
|
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
|
||||||
@@ -69,7 +70,7 @@ import java.util.*;
|
|||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
public class LivingEntity extends Entity {
|
public class LivingEntity extends Entity implements Tickable {
|
||||||
|
|
||||||
protected ItemData helmet = ItemData.AIR;
|
protected ItemData helmet = ItemData.AIR;
|
||||||
protected ItemData chestplate = ItemData.AIR;
|
protected ItemData chestplate = ItemData.AIR;
|
||||||
@@ -102,6 +103,11 @@ public class LivingEntity extends Entity {
|
|||||||
@Setter(AccessLevel.NONE)
|
@Setter(AccessLevel.NONE)
|
||||||
private float attributeScale;
|
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) {
|
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);
|
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);
|
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
|
@Override
|
||||||
public boolean isAlive() {
|
public boolean isAlive() {
|
||||||
return this.valid && health > 0f;
|
return this.valid && health > 0f;
|
||||||
@@ -304,7 +344,27 @@ public class LivingEntity extends Entity {
|
|||||||
clientVehicle.getVehicleComponent().moveRelative(relX, relY, relZ);
|
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
|
@Override
|
||||||
|
|||||||
@@ -101,6 +101,8 @@ public class PigEntity extends AnimalEntity implements Tickable, ClientVehicle {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
|
||||||
PlayerEntity player = getPlayerPassenger();
|
PlayerEntity player = getPlayerPassenger();
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -101,6 +101,8 @@ public class SnifferEntity extends AnimalEntity implements Tickable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
|
||||||
// The java client renders digging particles on its own, but bedrock does not
|
// The java client renders digging particles on its own, but bedrock does not
|
||||||
if (digTicks > 0 && --digTicks < DIG_START && digTicks % 5 == 0) {
|
if (digTicks > 0 && --digTicks < DIG_START && digTicks % 5 == 0) {
|
||||||
Vector3f rot = Vector3f.createDirectionDeg(0, -getYaw()).mul(2.25f);
|
Vector3f rot = Vector3f.createDirectionDeg(0, -getYaw()).mul(2.25f);
|
||||||
|
|||||||
@@ -148,6 +148,8 @@ public class StriderEntity extends AnimalEntity implements Tickable, ClientVehic
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
|
||||||
PlayerEntity player = getPlayerPassenger();
|
PlayerEntity player = getPlayerPassenger();
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -162,6 +162,8 @@ public class EnderDragonEntity extends MobEntity implements Tickable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
|
||||||
effectTick();
|
effectTick();
|
||||||
if (!getFlag(EntityFlag.NO_AI) && isAlive()) {
|
if (!getFlag(EntityFlag.NO_AI) && isAlive()) {
|
||||||
pushSegment();
|
pushSegment();
|
||||||
|
|||||||
@@ -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
|
@Override
|
||||||
protected boolean isEnemy() {
|
protected boolean isEnemy() {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -73,6 +73,8 @@ public class WardenEntity extends MonsterEntity implements Tickable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
|
||||||
if (++tickCount % heartBeatDelay == 0 && !silent) {
|
if (++tickCount % heartBeatDelay == 0 && !silent) {
|
||||||
// We have to do these calculations because they're clientside on Java Edition but we mute entities
|
// We have to do these calculations because they're clientside on Java Edition but we mute entities
|
||||||
// to prevent hearing their step sounds
|
// to prevent hearing their step sounds
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.translator.protocol.java.entity;
|
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.math.vector.Vector3f;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.SetEntityMotionPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.SetEntityMotionPacket;
|
||||||
import org.geysermc.geyser.entity.type.Entity;
|
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.session.GeyserSession;
|
||||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||||
import org.geysermc.geyser.translator.protocol.Translator;
|
import org.geysermc.geyser.translator.protocol.Translator;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundSetEntityMotionPacket;
|
||||||
|
|
||||||
@Translator(packet = ClientboundSetEntityMotionPacket.class)
|
@Translator(packet = ClientboundSetEntityMotionPacket.class)
|
||||||
public class JavaSetEntityMotionTranslator extends PacketTranslator<ClientboundSetEntityMotionPacket> {
|
public class JavaSetEntityMotionTranslator extends PacketTranslator<ClientboundSetEntityMotionPacket> {
|
||||||
|
|||||||
Reference in New Issue
Block a user