Entity (mostly rotation) fixes (#675)

* Entity (mostly rotation) fixes

    This PR adds:

    - Pig health displaying. Doesn't fix pigs being able to be controlled
    - Entity rotation is *mostly* correct. Villagers and sitting cats still seem to be odd but the ender dragon works great.

* Remove debug line

* Abstract rotation updating to functions per-entity

* Don't include changes from other projects

* Minor improvements

* Make updateRotation and updatePositionAndRotation cleaner

* Javadoc
This commit is contained in:
Camotoy 2020-06-16 19:58:06 -04:00 committed by GitHub
parent a6f91d5e15
commit 256c62ce88
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 166 additions and 69 deletions

View file

@ -44,19 +44,28 @@ public class BoatEntity extends Entity {
private final float ROWING_SPEED = 0.05f;
public BoatEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
super(entityId, geyserId, entityType, position.add(0d, entityType.getOffset(), 0d), motion, rotation.add(0, 0, 90));
super(entityId, geyserId, entityType, position.add(0d, entityType.getOffset(), 0d), motion, rotation.add(90, 0, 90));
}
@Override
public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) {
// Rotation is basically only called when entering/exiting a boat.
// We don't include the rotation (y) as it causes the boat to appear sideways
super.moveAbsolute(session, position.add(0d, this.entityType.getOffset(), 0d), Vector3f.from(0, 0, rotation.getZ() + 90), isOnGround, teleported);
super.moveAbsolute(session, position.add(0d, this.entityType.getOffset(), 0d), Vector3f.from(rotation.getX() + 90, 0, rotation.getX() + 90), isOnGround, teleported);
}
@Override
public void moveRelative(GeyserSession session, double relX, double relY, double relZ, Vector3f rotation, boolean isOnGround) {
super.moveRelative(session, relX, relY, relZ, Vector3f.from(0, 0, rotation.getZ()), isOnGround);
super.moveRelative(session, relX, relY, relZ, Vector3f.from(rotation.getX(), 0, rotation.getX()), isOnGround);
}
@Override
public void updatePositionAndRotation(GeyserSession session, double moveX, double moveY, double moveZ, float yaw, float pitch, boolean isOnGround) {
moveRelative(session, moveX, moveY, moveZ, yaw + 90, pitch, isOnGround);
}
@Override
public void updateRotation(GeyserSession session, float yaw, float pitch, boolean isOnGround) {
moveRelative(session, 0, 0, 0, Vector3f.from(yaw + 90, 0, 0), isOnGround);
}
@Override

View file

