From f236a9b01eea24d60c7218824e009479e42c0545 Mon Sep 17 00:00:00 2001 From: Sculas Date: Wed, 20 Mar 2024 18:12:48 +0100 Subject: [PATCH] fix: don't spam empty chunk packets --- .../limbo/player/PlayerInteractManager.java | 224 +++++++++--------- 1 file changed, 116 insertions(+), 108 deletions(-) diff --git a/src/main/java/com/loohp/limbo/player/PlayerInteractManager.java b/src/main/java/com/loohp/limbo/player/PlayerInteractManager.java index 719d242..e76157c 100644 --- a/src/main/java/com/loohp/limbo/player/PlayerInteractManager.java +++ b/src/main/java/com/loohp/limbo/player/PlayerInteractManager.java @@ -30,6 +30,7 @@ import com.loohp.limbo.network.protocol.packets.PacketPlayOutEntityDestroy; import com.loohp.limbo.network.protocol.packets.PacketPlayOutEntityMetadata; import com.loohp.limbo.network.protocol.packets.PacketPlayOutSpawnEntity; import com.loohp.limbo.network.protocol.packets.PacketPlayOutUnloadChunk; +import com.loohp.limbo.utils.GameMode; import com.loohp.limbo.world.ChunkPosition; import com.loohp.limbo.world.World; import net.querz.mca.Chunk; @@ -46,118 +47,125 @@ import java.util.Set; import java.util.stream.Collectors; public class PlayerInteractManager { - - private Player player; - - private Set entities; - private Map currentViewing; - - public PlayerInteractManager() { - this.player = null; - this.entities = new HashSet<>(); - this.currentViewing = new HashMap<>(); - } - - protected void setPlayer(Player player) { - if (this.player == null) { - this.player = player; - } else { - throw new RuntimeException("Player in PlayerInteractManager cannot be changed once created"); - } - } - - public Player getPlayer() { - return player; - } - - public void update() throws IOException { - if (player.clientConnection.getClientState() != ClientConnection.ClientState.PLAY) { - return; - } - int viewDistanceChunks = Limbo.getInstance().getServerProperties().getViewDistance(); - int viewDistanceBlocks = viewDistanceChunks << 4; - Location location = player.getLocation(); - Set entitiesInRange = player.getWorld().getEntities().stream().filter(each -> each.getLocation().distanceSquared(location) < viewDistanceBlocks * viewDistanceBlocks).collect(Collectors.toSet()); - for (Entity entity : entitiesInRange) { - if (!entities.contains(entity)) { - PacketPlayOutSpawnEntity packet = new PacketPlayOutSpawnEntity(entity.getEntityId(), entity.getUniqueId(), entity.getType(), entity.getX(), entity.getY(), entity.getZ(), entity.getYaw(), entity.getPitch(), entity.getPitch(), 0, (short) 0, (short) 0, (short) 0); - player.clientConnection.sendPacket(packet); + private Player player; - PacketPlayOutEntityMetadata meta = new PacketPlayOutEntityMetadata(entity); - player.clientConnection.sendPacket(meta); - } - } - List ids = new ArrayList<>(); - for (Entity entity : entities) { - if (!entitiesInRange.contains(entity)) { - ids.add(entity.getEntityId()); - } - } - for (int id : ids) { - PacketPlayOutEntityDestroy packet = new PacketPlayOutEntityDestroy(id); - player.clientConnection.sendPacket(packet); - } - - entities = entitiesInRange; - - int playerChunkX = (int) location.getX() >> 4; - int playerChunkZ = (int) location.getZ() >> 4; - World world = location.getWorld(); - - Map chunksInRange = new HashMap<>(); - - for (int x = playerChunkX - viewDistanceChunks; x < playerChunkX + viewDistanceChunks; x++) { - for (int z = playerChunkZ - viewDistanceChunks; z < playerChunkZ + viewDistanceChunks; z++) { - Chunk chunk = world.getChunkAt(x, z); - if (chunk != null) { - chunksInRange.put(new ChunkPosition(world, x, z), chunk); - } else { - chunksInRange.put(new ChunkPosition(world, x, z), World.EMPTY_CHUNK); - } - } - } - - for (Entry entry : currentViewing.entrySet()) { - ChunkPosition chunkPos = entry.getKey(); - if (!chunksInRange.containsKey(chunkPos)) { - PacketPlayOutUnloadChunk packet = new PacketPlayOutUnloadChunk(chunkPos.getChunkX(), chunkPos.getChunkZ()); - player.clientConnection.sendPacket(packet); - } - } + private Set entities; + private Map currentViewing; - int counter = 0; - ClientboundChunkBatchStartPacket chunkBatchStartPacket = new ClientboundChunkBatchStartPacket(); - player.clientConnection.sendPacket(chunkBatchStartPacket); - for (Entry entry : chunksInRange.entrySet()) { - ChunkPosition chunkPos = entry.getKey(); - if (!currentViewing.containsKey(chunkPos)) { - Chunk chunk = chunkPos.getWorld().getChunkAt(chunkPos.getChunkX(), chunkPos.getChunkZ()); - if (chunk == null) { - ClientboundLevelChunkWithLightPacket chunkdata = new ClientboundLevelChunkWithLightPacket(chunkPos.getChunkX(), chunkPos.getChunkZ(), entry.getValue(), world.getEnvironment(), Collections.emptyList(), Collections.emptyList()); - player.clientConnection.sendPacket(chunkdata); - } else { - List blockChunk = world.getLightEngineBlock().getBlockLightBitMask(chunkPos.getChunkX(), chunkPos.getChunkZ()); - if (blockChunk == null) { - blockChunk = new ArrayList<>(); - } - List skyChunk = null; - if (world.hasSkyLight()) { - skyChunk = world.getLightEngineSky().getSkyLightBitMask(chunkPos.getChunkX(), chunkPos.getChunkZ()); - } - if (skyChunk == null) { - skyChunk = new ArrayList<>(); - } - ClientboundLevelChunkWithLightPacket chunkdata = new ClientboundLevelChunkWithLightPacket(chunkPos.getChunkX(), chunkPos.getChunkZ(), chunk, world.getEnvironment(), skyChunk, blockChunk); - player.clientConnection.sendPacket(chunkdata); - } - counter++; + public PlayerInteractManager() { + this.player = null; + this.entities = new HashSet<>(); + this.currentViewing = new HashMap<>(); + } + + protected void setPlayer(Player player) { + if (this.player == null) { + this.player = player; + } else { + throw new RuntimeException("Player in PlayerInteractManager cannot be changed once created"); + } + } + + public Player getPlayer() { + return player; + } + + public void update() throws IOException { + if (player.clientConnection.getClientState() != ClientConnection.ClientState.PLAY && !player.clientConnection.isReady()) { + return; + } + + int viewDistanceChunks = Limbo.getInstance().getServerProperties().getViewDistance(); + int viewDistanceBlocks = viewDistanceChunks << 4; + Location location = player.getLocation(); + Set entitiesInRange = player.getWorld().getEntities().stream().filter(each -> each.getLocation().distanceSquared(location) < viewDistanceBlocks * viewDistanceBlocks).collect(Collectors.toSet()); + for (Entity entity : entitiesInRange) { + if (!entities.contains(entity)) { + PacketPlayOutSpawnEntity packet = new PacketPlayOutSpawnEntity(entity.getEntityId(), entity.getUniqueId(), entity.getType(), entity.getX(), entity.getY(), entity.getZ(), entity.getYaw(), entity.getPitch(), entity.getPitch(), 0, (short) 0, (short) 0, (short) 0); + player.clientConnection.sendPacket(packet); + + PacketPlayOutEntityMetadata meta = new PacketPlayOutEntityMetadata(entity); + player.clientConnection.sendPacket(meta); } - } - ClientboundChunkBatchFinishedPacket chunkBatchFinishedPacket = new ClientboundChunkBatchFinishedPacket(counter); - player.clientConnection.sendPacket(chunkBatchFinishedPacket); + } + List ids = new ArrayList<>(); + for (Entity entity : entities) { + if (!entitiesInRange.contains(entity)) { + ids.add(entity.getEntityId()); + } + } + for (int id : ids) { + PacketPlayOutEntityDestroy packet = new PacketPlayOutEntityDestroy(id); + player.clientConnection.sendPacket(packet); + } - currentViewing = chunksInRange; - } + entities = entitiesInRange; + + int playerChunkX = (int) location.getX() >> 4; + int playerChunkZ = (int) location.getZ() >> 4; + World world = location.getWorld(); + + Map chunksInRange = new HashMap<>(); + + for (int x = playerChunkX - viewDistanceChunks; x < playerChunkX + viewDistanceChunks; x++) { + for (int z = playerChunkZ - viewDistanceChunks; z < playerChunkZ + viewDistanceChunks; z++) { + Chunk chunk = world.getChunkAt(x, z); + if (chunk != null) { + chunksInRange.put(new ChunkPosition(world, x, z), chunk); + } else { + chunksInRange.put(new ChunkPosition(world, x, z), World.EMPTY_CHUNK); + } + } + } + + for (ChunkPosition chunkPos : currentViewing.keySet()) { + if (!chunksInRange.containsKey(chunkPos)) { + PacketPlayOutUnloadChunk packet = new PacketPlayOutUnloadChunk(chunkPos.getChunkX(), chunkPos.getChunkZ()); + player.clientConnection.sendPacket(packet); + } + } + + // blocks cannot be broken, so don't send chunks to the client + if (getPlayer().getGamemode() == GameMode.ADVENTURE) { + for (ChunkPosition chunkPos : chunksInRange.keySet()) { + currentViewing.remove(chunkPos); + } + } + + // if we don't have any chunk updates, don't send any packets + if (chunksInRange.isEmpty()) return; + + int counter = 0; + ClientboundChunkBatchStartPacket chunkBatchStartPacket = new ClientboundChunkBatchStartPacket(); + player.clientConnection.sendPacket(chunkBatchStartPacket); + for (Entry entry : chunksInRange.entrySet()) { + ChunkPosition chunkPos = entry.getKey(); + Chunk chunk = chunkPos.getWorld().getChunkAt(chunkPos.getChunkX(), chunkPos.getChunkZ()); + if (chunk == null) { + ClientboundLevelChunkWithLightPacket chunkdata = new ClientboundLevelChunkWithLightPacket(chunkPos.getChunkX(), chunkPos.getChunkZ(), entry.getValue(), world.getEnvironment(), Collections.emptyList(), Collections.emptyList()); + player.clientConnection.sendPacket(chunkdata); + } else { + List blockChunk = world.getLightEngineBlock().getBlockLightBitMask(chunkPos.getChunkX(), chunkPos.getChunkZ()); + if (blockChunk == null) { + blockChunk = new ArrayList<>(); + } + List skyChunk = null; + if (world.hasSkyLight()) { + skyChunk = world.getLightEngineSky().getSkyLightBitMask(chunkPos.getChunkX(), chunkPos.getChunkZ()); + } + if (skyChunk == null) { + skyChunk = new ArrayList<>(); + } + ClientboundLevelChunkWithLightPacket chunkdata = new ClientboundLevelChunkWithLightPacket(chunkPos.getChunkX(), chunkPos.getChunkZ(), chunk, world.getEnvironment(), skyChunk, blockChunk); + player.clientConnection.sendPacket(chunkdata); + } + counter++; + } + ClientboundChunkBatchFinishedPacket chunkBatchFinishedPacket = new ClientboundChunkBatchFinishedPacket(counter); + player.clientConnection.sendPacket(chunkBatchFinishedPacket); + + currentViewing = chunksInRange; + } }