Skip to content

Commit

Permalink
Optimise multiple block updates occurring in the same chunk
Browse files Browse the repository at this point in the history
We can avoid multiple ticket additions for the same ChunkTasks
instance. This will help in situations where significant number of
block updates occur for the same chunk in the same tick, such as
water draining.
  • Loading branch information
Spottedleaf committed Sep 11, 2023
1 parent c9cd94f commit fb06829
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 62 deletions.
81 changes: 45 additions & 36 deletions patches/server/0016-Starlight.patch
Original file line number Diff line number Diff line change
Expand Up @@ -3035,10 +3035,10 @@ index 0000000000000000000000000000000000000000..ad1eeebe6de219143492b94da309cb54
+}
diff --git a/src/main/java/ca/spottedleaf/starlight/common/light/StarLightInterface.java b/src/main/java/ca/spottedleaf/starlight/common/light/StarLightInterface.java
new file mode 100644
index 0000000000000000000000000000000000000000..146c78a333e47cb4d8aa97700e19a12ca176ce76
index 0000000000000000000000000000000000000000..499c069d64692872924963d3a7ac39664b20468d
--- /dev/null
+++ b/src/main/java/ca/spottedleaf/starlight/common/light/StarLightInterface.java
@@ -0,0 +1,673 @@
@@ -0,0 +1,674 @@
+package ca.spottedleaf.starlight.common.light;
+
+import ca.spottedleaf.starlight.common.util.CoordinateUtils;
Expand Down Expand Up @@ -3233,7 +3233,7 @@ index 0000000000000000000000000000000000000000..146c78a333e47cb4d8aa97700e19a12c
+ return this.hasBlockLight;
+ }
+
+ protected int getSkyLightValue(final BlockPos blockPos, final ChunkAccess chunk) {
+ public int getSkyLightValue(final BlockPos blockPos, final ChunkAccess chunk) {
+ if (!this.hasSkyLight) {
+ return 0;
+ }
Expand Down Expand Up @@ -3303,7 +3303,7 @@ index 0000000000000000000000000000000000000000..146c78a333e47cb4d8aa97700e19a12c
+ return 15;
+ }
+
+ protected int getBlockLightValue(final BlockPos blockPos, final ChunkAccess chunk) {
+ public int getBlockLightValue(final BlockPos blockPos, final ChunkAccess chunk) {
+ if (!this.hasBlockLight) {
+ return 0;
+ }
Expand Down Expand Up @@ -3422,15 +3422,15 @@ index 0000000000000000000000000000000000000000..146c78a333e47cb4d8aa97700e19a12c
+ }
+ }
+
+ public CompletableFuture<Void> blockChange(final BlockPos pos) {
+ public LightQueue.ChunkTasks blockChange(final BlockPos pos) {
+ if (this.world == null || pos.getY() < WorldUtil.getMinBlockY(this.world) || pos.getY() > WorldUtil.getMaxBlockY(this.world)) { // empty world
+ return null;
+ }
+
+ return this.lightQueue.queueBlockChange(pos);
+ }
+
+ public CompletableFuture<Void> sectionChange(final SectionPos pos, final boolean newEmptyValue) {
+ public LightQueue.ChunkTasks sectionChange(final SectionPos pos, final boolean newEmptyValue) {
+ if (this.world == null) { // empty world
+ return null;
+ }
Expand Down Expand Up @@ -3613,7 +3613,7 @@ index 0000000000000000000000000000000000000000..146c78a333e47cb4d8aa97700e19a12c
+ }
+ }
+
+ protected static final class LightQueue {
+ public static final class LightQueue {
+
+ protected final Long2ObjectLinkedOpenHashMap<ChunkTasks> chunkTasks = new Long2ObjectLinkedOpenHashMap<>();
+ protected final StarLightInterface manager;
Expand All @@ -3626,34 +3626,34 @@ index 0000000000000000000000000000000000000000..146c78a333e47cb4d8aa97700e19a12c
+ return this.chunkTasks.isEmpty();
+ }
+
+ public synchronized CompletableFuture<Void> queueBlockChange(final BlockPos pos) {
+ public synchronized LightQueue.ChunkTasks queueBlockChange(final BlockPos pos) {
+ final ChunkTasks tasks = this.chunkTasks.computeIfAbsent(CoordinateUtils.getChunkKey(pos), ChunkTasks::new);
+ tasks.changedPositions.add(pos.immutable());
+ return tasks.onComplete;
+ return tasks;
+ }
+
+ public synchronized CompletableFuture<Void> queueSectionChange(final SectionPos pos, final boolean newEmptyValue) {
+ public synchronized LightQueue.ChunkTasks queueSectionChange(final SectionPos pos, final boolean newEmptyValue) {
+ final ChunkTasks tasks = this.chunkTasks.computeIfAbsent(CoordinateUtils.getChunkKey(pos), ChunkTasks::new);
+
+ if (tasks.changedSectionSet == null) {
+ tasks.changedSectionSet = new Boolean[this.manager.maxSection - this.manager.minSection + 1];
+ }
+ tasks.changedSectionSet[pos.getY() - this.manager.minSection] = Boolean.valueOf(newEmptyValue);
+
+ return tasks.onComplete;
+ return tasks;
+ }
+
+ public synchronized CompletableFuture<Void> queueChunkLighting(final ChunkPos pos, final Runnable lightTask) {
+ public synchronized LightQueue.ChunkTasks queueChunkLighting(final ChunkPos pos, final Runnable lightTask) {
+ final ChunkTasks tasks = this.chunkTasks.computeIfAbsent(CoordinateUtils.getChunkKey(pos), ChunkTasks::new);
+ if (tasks.lightTasks == null) {
+ tasks.lightTasks = new ArrayList<>();
+ }
+ tasks.lightTasks.add(lightTask);
+
+ return tasks.onComplete;
+ return tasks;
+ }
+
+ public synchronized CompletableFuture<Void> queueChunkSkylightEdgeCheck(final SectionPos pos, final ShortCollection sections) {
+ public synchronized LightQueue.ChunkTasks queueChunkSkylightEdgeCheck(final SectionPos pos, final ShortCollection sections) {
+ final ChunkTasks tasks = this.chunkTasks.computeIfAbsent(CoordinateUtils.getChunkKey(pos), ChunkTasks::new);
+
+ ShortOpenHashSet queuedEdges = tasks.queuedEdgeChecksSky;
Expand All @@ -3662,10 +3662,10 @@ index 0000000000000000000000000000000000000000..146c78a333e47cb4d8aa97700e19a12c
+ }
+ queuedEdges.addAll(sections);
+
+ return tasks.onComplete;
+ return tasks;
+ }
+
+ public synchronized CompletableFuture<Void> queueChunkBlocklightEdgeCheck(final SectionPos pos, final ShortCollection sections) {
+ public synchronized LightQueue.ChunkTasks queueChunkBlocklightEdgeCheck(final SectionPos pos, final ShortCollection sections) {
+ final ChunkTasks tasks = this.chunkTasks.computeIfAbsent(CoordinateUtils.getChunkKey(pos), ChunkTasks::new);
+
+ ShortOpenHashSet queuedEdges = tasks.queuedEdgeChecksBlock;
Expand All @@ -3674,7 +3674,7 @@ index 0000000000000000000000000000000000000000..146c78a333e47cb4d8aa97700e19a12c
+ }
+ queuedEdges.addAll(sections);
+
+ return tasks.onComplete;
+ return tasks;
+ }
+
+ public void removeChunk(final ChunkPos pos) {
Expand All @@ -3694,14 +3694,15 @@ index 0000000000000000000000000000000000000000..146c78a333e47cb4d8aa97700e19a12c
+ return this.chunkTasks.removeFirst();
+ }
+
+ protected static final class ChunkTasks {
+ public static final class ChunkTasks {
+
+ public final Set<BlockPos> changedPositions = new ObjectOpenHashSet<>();
+ public Boolean[] changedSectionSet;
+ public ShortOpenHashSet queuedEdgeChecksSky;
+ public ShortOpenHashSet queuedEdgeChecksBlock;
+ public List<Runnable> lightTasks;
+
+ public boolean isTicketAdded = false;
+ public final CompletableFuture<Void> onComplete = new CompletableFuture<>();
+
+ public final long chunkCoordinate;
Expand Down Expand Up @@ -4518,7 +4519,7 @@ index d8b83c8c89143d78620f812c491a1950e3218eb1..f3c9a3dbb6f0e6f825b7477c89ed72ed

while (objectiterator.hasNext()) {
diff --git a/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java b/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java
index 65d72701b13c25dd701533833055e77c2aff9db8..481272124b7589cff0aa05b6df5b7e6f1d539414 100644
index 65d72701b13c25dd701533833055e77c2aff9db8..6716d9acc8b31f3fc3642b47fa52ce32c5195a3e 100644
--- a/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java
+++ b/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java
@@ -23,6 +23,17 @@ import net.minecraft.world.level.chunk.LightChunkGetter;
Expand All @@ -4539,7 +4540,7 @@ index 65d72701b13c25dd701533833055e77c2aff9db8..481272124b7589cff0aa05b6df5b7e6f
public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCloseable {
public static final int DEFAULT_BATCH_SIZE = 1000;
private static final Logger LOGGER = LogUtils.getLogger();
@@ -33,12 +44,153 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl
@@ -33,13 +44,161 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl
private final int taskPerBatch = 1000;
private final AtomicBoolean scheduled = new AtomicBoolean();

Expand Down Expand Up @@ -4614,7 +4615,8 @@ index 65d72701b13c25dd701533833055e77c2aff9db8..481272124b7589cff0aa05b6df5b7e6f
+
+ private final Long2IntOpenHashMap chunksBeingWorkedOn = new Long2IntOpenHashMap();
+
+ private void queueTaskForSection(final int chunkX, final int chunkY, final int chunkZ, final Supplier<CompletableFuture<Void>> runnable) {
+ private void queueTaskForSection(final int chunkX, final int chunkY, final int chunkZ,
+ final Supplier<ca.spottedleaf.starlight.common.light.StarLightInterface.LightQueue.ChunkTasks> runnable) {
+ final ServerLevel world = (ServerLevel)this.theLightEngine.getWorld();
+
+ final ChunkAccess center = this.theLightEngine.getAnyChunkNow(chunkX, chunkZ);
Expand All @@ -4641,20 +4643,26 @@ index 65d72701b13c25dd701533833055e77c2aff9db8..481272124b7589cff0aa05b6df5b7e6f
+
+ final long key = CoordinateUtils.getChunkKey(chunkX, chunkZ);
+
+ final CompletableFuture<Void> updateFuture = runnable.get();
+ final ca.spottedleaf.starlight.common.light.StarLightInterface.LightQueue.ChunkTasks updateFuture = runnable.get();
+
+ if (updateFuture == null) {
+ // not scheduled
+ return;
+ }
+
+ if (updateFuture.isTicketAdded) {
+ // ticket already added
+ return;
+ }
+ updateFuture.isTicketAdded = true;
+
+ final int references = this.chunksBeingWorkedOn.addTo(key, 1);
+ if (references == 0) {
+ final ChunkPos pos = new ChunkPos(chunkX, chunkZ);
+ world.getChunkSource().addRegionTicket(ca.spottedleaf.starlight.common.light.StarLightInterface.CHUNK_WORK_TICKET, pos, 0, pos);
+ }
+
+ updateFuture.thenAcceptAsync((final Void ignore) -> {
+ updateFuture.onComplete.thenAcceptAsync((final Void ignore) -> {
+ final int newReferences = this.chunksBeingWorkedOn.get(key);
+ if (newReferences == 1) {
+ this.chunksBeingWorkedOn.remove(key);
Expand All @@ -4668,8 +4676,8 @@ index 65d72701b13c25dd701533833055e77c2aff9db8..481272124b7589cff0aa05b6df5b7e6f
+ LOGGER.error("Failed to remove ticket level for post chunk task " + new ChunkPos(chunkX, chunkZ), thr);
+ }
+ });
+ }
+
}
+ @Override
+ public boolean hasLightWork() {
+ // route to new light engine
Expand All @@ -4689,12 +4697,13 @@ index 65d72701b13c25dd701533833055e77c2aff9db8..481272124b7589cff0aa05b6df5b7e6f
+ if (sky == 15) return 15;
+ final int block = this.theLightEngine.getBlockReader().getLightValue(pos);
+ return Math.max(sky, block);
}
+ }
+ // Paper end - replace light engine imp
+
@Override
public void close() {
@@ -51,15 +203,16 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl
}
@@ -51,15 +210,16 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl

@Override
public void checkBlock(BlockPos pos) {
Expand All @@ -4717,7 +4726,7 @@ index 65d72701b13c25dd701533833055e77c2aff9db8..481272124b7589cff0aa05b6df5b7e6f
this.addTask(pos.x, pos.z, () -> {
return 0;
}, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> {
@@ -82,17 +235,16 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl
@@ -82,17 +242,16 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl

@Override
public void updateSectionStatus(SectionPos pos, boolean notReady) {
Expand All @@ -4741,39 +4750,39 @@ index 65d72701b13c25dd701533833055e77c2aff9db8..481272124b7589cff0aa05b6df5b7e6f
this.addTask(chunkPos.x, chunkPos.z, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> {
super.propagateLightSources(chunkPos);
}, () -> {
@@ -102,6 +254,7 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl
@@ -102,6 +261,7 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl

@Override
public void setLightEnabled(ChunkPos pos, boolean retainData) {
+ if (true) return; // Paper - replace light engine impl
this.addTask(pos.x, pos.z, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> {
super.setLightEnabled(pos, retainData);
}, () -> {
@@ -111,6 +264,7 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl
@@ -111,6 +271,7 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl

@Override
public void queueSectionData(LightLayer lightType, SectionPos pos, @Nullable DataLayer nibbles) {
+ if (true) return; // Paper - replace light engine impl
this.addTask(pos.x(), pos.z(), () -> {
return 0;
}, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> {
@@ -136,6 +290,7 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl
@@ -136,6 +297,7 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl

@Override
public void retainData(ChunkPos pos, boolean retainData) {
+ if (true) return; // Paper - replace light engine impl
this.addTask(pos.x, pos.z, () -> {
return 0;
}, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> {
@@ -146,6 +301,7 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl
@@ -146,6 +308,7 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl
}

public CompletableFuture<ChunkAccess> initializeLight(ChunkAccess chunk, boolean bl) {
+ if (true) return CompletableFuture.completedFuture(chunk); // Paper - replace light engine impl
ChunkPos chunkPos = chunk.getPos();
this.addTask(chunkPos.x, chunkPos.z, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> {
LevelChunkSection[] levelChunkSections = chunk.getSections();
@@ -171,6 +327,37 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl
@@ -171,6 +334,37 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl
}

public CompletableFuture<ChunkAccess> lightChunk(ChunkAccess chunk, boolean excludeBlocks) {
Expand Down Expand Up @@ -4811,7 +4820,7 @@ index 65d72701b13c25dd701533833055e77c2aff9db8..481272124b7589cff0aa05b6df5b7e6f
ChunkPos chunkPos = chunk.getPos();
chunk.setLightCorrect(false);
this.addTask(chunkPos.x, chunkPos.z, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> {
@@ -191,7 +378,7 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl
@@ -191,7 +385,7 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl
}

public void tryScheduleUpdate() {
Expand All @@ -4820,7 +4829,7 @@ index 65d72701b13c25dd701533833055e77c2aff9db8..481272124b7589cff0aa05b6df5b7e6f
this.taskMailbox.tell(() -> {
this.runUpdate();
this.scheduled.set(false);
@@ -213,7 +400,7 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl
@@ -213,7 +407,7 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl
}

objectListIterator.back(j);
Expand Down
Loading

0 comments on commit fb06829

Please sign in to comment.