Skip to content

Commit

Permalink
Entity (mostly rotation) fixes (GeyserMC#675)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
Camotoy authored Jun 16, 2020
1 parent a6f91d5 commit 256c62c
Show file tree
Hide file tree
Showing 12 changed files with 166 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
57 changes: 55 additions & 2 deletions connector/src/main/java/org/geysermc/connector/entity/Entity.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -150,11 +155,12 @@ public boolean despawnEntity(GeyserSession session) {
}

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();
Expand All @@ -168,12 +174,13 @@ public void moveRelative(GeyserSession session, double relX, double relY, double
}

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);
Expand All @@ -185,6 +192,52 @@ public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rota
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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ public void spawnEntity(GeyserSession session) {
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -144,7 +143,7 @@ public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rota
setPosition(position);
setRotation(rotation);

this.onGround = isOnGround;
setOnGround(isOnGround);

MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
movePlayerPacket.setRuntimeEntityId(geyserId);
Expand All @@ -171,7 +170,7 @@ public void moveRelative(GeyserSession session, double relX, double relY, double
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);
Expand All @@ -188,6 +187,35 @@ public void moveRelative(GeyserSession session, double relX, double relY, double
}
}

@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);
Expand Down Expand Up @@ -227,7 +255,7 @@ public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession s
}

// 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,58 @@

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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ public CatEntity(long entityId, long geyserId, EntityType entityType, Vector3f p
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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,16 @@
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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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> {

Expand All @@ -48,21 +43,6 @@ public void translate(ServerEntityHeadLookPacket packet, GeyserSession session)

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());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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> {

Expand All @@ -43,10 +41,7 @@ public void translate(ServerEntityPositionRotationPacket packet, GeyserSession s
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());
}
}
Loading

0 comments on commit 256c62c

Please sign in to comment.