diff --git a/src/main/java/fr/themode/minestom/Main.java b/src/main/java/fr/themode/minestom/Main.java index d1335c56a..3384cb93b 100644 --- a/src/main/java/fr/themode/minestom/Main.java +++ b/src/main/java/fr/themode/minestom/Main.java @@ -13,6 +13,7 @@ import fr.themode.minestom.net.PacketProcessor; import fr.themode.minestom.net.packet.PacketReader; import fr.themode.minestom.net.packet.client.status.LegacyServerListPingPacket; import fr.themode.minestom.net.packet.server.play.KeepAlivePacket; +import fr.themode.minestom.net.player.PlayerConnection; import fr.themode.minestom.utils.Utils; import simplenet.Server; @@ -61,10 +62,12 @@ public class Main { server.onConnect(client -> { System.out.println("CONNECTION"); - client.postDisconnect(() -> { + client.preDisconnect(() -> { System.out.println("A Disconnection"); if (packetProcessor.hasPlayerConnection(client)) { - Player player = connectionManager.getPlayer(packetProcessor.getPlayerConnection(client)); + PlayerConnection playerConnection = packetProcessor.getPlayerConnection(client); + playerConnection.refreshOnline(false); + Player player = connectionManager.getPlayer(playerConnection); if (player != null) { player.remove(); diff --git a/src/main/java/fr/themode/minestom/collision/BoundingBox.java b/src/main/java/fr/themode/minestom/collision/BoundingBox.java index 50934e67d..767a1aae5 100644 --- a/src/main/java/fr/themode/minestom/collision/BoundingBox.java +++ b/src/main/java/fr/themode/minestom/collision/BoundingBox.java @@ -26,9 +26,9 @@ public class BoundingBox { } public boolean intersect(BlockPosition blockPosition) { - final float x = 1f; + final float x = 1.6f; final float y = 1; - final float z = 1f; + final float z = 1.6f; float minX = blockPosition.getX() - (x / 2) + 0.5f; float maxX = blockPosition.getX() + (x / 2) + 0.5f; diff --git a/src/main/java/fr/themode/minestom/entity/Entity.java b/src/main/java/fr/themode/minestom/entity/Entity.java index 4243e1db1..58efc3faa 100644 --- a/src/main/java/fr/themode/minestom/entity/Entity.java +++ b/src/main/java/fr/themode/minestom/entity/Entity.java @@ -12,11 +12,13 @@ import fr.themode.minestom.instance.Chunk; import fr.themode.minestom.instance.Instance; import fr.themode.minestom.net.packet.server.play.*; import fr.themode.minestom.net.player.PlayerConnection; -import fr.themode.minestom.utils.Vector; import fr.themode.minestom.utils.*; import simplenet.packet.Packet; -import java.util.*; +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.atomic.AtomicInteger; @@ -24,7 +26,7 @@ import java.util.function.Consumer; public abstract class Entity implements Viewable, DataContainer { - private static Map entityById = new HashMap<>(); + private static Map entityById = new ConcurrentHashMap<>(); private static AtomicInteger lastEntityId = new AtomicInteger(); // Metadata @@ -92,15 +94,11 @@ public abstract class Entity implements Viewable, DataContainer { setBoundingBox(0, 0, 0); - synchronized (entityById) { - entityById.put(id, this); - } + entityById.put(id, this); } public static Entity getEntity(int id) { - synchronized (entityById) { - return entityById.get(id); - } + return entityById.get(id); } private static int generateId() { @@ -538,9 +536,7 @@ public abstract class Entity implements Viewable, DataContainer { public void remove() { this.shouldRemove = true; - synchronized (entityById) { - entityById.remove(id); - } + entityById.remove(id); if (instance != null) instance.removeEntity(this); } diff --git a/src/main/java/fr/themode/minestom/entity/Player.java b/src/main/java/fr/themode/minestom/entity/Player.java index 9d9de8461..10cb768c1 100644 --- a/src/main/java/fr/themode/minestom/entity/Player.java +++ b/src/main/java/fr/themode/minestom/entity/Player.java @@ -50,7 +50,7 @@ public class Player extends LivingEntity { static { ChunkGeneratorDemo chunkGeneratorDemo = new ChunkGeneratorDemo(); - //instance = Main.getInstanceManager().createInstance(new File("C:\\Users\\themo\\OneDrive\\Bureau\\Minestom data")); + //instanceContainer = Main.getInstanceManager().createInstanceContainer(new File("C:\\Users\\themo\\OneDrive\\Bureau\\Minestom data")); instanceContainer = Main.getInstanceManager().createInstanceContainer(); instanceContainer.enableAutoChunkLoad(true); instanceContainer.setChunkGenerator(chunkGeneratorDemo); @@ -156,7 +156,7 @@ public class Player extends LivingEntity { setEventCallback(PlayerSpawnEvent.class, event -> { System.out.println("SPAWN"); - setGameMode(GameMode.SURVIVAL); + setGameMode(GameMode.CREATIVE); teleport(new Position(0, 66, 0)); /*ChickenCreature chickenCreature = new ChickenCreature(); @@ -329,6 +329,7 @@ public class Player extends LivingEntity { if (getOpenInventory() != null) getOpenInventory().removeViewer(this); this.viewableEntities.forEach(entity -> entity.removeViewer(this)); + this.viewableChunks.forEach(chunk -> chunk.removeViewer(this)); super.remove(); } @@ -607,6 +608,10 @@ public class Player extends LivingEntity { return playerConnection; } + public boolean isOnline() { + return playerConnection.isOnline(); + } + public PlayerSettings getSettings() { return settings; } diff --git a/src/main/java/fr/themode/minestom/instance/ChunkLoaderIO.java b/src/main/java/fr/themode/minestom/instance/ChunkLoaderIO.java index c252155a1..28a49be17 100644 --- a/src/main/java/fr/themode/minestom/instance/ChunkLoaderIO.java +++ b/src/main/java/fr/themode/minestom/instance/ChunkLoaderIO.java @@ -1,7 +1,7 @@ package fr.themode.minestom.instance; -import com.github.luben.zstd.Zstd; import fr.themode.minestom.Main; +import fr.themode.minestom.utils.CompressionUtils; import fr.themode.minestom.utils.SerializerUtils; import java.io.*; @@ -29,14 +29,7 @@ public class ChunkLoaderIO { File chunkFile = getChunkFile(chunk.getChunkX(), chunk.getChunkZ(), folder); try (FileOutputStream fos = new FileOutputStream(chunkFile)) { byte[] data = chunk.getSerializedData(); - byte[] decompressedLength = SerializerUtils.intToBytes(data.length); - byte[] compressed = Zstd.compress(data, COMPRESSION_LEVEL); - - byte[] result = new byte[decompressedLength.length + compressed.length]; - System.arraycopy(decompressedLength, 0, result, 0, decompressedLength.length); - System.arraycopy(compressed, 0, result, decompressedLength.length, compressed.length); - - fos.write(result); + fos.write(CompressionUtils.getCompressedData(data)); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { @@ -65,19 +58,7 @@ public class ChunkLoaderIO { return; } - int decompressedLength = SerializerUtils.bytesToInt(array); - - byte[] compressedChunkData = new byte[array.length - Integer.BYTES]; - System.arraycopy(array, Integer.BYTES, compressedChunkData, 0, compressedChunkData.length); // Remove the decompressed length from the array - - byte[] decompressed = new byte[decompressedLength]; - long result = Zstd.decompress(decompressed, compressedChunkData); // Decompressed in an array with the max size - - array = new byte[(int) result]; - System.arraycopy(decompressed, 0, array, 0, (int) result); // Resize the data array properly - - - DataInputStream stream = new DataInputStream(new ByteArrayInputStream(array)); + DataInputStream stream = new DataInputStream(new ByteArrayInputStream(CompressionUtils.getDecompressedData(array))); Chunk chunk = null; try { diff --git a/src/main/java/fr/themode/minestom/instance/Instance.java b/src/main/java/fr/themode/minestom/instance/Instance.java index ee37ead9b..265f40f41 100644 --- a/src/main/java/fr/themode/minestom/instance/Instance.java +++ b/src/main/java/fr/themode/minestom/instance/Instance.java @@ -190,37 +190,41 @@ public abstract class Instance implements BlockModifier { public void addEntityToChunk(Entity entity, Chunk chunk) { long chunkIndex = ChunkUtils.getChunkIndex(chunk.getChunkX(), chunk.getChunkZ()); - Set entities = getEntitiesInChunk(chunkIndex); - entities.add(entity); - this.chunkEntities.put(chunkIndex, entities); - if (entity instanceof Player) { - this.players.add((Player) entity); - } else if (entity instanceof EntityCreature) { - this.creatures.add((EntityCreature) entity); - } else if (entity instanceof ObjectEntity) { - this.objectEntities.add((ObjectEntity) entity); - } else if (entity instanceof ExperienceOrb) { - this.experienceOrbs.add((ExperienceOrb) entity); + synchronized (chunkEntities) { + Set entities = getEntitiesInChunk(chunkIndex); + entities.add(entity); + this.chunkEntities.put(chunkIndex, entities); + if (entity instanceof Player) { + this.players.add((Player) entity); + } else if (entity instanceof EntityCreature) { + this.creatures.add((EntityCreature) entity); + } else if (entity instanceof ObjectEntity) { + this.objectEntities.add((ObjectEntity) entity); + } else if (entity instanceof ExperienceOrb) { + this.experienceOrbs.add((ExperienceOrb) entity); + } } } public void removeEntityFromChunk(Entity entity, Chunk chunk) { long chunkIndex = ChunkUtils.getChunkIndex(chunk.getChunkX(), chunk.getChunkZ()); - Set entities = getEntitiesInChunk(chunkIndex); - entities.remove(entity); - if (entities.isEmpty()) { - this.chunkEntities.remove(chunkIndex); - } else { - this.chunkEntities.put(chunkIndex, entities); - } - if (entity instanceof Player) { - this.players.remove(entity); - } else if (entity instanceof EntityCreature) { - this.creatures.remove(entity); - } else if (entity instanceof ObjectEntity) { - this.objectEntities.remove(entity); - } else if (entity instanceof ExperienceOrb) { - this.experienceOrbs.remove((ExperienceOrb) entity); + synchronized (chunkEntities) { + Set entities = getEntitiesInChunk(chunkIndex); + entities.remove(entity); + if (entities.isEmpty()) { + this.chunkEntities.remove(chunkIndex); + } else { + this.chunkEntities.put(chunkIndex, entities); + } + if (entity instanceof Player) { + this.players.remove(entity); + } else if (entity instanceof EntityCreature) { + this.creatures.remove(entity); + } else if (entity instanceof ObjectEntity) { + this.objectEntities.remove(entity); + } else if (entity instanceof ExperienceOrb) { + this.experienceOrbs.remove((ExperienceOrb) entity); + } } } diff --git a/src/main/java/fr/themode/minestom/instance/InstanceContainer.java b/src/main/java/fr/themode/minestom/instance/InstanceContainer.java index 85c2375e7..b3e93e57b 100644 --- a/src/main/java/fr/themode/minestom/instance/InstanceContainer.java +++ b/src/main/java/fr/themode/minestom/instance/InstanceContainer.java @@ -8,6 +8,7 @@ import fr.themode.minestom.net.packet.server.play.ChunkDataPacket; import fr.themode.minestom.net.packet.server.play.ParticlePacket; import fr.themode.minestom.utils.BlockPosition; import fr.themode.minestom.utils.ChunkUtils; +import simplenet.packet.Packet; import java.io.File; import java.util.*; @@ -196,17 +197,6 @@ public class InstanceContainer extends Instance { if (!chunkViewers.isEmpty()) { sendChunkUpdate(chunkViewers, chunk); } - // Update for players in this instance - /*if (!getPlayers().isEmpty()) - sendChunkUpdate(getPlayers(), chunk); - - // Update for shared instances - if (!sharedInstances.isEmpty()) - this.sharedInstances.forEach(sharedInstance -> { - Set instancePlayers = sharedInstance.getPlayers(); - if (!instancePlayers.isEmpty()) - sendChunkUpdate(instancePlayers, chunk); - });*/ } @Override @@ -218,19 +208,15 @@ public class InstanceContainer extends Instance { @Override public void sendChunk(Player player, Chunk chunk) { - /*Buffer data = chunk.getFullDataPacket(); - if(data == null) { + Packet data = chunk.getFullDataPacket(); + if (data == null) { PacketWriterUtils.writeCallbackPacket(chunk.getFreshFullDataPacket(), buffer -> { chunk.setFullDataPacket(buffer); sendChunkUpdate(player, chunk); }); - }else{ + } else { sendChunkUpdate(player, chunk); - }*/ - PacketWriterUtils.writeCallbackPacket(chunk.getFreshFullDataPacket(), buffer -> { - chunk.setFullDataPacket(buffer); - sendChunkUpdate(player, chunk); - }); + } } @Override diff --git a/src/main/java/fr/themode/minestom/net/player/PlayerConnection.java b/src/main/java/fr/themode/minestom/net/player/PlayerConnection.java index 1df9bca9c..862352518 100644 --- a/src/main/java/fr/themode/minestom/net/player/PlayerConnection.java +++ b/src/main/java/fr/themode/minestom/net/player/PlayerConnection.java @@ -10,14 +10,17 @@ public class PlayerConnection { private Client client; private ConnectionState connectionState; + private boolean online; public PlayerConnection(Client client) { this.client = client; this.connectionState = ConnectionState.UNKNOWN; + this.online = true; } public void sendPacket(Packet packet) { - packet.writeAndFlush(client); + if (isOnline()) + packet.writeAndFlush(client); } public void writeUnencodedPacket(Packet packet) { @@ -25,8 +28,8 @@ public class PlayerConnection { } public void sendPacket(ServerPacket serverPacket) { - PacketUtils.writePacket(serverPacket, packet -> sendPacket(packet)); - //PacketWriterUtils.writeAndSend(this, serverPacket); + if (isOnline()) + PacketUtils.writePacket(serverPacket, packet -> sendPacket(packet)); } public void flush() { @@ -37,6 +40,14 @@ public class PlayerConnection { return client; } + public boolean isOnline() { + return online; + } + + public void refreshOnline(boolean online) { + this.online = online; + } + public void setConnectionState(ConnectionState connectionState) { this.connectionState = connectionState; } diff --git a/src/main/java/fr/themode/minestom/utils/CompressionUtils.java b/src/main/java/fr/themode/minestom/utils/CompressionUtils.java new file mode 100644 index 000000000..95427aa0c --- /dev/null +++ b/src/main/java/fr/themode/minestom/utils/CompressionUtils.java @@ -0,0 +1,36 @@ +package fr.themode.minestom.utils; + +import com.github.luben.zstd.Zstd; + +public class CompressionUtils { + + private static final int COMPRESSION_LEVEL = 1; + + public static byte[] getCompressedData(byte[] decompressed) { + byte[] decompressedLength = SerializerUtils.intToBytes(decompressed.length); + byte[] compressed = Zstd.compress(decompressed, COMPRESSION_LEVEL); + + byte[] result = new byte[decompressedLength.length + compressed.length]; + System.arraycopy(decompressedLength, 0, result, 0, decompressedLength.length); + System.arraycopy(compressed, 0, result, decompressedLength.length, compressed.length); + + return result; + } + + public static byte[] getDecompressedData(byte[] compressed) { + int decompressedLength = SerializerUtils.bytesToInt(compressed); + + byte[] compressedChunkData = new byte[compressed.length - Integer.BYTES]; + System.arraycopy(compressed, Integer.BYTES, compressedChunkData, 0, compressedChunkData.length); // Remove the decompressed length from the array + + byte[] decompressed = new byte[decompressedLength]; + long result = Zstd.decompress(decompressed, compressedChunkData); // Decompressed in an array with the max size + + compressed = new byte[(int) result]; + System.arraycopy(decompressed, 0, compressed, 0, (int) result); // Resize the data array properly + + return compressed; + } + + +}