From 8b95e3881ddc6e0b06607796c7f579ed76cb5d4b Mon Sep 17 00:00:00 2001 From: TheMode Date: Tue, 27 Aug 2019 20:49:11 +0200 Subject: [PATCH] Added gravity --- .../fr/themode/minestom/entity/Entity.java | 62 ++++++++++++-- .../minestom/entity/EntityCreature.java | 12 ++- .../themode/minestom/entity/EntityType.java | 85 +++++++++++++++++++ .../themode/minestom/entity/ItemEntity.java | 1 + .../themode/minestom/entity/LivingEntity.java | 12 +++ .../themode/minestom/entity/ObjectEntity.java | 7 ++ .../fr/themode/minestom/entity/Player.java | 37 +++++--- .../minestom/entity/demo/ChickenCreature.java | 8 +- .../themode/minestom/instance/BlockBatch.java | 7 +- .../themode/minestom/instance/ChunkBatch.java | 1 + .../themode/minestom/instance/Instance.java | 28 +++--- .../minestom/instance/InstanceContainer.java | 18 ++-- .../listener/PlayerPositionListener.java | 3 +- .../themode/minestom/utils/BlockPosition.java | 10 ++- .../fr/themode/minestom/utils/ChunkUtils.java | 6 ++ .../themode/minestom/utils/EntityUtils.java | 10 +++ .../fr/themode/minestom/utils/Position.java | 9 +- 17 files changed, 264 insertions(+), 52 deletions(-) create mode 100644 src/main/java/fr/themode/minestom/entity/EntityType.java diff --git a/src/main/java/fr/themode/minestom/entity/Entity.java b/src/main/java/fr/themode/minestom/entity/Entity.java index 61ddc9471..77a1147f1 100644 --- a/src/main/java/fr/themode/minestom/entity/Entity.java +++ b/src/main/java/fr/themode/minestom/entity/Entity.java @@ -36,7 +36,6 @@ public abstract class Entity implements Viewable, DataContainer { protected Instance instance; protected Position position; - protected boolean onGround; protected float lastX, lastY, lastZ; protected float lastYaw, lastPitch; private int id; @@ -45,6 +44,9 @@ public abstract class Entity implements Viewable, DataContainer { // Velocity // TODO gravity implementation for entity other than players protected Vector velocity = new Vector(); // Movement in block per second + protected float gravityDragPerTick; + private int gravityTickCounter; + private Set viewers = new CopyOnWriteArraySet<>(); private Data data; private Set passengers = new CopyOnWriteArraySet<>(); @@ -104,6 +106,8 @@ public abstract class Entity implements Viewable, DataContainer { // Called when entity a new instance is set public abstract void spawn(); + public abstract boolean isOnGround(); + public void teleport(Position position, Runnable callback) { if (instance == null) throw new IllegalStateException("You need to use Entity#setInstance before teleporting an entity!"); @@ -114,7 +118,7 @@ public abstract class Entity implements Viewable, DataContainer { EntityTeleportPacket entityTeleportPacket = new EntityTeleportPacket(); entityTeleportPacket.entityId = getEntityId(); entityTeleportPacket.position = position; - entityTeleportPacket.onGround = onGround; + entityTeleportPacket.onGround = isOnGround(); sendPacketToViewers(entityTeleportPacket); }; @@ -125,7 +129,7 @@ public abstract class Entity implements Viewable, DataContainer { callback.run(); }); } else { - if (isChunkUnloaded(position.getX(), position.getZ())) + if (ChunkUtils.isChunkUnloaded(instance, position.getX(), position.getZ())) return; runnable.run(); if (callback != null) @@ -210,6 +214,36 @@ public abstract class Entity implements Viewable, DataContainer { } } + // Gravity + if (!(this instanceof Player) && !noGravity && gravityDragPerTick != 0) { // Players do manage gravity client-side + Position position = getPosition(); + if (!isOnGround()) { + float strength = gravityDragPerTick * gravityTickCounter; + + int firstBlock = 0; + for (int y = (int) position.getY(); y > 0; y--) { + short blockId = instance.getBlockId((int) position.getX(), y, (int) position.getZ()); + if (blockId != 0) { + firstBlock = y; + break; + } + } + + float newY = position.getY() - strength; + newY = Math.max(newY, firstBlock); + refreshPosition(position.getX(), newY, position.getZ()); + gravityTickCounter++; + if (isOnGround()) { // Round Y axis when gravity movement is done + refreshPosition(position.getX(), Math.round(position.getY()), position.getZ()); + gravityTickCounter = 0; + } + + if (this instanceof EntityCreature) // Objects are automatically updated client side + teleport(getPosition()); + } + } + + update(); // Scheduled synchronization @@ -295,6 +329,10 @@ public abstract class Entity implements Viewable, DataContainer { this.velocityTime = 0; } + public void setGravity(float gravityDragPerTick) { + this.gravityDragPerTick = gravityDragPerTick; + } + public float getDistance(Entity entity) { return getPosition().getDistance(entity.getPosition()); } @@ -360,18 +398,26 @@ public abstract class Entity implements Viewable, DataContainer { sendMetadataIndex(0); } + public boolean isOnFire() { + return onFire; + } + public void setGlowing(boolean glowing) { this.glowing = glowing; sendMetadataIndex(0); } + public boolean isGlowing() { + return glowing; + } + public void setNoGravity(boolean noGravity) { this.noGravity = noGravity; sendMetadataIndex(5); } - public boolean isChunkUnloaded(float x, float z) { - return getInstance().getChunk((int) Math.floor(x / 16), (int) Math.floor(z / 16)) == null; + public boolean hasNoGravity() { + return noGravity; } public void refreshPosition(float x, float y, float z) { @@ -436,6 +482,10 @@ public abstract class Entity implements Viewable, DataContainer { } } + public void refreshPosition(Position position) { + refreshPosition(position.getX(), position.getY(), position.getZ()); + } + public void refreshView(float yaw, float pitch) { this.lastYaw = position.getYaw(); this.lastPitch = position.getPitch(); @@ -554,7 +604,7 @@ public abstract class Entity implements Viewable, DataContainer { EntityTeleportPacket entityTeleportPacket = new EntityTeleportPacket(); entityTeleportPacket.entityId = getEntityId(); entityTeleportPacket.position = getPosition(); - entityTeleportPacket.onGround = onGround; + entityTeleportPacket.onGround = isOnGround(); sendPacketToViewers(entityTeleportPacket); } diff --git a/src/main/java/fr/themode/minestom/entity/EntityCreature.java b/src/main/java/fr/themode/minestom/entity/EntityCreature.java index 850196050..1e0ebe6e9 100644 --- a/src/main/java/fr/themode/minestom/entity/EntityCreature.java +++ b/src/main/java/fr/themode/minestom/entity/EntityCreature.java @@ -5,13 +5,15 @@ import fr.themode.minestom.net.packet.server.play.EntityPacket; import fr.themode.minestom.net.packet.server.play.EntityRelativeMovePacket; import fr.themode.minestom.net.packet.server.play.SpawnMobPacket; import fr.themode.minestom.net.player.PlayerConnection; +import fr.themode.minestom.utils.ChunkUtils; +import fr.themode.minestom.utils.EntityUtils; import fr.themode.minestom.utils.Position; // TODO viewers synchronization each X ticks? public abstract class EntityCreature extends LivingEntity { - public EntityCreature(int entityType) { - super(entityType); + public EntityCreature(EntityType entityType) { + super(entityType.getId()); } @Override @@ -26,7 +28,7 @@ public abstract class EntityCreature extends LivingEntity { float newY = position.getY() + y; float newZ = position.getZ() + z; - if (isChunkUnloaded(newX, newZ)) + if (ChunkUtils.isChunkUnloaded(getInstance(), newX, newZ)) return; EntityRelativeMovePacket entityRelativeMovePacket = new EntityRelativeMovePacket(); @@ -67,4 +69,8 @@ public abstract class EntityCreature extends LivingEntity { playerConnection.sendPacket(getMetadataPacket()); } + @Override + public boolean isOnGround() { + return EntityUtils.isOnGround(this); + } } diff --git a/src/main/java/fr/themode/minestom/entity/EntityType.java b/src/main/java/fr/themode/minestom/entity/EntityType.java new file mode 100644 index 000000000..0e0cfa943 --- /dev/null +++ b/src/main/java/fr/themode/minestom/entity/EntityType.java @@ -0,0 +1,85 @@ +package fr.themode.minestom.entity; + +import java.util.Arrays; + +public enum EntityType { + ARMOR_STAND(1), // Object + BAT(3), + BLAZE(4), + CAT(6), + CAVE_SPIDER(7), + CHICKEN(8), + COD(9), + COW(10), + CREEPER(11), + DONKEY(12), + DOLPHIN(13), + DROWNED(15), + ELDER_GUARDIAN(16), + ENDER_DRAGON(18), + ENDERMAN(19), + ENDERMITE(20), + EVOKER(22), + FOX(27), + GHAST(28), + GIANT(29), + GUARDIAN(30), + HORSE(31), + HUSK(32), + ILLUSIONER(33), + LLAMA(38), + MAGMA_CUBE(40), + MULE(48), + MOOSHROOM(49), + OCELOT(50), + PANDA(52), + PARROT(53), + PIG(54), + PUFFERFISH(55), + ZOMBIE_PIGMAN(56), + POLAR_BEAR(57), + RABBIT(59), + SALMON(60), + SHEEP(61), + SHULKER(62), + SILVERFISH(64), + SKELETON(65), + SKELETON_HORSE(66), + SLIME(67), + SNOW_GOLEM(69), + SPIDER(72), + SQUID(73), + STRAY(74), + TRADER_LLAMA(75), + TROPICAL_FISH(76), + TURTLE(77), + VEX(83), + VILLAGER(84), + IRON_GOLEM(85), + VINDICATOR(86), + PILLAGER(87), + WANGERING_TRADER(88), + WITCH(89), + WITHER(90), + WITHER_SKELETON(91), + WOLF(93), + ZOMBIE(94), + ZOMBIE_HORSE(95), + ZOMBIE_VILLAGER(96), + PHANTOM(97), + RAVAGER(98); + + private int id; + + EntityType(int id) { + this.id = id; + } + + public static EntityType fromId(int id) { + return Arrays.stream(values()).filter(entityType -> entityType.id == id).findFirst().get(); + } + + public int getId() { + return id; + } +} diff --git a/src/main/java/fr/themode/minestom/entity/ItemEntity.java b/src/main/java/fr/themode/minestom/entity/ItemEntity.java index d5981804d..aadc291a4 100644 --- a/src/main/java/fr/themode/minestom/entity/ItemEntity.java +++ b/src/main/java/fr/themode/minestom/entity/ItemEntity.java @@ -12,6 +12,7 @@ public class ItemEntity extends ObjectEntity { public ItemEntity(ItemStack itemStack) { super(34); this.itemStack = itemStack; + setGravity(0.02f); } @Override diff --git a/src/main/java/fr/themode/minestom/entity/LivingEntity.java b/src/main/java/fr/themode/minestom/entity/LivingEntity.java index d60b1b55d..e3cf8c1ce 100644 --- a/src/main/java/fr/themode/minestom/entity/LivingEntity.java +++ b/src/main/java/fr/themode/minestom/entity/LivingEntity.java @@ -5,6 +5,7 @@ import fr.themode.minestom.entity.property.Attribute; import fr.themode.minestom.event.PickupItemEvent; import fr.themode.minestom.instance.Chunk; import fr.themode.minestom.item.ItemStack; +import fr.themode.minestom.net.packet.server.play.AnimationPacket; import fr.themode.minestom.net.packet.server.play.CollectItemPacket; import fr.themode.minestom.net.packet.server.play.EntityPropertiesPacket; @@ -26,6 +27,7 @@ public abstract class LivingEntity extends Entity { public LivingEntity(int entityType) { super(entityType); setupAttributes(); + setGravity(0.02f); } public abstract void kill(); @@ -79,11 +81,21 @@ public abstract class LivingEntity extends Entity { return buffer; } + public void damage(float value) { + AnimationPacket animationPacket = new AnimationPacket(); + animationPacket.entityId = getEntityId(); + animationPacket.animation = AnimationPacket.Animation.TAKE_DAMAGE; + sendPacketToViewersAndSelf(animationPacket); + setHealth(getHealth() - value); + } + public float getHealth() { return health; } public void setHealth(float health) { + health = Math.min(health, getMaxHealth()); + this.health = health; if (this.health <= 0) { kill(); diff --git a/src/main/java/fr/themode/minestom/entity/ObjectEntity.java b/src/main/java/fr/themode/minestom/entity/ObjectEntity.java index 6ce34140c..2abb8770b 100644 --- a/src/main/java/fr/themode/minestom/entity/ObjectEntity.java +++ b/src/main/java/fr/themode/minestom/entity/ObjectEntity.java @@ -2,6 +2,7 @@ package fr.themode.minestom.entity; import fr.themode.minestom.net.packet.server.play.SpawnObjectPacket; import fr.themode.minestom.net.player.PlayerConnection; +import fr.themode.minestom.utils.EntityUtils; // TODO viewers synchronization each X ticks? public abstract class ObjectEntity extends Entity { @@ -31,4 +32,10 @@ public abstract class ObjectEntity extends Entity { public void removeViewer(Player player) { super.removeViewer(player); } + + @Override + public boolean isOnGround() { + return EntityUtils.isOnGround(this); + } + } diff --git a/src/main/java/fr/themode/minestom/entity/Player.java b/src/main/java/fr/themode/minestom/entity/Player.java index 2c9de4b53..bace47104 100644 --- a/src/main/java/fr/themode/minestom/entity/Player.java +++ b/src/main/java/fr/themode/minestom/entity/Player.java @@ -4,6 +4,7 @@ import fr.themode.minestom.Main; import fr.themode.minestom.bossbar.BossBar; import fr.themode.minestom.chat.Chat; import fr.themode.minestom.data.Data; +import fr.themode.minestom.entity.demo.ChickenCreature; import fr.themode.minestom.entity.property.Attribute; import fr.themode.minestom.event.*; import fr.themode.minestom.instance.Chunk; @@ -13,6 +14,7 @@ import fr.themode.minestom.instance.InstanceContainer; import fr.themode.minestom.instance.demo.ChunkGeneratorDemo; import fr.themode.minestom.inventory.Inventory; import fr.themode.minestom.inventory.PlayerInventory; +import fr.themode.minestom.item.ItemStack; import fr.themode.minestom.net.packet.client.ClientPlayPacket; import fr.themode.minestom.net.packet.server.ServerPacket; import fr.themode.minestom.net.packet.server.play.*; @@ -40,6 +42,8 @@ public class Player extends LivingEntity { private GameMode gameMode; private LevelType levelType; + protected boolean onGround; + private static InstanceContainer instanceContainer; static { @@ -82,7 +86,7 @@ public class Player extends LivingEntity { protected boolean spawned; public Player(UUID uuid, String username, PlayerConnection playerConnection) { - super(93); + super(100); this.uuid = uuid; this.username = username; this.playerConnection = playerConnection; @@ -98,8 +102,11 @@ public class Player extends LivingEntity { setEventCallback(AttackEvent.class, event -> { Entity entity = event.getTarget(); if (entity instanceof EntityCreature) { - ((EntityCreature) entity).kill(); - sendMessage("You killed an entity!"); + ((EntityCreature) entity).damage(-1); + Vector velocity = getPosition().clone().getDirection().multiply(6); + velocity.setY(4f); + entity.setVelocity(velocity, 150); + sendMessage("You attacked an entity!"); } else if (entity instanceof Player) { Player player = (Player) entity; Vector velocity = getPosition().clone().getDirection().multiply(6); @@ -145,18 +152,18 @@ public class Player extends LivingEntity { setGameMode(GameMode.SURVIVAL); teleport(new Position(0, 66, 0)); - /*ChickenCreature chickenCreature = new ChickenCreature(); + ChickenCreature chickenCreature = new ChickenCreature(); chickenCreature.refreshPosition(2, 65, 2); chickenCreature.setInstance(getInstance()); for (int ix = 0; ix < 4; ix++) for (int iz = 0; iz < 4; iz++) { ItemEntity itemEntity = new ItemEntity(new ItemStack(1, (byte) 32)); - itemEntity.refreshPosition(ix, 66, iz); - itemEntity.setNoGravity(true); + itemEntity.refreshPosition(ix, 68, iz); + //itemEntity.setNoGravity(true); itemEntity.setInstance(getInstance()); //itemEntity.remove(); - }*/ + } TeamsPacket teamsPacket = new TeamsPacket(); teamsPacket.teamName = "TEAMNAME" + new Random().nextInt(100); @@ -270,6 +277,11 @@ public class Player extends LivingEntity { } + @Override + public boolean isOnGround() { + return onGround; + } + @Override public void remove() { clearBossBars(); @@ -345,15 +357,12 @@ public class Player extends LivingEntity { playerConnection.sendPacket(chatMessagePacket); } - public void damage(float amount) { + @Override + public void damage(float value) { if (getGameMode() == GameMode.CREATIVE) return; - AnimationPacket animationPacket = new AnimationPacket(); - animationPacket.entityId = getEntityId(); - animationPacket.animation = AnimationPacket.Animation.TAKE_DAMAGE; - sendPacketToViewersAndSelf(animationPacket); - setHealth(getHealth() - amount); + super.damage(value); } @Override @@ -471,7 +480,7 @@ public class Player extends LivingEntity { @Override public void teleport(Position position, Runnable callback) { super.teleport(position, () -> { - if (!instance.hasEnabledAutoChunkLoad() && isChunkUnloaded(position.getX(), position.getZ())) + if (!instance.hasEnabledAutoChunkLoad() && ChunkUtils.isChunkUnloaded(instance, position.getX(), position.getZ())) return; updatePlayerPosition(); if (callback != null) diff --git a/src/main/java/fr/themode/minestom/entity/demo/ChickenCreature.java b/src/main/java/fr/themode/minestom/entity/demo/ChickenCreature.java index ceebf72e5..b6ffc8ca0 100644 --- a/src/main/java/fr/themode/minestom/entity/demo/ChickenCreature.java +++ b/src/main/java/fr/themode/minestom/entity/demo/ChickenCreature.java @@ -1,12 +1,12 @@ package fr.themode.minestom.entity.demo; import fr.themode.minestom.entity.EntityCreature; -import fr.themode.minestom.utils.Vector; +import fr.themode.minestom.entity.EntityType; public class ChickenCreature extends EntityCreature { public ChickenCreature() { - super(8); + super(EntityType.CHICKEN); } @Override @@ -43,11 +43,11 @@ public class ChickenCreature extends EntityCreature { move(x * speed, 0, z * speed); } }*/ - move(0, 0, speed); + // move(0, 0, speed); } @Override public void spawn() { - setVelocity(new Vector(0, 1, 0), 3000); + // setVelocity(new Vector(0, 1, 0), 3000); } } diff --git a/src/main/java/fr/themode/minestom/instance/BlockBatch.java b/src/main/java/fr/themode/minestom/instance/BlockBatch.java index f0858ad81..79af3fc69 100644 --- a/src/main/java/fr/themode/minestom/instance/BlockBatch.java +++ b/src/main/java/fr/themode/minestom/instance/BlockBatch.java @@ -65,8 +65,11 @@ public class BlockBatch implements BlockModifier { } chunk.refreshDataPacket(); instance.sendChunkUpdate(chunk); - if (isLast && callback != null) - callback.run(); + if (isLast) { + // data.clear(); + if (callback != null) + callback.run(); + } } }); } diff --git a/src/main/java/fr/themode/minestom/instance/ChunkBatch.java b/src/main/java/fr/themode/minestom/instance/ChunkBatch.java index 86660d403..77f878012 100644 --- a/src/main/java/fr/themode/minestom/instance/ChunkBatch.java +++ b/src/main/java/fr/themode/minestom/instance/ChunkBatch.java @@ -54,6 +54,7 @@ public class ChunkBatch implements BlockModifier { data.apply(chunk); } + // dataList.clear(); chunk.refreshDataPacket(); instance.sendChunkUpdate(chunk); if (callback != null) diff --git a/src/main/java/fr/themode/minestom/instance/Instance.java b/src/main/java/fr/themode/minestom/instance/Instance.java index 78ad6834c..bf8c1c6ab 100644 --- a/src/main/java/fr/themode/minestom/instance/Instance.java +++ b/src/main/java/fr/themode/minestom/instance/Instance.java @@ -153,20 +153,22 @@ public abstract class Instance implements BlockModifier { lastInstance.removeEntity(entity); // If entity is in another instance, remove it from there and add it to this } - if (entity instanceof Player) { - Player player = (Player) entity; - sendChunks(player); + long[] visibleChunksEntity = ChunkUtils.getChunksInRange(entity.getPosition(), Main.ENTITY_VIEW_DISTANCE); + boolean isPlayer = entity instanceof Player; - // Send player all visible entities - long[] visibleChunksEntity = ChunkUtils.getChunksInRange(entity.getPosition(), Main.ENTITY_VIEW_DISTANCE); - for (long chunkIndex : visibleChunksEntity) { - getEntitiesInChunk(chunkIndex).forEach(ent -> { - ent.addViewer(player); - if (ent instanceof Player) { - player.addViewer((Player) ent); - } - }); - } + if (isPlayer) { + sendChunks((Player) entity); + } + + // Send all visible entities + for (long chunkIndex : visibleChunksEntity) { + getEntitiesInChunk(chunkIndex).forEach(ent -> { + if (isPlayer) + ent.addViewer((Player) entity); + if (ent instanceof Player) { + entity.addViewer((Player) ent); + } + }); } Chunk chunk = getChunkAt(entity.getPosition()); diff --git a/src/main/java/fr/themode/minestom/instance/InstanceContainer.java b/src/main/java/fr/themode/minestom/instance/InstanceContainer.java index f4b4efa12..4ece5e3aa 100644 --- a/src/main/java/fr/themode/minestom/instance/InstanceContainer.java +++ b/src/main/java/fr/themode/minestom/instance/InstanceContainer.java @@ -207,15 +207,19 @@ public class InstanceContainer extends Instance { @Override public void sendChunk(Player player, Chunk chunk) { + /*Buffer data = chunk.getFullDataPacket(); + if(data == null) { + PacketWriter.writeCallbackPacket(chunk.getFreshFullDataPacket(), buffer -> { + chunk.setFullDataPacket(buffer); + sendChunkUpdate(player, chunk); + }); + }else{ + sendChunkUpdate(player, chunk); + }*/ PacketWriter.writeCallbackPacket(chunk.getFreshFullDataPacket(), buffer -> { - buffer.getData().retain(1).markReaderIndex(); - player.getPlayerConnection().sendUnencodedPacket(buffer); - buffer.getData().resetReaderIndex(); + chunk.setFullDataPacket(buffer); + sendChunkUpdate(player, chunk); }); - // TODO use cached chunk data - /*chunkData.getData().retain(1).markReaderIndex(); - player.getPlayerConnection().sendUnencodedPacket(chunkData); - chunkData.getData().resetReaderIndex();*/ } @Override diff --git a/src/main/java/fr/themode/minestom/listener/PlayerPositionListener.java b/src/main/java/fr/themode/minestom/listener/PlayerPositionListener.java index bde5b651d..3bb0a4f59 100644 --- a/src/main/java/fr/themode/minestom/listener/PlayerPositionListener.java +++ b/src/main/java/fr/themode/minestom/listener/PlayerPositionListener.java @@ -6,6 +6,7 @@ import fr.themode.minestom.net.packet.client.play.ClientPlayerLookPacket; import fr.themode.minestom.net.packet.client.play.ClientPlayerPacket; import fr.themode.minestom.net.packet.client.play.ClientPlayerPositionAndLookPacket; import fr.themode.minestom.net.packet.client.play.ClientPlayerPositionPacket; +import fr.themode.minestom.utils.ChunkUtils; public class PlayerPositionListener { @@ -42,7 +43,7 @@ public class PlayerPositionListener { private static void processMovement(Player player, float x, float y, float z, Runnable runnable) { //System.out.println("MOVEMENT PACKET " + Math.round(x) + ":" + Math.round(y) + ":" + Math.round(z)); - boolean chunkTest = player.isChunkUnloaded(x, z); + boolean chunkTest = ChunkUtils.isChunkUnloaded(player.getInstance(), x, z); if (chunkTest) { player.teleport(player.getPosition()); return; diff --git a/src/main/java/fr/themode/minestom/utils/BlockPosition.java b/src/main/java/fr/themode/minestom/utils/BlockPosition.java index 4e1082a74..da2e61244 100644 --- a/src/main/java/fr/themode/minestom/utils/BlockPosition.java +++ b/src/main/java/fr/themode/minestom/utils/BlockPosition.java @@ -10,10 +10,18 @@ public class BlockPosition { this.z = z; } - public void add(int x, int y, int z) { + public BlockPosition add(int x, int y, int z) { this.x += x; this.y += y; this.z += z; + return this; + } + + public BlockPosition subtract(int x, int y, int z) { + this.x -= x; + this.y -= y; + this.z -= z; + return this; } public int getX() { diff --git a/src/main/java/fr/themode/minestom/utils/ChunkUtils.java b/src/main/java/fr/themode/minestom/utils/ChunkUtils.java index 2e2b33b21..1f7120870 100644 --- a/src/main/java/fr/themode/minestom/utils/ChunkUtils.java +++ b/src/main/java/fr/themode/minestom/utils/ChunkUtils.java @@ -1,7 +1,13 @@ package fr.themode.minestom.utils; +import fr.themode.minestom.instance.Instance; + public class ChunkUtils { + public static boolean isChunkUnloaded(Instance instance, float x, float z) { + return instance.getChunk((int) Math.floor(x / 16), (int) Math.floor(z / 16)) == null; + } + public static long getChunkIndex(int chunkX, int chunkZ) { return (((long) chunkX) << 32) | (chunkZ & 0xffffffffL); } diff --git a/src/main/java/fr/themode/minestom/utils/EntityUtils.java b/src/main/java/fr/themode/minestom/utils/EntityUtils.java index 2355bf865..a0e98e9fd 100644 --- a/src/main/java/fr/themode/minestom/utils/EntityUtils.java +++ b/src/main/java/fr/themode/minestom/utils/EntityUtils.java @@ -3,6 +3,7 @@ package fr.themode.minestom.utils; import fr.themode.minestom.Main; import fr.themode.minestom.entity.Entity; import fr.themode.minestom.instance.Chunk; +import fr.themode.minestom.instance.Instance; public class EntityUtils { @@ -26,4 +27,13 @@ public class EntityUtils { return false; } + public static boolean isOnGround(Entity entity) { + Instance instance = entity.getInstance(); + if (instance == null) + return false; + Position position = entity.getPosition(); + short blockId = instance.getBlockId(position.toBlockPosition().subtract(0, 1, 0)); + return blockId != 0; + } + } diff --git a/src/main/java/fr/themode/minestom/utils/Position.java b/src/main/java/fr/themode/minestom/utils/Position.java index 1e16cb5f9..34f2ec087 100644 --- a/src/main/java/fr/themode/minestom/utils/Position.java +++ b/src/main/java/fr/themode/minestom/utils/Position.java @@ -28,6 +28,13 @@ public class Position { return this; } + public Position subtract(float x, float y, float z) { + this.x -= x; + this.y -= y; + this.z -= z; + return this; + } + public float getDistance(Position position) { return (float) Math.sqrt(MathUtils.square(position.getX() - getX()) + MathUtils.square(position.getY() - getY()) + MathUtils.square(position.getZ() - getZ())); } @@ -133,7 +140,7 @@ public class Position { } public BlockPosition toBlockPosition() { - return new BlockPosition((int) getX(), (int) getY(), (int) getZ()); + return new BlockPosition((int) Math.ceil(getX()), (int) Math.ceil(getY()), (int) Math.ceil(getZ())); } @Override