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 BlockManager blockManager;
private static EntityManager entityManager; private static EntityManager entityManager;
public static void main(String[] args) { public static void main(String[] args) throws InterruptedException {
connectionManager = new ConnectionManager(); connectionManager = new ConnectionManager();
packetProcessor = new PacketProcessor(); packetProcessor = new PacketProcessor();
packetListenerManager = new PacketListenerManager(); packetListenerManager = new PacketListenerManager();
@ -95,28 +95,28 @@ public class Main {
System.out.println("Server started"); System.out.println("Server started");
long tickDistance = TICK_MS * 1000000; long tickDistance = TICK_MS * 1000000;
long nextTick = System.nanoTime();
long currentTime; long currentTime;
while (true) { while (true) {
currentTime = System.nanoTime(); currentTime = System.nanoTime();
if (currentTime >= nextTick) {
// Tick
// Keep Alive Handling // 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 -> { 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(); long id = System.currentTimeMillis();
player.refreshKeepAlive(id); player.refreshKeepAlive(id);
KeepAlivePacket keepAlivePacket = new KeepAlivePacket(id); KeepAlivePacket keepAlivePacket = new KeepAlivePacket(id);
player.getPlayerConnection().sendPacket(keepAlivePacket); player.getPlayerConnection().sendPacket(keepAlivePacket);
}); });
// Entities update // Entities update
entityManager.update(); entityManager.update();
// Set next tick update time // Sleep until next tick
currentTime = System.nanoTime(); long sleepTime = (tickDistance - (System.nanoTime() - currentTime)) / 1000000;
nextTick = currentTime + tickDistance - (currentTime - nextTick);
} //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; package fr.themode.minestom;
import fr.themode.minestom.entity.Player; import fr.themode.minestom.entity.Player;
import fr.themode.minestom.net.packet.server.ServerPacket;
import java.util.Set; import java.util.Set;
@ -16,4 +17,15 @@ public interface Viewable {
return getViewers().contains(player); 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 bossBarPacket = new BossBarPacket();
bossBarPacket.uuid = uuid; bossBarPacket.uuid = uuid;
bossBarPacket.action = BossBarPacket.Action.REMOVE; bossBarPacket.action = BossBarPacket.Action.REMOVE;
sendPacket(bossBarPacket); sendPacketToViewers(bossBarPacket);
getViewers().forEach(player -> player.refreshRemoveBossbar(this)); getViewers().forEach(player -> player.refreshRemoveBossbar(this));
} }
@ -113,7 +113,7 @@ public class BossBar implements Viewable {
bossBarPacket.uuid = uuid; bossBarPacket.uuid = uuid;
bossBarPacket.action = BossBarPacket.Action.UPDATE_TITLE; bossBarPacket.action = BossBarPacket.Action.UPDATE_TITLE;
bossBarPacket.title = title; bossBarPacket.title = title;
sendPacket(bossBarPacket); sendPacketToViewers(bossBarPacket);
} }
private void updateProgress() { private void updateProgress() {
@ -121,7 +121,7 @@ public class BossBar implements Viewable {
bossBarPacket.uuid = uuid; bossBarPacket.uuid = uuid;
bossBarPacket.action = BossBarPacket.Action.UPDATE_HEALTH; bossBarPacket.action = BossBarPacket.Action.UPDATE_HEALTH;
bossBarPacket.health = progress; bossBarPacket.health = progress;
sendPacket(bossBarPacket); sendPacketToViewers(bossBarPacket);
} }
private void updateStyle() { private void updateStyle() {
@ -129,10 +129,6 @@ public class BossBar implements Viewable {
bossBarPacket.uuid = uuid; bossBarPacket.uuid = uuid;
bossBarPacket.action = BossBarPacket.Action.UPDATE_STYLE; bossBarPacket.action = BossBarPacket.Action.UPDATE_STYLE;
bossBarPacket.color = color; bossBarPacket.color = color;
sendPacket(bossBarPacket); sendPacketToViewers(bossBarPacket);
}
private void sendPacket(BossBarPacket bossBarPacket) {
getViewers().forEach(player -> player.getPlayerConnection().sendPacket(bossBarPacket));
} }
} }

View File

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

View File

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

View File

