Added gravity

This commit is contained in:
TheMode 2019-08-27 20:49:11 +02:00
parent 0a732034c2
commit 8b95e3881d
17 changed files with 264 additions and 52 deletions

View File

@ -36,7 +36,6 @@ public abstract class Entity implements Viewable, DataContainer {
protected Instance instance; protected Instance instance;
protected Position position; protected Position position;
protected boolean onGround;
protected float lastX, lastY, lastZ; protected float lastX, lastY, lastZ;
protected float lastYaw, lastPitch; protected float lastYaw, lastPitch;
private int id; private int id;
@ -45,6 +44,9 @@ public abstract class Entity implements Viewable, DataContainer {
// Velocity // Velocity
// TODO gravity implementation for entity other than players // TODO gravity implementation for entity other than players
protected Vector velocity = new Vector(); // Movement in block per second protected Vector velocity = new Vector(); // Movement in block per second
protected float gravityDragPerTick;
private int gravityTickCounter;
private Set<Player> viewers = new CopyOnWriteArraySet<>(); private Set<Player> viewers = new CopyOnWriteArraySet<>();
private Data data; private Data data;
private Set<Entity> passengers = new CopyOnWriteArraySet<>(); private Set<Entity> passengers = new CopyOnWriteArraySet<>();
@ -104,6 +106,8 @@ public abstract class Entity implements Viewable, DataContainer {
// Called when entity a new instance is set // Called when entity a new instance is set
public abstract void spawn(); public abstract void spawn();
public abstract boolean isOnGround();
public void teleport(Position position, Runnable callback) { public void teleport(Position position, Runnable callback) {
if (instance == null) if (instance == null)
throw new IllegalStateException("You need to use Entity#setInstance before teleporting an entity!"); 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 entityTeleportPacket = new EntityTeleportPacket();
entityTeleportPacket.entityId = getEntityId(); entityTeleportPacket.entityId = getEntityId();
entityTeleportPacket.position = position; entityTeleportPacket.position = position;
entityTeleportPacket.onGround = onGround; entityTeleportPacket.onGround = isOnGround();
sendPacketToViewers(entityTeleportPacket); sendPacketToViewers(entityTeleportPacket);
}; };
@ -125,7 +129,7 @@ public abstract class Entity implements Viewable, DataContainer {
callback.run(); callback.run();
}); });
} else { } else {
if (isChunkUnloaded(position.getX(), position.getZ())) if (ChunkUtils.isChunkUnloaded(instance, position.getX(), position.getZ()))
return; return;
runnable.run(); runnable.run();
if (callback != null) 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(); update();
// Scheduled synchronization // Scheduled synchronization
@ -295,6 +329,10 @@ public abstract class Entity implements Viewable, DataContainer {
this.velocityTime = 0; this.velocityTime = 0;
} }
public void setGravity(float gravityDragPerTick) {
this.gravityDragPerTick = gravityDragPerTick;
}
public float getDistance(Entity entity) { public float getDistance(Entity entity) {
return getPosition().getDistance(entity.getPosition()); return getPosition().getDistance(entity.getPosition());
} }
@ -360,18 +398,26 @@ public abstract class Entity implements Viewable, DataContainer {
sendMetadataIndex(0); sendMetadataIndex(0);
} }
public boolean isOnFire() {
return onFire;
}
public void setGlowing(boolean glowing) { public void setGlowing(boolean glowing) {
this.glowing = glowing; this.glowing = glowing;
sendMetadataIndex(0); sendMetadataIndex(0);
} }
public boolean isGlowing() {
return glowing;
}
public void setNoGravity(boolean noGravity) { public void setNoGravity(boolean noGravity) {
this.noGravity = noGravity; this.noGravity = noGravity;
sendMetadataIndex(5); sendMetadataIndex(5);
} }
public boolean isChunkUnloaded(float x, float z) { public boolean hasNoGravity() {
return getInstance().getChunk((int) Math.floor(x / 16), (int) Math.floor(z / 16)) == null; return noGravity;
} }
public void refreshPosition(float x, float y, float z) { 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) { public void refreshView(float yaw, float pitch) {
this.lastYaw = position.getYaw(); this.lastYaw = position.getYaw();
this.lastPitch = position.getPitch(); this.lastPitch = position.getPitch();
@ -554,7 +604,7 @@ public abstract class Entity implements Viewable, DataContainer {
EntityTeleportPacket entityTeleportPacket = new EntityTeleportPacket(); EntityTeleportPacket entityTeleportPacket = new EntityTeleportPacket();
entityTeleportPacket.entityId = getEntityId(); entityTeleportPacket.entityId = getEntityId();
entityTeleportPacket.position = getPosition(); entityTeleportPacket.position = getPosition();
entityTeleportPacket.onGround = onGround; entityTeleportPacket.onGround = isOnGround();
sendPacketToViewers(entityTeleportPacket); sendPacketToViewers(entityTeleportPacket);
} }

View File

@ -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.EntityRelativeMovePacket;
import fr.themode.minestom.net.packet.server.play.SpawnMobPacket; import fr.themode.minestom.net.packet.server.play.SpawnMobPacket;
import fr.themode.minestom.net.player.PlayerConnection; 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; import fr.themode.minestom.utils.Position;
// TODO viewers synchronization each X ticks? // TODO viewers synchronization each X ticks?
public abstract class EntityCreature extends LivingEntity { public abstract class EntityCreature extends LivingEntity {
public EntityCreature(int entityType) { public EntityCreature(EntityType entityType) {
super(entityType); super(entityType.getId());
} }
@Override @Override
@ -26,7 +28,7 @@ public abstract class EntityCreature extends LivingEntity {
float newY = position.getY() + y; float newY = position.getY() + y;
float newZ = position.getZ() + z; float newZ = position.getZ() + z;
if (isChunkUnloaded(newX, newZ)) if (ChunkUtils.isChunkUnloaded(getInstance(), newX, newZ))
return; return;
EntityRelativeMovePacket entityRelativeMovePacket = new EntityRelativeMovePacket(); EntityRelativeMovePacket entityRelativeMovePacket = new EntityRelativeMovePacket();
@ -67,4 +69,8 @@ public abstract class EntityCreature extends LivingEntity {
playerConnection.sendPacket(getMetadataPacket()); playerConnection.sendPacket(getMetadataPacket());
} }
@Override
public boolean isOnGround() {
return EntityUtils.isOnGround(this);
}
} }

View File

@ -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;
}
}

