From 9d8e4e7ea2d93ebf09d23eee79a7e1fd51c0d5b3 Mon Sep 17 00:00:00 2001 From: TheMode Date: Tue, 20 Aug 2019 22:40:57 +0200 Subject: [PATCH] Multiplayer synchronization --- src/main/java/fr/themode/minestom/Main.java | 18 +- .../fr/themode/minestom/entity/Entity.java | 65 ++++-- .../fr/themode/minestom/entity/Player.java | 205 +++++++++++++----- .../minestom/event/BlockBreakEvent.java | 16 ++ .../themode/minestom/instance/Instance.java | 47 +++- .../minestom/inventory/PlayerInventory.java | 90 ++++++-- .../minestom/listener/AnimationListener.java | 16 ++ .../minestom/listener/KeepAliveListener.java | 5 +- .../listener/PacketListenerManager.java | 1 + .../listener/PlayerDiggingListener.java | 4 +- .../packet/client/login/LoginStartPacket.java | 83 +++---- .../packet/server/play/AnimationPacket.java | 31 +++ .../packet/server/play/DisconnectPacket.java | 9 +- .../server/play/EntityEquipmentPacket.java | 35 +++ .../server/play/EntityHeadLookPacket.java | 22 ++ .../packet/server/play/EntityLookPacket.java | 25 +++ .../packet/server/play/PlayerInfoPacket.java | 2 +- .../packet/server/play/SpawnPlayerPacket.java | 8 +- 18 files changed, 505 insertions(+), 177 deletions(-) create mode 100644 src/main/java/fr/themode/minestom/event/BlockBreakEvent.java create mode 100644 src/main/java/fr/themode/minestom/listener/AnimationListener.java create mode 100644 src/main/java/fr/themode/minestom/net/packet/server/play/AnimationPacket.java create mode 100644 src/main/java/fr/themode/minestom/net/packet/server/play/EntityEquipmentPacket.java create mode 100644 src/main/java/fr/themode/minestom/net/packet/server/play/EntityHeadLookPacket.java create mode 100644 src/main/java/fr/themode/minestom/net/packet/server/play/EntityLookPacket.java diff --git a/src/main/java/fr/themode/minestom/Main.java b/src/main/java/fr/themode/minestom/Main.java index 4c36fe09e..fe1e35c15 100644 --- a/src/main/java/fr/themode/minestom/Main.java +++ b/src/main/java/fr/themode/minestom/Main.java @@ -8,14 +8,13 @@ import fr.adamaq01.ozao.net.server.backend.tcp.TCPServer; import fr.themode.minestom.entity.EntityManager; import fr.themode.minestom.entity.Player; import fr.themode.minestom.instance.BlockManager; +import fr.themode.minestom.instance.Instance; import fr.themode.minestom.instance.InstanceManager; import fr.themode.minestom.instance.demo.StoneBlock; import fr.themode.minestom.listener.PacketListenerManager; import fr.themode.minestom.net.ConnectionManager; import fr.themode.minestom.net.PacketProcessor; -import fr.themode.minestom.net.packet.server.play.DestroyEntitiesPacket; import fr.themode.minestom.net.packet.server.play.KeepAlivePacket; -import fr.themode.minestom.net.packet.server.play.PlayerInfoPacket; import fr.themode.minestom.net.protocol.MinecraftProtocol; import java.lang.reflect.InvocationTargetException; @@ -59,18 +58,13 @@ public class Main { if (connectionManager.getPlayer(packetProcessor.getPlayerConnection(connection)) != null) { Player player = connectionManager.getPlayer(packetProcessor.getPlayerConnection(connection)); player.remove(); - connectionManager.removePlayer(packetProcessor.getPlayerConnection(connection)); - PlayerInfoPacket playerInfoPacket = new PlayerInfoPacket(PlayerInfoPacket.Action.REMOVE_PLAYER); - playerInfoPacket.playerInfos.add(new PlayerInfoPacket.RemovePlayer(player.getUuid())); - DestroyEntitiesPacket destroyEntitiesPacket = new DestroyEntitiesPacket(); - destroyEntitiesPacket.entityIds = new int[]{player.getEntityId()}; - for (Player onlinePlayer : connectionManager.getOnlinePlayers()) { - if (!onlinePlayer.equals(player)) { - onlinePlayer.getPlayerConnection().sendPacket(destroyEntitiesPacket); - onlinePlayer.getPlayerConnection().sendPacket(playerInfoPacket); - } + Instance instance = player.getInstance(); + if (instance != null) { + instance.removeEntity(player); } + + connectionManager.removePlayer(packetProcessor.getPlayerConnection(connection)); } packetProcessor.removePlayerConnection(connection); } diff --git a/src/main/java/fr/themode/minestom/entity/Entity.java b/src/main/java/fr/themode/minestom/entity/Entity.java index 8b1c0058c..a7484171d 100644 --- a/src/main/java/fr/themode/minestom/entity/Entity.java +++ b/src/main/java/fr/themode/minestom/entity/Entity.java @@ -9,6 +9,8 @@ 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.utils.Utils; @@ -38,6 +40,7 @@ public abstract class Entity implements Viewable { protected double lastX, lastY, lastZ; protected double x, y, z; protected float yaw, pitch; + protected float lastYaw, lastPitch; private int id; protected Entity vehicle; @@ -90,7 +93,9 @@ public abstract class Entity implements Viewable { if (!viewers.contains(player)) return; this.viewers.remove(player); - // TODO send packet to remove entity + DestroyEntitiesPacket destroyEntitiesPacket = new DestroyEntitiesPacket(); + destroyEntitiesPacket.entityIds = new int[]{getEntityId()}; + player.getPlayerConnection().sendPacket(destroyEntitiesPacket); } } @@ -183,6 +188,11 @@ public abstract class Entity implements Viewable { return Collections.unmodifiableSet(passengers); } + 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; @@ -206,6 +216,23 @@ 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; + } + + public void refreshSneaking(boolean sneaking) { + this.crouched = sneaking; + sendMetadata(0); + } + + public void refreshSprinting(boolean sprinting) { + this.sprinting = sprinting; + sendMetadata(0); + } + public double getX() { return x; } @@ -230,30 +257,36 @@ public abstract class Entity implements Viewable { this.shouldRemove = true; } - protected void sendPacketToViewers(ServerPacket packet) { + 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 Buffer getMetadataBuffer() { Buffer buffer = Buffer.create(); fillMetadataIndex(buffer, 0); - /*Utils.writeVarInt(buffer, 0); - Utils.writeString(buffer, customName); - buffer.putBoolean(silent); - buffer.putBoolean(noGravity); - Utils.writeVarInt(buffer, pose.ordinal());*/ - - // Chicken test - /*buffer.putByte((byte) 0); // Hand states - buffer.putFloat(10f); // Health - Utils.writeVarInt(buffer, 0); // Potion effect color - buffer.putBoolean(false); // Potion effect ambient - Utils.writeVarInt(buffer, 0); // Arrow count in entity - buffer.putByte((byte) 0); // (Insentient) - buffer.putBoolean(false); // baby (Ageable)*/ return buffer; } + protected void sendMetadata(int index) { + Buffer buffer = Buffer.create(); + fillMetadataIndex(buffer, index); + + EntityMetaDataPacket metaDataPacket = new EntityMetaDataPacket(); + metaDataPacket.entityId = getEntityId(); + metaDataPacket.data = buffer; + sendPacketToViewers(metaDataPacket); + if (this instanceof Player) { + ((Player) this).getPlayerConnection().sendPacket(metaDataPacket); + } + } + private void fillMetadataIndex(Buffer buffer, int index) { switch (index) { case 0: diff --git a/src/main/java/fr/themode/minestom/entity/Player.java b/src/main/java/fr/themode/minestom/entity/Player.java index 0462b10ea..38107b320 100644 --- a/src/main/java/fr/themode/minestom/entity/Player.java +++ b/src/main/java/fr/themode/minestom/entity/Player.java @@ -1,9 +1,7 @@ package fr.themode.minestom.entity; -import fr.themode.minestom.Main; import fr.themode.minestom.bossbar.BossBar; import fr.themode.minestom.chat.Chat; -import fr.themode.minestom.event.BlockPlaceEvent; import fr.themode.minestom.event.PickupItemEvent; import fr.themode.minestom.instance.Chunk; import fr.themode.minestom.instance.CustomBlock; @@ -11,14 +9,15 @@ import fr.themode.minestom.inventory.Inventory; import fr.themode.minestom.inventory.PlayerInventory; import fr.themode.minestom.item.ItemStack; import fr.themode.minestom.net.packet.client.ClientPlayPacket; +import fr.themode.minestom.net.packet.server.ServerPacket; import fr.themode.minestom.net.packet.server.play.*; import fr.themode.minestom.net.player.PlayerConnection; import fr.themode.minestom.utils.Position; import java.util.Collections; +import java.util.LinkedList; import java.util.Set; import java.util.UUID; -import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CopyOnWriteArraySet; public class Player extends LivingEntity { @@ -27,7 +26,7 @@ public class Player extends LivingEntity { private String username; private PlayerConnection playerConnection; - private ConcurrentLinkedQueue packets = new ConcurrentLinkedQueue<>(); + private LinkedList packets = new LinkedList<>(); private GameMode gameMode; private PlayerInventory inventory; @@ -40,13 +39,16 @@ public class Player extends LivingEntity { private Set bossBars = new CopyOnWriteArraySet<>(); + // Synchronization + private long synchronizationDelay = 1000; // In ms + private long lastSynchronizationTime; + // Vehicle private float sideways; private float forward; - // TODO set proper UUID public Player(UUID uuid, String username, PlayerConnection playerConnection) { - super(93); // TODO correct ? + super(93); // FIXME verify this.uuid = uuid; this.username = username; this.playerConnection = playerConnection; @@ -65,17 +67,19 @@ public class Player extends LivingEntity { sendMessage("Cancelled: " + cancel); });*/ - setEventCallback(BlockPlaceEvent.class, event -> { + /*setEventCallback(BlockPlaceEvent.class, event -> { event.setCancelled(true); sendMessage("CANCELLED"); - }); + });*/ } @Override public void update() { - while (!packets.isEmpty()) { - ClientPlayPacket packet = packets.remove(); - packet.process(this); + synchronized (packets) { + while (!packets.isEmpty()) { + ClientPlayPacket packet = packets.pollFirst(); + packet.process(this); + } } // Target block stage @@ -86,15 +90,14 @@ public class Player extends LivingEntity { byte stage = (byte) (since / (timeBreak / animationCount)); sendBlockBreakAnimation(targetBlockPosition, stage);// TODO send to all near players if (stage > 9) { - instance.setBlock(targetBlockPosition.getX(), targetBlockPosition.getY(), targetBlockPosition.getZ(), (short) 0); - testParticle(targetBlockPosition.getX() + 0.5f, targetBlockPosition.getY(), targetBlockPosition.getZ() + 0.5f, targetCustomBlock.getType()); + instance.breakBlock(this, targetBlockPosition, targetCustomBlock); resetTargetBlock(); } } // Item pickup if (instance != null) { - Chunk chunk = instance.getChunkAt(getX(), getZ()); + Chunk chunk = instance.getChunkAt(getX(), getZ()); // TODO check surrounding chunks Set objectEntities = chunk.getObjectEntities(); for (ObjectEntity objectEntity : objectEntities) { if (objectEntity instanceof ItemEntity) { @@ -125,19 +128,117 @@ public class Player extends LivingEntity { // Multiplayer sync - EntityTeleportPacket entityTeleportPacket = new EntityTeleportPacket(); - entityTeleportPacket.entityId = getEntityId(); - entityTeleportPacket.x = x; - entityTeleportPacket.y = y; - entityTeleportPacket.z = z; - entityTeleportPacket.yaw = yaw; - entityTeleportPacket.pitch = pitch; - entityTeleportPacket.onGround = true; - for (Player onlinePlayer : Main.getConnectionManager().getOnlinePlayers()) { - if (!onlinePlayer.equals(this)) - onlinePlayer.getPlayerConnection().sendPacket(entityTeleportPacket); + boolean positionChanged = x != lastX || z != lastZ || y != lastY; + boolean viewChanged = yaw != lastYaw || pitch != 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.onGround = onGround; + + EntityHeadLookPacket entityHeadLookPacket = new EntityHeadLookPacket(); + entityHeadLookPacket.entityId = getEntityId(); + entityHeadLookPacket.yaw = yaw; + + lastX = x; + lastY = y; + lastZ = z; + lastYaw = yaw; + lastPitch = pitch; + 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.onGround = onGround; + lastX = x; + lastY = y; + lastZ = z; + updatePacket = entityRelativeMovePacket; + } else if (viewChanged) { + EntityLookPacket entityLookPacket = new EntityLookPacket(); + entityLookPacket.entityId = getEntityId(); + entityLookPacket.yaw = yaw; + entityLookPacket.pitch = pitch; + entityLookPacket.onGround = onGround; + + EntityHeadLookPacket entityHeadLookPacket = new EntityHeadLookPacket(); + entityHeadLookPacket.entityId = getEntityId(); + entityHeadLookPacket.yaw = yaw; + + lastYaw = yaw; + lastPitch = pitch; + updatePacket = entityLookPacket; + optionalUpdatePacket = entityHeadLookPacket; + } + if (updatePacket != null) { + if (optionalUpdatePacket != null) { + sendPacketsToViewers(updatePacket, optionalUpdatePacket); + } else { + sendPacketToViewers(updatePacket); + } } playerConnection.sendPacket(new UpdateViewPositionPacket(Math.floorDiv((int) x, 16), Math.floorDiv((int) z, 16))); + + // Synchronization + long time = System.currentTimeMillis(); + if (time - lastSynchronizationTime >= synchronizationDelay) { + lastSynchronizationTime = System.currentTimeMillis(); + 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.onGround = viewer.onGround; + playerConnection.sendPacket(teleportPacket); + } + } + } + + @Override + public void addViewer(Player player) { + super.addViewer(player); + PlayerConnection connection = player.getPlayerConnection(); + String property = "eyJ0aW1lc3RhbXAiOjE1NjU0ODMwODQwOTYsInByb2ZpbGVJZCI6ImFiNzBlY2I0MjM0NjRjMTRhNTJkN2EwOTE1MDdjMjRlIiwicHJvZmlsZU5hbWUiOiJUaGVNb2RlOTExIiwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2RkOTE2NzJiNTE0MmJhN2Y3MjA2ZTRjN2IwOTBkNzhlM2Y1ZDc2NDdiNWFmZDIyNjFhZDk4OGM0MWI2ZjcwYTEifX19"; + 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; + + PlayerInfoPacket pInfoPacket = new PlayerInfoPacket(PlayerInfoPacket.Action.ADD_PLAYER); + PlayerInfoPacket.AddPlayer addP = new PlayerInfoPacket.AddPlayer(getUuid(), getUsername(), GameMode.CREATIVE, 10); + PlayerInfoPacket.AddPlayer.Property p = new PlayerInfoPacket.AddPlayer.Property("textures", property);//new PlayerInfoPacket.AddPlayer.Property("textures", properties.get(onlinePlayer.getUsername())); + addP.properties.add(p); + pInfoPacket.playerInfos.add(addP); + + connection.sendPacket(pInfoPacket); + connection.sendPacket(spawnPlayerPacket); + + for (EntityEquipmentPacket.Slot slot : EntityEquipmentPacket.Slot.values()) { + syncEquipment(slot); // TODO only send packets to "player" and not all viewers + } + } + + @Override + public void removeViewer(Player player) { + super.removeViewer(player); + PlayerInfoPacket playerInfoPacket = new PlayerInfoPacket(PlayerInfoPacket.Action.REMOVE_PLAYER); + playerInfoPacket.playerInfos.add(new PlayerInfoPacket.RemovePlayer(getUuid())); + player.playerConnection.sendPacket(playerInfoPacket); } public void sendBlockBreakAnimation(Position blockPosition, byte destroyStage) { @@ -146,22 +247,7 @@ public class Player extends LivingEntity { breakAnimationPacket.blockPosition = blockPosition; breakAnimationPacket.destroyStage = destroyStage; playerConnection.sendPacket(breakAnimationPacket); - } - - private void testParticle(float x, float y, float z, int blockId) { - ParticlePacket particlePacket = new ParticlePacket(); - particlePacket.particleId = 3; // Block particle - particlePacket.longDistance = false; - particlePacket.x = x; - particlePacket.y = y; - particlePacket.z = z; - particlePacket.offsetX = 0.4f; - particlePacket.offsetY = 0.65f; - particlePacket.offsetZ = 0.4f; - particlePacket.particleData = 0.3f; - particlePacket.particleCount = 75; - particlePacket.blockId = blockId; - playerConnection.sendPacket(particlePacket); + sendPacketToViewers(breakAnimationPacket); } public void sendMessage(String message) { @@ -197,6 +283,13 @@ public class Player extends LivingEntity { return gameMode; } + public void kick(String message) { + DisconnectPacket disconnectPacket = new DisconnectPacket(); + disconnectPacket.message = message; + playerConnection.sendPacket(disconnectPacket); + playerConnection.getConnection().close(); + } + public void setGameMode(GameMode gameMode) { ChangeGameStatePacket changeGameStatePacket = new ChangeGameStatePacket(); changeGameStatePacket.reason = ChangeGameStatePacket.Reason.CHANGE_GAMEMODE; @@ -218,10 +311,6 @@ public class Player extends LivingEntity { return heldSlot; } - public ItemStack getHeldItemStack() { - return inventory.getItemStack(heldSlot); - } - public Inventory getOpenInventory() { return openInventory; } @@ -273,37 +362,35 @@ public class Player extends LivingEntity { inventory.update(); } + public void syncEquipment(EntityEquipmentPacket.Slot slot) { + EntityEquipmentPacket equipmentPacket = new EntityEquipmentPacket(); + equipmentPacket.entityId = getEntityId(); + equipmentPacket.slot = slot; + equipmentPacket.itemStack = inventory.getEquipment(slot); + sendPacketToViewers(equipmentPacket); + } + public void addPacketToQueue(ClientPlayPacket packet) { - this.packets.add(packet); + synchronized (packets) { + this.packets.add(packet); + } } public void refreshGameMode(GameMode gameMode) { this.gameMode = gameMode; } - public void refreshView(float yaw, float pitch) { - this.yaw = yaw; - this.pitch = pitch; - } - public void refreshOnGround(boolean onGround) { this.onGround = onGround; } - public void refreshSneaking(boolean sneaking) { - sneaking = sneaking; - } - - public void refreshSprinting(boolean sprinting) { - sprinting = sprinting; - } - public void refreshKeepAlive(long lastKeepAlive) { this.lastKeepAlive = lastKeepAlive; } public void refreshHeldSlot(short slot) { this.heldSlot = slot; + syncEquipment(EntityEquipmentPacket.Slot.MAIN_HAND); } public void refreshOpenInventory(Inventory openInventory) { diff --git a/src/main/java/fr/themode/minestom/event/BlockBreakEvent.java b/src/main/java/fr/themode/minestom/event/BlockBreakEvent.java new file mode 100644 index 000000000..4d2e1c9b5 --- /dev/null +++ b/src/main/java/fr/themode/minestom/event/BlockBreakEvent.java @@ -0,0 +1,16 @@ +package fr.themode.minestom.event; + +import fr.themode.minestom.utils.Position; + +public class BlockBreakEvent extends CancellableEvent { + + private Position position; + + public BlockBreakEvent(Position position) { + this.position = position; + } + + public Position getPosition() { + return position; + } +} diff --git a/src/main/java/fr/themode/minestom/instance/Instance.java b/src/main/java/fr/themode/minestom/instance/Instance.java index 9a982758e..e463f0224 100644 --- a/src/main/java/fr/themode/minestom/instance/Instance.java +++ b/src/main/java/fr/themode/minestom/instance/Instance.java @@ -4,8 +4,10 @@ import fr.themode.minestom.entity.Entity; import fr.themode.minestom.entity.EntityCreature; import fr.themode.minestom.entity.ObjectEntity; import fr.themode.minestom.entity.Player; +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.GroupedCollections; import fr.themode.minestom.utils.Position; @@ -49,6 +51,37 @@ public class Instance implements BlockModifier { } } + public void breakBlock(Player player, Position position, short blockId) { + BlockBreakEvent blockBreakEvent = new BlockBreakEvent(position); + player.callEvent(BlockBreakEvent.class, blockBreakEvent); + if (!blockBreakEvent.isCancelled()) { + int x = position.getX(); + int y = position.getY(); + int z = position.getZ(); + setBlock(x, y, z, (short) 0); + ParticlePacket particlePacket = new ParticlePacket(); // TODO change by a proper particle API + particlePacket.particleId = 3; // Block particle + particlePacket.longDistance = false; + particlePacket.x = x + 0.5f; + particlePacket.y = y; + particlePacket.z = z + 0.5f; + particlePacket.offsetX = 0.4f; + particlePacket.offsetY = 0.65f; + particlePacket.offsetZ = 0.4f; + particlePacket.particleData = 0.3f; + particlePacket.particleCount = 75; + particlePacket.blockId = blockId; + player.getPlayerConnection().sendPacket(particlePacket); + player.sendPacketToViewers(particlePacket); + } else { + sendChunkUpdate(player, getChunkAt(position)); + } + } + + public void breakBlock(Player player, Position position, CustomBlock customBlock) { + breakBlock(player, position, customBlock.getType()); + } + public Chunk loadChunk(int chunkX, int chunkZ) { Chunk chunk = getChunk(chunkX, chunkZ); return chunk == null ? createChunk(chunkX, chunkZ) : chunk; // TODO load from file @@ -59,6 +92,10 @@ 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 CustomBlock getCustomBlock(int x, int y, int z) { Chunk chunk = getChunkAt(x, z); return chunk.getCustomBlock((byte) (x % 16), (byte) y, (byte) (z % 16)); @@ -96,13 +133,14 @@ public class Instance implements BlockModifier { lastInstance.removeEntity(entity); } + // TODO based on distance with players + getPlayers().forEach(p -> entity.addViewer(p)); + if (entity instanceof Player) { Player player = (Player) entity; sendChunks(player); getCreatures().forEach(entityCreature -> entityCreature.addViewer(player)); - } else { - // TODO based on distance with players - getPlayers().forEach(p -> entity.addViewer(p)); + getPlayers().forEach(p -> p.addViewer(player)); } Chunk chunk = getChunkAt(entity.getX(), entity.getZ()); @@ -114,12 +152,13 @@ public class Instance implements BlockModifier { if (entityInstance == null || entityInstance != this) return; + entity.getViewers().forEach(p -> entity.removeViewer(p)); + if (!(entity instanceof Player)) { DestroyEntitiesPacket destroyEntitiesPacket = new DestroyEntitiesPacket(); destroyEntitiesPacket.entityIds = new int[]{entity.getEntityId()}; entity.getViewers().forEach(p -> p.getPlayerConnection().sendPacket(destroyEntitiesPacket)); // TODO destroy batch - entity.getViewers().forEach(p -> entity.removeViewer(p)); } Chunk chunk = getChunkAt(entity.getX(), entity.getZ()); diff --git a/src/main/java/fr/themode/minestom/inventory/PlayerInventory.java b/src/main/java/fr/themode/minestom/inventory/PlayerInventory.java index a0f8fb64e..2fa60c549 100644 --- a/src/main/java/fr/themode/minestom/inventory/PlayerInventory.java +++ b/src/main/java/fr/themode/minestom/inventory/PlayerInventory.java @@ -2,6 +2,7 @@ package fr.themode.minestom.inventory; import fr.themode.minestom.entity.Player; import fr.themode.minestom.item.ItemStack; +import fr.themode.minestom.net.packet.server.play.EntityEquipmentPacket; import fr.themode.minestom.net.packet.server.play.SetSlotPacket; import fr.themode.minestom.net.packet.server.play.WindowItemsPacket; import fr.themode.minestom.net.player.PlayerConnection; @@ -80,28 +81,58 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler return false; } - public void setHelmet(ItemStack itemStack) { - safeItemInsert(HELMET_SLOT, itemStack); - } - - public void setChestplate(ItemStack itemStack) { - safeItemInsert(CHESTPLATE_SLOT, itemStack); - } - - public void setLeggings(ItemStack itemStack) { - safeItemInsert(LEGGINGS_SLOT, itemStack); - } - - public void setBoots(ItemStack itemStack) { - safeItemInsert(BOOTS_SLOT, itemStack); + public ItemStack getItemInMainHand() { + return getItemStack(player.getHeldSlot()); } public void setItemInMainHand(ItemStack itemStack) { safeItemInsert(player.getHeldSlot(), itemStack); + player.syncEquipment(EntityEquipmentPacket.Slot.MAIN_HAND); + } + + public ItemStack getItemInOffHand() { + return getItemStack(OFFHAND_SLOT); } public void setItemInOffHand(ItemStack itemStack) { safeItemInsert(OFFHAND_SLOT, itemStack); + player.syncEquipment(EntityEquipmentPacket.Slot.OFF_HAND); + } + + public ItemStack getHelmet() { + return getItemStack(HELMET_SLOT); + } + + public void setHelmet(ItemStack itemStack) { + safeItemInsert(HELMET_SLOT, itemStack); + player.syncEquipment(EntityEquipmentPacket.Slot.HELMET); + } + + public ItemStack getChestplate() { + return getItemStack(CHESTPLATE_SLOT); + } + + public void setChestplate(ItemStack itemStack) { + safeItemInsert(CHESTPLATE_SLOT, itemStack); + player.syncEquipment(EntityEquipmentPacket.Slot.CHESTPLATE); + } + + public ItemStack getLeggings() { + return getItemStack(LEGGINGS_SLOT); + } + + public void setLeggings(ItemStack itemStack) { + safeItemInsert(LEGGINGS_SLOT, itemStack); + player.syncEquipment(EntityEquipmentPacket.Slot.LEGGINGS); + } + + public ItemStack getBoots() { + return getItemStack(BOOTS_SLOT); + } + + public void setBoots(ItemStack itemStack) { + safeItemInsert(BOOTS_SLOT, itemStack); + player.syncEquipment(EntityEquipmentPacket.Slot.BOOTS); } public void update() { @@ -121,6 +152,24 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler this.cursorItem = cursorItem; } + public ItemStack getEquipment(EntityEquipmentPacket.Slot slot) { + switch (slot) { + case MAIN_HAND: + return getItemInMainHand(); + case OFF_HAND: + return getItemInOffHand(); + case HELMET: + return getHelmet(); + case CHESTPLATE: + return getChestplate(); + case LEGGINGS: + return getLeggings(); + case BOOTS: + return getBoots(); + } + return ItemStack.AIR_ITEM; + } + private void safeItemInsert(int slot, ItemStack itemStack) { synchronized (this) { itemStack = itemStack == null ? ItemStack.AIR_ITEM : itemStack; @@ -128,6 +177,19 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler // System.out.println("INSERT: " + slot); //sendSlotRefresh((short) slot, itemStack); update(); + if (slot == player.getHeldSlot()) { + player.syncEquipment(EntityEquipmentPacket.Slot.MAIN_HAND); + } else if (slot == OFFHAND_SLOT) { + player.syncEquipment(EntityEquipmentPacket.Slot.OFF_HAND); + } else if (slot == HELMET_SLOT) { + player.syncEquipment(EntityEquipmentPacket.Slot.HELMET); + } else if (slot == CHESTPLATE_SLOT) { + player.syncEquipment(EntityEquipmentPacket.Slot.CHESTPLATE); + } else if (slot == LEGGINGS_SLOT) { + player.syncEquipment(EntityEquipmentPacket.Slot.LEGGINGS); + } else if (slot == BOOTS_SLOT) { + player.syncEquipment(EntityEquipmentPacket.Slot.BOOTS); + } } } diff --git a/src/main/java/fr/themode/minestom/listener/AnimationListener.java b/src/main/java/fr/themode/minestom/listener/AnimationListener.java new file mode 100644 index 000000000..97a70c59d --- /dev/null +++ b/src/main/java/fr/themode/minestom/listener/AnimationListener.java @@ -0,0 +1,16 @@ +package fr.themode.minestom.listener; + +import fr.themode.minestom.entity.Player; +import fr.themode.minestom.net.packet.client.play.ClientAnimationPacket; +import fr.themode.minestom.net.packet.server.play.AnimationPacket; + +public class AnimationListener { + + public static void animationListener(ClientAnimationPacket packet, Player player) { + AnimationPacket animationPacket = new AnimationPacket(); + animationPacket.playerId = player.getEntityId(); + animationPacket.animation = packet.hand == Player.Hand.MAIN ? AnimationPacket.Animation.SWING_MAIN_ARM : AnimationPacket.Animation.SWING_OFF_HAND; + player.sendPacketToViewers(animationPacket); + } + +} diff --git a/src/main/java/fr/themode/minestom/listener/KeepAliveListener.java b/src/main/java/fr/themode/minestom/listener/KeepAliveListener.java index 06b87795b..c4d0b757a 100644 --- a/src/main/java/fr/themode/minestom/listener/KeepAliveListener.java +++ b/src/main/java/fr/themode/minestom/listener/KeepAliveListener.java @@ -1,16 +1,13 @@ package fr.themode.minestom.listener; -import fr.themode.minestom.chat.Chat; import fr.themode.minestom.entity.Player; import fr.themode.minestom.net.packet.client.play.ClientKeepAlivePacket; -import fr.themode.minestom.net.packet.server.play.DisconnectPacket; public class KeepAliveListener { public static void listener(ClientKeepAlivePacket packet, Player player) { if (packet.id != player.getLastKeepAlive()) { - player.getPlayerConnection().sendPacket(new DisconnectPacket(Chat.rawText("Bad Keep Alive packet"))); - player.getPlayerConnection().getConnection().close(); + player.kick("Bad Keep Alive packet"); } } diff --git a/src/main/java/fr/themode/minestom/listener/PacketListenerManager.java b/src/main/java/fr/themode/minestom/listener/PacketListenerManager.java index fd67b77e5..5a7cbc941 100644 --- a/src/main/java/fr/themode/minestom/listener/PacketListenerManager.java +++ b/src/main/java/fr/themode/minestom/listener/PacketListenerManager.java @@ -26,6 +26,7 @@ public class PacketListenerManager { addListener(ClientPlayerPositionPacket.class, PlayerPositionListener::playerPositionListener); addListener(ClientPlayerPositionAndLookPacket.class, PlayerPositionListener::playerPositionAndLookListener); addListener(ClientPlayerDiggingPacket.class, PlayerDiggingListener::playerDiggingListener); + addListener(ClientAnimationPacket.class, AnimationListener::animationListener); } diff --git a/src/main/java/fr/themode/minestom/listener/PlayerDiggingListener.java b/src/main/java/fr/themode/minestom/listener/PlayerDiggingListener.java index 41dcfd48f..023187d4d 100644 --- a/src/main/java/fr/themode/minestom/listener/PlayerDiggingListener.java +++ b/src/main/java/fr/themode/minestom/listener/PlayerDiggingListener.java @@ -41,7 +41,6 @@ public class PlayerDiggingListener { } break; case CANCELLED_DIGGING: - // TODO BlockBreakEvent player.sendBlockBreakAnimation(position, (byte) -1); player.resetTargetBlock(); removeEffect(player); @@ -53,7 +52,8 @@ public class PlayerDiggingListener { } else { Instance instance = player.getInstance(); if (instance != null) { - instance.setBlock(position.getX(), position.getY(), position.getZ(), (short) 0); + short blockId = instance.getBlockId(position); + instance.breakBlock(player, position, blockId); } } break; diff --git a/src/main/java/fr/themode/minestom/net/packet/client/login/LoginStartPacket.java b/src/main/java/fr/themode/minestom/net/packet/client/login/LoginStartPacket.java index 075a54a33..d365a3a97 100644 --- a/src/main/java/fr/themode/minestom/net/packet/client/login/LoginStartPacket.java +++ b/src/main/java/fr/themode/minestom/net/packet/client/login/LoginStartPacket.java @@ -11,8 +11,6 @@ import fr.themode.minestom.entity.Player; import fr.themode.minestom.entity.demo.ChickenCreature; import fr.themode.minestom.instance.Instance; import fr.themode.minestom.instance.demo.ChunkGeneratorDemo; -import fr.themode.minestom.inventory.Inventory; -import fr.themode.minestom.inventory.InventoryType; import fr.themode.minestom.inventory.PlayerInventory; import fr.themode.minestom.item.ItemStack; import fr.themode.minestom.net.ConnectionManager; @@ -22,13 +20,11 @@ import fr.themode.minestom.net.packet.server.login.JoinGamePacket; import fr.themode.minestom.net.packet.server.login.LoginSuccessPacket; import fr.themode.minestom.net.packet.server.play.PlayerInfoPacket; import fr.themode.minestom.net.packet.server.play.PlayerPositionAndLookPacket; -import fr.themode.minestom.net.packet.server.play.SpawnPlayerPacket; 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 java.util.HashMap; import java.util.UUID; public class LoginStartPacket implements ClientPreplayPacket { @@ -54,23 +50,29 @@ public class LoginStartPacket implements ClientPreplayPacket { @Override public void process(PlayerConnection connection, ConnectionManager connectionManager) { - HashMap uuids = new HashMap<>(); + String property = "eyJ0aW1lc3RhbXAiOjE1NjU0ODMwODQwOTYsInByb2ZpbGVJZCI6ImFiNzBlY2I0MjM0NjRjMTRhNTJkN2EwOTE1MDdjMjRlIiwicHJvZmlsZU5hbWUiOiJUaGVNb2RlOTExIiwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2RkOTE2NzJiNTE0MmJhN2Y3MjA2ZTRjN2IwOTBkNzhlM2Y1ZDc2NDdiNWFmZDIyNjFhZDk4OGM0MWI2ZjcwYTEifX19"; + /*HashMap uuids = new HashMap<>(); uuids.put("TheMode911", UUID.fromString("ab70ecb4-2346-4c14-a52d-7a091507c24e")); uuids.put("Adamaq01", UUID.fromString("58ffa9d8-aee1-4587-8b79-41b754f6f238")); HashMap properties = new HashMap<>(); properties.put("TheMode911", "eyJ0aW1lc3RhbXAiOjE1NjU0ODMwODQwOTYsInByb2ZpbGVJZCI6ImFiNzBlY2I0MjM0NjRjMTRhNTJkN2EwOTE1MDdjMjRlIiwicHJvZmlsZU5hbWUiOiJUaGVNb2RlOTExIiwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2RkOTE2NzJiNTE0MmJhN2Y3MjA2ZTRjN2IwOTBkNzhlM2Y1ZDc2NDdiNWFmZDIyNjFhZDk4OGM0MWI2ZjcwYTEifX19"); - properties.put("Adamaq01", "eyJ0aW1lc3RhbXAiOjE1NjU0NzgyODU4MTksInByb2ZpbGVJZCI6IjU4ZmZhOWQ4YWVlMTQ1ODc4Yjc5NDFiNzU0ZjZmMjM4IiwicHJvZmlsZU5hbWUiOiJBZGFtYXEwMSIsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9lMTNiNmMyMjNlMTFiYjM1Nzc5OTdkZWY3YzA2ZDUwZmM4NzMxYjBkZWQyOTRlZDQ2ZmM4ZDczNDI1NGM5ZTkifSwiQ0FQRSI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2IwY2MwODg0MDcwMDQ0NzMyMmQ5NTNhMDJiOTY1ZjFkNjVhMTNhNjAzYmY2NGIxN2M4MDNjMjE0NDZmZTE2MzUifX19"); + properties.put("Adamaq01", "eyJ0aW1lc3RhbXAiOjE1NjU0NzgyODU4MTksInByb2ZpbGVJZCI6IjU4ZmZhOWQ4YWVlMTQ1ODc4Yjc5NDFiNzU0ZjZmMjM4IiwicHJvZmlsZU5hbWUiOiJBZGFtYXEwMSIsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9lMTNiNmMyMjNlMTFiYjM1Nzc5OTdkZWY3YzA2ZDUwZmM4NzMxYjBkZWQyOTRlZDQ2ZmM4ZDczNDI1NGM5ZTkifSwiQ0FQRSI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2IwY2MwODg0MDcwMDQ0NzMyMmQ5NTNhMDJiOTY1ZjFkNjVhMTNhNjAzYmY2NGIxN2M4MDNjMjE0NDZmZTE2MzUifX19");*/ // TODO send encryption request OR directly login success - LoginSuccessPacket successPacket = new LoginSuccessPacket(uuids.get(username), username); + UUID playerUuid = UUID.randomUUID();//UUID.fromString("OfflinePlayer:" + username); + LoginSuccessPacket successPacket = new LoginSuccessPacket(playerUuid, username);//new LoginSuccessPacket(uuids.get(username), username); connection.sendPacket(successPacket); connection.setConnectionState(ConnectionState.PLAY); - connectionManager.createPlayer(uuids.get(username), username, connection); + connectionManager.createPlayer(playerUuid, username, connection); Player player = connectionManager.getPlayer(connection); GameMode gameMode = GameMode.SURVIVAL; + float x = 5; + float y = 5; + float z = 5; player.refreshGameMode(gameMode); + player.refreshPosition(x, y, z); // TODO complete login sequence with optionals packets JoinGamePacket joinGamePacket = new JoinGamePacket(); @@ -89,8 +91,6 @@ public class LoginStartPacket implements ClientPreplayPacket { // TODO player abilities - player.setInstance(instance); - SpawnPositionPacket spawnPositionPacket = new SpawnPositionPacket(); spawnPositionPacket.x = 0; @@ -99,9 +99,9 @@ public class LoginStartPacket implements ClientPreplayPacket { connection.sendPacket(spawnPositionPacket); PlayerPositionAndLookPacket playerPositionAndLookPacket = new PlayerPositionAndLookPacket(); - playerPositionAndLookPacket.x = 0; - playerPositionAndLookPacket.y = 5; - playerPositionAndLookPacket.z = 0; + playerPositionAndLookPacket.x = x; + playerPositionAndLookPacket.y = y; + playerPositionAndLookPacket.z = z; playerPositionAndLookPacket.yaw = 0; playerPositionAndLookPacket.pitch = 0; playerPositionAndLookPacket.flags = 0; @@ -109,70 +109,43 @@ public class LoginStartPacket implements ClientPreplayPacket { connection.sendPacket(playerPositionAndLookPacket); PlayerInfoPacket playerInfoPacket = new PlayerInfoPacket(PlayerInfoPacket.Action.ADD_PLAYER); - PlayerInfoPacket.AddPlayer addPlayer = new PlayerInfoPacket.AddPlayer(uuids.get(username), username, GameMode.CREATIVE, 10); - PlayerInfoPacket.AddPlayer.Property property = new PlayerInfoPacket.AddPlayer.Property("textures", properties.get(username)); - addPlayer.properties.add(property); + PlayerInfoPacket.AddPlayer addPlayer = new PlayerInfoPacket.AddPlayer(player.getUuid(), username, GameMode.CREATIVE, 10); + PlayerInfoPacket.AddPlayer.Property prop = new PlayerInfoPacket.AddPlayer.Property("textures", property); //new PlayerInfoPacket.AddPlayer.Property("textures", properties.get(username)); + addPlayer.properties.add(prop); playerInfoPacket.playerInfos.add(addPlayer); connection.sendPacket(playerInfoPacket); - for (int x = 0; x < 4; x++) - for (int z = 0; z < 4; z++) { + player.setInstance(instance); + + for (int cx = 0; cx < 4; cx++) + for (int cz = 0; cz < 4; cz++) { ChickenCreature chickenCreature = new ChickenCreature(); - chickenCreature.refreshPosition(0 + (double) x * 1, 5, 0 + (double) z * 1); + chickenCreature.refreshPosition(0 + (double) cx * 1, 5, 0 + (double) cz * 1); + chickenCreature.setOnFire(true); chickenCreature.setInstance(instance); - if (x == 3 && z == 3) { + if (cx == 3 && cz == 3) { //chickenCreature.addPassenger(player); } } - - SpawnPlayerPacket spawnPlayerPacket = new SpawnPlayerPacket(); - spawnPlayerPacket.entityId = player.getEntityId(); - spawnPlayerPacket.playerUuid = uuids.get(username); - spawnPlayerPacket.x = 0; - spawnPlayerPacket.y = 5; - spawnPlayerPacket.z = 0; - for (Player onlinePlayer : connectionManager.getOnlinePlayers()) { - if (onlinePlayer.getUsername().equals(username)) continue; - onlinePlayer.getPlayerConnection().sendPacket(playerInfoPacket); - onlinePlayer.getPlayerConnection().sendPacket(spawnPlayerPacket); - - SpawnPlayerPacket spawnPacket = new SpawnPlayerPacket(); - spawnPacket.entityId = onlinePlayer.getEntityId(); - spawnPacket.playerUuid = uuids.get(onlinePlayer.getUsername()); - spawnPacket.x = onlinePlayer.getX(); - spawnPacket.y = onlinePlayer.getY(); - spawnPacket.z = onlinePlayer.getZ(); - - PlayerInfoPacket pInfoPacket = new PlayerInfoPacket(PlayerInfoPacket.Action.ADD_PLAYER); - PlayerInfoPacket.AddPlayer addP = new PlayerInfoPacket.AddPlayer(uuids.get(onlinePlayer.getUsername()), onlinePlayer.getUsername(), GameMode.CREATIVE, 10); - PlayerInfoPacket.AddPlayer.Property p = new PlayerInfoPacket.AddPlayer.Property("textures", properties.get(onlinePlayer.getUsername())); - addP.properties.add(p); - pInfoPacket.playerInfos.add(addP); - connection.sendPacket(pInfoPacket); - connection.sendPacket(spawnPacket); - } - //System.out.println("HAHAHAHHAHHAH " + player.getUuid()); - PlayerInventory inventory = player.getInventory(); for (int i = 0; i < 20; i++) { inventory.addItemStack(new ItemStack(1, (byte) 64)); } - Inventory inv = new Inventory(InventoryType.WINDOW_3X3, "Salut je suis le titre"); + /*Inventory inv = new Inventory(InventoryType.WINDOW_3X3, "Salut je suis le titre"); inv.setItemStack(0, new ItemStack(1, (byte) 1)); player.openInventory(inv); - inv.setItemStack(1, new ItemStack(1, (byte) 2)); - //inv.updateItems(); + inv.setItemStack(1, new ItemStack(1, (byte) 2));*/ BossBar bossBar = new BossBar("Le titre", BarColor.BLUE, BarDivision.SEGMENT_12); bossBar.setProgress(0.75f); bossBar.addViewer(player); - for (int x = 0; x < 4; x++) - for (int z = 0; z < 4; z++) { + for (int ix = 0; ix < 4; ix++) + for (int iz = 0; iz < 4; iz++) { ItemEntity itemEntity = new ItemEntity(new ItemStack(1, (byte) 32)); - itemEntity.refreshPosition(x, 5, z); + itemEntity.refreshPosition(ix, 5, iz); itemEntity.setInstance(instance); //itemEntity.remove(); } diff --git a/src/main/java/fr/themode/minestom/net/packet/server/play/AnimationPacket.java b/src/main/java/fr/themode/minestom/net/packet/server/play/AnimationPacket.java new file mode 100644 index 000000000..df228d26d --- /dev/null +++ b/src/main/java/fr/themode/minestom/net/packet/server/play/AnimationPacket.java @@ -0,0 +1,31 @@ +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 AnimationPacket implements ServerPacket { + + public int playerId; // FIXME verify if this is only player? + public Animation animation; + + @Override + public void write(Buffer buffer) { + Utils.writeVarInt(buffer, playerId); + buffer.putByte((byte) animation.ordinal()); + } + + @Override + public int getId() { + return 0x06; + } + + public enum Animation { + SWING_MAIN_ARM, + TAKE_DAMAGE, + LEAVE_BED, + SWING_OFF_HAND, + CRITICAL_EFFECT, + MAGICAL_CRITICAL_EFFECT; + } +} diff --git a/src/main/java/fr/themode/minestom/net/packet/server/play/DisconnectPacket.java b/src/main/java/fr/themode/minestom/net/packet/server/play/DisconnectPacket.java index 54afe38b7..38ca96bd9 100644 --- a/src/main/java/fr/themode/minestom/net/packet/server/play/DisconnectPacket.java +++ b/src/main/java/fr/themode/minestom/net/packet/server/play/DisconnectPacket.java @@ -1,20 +1,17 @@ package fr.themode.minestom.net.packet.server.play; import fr.adamaq01.ozao.net.Buffer; +import fr.themode.minestom.chat.Chat; import fr.themode.minestom.net.packet.server.ServerPacket; import fr.themode.minestom.utils.Utils; public class DisconnectPacket implements ServerPacket { - private String message; - - public DisconnectPacket(String message) { - this.message = message; - } + public String message; @Override public void write(Buffer buffer) { - Utils.writeString(buffer, this.message); + Utils.writeString(buffer, Chat.rawText(message)); } @Override diff --git a/src/main/java/fr/themode/minestom/net/packet/server/play/EntityEquipmentPacket.java b/src/main/java/fr/themode/minestom/net/packet/server/play/EntityEquipmentPacket.java new file mode 100644 index 000000000..bc9740eda --- /dev/null +++ b/src/main/java/fr/themode/minestom/net/packet/server/play/EntityEquipmentPacket.java @@ -0,0 +1,35 @@ +package fr.themode.minestom.net.packet.server.play; + +import fr.adamaq01.ozao.net.Buffer; +import fr.themode.minestom.item.ItemStack; +import fr.themode.minestom.net.packet.server.ServerPacket; +import fr.themode.minestom.utils.Utils; + +public class EntityEquipmentPacket implements ServerPacket { + + public int entityId; + public Slot slot; + public ItemStack itemStack; + + @Override + public void write(Buffer buffer) { + Utils.writeVarInt(buffer, entityId); + Utils.writeVarInt(buffer, slot.ordinal()); + Utils.writeItemStack(buffer, itemStack); + } + + @Override + public int getId() { + return 0x46; + } + + public enum Slot { + MAIN_HAND, + OFF_HAND, + BOOTS, + LEGGINGS, + CHESTPLATE, + HELMET; + } + +} diff --git a/src/main/java/fr/themode/minestom/net/packet/server/play/EntityHeadLookPacket.java b/src/main/java/fr/themode/minestom/net/packet/server/play/EntityHeadLookPacket.java new file mode 100644 index 000000000..37cbb9065 --- /dev/null +++ b/src/main/java/fr/themode/minestom/net/packet/server/play/EntityHeadLookPacket.java @@ -0,0 +1,22 @@ +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 EntityHeadLookPacket implements ServerPacket { + + public int entityId; + public float yaw; + + @Override + public void write(Buffer buffer) { + Utils.writeVarInt(buffer, entityId); + buffer.putByte((byte) (this.yaw * 256 / 360)); + } + + @Override + public int getId() { + return 0x3B; + } +} diff --git a/src/main/java/fr/themode/minestom/net/packet/server/play/EntityLookPacket.java b/src/main/java/fr/themode/minestom/net/packet/server/play/EntityLookPacket.java new file mode 100644 index 000000000..ef9ff877d --- /dev/null +++ b/src/main/java/fr/themode/minestom/net/packet/server/play/EntityLookPacket.java @@ -0,0 +1,25 @@ +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 EntityLookPacket implements ServerPacket { + + public int entityId; + public float yaw, pitch; + public boolean onGround; + + @Override + public void write(Buffer buffer) { + Utils.writeVarInt(buffer, entityId); + buffer.putByte((byte) (this.yaw * 256 / 360)); + buffer.putByte((byte) (this.pitch * 256 / 360)); + buffer.putBoolean(onGround); + } + + @Override + public int getId() { + return 0x2A; + } +} diff --git a/src/main/java/fr/themode/minestom/net/packet/server/play/PlayerInfoPacket.java b/src/main/java/fr/themode/minestom/net/packet/server/play/PlayerInfoPacket.java index 3df552d75..de5e55e00 100644 --- a/src/main/java/fr/themode/minestom/net/packet/server/play/PlayerInfoPacket.java +++ b/src/main/java/fr/themode/minestom/net/packet/server/play/PlayerInfoPacket.java @@ -35,7 +35,7 @@ public class PlayerInfoPacket implements ServerPacket { return 0x33; } - public static enum Action { + public enum Action { ADD_PLAYER(AddPlayer.class), UPDATE_GAMEMODE(UpdateGamemode.class), diff --git a/src/main/java/fr/themode/minestom/net/packet/server/play/SpawnPlayerPacket.java b/src/main/java/fr/themode/minestom/net/packet/server/play/SpawnPlayerPacket.java index 064e2971c..d1bab189d 100644 --- a/src/main/java/fr/themode/minestom/net/packet/server/play/SpawnPlayerPacket.java +++ b/src/main/java/fr/themode/minestom/net/packet/server/play/SpawnPlayerPacket.java @@ -13,8 +13,8 @@ public class SpawnPlayerPacket implements ServerPacket { public double x; public double y; public double z; - // public float yaw; - // public float pitch; + public float yaw; + public float pitch; @Override public void write(Buffer buffer) { @@ -24,8 +24,8 @@ public class SpawnPlayerPacket implements ServerPacket { buffer.putDouble(x); buffer.putDouble(y); buffer.putDouble(z); - buffer.getData().writeByte(0); - buffer.getData().writeByte(0); + buffer.putByte((byte) (yaw * 256 / 360)); + buffer.putByte((byte) (pitch * 256 / 360)); buffer.putByte((byte) 0xff); // TODO Metadata }