@ -19,7 +19,7 @@ public class EntityManager {
public void update() { public void update() {
for (Instance instance : instanceManager.getInstances()) { 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; package fr.themode.minestom.entity;
// TODO attributes https://wiki.vg/Protocol#Entity_Properties
public abstract class LivingEntity extends Entity { public abstract class LivingEntity extends Entity {
protected boolean onGround; protected boolean onGround;
@ -8,8 +9,4 @@ public abstract class LivingEntity extends Entity {
super(entityType); 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.entityId = getEntityId();
spawnObjectPacket.uuid = getUuid(); spawnObjectPacket.uuid = getUuid();
spawnObjectPacket.type = getEntityType(); spawnObjectPacket.type = getEntityType();
spawnObjectPacket.x = getX(); spawnObjectPacket.position = getPosition();
spawnObjectPacket.y = getY();
spawnObjectPacket.z = getZ();
spawnObjectPacket.yaw = getYaw();
spawnObjectPacket.pitch = getPitch();
spawnObjectPacket.data = getData(); spawnObjectPacket.data = getData();
EntityMetaDataPacket entityMetaDataPacket = new EntityMetaDataPacket(); EntityMetaDataPacket entityMetaDataPacket = new EntityMetaDataPacket();
entityMetaDataPacket.entityId = getEntityId(); entityMetaDataPacket.entityId = getEntityId();

View File

@ -2,6 +2,7 @@ package fr.themode.minestom.entity;
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.event.AttackEvent;
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.instance.CustomBlock; 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.ServerPacket;
import fr.themode.minestom.net.packet.server.play.*; import fr.themode.minestom.net.packet.server.play.*;
import fr.themode.minestom.net.player.PlayerConnection; import fr.themode.minestom.net.player.PlayerConnection;
import fr.themode.minestom.utils.BlockPosition;
import fr.themode.minestom.utils.Position; 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.Collections;
import java.util.LinkedList; import java.util.LinkedList;
@ -28,13 +32,16 @@ public class Player extends LivingEntity {
private PlayerConnection playerConnection; private PlayerConnection playerConnection;
private LinkedList<ClientPlayPacket> packets = new LinkedList<>(); private LinkedList<ClientPlayPacket> packets = new LinkedList<>();
private Dimension dimension;
private GameMode gameMode; private GameMode gameMode;
private LevelType levelType;
private PlayerSettings settings;
private PlayerInventory inventory; private PlayerInventory inventory;
private short heldSlot; private short heldSlot;
private Inventory openInventory; private Inventory openInventory;
private CustomBlock targetCustomBlock; private CustomBlock targetCustomBlock;
private Position targetBlockPosition; private BlockPosition targetBlockPosition;
private long targetBlockTime; private long targetBlockTime;
private Set<BossBar> bossBars = new CopyOnWriteArraySet<>(); private Set<BossBar> bossBars = new CopyOnWriteArraySet<>();
@ -71,6 +78,19 @@ public class Player extends LivingEntity {
event.setCancelled(true); event.setCancelled(true);
sendMessage("CANCELLED"); 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 @Override
@ -97,7 +117,7 @@ public class Player extends LivingEntity {
// Item pickup // Item pickup
if (instance != null) { 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(); Set<ObjectEntity> objectEntities = chunk.getObjectEntities();
for (ObjectEntity objectEntity : objectEntities) { for (ObjectEntity objectEntity : objectEntities) {
if (objectEntity instanceof ItemEntity) { if (objectEntity instanceof ItemEntity) {
@ -112,13 +132,16 @@ public class Player extends LivingEntity {
ItemStack item = itemEntity.getItemStack(); ItemStack item = itemEntity.getItemStack();
PickupItemEvent pickupItemEvent = new PickupItemEvent(item); PickupItemEvent pickupItemEvent = new PickupItemEvent(item);
callCancellableEvent(PickupItemEvent.class, pickupItemEvent, () -> { callCancellableEvent(PickupItemEvent.class, pickupItemEvent, () -> {
CollectItemPacket collectItemPacket = new CollectItemPacket(); boolean result = getInventory().addItemStack(item);
collectItemPacket.collectedEntityId = itemEntity.getEntityId(); if (result) {
collectItemPacket.collectorEntityId = getEntityId(); CollectItemPacket collectItemPacket = new CollectItemPacket();
collectItemPacket.pickupItemCount = item.getAmount(); collectItemPacket.collectedEntityId = itemEntity.getEntityId();
instance.getPlayers().forEach(player -> player.getPlayerConnection().sendPacket(collectItemPacket)); collectItemPacket.collectorEntityId = getEntityId();
getInventory().addItemStack(item); collectItemPacket.pickupItemCount = item.getAmount();
objectEntity.remove(); playerConnection.sendPacket(collectItemPacket);
sendPacketToViewers(collectItemPacket);
objectEntity.remove();
}
}); });
} }
} }
@ -128,55 +151,56 @@ public class Player extends LivingEntity {
// Multiplayer sync // Multiplayer sync
boolean positionChanged = x != lastX || z != lastZ || y != lastY; Position position = getPosition();
boolean viewChanged = yaw != lastYaw || pitch != lastPitch; boolean positionChanged = position.getX() != lastX || position.getZ() != lastZ || position.getY() != lastY;
boolean viewChanged = position.getYaw() != lastYaw || position.getPitch() != lastPitch;
ServerPacket updatePacket = null; ServerPacket updatePacket = null;
ServerPacket optionalUpdatePacket = null; ServerPacket optionalUpdatePacket = null;
if (positionChanged && viewChanged) { if (positionChanged && viewChanged) {
EntityLookAndRelativeMovePacket entityLookAndRelativeMovePacket = new EntityLookAndRelativeMovePacket(); EntityLookAndRelativeMovePacket entityLookAndRelativeMovePacket = new EntityLookAndRelativeMovePacket();
entityLookAndRelativeMovePacket.entityId = getEntityId(); entityLookAndRelativeMovePacket.entityId = getEntityId();
entityLookAndRelativeMovePacket.deltaX = (short) ((x * 32 - lastX * 32) * 128); entityLookAndRelativeMovePacket.deltaX = (short) ((position.getX() * 32 - lastX * 32) * 128);
entityLookAndRelativeMovePacket.deltaY = (short) ((y * 32 - lastY * 32) * 128); entityLookAndRelativeMovePacket.deltaY = (short) ((position.getY() * 32 - lastY * 32) * 128);
entityLookAndRelativeMovePacket.deltaZ = (short) ((z * 32 - lastZ * 32) * 128); entityLookAndRelativeMovePacket.deltaZ = (short) ((position.getZ() * 32 - lastZ * 32) * 128);
entityLookAndRelativeMovePacket.yaw = yaw; entityLookAndRelativeMovePacket.yaw = position.getYaw();
entityLookAndRelativeMovePacket.pitch = pitch; entityLookAndRelativeMovePacket.pitch = position.getPitch();
entityLookAndRelativeMovePacket.onGround = onGround; entityLookAndRelativeMovePacket.onGround = onGround;
EntityHeadLookPacket entityHeadLookPacket = new EntityHeadLookPacket(); EntityHeadLookPacket entityHeadLookPacket = new EntityHeadLookPacket();
entityHeadLookPacket.entityId = getEntityId(); entityHeadLookPacket.entityId = getEntityId();
entityHeadLookPacket.yaw = yaw; entityHeadLookPacket.yaw = position.getYaw();
lastX = x; lastX = position.getX();
lastY = y; lastY = position.getY();
lastZ = z; lastZ = position.getZ();
lastYaw = yaw; lastYaw = position.getYaw();
lastPitch = pitch; lastPitch = position.getPitch();
updatePacket = entityLookAndRelativeMovePacket; updatePacket = entityLookAndRelativeMovePacket;
optionalUpdatePacket = entityHeadLookPacket; optionalUpdatePacket = entityHeadLookPacket;
} else if (positionChanged) { } else if (positionChanged) {
EntityRelativeMovePacket entityRelativeMovePacket = new EntityRelativeMovePacket(); EntityRelativeMovePacket entityRelativeMovePacket = new EntityRelativeMovePacket();
entityRelativeMovePacket.entityId = getEntityId(); entityRelativeMovePacket.entityId = getEntityId();
entityRelativeMovePacket.deltaX = (short) ((x * 32 - lastX * 32) * 128); entityRelativeMovePacket.deltaX = (short) ((position.getX() * 32 - lastX * 32) * 128);
entityRelativeMovePacket.deltaY = (short) ((y * 32 - lastY * 32) * 128); entityRelativeMovePacket.deltaY = (short) ((position.getY() * 32 - lastY * 32) * 128);
entityRelativeMovePacket.deltaZ = (short) ((z * 32 - lastZ * 32) * 128); entityRelativeMovePacket.deltaZ = (short) ((position.getZ() * 32 - lastZ * 32) * 128);
entityRelativeMovePacket.onGround = onGround; entityRelativeMovePacket.onGround = onGround;
lastX = x; lastX = position.getX();
lastY = y; lastY = position.getY();
lastZ = z; lastZ = position.getZ();
updatePacket = entityRelativeMovePacket; updatePacket = entityRelativeMovePacket;
} else if (viewChanged) { } else if (viewChanged) {
EntityLookPacket entityLookPacket = new EntityLookPacket(); EntityLookPacket entityLookPacket = new EntityLookPacket();
entityLookPacket.entityId = getEntityId(); entityLookPacket.entityId = getEntityId();
entityLookPacket.yaw = yaw; entityLookPacket.yaw = position.getYaw();
entityLookPacket.pitch = pitch; entityLookPacket.pitch = position.getPitch();
entityLookPacket.onGround = onGround; entityLookPacket.onGround = onGround;
EntityHeadLookPacket entityHeadLookPacket = new EntityHeadLookPacket(); EntityHeadLookPacket entityHeadLookPacket = new EntityHeadLookPacket();
entityHeadLookPacket.entityId = getEntityId(); entityHeadLookPacket.entityId = getEntityId();
entityHeadLookPacket.yaw = yaw; entityHeadLookPacket.yaw = position.getYaw();
lastYaw = yaw; lastYaw = position.getYaw();
lastPitch = pitch; lastPitch = position.getPitch();
updatePacket = entityLookPacket; updatePacket = entityLookPacket;
optionalUpdatePacket = entityHeadLookPacket; optionalUpdatePacket = entityHeadLookPacket;
} }
@ -187,7 +211,7 @@ public class Player extends LivingEntity {
sendPacketToViewers(updatePacket); sendPacketToViewers(updatePacket);
} }
} }
playerConnection.sendPacket(new UpdateViewPositionPacket(Math.floorDiv((int) x, 16), Math.floorDiv((int) z, 16))); playerConnection.sendPacket(new UpdateViewPositionPacket(instance.getChunkAt(getPosition())));
// Synchronization // Synchronization
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
@ -196,9 +220,7 @@ public class Player extends LivingEntity {
for (Player viewer : getViewers()) { for (Player viewer : getViewers()) {
EntityTeleportPacket teleportPacket = new EntityTeleportPacket(); EntityTeleportPacket teleportPacket = new EntityTeleportPacket();
teleportPacket.entityId = viewer.getEntityId(); teleportPacket.entityId = viewer.getEntityId();
teleportPacket.x = viewer.getX(); teleportPacket.position = getPosition();
teleportPacket.y = viewer.getY();
teleportPacket.z = viewer.getZ();
teleportPacket.onGround = viewer.onGround; teleportPacket.onGround = viewer.onGround;
playerConnection.sendPacket(teleportPacket); playerConnection.sendPacket(teleportPacket);
} }
@ -213,11 +235,7 @@ public class Player extends LivingEntity {
SpawnPlayerPacket spawnPlayerPacket = new SpawnPlayerPacket(); SpawnPlayerPacket spawnPlayerPacket = new SpawnPlayerPacket();
spawnPlayerPacket.entityId = getEntityId(); spawnPlayerPacket.entityId = getEntityId();
spawnPlayerPacket.playerUuid = getUuid(); spawnPlayerPacket.playerUuid = getUuid();
spawnPlayerPacket.x = x; spawnPlayerPacket.position = getPosition();
spawnPlayerPacket.y = y;
spawnPlayerPacket.z = z;
spawnPlayerPacket.yaw = yaw;
spawnPlayerPacket.pitch = pitch;
PlayerInfoPacket pInfoPacket = new PlayerInfoPacket(PlayerInfoPacket.Action.ADD_PLAYER); PlayerInfoPacket pInfoPacket = new PlayerInfoPacket(PlayerInfoPacket.Action.ADD_PLAYER);
PlayerInfoPacket.AddPlayer addP = new PlayerInfoPacket.AddPlayer(getUuid(), getUsername(), GameMode.CREATIVE, 10); PlayerInfoPacket.AddPlayer addP = new PlayerInfoPacket.AddPlayer(getUuid(), getUsername(), GameMode.CREATIVE, 10);
@ -241,7 +259,7 @@ public class Player extends LivingEntity {
player.playerConnection.sendPacket(playerInfoPacket); player.playerConnection.sendPacket(playerInfoPacket);
} }
public void sendBlockBreakAnimation(Position blockPosition, byte destroyStage) { public void sendBlockBreakAnimation(BlockPosition blockPosition, byte destroyStage) {
BlockBreakAnimationPacket breakAnimationPacket = new BlockBreakAnimationPacket(); BlockBreakAnimationPacket breakAnimationPacket = new BlockBreakAnimationPacket();
breakAnimationPacket.entityId = getEntityId() + 1; breakAnimationPacket.entityId = getEntityId() + 1;
breakAnimationPacket.blockPosition = blockPosition; breakAnimationPacket.blockPosition = blockPosition;
@ -255,13 +273,12 @@ public class Player extends LivingEntity {
playerConnection.sendPacket(chatMessagePacket); 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(); PlayerPositionAndLookPacket positionAndLookPacket = new PlayerPositionAndLookPacket();
positionAndLookPacket.x = x; positionAndLookPacket.position = position;
positionAndLookPacket.y = y;
positionAndLookPacket.z = z;
positionAndLookPacket.yaw = getYaw();
positionAndLookPacket.pitch = getPitch();
positionAndLookPacket.flags = 0x00; positionAndLookPacket.flags = 0x00;
positionAndLookPacket.teleportId = 67; positionAndLookPacket.teleportId = 67;
getPlayerConnection().sendPacket(positionAndLookPacket); getPlayerConnection().sendPacket(positionAndLookPacket);
@ -275,14 +292,34 @@ public class Player extends LivingEntity {
return playerConnection; return playerConnection;
} }
public PlayerSettings getSettings() {
return settings;
}
public PlayerInventory getInventory() { public PlayerInventory getInventory() {
return inventory; return inventory;
} }
public Dimension getDimension() {
return dimension;
}
public GameMode getGameMode() { public GameMode getGameMode() {
return gameMode; 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) { public void kick(String message) {
DisconnectPacket disconnectPacket = new DisconnectPacket(); DisconnectPacket disconnectPacket = new DisconnectPacket();
disconnectPacket.message = message; disconnectPacket.message = message;
@ -290,6 +327,10 @@ public class Player extends LivingEntity {
playerConnection.getConnection().close(); playerConnection.getConnection().close();
} }
public LevelType getLevelType() {
return levelType;
}
public void setGameMode(GameMode gameMode) { public void setGameMode(GameMode gameMode) {
ChangeGameStatePacket changeGameStatePacket = new ChangeGameStatePacket(); ChangeGameStatePacket changeGameStatePacket = new ChangeGameStatePacket();
changeGameStatePacket.reason = ChangeGameStatePacket.Reason.CHANGE_GAMEMODE; 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) { public void refreshGameMode(GameMode gameMode) {
this.gameMode = gameMode; this.gameMode = gameMode;
} }
public void refreshLevelType(LevelType levelType) {
this.levelType = levelType;
}
public void refreshOnGround(boolean onGround) { public void refreshOnGround(boolean onGround) {
this.onGround = onGround; this.onGround = onGround;
} }
@ -397,7 +446,7 @@ public class Player extends LivingEntity {
this.openInventory = openInventory; this.openInventory = openInventory;
} }
public void refreshTargetBlock(CustomBlock targetCustomBlock, Position targetBlockPosition) { public void refreshTargetBlock(CustomBlock targetCustomBlock, BlockPosition targetBlockPosition) {
this.targetCustomBlock = targetCustomBlock; this.targetCustomBlock = targetCustomBlock;
this.targetBlockPosition = targetBlockPosition; this.targetBlockPosition = targetBlockPosition;
this.targetBlockTime = targetBlockPosition == null ? 0 : System.currentTimeMillis(); this.targetBlockTime = targetBlockPosition == null ? 0 : System.currentTimeMillis();
@ -430,4 +479,59 @@ public class Player extends LivingEntity {
MAIN, MAIN,
OFF 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 @Override
public void update() { public void update() {
float speed = 0.075f; float speed = 0.05f;
/*if (hasPassenger()) { /*if (hasPassenger()) {
Entity passenger = getPassengers().iterator().next(); Entity passenger = getPassengers().iterator().next();
@ -41,6 +41,7 @@ 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);
} }
} }

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

View File

@ -8,7 +8,7 @@ public class AnimationListener {
public static void animationListener(ClientAnimationPacket packet, Player player) { public static void animationListener(ClientAnimationPacket packet, Player player) {
AnimationPacket animationPacket = new AnimationPacket(); 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; animationPacket.animation = packet.hand == Player.Hand.MAIN ? AnimationPacket.Animation.SWING_MAIN_ARM : AnimationPacket.Animation.SWING_OFF_HAND;
player.sendPacketToViewers(animationPacket); 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.instance.Instance;
import fr.themode.minestom.net.packet.client.play.ClientPlayerBlockPlacementPacket; import fr.themode.minestom.net.packet.client.play.ClientPlayerBlockPlacementPacket;
import fr.themode.minestom.net.packet.client.play.ClientPlayerDiggingPacket; 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 class BlockPlacementListener {
public static void listener(ClientPlayerBlockPlacementPacket packet, Player player) { public static void listener(ClientPlayerBlockPlacementPacket packet, Player player) {
ClientPlayerDiggingPacket.BlockFace blockFace = packet.blockFace; ClientPlayerDiggingPacket.BlockFace blockFace = packet.blockFace;
Position position = packet.position; BlockPosition blockPosition = packet.blockPosition;
Instance instance = player.getInstance(); Instance instance = player.getInstance();
if (instance == null) if (instance == null)
@ -25,10 +25,10 @@ public class BlockPlacementListener {
BlockPlaceEvent blockPlaceEvent = new BlockPlaceEvent((short) 10); BlockPlaceEvent blockPlaceEvent = new BlockPlaceEvent((short) 10);
player.callEvent(BlockPlaceEvent.class, blockPlaceEvent); player.callEvent(BlockPlaceEvent.class, blockPlaceEvent);
if (!blockPlaceEvent.isCancelled()) { 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 // TODO consume block in hand for survival players
} else { } else {
Chunk chunk = instance.getChunkAt(position); Chunk chunk = instance.getChunkAt(blockPosition);
instance.sendChunkUpdate(player, chunk); instance.sendChunkUpdate(player, chunk);
} }
player.getInventory().refreshSlot(player.getHeldSlot()); player.getInventory().refreshSlot(player.getHeldSlot());

View File

@ -27,7 +27,10 @@ public class PacketListenerManager {
addListener(ClientPlayerPositionAndLookPacket.class, PlayerPositionListener::playerPositionAndLookListener); addListener(ClientPlayerPositionAndLookPacket.class, PlayerPositionListener::playerPositionAndLookListener);
addListener(ClientPlayerDiggingPacket.class, PlayerDiggingListener::playerDiggingListener); addListener(ClientPlayerDiggingPacket.class, PlayerDiggingListener::playerDiggingListener);
addListener(ClientAnimationPacket.class, AnimationListener::animationListener); 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) { 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.client.play.ClientPlayerDiggingPacket;
import fr.themode.minestom.net.packet.server.play.EntityEffectPacket; import fr.themode.minestom.net.packet.server.play.EntityEffectPacket;
import fr.themode.minestom.net.packet.server.play.RemoveEntityEffectPacket; 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 class PlayerDiggingListener {
public static void playerDiggingListener(ClientPlayerDiggingPacket packet, Player player) { public static void playerDiggingListener(ClientPlayerDiggingPacket packet, Player player) {
ClientPlayerDiggingPacket.Status status = packet.status; ClientPlayerDiggingPacket.Status status = packet.status;
Position position = packet.position; BlockPosition blockPosition = packet.blockPosition;
switch (status) { switch (status) {
case STARTED_DIGGING: case STARTED_DIGGING:
if (player.getGameMode() == GameMode.CREATIVE) { if (player.getGameMode() == GameMode.CREATIVE) {
Instance instance = player.getInstance(); Instance instance = player.getInstance();
if (instance != null) { 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) { } else if (player.getGameMode() == GameMode.SURVIVAL) {
Instance instance = player.getInstance(); Instance instance = player.getInstance();
if (instance != null) { 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) { if (customBlock != null) {
StartDiggingEvent startDiggingEvent = new StartDiggingEvent(customBlock); StartDiggingEvent startDiggingEvent = new StartDiggingEvent(customBlock);
player.callEvent(StartDiggingEvent.class, startDiggingEvent); player.callEvent(StartDiggingEvent.class, startDiggingEvent);
if (!startDiggingEvent.isCancelled()) { if (!startDiggingEvent.isCancelled()) {
player.refreshTargetBlock(customBlock, position); player.refreshTargetBlock(customBlock, blockPosition);
} }
addEffect(player); addEffect(player);
} else { } else {
@ -41,7 +41,7 @@ public class PlayerDiggingListener {
} }
break; break;
case CANCELLED_DIGGING: case CANCELLED_DIGGING:
player.sendBlockBreakAnimation(position, (byte) -1); player.sendBlockBreakAnimation(blockPosition, (byte) -1);
player.resetTargetBlock(); player.resetTargetBlock();
removeEffect(player); removeEffect(player);
break; break;
@ -52,8 +52,8 @@ public class PlayerDiggingListener {
} else { } else {
Instance instance = player.getInstance(); Instance instance = player.getInstance();
if (instance != null) { if (instance != null) {
short blockId = instance.getBlockId(position); short blockId = instance.getBlockId(blockPosition);
instance.breakBlock(player, position, blockId); instance.breakBlock(player, blockPosition, blockId);
} }
} }
break; break;

View File

@ -1,6 +1,7 @@
package fr.themode.minestom.listener; package fr.themode.minestom.listener;
import fr.themode.minestom.entity.Player; 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.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;
@ -15,29 +16,44 @@ public class PlayerPositionListener {
public static void playerLookListener(ClientPlayerLookPacket packet, Player player) { public static void playerLookListener(ClientPlayerLookPacket packet, Player player) {
player.refreshView(packet.yaw, packet.pitch); player.refreshView(packet.yaw, packet.pitch);
player.refreshOnGround(packet.onGround); player.refreshOnGround(packet.onGround);
// TODO move event?
} }
public static void playerPositionListener(ClientPlayerPositionPacket packet, Player player) { public static void playerPositionListener(ClientPlayerPositionPacket packet, Player player) {
boolean chunkTest = player.chunkTest(packet.x, packet.z); float x = (float) packet.x;
if (chunkTest) { float y = (float) packet.y;
player.teleport(player.getX(), player.getY(), player.getZ()); float z = (float) packet.z;
return; processMovement(player, x, y, z, () -> {
} player.refreshPosition(x, y, z);
player.refreshOnGround(packet.onGround);
player.refreshPosition(packet.x, packet.y, packet.z); });
player.refreshOnGround(packet.onGround);
} }
public static void playerPositionAndLookListener(ClientPlayerPositionAndLookPacket packet, Player player) { 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) { if (chunkTest) {
player.teleport(player.getX(), player.getY(), player.getZ()); player.teleport(player.getPosition());
return; return;
} }
player.refreshPosition(packet.x, packet.y, packet.z); PlayerMoveEvent playerMoveEvent = new PlayerMoveEvent(x, y, z);
player.refreshView(packet.yaw, packet.pitch); player.callEvent(PlayerMoveEvent.class, playerMoveEvent);
player.refreshOnGround(packet.onGround); 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(); 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 { public void process(Connection connection, Packet packet) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
int id = packet.get(PACKET_ID_IDENTIFIER); int id = packet.get(PACKET_ID_IDENTIFIER);
if (!printBlackList.contains(id)) { if (!printBlackList.contains(id)) {
// System.out.println("RECEIVED ID: " + id); System.out.println("RECEIVED ID: " + id);
} }
Buffer buffer = packet.getPayload(); Buffer buffer = packet.getPayload();
connectionPlayerConnectionMap.get(connection); connectionPlayerConnectionMap.get(connection);

View File

@ -25,5 +25,7 @@ public class ClientPlayPacketsHandler extends ClientPacketsHandler {
register(0x0A, ClientCloseWindow.class); register(0x0A, ClientCloseWindow.class);
register(0x07, ClientConfirmTransactionPacket.class); register(0x07, ClientConfirmTransactionPacket.class);
register(0x1C, ClientSteerVehiclePacket.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.net.player.PlayerConnection;
import fr.themode.minestom.utils.Utils; import fr.themode.minestom.utils.Utils;
import fr.themode.minestom.world.Dimension; import fr.themode.minestom.world.Dimension;
import fr.themode.minestom.world.LevelType;
import java.util.UUID; import java.util.UUID;
@ -67,20 +68,24 @@ public class LoginStartPacket implements ClientPreplayPacket {
connectionManager.createPlayer(playerUuid, username, connection); connectionManager.createPlayer(playerUuid, username, connection);
Player player = connectionManager.getPlayer(connection); Player player = connectionManager.getPlayer(connection);
GameMode gameMode = GameMode.SURVIVAL; GameMode gameMode = GameMode.SURVIVAL;
Dimension dimension = Dimension.OVERWORLD;
LevelType levelType = LevelType.DEFAULT;
float x = 5; float x = 5;
float y = 5; float y = 5;
float z = 5; float z = 5;
player.refreshDimension(dimension);
player.refreshGameMode(gameMode); player.refreshGameMode(gameMode);
player.refreshLevelType(levelType);
player.refreshPosition(x, y, z); player.refreshPosition(x, y, z);
// TODO complete login sequence with optionals packets // TODO complete login sequence with optionals packets
JoinGamePacket joinGamePacket = new JoinGamePacket(); JoinGamePacket joinGamePacket = new JoinGamePacket();
joinGamePacket.entityId = player.getEntityId(); joinGamePacket.entityId = player.getEntityId();
joinGamePacket.gameMode = gameMode; joinGamePacket.gameMode = gameMode;
joinGamePacket.dimension = Dimension.OVERWORLD; joinGamePacket.dimension = dimension;
joinGamePacket.maxPlayers = 0; // Unused joinGamePacket.maxPlayers = 0; // Unused
joinGamePacket.levelType = "default"; joinGamePacket.levelType = levelType;
joinGamePacket.viewDistance = 14; joinGamePacket.viewDistance = 14;
joinGamePacket.reducedDebugInfo = false; joinGamePacket.reducedDebugInfo = false;
connection.sendPacket(joinGamePacket); connection.sendPacket(joinGamePacket);
@ -99,11 +104,7 @@ public class LoginStartPacket implements ClientPreplayPacket {
connection.sendPacket(spawnPositionPacket); connection.sendPacket(spawnPositionPacket);
PlayerPositionAndLookPacket playerPositionAndLookPacket = new PlayerPositionAndLookPacket(); PlayerPositionAndLookPacket playerPositionAndLookPacket = new PlayerPositionAndLookPacket();
playerPositionAndLookPacket.x = x; playerPositionAndLookPacket.position = player.getPosition();
playerPositionAndLookPacket.y = y;
playerPositionAndLookPacket.z = z;
playerPositionAndLookPacket.yaw = 0;
playerPositionAndLookPacket.pitch = 0;
playerPositionAndLookPacket.flags = 0; playerPositionAndLookPacket.flags = 0;
playerPositionAndLookPacket.teleportId = 42; playerPositionAndLookPacket.teleportId = 42;
connection.sendPacket(playerPositionAndLookPacket); connection.sendPacket(playerPositionAndLookPacket);
@ -120,12 +121,10 @@ public class LoginStartPacket implements ClientPreplayPacket {
for (int cx = 0; cx < 4; cx++) for (int cx = 0; cx < 4; cx++)
for (int cz = 0; cz < 4; cz++) { for (int cz = 0; cz < 4; cz++) {
ChickenCreature chickenCreature = new ChickenCreature(); ChickenCreature chickenCreature = new ChickenCreature();
chickenCreature.refreshPosition(0 + (double) cx * 1, 5, 0 + (double) cz * 1); chickenCreature.refreshPosition(0 + (float) cx * 1, 5, 0 + (float) cz * 1);
chickenCreature.setOnFire(true); //chickenCreature.setOnFire(true);
chickenCreature.setInstance(instance); chickenCreature.setInstance(instance);
if (cx == 3 && cz == 3) { //chickenCreature.addPassenger(player);
//chickenCreature.addPassenger(player);
}
} }
PlayerInventory inventory = player.getInventory(); 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.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.net.packet.client.ClientPlayPacket; 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; import fr.themode.minestom.utils.Utils;
public class ClientPlayerBlockPlacementPacket extends ClientPlayPacket { public class ClientPlayerBlockPlacementPacket extends ClientPlayPacket {
public Hand hand; public Hand hand;
public Position position; public BlockPosition blockPosition;
public ClientPlayerDiggingPacket.BlockFace blockFace; public ClientPlayerDiggingPacket.BlockFace blockFace;
public float cursorPositionX, cursorPositionY, cursorPositionZ; public float cursorPositionX, cursorPositionY, cursorPositionZ;
public boolean insideBlock; public boolean insideBlock;
@ -16,7 +16,7 @@ public class ClientPlayerBlockPlacementPacket extends ClientPlayPacket {
@Override @Override
public void read(Buffer buffer) { public void read(Buffer buffer) {
this.hand = Hand.values()[Utils.readVarInt(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.blockFace = ClientPlayerDiggingPacket.BlockFace.values()[Utils.readVarInt(buffer)];
this.cursorPositionX = buffer.getFloat(); this.cursorPositionX = buffer.getFloat();
this.cursorPositionY = 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.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.net.packet.client.ClientPlayPacket; 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; import fr.themode.minestom.utils.Utils;
public class ClientPlayerDiggingPacket extends ClientPlayPacket { public class ClientPlayerDiggingPacket extends ClientPlayPacket {
public Status status; public Status status;
public Position position; public BlockPosition blockPosition;
public BlockFace blockFace; public BlockFace blockFace;
@Override @Override
public void read(Buffer buffer) { public void read(Buffer buffer) {
this.status = Status.values()[Utils.readVarInt(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)]; this.blockFace = BlockFace.values()[Utils.readVarInt(buffer)];
} }

View File

@ -1,6 +1,7 @@
package fr.themode.minestom.net.packet.client.play; package fr.themode.minestom.net.packet.client.play;
import fr.adamaq01.ozao.net.Buffer; import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.entity.Player;
import fr.themode.minestom.net.packet.client.ClientPlayPacket; import fr.themode.minestom.net.packet.client.ClientPlayPacket;
import fr.themode.minestom.utils.Utils; import fr.themode.minestom.utils.Utils;
@ -8,18 +9,18 @@ public class ClientSettingsPacket extends ClientPlayPacket {
public String locale; public String locale;
public byte viewDistance; public byte viewDistance;
// TODO chat mode public Player.ChatMode chatMode;
public boolean chatColors; public boolean chatColors;
public byte displayedSkinParts; public byte displayedSkinParts;
// TODO main hand public Player.MainHand mainHand;
@Override @Override
public void read(Buffer buffer) { public void read(Buffer buffer) {
this.locale = Utils.readString(buffer); this.locale = Utils.readString(buffer);
this.viewDistance = buffer.getByte(); this.viewDistance = buffer.getByte();
Utils.readVarInt(buffer); // chat mode this.chatMode = Player.ChatMode.values()[Utils.readVarInt(buffer)];
this.chatColors = buffer.getBoolean(); this.chatColors = buffer.getBoolean();
this.displayedSkinParts = buffer.getByte(); 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 { public class ClientUseEntityPacket extends ClientPlayPacket {
private int target; public int targetId;
private Type type; public Type type;
private float x; public float x;
private float y; public float y;
private float z; public float z;
private Player.Hand hand; public Player.Hand hand;
@Override @Override
public void read(Buffer buffer) { public void read(Buffer buffer) {
this.target = Utils.readVarInt(buffer); this.targetId = Utils.readVarInt(buffer);
this.type = Type.values()[Utils.readVarInt(buffer)]; this.type = Type.values()[Utils.readVarInt(buffer)];
if (this.type == Type.INTERACT_AT) { if (this.type == Type.INTERACT_AT) {
this.x = buffer.getFloat(); this.x = buffer.getFloat();
@ -28,7 +28,6 @@ public class ClientUseEntityPacket extends ClientPlayPacket {
} }
public enum Type { public enum Type {
INTERACT, INTERACT,
ATTACK, ATTACK,
INTERACT_AT; 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.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Utils; import fr.themode.minestom.utils.Utils;
import fr.themode.minestom.world.Dimension; import fr.themode.minestom.world.Dimension;
import fr.themode.minestom.world.LevelType;
public class JoinGamePacket implements ServerPacket { public class JoinGamePacket implements ServerPacket {
@ -12,7 +13,7 @@ public class JoinGamePacket implements ServerPacket {
public GameMode gameMode = GameMode.SURVIVAL; public GameMode gameMode = GameMode.SURVIVAL;
public Dimension dimension = Dimension.OVERWORLD; public Dimension dimension = Dimension.OVERWORLD;
public byte maxPlayers = 0; // Unused public byte maxPlayers = 0; // Unused
public String levelType = "default"; public LevelType levelType;
public int viewDistance; public int viewDistance;
public boolean reducedDebugInfo = false; public boolean reducedDebugInfo = false;
@ -26,7 +27,7 @@ public class JoinGamePacket implements ServerPacket {
buffer.putByte((byte) gameModeId); buffer.putByte((byte) gameModeId);
buffer.putInt(dimension.getId()); buffer.putInt(dimension.getId());
buffer.putByte(maxPlayers); buffer.putByte(maxPlayers);
Utils.writeString(buffer, levelType); Utils.writeString(buffer, levelType.getType());
Utils.writeVarInt(buffer, viewDistance); Utils.writeVarInt(buffer, viewDistance);
buffer.putBoolean(reducedDebugInfo); 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.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.net.packet.client.play.ClientPlayerDiggingPacket; import fr.themode.minestom.net.packet.client.play.ClientPlayerDiggingPacket;
import fr.themode.minestom.net.packet.server.ServerPacket; 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; import fr.themode.minestom.utils.Utils;
public class AcknowledgePlayerDiggingPacket implements ServerPacket { public class AcknowledgePlayerDiggingPacket implements ServerPacket {
public Position position; public BlockPosition blockPosition;
public int blockStateId; public int blockStateId;
public ClientPlayerDiggingPacket.Status status; public ClientPlayerDiggingPacket.Status status;
public boolean successful; public boolean successful;
@Override @Override
public void write(Buffer buffer) { public void write(Buffer buffer) {
Utils.writePosition(buffer, position); Utils.writePosition(buffer, blockPosition);
Utils.writeVarInt(buffer, blockStateId); Utils.writeVarInt(buffer, blockStateId);
Utils.writeVarInt(buffer, status.ordinal()); Utils.writeVarInt(buffer, status.ordinal());
buffer.putBoolean(successful); buffer.putBoolean(successful);

View File

@ -6,12 +6,12 @@ import fr.themode.minestom.utils.Utils;
public class AnimationPacket implements ServerPacket { public class AnimationPacket implements ServerPacket {
public int playerId; // FIXME verify if this is only player? public int entityId;
public Animation animation; public Animation animation;
@Override @Override
public void write(Buffer buffer) { public void write(Buffer buffer) {
Utils.writeVarInt(buffer, playerId); Utils.writeVarInt(buffer, entityId);
buffer.putByte((byte) animation.ordinal()); 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.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.net.packet.server.ServerPacket; 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; import fr.themode.minestom.utils.Utils;
public class BlockBreakAnimationPacket implements ServerPacket { public class BlockBreakAnimationPacket implements ServerPacket {
public int entityId; public int entityId;
public Position blockPosition; public BlockPosition blockPosition;
public byte destroyStage; public byte destroyStage;
@Override @Override

View File

@ -2,17 +2,17 @@ package fr.themode.minestom.net.packet.server.play;
import fr.adamaq01.ozao.net.Buffer; import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.net.packet.server.ServerPacket; 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; import fr.themode.minestom.utils.Utils;
public class BlockChangePacket implements ServerPacket { public class BlockChangePacket implements ServerPacket {
public Position position; public BlockPosition blockPosition;
public int blockId; public int blockId;
@Override @Override
public void write(Buffer buffer) { 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); Utils.writeVarInt(buffer, blockId);
} }

View File

@ -29,7 +29,7 @@ public class ChunkDataPacket implements ServerPacket {
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
// TODO if fullchunk is false then only send changed sections // TODO if fullchunk is false then only send changed sections
mask |= 1 << i; mask |= 1 << i;
Short[] section = getSection(chunk, i); short[] section = getSection(chunk, i);
Utils.writeBlocks(blocks, section, 14); Utils.writeBlocks(blocks, section, 14);
} }
// Biome data // Biome data
@ -72,8 +72,8 @@ public class ChunkDataPacket implements ServerPacket {
Utils.writeVarInt(buffer, 0); Utils.writeVarInt(buffer, 0);
} }
private Short[] getSection(Chunk chunk, int section) { private short[] getSection(Chunk chunk, int section) {
Short[] blocks = new Short[16 * 16 * 16]; short[] blocks = new short[16 * 16 * 16];
for (byte y = 0; y < 16; y++) { for (byte y = 0; y < 16; y++) {
for (byte x = 0; x < 16; x++) { for (byte x = 0; x < 16; x++) {
for (byte z = 0; z < 16; z++) { 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.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.net.packet.server.ServerPacket; import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Position;
import fr.themode.minestom.utils.Utils; import fr.themode.minestom.utils.Utils;
public class EntityTeleportPacket implements ServerPacket { public class EntityTeleportPacket implements ServerPacket {
public int entityId; public int entityId;
public double x, y, z; public Position position;
public float yaw, pitch;
public boolean onGround; public boolean onGround;
@Override @Override
public void write(Buffer buffer) { public void write(Buffer buffer) {
Utils.writeVarInt(buffer, entityId); Utils.writeVarInt(buffer, entityId);
buffer.putDouble(x); buffer.putDouble(position.getX());
buffer.putDouble(y); buffer.putDouble(position.getY());
buffer.putDouble(z); buffer.putDouble(position.getZ());
buffer.putByte((byte) (this.yaw * 256 / 360)); buffer.putByte((byte) (position.getYaw() * 256f / 360f));
buffer.putByte((byte) (this.pitch * 256 / 360)); buffer.putByte((byte) (position.getPitch() * 256f / 360f));
buffer.putBoolean(onGround); 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.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.net.packet.server.ServerPacket; import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Position;
import fr.themode.minestom.utils.Utils; import fr.themode.minestom.utils.Utils;
public class PlayerPositionAndLookPacket implements ServerPacket { public class PlayerPositionAndLookPacket implements ServerPacket {
public double x, y, z; public Position position;
public float yaw, pitch;
public byte flags; public byte flags;
public int teleportId; public int teleportId;
@Override @Override
public void write(Buffer buffer) { public void write(Buffer buffer) {
buffer.putDouble(x); buffer.putDouble(position.getX());
buffer.putDouble(y); buffer.putDouble(position.getY());
buffer.putDouble(z); buffer.putDouble(position.getZ());
buffer.putFloat(yaw); buffer.putFloat(position.getYaw());
buffer.putFloat(pitch); buffer.putFloat(position.getPitch());
buffer.putBytes(flags); buffer.putBytes(flags);
Utils.writeVarInt(buffer, teleportId); 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.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.net.packet.server.ServerPacket; import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Position;
import fr.themode.minestom.utils.Utils; import fr.themode.minestom.utils.Utils;
import java.util.UUID; import java.util.UUID;
@ -11,8 +12,7 @@ public class SpawnMobPacket implements ServerPacket {
public int entityId; public int entityId;
public UUID entityUuid; public UUID entityUuid;
public int entityType; public int entityType;
public double x, y, z; public Position position;
public float yaw, pitch;
public float headPitch; public float headPitch;
public short velocityX, velocityY, velocityZ; public short velocityX, velocityY, velocityZ;
// TODO metadata // TODO metadata
@ -22,11 +22,11 @@ public class SpawnMobPacket implements ServerPacket {
Utils.writeVarInt(buffer, entityId); Utils.writeVarInt(buffer, entityId);
Utils.writeUuid(buffer, entityUuid); Utils.writeUuid(buffer, entityUuid);
Utils.writeVarInt(buffer, entityType); Utils.writeVarInt(buffer, entityType);
buffer.putDouble(x); buffer.putDouble(position.getX());
buffer.putDouble(y); buffer.putDouble(position.getY());
buffer.putDouble(z); buffer.putDouble(position.getZ());
buffer.putFloat(yaw); buffer.putFloat(position.getYaw());
buffer.putFloat(pitch); buffer.putFloat(position.getPitch());
buffer.putFloat(headPitch); buffer.putFloat(headPitch);
buffer.putShort(velocityX); buffer.putShort(velocityX);
buffer.putShort(velocityY); 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.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.net.packet.server.ServerPacket; import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Position;
import fr.themode.minestom.utils.Utils; import fr.themode.minestom.utils.Utils;
import java.util.UUID; import java.util.UUID;
@ -11,8 +12,7 @@ public class SpawnObjectPacket implements ServerPacket {
public int entityId; public int entityId;
public UUID uuid; public UUID uuid;
public int type; public int type;
public double x, y, z; public Position position;
public float yaw, pitch;
public int data; public int data;
@Override @Override
@ -20,11 +20,11 @@ public class SpawnObjectPacket implements ServerPacket {
Utils.writeVarInt(buffer, entityId); Utils.writeVarInt(buffer, entityId);
Utils.writeUuid(buffer, uuid); Utils.writeUuid(buffer, uuid);
Utils.writeVarInt(buffer, type); Utils.writeVarInt(buffer, type);
buffer.putDouble(x); buffer.putDouble(position.getX());
buffer.putDouble(y); buffer.putDouble(position.getY());
buffer.putDouble(z); buffer.putDouble(position.getZ());
buffer.putFloat(yaw); buffer.putFloat(position.getYaw());
buffer.putFloat(pitch); buffer.putFloat(position.getPitch());
buffer.putInt(data); 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.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.net.packet.server.ServerPacket; import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Position;
import fr.themode.minestom.utils.Utils; import fr.themode.minestom.utils.Utils;
import java.util.UUID; import java.util.UUID;
@ -10,22 +11,18 @@ public class SpawnPlayerPacket implements ServerPacket {
public int entityId; public int entityId;
public UUID playerUuid; public UUID playerUuid;
public double x; public Position position;
public double y;
public double z;
public float yaw;
public float pitch;
@Override @Override
public void write(Buffer buffer) { public void write(Buffer buffer) {
Utils.writeVarInt(buffer, entityId); Utils.writeVarInt(buffer, entityId);
buffer.putLong(playerUuid.getMostSignificantBits()); buffer.putLong(playerUuid.getMostSignificantBits());
buffer.putLong(playerUuid.getLeastSignificantBits()); buffer.putLong(playerUuid.getLeastSignificantBits());
buffer.putDouble(x); buffer.putDouble(position.getX());
buffer.putDouble(y); buffer.putDouble(position.getY());
buffer.putDouble(z); buffer.putDouble(position.getZ());
buffer.putByte((byte) (yaw * 256 / 360)); buffer.putByte((byte) (position.getYaw() * 256f / 360f));
buffer.putByte((byte) (pitch * 256 / 360)); buffer.putByte((byte) (position.getPitch() * 256f / 360f));
buffer.putByte((byte) 0xff); // TODO Metadata 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; package fr.themode.minestom.net.packet.server.play;
import fr.adamaq01.ozao.net.Buffer; import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.instance.Chunk;
import fr.themode.minestom.net.packet.server.ServerPacket; import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Utils; import fr.themode.minestom.utils.Utils;
public class UpdateViewPositionPacket implements ServerPacket { public class UpdateViewPositionPacket implements ServerPacket {
private int chunkX; private Chunk chunk;
private int chunkZ;
public UpdateViewPositionPacket(int chunkX, int chunkZ) { public UpdateViewPositionPacket(Chunk chunk) {
this.chunkX = chunkX; this.chunk = chunk;
this.chunkZ = chunkZ;
} }
@Override @Override
public void write(Buffer buffer) { public void write(Buffer buffer) {
Utils.writeVarInt(buffer, chunkX); Utils.writeVarInt(buffer, chunk.getChunkX());
Utils.writeVarInt(buffer, chunkZ); Utils.writeVarInt(buffer, chunk.getChunkZ());
} }
@Override @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 { 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.x = x;
this.y = y; this.y = y;
this.z = z; 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; return x;
} }
public void setX(int x) { public void setX(float x) {
this.x = x; this.x = x;
} }
public int getY() { public float getY() {
return y; return y;
} }
public void setY(int y) { public void setY(float y) {
this.y = y; this.y = y;
} }
public int getZ() { public float getZ() {
return z; return z;
} }
public void setZ(int z) { public void setZ(float z) {
this.z = z; this.z = z;
} }
@Override public float getYaw() {
public String toString() { return yaw;
return "Position[" + x + ":" + y + ":" + z + "]"; }
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 fr.themode.minestom.item.ItemStack;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors;
public class Utils { public class Utils {
@ -125,16 +123,16 @@ public class Utils {
buffer.putLong((((long) x & 0x3FFFFFF) << 38) | (((long) z & 0x3FFFFFF) << 12) | ((long) y & 0xFFF)); buffer.putLong((((long) x & 0x3FFFFFF) << 38) | (((long) z & 0x3FFFFFF) << 12) | ((long) y & 0xFFF));
} }
public static void writePosition(Buffer buffer, Position position) { public static void writePosition(Buffer buffer, BlockPosition blockPosition) {
writePosition(buffer, position.getX(), position.getY(), position.getZ()); writePosition(buffer, blockPosition.getX(), blockPosition.getY(), blockPosition.getZ());
} }
public static Position readPosition(Buffer buffer) { public static BlockPosition readPosition(Buffer buffer) {
long val = buffer.getLong(); long val = buffer.getLong();
int x = (int) (val >> 38); int x = (int) (val >> 38);
int y = (int) (val & 0xFFF); int y = (int) (val & 0xFFF);
int z = (int) (val << 26 >> 38); 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) { 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) { public static void writeBlocks(Buffer buffer, short[] blocksId, int bitsPerEntry) {
buffer.putShort((short) Arrays.stream(blocksId).filter(customBlock -> customBlock != 0).collect(Collectors.toList()).size()); short count = 0;
for (short id : blocksId)
if (id != 0)
count++;
buffer.putShort(count);
buffer.putByte((byte) bitsPerEntry); buffer.putByte((byte) bitsPerEntry);
int[] blocksData = new int[16 * 16 * 16]; int[] blocksData = new int[16 * 16 * 16];
for (int y = 0; y < 16; y++) { 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;
}
}