View File

@ -12,6 +12,7 @@ public class ItemEntity extends ObjectEntity {
public ItemEntity(ItemStack itemStack) { public ItemEntity(ItemStack itemStack) {
super(34); super(34);
this.itemStack = itemStack; this.itemStack = itemStack;
setGravity(0.02f);
} }
@Override @Override

View File

@ -5,6 +5,7 @@ import fr.themode.minestom.entity.property.Attribute;
import fr.themode.minestom.event.PickupItemEvent; import fr.themode.minestom.event.PickupItemEvent;
import fr.themode.minestom.instance.Chunk; import fr.themode.minestom.instance.Chunk;
import fr.themode.minestom.item.ItemStack; 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.CollectItemPacket;
import fr.themode.minestom.net.packet.server.play.EntityPropertiesPacket; import fr.themode.minestom.net.packet.server.play.EntityPropertiesPacket;
@ -26,6 +27,7 @@ public abstract class LivingEntity extends Entity {
public LivingEntity(int entityType) { public LivingEntity(int entityType) {
super(entityType); super(entityType);
setupAttributes(); setupAttributes();
setGravity(0.02f);
} }
public abstract void kill(); public abstract void kill();
@ -79,11 +81,21 @@ public abstract class LivingEntity extends Entity {
return buffer; 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() { public float getHealth() {
return health; return health;
} }
public void setHealth(float health) { public void setHealth(float health) {
health = Math.min(health, getMaxHealth());
this.health = health; this.health = health;
if (this.health <= 0) { if (this.health <= 0) {
kill(); kill();

View File

@ -2,6 +2,7 @@ package fr.themode.minestom.entity;
import fr.themode.minestom.net.packet.server.play.SpawnObjectPacket; import fr.themode.minestom.net.packet.server.play.SpawnObjectPacket;
import fr.themode.minestom.net.player.PlayerConnection; import fr.themode.minestom.net.player.PlayerConnection;
import fr.themode.minestom.utils.EntityUtils;
// TODO viewers synchronization each X ticks? // TODO viewers synchronization each X ticks?
public abstract class ObjectEntity extends Entity { public abstract class ObjectEntity extends Entity {
@ -31,4 +32,10 @@ public abstract class ObjectEntity extends Entity {
public void removeViewer(Player player) { public void removeViewer(Player player) {
super.removeViewer(player); super.removeViewer(player);
} }
@Override
public boolean isOnGround() {
return EntityUtils.isOnGround(this);
}
} }

View File

@ -4,6 +4,7 @@ import fr.themode.minestom.Main;
import fr.themode.minestom.bossbar.BossBar; import fr.themode.minestom.bossbar.BossBar;
import fr.themode.minestom.chat.Chat; import fr.themode.minestom.chat.Chat;
import fr.themode.minestom.data.Data; import fr.themode.minestom.data.Data;
import fr.themode.minestom.entity.demo.ChickenCreature;
import fr.themode.minestom.entity.property.Attribute; import fr.themode.minestom.entity.property.Attribute;
import fr.themode.minestom.event.*; import fr.themode.minestom.event.*;
import fr.themode.minestom.instance.Chunk; 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.instance.demo.ChunkGeneratorDemo;
import fr.themode.minestom.inventory.Inventory; import fr.themode.minestom.inventory.Inventory;
import fr.themode.minestom.inventory.PlayerInventory; 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.client.ClientPlayPacket;
import fr.themode.minestom.net.packet.server.ServerPacket; import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.net.packet.server.play.*; import fr.themode.minestom.net.packet.server.play.*;
@ -40,6 +42,8 @@ public class Player extends LivingEntity {
private GameMode gameMode; private GameMode gameMode;
private LevelType levelType; private LevelType levelType;
protected boolean onGround;
private static InstanceContainer instanceContainer; private static InstanceContainer instanceContainer;
static { static {
@ -82,7 +86,7 @@ public class Player extends LivingEntity {
protected boolean spawned; protected boolean spawned;
public Player(UUID uuid, String username, PlayerConnection playerConnection) { public Player(UUID uuid, String username, PlayerConnection playerConnection) {
super(93); super(100);
this.uuid = uuid; this.uuid = uuid;
this.username = username; this.username = username;
this.playerConnection = playerConnection; this.playerConnection = playerConnection;
@ -98,8 +102,11 @@ public class Player extends LivingEntity {
setEventCallback(AttackEvent.class, event -> { setEventCallback(AttackEvent.class, event -> {
Entity entity = event.getTarget(); Entity entity = event.getTarget();
if (entity instanceof EntityCreature) { if (entity instanceof EntityCreature) {
((EntityCreature) entity).kill(); ((EntityCreature) entity).damage(-1);
sendMessage("You killed an entity!"); Vector velocity = getPosition().clone().getDirection().multiply(6);
velocity.setY(4f);
entity.setVelocity(velocity, 150);
sendMessage("You attacked an entity!");
} else if (entity instanceof Player) { } else if (entity instanceof Player) {
Player player = (Player) entity; Player player = (Player) entity;
Vector velocity = getPosition().clone().getDirection().multiply(6); Vector velocity = getPosition().clone().getDirection().multiply(6);
@ -145,18 +152,18 @@ public class Player extends LivingEntity {
setGameMode(GameMode.SURVIVAL); setGameMode(GameMode.SURVIVAL);
teleport(new Position(0, 66, 0)); teleport(new Position(0, 66, 0));
/*ChickenCreature chickenCreature = new ChickenCreature(); ChickenCreature chickenCreature = new ChickenCreature();
chickenCreature.refreshPosition(2, 65, 2); chickenCreature.refreshPosition(2, 65, 2);
chickenCreature.setInstance(getInstance()); chickenCreature.setInstance(getInstance());
for (int ix = 0; ix < 4; ix++) for (int ix = 0; ix < 4; ix++)
for (int iz = 0; iz < 4; iz++) { for (int iz = 0; iz < 4; iz++) {
ItemEntity itemEntity = new ItemEntity(new ItemStack(1, (byte) 32)); ItemEntity itemEntity = new ItemEntity(new ItemStack(1, (byte) 32));
itemEntity.refreshPosition(ix, 66, iz); itemEntity.refreshPosition(ix, 68, iz);
itemEntity.setNoGravity(true); //itemEntity.setNoGravity(true);
itemEntity.setInstance(getInstance()); itemEntity.setInstance(getInstance());
//itemEntity.remove(); //itemEntity.remove();
}*/ }
TeamsPacket teamsPacket = new TeamsPacket(); TeamsPacket teamsPacket = new TeamsPacket();
teamsPacket.teamName = "TEAMNAME" + new Random().nextInt(100); teamsPacket.teamName = "TEAMNAME" + new Random().nextInt(100);
@ -270,6 +277,11 @@ public class Player extends LivingEntity {
} }
@Override
public boolean isOnGround() {
return onGround;
}
@Override @Override
public void remove() { public void remove() {
clearBossBars(); clearBossBars();
@ -345,15 +357,12 @@ public class Player extends LivingEntity {
playerConnection.sendPacket(chatMessagePacket); playerConnection.sendPacket(chatMessagePacket);
} }
public void damage(float amount) { @Override
public void damage(float value) {
if (getGameMode() == GameMode.CREATIVE) if (getGameMode() == GameMode.CREATIVE)
return; return;
AnimationPacket animationPacket = new AnimationPacket(); super.damage(value);
animationPacket.entityId = getEntityId();
animationPacket.animation = AnimationPacket.Animation.TAKE_DAMAGE;
sendPacketToViewersAndSelf(animationPacket);
setHealth(getHealth() - amount);
} }
@Override @Override
@ -471,7 +480,7 @@ public class Player extends LivingEntity {
@Override @Override
public void teleport(Position position, Runnable callback) { public void teleport(Position position, Runnable callback) {
super.teleport(position, () -> { super.teleport(position, () -> {
if (!instance.hasEnabledAutoChunkLoad() && isChunkUnloaded(position.getX(), position.getZ())) if (!instance.hasEnabledAutoChunkLoad() && ChunkUtils.isChunkUnloaded(instance, position.getX(), position.getZ()))
return; return;
updatePlayerPosition(); updatePlayerPosition();
if (callback != null) if (callback != null)

View File

@ -1,12 +1,12 @@
package fr.themode.minestom.entity.demo; package fr.themode.minestom.entity.demo;
import fr.themode.minestom.entity.EntityCreature; import fr.themode.minestom.entity.EntityCreature;
import fr.themode.minestom.utils.Vector; import fr.themode.minestom.entity.EntityType;
public class ChickenCreature extends EntityCreature { public class ChickenCreature extends EntityCreature {
public ChickenCreature() { public ChickenCreature() {
super(8); super(EntityType.CHICKEN);
} }
@Override @Override
@ -43,11 +43,11 @@ public class ChickenCreature extends EntityCreature {
move(x * speed, 0, z * speed); move(x * speed, 0, z * speed);
} }
}*/ }*/
move(0, 0, speed); // move(0, 0, speed);
} }
@Override @Override
public void spawn() { public void spawn() {
setVelocity(new Vector(0, 1, 0), 3000); // setVelocity(new Vector(0, 1, 0), 3000);
} }
} }

View File

@ -65,8 +65,11 @@ public class BlockBatch implements BlockModifier {
} }
chunk.refreshDataPacket(); chunk.refreshDataPacket();
instance.sendChunkUpdate(chunk); instance.sendChunkUpdate(chunk);
if (isLast && callback != null) if (isLast) {
callback.run(); // data.clear();
if (callback != null)
callback.run();
}
} }
}); });
} }

View File

@ -54,6 +54,7 @@ public class ChunkBatch implements BlockModifier {
data.apply(chunk); data.apply(chunk);
} }
// dataList.clear();
chunk.refreshDataPacket(); chunk.refreshDataPacket();
instance.sendChunkUpdate(chunk); instance.sendChunkUpdate(chunk);
if (callback != null) if (callback != null)

View File

@ -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 lastInstance.removeEntity(entity); // If entity is in another instance, remove it from there and add it to this
} }
if (entity instanceof Player) { long[] visibleChunksEntity = ChunkUtils.getChunksInRange(entity.getPosition(), Main.ENTITY_VIEW_DISTANCE);
Player player = (Player) entity; boolean isPlayer = entity instanceof Player;
sendChunks(player);
// Send player all visible entities if (isPlayer) {
long[] visibleChunksEntity = ChunkUtils.getChunksInRange(entity.getPosition(), Main.ENTITY_VIEW_DISTANCE); sendChunks((Player) entity);
for (long chunkIndex : visibleChunksEntity) { }
getEntitiesInChunk(chunkIndex).forEach(ent -> {
ent.addViewer(player); // Send all visible entities
if (ent instanceof Player) { for (long chunkIndex : visibleChunksEntity) {
player.addViewer((Player) ent); getEntitiesInChunk(chunkIndex).forEach(ent -> {
} if (isPlayer)
}); ent.addViewer((Player) entity);
} if (ent instanceof Player) {
entity.addViewer((Player) ent);
}
});
} }
Chunk chunk = getChunkAt(entity.getPosition()); Chunk chunk = getChunkAt(entity.getPosition());

View File

@ -207,15 +207,19 @@ public class InstanceContainer extends Instance {
@Override @Override
public void sendChunk(Player player, Chunk chunk) { 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 -> { PacketWriter.writeCallbackPacket(chunk.getFreshFullDataPacket(), buffer -> {
buffer.getData().retain(1).markReaderIndex(); chunk.setFullDataPacket(buffer);
player.getPlayerConnection().sendUnencodedPacket(buffer); sendChunkUpdate(player, chunk);
buffer.getData().resetReaderIndex();
}); });
// TODO use cached chunk data
/*chunkData.getData().retain(1).markReaderIndex();
player.getPlayerConnection().sendUnencodedPacket(chunkData);
chunkData.getData().resetReaderIndex();*/
} }
@Override @Override

View File

@ -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.ClientPlayerPacket;
import fr.themode.minestom.net.packet.client.play.ClientPlayerPositionAndLookPacket; import fr.themode.minestom.net.packet.client.play.ClientPlayerPositionAndLookPacket;
import fr.themode.minestom.net.packet.client.play.ClientPlayerPositionPacket; import fr.themode.minestom.net.packet.client.play.ClientPlayerPositionPacket;
import fr.themode.minestom.utils.ChunkUtils;
public class PlayerPositionListener { public class PlayerPositionListener {
@ -42,7 +43,7 @@ public class PlayerPositionListener {
private static void processMovement(Player player, float x, float y, float z, Runnable runnable) { 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)); //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) { if (chunkTest) {
player.teleport(player.getPosition()); player.teleport(player.getPosition());
return; return;

View File

@ -10,10 +10,18 @@ public class BlockPosition {
this.z = z; 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.x += x;
this.y += y; this.y += y;
this.z += z; 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() { public int getX() {

View File

@ -1,7 +1,13 @@
package fr.themode.minestom.utils; package fr.themode.minestom.utils;
import fr.themode.minestom.instance.Instance;
public class ChunkUtils { 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) { public static long getChunkIndex(int chunkX, int chunkZ) {
return (((long) chunkX) << 32) | (chunkZ & 0xffffffffL); return (((long) chunkX) << 32) | (chunkZ & 0xffffffffL);
} }

View File

@ -3,6 +3,7 @@ package fr.themode.minestom.utils;
import fr.themode.minestom.Main; import fr.themode.minestom.Main;
import fr.themode.minestom.entity.Entity; import fr.themode.minestom.entity.Entity;
import fr.themode.minestom.instance.Chunk; import fr.themode.minestom.instance.Chunk;
import fr.themode.minestom.instance.Instance;
public class EntityUtils { public class EntityUtils {
@ -26,4 +27,13 @@ public class EntityUtils {
return false; 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;
}
} }

View File

@ -28,6 +28,13 @@ public class Position {
return this; 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) { public float getDistance(Position position) {
return (float) Math.sqrt(MathUtils.square(position.getX() - getX()) + MathUtils.square(position.getY() - getY()) + MathUtils.square(position.getZ() - getZ())); 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() { 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 @Override