2025-11-24 22:52:51 +03:00

203 lines
8.7 KiB
Java

/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* com.mojang.datafixers.util.Pair
* com.mojang.logging.LogUtils
* it.unimi.dsi.fastutil.objects.ObjectArrayList
* it.unimi.dsi.fastutil.objects.ObjectList
* it.unimi.dsi.fastutil.objects.ObjectListIterator
* org.jspecify.annotations.Nullable
* org.slf4j.Logger
*/
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 net.minecraft.SharedConstants;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ChunkTaskDispatcher;
import net.minecraft.util.Util;
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.jspecify.annotations.Nullable;
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<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 lightChunkGetter, ChunkMap chunkMap, boolean hasSkyLight, ConsecutiveExecutor consecutiveExecutor, ChunkTaskDispatcher taskDispatcher) {
super(lightChunkGetter, true, hasSkyLight);
this.chunkMap = chunkMap;
this.taskDispatcher = taskDispatcher;
this.consecutiveExecutor = consecutiveExecutor;
}
@Override
public void close() {
}
@Override
public int runLightUpdates() {
throw Util.pauseInIde(new UnsupportedOperationException("Ran automatically on a different thread!"));
}
@Override
public void checkBlock(BlockPos pos) {
BlockPos immutable = pos.immutable();
this.addTask(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ()), TaskType.PRE_UPDATE, Util.name(() -> super.checkBlock(immutable), () -> "checkBlock " + String.valueOf(immutable)));
}
protected void updateChunkStatus(ChunkPos pos) {
this.addTask(pos.x, pos.z, () -> 0, TaskType.PRE_UPDATE, Util.name(() -> {
int sectionY;
super.retainData(pos, false);
super.setLightEnabled(pos, false);
for (sectionY = this.getMinLightSection(); sectionY < this.getMaxLightSection(); ++sectionY) {
super.queueSectionData(LightLayer.BLOCK, SectionPos.of(pos, sectionY), null);
super.queueSectionData(LightLayer.SKY, SectionPos.of(pos, sectionY), null);
}
for (sectionY = this.levelHeightAccessor.getMinSectionY(); sectionY <= this.levelHeightAccessor.getMaxSectionY(); ++sectionY) {
super.updateSectionStatus(SectionPos.of(pos, sectionY), true);
}
}, () -> "updateChunkStatus " + String.valueOf(pos) + " true"));
}
@Override
public void updateSectionStatus(SectionPos pos, boolean sectionEmpty) {
this.addTask(pos.x(), pos.z(), () -> 0, TaskType.PRE_UPDATE, Util.name(() -> super.updateSectionStatus(pos, sectionEmpty), () -> "updateSectionStatus " + String.valueOf(pos) + " " + sectionEmpty));
}
@Override
public void propagateLightSources(ChunkPos pos) {
this.addTask(pos.x, pos.z, TaskType.PRE_UPDATE, Util.name(() -> super.propagateLightSources(pos), () -> "propagateLight " + String.valueOf(pos)));
}
@Override
public void setLightEnabled(ChunkPos pos, boolean enable) {
this.addTask(pos.x, pos.z, TaskType.PRE_UPDATE, Util.name(() -> super.setLightEnabled(pos, enable), () -> "enableLight " + String.valueOf(pos) + " " + enable));
}
@Override
public void queueSectionData(LightLayer layer, SectionPos pos, @Nullable DataLayer data) {
this.addTask(pos.x(), pos.z(), () -> 0, TaskType.PRE_UPDATE, Util.name(() -> super.queueSectionData(layer, pos, data), () -> "queueData " + String.valueOf(pos)));
}
private void addTask(int chunkX, int chunkZ, TaskType type, Runnable runnable) {
this.addTask(chunkX, chunkZ, this.chunkMap.getChunkQueueLevel(ChunkPos.asLong(chunkX, chunkZ)), type, runnable);
}
private void addTask(int chunkX, int chunkZ, IntSupplier level, TaskType type, Runnable runnable) {
this.taskDispatcher.submit(() -> {
this.lightTasks.add((Object)Pair.of((Object)((Object)type), (Object)runnable));
if (this.lightTasks.size() >= 1000) {
this.runUpdate();
}
}, ChunkPos.asLong(chunkX, chunkZ), level);
}
@Override
public void retainData(ChunkPos pos, boolean retain) {
this.addTask(pos.x, pos.z, () -> 0, TaskType.PRE_UPDATE, Util.name(() -> super.retainData(pos, retain), () -> "retainData " + String.valueOf(pos)));
}
public CompletableFuture<ChunkAccess> initializeLight(ChunkAccess chunk, boolean lighted) {
ChunkPos pos = chunk.getPos();
this.addTask(pos.x, pos.z, TaskType.PRE_UPDATE, Util.name(() -> {
LevelChunkSection[] sections = chunk.getSections();
for (int sectionIndex = 0; sectionIndex < chunk.getSectionsCount(); ++sectionIndex) {
LevelChunkSection section = sections[sectionIndex];
if (section.hasOnlyAir()) continue;
int sectionY = this.levelHeightAccessor.getSectionYFromSectionIndex(sectionIndex);
super.updateSectionStatus(SectionPos.of(pos, sectionY), false);
}
}, () -> "initializeLight: " + String.valueOf(pos)));
return CompletableFuture.supplyAsync(() -> {
super.setLightEnabled(pos, lighted);
super.retainData(pos, false);
return chunk;
}, r -> this.addTask(pos.x, pos.z, TaskType.POST_UPDATE, r));
}
public CompletableFuture<ChunkAccess> lightChunk(ChunkAccess centerChunk, boolean lighted) {
ChunkPos pos = centerChunk.getPos();
centerChunk.setLightCorrect(false);
this.addTask(pos.x, pos.z, TaskType.PRE_UPDATE, Util.name(() -> {
if (!lighted) {
super.propagateLightSources(pos);
}
if (SharedConstants.DEBUG_VERBOSE_SERVER_EVENTS) {
LOGGER.debug("LIT {}", (Object)pos);
}
}, () -> "lightChunk " + String.valueOf(pos) + " " + lighted));
return CompletableFuture.supplyAsync(() -> {
centerChunk.setLightCorrect(true);
return centerChunk;
}, r -> this.addTask(pos.x, pos.z, TaskType.POST_UPDATE, r));
}
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() {
Pair task;
int count;
int totalSize = Math.min(this.lightTasks.size(), 1000);
ObjectListIterator iterator = this.lightTasks.iterator();
for (count = 0; iterator.hasNext() && count < totalSize; ++count) {
task = (Pair)iterator.next();
if (task.getFirst() != TaskType.PRE_UPDATE) continue;
((Runnable)task.getSecond()).run();
}
iterator.back(count);
super.runLightUpdates();
for (count = 0; iterator.hasNext() && count < totalSize; ++count) {
task = (Pair)iterator.next();
if (task.getFirst() == TaskType.POST_UPDATE) {
((Runnable)task.getSecond()).run();
}
iterator.remove();
}
}
public CompletableFuture<?> waitForPendingTasks(int chunkX, int chunkZ) {
return CompletableFuture.runAsync(() -> {}, r -> this.addTask(chunkX, chunkZ, TaskType.POST_UPDATE, r));
}
private static enum TaskType {
PRE_UPDATE,
POST_UPDATE;
}
}