From a0bb437c4c9cb7ceffb52d667f2b687d8080aa25 Mon Sep 17 00:00:00 2001 From: TheMode Date: Wed, 21 Jul 2021 22:21:43 +0200 Subject: [PATCH] Reduce chunk entities Set allocation --- .../net/minestom/server/entity/Player.java | 5 +-- .../minestom/server/instance/Instance.java | 38 +++++++++++++------ .../server/instance/InstanceContainer.java | 4 +- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 865f60d74..eec3993a7 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -1434,10 +1434,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, */ public void refreshVisibleChunks(@NotNull Chunk newChunk) { // Previous chunks indexes - final long[] lastVisibleChunks = viewableChunks.stream().mapToLong(viewableChunks -> - ChunkUtils.getChunkIndex(viewableChunks.getChunkX(), viewableChunks.getChunkZ()) - ).toArray(); - + final long[] lastVisibleChunks = viewableChunks.stream().mapToLong(ChunkUtils::getChunkIndex).toArray(); // New chunks indexes final long[] updatedVisibleChunks = ChunkUtils.getChunksInRange(newChunk.toPosition(), getChunkRange()); diff --git a/src/main/java/net/minestom/server/instance/Instance.java b/src/main/java/net/minestom/server/instance/Instance.java index 7287dfae6..377ed1900 100644 --- a/src/main/java/net/minestom/server/instance/Instance.java +++ b/src/main/java/net/minestom/server/instance/Instance.java @@ -1,5 +1,7 @@ package net.minestom.server.instance; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import net.kyori.adventure.identity.Identity; import net.kyori.adventure.pointer.Pointers; import net.minestom.server.MinecraftServer; @@ -83,8 +85,8 @@ public abstract class Instance implements BlockGetter, BlockSetter, Tickable, Ta protected final Set creatures = ConcurrentHashMap.newKeySet(); protected final Set experienceOrbs = ConcurrentHashMap.newKeySet(); // Entities per chunk - protected final Map> chunkEntities = new ConcurrentHashMap<>(); - private final Object entitiesLock = new Object(); // Lock used to prevent the entities Set and Map to be subject to race condition + protected final Object entitiesLock = new Object(); // Lock used to prevent the entities Set and Map to be subject to race condition + protected final Long2ObjectMap> chunkEntities = new Long2ObjectOpenHashMap<>(); // the uuid of this instance protected UUID uniqueId; @@ -486,9 +488,12 @@ public abstract class Instance implements BlockGetter, BlockSetter, Tickable, Ta public @NotNull Set getChunkEntities(Chunk chunk) { if (!ChunkUtils.isLoaded(chunk)) return Collections.emptySet(); - - final long index = ChunkUtils.getChunkIndex(chunk.getChunkX(), chunk.getChunkZ()); - final Set entities = getEntitiesInChunk(index); + final Set entities; + synchronized (entitiesLock) { + if ((entities = chunkEntities.get(ChunkUtils.getChunkIndex(chunk))) == null) { + return Collections.emptySet(); + } + } return Collections.unmodifiableSet(entities); } @@ -642,15 +647,15 @@ public abstract class Instance implements BlockGetter, BlockSetter, Tickable, Ta final long oldIndex = ChunkUtils.getChunkIndex(lastChunk); final long newIndex = ChunkUtils.getChunkIndex(newChunk); synchronized (entitiesLock) { - getEntitiesInChunk(oldIndex).remove(entity); - getEntitiesInChunk(newIndex).add(entity); + removeEntityChunk(oldIndex, entity); + addEntityChunk(newIndex, entity); } } private void UNSAFE_addEntityToChunk(@NotNull Entity entity, @NotNull Chunk chunk) { final long chunkIndex = ChunkUtils.getChunkIndex(chunk); synchronized (entitiesLock) { - getEntitiesInChunk(chunkIndex).add(entity); + addEntityChunk(chunkIndex, entity); this.entities.add(entity); if (entity instanceof Player) { this.players.add((Player) entity); @@ -665,7 +670,7 @@ public abstract class Instance implements BlockGetter, BlockSetter, Tickable, Ta private void UNSAFE_removeEntityFromChunk(@NotNull Entity entity, @NotNull Chunk chunk) { final long chunkIndex = ChunkUtils.getChunkIndex(chunk); synchronized (entitiesLock) { - getEntitiesInChunk(chunkIndex).remove(entity); + removeEntityChunk(chunkIndex, entity); this.entities.remove(entity); if (entity instanceof Player) { this.players.remove(entity); @@ -677,9 +682,18 @@ public abstract class Instance implements BlockGetter, BlockSetter, Tickable, Ta } } - @NotNull - private Set getEntitiesInChunk(long index) { - return chunkEntities.computeIfAbsent(index, i -> ConcurrentHashMap.newKeySet()); + private void addEntityChunk(long index, Entity entity) { + this.chunkEntities.computeIfAbsent(index, i -> ConcurrentHashMap.newKeySet()).add(entity); + } + + private void removeEntityChunk(long index, Entity entity) { + var chunkEntities = this.chunkEntities.get(index); + if (chunkEntities != null) { + chunkEntities.remove(entity); + if (chunkEntities.isEmpty()) { + this.chunkEntities.remove(index); + } + } } /** diff --git a/src/main/java/net/minestom/server/instance/InstanceContainer.java b/src/main/java/net/minestom/server/instance/InstanceContainer.java index 6dcb2155e..72f71a6b7 100644 --- a/src/main/java/net/minestom/server/instance/InstanceContainer.java +++ b/src/main/java/net/minestom/server/instance/InstanceContainer.java @@ -566,7 +566,9 @@ public class InstanceContainer extends Instance { // Clear cache this.chunks.remove(index); - this.chunkEntities.remove(index); + synchronized (entitiesLock){ + this.chunkEntities.remove(index); + } chunk.unload();