Cleaned and optimized code

This commit is contained in:
TheMode 2019-08-21 16:50:52 +02:00
parent 9d8e4e7ea2
commit 8ddfdbb42a
56 changed files with 869 additions and 325 deletions

View File

@ -34,7 +34,7 @@ public class Main {
private static BlockManager blockManager;
private static EntityManager entityManager;
public static void main(String[] args) {
public static void main(String[] args) throws InterruptedException {
connectionManager = new ConnectionManager();
packetProcessor = new PacketProcessor();
packetListenerManager = new PacketListenerManager();
@ -95,28 +95,28 @@ public class Main {
System.out.println("Server started");
long tickDistance = TICK_MS * 1000000;
long nextTick = System.nanoTime();
long currentTime;
while (true) {
currentTime = System.nanoTime();
if (currentTime >= nextTick) {
// Tick
// Keep Alive Handling
server.getConnections().stream().filter(connection -> packetProcessor.hasPlayerConnection(connection) && connectionManager.getPlayer(packetProcessor.getPlayerConnection(connection)) != null && System.currentTimeMillis() - connectionManager.getPlayer(packetProcessor.getPlayerConnection(connection)).getLastKeepAlive() > 20000).map(connection -> connectionManager.getPlayer(packetProcessor.getPlayerConnection(connection))).forEach(player -> {
long id = System.currentTimeMillis();
player.refreshKeepAlive(id);
KeepAlivePacket keepAlivePacket = new KeepAlivePacket(id);
player.getPlayerConnection().sendPacket(keepAlivePacket);
});
// Keep Alive Handling
server.getConnections().stream().filter(connection -> packetProcessor.hasPlayerConnection(connection) && connectionManager.getPlayer(packetProcessor.getPlayerConnection(connection)) != null && System.currentTimeMillis() - connectionManager.getPlayer(packetProcessor.getPlayerConnection(connection)).getLastKeepAlive() > 20000).map(connection -> connectionManager.getPlayer(packetProcessor.getPlayerConnection(connection))).forEach(player -> {
long id = System.currentTimeMillis();
player.refreshKeepAlive(id);
KeepAlivePacket keepAlivePacket = new KeepAlivePacket(id);
player.getPlayerConnection().sendPacket(keepAlivePacket);
});
// Entities update
entityManager.update();
// Entities update
entityManager.update();
// Set next tick update time
currentTime = System.nanoTime();
nextTick = currentTime + tickDistance - (currentTime - nextTick);
}
// Sleep until next tick
long sleepTime = (tickDistance - (System.nanoTime() - currentTime)) / 1000000;
//String perfMessage = "Online: " + getConnectionManager().getOnlinePlayers().size() + " Tick time: " + (TICK_MS - sleepTime) + " ms";
//getConnectionManager().getOnlinePlayers().forEach(player -> player.sendMessage(perfMessage));
Thread.sleep(sleepTime);
}
}

View File

@ -1,6 +1,7 @@
package fr.themode.minestom;
import fr.themode.minestom.entity.Player;
import fr.themode.minestom.net.packet.server.ServerPacket;
import java.util.Set;
@ -16,4 +17,15 @@ public interface Viewable {
return getViewers().contains(player);
}
default void sendPacketToViewers(ServerPacket packet) {
getViewers().forEach(player -> player.getPlayerConnection().sendPacket(packet));
}
default void sendPacketsToViewers(ServerPacket... packets) {
getViewers().forEach(player -> {
for (ServerPacket packet : packets)
player.getPlayerConnection().sendPacket(packet);
});
}
}

View File

@ -85,7 +85,7 @@ public class BossBar implements Viewable {
BossBarPacket bossBarPacket = new BossBarPacket();
bossBarPacket.uuid = uuid;
bossBarPacket.action = BossBarPacket.Action.REMOVE;
sendPacket(bossBarPacket);
sendPacketToViewers(bossBarPacket);
getViewers().forEach(player -> player.refreshRemoveBossbar(this));
}
@ -113,7 +113,7 @@ public class BossBar implements Viewable {
bossBarPacket.uuid = uuid;
bossBarPacket.action = BossBarPacket.Action.UPDATE_TITLE;
bossBarPacket.title = title;
sendPacket(bossBarPacket);
sendPacketToViewers(bossBarPacket);
}
private void updateProgress() {
@ -121,7 +121,7 @@ public class BossBar implements Viewable {
bossBarPacket.uuid = uuid;
bossBarPacket.action = BossBarPacket.Action.UPDATE_HEALTH;
bossBarPacket.health = progress;
sendPacket(bossBarPacket);
sendPacketToViewers(bossBarPacket);
}
private void updateStyle() {
@ -129,10 +129,6 @@ public class BossBar implements Viewable {
bossBarPacket.uuid = uuid;
bossBarPacket.action = BossBarPacket.Action.UPDATE_STYLE;
bossBarPacket.color = color;
sendPacket(bossBarPacket);
}
private void sendPacket(BossBarPacket bossBarPacket) {
getViewers().forEach(player -> player.getPlayerConnection().sendPacket(bossBarPacket));
sendPacketToViewers(bossBarPacket);
}
}

View File

@ -8,22 +8,18 @@ import fr.themode.minestom.event.CancellableEvent;
import fr.themode.minestom.event.Event;
import fr.themode.minestom.instance.Chunk;
import fr.themode.minestom.instance.Instance;
import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.net.packet.server.play.DestroyEntitiesPacket;
import fr.themode.minestom.net.packet.server.play.EntityMetaDataPacket;
import fr.themode.minestom.net.packet.server.play.SetPassengersPacket;
import fr.themode.minestom.net.packet.server.play.*;
import fr.themode.minestom.utils.Position;
import fr.themode.minestom.utils.Utils;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;
public abstract class Entity implements Viewable {
private static Map<Integer, Entity> entityById = new HashMap<>();
private static AtomicInteger lastEntityId = new AtomicInteger();
// Metadata
@ -37,9 +33,8 @@ public abstract class Entity implements Viewable {
protected static final byte METADATA_BOOLEAN = 7;
protected Instance instance;
protected Position position;
protected double lastX, lastY, lastZ;
protected double x, y, z;
protected float yaw, pitch;
protected float lastYaw, lastPitch;
private int id;
@ -48,12 +43,16 @@ public abstract class Entity implements Viewable {
private Set<Player> viewers = new CopyOnWriteArraySet<>();
private Set<Entity> passengers = new CopyOnWriteArraySet<>();
// Metadata
protected boolean onFire;
protected UUID uuid;
private boolean isActive; // False if entity has only been instanced without being added somewhere
protected boolean crouched;
private boolean shouldRemove;
private long scheduledRemoveTime;
private int entityType;
private long lastUpdate;
// Metadata
protected boolean onFire;
protected boolean crouched;
protected boolean UNUSED_METADATA;
protected boolean sprinting;
protected boolean swimming;
@ -66,15 +65,23 @@ public abstract class Entity implements Viewable {
protected boolean silent;
protected boolean noGravity;
protected Pose pose = Pose.STANDING;
private int entityType;
private long lastUpdate;
public Entity(int entityType) {
this.id = generateId();
this.entityType = entityType;
this.uuid = UUID.randomUUID();
this.position = new Position();
synchronized (entityById) {
entityById.put(id, this);
}
}
public static Entity getEntity(int id) {
synchronized (entityById) {
return entityById.get(id);
}
}
private static int generateId() {
return lastEntityId.incrementAndGet();
@ -82,6 +89,17 @@ public abstract class Entity implements Viewable {
public abstract void update();
public void teleport(Position position) {
if (isChunkUnloaded(position.getX(), position.getZ()))
return;
EntityTeleportPacket entityTeleportPacket = new EntityTeleportPacket();
entityTeleportPacket.entityId = getEntityId();
entityTeleportPacket.position = position;
entityTeleportPacket.onGround = true;
sendPacketToViewers(entityTeleportPacket);
}
@Override
public void addViewer(Player player) {
this.viewers.add(player);
@ -105,6 +123,13 @@ public abstract class Entity implements Viewable {
}
public void tick() {
if (scheduledRemoveTime != 0) { // Any entity with scheduled remove does not update
boolean finished = System.currentTimeMillis() >= scheduledRemoveTime;
if (finished) {
remove();
}
return;
}
if (shouldUpdate()) {
update();
this.lastUpdate = System.currentTimeMillis();
@ -166,16 +191,17 @@ public abstract class Entity implements Viewable {
}
public float getDistance(Entity entity) {
return (float) Math.sqrt(Math.pow(entity.getX() - getX(), 2) + Math.pow(entity.getY() - getY(), 2) + Math.pow(entity.getZ() - getZ(), 2));
return getPosition().getDistance(entity.getPosition());
}
public void addPassenger(Entity entity) {
// TODO if entity already has a vehicle, leave it before?
this.passengers.add(entity);
entity.vehicle = this;
if (instance != null) {
SetPassengersPacket passengersPacket = new SetPassengersPacket();
passengersPacket.vehicleEntityId = getEntityId();
passengersPacket.passengersId = new int[]{entity.getEntityId()};
passengersPacket.passengersId = new int[]{entity.getEntityId()}; // TODO all passengers not only the new
sendPacketToViewers(passengersPacket);
}
}
@ -188,18 +214,29 @@ public abstract class Entity implements Viewable {
return Collections.unmodifiableSet(passengers);
}
public void triggerStatus(byte status) {
EntityStatusPacket statusPacket = new EntityStatusPacket();
statusPacket.entityId = getEntityId();
statusPacket.status = status;
sendPacketToViewers(statusPacket);
}
public void setOnFire(boolean fire) {
this.onFire = fire;
sendMetadata(0);
}
public void refreshPosition(double x, double y, double z) {
this.lastX = this.x;
this.lastY = this.y;
this.lastZ = this.z;
this.x = x;
this.y = y;
this.z = z;
public boolean isChunkUnloaded(float x, float z) {
return getInstance().getChunk((int) Math.floor(x / 16), (int) Math.floor(z / 16)) == null;
}
public void refreshPosition(float x, float y, float z) {
this.lastX = position.getX();
this.lastY = position.getY();
this.lastZ = position.getZ();
position.setX(x);
position.setY(y);
position.setZ(z);
Instance instance = getInstance();
if (instance != null) {
@ -217,10 +254,10 @@ public abstract class Entity implements Viewable {
}
public void refreshView(float yaw, float pitch) {
this.lastYaw = this.yaw;
this.lastPitch = this.pitch;
this.yaw = yaw;
this.pitch = pitch;
this.lastYaw = position.getYaw();
this.lastPitch = position.getPitch();
position.setYaw(yaw);
position.setPitch(pitch);
}
public void refreshSneaking(boolean sneaking) {
@ -233,39 +270,23 @@ public abstract class Entity implements Viewable {
sendMetadata(0);
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getZ() {
return z;
}
public float getYaw() {
return yaw;
}
public float getPitch() {
return pitch;
public Position getPosition() {
return position;
}
public void remove() {
this.shouldRemove = true;
synchronized (entityById) {
entityById.remove(id);
}
}
public void sendPacketToViewers(ServerPacket packet) {
getViewers().forEach(player -> player.getPlayerConnection().sendPacket(packet));
}
public void sendPacketsToViewers(ServerPacket... packets) {
getViewers().forEach(player -> {
for (ServerPacket packet : packets)
player.getPlayerConnection().sendPacket(packet);
});
public void scheduleRemove(long delay) {
if (delay == 0) { // Cancel the scheduled remove
this.scheduledRemoveTime = 0;
return;
}
this.scheduledRemoveTime = System.currentTimeMillis() + delay;
}
public Buffer getMetadataBuffer() {

View File

@ -1,7 +1,11 @@
package fr.themode.minestom.entity;
import fr.themode.minestom.net.packet.server.play.*;
import fr.themode.minestom.net.packet.server.play.EntityMetaDataPacket;
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.Position;
public abstract class EntityCreature extends LivingEntity {
@ -9,38 +13,29 @@ public abstract class EntityCreature extends LivingEntity {
super(entityType);
}
public void move(double x, double y, double z) {
double newX = getX() + x;
double newY = getY() + y;
double newZ = getZ() + z;
public void move(float x, float y, float z) {
Position position = getPosition();
float newX = position.getX() + x;
float newY = position.getY() + y;
float newZ = position.getZ() + z;
if (chunkTest(newX, newZ))
if (isChunkUnloaded(newX, newZ))
return;
EntityRelativeMovePacket entityRelativeMovePacket = new EntityRelativeMovePacket();
entityRelativeMovePacket.entityId = getEntityId();
entityRelativeMovePacket.deltaX = (short) ((newX * 32 - getX() * 32) * 128);
entityRelativeMovePacket.deltaY = (short) ((newY * 32 - getY() * 32) * 128);
entityRelativeMovePacket.deltaZ = (short) ((newZ * 32 - getZ() * 32) * 128);
entityRelativeMovePacket.deltaX = (short) ((newX * 32 - position.getX() * 32) * 128);
entityRelativeMovePacket.deltaY = (short) ((newY * 32 - position.getY() * 32) * 128);
entityRelativeMovePacket.deltaZ = (short) ((newZ * 32 - position.getZ() * 32) * 128);
entityRelativeMovePacket.onGround = true;
sendPacketToViewers(entityRelativeMovePacket);
refreshPosition(newX, newY, newZ);
}
public void teleport(double x, double y, double z) {
if (chunkTest(x, z))
return;
EntityTeleportPacket entityTeleportPacket = new EntityTeleportPacket();
entityTeleportPacket.entityId = getEntityId();
entityTeleportPacket.x = x;
entityTeleportPacket.y = y;
entityTeleportPacket.z = z;
entityTeleportPacket.yaw = getYaw();
entityTeleportPacket.pitch = getPitch();
entityTeleportPacket.onGround = true;
sendPacketToViewers(entityTeleportPacket);
public void kill() {
triggerStatus((byte) 3);
scheduleRemove(1000);
}
@Override
@ -54,11 +49,7 @@ public abstract class EntityCreature extends LivingEntity {
spawnMobPacket.entityId = getEntityId();
spawnMobPacket.entityUuid = getUuid();
spawnMobPacket.entityType = getEntityType();
spawnMobPacket.x = getX();
spawnMobPacket.y = getY();
spawnMobPacket.z = getZ();
spawnMobPacket.yaw = getYaw();
spawnMobPacket.pitch = getPitch();
spawnMobPacket.position = getPosition();
spawnMobPacket.headPitch = 0;
EntityMetaDataPacket entityMetaDataPacket = new EntityMetaDataPacket();
entityMetaDataPacket.entityId = getEntityId();

View File

@ -19,7 +19,7 @@ public class EntityManager {
public void update() {
for (Instance instance : instanceManager.getInstances()) {
testTick2(instance);
testTick2(instance); // TODO optimize update engine for when there are too many entities on one chunk
}
}

View File

@ -1,5 +1,6 @@
package fr.themode.minestom.entity;
// TODO attributes https://wiki.vg/Protocol#Entity_Properties
public abstract class LivingEntity extends Entity {
protected boolean onGround;
@ -8,8 +9,4 @@ public abstract class LivingEntity extends Entity {
super(entityType);
}
public boolean chunkTest(double x, double z) {
return getInstance().getChunk((int) Math.floor(x / 16), (int) Math.floor(z / 16)) == null;
}
}

View File

@ -28,11 +28,7 @@ public abstract class ObjectEntity extends Entity implements Viewable {
spawnObjectPacket.entityId = getEntityId();
spawnObjectPacket.uuid = getUuid();
spawnObjectPacket.type = getEntityType();
spawnObjectPacket.x = getX();
spawnObjectPacket.y = getY();
spawnObjectPacket.z = getZ();
spawnObjectPacket.yaw = getYaw();
spawnObjectPacket.pitch = getPitch();
spawnObjectPacket.position = getPosition();
spawnObjectPacket.data = getData();
EntityMetaDataPacket entityMetaDataPacket = new EntityMetaDataPacket();
entityMetaDataPacket.entityId = getEntityId();

View File

@ -2,6 +2,7 @@ package fr.themode.minestom.entity;
import fr.themode.minestom.bossbar.BossBar;
import fr.themode.minestom.chat.Chat;
import fr.themode.minestom.event.AttackEvent;
import fr.themode.minestom.event.PickupItemEvent;
import fr.themode.minestom.instance.Chunk;
import fr.themode.minestom.instance.CustomBlock;
@ -12,7 +13,10 @@ import fr.themode.minestom.net.packet.client.ClientPlayPacket;
import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.net.packet.server.play.*;
import fr.themode.minestom.net.player.PlayerConnection;
import fr.themode.minestom.utils.BlockPosition;
import fr.themode.minestom.utils.Position;
import fr.themode.minestom.world.Dimension;
import fr.themode.minestom.world.LevelType;
import java.util.Collections;
import java.util.LinkedList;
@ -28,13 +32,16 @@ public class Player extends LivingEntity {
private PlayerConnection playerConnection;
private LinkedList<ClientPlayPacket> packets = new LinkedList<>();
private Dimension dimension;
private GameMode gameMode;
private LevelType levelType;
private PlayerSettings settings;
private PlayerInventory inventory;
private short heldSlot;
private Inventory openInventory;
private CustomBlock targetCustomBlock;
private Position targetBlockPosition;
private BlockPosition targetBlockPosition;
private long targetBlockTime;
private Set<BossBar> bossBars = new CopyOnWriteArraySet<>();
@ -71,6 +78,19 @@ public class Player extends LivingEntity {
event.setCancelled(true);
sendMessage("CANCELLED");
});*/
setEventCallback(AttackEvent.class, event -> {
Entity entity = event.getTarget();
if (entity instanceof EntityCreature) {
((EntityCreature) entity).kill();
sendMessage("You killed an entity!");
}
/*UpdateHealthPacket updateHealthPacket = new UpdateHealthPacket();
updateHealthPacket.health = -1f;
updateHealthPacket.food = 5;
updateHealthPacket.foodSaturation = 0;
playerConnection.sendPacket(updateHealthPacket);*/
});
}
@Override
@ -97,7 +117,7 @@ public class Player extends LivingEntity {
// Item pickup
if (instance != null) {
Chunk chunk = instance.getChunkAt(getX(), getZ()); // TODO check surrounding chunks
Chunk chunk = instance.getChunkAt(getPosition()); // TODO check surrounding chunks
Set<ObjectEntity> objectEntities = chunk.getObjectEntities();
for (ObjectEntity objectEntity : objectEntities) {
if (objectEntity instanceof ItemEntity) {
@ -112,13 +132,16 @@ public class Player extends LivingEntity {
ItemStack item = itemEntity.getItemStack();
PickupItemEvent pickupItemEvent = new PickupItemEvent(item);
callCancellableEvent(PickupItemEvent.class, pickupItemEvent, () -> {
CollectItemPacket collectItemPacket = new CollectItemPacket();
collectItemPacket.collectedEntityId = itemEntity.getEntityId();
collectItemPacket.collectorEntityId = getEntityId();
collectItemPacket.pickupItemCount = item.getAmount();
instance.getPlayers().forEach(player -> player.getPlayerConnection().sendPacket(collectItemPacket));
getInventory().addItemStack(item);
objectEntity.remove();
boolean result = getInventory().addItemStack(item);
if (result) {
CollectItemPacket collectItemPacket = new CollectItemPacket();
collectItemPacket.collectedEntityId = itemEntity.getEntityId();
collectItemPacket.collectorEntityId = getEntityId();
collectItemPacket.pickupItemCount = item.getAmount();
playerConnection.sendPacket(collectItemPacket);
sendPacketToViewers(collectItemPacket);
objectEntity.remove();
}
});
}
}
@ -128,55 +151,56 @@ public class Player extends LivingEntity {
// Multiplayer sync
boolean positionChanged = x != lastX || z != lastZ || y != lastY;
boolean viewChanged = yaw != lastYaw || pitch != lastPitch;
Position position = getPosition();
boolean positionChanged = position.getX() != lastX || position.getZ() != lastZ || position.getY() != lastY;
boolean viewChanged = position.getYaw() != lastYaw || position.getPitch() != lastPitch;
ServerPacket updatePacket = null;
ServerPacket optionalUpdatePacket = null;
if (positionChanged && viewChanged) {
EntityLookAndRelativeMovePacket entityLookAndRelativeMovePacket = new EntityLookAndRelativeMovePacket();
entityLookAndRelativeMovePacket.entityId = getEntityId();
entityLookAndRelativeMovePacket.deltaX = (short) ((x * 32 - lastX * 32) * 128);
entityLookAndRelativeMovePacket.deltaY = (short) ((y * 32 - lastY * 32) * 128);
entityLookAndRelativeMovePacket.deltaZ = (short) ((z * 32 - lastZ * 32) * 128);
entityLookAndRelativeMovePacket.yaw = yaw;
entityLookAndRelativeMovePacket.pitch = pitch;
entityLookAndRelativeMovePacket.deltaX = (short) ((position.getX() * 32 - lastX * 32) * 128);
entityLookAndRelativeMovePacket.deltaY = (short) ((position.getY() * 32 - lastY * 32) * 128);
entityLookAndRelativeMovePacket.deltaZ = (short) ((position.getZ() * 32 - lastZ * 32) * 128);
entityLookAndRelativeMovePacket.yaw = position.getYaw();
entityLookAndRelativeMovePacket.pitch = position.getPitch();
entityLookAndRelativeMovePacket.onGround = onGround;
EntityHeadLookPacket entityHeadLookPacket = new EntityHeadLookPacket();
entityHeadLookPacket.entityId = getEntityId();
entityHeadLookPacket.yaw = yaw;
entityHeadLookPacket.yaw = position.getYaw();
lastX = x;
lastY = y;
lastZ = z;
lastYaw = yaw;
lastPitch = pitch;
lastX = position.getX();
lastY = position.getY();
lastZ = position.getZ();
lastYaw = position.getYaw();
lastPitch = position.getPitch();
updatePacket = entityLookAndRelativeMovePacket;
optionalUpdatePacket = entityHeadLookPacket;
} else if (positionChanged) {
EntityRelativeMovePacket entityRelativeMovePacket = new EntityRelativeMovePacket();
entityRelativeMovePacket.entityId = getEntityId();
entityRelativeMovePacket.deltaX = (short) ((x * 32 - lastX * 32) * 128);
entityRelativeMovePacket.deltaY = (short) ((y * 32 - lastY * 32) * 128);
entityRelativeMovePacket.deltaZ = (short) ((z * 32 - lastZ * 32) * 128);
entityRelativeMovePacket.deltaX = (short) ((position.getX() * 32 - lastX * 32) * 128);
entityRelativeMovePacket.deltaY = (short) ((position.getY() * 32 - lastY * 32) * 128);
entityRelativeMovePacket.deltaZ = (short) ((position.getZ() * 32 - lastZ * 32) * 128);
entityRelativeMovePacket.onGround = onGround;
lastX = x;
lastY = y;
lastZ = z;
lastX = position.getX();
lastY = position.getY();
lastZ = position.getZ();
updatePacket = entityRelativeMovePacket;
} else if (viewChanged) {
EntityLookPacket entityLookPacket = new EntityLookPacket();
entityLookPacket.entityId = getEntityId();
entityLookPacket.yaw = yaw;
entityLookPacket.pitch = pitch;
entityLookPacket.yaw = position.getYaw();
entityLookPacket.pitch = position.getPitch();
entityLookPacket.onGround = onGround;
EntityHeadLookPacket entityHeadLookPacket = new EntityHeadLookPacket();
entityHeadLookPacket.entityId = getEntityId();
entityHeadLookPacket.yaw = yaw;
entityHeadLookPacket.yaw = position.getYaw();
lastYaw = yaw;
lastPitch = pitch;
lastYaw = position.getYaw();
lastPitch = position.getPitch();
updatePacket = entityLookPacket;
optionalUpdatePacket = entityHeadLookPacket;
}
@ -187,7 +211,7 @@ public class Player extends LivingEntity {
sendPacketToViewers(updatePacket);
}
}
playerConnection.sendPacket(new UpdateViewPositionPacket(Math.floorDiv((int) x, 16), Math.floorDiv((int) z, 16)));
playerConnection.sendPacket(new UpdateViewPositionPacket(instance.getChunkAt(getPosition())));
// Synchronization
long time = System.currentTimeMillis();
@ -196,9 +220,7 @@ public class Player extends LivingEntity {
for (Player viewer : getViewers()) {
EntityTeleportPacket teleportPacket = new EntityTeleportPacket();
teleportPacket.entityId = viewer.getEntityId();
teleportPacket.x = viewer.getX();
teleportPacket.y = viewer.getY();
teleportPacket.z = viewer.getZ();
teleportPacket.position = getPosition();
teleportPacket.onGround = viewer.onGround;
playerConnection.sendPacket(teleportPacket);
}
@ -213,11 +235,7 @@ public class Player extends LivingEntity {
SpawnPlayerPacket spawnPlayerPacket = new SpawnPlayerPacket();
spawnPlayerPacket.entityId = getEntityId();
spawnPlayerPacket.playerUuid = getUuid();
spawnPlayerPacket.x = x;
spawnPlayerPacket.y = y;
spawnPlayerPacket.z = z;
spawnPlayerPacket.yaw = yaw;
spawnPlayerPacket.pitch = pitch;
spawnPlayerPacket.position = getPosition();
PlayerInfoPacket pInfoPacket = new PlayerInfoPacket(PlayerInfoPacket.Action.ADD_PLAYER);
PlayerInfoPacket.AddPlayer addP = new PlayerInfoPacket.AddPlayer(getUuid(), getUsername(), GameMode.CREATIVE, 10);
@ -241,7 +259,7 @@ public class Player extends LivingEntity {
player.playerConnection.sendPacket(playerInfoPacket);
}
public void sendBlockBreakAnimation(Position blockPosition, byte destroyStage) {
public void sendBlockBreakAnimation(BlockPosition blockPosition, byte destroyStage) {
BlockBreakAnimationPacket breakAnimationPacket = new BlockBreakAnimationPacket();
breakAnimationPacket.entityId = getEntityId() + 1;
breakAnimationPacket.blockPosition = blockPosition;
@ -255,13 +273,12 @@ public class Player extends LivingEntity {
playerConnection.sendPacket(chatMessagePacket);
}
public void teleport(double x, double y, double z) {
@Override
public void teleport(Position position) {
refreshPosition(position.getX(), position.getY(), position.getZ());
refreshView(position.getYaw(), position.getPitch());
PlayerPositionAndLookPacket positionAndLookPacket = new PlayerPositionAndLookPacket();
positionAndLookPacket.x = x;
positionAndLookPacket.y = y;
positionAndLookPacket.z = z;
positionAndLookPacket.yaw = getYaw();
positionAndLookPacket.pitch = getPitch();
positionAndLookPacket.position = position;
positionAndLookPacket.flags = 0x00;
positionAndLookPacket.teleportId = 67;
getPlayerConnection().sendPacket(positionAndLookPacket);
@ -275,14 +292,34 @@ public class Player extends LivingEntity {
return playerConnection;
}
public PlayerSettings getSettings() {
return settings;
}
public PlayerInventory getInventory() {
return inventory;
}
public Dimension getDimension() {
return dimension;
}
public GameMode getGameMode() {
return gameMode;
}
public void setDimension(Dimension dimension) {
if (dimension == null)
throw new IllegalArgumentException("Dimension cannot be null!");
if (dimension.equals(getDimension()))
return;
RespawnPacket respawnPacket = new RespawnPacket();
respawnPacket.dimension = dimension;
respawnPacket.gameMode = gameMode;
respawnPacket.levelType = levelType;
playerConnection.sendPacket(respawnPacket);
}
public void kick(String message) {
DisconnectPacket disconnectPacket = new DisconnectPacket();
disconnectPacket.message = message;
@ -290,6 +327,10 @@ public class Player extends LivingEntity {
playerConnection.getConnection().close();
}
public LevelType getLevelType() {
return levelType;
}
public void setGameMode(GameMode gameMode) {
ChangeGameStatePacket changeGameStatePacket = new ChangeGameStatePacket();
changeGameStatePacket.reason = ChangeGameStatePacket.Reason.CHANGE_GAMEMODE;
@ -376,10 +417,18 @@ public class Player extends LivingEntity {
}
}
public void refreshDimension(Dimension dimension) {
this.dimension = dimension;
}
public void refreshGameMode(GameMode gameMode) {
this.gameMode = gameMode;
}
public void refreshLevelType(LevelType levelType) {
this.levelType = levelType;
}
public void refreshOnGround(boolean onGround) {
this.onGround = onGround;
}
@ -397,7 +446,7 @@ public class Player extends LivingEntity {
this.openInventory = openInventory;
}
public void refreshTargetBlock(CustomBlock targetCustomBlock, Position targetBlockPosition) {
public void refreshTargetBlock(CustomBlock targetCustomBlock, BlockPosition targetBlockPosition) {
this.targetCustomBlock = targetCustomBlock;
this.targetBlockPosition = targetBlockPosition;
this.targetBlockTime = targetBlockPosition == null ? 0 : System.currentTimeMillis();
@ -430,4 +479,59 @@ public class Player extends LivingEntity {
MAIN,
OFF
}
public enum MainHand {
LEFT,
RIGHT;
}
public enum ChatMode {
ENABLED,
COMMANDS_ONLY,
HIDDEN;
}
public class PlayerSettings {
private String locale;
private byte viewDistance;
private ChatMode chatMode;
private boolean chatColors;
private byte displayedSkinParts;
private MainHand mainHand;
public String getLocale() {
return locale;
}
public byte getViewDistance() {
return viewDistance;
}
public ChatMode getChatMode() {
return chatMode;
}
public boolean hasChatColors() {
return chatColors;
}
public byte getDisplayedSkinParts() {
return displayedSkinParts;
}
public MainHand getMainHand() {
return mainHand;
}
public void refresh(String locale, byte viewDistance, ChatMode chatMode, boolean chatColors, byte displayedSkinParts, MainHand mainHand) {
this.locale = locale;
this.viewDistance = viewDistance;
this.chatMode = chatMode;
this.chatColors = chatColors;
this.displayedSkinParts = displayedSkinParts;
this.mainHand = mainHand;
}
}
}

View File

@ -10,7 +10,7 @@ public class ChickenCreature extends EntityCreature {
@Override
public void update() {
float speed = 0.075f;
float speed = 0.05f;
/*if (hasPassenger()) {
Entity passenger = getPassengers().iterator().next();
@ -41,6 +41,7 @@ public class ChickenCreature extends EntityCreature {
move(x * speed, 0, z * speed);
}
}*/
move(0, 0, speed);
}
}

View File

@ -0,0 +1,16 @@
package fr.themode.minestom.event;
import fr.themode.minestom.entity.Entity;
public class AttackEvent extends Event {
private Entity target;
public AttackEvent(Entity target) {
this.target = target;
}
public Entity getTarget() {
return target;
}
}

View File

@ -1,16 +1,16 @@
package fr.themode.minestom.event;
import fr.themode.minestom.utils.Position;
import fr.themode.minestom.utils.BlockPosition;
public class BlockBreakEvent extends CancellableEvent {
private Position position;
private BlockPosition blockPosition;
public BlockBreakEvent(Position position) {
this.position = position;
public BlockBreakEvent(BlockPosition blockPosition) {
this.blockPosition = blockPosition;
}
public Position getPosition() {
return position;
public BlockPosition getBlockPosition() {
return blockPosition;
}
}

View File

@ -0,0 +1,16 @@
package fr.themode.minestom.event;
import fr.themode.minestom.entity.Entity;
public class InteractEvent extends Event {
private Entity target;
public InteractEvent(Entity target) {
this.target = target;
}
public Entity getTarget() {
return target;
}
}

View File

@ -0,0 +1,13 @@
package fr.themode.minestom.event;
public class PlayerMoveEvent extends CancellableEvent {
private float toX, toY, toZ;
public PlayerMoveEvent(float toX, float toY, float toZ) {
this.toX = toX;
this.toY = toY;
this.toZ = toZ;
}
}

View File

@ -0,0 +1,20 @@
package fr.themode.minestom.event;
import fr.themode.minestom.utils.Position;
public class PlayerRespawnEvent extends Event {
private Position respawnPosition;
public PlayerRespawnEvent(Position respawnPosition) {
this.respawnPosition = respawnPosition;
}
public Position getRespawnPosition() {
return respawnPosition;
}
public void setRespawnPosition(Position respawnPosition) {
this.respawnPosition = respawnPosition;
}
}

View File

@ -0,0 +1,23 @@
package fr.themode.minestom.event;
import fr.themode.minestom.entity.Player;
import fr.themode.minestom.item.ItemStack;
public class UseItemEvent extends Event {
private Player.Hand hand;
private ItemStack itemStack;
public UseItemEvent(Player.Hand hand, ItemStack itemStack) {
this.hand = hand;
this.itemStack = itemStack;
}
public Player.Hand getHand() {
return hand;
}
public ItemStack getItemStack() {
return itemStack;
}
}

View File

@ -17,8 +17,9 @@ public class Chunk {
protected Set<ObjectEntity> objectEntities = new CopyOnWriteArraySet<>();
protected Set<EntityCreature> creatures = new CopyOnWriteArraySet<>();
protected Set<Player> players = new CopyOnWriteArraySet<>();
private int chunkX, chunkZ;
private Biome biome;
private int chunkX, chunkZ;
private short[] blocksId = new short[CHUNK_SIZE];
private short[] customBlocks = new short[CHUNK_SIZE];

View File

@ -8,6 +8,7 @@ import fr.themode.minestom.event.BlockBreakEvent;
import fr.themode.minestom.net.packet.server.play.ChunkDataPacket;
import fr.themode.minestom.net.packet.server.play.DestroyEntitiesPacket;
import fr.themode.minestom.net.packet.server.play.ParticlePacket;
import fr.themode.minestom.utils.BlockPosition;
import fr.themode.minestom.utils.GroupedCollections;
import fr.themode.minestom.utils.Position;
@ -51,13 +52,13 @@ public class Instance implements BlockModifier {
}
}
public void breakBlock(Player player, Position position, short blockId) {
BlockBreakEvent blockBreakEvent = new BlockBreakEvent(position);
public void breakBlock(Player player, BlockPosition blockPosition, short blockId) {
BlockBreakEvent blockBreakEvent = new BlockBreakEvent(blockPosition);
player.callEvent(BlockBreakEvent.class, blockBreakEvent);
if (!blockBreakEvent.isCancelled()) {
int x = position.getX();
int y = position.getY();
int z = position.getZ();
int x = blockPosition.getX();
int y = blockPosition.getY();
int z = blockPosition.getZ();
setBlock(x, y, z, (short) 0);
ParticlePacket particlePacket = new ParticlePacket(); // TODO change by a proper particle API
particlePacket.particleId = 3; // Block particle
@ -74,12 +75,12 @@ public class Instance implements BlockModifier {
player.getPlayerConnection().sendPacket(particlePacket);
player.sendPacketToViewers(particlePacket);
} else {
sendChunkUpdate(player, getChunkAt(position));
sendChunkUpdate(player, getChunkAt(blockPosition));
}
}
public void breakBlock(Player player, Position position, CustomBlock customBlock) {
breakBlock(player, position, customBlock.getType());
public void breakBlock(Player player, BlockPosition blockPosition, CustomBlock customBlock) {
breakBlock(player, blockPosition, customBlock.getType());
}
public Chunk loadChunk(int chunkX, int chunkZ) {
@ -92,8 +93,8 @@ public class Instance implements BlockModifier {
return chunk.getBlockId((byte) (x % 16), (byte) y, (byte) (z % 16));
}
public short getBlockId(Position position) {
return getBlockId(position.getX(), position.getY(), position.getZ());
public short getBlockId(BlockPosition blockPosition) {
return getBlockId(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ());
}
public CustomBlock getCustomBlock(int x, int y, int z) {
@ -115,6 +116,10 @@ public class Instance implements BlockModifier {
return getChunk(chunkX, chunkZ);
}
public Chunk getChunkAt(BlockPosition blockPosition) {
return getChunkAt(blockPosition.getX(), blockPosition.getZ());
}
public Chunk getChunkAt(Position position) {
return getChunkAt(position.getX(), position.getZ());
}
@ -143,7 +148,7 @@ public class Instance implements BlockModifier {
getPlayers().forEach(p -> p.addViewer(player));
}
Chunk chunk = getChunkAt(entity.getX(), entity.getZ());
Chunk chunk = getChunkAt(entity.getPosition());
chunk.addEntity(entity);
}
@ -161,7 +166,7 @@ public class Instance implements BlockModifier {
entity.getViewers().forEach(p -> p.getPlayerConnection().sendPacket(destroyEntitiesPacket)); // TODO destroy batch
}
Chunk chunk = getChunkAt(entity.getX(), entity.getZ());
Chunk chunk = getChunkAt(entity.getPosition());
chunk.removeEntity(entity);
}

View File

@ -8,7 +8,7 @@ public class AnimationListener {
public static void animationListener(ClientAnimationPacket packet, Player player) {
AnimationPacket animationPacket = new AnimationPacket();
animationPacket.playerId = player.getEntityId();
animationPacket.entityId = player.getEntityId();
animationPacket.animation = packet.hand == Player.Hand.MAIN ? AnimationPacket.Animation.SWING_MAIN_ARM : AnimationPacket.Animation.SWING_OFF_HAND;
player.sendPacketToViewers(animationPacket);
}

View File

@ -6,13 +6,13 @@ import fr.themode.minestom.instance.Chunk;
import fr.themode.minestom.instance.Instance;
import fr.themode.minestom.net.packet.client.play.ClientPlayerBlockPlacementPacket;
import fr.themode.minestom.net.packet.client.play.ClientPlayerDiggingPacket;
import fr.themode.minestom.utils.Position;
import fr.themode.minestom.utils.BlockPosition;
public class BlockPlacementListener {
public static void listener(ClientPlayerBlockPlacementPacket packet, Player player) {
ClientPlayerDiggingPacket.BlockFace blockFace = packet.blockFace;
Position position = packet.position;
BlockPosition blockPosition = packet.blockPosition;
Instance instance = player.getInstance();
if (instance == null)
@ -25,10 +25,10 @@ public class BlockPlacementListener {
BlockPlaceEvent blockPlaceEvent = new BlockPlaceEvent((short) 10);
player.callEvent(BlockPlaceEvent.class, blockPlaceEvent);
if (!blockPlaceEvent.isCancelled()) {
instance.setBlock(position.getX() + offsetX, position.getY() + offsetY, position.getZ() + offsetZ, "custom_block");
instance.setBlock(blockPosition.getX() + offsetX, blockPosition.getY() + offsetY, blockPosition.getZ() + offsetZ, "custom_block");
// TODO consume block in hand for survival players
} else {
Chunk chunk = instance.getChunkAt(position);
Chunk chunk = instance.getChunkAt(blockPosition);
instance.sendChunkUpdate(player, chunk);
}
player.getInventory().refreshSlot(player.getHeldSlot());

View File

@ -27,7 +27,10 @@ public class PacketListenerManager {
addListener(ClientPlayerPositionAndLookPacket.class, PlayerPositionListener::playerPositionAndLookListener);
addListener(ClientPlayerDiggingPacket.class, PlayerDiggingListener::playerDiggingListener);
addListener(ClientAnimationPacket.class, AnimationListener::animationListener);
addListener(ClientUseEntityPacket.class, UseEntityListener::useEntityListener);
addListener(ClientUseItemPacket.class, UseItemListener::useItemListener);
addListener(ClientStatusPacket.class, StatusListener::listener);
addListener(ClientSettingsPacket.class, SettingsListener::listener);
}
public <T extends ClientPlayPacket> void process(T packet, Player player) {

View File

@ -8,29 +8,29 @@ import fr.themode.minestom.instance.Instance;
import fr.themode.minestom.net.packet.client.play.ClientPlayerDiggingPacket;
import fr.themode.minestom.net.packet.server.play.EntityEffectPacket;
import fr.themode.minestom.net.packet.server.play.RemoveEntityEffectPacket;
import fr.themode.minestom.utils.Position;
import fr.themode.minestom.utils.BlockPosition;
public class PlayerDiggingListener {
public static void playerDiggingListener(ClientPlayerDiggingPacket packet, Player player) {
ClientPlayerDiggingPacket.Status status = packet.status;
Position position = packet.position;
BlockPosition blockPosition = packet.blockPosition;
switch (status) {
case STARTED_DIGGING:
if (player.getGameMode() == GameMode.CREATIVE) {
Instance instance = player.getInstance();
if (instance != null) {
instance.setBlock(position.getX(), position.getY(), position.getZ(), (short) 0);
instance.setBlock(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ(), (short) 0);
}
} else if (player.getGameMode() == GameMode.SURVIVAL) {
Instance instance = player.getInstance();
if (instance != null) {
CustomBlock customBlock = instance.getCustomBlock(position.getX(), position.getY(), position.getZ());
CustomBlock customBlock = instance.getCustomBlock(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ());
if (customBlock != null) {
StartDiggingEvent startDiggingEvent = new StartDiggingEvent(customBlock);
player.callEvent(StartDiggingEvent.class, startDiggingEvent);
if (!startDiggingEvent.isCancelled()) {
player.refreshTargetBlock(customBlock, position);
player.refreshTargetBlock(customBlock, blockPosition);
}
addEffect(player);
} else {
@ -41,7 +41,7 @@ public class PlayerDiggingListener {
}
break;
case CANCELLED_DIGGING:
player.sendBlockBreakAnimation(position, (byte) -1);
player.sendBlockBreakAnimation(blockPosition, (byte) -1);
player.resetTargetBlock();
removeEffect(player);
break;
@ -52,8 +52,8 @@ public class PlayerDiggingListener {
} else {
Instance instance = player.getInstance();
if (instance != null) {
short blockId = instance.getBlockId(position);
instance.breakBlock(player, position, blockId);
short blockId = instance.getBlockId(blockPosition);
instance.breakBlock(player, blockPosition, blockId);
}
}
break;

View File

@ -1,6 +1,7 @@
package fr.themode.minestom.listener;
import fr.themode.minestom.entity.Player;
import fr.themode.minestom.event.PlayerMoveEvent;
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;
@ -15,29 +16,44 @@ public class PlayerPositionListener {
public static void playerLookListener(ClientPlayerLookPacket packet, Player player) {
player.refreshView(packet.yaw, packet.pitch);
player.refreshOnGround(packet.onGround);
// TODO move event?
}
public static void playerPositionListener(ClientPlayerPositionPacket packet, Player player) {
boolean chunkTest = player.chunkTest(packet.x, packet.z);
if (chunkTest) {
player.teleport(player.getX(), player.getY(), player.getZ());
return;
}
player.refreshPosition(packet.x, packet.y, packet.z);
player.refreshOnGround(packet.onGround);
float x = (float) packet.x;
float y = (float) packet.y;
float z = (float) packet.z;
processMovement(player, x, y, z, () -> {
player.refreshPosition(x, y, z);
player.refreshOnGround(packet.onGround);
});
}
public static void playerPositionAndLookListener(ClientPlayerPositionAndLookPacket packet, Player player) {
boolean chunkTest = player.chunkTest(packet.x, packet.z);
float x = (float) packet.x;
float y = (float) packet.y;
float z = (float) packet.z;
processMovement(player, x, y, z, () -> {
player.refreshPosition(x, y, z);
player.refreshView(packet.yaw, packet.pitch);
player.refreshOnGround(packet.onGround);
});
}
private static void processMovement(Player player, float x, float y, float z, Runnable runnable) {
boolean chunkTest = player.isChunkUnloaded(x, z);
if (chunkTest) {
player.teleport(player.getX(), player.getY(), player.getZ());
player.teleport(player.getPosition());
return;
}
player.refreshPosition(packet.x, packet.y, packet.z);
player.refreshView(packet.yaw, packet.pitch);
player.refreshOnGround(packet.onGround);
PlayerMoveEvent playerMoveEvent = new PlayerMoveEvent(x, y, z);
player.callEvent(PlayerMoveEvent.class, playerMoveEvent);
if (!playerMoveEvent.isCancelled()) {
runnable.run();
} else {
player.teleport(player.getPosition());
}
}
}

View File

@ -0,0 +1,13 @@
package fr.themode.minestom.listener;
import fr.themode.minestom.entity.Player;
import fr.themode.minestom.net.packet.client.play.ClientSettingsPacket;
public class SettingsListener {
public static void listener(ClientSettingsPacket packet, Player player) {
Player.PlayerSettings settings = player.getSettings();
settings.refresh(packet.locale, packet.viewDistance, packet.chatMode, packet.chatColors, packet.displayedSkinParts, packet.mainHand);
}
}

View File

@ -0,0 +1,29 @@
package fr.themode.minestom.listener;
import fr.themode.minestom.entity.Player;
import fr.themode.minestom.event.PlayerRespawnEvent;
import fr.themode.minestom.net.packet.client.play.ClientStatusPacket;
import fr.themode.minestom.net.packet.server.play.RespawnPacket;
public class StatusListener {
public static void listener(ClientStatusPacket packet, Player player) {
switch (packet.action) {
case PERFORM_RESPAWN:
RespawnPacket respawnPacket = new RespawnPacket();
respawnPacket.dimension = player.getDimension();
respawnPacket.gameMode = player.getGameMode();
respawnPacket.levelType = player.getLevelType();
player.getPlayerConnection().sendPacket(respawnPacket);
PlayerRespawnEvent respawnEvent = new PlayerRespawnEvent(player.getPosition());
player.callEvent(PlayerRespawnEvent.class, respawnEvent);
player.teleport(respawnEvent.getRespawnPosition());
player.getInventory().update();
break;
case REQUEST_STATS:
// TODO stats
break;
}
}
}

View File

@ -0,0 +1,28 @@
package fr.themode.minestom.listener;
import fr.themode.minestom.entity.Entity;
import fr.themode.minestom.entity.Player;
import fr.themode.minestom.event.AttackEvent;
import fr.themode.minestom.event.InteractEvent;
import fr.themode.minestom.net.packet.client.play.ClientUseEntityPacket;
public class UseEntityListener {
public static void useEntityListener(ClientUseEntityPacket packet, Player player) {
Entity entity = Entity.getEntity(packet.targetId);
if (entity == null)
return;
ClientUseEntityPacket.Type type = packet.type;
if (type == ClientUseEntityPacket.Type.ATTACK) {
AttackEvent attackEvent = new AttackEvent(entity);
player.callEvent(AttackEvent.class, attackEvent);
} else if (type == ClientUseEntityPacket.Type.INTERACT) {
InteractEvent interactEvent = new InteractEvent(entity);
player.callEvent(InteractEvent.class, interactEvent);
} else {
InteractEvent interactEvent = new InteractEvent(entity); // TODO find difference with INTERACT
player.callEvent(InteractEvent.class, interactEvent);
}
}
}

View File

@ -0,0 +1,18 @@
package fr.themode.minestom.listener;
import fr.themode.minestom.entity.Player;
import fr.themode.minestom.event.UseItemEvent;
import fr.themode.minestom.inventory.PlayerInventory;
import fr.themode.minestom.item.ItemStack;
import fr.themode.minestom.net.packet.client.play.ClientUseItemPacket;
public class UseItemListener {
public static void useItemListener(ClientUseItemPacket packet, Player player) {
PlayerInventory inventory = player.getInventory();
Player.Hand hand = packet.hand;
ItemStack itemStack = hand == Player.Hand.MAIN ? inventory.getItemInMainHand() : inventory.getItemInOffHand();
UseItemEvent useItemEvent = new UseItemEvent(hand, itemStack);
}
}

View File

@ -40,12 +40,12 @@ public class PacketProcessor {
this.playPacketsHandler = new ClientPlayPacketsHandler();
}
private List<Integer> printBlackList = Arrays.asList(17);
private List<Integer> printBlackList = Arrays.asList(17, 18, 19);
public void process(Connection connection, Packet packet) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
int id = packet.get(PACKET_ID_IDENTIFIER);
if (!printBlackList.contains(id)) {
// System.out.println("RECEIVED ID: " + id);
System.out.println("RECEIVED ID: " + id);
}
Buffer buffer = packet.getPayload();
connectionPlayerConnectionMap.get(connection);

View File

@ -25,5 +25,7 @@ public class ClientPlayPacketsHandler extends ClientPacketsHandler {
register(0x0A, ClientCloseWindow.class);
register(0x07, ClientConfirmTransactionPacket.class);
register(0x1C, ClientSteerVehiclePacket.class);
register(0x2D, ClientUseItemPacket.class);
register(0x04, ClientStatusPacket.class);
}
}

View File

@ -24,6 +24,7 @@ import fr.themode.minestom.net.packet.server.play.SpawnPositionPacket;
import fr.themode.minestom.net.player.PlayerConnection;
import fr.themode.minestom.utils.Utils;
import fr.themode.minestom.world.Dimension;
import fr.themode.minestom.world.LevelType;
import java.util.UUID;
@ -67,20 +68,24 @@ public class LoginStartPacket implements ClientPreplayPacket {
connectionManager.createPlayer(playerUuid, username, connection);
Player player = connectionManager.getPlayer(connection);
GameMode gameMode = GameMode.SURVIVAL;
Dimension dimension = Dimension.OVERWORLD;
LevelType levelType = LevelType.DEFAULT;
float x = 5;
float y = 5;
float z = 5;
player.refreshDimension(dimension);
player.refreshGameMode(gameMode);
player.refreshLevelType(levelType);
player.refreshPosition(x, y, z);
// TODO complete login sequence with optionals packets
JoinGamePacket joinGamePacket = new JoinGamePacket();
joinGamePacket.entityId = player.getEntityId();
joinGamePacket.gameMode = gameMode;
joinGamePacket.dimension = Dimension.OVERWORLD;
joinGamePacket.dimension = dimension;
joinGamePacket.maxPlayers = 0; // Unused
joinGamePacket.levelType = "default";
joinGamePacket.levelType = levelType;
joinGamePacket.viewDistance = 14;
joinGamePacket.reducedDebugInfo = false;
connection.sendPacket(joinGamePacket);
@ -99,11 +104,7 @@ public class LoginStartPacket implements ClientPreplayPacket {
connection.sendPacket(spawnPositionPacket);
PlayerPositionAndLookPacket playerPositionAndLookPacket = new PlayerPositionAndLookPacket();
playerPositionAndLookPacket.x = x;
playerPositionAndLookPacket.y = y;
playerPositionAndLookPacket.z = z;
playerPositionAndLookPacket.yaw = 0;
playerPositionAndLookPacket.pitch = 0;
playerPositionAndLookPacket.position = player.getPosition();
playerPositionAndLookPacket.flags = 0;
playerPositionAndLookPacket.teleportId = 42;
connection.sendPacket(playerPositionAndLookPacket);
@ -120,12 +121,10 @@ public class LoginStartPacket implements ClientPreplayPacket {
for (int cx = 0; cx < 4; cx++)
for (int cz = 0; cz < 4; cz++) {
ChickenCreature chickenCreature = new ChickenCreature();
chickenCreature.refreshPosition(0 + (double) cx * 1, 5, 0 + (double) cz * 1);
chickenCreature.setOnFire(true);
chickenCreature.refreshPosition(0 + (float) cx * 1, 5, 0 + (float) cz * 1);
//chickenCreature.setOnFire(true);
chickenCreature.setInstance(instance);
if (cx == 3 && cz == 3) {
//chickenCreature.addPassenger(player);
}
//chickenCreature.addPassenger(player);
}
PlayerInventory inventory = player.getInventory();

View File

@ -2,13 +2,13 @@ package fr.themode.minestom.net.packet.client.play;
import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.net.packet.client.ClientPlayPacket;
import fr.themode.minestom.utils.Position;
import fr.themode.minestom.utils.BlockPosition;
import fr.themode.minestom.utils.Utils;
public class ClientPlayerBlockPlacementPacket extends ClientPlayPacket {
public Hand hand;
public Position position;
public BlockPosition blockPosition;
public ClientPlayerDiggingPacket.BlockFace blockFace;
public float cursorPositionX, cursorPositionY, cursorPositionZ;
public boolean insideBlock;
@ -16,7 +16,7 @@ public class ClientPlayerBlockPlacementPacket extends ClientPlayPacket {
@Override
public void read(Buffer buffer) {
this.hand = Hand.values()[Utils.readVarInt(buffer)];
this.position = Utils.readPosition(buffer);
this.blockPosition = Utils.readPosition(buffer);
this.blockFace = ClientPlayerDiggingPacket.BlockFace.values()[Utils.readVarInt(buffer)];
this.cursorPositionX = buffer.getFloat();
this.cursorPositionY = buffer.getFloat();

View File

@ -2,19 +2,19 @@ package fr.themode.minestom.net.packet.client.play;
import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.net.packet.client.ClientPlayPacket;
import fr.themode.minestom.utils.Position;
import fr.themode.minestom.utils.BlockPosition;
import fr.themode.minestom.utils.Utils;
public class ClientPlayerDiggingPacket extends ClientPlayPacket {
public Status status;
public Position position;
public BlockPosition blockPosition;
public BlockFace blockFace;
@Override
public void read(Buffer buffer) {
this.status = Status.values()[Utils.readVarInt(buffer)];
this.position = Utils.readPosition(buffer);
this.blockPosition = Utils.readPosition(buffer);
this.blockFace = BlockFace.values()[Utils.readVarInt(buffer)];
}

View File

@ -1,6 +1,7 @@
package fr.themode.minestom.net.packet.client.play;
import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.entity.Player;
import fr.themode.minestom.net.packet.client.ClientPlayPacket;
import fr.themode.minestom.utils.Utils;
@ -8,18 +9,18 @@ public class ClientSettingsPacket extends ClientPlayPacket {
public String locale;
public byte viewDistance;
// TODO chat mode
public Player.ChatMode chatMode;
public boolean chatColors;
public byte displayedSkinParts;
// TODO main hand
public Player.MainHand mainHand;
@Override
public void read(Buffer buffer) {
this.locale = Utils.readString(buffer);
this.viewDistance = buffer.getByte();
Utils.readVarInt(buffer); // chat mode
this.chatMode = Player.ChatMode.values()[Utils.readVarInt(buffer)];
this.chatColors = buffer.getBoolean();
this.displayedSkinParts = buffer.getByte();
Utils.readVarInt(buffer); // main hand
this.mainHand = Player.MainHand.values()[Utils.readVarInt(buffer)];
}
}

View File

@ -0,0 +1,21 @@
package fr.themode.minestom.net.packet.client.play;
import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.net.packet.client.ClientPlayPacket;
import fr.themode.minestom.utils.Utils;
public class ClientStatusPacket extends ClientPlayPacket {
public Action action;
@Override
public void read(Buffer buffer) {
this.action = Action.values()[Utils.readVarInt(buffer)];
}
public enum Action {
PERFORM_RESPAWN,
REQUEST_STATS;
}
}

View File

@ -7,16 +7,16 @@ import fr.themode.minestom.utils.Utils;
public class ClientUseEntityPacket extends ClientPlayPacket {
private int target;
private Type type;
private float x;
private float y;
private float z;
private Player.Hand hand;
public int targetId;
public Type type;
public float x;
public float y;
public float z;
public Player.Hand hand;
@Override
public void read(Buffer buffer) {
this.target = Utils.readVarInt(buffer);
this.targetId = Utils.readVarInt(buffer);
this.type = Type.values()[Utils.readVarInt(buffer)];
if (this.type == Type.INTERACT_AT) {
this.x = buffer.getFloat();
@ -28,7 +28,6 @@ public class ClientUseEntityPacket extends ClientPlayPacket {
}
public enum Type {
INTERACT,
ATTACK,
INTERACT_AT;

View File

@ -0,0 +1,16 @@
package fr.themode.minestom.net.packet.client.play;
import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.entity.Player;
import fr.themode.minestom.net.packet.client.ClientPlayPacket;
import fr.themode.minestom.utils.Utils;
public class ClientUseItemPacket extends ClientPlayPacket {
public Player.Hand hand;
@Override
public void read(Buffer buffer) {
this.hand = Player.Hand.values()[Utils.readVarInt(buffer)];
}
}

View File

@ -5,6 +5,7 @@ import fr.themode.minestom.entity.GameMode;
import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Utils;
import fr.themode.minestom.world.Dimension;
import fr.themode.minestom.world.LevelType;
public class JoinGamePacket implements ServerPacket {
@ -12,7 +13,7 @@ public class JoinGamePacket implements ServerPacket {
public GameMode gameMode = GameMode.SURVIVAL;
public Dimension dimension = Dimension.OVERWORLD;
public byte maxPlayers = 0; // Unused
public String levelType = "default";
public LevelType levelType;
public int viewDistance;
public boolean reducedDebugInfo = false;
@ -26,7 +27,7 @@ public class JoinGamePacket implements ServerPacket {
buffer.putByte((byte) gameModeId);
buffer.putInt(dimension.getId());
buffer.putByte(maxPlayers);
Utils.writeString(buffer, levelType);
Utils.writeString(buffer, levelType.getType());
Utils.writeVarInt(buffer, viewDistance);
buffer.putBoolean(reducedDebugInfo);
}

View File

@ -3,19 +3,19 @@ package fr.themode.minestom.net.packet.server.play;
import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.net.packet.client.play.ClientPlayerDiggingPacket;
import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Position;
import fr.themode.minestom.utils.BlockPosition;
import fr.themode.minestom.utils.Utils;
public class AcknowledgePlayerDiggingPacket implements ServerPacket {
public Position position;
public BlockPosition blockPosition;
public int blockStateId;
public ClientPlayerDiggingPacket.Status status;
public boolean successful;
@Override
public void write(Buffer buffer) {
Utils.writePosition(buffer, position);
Utils.writePosition(buffer, blockPosition);
Utils.writeVarInt(buffer, blockStateId);
Utils.writeVarInt(buffer, status.ordinal());
buffer.putBoolean(successful);

View File

@ -6,12 +6,12 @@ import fr.themode.minestom.utils.Utils;
public class AnimationPacket implements ServerPacket {
public int playerId; // FIXME verify if this is only player?
public int entityId;
public Animation animation;
@Override
public void write(Buffer buffer) {
Utils.writeVarInt(buffer, playerId);
Utils.writeVarInt(buffer, entityId);
buffer.putByte((byte) animation.ordinal());
}

View File

@ -2,13 +2,13 @@ package fr.themode.minestom.net.packet.server.play;
import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Position;
import fr.themode.minestom.utils.BlockPosition;
import fr.themode.minestom.utils.Utils;
public class BlockBreakAnimationPacket implements ServerPacket {
public int entityId;
public Position blockPosition;
public BlockPosition blockPosition;
public byte destroyStage;
@Override

View File

@ -2,17 +2,17 @@ package fr.themode.minestom.net.packet.server.play;
import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Position;
import fr.themode.minestom.utils.BlockPosition;
import fr.themode.minestom.utils.Utils;
public class BlockChangePacket implements ServerPacket {
public Position position;
public BlockPosition blockPosition;
public int blockId;
@Override
public void write(Buffer buffer) {
Utils.writePosition(buffer, position.getX(), position.getY(), position.getZ());
Utils.writePosition(buffer, blockPosition.getX(), blockPosition.getY(), blockPosition.getZ());
Utils.writeVarInt(buffer, blockId);
}

View File

@ -29,7 +29,7 @@ public class ChunkDataPacket implements ServerPacket {
for (int i = 0; i < 16; i++) {
// TODO if fullchunk is false then only send changed sections
mask |= 1 << i;
Short[] section = getSection(chunk, i);
short[] section = getSection(chunk, i);
Utils.writeBlocks(blocks, section, 14);
}
// Biome data
@ -72,8 +72,8 @@ public class ChunkDataPacket implements ServerPacket {
Utils.writeVarInt(buffer, 0);
}
private Short[] getSection(Chunk chunk, int section) {
Short[] blocks = new Short[16 * 16 * 16];
private short[] getSection(Chunk chunk, int section) {
short[] blocks = new short[16 * 16 * 16];
for (byte y = 0; y < 16; y++) {
for (byte x = 0; x < 16; x++) {
for (byte z = 0; z < 16; z++) {

View File

@ -0,0 +1,21 @@
package fr.themode.minestom.net.packet.server.play;
import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.net.packet.server.ServerPacket;
public class EntityStatusPacket implements ServerPacket {
public int entityId;
public byte status;
@Override
public void write(Buffer buffer) {
buffer.putInt(entityId);
buffer.putByte(status);
}
@Override
public int getId() {
return 0x1B;
}
}

View File

@ -2,23 +2,23 @@ package fr.themode.minestom.net.packet.server.play;
import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Position;
import fr.themode.minestom.utils.Utils;
public class EntityTeleportPacket implements ServerPacket {
public int entityId;
public double x, y, z;
public float yaw, pitch;
public Position position;
public boolean onGround;
@Override
public void write(Buffer buffer) {
Utils.writeVarInt(buffer, entityId);
buffer.putDouble(x);
buffer.putDouble(y);
buffer.putDouble(z);
buffer.putByte((byte) (this.yaw * 256 / 360));
buffer.putByte((byte) (this.pitch * 256 / 360));
buffer.putDouble(position.getX());
buffer.putDouble(position.getY());
buffer.putDouble(position.getZ());
buffer.putByte((byte) (position.getYaw() * 256f / 360f));
buffer.putByte((byte) (position.getPitch() * 256f / 360f));
buffer.putBoolean(onGround);
}

View File

@ -2,23 +2,23 @@ package fr.themode.minestom.net.packet.server.play;
import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Position;
import fr.themode.minestom.utils.Utils;
public class PlayerPositionAndLookPacket implements ServerPacket {
public double x, y, z;
public float yaw, pitch;
public Position position;
public byte flags;
public int teleportId;
@Override
public void write(Buffer buffer) {
buffer.putDouble(x);
buffer.putDouble(y);
buffer.putDouble(z);
buffer.putFloat(yaw);
buffer.putFloat(pitch);
buffer.putDouble(position.getX());
buffer.putDouble(position.getY());
buffer.putDouble(position.getZ());
buffer.putFloat(position.getYaw());
buffer.putFloat(position.getPitch());
buffer.putBytes(flags);
Utils.writeVarInt(buffer, teleportId);
}

View File

@ -0,0 +1,31 @@
package fr.themode.minestom.net.packet.server.play;
import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.entity.GameMode;
import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Utils;
import fr.themode.minestom.world.Dimension;
import fr.themode.minestom.world.LevelType;
public class RespawnPacket implements ServerPacket {
public Dimension dimension;
public GameMode gameMode;
public LevelType levelType;
@Override
public void write(Buffer buffer) {
int gameModeId = gameMode.getId();
if (gameMode.isHardcore())
gameModeId |= 8;
buffer.putByte((byte) gameModeId);
buffer.putInt(dimension.getId());
Utils.writeString(buffer, levelType.getType());
}
@Override
public int getId() {
return 0x3A;
}
}

View File

@ -0,0 +1,24 @@
package fr.themode.minestom.net.packet.server.play;
import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Utils;
public class SetExperiencePacket implements ServerPacket {
public float percentage;
public int level;
public int totalExperience;
@Override
public void write(Buffer buffer) {
buffer.putFloat(percentage);
Utils.writeVarInt(buffer, level);
Utils.writeVarInt(buffer, totalExperience);
}
@Override
public int getId() {
return 0x47;
}
}

View File

@ -2,6 +2,7 @@ package fr.themode.minestom.net.packet.server.play;
import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Position;
import fr.themode.minestom.utils.Utils;
import java.util.UUID;
@ -11,8 +12,7 @@ public class SpawnMobPacket implements ServerPacket {
public int entityId;
public UUID entityUuid;
public int entityType;
public double x, y, z;
public float yaw, pitch;
public Position position;
public float headPitch;
public short velocityX, velocityY, velocityZ;
// TODO metadata
@ -22,11 +22,11 @@ public class SpawnMobPacket implements ServerPacket {
Utils.writeVarInt(buffer, entityId);
Utils.writeUuid(buffer, entityUuid);
Utils.writeVarInt(buffer, entityType);
buffer.putDouble(x);
buffer.putDouble(y);
buffer.putDouble(z);
buffer.putFloat(yaw);
buffer.putFloat(pitch);
buffer.putDouble(position.getX());
buffer.putDouble(position.getY());
buffer.putDouble(position.getZ());
buffer.putFloat(position.getYaw());
buffer.putFloat(position.getPitch());
buffer.putFloat(headPitch);
buffer.putShort(velocityX);
buffer.putShort(velocityY);

View File

@ -2,6 +2,7 @@ package fr.themode.minestom.net.packet.server.play;
import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Position;
import fr.themode.minestom.utils.Utils;
import java.util.UUID;
@ -11,8 +12,7 @@ public class SpawnObjectPacket implements ServerPacket {
public int entityId;
public UUID uuid;
public int type;
public double x, y, z;
public float yaw, pitch;
public Position position;
public int data;
@Override
@ -20,11 +20,11 @@ public class SpawnObjectPacket implements ServerPacket {
Utils.writeVarInt(buffer, entityId);
Utils.writeUuid(buffer, uuid);
Utils.writeVarInt(buffer, type);
buffer.putDouble(x);
buffer.putDouble(y);
buffer.putDouble(z);
buffer.putFloat(yaw);
buffer.putFloat(pitch);
buffer.putDouble(position.getX());
buffer.putDouble(position.getY());
buffer.putDouble(position.getZ());
buffer.putFloat(position.getYaw());
buffer.putFloat(position.getPitch());
buffer.putInt(data);
}

View File

@ -2,6 +2,7 @@ package fr.themode.minestom.net.packet.server.play;
import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Position;
import fr.themode.minestom.utils.Utils;
import java.util.UUID;
@ -10,22 +11,18 @@ public class SpawnPlayerPacket implements ServerPacket {
public int entityId;
public UUID playerUuid;
public double x;
public double y;
public double z;
public float yaw;
public float pitch;
public Position position;
@Override
public void write(Buffer buffer) {
Utils.writeVarInt(buffer, entityId);
buffer.putLong(playerUuid.getMostSignificantBits());
buffer.putLong(playerUuid.getLeastSignificantBits());
buffer.putDouble(x);
buffer.putDouble(y);
buffer.putDouble(z);
buffer.putByte((byte) (yaw * 256 / 360));
buffer.putByte((byte) (pitch * 256 / 360));
buffer.putDouble(position.getX());
buffer.putDouble(position.getY());
buffer.putDouble(position.getZ());
buffer.putByte((byte) (position.getYaw() * 256f / 360f));
buffer.putByte((byte) (position.getPitch() * 256f / 360f));
buffer.putByte((byte) 0xff); // TODO Metadata
}

View File

@ -0,0 +1,24 @@
package fr.themode.minestom.net.packet.server.play;
import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Utils;
public class UpdateHealthPacket implements ServerPacket {
public float health;
public int food;
public float foodSaturation;
@Override
public void write(Buffer buffer) {
buffer.putFloat(health);
Utils.writeVarInt(buffer, food);
buffer.putFloat(foodSaturation);
}
@Override
public int getId() {
return 0x48;
}
}

View File

@ -1,23 +1,22 @@
package fr.themode.minestom.net.packet.server.play;
import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.instance.Chunk;
import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Utils;
public class UpdateViewPositionPacket implements ServerPacket {
private int chunkX;
private int chunkZ;
private Chunk chunk;
public UpdateViewPositionPacket(int chunkX, int chunkZ) {
this.chunkX = chunkX;
this.chunkZ = chunkZ;
public UpdateViewPositionPacket(Chunk chunk) {
this.chunk = chunk;
}
@Override
public void write(Buffer buffer) {
Utils.writeVarInt(buffer, chunkX);
Utils.writeVarInt(buffer, chunkZ);
Utils.writeVarInt(buffer, chunk.getChunkX());
Utils.writeVarInt(buffer, chunk.getChunkZ());
}
@Override

View File

@ -0,0 +1,41 @@
package fr.themode.minestom.utils;
public class BlockPosition {
private int x, y, z;
public BlockPosition(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getZ() {
return z;
}
public void setZ(int z) {
this.z = z;
}
@Override
public String toString() {
return "Position[" + x + ":" + y + ":" + z + "]";
}
}

View File

@ -2,40 +2,66 @@ package fr.themode.minestom.utils;
public class Position {
private int x, y, z;
private float x, y, z;
private float yaw, pitch;
public Position(int x, int y, int z) {
public Position(float x, float y, float z, float yaw, float pitch) {
this.x = x;
this.y = y;
this.z = z;
this.yaw = yaw;
this.pitch = pitch;
}
public int getX() {
public Position(float x, float y, float z) {
this(x, y, z, 0, 0);
}
public Position() {
this(0, 0, 0);
}
public float getDistance(Position position) {
return (float) Math.sqrt(Math.pow(position.getX() - getX(), 2) + Math.pow(position.getY() - getY(), 2) + Math.pow(position.getZ() - getZ(), 2));
}
public float getX() {
return x;
}
public void setX(int x) {
public void setX(float x) {
this.x = x;
}
public int getY() {
public float getY() {
return y;
}
public void setY(int y) {
public void setY(float y) {
this.y = y;
}
public int getZ() {
public float getZ() {
return z;
}
public void setZ(int z) {
public void setZ(float z) {
this.z = z;
}
@Override
public String toString() {
return "Position[" + x + ":" + y + ":" + z + "]";
public float getYaw() {
return yaw;
}
public void setYaw(float yaw) {
this.yaw = yaw;
}
public float getPitch() {
return pitch;
}
public void setPitch(float pitch) {
this.pitch = pitch;
}
}

View File

@ -4,9 +4,7 @@ import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.item.ItemStack;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.UUID;
import java.util.stream.Collectors;
public class Utils {
@ -125,16 +123,16 @@ public class Utils {
buffer.putLong((((long) x & 0x3FFFFFF) << 38) | (((long) z & 0x3FFFFFF) << 12) | ((long) y & 0xFFF));
}
public static void writePosition(Buffer buffer, Position position) {
writePosition(buffer, position.getX(), position.getY(), position.getZ());
public static void writePosition(Buffer buffer, BlockPosition blockPosition) {
writePosition(buffer, blockPosition.getX(), blockPosition.getY(), blockPosition.getZ());
}
public static Position readPosition(Buffer buffer) {
public static BlockPosition readPosition(Buffer buffer) {
long val = buffer.getLong();
int x = (int) (val >> 38);
int y = (int) (val & 0xFFF);
int z = (int) (val << 26 >> 38);
return new Position(x, y, z);
return new BlockPosition(x, y, z);
}
public static void writeUuid(Buffer buffer, UUID uuid) {
@ -153,8 +151,13 @@ public class Utils {
}
}
public static void writeBlocks(Buffer buffer, Short[] blocksId, int bitsPerEntry) {
buffer.putShort((short) Arrays.stream(blocksId).filter(customBlock -> customBlock != 0).collect(Collectors.toList()).size());
public static void writeBlocks(Buffer buffer, short[] blocksId, int bitsPerEntry) {
short count = 0;
for (short id : blocksId)
if (id != 0)
count++;
buffer.putShort(count);
buffer.putByte((byte) bitsPerEntry);
int[] blocksData = new int[16 * 16 * 16];
for (int y = 0; y < 16; y++) {

View File

@ -0,0 +1,20 @@
package fr.themode.minestom.world;
public enum LevelType {
DEFAULT("default"),
FLAT("flat"),
LARGE_BIOMES("largeBiomes"),
AMPLIFIED("amplified"),
DEFAULT_1_1("default_1_1");
private String type;
LevelType(String type) {
this.type = type;
}
public String getType() {
return type;
}
}