Skip to content

Commit 12ed57c

Browse files
MomotherealPostremus
authored andcommitted
Memory usage optimization with chunks (#569)
* Initial optimization w/ caching for chunk keys * Unify Key hashCode function
1 parent 76bf760 commit 12ed57c

File tree

10 files changed

+52
-21
lines changed

10 files changed

+52
-21
lines changed

src/main/java/net/glowstone/GlowWorld.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ private void updateActiveChunkCollection(GlowEntity entity) {
426426
for (int x = cx - radius; x <= cx + radius; x++) {
427427
for (int z = cz - radius; z <= cz + radius; z++) {
428428
if (isChunkLoaded(cx, cz)) {
429-
activeChunksSet.add(new Key(x, z));
429+
activeChunksSet.add(GlowChunk.ChunkKeyStore.get(x, z));
430430
}
431431
}
432432
}
@@ -827,7 +827,7 @@ private void prepareSpawn() {
827827
} else {
828828
loadChunk(x, z);
829829
}
830-
spawnChunkLock.acquire(new Key(x, z));
830+
spawnChunkLock.acquire(GlowChunk.ChunkKeyStore.get(x, z));
831831
if (System.currentTimeMillis() >= loadTime + 1000) {
832832
int progress = 100 * current / total;
833833
GlowServer.logger.info("Preparing spawn for " + name + ": " + progress + "%");
@@ -1271,7 +1271,7 @@ public boolean refreshChunk(int x, int z) {
12711271
return false;
12721272
}
12731273

1274-
Key key = new Key(x, z);
1274+
Key key = GlowChunk.ChunkKeyStore.get(x, z);
12751275
boolean result = false;
12761276

12771277
for (GlowPlayer player : getRawPlayers()) {

src/main/java/net/glowstone/block/entity/BlockEntity.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import net.glowstone.block.GlowBlock;
44
import net.glowstone.block.GlowBlockState;
5+
import net.glowstone.chunk.GlowChunk;
56
import net.glowstone.chunk.GlowChunk.Key;
67
import net.glowstone.entity.GlowPlayer;
78
import net.glowstone.util.nbt.CompoundTag;
@@ -41,7 +42,7 @@ public final Block getBlock() {
4142
* Update this BlockEntity's visible state to all players in range.
4243
*/
4344
public final void updateInRange() {
44-
Key key = new Key(block.getChunk().getX(), block.getChunk().getZ());
45+
Key key = GlowChunk.ChunkKeyStore.get(block.getChunk().getX(), block.getChunk().getZ());
4546
block.getWorld().getRawPlayers().stream().filter(player -> player.canSeeChunk(key)).forEach(this::update);
4647
}
4748

src/main/java/net/glowstone/block/itemtype/ItemPainting.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.util.List;
1010
import java.util.concurrent.ThreadLocalRandom;
1111
import net.glowstone.block.GlowBlock;
12+
import net.glowstone.chunk.GlowChunk;
1213
import net.glowstone.chunk.GlowChunk.Key;
1314
import net.glowstone.entity.GlowPlayer;
1415
import net.glowstone.entity.objects.GlowPainting;
@@ -37,7 +38,7 @@ public class ItemPainting extends ItemType {
3738
)
3839
).arrayListValues().build();
3940

40-
Arrays.stream(Art.values()).forEach(art -> ART_BY_SIZE.put(new Key(art.getBlockHeight(), art.getBlockWidth()), art));
41+
Arrays.stream(Art.values()).forEach(art -> ART_BY_SIZE.put(GlowChunk.ChunkKeyStore.get(art.getBlockHeight(), art.getBlockWidth()), art));
4142
}
4243

4344
@Override

src/main/java/net/glowstone/block/state/GlowNoteBlock.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import net.glowstone.block.GlowBlock;
55
import net.glowstone.block.GlowBlockState;
66
import net.glowstone.block.entity.NoteblockEntity;
7+
import net.glowstone.chunk.GlowChunk;
78
import net.glowstone.chunk.GlowChunk.Key;
89
import org.bukkit.Instrument;
910
import org.bukkit.Location;
@@ -196,7 +197,7 @@ public boolean play(Instrument instrument, Note note) {
196197

197198
Location location = getBlock().getLocation();
198199

199-
Key key = new Key(getX() >> 4, getZ() >> 4);
200+
Key key = GlowChunk.ChunkKeyStore.get(getX() >> 4, getZ() >> 4);
200201
getWorld().getRawPlayers().stream().filter(player -> player.canSeeChunk(key)).forEach(player -> player.playNote(location, instrument, note));
201202

202203
return true;

src/main/java/net/glowstone/chunk/ChunkManager.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public ChunkGenerator getGenerator() {
9696
* @return The chunk.
9797
*/
9898
public GlowChunk getChunk(int x, int z) {
99-
Key key = new Key(x, z);
99+
Key key = GlowChunk.ChunkKeyStore.get(x, z);
100100
if (chunks.containsKey(key)) {
101101
return chunks.get(key);
102102
} else {
@@ -115,7 +115,7 @@ public GlowChunk getChunk(int x, int z) {
115115
* @return true if the chunk is loaded, otherwise false.
116116
*/
117117
public boolean isChunkLoaded(int x, int z) {
118-
Key key = new Key(x, z);
118+
Key key = GlowChunk.ChunkKeyStore.get(x, z);
119119
return chunks.containsKey(key) && chunks.get(key).isLoaded();
120120
}
121121

@@ -127,7 +127,7 @@ public boolean isChunkLoaded(int x, int z) {
127127
* @return Whether the chunk is in use.
128128
*/
129129
public boolean isChunkInUse(int x, int z) {
130-
Key key = new Key(x, z);
130+
Key key = GlowChunk.ChunkKeyStore.get(x, z);
131131
Set<ChunkLock> lockSet = locks.get(key);
132132
return lockSet != null && !lockSet.isEmpty();
133133
}

src/main/java/net/glowstone/chunk/GlowChunk.java

+30-3
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ private void initializeSection(int y, ChunkSection section) {
282282
* @param cy the Y coordinate of the BlockEntity
283283
* @param cz the Z coordinate of the BlockEntity
284284
* @param type the type of BlockEntity
285-
* @return The BlockEntity that was created.
285+
* @return The BlockEntity that was created.
286286
*/
287287
public BlockEntity createEntity(int cx, int cy, int cz, int type) {
288288
Material material = Material.getMaterial(type);
@@ -694,7 +694,7 @@ public ChunkDataMessage toMessage(boolean skylight) {
694694
* Creates a new {@link ChunkDataMessage} which can be sent to a client to stream
695695
* parts of this chunk to them.
696696
*
697-
* @param skylight Whether to include skylight data.
697+
* @param skylight Whether to include skylight data.
698698
* @param entireChunk Whether to send all chunk sections.
699699
* @return The {@link ChunkDataMessage}.
700700
*/
@@ -755,7 +755,34 @@ public static final class Key {
755755
/**
756756
* The coordinates.
757757
*/
758-
private final int x, z;
758+
private final int x, z, hashCode;
759+
760+
private Key(int x, int z) {
761+
this.x = x;
762+
this.z = z;
763+
this.hashCode = hashCode(x, z);
764+
}
765+
766+
@Override
767+
public int hashCode() {
768+
return hashCode;
769+
}
770+
771+
private static int hashCode(int x, int z) {
772+
return x * 31 + z;
773+
}
759774
}
760775

776+
public static final class ChunkKeyStore {
777+
private static final ConcurrentHashMap<Integer, Key> keys = new ConcurrentHashMap<>();
778+
779+
public static Key get(int x, int z) {
780+
int id = Key.hashCode(x, z);
781+
Key key = keys.get(id);
782+
if (key != null) return key;
783+
key = new Key(x, z);
784+
keys.put(id, key);
785+
return key;
786+
}
787+
}
761788
}

src/main/java/net/glowstone/entity/GlowPlayer.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,7 @@ private void processBlockChanges() {
734734
Map<Key, Map<BlockVector, BlockChangeMessage>> chunks = new HashMap<>();
735735
for (BlockChangeMessage message : messages) {
736736
if (message != null) {
737-
Key key = new Key(message.getX() >> 4, message.getZ() >> 4);
737+
Key key = GlowChunk.ChunkKeyStore.get(message.getX() >> 4, message.getZ() >> 4);
738738
if (canSeeChunk(key)) {
739739
Map<BlockVector, BlockChangeMessage> map = chunks.computeIfAbsent(key, k -> new HashMap<>());
740740
map.put(new BlockVector(message.getX(), message.getY(), message.getZ()), message);
@@ -772,7 +772,7 @@ private void streamBlocks() {
772772
int radius = Math.min(server.getViewDistance(), 1 + settings.getViewDistance());
773773
for (int x = centralX - radius; x <= centralX + radius; x++) {
774774
for (int z = centralZ - radius; z <= centralZ + radius; z++) {
775-
Key key = new Key(x, z);
775+
Key key = GlowChunk.ChunkKeyStore.get(x, z);
776776
if (knownChunks.contains(key)) {
777777
previousChunks.remove(key);
778778
} else {
@@ -2188,7 +2188,7 @@ public void sendBlockChange(Location loc, int material, byte data) {
21882188

21892189
public void sendBlockChange(BlockChangeMessage message) {
21902190
// only send message if the chunk is within visible range
2191-
Key key = new Key(message.getX() >> 4, message.getZ() >> 4);
2191+
Key key = GlowChunk.ChunkKeyStore.get(message.getX() >> 4, message.getZ() >> 4);
21922192
if (canSeeChunk(key)) {
21932193
blockChanges.add(message);
21942194
}
@@ -2953,7 +2953,7 @@ private void sendBlockBreakAnimation(Location loc, int destroyStage) {
29532953
}
29542954

29552955
private void broadcastBlockBreakAnimation(GlowBlock block, int destroyStage) {
2956-
GlowChunk.Key key = new GlowChunk.Key(block.getChunk().getX(), block.getChunk().getZ());
2956+
GlowChunk.Key key = GlowChunk.ChunkKeyStore.get(block.getChunk().getX(), block.getChunk().getZ());
29572957
block.getWorld().getRawPlayers().stream()
29582958
.filter(player -> player.canSeeChunk(key) && player != this)
29592959
.forEach(player -> player.sendBlockBreakAnimation(block.getLocation(), destroyStage));

src/main/java/net/glowstone/entity/objects/GlowItemFrame.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.flowpowered.network.Message;
44
import net.glowstone.EventFactory;
5+
import net.glowstone.chunk.GlowChunk;
56
import net.glowstone.chunk.GlowChunk.Key;
67
import net.glowstone.entity.GlowHangingEntity;
78
import net.glowstone.entity.GlowPlayer;
@@ -147,7 +148,7 @@ private void createTeleportMessage(BlockFace face) {
147148
break;
148149
}
149150

150-
Key key = new Key(location.getChunk().getX(), location.getChunk().getZ());
151+
Key key = GlowChunk.ChunkKeyStore.get(location.getChunk().getX(), location.getChunk().getZ());
151152
for (GlowPlayer player : getWorld().getRawPlayers()) {
152153
if (player.canSeeChunk(key)) {
153154
double x = location.getX();

src/main/java/net/glowstone/generator/populators/StructurePopulator.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import net.glowstone.GlowServer;
44
import net.glowstone.GlowWorld;
5-
import net.glowstone.chunk.GlowChunk.Key;
5+
import net.glowstone.chunk.GlowChunk;
66
import net.glowstone.generator.structures.GlowStructure;
77
import net.glowstone.io.structure.StructureStorage;
88
import net.glowstone.io.structure.StructureStore;
@@ -36,7 +36,7 @@ public void populate(World world, Random random, Chunk source) {
3636
if (world.getChunkAt(x, z).isLoaded() || world.getChunkAt(x, z).load(true)) {
3737
random.setSeed(x * xRand + z * zRand ^ world.getSeed());
3838
Map<Integer, GlowStructure> structures = ((GlowWorld) world).getStructures();
39-
int key = new Key(x, z).hashCode();
39+
int key = GlowChunk.ChunkKeyStore.get(x, z).hashCode();
4040
if (!structures.containsKey(key)) {
4141
for (StructureStore<?> store : StructureStorage.getStructureStores()) {
4242
GlowStructure structure = store.createNewStructure((GlowWorld) world, random, x, z);

src/main/java/net/glowstone/io/nbt/NbtStructureDataService.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import net.glowstone.GlowServer;
44
import net.glowstone.GlowWorld;
5-
import net.glowstone.chunk.GlowChunk.Key;
5+
import net.glowstone.chunk.GlowChunk;
66
import net.glowstone.generator.structures.GlowStructure;
77
import net.glowstone.io.StructureDataService;
88
import net.glowstone.io.structure.StructureStorage;
@@ -51,7 +51,7 @@ public Map<Integer, GlowStructure> readStructuresData() {
5151
CompoundTag features = data.getCompound("Features");
5252
features.getValue().keySet().stream().filter(features::isCompound).forEach(key -> {
5353
GlowStructure structure = StructureStorage.loadStructure(world, features.getCompound(key));
54-
structures.put(new Key(structure.getChunkX(), structure.getChunkZ()).hashCode(), structure);
54+
structures.put(GlowChunk.ChunkKeyStore.get(structure.getChunkX(), structure.getChunkZ()).hashCode(), structure);
5555
});
5656
}
5757
} else {

0 commit comments

Comments
 (0)