/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.mojang.logging.LogUtils * org.jspecify.annotations.Nullable * org.slf4j.Logger */ package net.minecraft.server.level; import com.mojang.logging.LogUtils; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.function.IntConsumer; import java.util.function.IntSupplier; import net.minecraft.SharedConstants; import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ChunkTaskPriorityQueue; import net.minecraft.util.Unit; import net.minecraft.util.thread.PriorityConsecutiveExecutor; import net.minecraft.util.thread.StrictQueue; import net.minecraft.util.thread.TaskScheduler; import net.minecraft.world.level.ChunkPos; import org.jspecify.annotations.Nullable; import org.slf4j.Logger; public class ChunkTaskDispatcher implements ChunkHolder.LevelChangeListener, AutoCloseable { public static final int DISPATCHER_PRIORITY_COUNT = 4; private static final Logger LOGGER = LogUtils.getLogger(); private final ChunkTaskPriorityQueue queue; private final TaskScheduler executor; private final PriorityConsecutiveExecutor dispatcher; protected boolean sleeping; public ChunkTaskDispatcher(TaskScheduler executor, Executor dispatcherExecutor) { this.queue = new ChunkTaskPriorityQueue(executor.name() + "_queue"); this.executor = executor; this.dispatcher = new PriorityConsecutiveExecutor(4, dispatcherExecutor, "dispatcher"); this.sleeping = true; } public boolean hasWork() { return this.dispatcher.hasWork() || this.queue.hasWork(); } @Override public void onLevelChange(ChunkPos pos, IntSupplier oldLevel, int newLevel, IntConsumer setQueueLevel) { this.dispatcher.schedule(new StrictQueue.RunnableWithPriority(0, () -> { int oldTicketLevel = oldLevel.getAsInt(); if (SharedConstants.DEBUG_VERBOSE_SERVER_EVENTS) { LOGGER.debug("RES {} {} -> {}", new Object[]{pos, oldTicketLevel, newLevel}); } this.queue.resortChunkTasks(oldTicketLevel, pos, newLevel); setQueueLevel.accept(newLevel); })); } public void release(long pos, Runnable whenReleased, boolean clearQueue) { this.dispatcher.schedule(new StrictQueue.RunnableWithPriority(1, () -> { this.queue.release(pos, clearQueue); this.onRelease(pos); if (this.sleeping) { this.sleeping = false; this.pollTask(); } whenReleased.run(); })); } public void submit(Runnable task, long pos, IntSupplier level) { this.dispatcher.schedule(new StrictQueue.RunnableWithPriority(2, () -> { int ticketLevel = level.getAsInt(); if (SharedConstants.DEBUG_VERBOSE_SERVER_EVENTS) { LOGGER.debug("SUB {} {} {} {}", new Object[]{new ChunkPos(pos), ticketLevel, this.executor, this.queue}); } this.queue.submit(task, pos, ticketLevel); if (this.sleeping) { this.sleeping = false; this.pollTask(); } })); } protected void pollTask() { this.dispatcher.schedule(new StrictQueue.RunnableWithPriority(3, () -> { ChunkTaskPriorityQueue.TasksForChunk tasksForChunk = this.popTasks(); if (tasksForChunk == null) { this.sleeping = true; } else { this.scheduleForExecution(tasksForChunk); } })); } protected void scheduleForExecution(ChunkTaskPriorityQueue.TasksForChunk tasksForChunk) { CompletableFuture.allOf((CompletableFuture[])tasksForChunk.tasks().stream().map(message -> this.executor.scheduleWithResult(future -> { message.run(); future.complete(Unit.INSTANCE); })).toArray(CompletableFuture[]::new)).thenAccept(r -> this.pollTask()); } protected void onRelease(long key) { } protected @Nullable ChunkTaskPriorityQueue.TasksForChunk popTasks() { return this.queue.pop(); } @Override public void close() { this.executor.close(); } }