diff --git a/connector/src/main/java/org/geysermc/connector/entity/BoatEntity.java b/connector/src/main/java/org/geysermc/connector/entity/BoatEntity.java index 8f79526d..a59cd08f 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/BoatEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/BoatEntity.java @@ -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 diff --git a/connector/src/main/java/org/geysermc/connector/entity/Entity.java b/connector/src/main/java/org/geysermc/connector/entity/Entity.java index c5fcde9e..d5ae391c 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/Entity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/Entity.java @@ -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; diff --git a/connector/src/main/java/org/geysermc/connector/entity/PaintingEntity.java b/connector/src/main/java/org/geysermc/connector/entity/PaintingEntity.java index 1711fd38..00cfc8b5 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/PaintingEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/PaintingEntity.java @@ -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; diff --git a/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java index aa7848da..594f139a 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java @@ -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 diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/PigEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/PigEntity.java index b28ad99f..fd9fd999 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/PigEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/PigEntity.java @@ -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 attributesLocal = new ArrayList<>(); + for (Map.Entry 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); + } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/CatEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/CatEntity.java index 63a67a0a..de9bcb4e 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/CatEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/CatEntity.java @@ -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) { diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/merchant/AbstractMerchantEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/merchant/AbstractMerchantEntity.java index ddeb31bd..11028b79 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/merchant/AbstractMerchantEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/merchant/AbstractMerchantEntity.java @@ -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); + } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityHeadLookTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityHeadLookTranslator.java index e26a5880..115cae55 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityHeadLookTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityHeadLookTranslator.java @@ -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 { @@ -48,21 +43,6 @@ public class JavaEntityHeadLookTranslator extends PacketTranslator { @@ -43,10 +41,7 @@ public class JavaEntityPositionRotationTranslator extends PacketTranslator { @@ -47,23 +42,6 @@ public class JavaEntityRotationTranslator extends PacketTranslator entityConstructor = entityClass.getConstructor(long.class, long.class, org.geysermc.connector.entity.type.EntityType.class, Vector3f.class, Vector3f.class, Vector3f.class);