From d7fbdaf93d7e30bc62853220daba63d91a2fabe2 Mon Sep 17 00:00:00 2001 From: David Choo Date: Tue, 20 Jul 2021 12:08:48 -0400 Subject: [PATCH] Fix Squid Animation (#2398) --- .../org/geysermc/connector/entity/Entity.java | 23 ++++-- .../connector/entity/living/SquidEntity.java | 70 ++++++++++++++++++- .../connector/entity/living/WaterEntity.java | 3 - .../entity/living/animal/AxolotlEntity.java | 5 ++ .../entity/player/SessionPlayerEntity.java | 9 +++ .../geysermc/connector/utils/MathUtils.java | 24 +++++++ 6 files changed, 123 insertions(+), 11 deletions(-) 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 ad43f2354..04a876f8f 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/Entity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/Entity.java @@ -46,6 +46,7 @@ import org.geysermc.connector.entity.player.PlayerEntity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.chat.MessageTranslator; +import org.geysermc.connector.utils.MathUtils; @Getter @Setter @@ -83,11 +84,11 @@ public class Entity { this.valid = false; setPosition(position); + setAir(getMaxAir()); metadata.put(EntityData.SCALE, 1f); metadata.put(EntityData.COLOR, 0); - metadata.put(EntityData.MAX_AIR_SUPPLY, (short) 300); - metadata.put(EntityData.AIR_SUPPLY, (short) 0); + metadata.put(EntityData.MAX_AIR_SUPPLY, getMaxAir()); metadata.put(EntityData.LEASH_HOLDER_EID, -1L); metadata.put(EntityData.BOUNDING_BOX_HEIGHT, entityType.getHeight()); metadata.put(EntityData.BOUNDING_BOX_WIDTH, entityType.getWidth()); @@ -255,11 +256,7 @@ public class Entity { } break; case 1: // Air/bubbles - if ((int) entityMetadata.getValue() == 300) { - metadata.put(EntityData.AIR_SUPPLY, (short) 0); // Otherwise the bubble counter remains in the UI - } else { - metadata.put(EntityData.AIR_SUPPLY, (short) (int) entityMetadata.getValue()); - } + setAir((int) entityMetadata.getValue()); break; case 2: // custom name if (entityMetadata.getValue() instanceof Component) { @@ -334,6 +331,18 @@ public class Entity { metadata.put(EntityData.FREEZING_EFFECT_STRENGTH, amount); } + /** + * Set an int from 0 - this entity's maximum air - (air / maxAir) represents the percentage of bubbles left + * @param amount the amount of air + */ + protected void setAir(int amount) { + metadata.put(EntityData.AIR_SUPPLY, (short) MathUtils.constrain(amount, 0, getMaxAir())); + } + + protected int getMaxAir() { + return 300; + } + /** * x = Pitch, y = HeadYaw, z = Yaw * diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/SquidEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/SquidEntity.java index df914162d..baef24bb6 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/SquidEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/SquidEntity.java @@ -26,10 +26,78 @@ package org.geysermc.connector.entity.living; import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; +import org.geysermc.connector.entity.Tickable; import org.geysermc.connector.entity.type.EntityType; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.world.block.BlockStateValues; + +public class SquidEntity extends WaterEntity implements Tickable { + + private float pitch; + private float yaw; + + private float targetPitch; + private float targetYaw; + + private boolean inWater; -public class SquidEntity extends WaterEntity { public SquidEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); + this.yaw = rotation.getX(); + } + + @Override + public void tick(GeyserSession session) { + if (inWater) { + pitch += (targetPitch - pitch) * 0.1f; + yaw += (targetYaw - yaw) * 0.1f; + } else { + pitch += (-90 - pitch) * 0.02f; + } + super.moveAbsolute(session, position, Vector3f.from(yaw, 0, yaw), onGround, false); + } + + @Override + public void moveRelative(GeyserSession session, double relX, double relY, double relZ, Vector3f rotation, boolean isOnGround) { + super.moveRelative(session, relX, relY, relZ, rotation, isOnGround); + checkInWater(session); + } + + @Override + public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) { + super.moveAbsolute(session, position, rotation, isOnGround, teleported); + checkInWater(session); + } + + @Override + public void setRotation(Vector3f rotation) { + // Let the Java server control yaw when the squid is out of water + if (!inWater) { + yaw = rotation.getX(); + } + } + + @Override + public void setMotion(Vector3f motion) { + super.setMotion(motion); + + double horizontalSpeed = Math.sqrt(motion.getX() * motion.getX() + motion.getZ() * motion.getZ()); + targetPitch = (float) Math.toDegrees(-Math.atan2(horizontalSpeed, motion.getY())); + targetYaw = (float) Math.toDegrees(-Math.atan2(motion.getX(), motion.getZ())); + } + + @Override + public Vector3f getBedrockRotation() { + return Vector3f.from(pitch, yaw, yaw); + } + + private void checkInWater(GeyserSession session) { + if (getMetadata().getFlags().getFlag(EntityFlag.RIDING)) { + inWater = false; + } else { + int block = session.getConnector().getWorldManager().getBlockAt(session, position.toInt()); + inWater = BlockStateValues.getWaterLevel(block) != -1; + } } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/WaterEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/WaterEntity.java index 558b061b3..9b90ba72e 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/WaterEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/WaterEntity.java @@ -26,14 +26,11 @@ package org.geysermc.connector.entity.living; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; import org.geysermc.connector.entity.type.EntityType; public class WaterEntity extends CreatureEntity { public WaterEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); - - metadata.put(EntityData.AIR_SUPPLY, (short) 400); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/AxolotlEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/AxolotlEntity.java index f3d634140..3d2be0ce7 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/AxolotlEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/AxolotlEntity.java @@ -62,4 +62,9 @@ public class AxolotlEntity extends AnimalEntity { public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemMapping mapping) { return javaIdentifierStripped.equals("tropical_fish_bucket"); } + + @Override + protected int getMaxAir() { + return 6000; + } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/player/SessionPlayerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/player/SessionPlayerEntity.java index baf07b55d..373ff6f43 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/player/SessionPlayerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/player/SessionPlayerEntity.java @@ -119,6 +119,15 @@ public class SessionPlayerEntity extends PlayerEntity { super.setHealth(health); } + @Override + protected void setAir(int amount) { + if (amount == getMaxAir()) { + super.setAir(0); // Hide the bubble counter from the UI for the player + } else { + super.setAir(amount); + } + } + @Override public AttributeData createHealthAttribute() { // Max health must be divisible by two in bedrock diff --git a/connector/src/main/java/org/geysermc/connector/utils/MathUtils.java b/connector/src/main/java/org/geysermc/connector/utils/MathUtils.java index 0bb854428..4896e54ce 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/MathUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/MathUtils.java @@ -42,6 +42,7 @@ public class MathUtils { /** * If number is greater than the max, set it to max, and if number is lower than low, set it to low. + * * @param num number to calculate * @param min the lowest value the number can be * @param max the greatest value the number can be @@ -53,6 +54,29 @@ public class MathUtils { if (num > max) { num = max; } + + if (num < min) { + num = min; + } + + return num; + } + + /** + * If number is greater than the max, set it to max, and if number is lower than low, set it to low. + * + * @param num number to calculate + * @param min the lowest value the number can be + * @param max the greatest value the number can be + * @return - min if num is lower than min
+ * - max if num is greater than max
+ * - num otherwise + */ + public static int constrain(int num, int min, int max) { + if (num > max) { + num = max; + } + if (num < min) { num = min; }