189 lines
8.3 KiB
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;
|
|
}
|
|
}
|