220 lines
9.1 KiB
Java
220 lines
9.1 KiB
Java
|
package net.minecraft.server.level;
|
||
|
|
||
|
import com.mojang.datafixers.util.Pair;
|
||
|
import com.mojang.logging.LogUtils;
|
||
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||
|
import it.unimi.dsi.fastutil.objects.ObjectList;
|
||
|
import it.unimi.dsi.fastutil.objects.ObjectListIterator;
|
||
|
import java.util.concurrent.CompletableFuture;
|
||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||
|
import java.util.function.IntSupplier;
|
||
|
import javax.annotation.Nullable;
|
||
|
import net.minecraft.Util;
|
||
|
import net.minecraft.core.BlockPos;
|
||
|
import net.minecraft.core.SectionPos;
|
||
|
import net.minecraft.util.thread.ConsecutiveExecutor;
|
||
|
import net.minecraft.world.level.ChunkPos;
|
||
|
import net.minecraft.world.level.LightLayer;
|
||
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||
|
import net.minecraft.world.level.chunk.DataLayer;
|
||
|
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||
|
import net.minecraft.world.level.chunk.LightChunkGetter;
|
||
|
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||
|
import org.slf4j.Logger;
|
||
|
|
||
|
public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCloseable {
|
||
|
public static final int DEFAULT_BATCH_SIZE = 1000;
|
||
|
private static final Logger LOGGER = LogUtils.getLogger();
|
||
|
private final ConsecutiveExecutor consecutiveExecutor;
|
||
|
private final ObjectList<Pair<ThreadedLevelLightEngine.TaskType, Runnable>> lightTasks = new ObjectArrayList<>();
|
||
|
private final ChunkMap chunkMap;
|
||
|
private final ChunkTaskDispatcher taskDispatcher;
|
||
|
private final int taskPerBatch = 1000;
|
||
|
private final AtomicBoolean scheduled = new AtomicBoolean();
|
||
|
|
||
|
public ThreadedLevelLightEngine(LightChunkGetter p_9305_, ChunkMap p_9306_, boolean p_9307_, ConsecutiveExecutor p_364647_, ChunkTaskDispatcher p_362920_) {
|
||
|
super(p_9305_, true, p_9307_);
|
||
|
this.chunkMap = p_9306_;
|
||
|
this.taskDispatcher = p_362920_;
|
||
|
this.consecutiveExecutor = p_364647_;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void close() {
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int runLightUpdates() {
|
||
|
throw (UnsupportedOperationException)Util.pauseInIde(new UnsupportedOperationException("Ran automatically on a different thread!"));
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void checkBlock(BlockPos p_9357_) {
|
||
|
BlockPos blockpos = p_9357_.immutable();
|
||
|
this.addTask(
|
||
|
SectionPos.blockToSectionCoord(p_9357_.getX()),
|
||
|
SectionPos.blockToSectionCoord(p_9357_.getZ()),
|
||
|
ThreadedLevelLightEngine.TaskType.PRE_UPDATE,
|
||
|
Util.name(() -> super.checkBlock(blockpos), () -> "checkBlock " + blockpos)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
protected void updateChunkStatus(ChunkPos p_9331_) {
|
||
|
this.addTask(p_9331_.x, p_9331_.z, () -> 0, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> {
|
||
|
super.retainData(p_9331_, false);
|
||
|
super.setLightEnabled(p_9331_, false);
|
||
|
|
||
|
for (int i = this.getMinLightSection(); i < this.getMaxLightSection(); i++) {
|
||
|
super.queueSectionData(LightLayer.BLOCK, SectionPos.of(p_9331_, i), null);
|
||
|
super.queueSectionData(LightLayer.SKY, SectionPos.of(p_9331_, i), null);
|
||
|
}
|
||
|
|
||
|
for (int j = this.levelHeightAccessor.getMinSectionY(); j <= this.levelHeightAccessor.getMaxSectionY(); j++) {
|
||
|
super.updateSectionStatus(SectionPos.of(p_9331_, j), true);
|
||
|
}
|
||
|
}, () -> "updateChunkStatus " + p_9331_ + " true"));
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void updateSectionStatus(SectionPos p_9364_, boolean p_9365_) {
|
||
|
this.addTask(
|
||
|
p_9364_.x(),
|
||
|
p_9364_.z(),
|
||
|
() -> 0,
|
||
|
ThreadedLevelLightEngine.TaskType.PRE_UPDATE,
|
||
|
Util.name(() -> super.updateSectionStatus(p_9364_, p_9365_), () -> "updateSectionStatus " + p_9364_ + " " + p_9365_)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void propagateLightSources(ChunkPos p_285029_) {
|
||
|
this.addTask(
|
||
|
p_285029_.x,
|
||
|
p_285029_.z,
|
||
|
ThreadedLevelLightEngine.TaskType.PRE_UPDATE,
|
||
|
Util.name(() -> super.propagateLightSources(p_285029_), () -> "propagateLight " + p_285029_)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setLightEnabled(ChunkPos p_9336_, boolean p_9337_) {
|
||
|
this.addTask(
|
||
|
p_9336_.x,
|
||
|
p_9336_.z,
|
||
|
ThreadedLevelLightEngine.TaskType.PRE_UPDATE,
|
||
|
Util.name(() -> super.setLightEnabled(p_9336_, p_9337_), () -> "enableLight " + p_9336_ + " " + p_9337_)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void queueSectionData(LightLayer p_285046_, SectionPos p_285496_, @Nullable DataLayer p_285495_) {
|
||
|
this.addTask(
|
||
|
p_285496_.x(),
|
||
|
p_285496_.z(),
|
||
|
() -> 0,
|
||
|
ThreadedLevelLightEngine.TaskType.PRE_UPDATE,
|
||
|
Util.name(() -> super.queueSectionData(p_285046_, p_285496_, p_285495_), () -> "queueData " + p_285496_)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
private void addTask(int p_9313_, int p_9314_, ThreadedLevelLightEngine.TaskType p_9315_, Runnable p_9316_) {
|
||
|
this.addTask(p_9313_, p_9314_, this.chunkMap.getChunkQueueLevel(ChunkPos.asLong(p_9313_, p_9314_)), p_9315_, p_9316_);
|
||
|
}
|
||
|
|
||
|
private void addTask(int p_9318_, int p_9319_, IntSupplier p_9320_, ThreadedLevelLightEngine.TaskType p_9321_, Runnable p_9322_) {
|
||
|
this.taskDispatcher.submit(() -> {
|
||
|
this.lightTasks.add(Pair.of(p_9321_, p_9322_));
|
||
|
if (this.lightTasks.size() >= 1000) {
|
||
|
this.runUpdate();
|
||
|
}
|
||
|
}, ChunkPos.asLong(p_9318_, p_9319_), p_9320_);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void retainData(ChunkPos p_9370_, boolean p_9371_) {
|
||
|
this.addTask(
|
||
|
p_9370_.x,
|
||
|
p_9370_.z,
|
||
|
() -> 0,
|
||
|
ThreadedLevelLightEngine.TaskType.PRE_UPDATE,
|
||
|
Util.name(() -> super.retainData(p_9370_, p_9371_), () -> "retainData " + p_9370_)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public CompletableFuture<ChunkAccess> initializeLight(ChunkAccess p_285128_, boolean p_285441_) {
|
||
|
ChunkPos chunkpos = p_285128_.getPos();
|
||
|
this.addTask(chunkpos.x, chunkpos.z, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> {
|
||
|
LevelChunkSection[] alevelchunksection = p_285128_.getSections();
|
||
|
|
||
|
for (int i = 0; i < p_285128_.getSectionsCount(); i++) {
|
||
|
LevelChunkSection levelchunksection = alevelchunksection[i];
|
||
|
if (!levelchunksection.hasOnlyAir()) {
|
||
|
int j = this.levelHeightAccessor.getSectionYFromSectionIndex(i);
|
||
|
super.updateSectionStatus(SectionPos.of(chunkpos, j), false);
|
||
|
}
|
||
|
}
|
||
|
}, () -> "initializeLight: " + chunkpos));
|
||
|
return CompletableFuture.supplyAsync(() -> {
|
||
|
super.setLightEnabled(chunkpos, p_285441_);
|
||
|
super.retainData(chunkpos, false);
|
||
|
return p_285128_;
|
||
|
}, p_215135_ -> this.addTask(chunkpos.x, chunkpos.z, ThreadedLevelLightEngine.TaskType.POST_UPDATE, p_215135_));
|
||
|
}
|
||
|
|
||
|
public CompletableFuture<ChunkAccess> lightChunk(ChunkAccess p_9354_, boolean p_9355_) {
|
||
|
ChunkPos chunkpos = p_9354_.getPos();
|
||
|
p_9354_.setLightCorrect(false);
|
||
|
this.addTask(chunkpos.x, chunkpos.z, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> {
|
||
|
if (!p_9355_) {
|
||
|
super.propagateLightSources(chunkpos);
|
||
|
}
|
||
|
}, () -> "lightChunk " + chunkpos + " " + p_9355_));
|
||
|
return CompletableFuture.supplyAsync(() -> {
|
||
|
p_9354_.setLightCorrect(true);
|
||
|
return p_9354_;
|
||
|
}, p_280982_ -> this.addTask(chunkpos.x, chunkpos.z, ThreadedLevelLightEngine.TaskType.POST_UPDATE, p_280982_));
|
||
|
}
|
||
|
|
||
|
public void tryScheduleUpdate() {
|
||
|
if ((!this.lightTasks.isEmpty() || super.hasLightWork()) && this.scheduled.compareAndSet(false, true)) {
|
||
|
this.consecutiveExecutor.schedule(() -> {
|
||
|
this.runUpdate();
|
||
|
this.scheduled.set(false);
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void runUpdate() {
|
||
|
int i = Math.min(this.lightTasks.size(), 1000);
|
||
|
ObjectListIterator<Pair<ThreadedLevelLightEngine.TaskType, Runnable>> objectlistiterator = this.lightTasks.iterator();
|
||
|
|
||
|
int j;
|
||
|
for (j = 0; objectlistiterator.hasNext() && j < i; j++) {
|
||
|
Pair<ThreadedLevelLightEngine.TaskType, Runnable> pair = objectlistiterator.next();
|
||
|
if (pair.getFirst() == ThreadedLevelLightEngine.TaskType.PRE_UPDATE) {
|
||
|
pair.getSecond().run();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
objectlistiterator.back(j);
|
||
|
super.runLightUpdates();
|
||
|
|
||
|
for (int k = 0; objectlistiterator.hasNext() && k < i; k++) {
|
||
|
Pair<ThreadedLevelLightEngine.TaskType, Runnable> pair1 = objectlistiterator.next();
|
||
|
if (pair1.getFirst() == ThreadedLevelLightEngine.TaskType.POST_UPDATE) {
|
||
|
pair1.getSecond().run();
|
||
|
}
|
||
|
|
||
|
objectlistiterator.remove();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public CompletableFuture<?> waitForPendingTasks(int p_297330_, int p_298866_) {
|
||
|
return CompletableFuture.runAsync(() -> {}, p_296584_ -> this.addTask(p_297330_, p_298866_, ThreadedLevelLightEngine.TaskType.POST_UPDATE, p_296584_));
|
||
|
}
|
||
|
|
||
|
static enum TaskType {
|
||
|
PRE_UPDATE,
|
||
|
POST_UPDATE;
|
||
|
}
|
||
|
}
|