Skip to content

Commit 4911e62

Browse files
committed
Minor optimizations in PlayerCubeMap
Avoid accessing gamerules for every cube being generated/loaded Don't use Multimap for cubesToSend as multimap is slower
1 parent 4eeac81 commit 4911e62

File tree

2 files changed

+32
-23
lines changed

2 files changed

+32
-23
lines changed

src/main/java/io/github/opencubicchunks/cubicchunks/core/server/PlayerCubeMap.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import static io.github.opencubicchunks.cubicchunks.api.util.Coords.blockToLocal;
2929
import io.github.opencubicchunks.cubicchunks.core.util.WatchersSortingList2D;
3030
import io.github.opencubicchunks.cubicchunks.core.util.WatchersSortingList3D;
31+
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
3132
import static net.minecraft.util.math.MathHelper.clamp;
3233

3334
import com.google.common.base.Predicate;
@@ -95,8 +96,6 @@
9596
public class PlayerCubeMap extends PlayerChunkMap {
9697

9798
private static final Predicate<EntityPlayerMP> NOT_SPECTATOR = player -> player != null && !player.isSpectator();
98-
private static final Predicate<EntityPlayerMP> CAN_GENERATE_CHUNKS = player -> player != null &&
99-
(!player.isSpectator() || player.getServerWorld().getGameRules().getBoolean("spectatorsGenerateChunks"));
10099

101100
/**
102101
* Cube selector is used to find which cube positions need to be loaded/unloaded
@@ -189,7 +188,7 @@ public class PlayerCubeMap extends PlayerChunkMap {
189188

190189
private final CubeProviderServer cubeCache;
191190

192-
private final Multimap<EntityPlayerMP, Cube> cubesToSend = Multimaps.newSetMultimap(new HashMap<>(), HashSet::new);
191+
private final Object2ObjectOpenHashMap<EntityPlayerMP, ObjectOpenHashSet<Cube>> cubesToSend = new Object2ObjectOpenHashMap<>(2);
193192

194193
// these player adds will be processed on the next tick
195194
// this exists as temporary workaround to player respawn code calling addPlayer() before spawning
@@ -287,6 +286,9 @@ private void addTickableColumns(TickableChunkContainer tickableChunksCubes) {
287286
@Override
288287
public void tick() {
289288
getWorldServer().profiler.startSection("playerCubeMapTick");
289+
boolean spectatorsGenerateChunks = getWorldServer().getGameRules().getBoolean("spectatorsGenerateChunks");
290+
Predicate<EntityPlayerMP> canGenerateChunkPredicate = player -> player != null && (spectatorsGenerateChunks ||!player.isSpectator());
291+
290292
long currentTime = this.getWorldServer().getTotalWorldTime();
291293

292294
getWorldServer().profiler.startSection("addPendingPlayers");
@@ -320,7 +322,6 @@ public void tick() {
320322
this.columnWatchersToUpdate.forEach(ColumnWatcher::update);
321323
this.columnWatchersToUpdate.clear();
322324
}
323-
324325
getWorldServer().profiler.endStartSection("sortTickableTracker");
325326
tickableCubeTracker.tick();
326327

@@ -329,7 +330,6 @@ public void tick() {
329330
this.columnsToGenerate.tick();
330331

331332
getWorldServer().profiler.endStartSection("sortToSend");
332-
//sort cubesToSendToClients every other 4 ticks
333333
this.cubesToSendToClients.tick();
334334
this.columnsToSendToClients.tick();
335335
this.watchersToAddPlayersTo.tick();
@@ -343,7 +343,7 @@ public void tick() {
343343

344344
boolean success = entry.getChunk() != null;
345345
if (!success) {
346-
boolean canGenerate = entry.hasPlayerMatching(CAN_GENERATE_CHUNKS);
346+
boolean canGenerate = entry.hasPlayerMatching(canGenerateChunkPredicate);
347347
getWorldServer().profiler.startSection("generate");
348348
success = entry.providePlayerChunk(canGenerate);
349349
getWorldServer().profiler.endSection(); // generate
@@ -375,7 +375,7 @@ public void tick() {
375375
boolean success = !watcher.isWaitingForCube();
376376
boolean alreadyLoaded = success;
377377
if (!success) {
378-
boolean canGenerate = watcher.hasPlayerMatching(CAN_GENERATE_CHUNKS);
378+
boolean canGenerate = watcher.hasPlayerMatching(canGenerateChunkPredicate);
379379
getWorldServer().profiler.startSection("generate");
380380
success = watcher.providePlayerCube(canGenerate);
381381
getWorldServer().profiler.endSection();
@@ -894,7 +894,8 @@ public void removeEntry(ColumnWatcher entry) {
894894
}
895895

896896
public void scheduleSendCubeToPlayer(Cube cube, EntityPlayerMP player) {
897-
cubesToSend.put(player, cube);
897+
ObjectOpenHashSet<Cube> cubes = cubesToSend.computeIfAbsent(player, k -> new ObjectOpenHashSet<>(1024));
898+
cubes.add(cube);
898899
}
899900

900901
public void removeSchedulesSendCubeToPlayer(Cube cube, EntityPlayerMP player) {

src/main/java/io/github/opencubicchunks/cubicchunks/core/world/ServerHeightMap.java

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -738,32 +738,40 @@ public byte[] getData() {
738738
}
739739

740740
public void readData(byte[] data) {
741-
try {
742-
ByteArrayInputStream buf = new ByteArrayInputStream(data);
743-
DataInputStream in = new DataInputStream(buf);
744-
readData(in);
745-
in.close();
746-
} catch (IOException ex) {
747-
throw new Error(ex);
748-
}
749-
}
750-
751-
private void readData(DataInputStream in) throws IOException {
741+
int pos = 0;
752742
for (int i = 0; i < this.segments.length; i++) {
753-
this.ymin[i] = in.readInt();
754-
this.ymax.set(i, in.readInt());
755-
int[] segments = new int[in.readUnsignedShort()];
743+
this.ymin[i] = readIntBigEndian(data, pos);
744+
pos += Integer.BYTES;
745+
this.ymax.set(i, readIntBigEndian(data, pos));
746+
pos += Integer.BYTES;
747+
int[] segments = new int[readUShortBigEndian(data, pos)];
748+
pos += Short.BYTES;
756749
if (segments.length == 0) {
757750
continue;
758751
}
759752
for (int j = 0; j < segments.length; j++) {
760-
segments[j] = in.readInt();
753+
segments[j] = readIntBigEndian(data, pos);
754+
pos += Integer.BYTES;
761755
}
762756
this.segments[i] = segments;
763757
assert parityCheck(i) : "The number of segments was wrong!";
764758
}
765759
}
766760

761+
private int readIntBigEndian(byte[] arr, int pos) {
762+
int ch1 = arr[pos] & 0xFF;
763+
int ch2 = arr[pos+1] & 0xFF;
764+
int ch3 = arr[pos+2] & 0xFF;
765+
int ch4 = arr[pos+3] & 0xFF;
766+
return (ch1 << 24) | (ch2 << 16) | (ch3 << 8) | ch4;
767+
}
768+
769+
private int readUShortBigEndian(byte[] arr, int pos) {
770+
int ch1 = arr[pos] & 0xFF;
771+
int ch2 = arr[pos+1] & 0xFF;
772+
return (ch1 << 8) | ch2;
773+
}
774+
767775
private void writeData(DataOutputStream out) throws IOException {
768776
for (int i = 0; i < this.segments.length; i++) {
769777
out.writeInt(this.ymin[i]);

0 commit comments

Comments
 (0)