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 bbe0bee23..9e5b62ca2 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/Entity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/Entity.java @@ -72,8 +72,6 @@ public class Entity { */ protected boolean onGround; - protected float scale = 1; - protected EntityType entityType; protected boolean valid; @@ -309,7 +307,7 @@ public class Entity { // The value that Java edition gives us is in ticks, but Bedrock uses a float percentage of the strength 0.0 -> 1.0 // The Java client caps its freezing tick percentage at 140 int freezingTicks = Math.min((int) entityMetadata.getValue(), 140); - metadata.put(EntityData.FREEZING_EFFECT_STRENGTH, (freezingTicks / 140f)); + setFreezing(session, freezingTicks / 140f); break; } } @@ -327,6 +325,15 @@ public class Entity { session.sendUpstreamPacket(entityDataPacket); } + /** + * If true, the entity should be shaking on the client's end. + * + * @return whether {@link EntityFlag#SHAKING} should be set to true. + */ + protected boolean isShaking(GeyserSession session) { + return false; + } + /** * Set the height and width of the entity's bounding box */ @@ -336,6 +343,13 @@ public class Entity { metadata.put(EntityData.BOUNDING_BOX_HEIGHT, entityType.getHeight()); } + /** + * Set a float from 0-1 - how strong the "frozen" overlay should be on screen. + */ + protected void setFreezing(GeyserSession session, float amount) { + metadata.put(EntityData.FREEZING_EFFECT_STRENGTH, amount); + } + /** * x = Pitch, y = HeadYaw, z = Yaw * diff --git a/connector/src/main/java/org/geysermc/connector/entity/LivingEntity.java b/connector/src/main/java/org/geysermc/connector/entity/LivingEntity.java index 9ccb91fc1..4ffb626a8 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/LivingEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/LivingEntity.java @@ -62,6 +62,11 @@ public class LivingEntity extends Entity { protected ItemData hand = ItemData.AIR; protected ItemData offHand = ItemData.AIR; + /** + * A convenience variable for if the entity has reached the maximum frozen ticks and should be shaking + */ + private boolean isMaxFrozenState = false; + public LivingEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); } @@ -112,6 +117,11 @@ public class LivingEntity extends Entity { super.updateBedrockMetadata(entityMetadata, session); } + @Override + protected boolean isShaking(GeyserSession session) { + return isMaxFrozenState; + } + @Override protected void setDimensions(Pose pose) { if (pose == Pose.SLEEPING) { @@ -122,6 +132,13 @@ public class LivingEntity extends Entity { } } + @Override + protected void setFreezing(GeyserSession session, float amount) { + super.setFreezing(session, amount); + this.isMaxFrozenState = amount >= 1.0f; + metadata.getFlags().setFlag(EntityFlag.SHAKING, isShaking(session)); + } + public void updateAllEquipment(GeyserSession session) { if (!valid) return; diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/HoglinEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/HoglinEntity.java index 1534abb0b..492ff68a8 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/HoglinEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/HoglinEntity.java @@ -34,6 +34,7 @@ import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.utils.DimensionUtils; public class HoglinEntity extends AnimalEntity { + private boolean isImmuneToZombification; public HoglinEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); @@ -44,11 +45,17 @@ public class HoglinEntity extends AnimalEntity { if (entityMetadata.getId() == 17) { // Immune to zombification? // Apply shaking effect if not in the nether and zombification is possible - metadata.getFlags().setFlag(EntityFlag.SHAKING, !((boolean) entityMetadata.getValue()) && !session.getDimension().equals(DimensionUtils.NETHER)); + this.isImmuneToZombification = (boolean) entityMetadata.getValue(); + metadata.getFlags().setFlag(EntityFlag.SHAKING, isShaking(session)); } super.updateBedrockMetadata(entityMetadata, session); } + @Override + protected boolean isShaking(GeyserSession session) { + return (!isImmuneToZombification && !session.getDimension().equals(DimensionUtils.NETHER)) || super.isShaking(session); + } + @Override public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemEntry itemEntry) { return javaIdentifierStripped.equals("crimson_fungus"); diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/StriderEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/StriderEntity.java index 51b7aacad..437f60cb4 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/StriderEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/StriderEntity.java @@ -35,7 +35,7 @@ import org.geysermc.connector.network.translators.item.ItemEntry; public class StriderEntity extends AnimalEntity { - private boolean shaking = false; + private boolean isCold = false; public StriderEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); @@ -47,7 +47,7 @@ public class StriderEntity extends AnimalEntity { @Override public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { if (entityMetadata.getId() == 18) { - shaking = (boolean) entityMetadata.getValue(); + isCold = (boolean) entityMetadata.getValue(); } if (entityMetadata.getId() == 19) { metadata.getFlags().setFlag(EntityFlag.SADDLED, (boolean) entityMetadata.getValue()); @@ -72,8 +72,8 @@ public class StriderEntity extends AnimalEntity { metadata.getFlags().setFlag(EntityFlag.BREATHING, !parentShaking); metadata.getFlags().setFlag(EntityFlag.SHAKING, parentShaking); } else { - metadata.getFlags().setFlag(EntityFlag.BREATHING, !shaking); - metadata.getFlags().setFlag(EntityFlag.SHAKING, shaking); + metadata.getFlags().setFlag(EntityFlag.BREATHING, !isCold); + metadata.getFlags().setFlag(EntityFlag.SHAKING, isShaking(session)); } // Update the passengers if we have any @@ -87,6 +87,11 @@ public class StriderEntity extends AnimalEntity { super.updateBedrockMetadata(session); } + @Override + protected boolean isShaking(GeyserSession session) { + return isCold || super.isShaking(session); + } + @Override public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemEntry itemEntry) { return javaIdentifierStripped.equals("warped_fungus"); diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/BasePiglinEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/BasePiglinEntity.java index 57eeb208d..cccdaf7d2 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/BasePiglinEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/BasePiglinEntity.java @@ -33,6 +33,7 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.utils.DimensionUtils; public class BasePiglinEntity extends MonsterEntity { + private boolean isImmuneToZombification; public BasePiglinEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); @@ -43,8 +44,14 @@ public class BasePiglinEntity extends MonsterEntity { if (entityMetadata.getId() == 16) { // Immune to zombification? // Apply shaking effect if not in the nether and zombification is possible - metadata.getFlags().setFlag(EntityFlag.SHAKING, !((boolean) entityMetadata.getValue()) && !session.getDimension().equals(DimensionUtils.NETHER)); + this.isImmuneToZombification = (boolean) entityMetadata.getValue(); + metadata.getFlags().setFlag(EntityFlag.SHAKING, isShaking(session)); } super.updateBedrockMetadata(entityMetadata, session); } + + @Override + protected boolean isShaking(GeyserSession session) { + return (!isImmuneToZombification && !session.getDimension().equals(DimensionUtils.NETHER)) || super.isShaking(session); + } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/SkeletonEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/SkeletonEntity.java new file mode 100644 index 000000000..44c1d1f85 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/SkeletonEntity.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.entity.living.monster; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; +import org.geysermc.connector.entity.type.EntityType; +import org.geysermc.connector.network.session.GeyserSession; + +public class SkeletonEntity extends AbstractSkeletonEntity { + private boolean convertingToStray = false; + + public SkeletonEntity(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) { + super.updateBedrockMetadata(entityMetadata, session); + if (entityMetadata.getId() == 16) { + this.convertingToStray = (boolean) entityMetadata.getValue(); + metadata.getFlags().setFlag(EntityFlag.SHAKING, isShaking(session)); + } + } + + @Override + protected boolean isShaking(GeyserSession session) { + return convertingToStray; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/ZombieEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/ZombieEntity.java index 83dbd0332..bae593e4f 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/ZombieEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/ZombieEntity.java @@ -33,6 +33,7 @@ import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; public class ZombieEntity extends MonsterEntity { + private boolean convertingToDrowned = false; public ZombieEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); @@ -42,11 +43,17 @@ public class ZombieEntity extends MonsterEntity { public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { if (entityMetadata.getId() == 16) { boolean isBaby = (boolean) entityMetadata.getValue(); - if (isBaby) { - metadata.put(EntityData.SCALE, .55f); - metadata.getFlags().setFlag(EntityFlag.BABY, true); - } + metadata.put(EntityData.SCALE, isBaby ? .55f : 1.0f); + metadata.getFlags().setFlag(EntityFlag.BABY, isBaby); + } else if (entityMetadata.getId() == 18) { + convertingToDrowned = (boolean) entityMetadata.getValue(); + metadata.getFlags().setFlag(EntityFlag.SHAKING, isShaking(session)); } super.updateBedrockMetadata(entityMetadata, session); } + + @Override + protected boolean isShaking(GeyserSession session) { + return convertingToDrowned || super.isShaking(session); + } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/ZombieVillagerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/ZombieVillagerEntity.java index eb4881b15..2e3308ec1 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/ZombieVillagerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/ZombieVillagerEntity.java @@ -35,6 +35,7 @@ import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; public class ZombieVillagerEntity extends ZombieEntity { + private boolean isTransforming; public ZombieVillagerEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); @@ -43,8 +44,9 @@ public class ZombieVillagerEntity extends ZombieEntity { @Override public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { if (entityMetadata.getId() == 19) { + isTransforming = (boolean) entityMetadata.getValue(); metadata.getFlags().setFlag(EntityFlag.IS_TRANSFORMING, (boolean) entityMetadata.getValue()); - metadata.getFlags().setFlag(EntityFlag.SHAKING, (boolean) entityMetadata.getValue()); + metadata.getFlags().setFlag(EntityFlag.SHAKING, isShaking(session)); } if (entityMetadata.getId() == 20) { VillagerData villagerData = (VillagerData) entityMetadata.getValue(); @@ -55,4 +57,9 @@ public class ZombieVillagerEntity extends ZombieEntity { } super.updateBedrockMetadata(entityMetadata, session); } + + @Override + protected boolean isShaking(GeyserSession session) { + return isTransforming || super.isShaking(session); + } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java b/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java index 4ca9470b0..36ee9e1c7 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java +++ b/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java @@ -71,7 +71,7 @@ public enum EntityType { ZOMBIE(ZombieEntity.class, 32, 1.8f, 0.6f, 0.6f, 1.62f), GIANT(GiantEntity.class, 32, 1.8f, 0.6f, 0.6f, 1.62f, "minecraft:zombie"), CREEPER(CreeperEntity.class, 33, 1.7f, 0.6f, 0.6f, 1.62f), - SKELETON(AbstractSkeletonEntity.class, 34, 1.8f, 0.6f, 0.6f, 1.62f), + SKELETON(SkeletonEntity.class, 34, 1.8f, 0.6f, 0.6f, 1.62f), SPIDER(SpiderEntity.class, 35, 0.9f, 1.4f, 1.4f, 1f), ZOMBIFIED_PIGLIN(ZombifiedPiglinEntity.class, 36, 1.95f, 0.6f, 0.6f, 1.62f, "minecraft:zombie_pigman"), SLIME(SlimeEntity.class, 37, 0.51f),