@ -78,6 +78,11 @@ public class Entity {
*/
protected Vector3f rotation;
/**
* Saves if the entity should be on the ground. Otherwise entities like parrots are flapping when rotating
*/
protected boolean onGround;
protected float scale = 1;
protected EntityType entityType;
@ -150,11 +155,12 @@ public class Entity {
}
public void moveRelative(GeyserSession session, double relX, double relY, double relZ, float yaw, float pitch, boolean isOnGround) {
moveRelative(session, relX, relY, relZ, Vector3f.from(yaw, pitch, yaw), isOnGround);
moveRelative(session, relX, relY, relZ, Vector3f.from(yaw, pitch, this.rotation.getZ()), isOnGround);
}
public void moveRelative(GeyserSession session, double relX, double relY, double relZ, Vector3f rotation, boolean isOnGround) {
setRotation(rotation);
setOnGround(isOnGround);
this.position = Vector3f.from(position.getX() + relX, position.getY() + relY, position.getZ() + relZ);
MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket();
@ -168,12 +174,13 @@ public class Entity {
}
public void moveAbsolute(GeyserSession session, Vector3f position, float yaw, float pitch, boolean isOnGround, boolean teleported) {
moveAbsolute(session, position, Vector3f.from(yaw, pitch, yaw), isOnGround, teleported);
moveAbsolute(session, position, Vector3f.from(yaw, pitch, this.rotation.getZ()), isOnGround, teleported);
}
public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) {
setPosition(position);
setRotation(rotation);
setOnGround(isOnGround);
MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket();
moveEntityPacket.setRuntimeEntityId(geyserId);
@ -185,6 +192,52 @@ public class Entity {
session.sendUpstreamPacket(moveEntityPacket);
}
/**
* Teleports an entity to a new location. Used in JavaEntityTeleportTranslator.
* @param session GeyserSession.
* @param position The new position of the entity.
* @param yaw The new yaw of the entity.
* @param pitch The new pitch of the entity.
* @param isOnGround Whether the entity is currently on the ground.
*/
public void teleport(GeyserSession session, Vector3f position, float yaw, float pitch, boolean isOnGround) {
moveAbsolute(session, position, yaw, pitch, isOnGround, false);
}
/**
* Updates an entity's head position. Used in JavaEntityHeadLookTranslator.
* @param session GeyserSession.
* @param headYaw The new head rotation of the entity.
*/
public void updateHeadLookRotation(GeyserSession session, float headYaw) {
moveRelative(session, 0, 0, 0, Vector3f.from(headYaw, rotation.getY(), rotation.getZ()), onGround);
}
/**
* Updates an entity's position and rotation. Used in JavaEntityPositionRotationTranslator.
* @param session GeyserSession
* @param moveX The new X offset of the current position.
* @param moveY The new Y offset of the current position.
* @param moveZ The new Z offset of the current position.
* @param yaw The new yaw of the entity.
* @param pitch The new pitch of the entity.
* @param isOnGround Whether the entity is currently on the ground.
*/
public void updatePositionAndRotation(GeyserSession session, double moveX, double moveY, double moveZ, float yaw, float pitch, boolean isOnGround) {
moveRelative(session, moveX, moveY, moveZ, Vector3f.from(rotation.getX(), pitch, yaw), isOnGround);
}
/**
* Updates an entity's rotation. Used in JavaEntityRotationTranslator.
* @param session GeyserSession.
* @param yaw The new yaw of the entity.
* @param pitch The new pitch of the entity.
* @param isOnGround Whether the entity is currently on the ground.
*/
public void updateRotation(GeyserSession session, float yaw, float pitch, boolean isOnGround) {
updatePositionAndRotation(session, 0, 0, 0, yaw, pitch, isOnGround);
}
public void updateBedrockAttributes(GeyserSession session) {
if (!valid) return;

View file

@ -62,6 +62,11 @@ public class PaintingEntity extends Entity {
session.getConnector().getLogger().debug("Spawned painting on " + position);
}
@Override
public void updateHeadLookRotation(GeyserSession session, float headYaw) {
// Do nothing, as head look messes up paintings
}
public Vector3f fixOffset(boolean toBedrock) {
if (toBedrock) {
Vector3f position = super.position;

View file

@ -57,7 +57,6 @@ public class PlayerEntity extends LivingEntity {
private String username;
private long lastSkinUpdate = -1;
private boolean playerList = true;
private boolean onGround;
private final EntityEffectCache effectCache;
private Entity leftParrot;
@ -144,7 +143,7 @@ public class PlayerEntity extends LivingEntity {
setPosition(position);
setRotation(rotation);
this.onGround = isOnGround;
setOnGround(isOnGround);
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
movePlayerPacket.setRuntimeEntityId(geyserId);
@ -171,7 +170,7 @@ public class PlayerEntity extends LivingEntity {
setRotation(rotation);
this.position = Vector3f.from(position.getX() + relX, position.getY() + relY, position.getZ() + relZ);
this.onGround = isOnGround;
setOnGround(isOnGround);
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
movePlayerPacket.setRuntimeEntityId(geyserId);
@ -188,6 +187,35 @@ public class PlayerEntity extends LivingEntity {
}
}
@Override
public void updateHeadLookRotation(GeyserSession session, float headYaw) {
moveRelative(session, 0, 0, 0, Vector3f.from(rotation.getX(), rotation.getY(), headYaw), onGround);
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
movePlayerPacket.setRuntimeEntityId(geyserId);
movePlayerPacket.setPosition(position);
movePlayerPacket.setRotation(getBedrockRotation());
movePlayerPacket.setMode(MovePlayerPacket.Mode.ROTATION);
session.sendUpstreamPacket(movePlayerPacket);
}
@Override
public void updatePositionAndRotation(GeyserSession session, double moveX, double moveY, double moveZ, float yaw, float pitch, boolean isOnGround) {
moveRelative(session, moveX, moveY, moveZ, yaw, pitch, isOnGround);
}
@Override
public void updateRotation(GeyserSession session, float yaw, float pitch, boolean isOnGround) {
super.updateRotation(session, yaw, pitch, isOnGround);
// Both packets need to be sent or else player head rotation isn't correctly updated
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
movePlayerPacket.setRuntimeEntityId(geyserId);
movePlayerPacket.setPosition(position);
movePlayerPacket.setRotation(getBedrockRotation());
movePlayerPacket.setOnGround(isOnGround);
movePlayerPacket.setMode(MovePlayerPacket.Mode.ROTATION);
session.sendUpstreamPacket(movePlayerPacket);
}
@Override
public void setPosition(Vector3f position) {
this.position = position.add(0, entityType.getOffset(), 0);
@ -227,7 +255,7 @@ public class PlayerEntity extends LivingEntity {
}
// Parrot occupying shoulder
if (entityMetadata.getId() == 18 || entityMetadata.getId() == 19) {
if ((entityMetadata.getId() == 18 && leftParrot == null) || (entityMetadata.getId() == 19 && rightParrot == null)) { // null check since this code just creates the parrot
CompoundTag tag = (CompoundTag) entityMetadata.getValue();
if (tag != null && !tag.isEmpty()) {
// The parrot is a separate entity in Bedrock, but part of the player entity in Java

View file

@ -27,21 +27,58 @@ package org.geysermc.connector.entity.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.Attribute;
import com.nukkitx.protocol.bedrock.data.EntityFlag;
import com.nukkitx.protocol.bedrock.packet.UpdateAttributesPacket;
import org.geysermc.connector.entity.attribute.AttributeType;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.utils.AttributeUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class PigEntity extends AnimalEntity {
// For updating the pig heart visual easier
private float health = 20f;
public PigEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
super(entityId, geyserId, entityType, position, motion, rotation);
}
@Override
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
if (entityMetadata.getId() == 8) {
health = (float) entityMetadata.getValue();
updateBedrockAttributes(session);
}
if (entityMetadata.getId() == 16) {
metadata.getFlags().setFlag(EntityFlag.SADDLED, (boolean) entityMetadata.getValue());
}
super.updateBedrockMetadata(entityMetadata, session);
}
@Override
public void updateBedrockAttributes(GeyserSession session) {
if (!valid) return;
float maxHealth = attributes.containsKey(AttributeType.MAX_HEALTH) ? attributes.get(AttributeType.MAX_HEALTH).getValue() : 20f;
List<Attribute> attributesLocal = new ArrayList<>();
for (Map.Entry<AttributeType, org.geysermc.connector.entity.attribute.Attribute> entry : this.attributes.entrySet()) {
if (!entry.getValue().getType().isBedrockAttribute())
continue;
attributesLocal.add(AttributeUtils.getBedrockAttribute(entry.getValue()));
}
attributesLocal.add(new Attribute("minecraft:health", 0.0f, maxHealth, health, maxHealth));
UpdateAttributesPacket updateAttributesPacket = new UpdateAttributesPacket();
updateAttributesPacket.setRuntimeEntityId(geyserId);
updateAttributesPacket.setAttributes(attributesLocal);
session.sendUpstreamPacket(updateAttributesPacket);
}
}

View file

@ -38,6 +38,11 @@ public class CatEntity extends TameableEntity {
super(entityId, geyserId, entityType, position, motion, rotation);
}
@Override
public void updateRotation(GeyserSession session, float yaw, float pitch, boolean isOnGround) {
moveRelative(session, 0, 0, 0, Vector3f.from(this.rotation.getX(), pitch, yaw), isOnGround);
}
@Override
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
if (entityMetadata.getId() == 18) {

View file

@ -28,10 +28,16 @@ package org.geysermc.connector.entity.living.merchant;
import com.nukkitx.math.vector.Vector3f;
import org.geysermc.connector.entity.living.AgeableEntity;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
public class AbstractMerchantEntity extends AgeableEntity {
public AbstractMerchantEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
super(entityId, geyserId, entityType, position, motion, rotation);
}
@Override
public void teleport(GeyserSession session, Vector3f position, float yaw, float pitch, boolean isOnGround) {
super.teleport(session, position, yaw - 180, pitch, isOnGround);
}
}

View file

@ -25,17 +25,12 @@
package org.geysermc.connector.network.translators.java.entity;
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityHeadLookPacket;
import org.geysermc.connector.entity.Entity;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityHeadLookPacket;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
@Translator(packet = ServerEntityHeadLookPacket.class)
public class JavaEntityHeadLookTranslator extends PacketTranslator<ServerEntityHeadLookPacket> {
@ -48,21 +43,6 @@ public class JavaEntityHeadLookTranslator extends PacketTranslator<ServerEntityH
if (entity == null) return;
entity.setRotation(Vector3f.from(entity.getRotation().getX(), entity.getRotation().getY(), packet.getHeadYaw()));
if (entity.getEntityType() != EntityType.PLAYER && entity.getEntityType() != EntityType.PAINTING) {
MoveEntityAbsolutePacket moveEntityAbsolutePacket = new MoveEntityAbsolutePacket();
moveEntityAbsolutePacket.setRuntimeEntityId(entity.getGeyserId());
moveEntityAbsolutePacket.setPosition(entity.getPosition());
moveEntityAbsolutePacket.setRotation(entity.getBedrockRotation());
session.sendUpstreamPacket(moveEntityAbsolutePacket);
} else {
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
movePlayerPacket.setRuntimeEntityId(entity.getGeyserId());
movePlayerPacket.setPosition(entity.getPosition());
movePlayerPacket.setRotation(entity.getBedrockRotation());
movePlayerPacket.setMode(MovePlayerPacket.Mode.ROTATION);
session.sendUpstreamPacket(movePlayerPacket);
}
entity.updateHeadLookRotation(session, packet.getHeadYaw());
}
}

View file

@ -25,14 +25,12 @@
package org.geysermc.connector.network.translators.java.entity;
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityPositionRotationPacket;
import org.geysermc.connector.entity.Entity;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityPositionRotationPacket;
@Translator(packet = ServerEntityPositionRotationPacket.class)
public class JavaEntityPositionRotationTranslator extends PacketTranslator<ServerEntityPositionRotationPacket> {
@ -43,10 +41,7 @@ public class JavaEntityPositionRotationTranslator extends PacketTranslator<Serve
entity = session.getPlayerEntity();
}
if (entity == null) return;
if (entity.getEntityType() == EntityType.BOAT) {
entity.moveRelative(session, packet.getMoveX(), packet.getMoveY(), packet.getMoveZ(), packet.getYaw() - 90, packet.getPitch(), packet.isOnGround());
} else {
entity.moveRelative(session, packet.getMoveX(), packet.getMoveY(), packet.getMoveZ(), packet.getYaw(), packet.getPitch(), packet.isOnGround());
}
entity.updatePositionAndRotation(session, packet.getMoveX(), packet.getMoveY(), packet.getMoveZ(), packet.getYaw(), packet.getPitch(), packet.isOnGround());
}
}

View file

@ -25,17 +25,12 @@
package org.geysermc.connector.network.translators.java.entity;
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityRotationPacket;
import org.geysermc.connector.entity.Entity;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityRotationPacket;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
@Translator(packet = ServerEntityRotationPacket.class)
public class JavaEntityRotationTranslator extends PacketTranslator<ServerEntityRotationPacket> {
@ -47,23 +42,6 @@ public class JavaEntityRotationTranslator extends PacketTranslator<ServerEntityR
}
if (entity == null) return;
// entity.moveRelative(packet.getMovementX(), packet.getMovementY(), packet.getMovementZ(), packet.getYaw(), packet.getPitch());
entity.setRotation(Vector3f.from(packet.getYaw(), packet.getPitch(), packet.getYaw()));
if (entity.getEntityType() != EntityType.PLAYER) {
MoveEntityAbsolutePacket moveEntityAbsolutePacket = new MoveEntityAbsolutePacket();
moveEntityAbsolutePacket.setRuntimeEntityId(entity.getGeyserId());
moveEntityAbsolutePacket.setPosition(entity.getPosition());
moveEntityAbsolutePacket.setRotation(entity.getBedrockRotation());
session.sendUpstreamPacket(moveEntityAbsolutePacket);
} else {
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
movePlayerPacket.setRuntimeEntityId(entity.getGeyserId());
movePlayerPacket.setPosition(entity.getPosition());
movePlayerPacket.setRotation(entity.getBedrockRotation());
movePlayerPacket.setOnGround(packet.isOnGround());
movePlayerPacket.setMode(MovePlayerPacket.Mode.ROTATION);
session.sendUpstreamPacket(movePlayerPacket);
}
entity.updateRotation(session, packet.getYaw(), packet.getPitch(), packet.isOnGround());
}
}

View file

@ -44,6 +44,6 @@ public class JavaEntityTeleportTranslator extends PacketTranslator<ServerEntityT
}
if (entity == null) return;
entity.moveAbsolute(session, Vector3f.from(packet.getX(), packet.getY(), packet.getZ()), packet.getYaw(), packet.getPitch(), packet.isOnGround(), false);
entity.teleport(session, Vector3f.from(packet.getX(), packet.getY(), packet.getZ()), packet.getYaw(), packet.getPitch(), packet.isOnGround());
}
}

View file

@ -31,10 +31,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.object.ProjectileData;
import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType;
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnEntityPacket;
import com.nukkitx.math.vector.Vector3f;
import org.geysermc.connector.entity.Entity;
import org.geysermc.connector.entity.FallingBlockEntity;
import org.geysermc.connector.entity.FishingHookEntity;
import org.geysermc.connector.entity.ItemFrameEntity;
import org.geysermc.connector.entity.*;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
@ -73,6 +70,10 @@ public class JavaSpawnEntityTranslator extends PacketTranslator<ServerSpawnEntit
// Fishing bobbers need the owner for the line
entity = new FishingHookEntity(packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
type, position, motion, rotation, (ProjectileData) packet.getData());
} else if (packet.getType() == EntityType.BOAT) {
// Initial rotation is incorrect
entity = new BoatEntity(packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
type, position, motion, Vector3f.from(packet.getYaw(), 0, packet.getYaw()));
} else {
Constructor<? extends Entity> entityConstructor = entityClass.getConstructor(long.class, long.class, org.geysermc.connector.entity.type.EntityType.class,
Vector3f.class, Vector3f.class, Vector3f.class);