minecraft-source/src/net/minecraft/server/level/ThreadedLevelLightEngine.java

189 lines
8.3 KiB
Java

package net.minecraft.server.level;
import org.apache.logging.log4j.LogManager;
import it.unimi.dsi.fastutil.objects.ObjectListIterator;
import net.minecraft.world.level.chunk.LevelChunkSection;
import java.util.concurrent.CompletableFuture;
import net.minecraft.world.level.chunk.ChunkAccess;
import java.util.function.IntSupplier;
import javax.annotation.Nullable;
import net.minecraft.world.level.chunk.DataLayer;
import net.minecraft.core.SectionPos;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.core.BlockPos;
import net.minecraft.Util;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.minecraft.world.level.chunk.LightChunkGetter;
import java.util.concurrent.atomic.AtomicBoolean;
import net.minecraft.util.thread.ProcessorHandle;
import com.mojang.datafixers.util.Pair;
import it.unimi.dsi.fastutil.objects.ObjectList;
import net.minecraft.util.thread.ProcessorMailbox;
import org.apache.logging.log4j.Logger;
import net.minecraft.world.level.lighting.LevelLightEngine;
public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCloseable {
private static final Logger LOGGER;
private final ProcessorMailbox<Runnable> taskMailbox;
private final ObjectList<Pair<TaskType, Runnable>> lightTasks;
private final ChunkMap chunkMap;
private final ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> sorterMailbox;
private volatile int taskPerBatch;
private final AtomicBoolean scheduled;
public ThreadedLevelLightEngine(final LightChunkGetter cak, final ChunkMap wp, final boolean boolean3, final ProcessorMailbox<Runnable> ais, final ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> air) {
super(cak, true, boolean3);
this.lightTasks = (ObjectList<Pair<TaskType, Runnable>>)new ObjectArrayList();
this.taskPerBatch = 5;
this.scheduled = new AtomicBoolean();
this.chunkMap = wp;
this.sorterMailbox = air;
this.taskMailbox = ais;
}
@Override
public void close() {
}
@Override
public int runUpdates(final int integer, final boolean boolean2, final boolean boolean3) {
throw Util.<UnsupportedOperationException>pauseInIde(new UnsupportedOperationException("Ran authomatically on a different thread!"));
}
@Override
public void onBlockEmissionIncrease(final BlockPos fk, final int integer) {
throw Util.<UnsupportedOperationException>pauseInIde(new UnsupportedOperationException("Ran authomatically on a different thread!"));
}
@Override
public void checkBlock(final BlockPos fk) {
final BlockPos fk2 = fk.immutable();
this.addTask(fk.getX() >> 4, fk.getZ() >> 4, TaskType.POST_UPDATE, Util.name(() -> super.checkBlock(fk2), () -> "checkBlock " + fk2));
}
protected void updateChunkStatus(final ChunkPos bje) {
int integer3;
int integer4;
this.addTask(bje.x, bje.z, () -> 0, TaskType.PRE_UPDATE, Util.name(() -> {
super.retainData(bje, false);
super.enableLightSources(bje, false);
for (integer3 = -1; integer3 < 17; ++integer3) {
super.queueSectionData(LightLayer.BLOCK, SectionPos.of(bje, integer3), null);
super.queueSectionData(LightLayer.SKY, SectionPos.of(bje, integer3), null);
}
for (integer4 = 0; integer4 < 16; ++integer4) {
super.updateSectionStatus(SectionPos.of(bje, integer4), true);
}
}, () -> "updateChunkStatus " + bje + " " + true));
}
@Override
public void updateSectionStatus(final SectionPos gd, final boolean boolean2) {
this.addTask(gd.x(), gd.z(), () -> 0, TaskType.PRE_UPDATE, Util.name(() -> super.updateSectionStatus(gd, boolean2), () -> "updateSectionStatus " + gd + " " + boolean2));
}
@Override
public void enableLightSources(final ChunkPos bje, final boolean boolean2) {
this.addTask(bje.x, bje.z, TaskType.PRE_UPDATE, Util.name(() -> super.enableLightSources(bje, boolean2), () -> "enableLight " + bje + " " + boolean2));
}
@Override
public void queueSectionData(final LightLayer bkc, final SectionPos gd, @Nullable final DataLayer cac) {
this.addTask(gd.x(), gd.z(), () -> 0, TaskType.PRE_UPDATE, Util.name(() -> super.queueSectionData(bkc, gd, cac), () -> "queueData " + gd));
}
private void addTask(final int integer1, final int integer2, final TaskType a, final Runnable runnable) {
this.addTask(integer1, integer2, this.chunkMap.getChunkQueueLevel(ChunkPos.asLong(integer1, integer2)), a, runnable);
}
private void addTask(final int integer1, final int integer2, final IntSupplier intSupplier, final TaskType a, final Runnable runnable) {
this.sorterMailbox.tell(ChunkTaskPriorityQueueSorter.message(() -> {
this.lightTasks.add(Pair.of((Object)a, (Object)runnable));
if (this.lightTasks.size() >= this.taskPerBatch) {
this.runUpdate();
}
}, ChunkPos.asLong(integer1, integer2), intSupplier));
}
@Override
public void retainData(final ChunkPos bje, final boolean boolean2) {
this.addTask(bje.x, bje.z, () -> 0, TaskType.PRE_UPDATE, Util.name(() -> super.retainData(bje, boolean2), () -> "retainData " + bje));
}
public CompletableFuture<ChunkAccess> lightChunk(final ChunkAccess bzv, final boolean boolean2) {
final ChunkPos bje4 = bzv.getPos();
bzv.setLightCorrect(false);
final LevelChunkSection[] arr5;
int integer6;
LevelChunkSection caj7;
final ChunkPos bje5;
this.addTask(bje4.x, bje4.z, TaskType.PRE_UPDATE, Util.name(() -> {
arr5 = bzv.getSections();
for (integer6 = 0; integer6 < 16; ++integer6) {
caj7 = arr5[integer6];
if (!LevelChunkSection.isEmpty(caj7)) {
super.updateSectionStatus(SectionPos.of(bje5, integer6), false);
}
}
super.enableLightSources(bje5, true);
if (!boolean2) {
bzv.getLights().forEach(fk -> super.onBlockEmissionIncrease(fk, bzv.getLightEmission(fk)));
}
this.chunkMap.releaseLightTicket(bje5);
return;
}, () -> "lightChunk " + bje4 + " " + boolean2));
final ChunkPos bje6;
final ChunkPos chunkPos;
return CompletableFuture.<ChunkAccess>supplyAsync(() -> {
bzv.setLightCorrect(true);
super.retainData(bje6, false);
return bzv;
}, runnable -> this.addTask(chunkPos.x, chunkPos.z, TaskType.POST_UPDATE, runnable));
}
public void tryScheduleUpdate() {
if ((!this.lightTasks.isEmpty() || super.hasLightWork()) && this.scheduled.compareAndSet(false, true)) {
this.taskMailbox.tell(() -> {
this.runUpdate();
this.scheduled.set(false);
});
}
}
private void runUpdate() {
int integer2;
ObjectListIterator<Pair<TaskType, Runnable>> objectListIterator3;
int integer3;
Pair<TaskType, Runnable> pair5;
for (integer2 = Math.min(this.lightTasks.size(), this.taskPerBatch), objectListIterator3 = (ObjectListIterator<Pair<TaskType, Runnable>>)this.lightTasks.iterator(), integer3 = 0; objectListIterator3.hasNext() && integer3 < integer2; ++integer3) {
pair5 = (Pair<TaskType, Runnable>)objectListIterator3.next();
if (pair5.getFirst() == TaskType.PRE_UPDATE) {
((Runnable)pair5.getSecond()).run();
}
}
objectListIterator3.back(integer3);
super.runUpdates(Integer.MAX_VALUE, true, true);
for (integer3 = 0; objectListIterator3.hasNext() && integer3 < integer2; ++integer3) {
pair5 = (Pair<TaskType, Runnable>)objectListIterator3.next();
if (pair5.getFirst() == TaskType.POST_UPDATE) {
((Runnable)pair5.getSecond()).run();
}
objectListIterator3.remove();
}
}
public void setTaskPerBatch(final int integer) {
this.taskPerBatch = integer;
}
static {
LOGGER = LogManager.getLogger();
}
enum TaskType {
PRE_UPDATE,
POST_UPDATE;
}
}