539 lines
22 KiB
Java
539 lines
22 KiB
Java
package net.minecraft.server.level;
|
|
|
|
import net.minecraft.core.Registry;
|
|
import java.util.concurrent.CompletionStage;
|
|
import net.minecraft.world.level.lighting.LevelLightEngine;
|
|
import net.minecraft.world.entity.ai.village.poi.PoiManager;
|
|
import net.minecraft.network.protocol.Packet;
|
|
import net.minecraft.core.SectionPos;
|
|
import net.minecraft.world.level.LightLayer;
|
|
import com.google.common.annotations.VisibleForTesting;
|
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
|
import net.minecraft.world.level.storage.LevelData;
|
|
import net.minecraft.world.level.NaturalSpawner;
|
|
import net.minecraft.world.entity.MobCategory;
|
|
import net.minecraft.world.level.GameRules;
|
|
import net.minecraft.world.level.LevelType;
|
|
import java.util.function.BooleanSupplier;
|
|
import java.io.IOException;
|
|
import java.util.function.Function;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.entity.Entity;
|
|
import java.util.Optional;
|
|
import net.minecraft.world.level.BlockGetter;
|
|
import net.minecraft.util.profiling.ProfilerFiller;
|
|
import java.util.Arrays;
|
|
import net.minecraft.world.level.chunk.LevelChunk;
|
|
import net.minecraft.Util;
|
|
import com.mojang.datafixers.util.Either;
|
|
import net.minecraft.world.level.ChunkPos;
|
|
import java.util.concurrent.CompletableFuture;
|
|
import javax.annotation.Nullable;
|
|
import net.minecraft.world.level.chunk.LightChunkGetter;
|
|
import net.minecraft.util.thread.BlockableEventLoop;
|
|
import net.minecraft.world.level.Level;
|
|
import java.util.function.Supplier;
|
|
import net.minecraft.server.level.progress.ChunkProgressListener;
|
|
import java.util.concurrent.Executor;
|
|
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager;
|
|
import com.mojang.datafixers.DataFixer;
|
|
import java.io.File;
|
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
|
import net.minecraft.world.level.storage.DimensionDataStorage;
|
|
import net.minecraft.world.level.chunk.ChunkGenerator;
|
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
|
import java.util.List;
|
|
import net.minecraft.world.level.chunk.ChunkSource;
|
|
|
|
public class ServerChunkCache extends ChunkSource {
|
|
private static final int MAGIC_NUMBER;
|
|
private static final List<ChunkStatus> CHUNK_STATUSES;
|
|
private final DistanceManager distanceManager;
|
|
private final ChunkGenerator<?> generator;
|
|
private final ServerLevel level;
|
|
private final Thread mainThread;
|
|
private final ThreadedLevelLightEngine lightEngine;
|
|
private final MainThreadExecutor mainThreadProcessor;
|
|
public final ChunkMap chunkMap;
|
|
private final DimensionDataStorage dataStorage;
|
|
private long lastInhabitedUpdate;
|
|
private boolean spawnEnemies;
|
|
private boolean spawnFriendlies;
|
|
private final long[] lastChunkPos;
|
|
private final ChunkStatus[] lastChunkStatus;
|
|
private final ChunkAccess[] lastChunk;
|
|
|
|
public ServerChunkCache(final ServerLevel xd, final File file, final DataFixer dataFixer, final StructureManager cml, final Executor executor, final ChunkGenerator<?> bzx, final int integer, final ChunkProgressListener xm, final Supplier<DimensionDataStorage> supplier) {
|
|
this.spawnEnemies = true;
|
|
this.spawnFriendlies = true;
|
|
this.lastChunkPos = new long[4];
|
|
this.lastChunkStatus = new ChunkStatus[4];
|
|
this.lastChunk = new ChunkAccess[4];
|
|
this.level = xd;
|
|
this.mainThreadProcessor = new MainThreadExecutor((Level)xd);
|
|
this.generator = bzx;
|
|
this.mainThread = Thread.currentThread();
|
|
final File file2 = xd.getDimension().getType().getStorageFolder(file);
|
|
final File file3 = new File(file2, "data");
|
|
file3.mkdirs();
|
|
this.dataStorage = new DimensionDataStorage(file3, dataFixer);
|
|
this.chunkMap = new ChunkMap(xd, file, dataFixer, cml, executor, this.mainThreadProcessor, this, this.getGenerator(), xm, supplier, integer);
|
|
this.lightEngine = this.chunkMap.getLightEngine();
|
|
this.distanceManager = this.chunkMap.getDistanceManager();
|
|
this.clearCache();
|
|
}
|
|
|
|
@Override
|
|
public ThreadedLevelLightEngine getLightEngine() {
|
|
return this.lightEngine;
|
|
}
|
|
|
|
@Nullable
|
|
private ChunkHolder getVisibleChunkIfPresent(final long long1) {
|
|
return this.chunkMap.getVisibleChunkIfPresent(long1);
|
|
}
|
|
|
|
public int getTickingGenerated() {
|
|
return this.chunkMap.getTickingGenerated();
|
|
}
|
|
|
|
private void storeInCache(final long long1, final ChunkAccess bzv, final ChunkStatus cab) {
|
|
for (int integer6 = 3; integer6 > 0; --integer6) {
|
|
this.lastChunkPos[integer6] = this.lastChunkPos[integer6 - 1];
|
|
this.lastChunkStatus[integer6] = this.lastChunkStatus[integer6 - 1];
|
|
this.lastChunk[integer6] = this.lastChunk[integer6 - 1];
|
|
}
|
|
this.lastChunkPos[0] = long1;
|
|
this.lastChunkStatus[0] = cab;
|
|
this.lastChunk[0] = bzv;
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public ChunkAccess getChunk(final int integer1, final int integer2, final ChunkStatus cab, final boolean boolean4) {
|
|
if (Thread.currentThread() != this.mainThread) {
|
|
return CompletableFuture.<ChunkAccess>supplyAsync(() -> this.getChunk(integer1, integer2, cab, boolean4), this.mainThreadProcessor).join();
|
|
}
|
|
final long long6 = ChunkPos.asLong(integer1, integer2);
|
|
for (int integer3 = 0; integer3 < 4; ++integer3) {
|
|
if (long6 == this.lastChunkPos[integer3] && cab == this.lastChunkStatus[integer3]) {
|
|
final ChunkAccess bzv2 = this.lastChunk[integer3];
|
|
if (bzv2 != null || !boolean4) {
|
|
return bzv2;
|
|
}
|
|
}
|
|
}
|
|
final CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> completableFuture8 = this.getChunkFutureMainThread(integer1, integer2, cab, boolean4);
|
|
this.mainThreadProcessor.managedBlock(completableFuture8::isDone);
|
|
final IllegalStateException throwable;
|
|
final ChunkAccess bzv2 = (ChunkAccess)completableFuture8.join().map(bzv -> bzv, a -> {
|
|
if (boolean4) {
|
|
new IllegalStateException("Chunk not there when requested: " + a);
|
|
throw Util.<IllegalStateException>pauseInIde(throwable);
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
});
|
|
this.storeInCache(long6, bzv2, cab);
|
|
return bzv2;
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public LevelChunk getChunkNow(final int integer1, final int integer2) {
|
|
if (Thread.currentThread() != this.mainThread) {
|
|
return null;
|
|
}
|
|
final long long4 = ChunkPos.asLong(integer1, integer2);
|
|
for (int integer3 = 0; integer3 < 4; ++integer3) {
|
|
if (long4 == this.lastChunkPos[integer3] && this.lastChunkStatus[integer3] == ChunkStatus.FULL) {
|
|
final ChunkAccess bzv7 = this.lastChunk[integer3];
|
|
return (bzv7 instanceof LevelChunk) ? ((LevelChunk)bzv7) : null;
|
|
}
|
|
}
|
|
final ChunkHolder wo6 = this.getVisibleChunkIfPresent(long4);
|
|
if (wo6 == null) {
|
|
return null;
|
|
}
|
|
final Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure> either7 = wo6.getFutureIfPresent(ChunkStatus.FULL).getNow(null);
|
|
if (either7 == null) {
|
|
return null;
|
|
}
|
|
final ChunkAccess bzv8 = either7.left().orElse(null);
|
|
if (bzv8 != null) {
|
|
this.storeInCache(long4, bzv8, ChunkStatus.FULL);
|
|
if (bzv8 instanceof LevelChunk) {
|
|
return (LevelChunk)bzv8;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private void clearCache() {
|
|
Arrays.fill(this.lastChunkPos, ChunkPos.INVALID_CHUNK_POS);
|
|
Arrays.fill(this.lastChunkStatus, null);
|
|
Arrays.fill(this.lastChunk, null);
|
|
}
|
|
|
|
public CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> getChunkFuture(final int integer1, final int integer2, final ChunkStatus cab, final boolean boolean4) {
|
|
final boolean boolean5 = Thread.currentThread() == this.mainThread;
|
|
CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> completableFuture2;
|
|
if (boolean5) {
|
|
completableFuture2 = this.getChunkFutureMainThread(integer1, integer2, cab, boolean4);
|
|
this.mainThreadProcessor.managedBlock(completableFuture2::isDone);
|
|
}
|
|
else {
|
|
completableFuture2 = CompletableFuture.<CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>>supplyAsync(() -> this.getChunkFutureMainThread(integer1, integer2, cab, boolean4), this.mainThreadProcessor).<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>thenCompose(completableFuture -> completableFuture);
|
|
}
|
|
return completableFuture2;
|
|
}
|
|
|
|
private CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> getChunkFutureMainThread(final int integer1, final int integer2, final ChunkStatus cab, final boolean boolean4) {
|
|
final ChunkPos bje6 = new ChunkPos(integer1, integer2);
|
|
final long long7 = bje6.toLong();
|
|
final int integer3 = 33 + ChunkStatus.getDistance(cab);
|
|
ChunkHolder wo10 = this.getVisibleChunkIfPresent(long7);
|
|
if (boolean4) {
|
|
this.distanceManager.<ChunkPos>addTicket(TicketType.UNKNOWN, bje6, integer3, bje6);
|
|
if (this.chunkAbsent(wo10, integer3)) {
|
|
final ProfilerFiller aim11 = this.level.getProfiler();
|
|
aim11.push("chunkLoad");
|
|
this.runDistanceManagerUpdates();
|
|
wo10 = this.getVisibleChunkIfPresent(long7);
|
|
aim11.pop();
|
|
if (this.chunkAbsent(wo10, integer3)) {
|
|
throw Util.<IllegalStateException>pauseInIde(new IllegalStateException("No chunk holder after ticket has been added"));
|
|
}
|
|
}
|
|
}
|
|
if (this.chunkAbsent(wo10, integer3)) {
|
|
return ChunkHolder.UNLOADED_CHUNK_FUTURE;
|
|
}
|
|
return wo10.getOrScheduleFuture(cab, this.chunkMap);
|
|
}
|
|
|
|
private boolean chunkAbsent(@Nullable final ChunkHolder wo, final int integer) {
|
|
return wo == null || wo.getTicketLevel() > integer;
|
|
}
|
|
|
|
@Override
|
|
public boolean hasChunk(final int integer1, final int integer2) {
|
|
final ChunkHolder wo4 = this.getVisibleChunkIfPresent(new ChunkPos(integer1, integer2).toLong());
|
|
final int integer3 = 33 + ChunkStatus.getDistance(ChunkStatus.FULL);
|
|
return !this.chunkAbsent(wo4, integer3);
|
|
}
|
|
|
|
@Override
|
|
public BlockGetter getChunkForLighting(final int integer1, final int integer2) {
|
|
final long long4 = ChunkPos.asLong(integer1, integer2);
|
|
final ChunkHolder wo6 = this.getVisibleChunkIfPresent(long4);
|
|
if (wo6 == null) {
|
|
return null;
|
|
}
|
|
int integer3 = ServerChunkCache.CHUNK_STATUSES.size() - 1;
|
|
while (true) {
|
|
final ChunkStatus cab8 = ServerChunkCache.CHUNK_STATUSES.get(integer3);
|
|
final Optional<ChunkAccess> optional9 = (Optional<ChunkAccess>)wo6.getFutureIfPresentUnchecked(cab8).getNow(ChunkHolder.UNLOADED_CHUNK).left();
|
|
if (optional9.isPresent()) {
|
|
return optional9.get();
|
|
}
|
|
if (cab8 == ChunkStatus.LIGHT.getParent()) {
|
|
return null;
|
|
}
|
|
--integer3;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public Level getLevel() {
|
|
return this.level;
|
|
}
|
|
|
|
public boolean pollTask() {
|
|
return this.mainThreadProcessor.pollTask();
|
|
}
|
|
|
|
private boolean runDistanceManagerUpdates() {
|
|
final boolean boolean2 = this.distanceManager.runAllUpdates(this.chunkMap);
|
|
final boolean boolean3 = this.chunkMap.promoteChunkMap();
|
|
if (boolean2 || boolean3) {
|
|
this.clearCache();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean isEntityTickingChunk(final Entity akn) {
|
|
final long long3 = ChunkPos.asLong(Mth.floor(akn.getX()) >> 4, Mth.floor(akn.getZ()) >> 4);
|
|
return this.checkChunkFuture(long3, ChunkHolder::getEntityTickingChunkFuture);
|
|
}
|
|
|
|
@Override
|
|
public boolean isEntityTickingChunk(final ChunkPos bje) {
|
|
return this.checkChunkFuture(bje.toLong(), ChunkHolder::getEntityTickingChunkFuture);
|
|
}
|
|
|
|
@Override
|
|
public boolean isTickingChunk(final BlockPos fk) {
|
|
final long long3 = ChunkPos.asLong(fk.getX() >> 4, fk.getZ() >> 4);
|
|
return this.checkChunkFuture(long3, ChunkHolder::getTickingChunkFuture);
|
|
}
|
|
|
|
public boolean isInAccessibleChunk(final Entity akn) {
|
|
final long long3 = ChunkPos.asLong(Mth.floor(akn.getX()) >> 4, Mth.floor(akn.getZ()) >> 4);
|
|
return this.checkChunkFuture(long3, ChunkHolder::getFullChunkFuture);
|
|
}
|
|
|
|
private boolean checkChunkFuture(final long long1, final Function<ChunkHolder, CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>>> function) {
|
|
final ChunkHolder wo5 = this.getVisibleChunkIfPresent(long1);
|
|
if (wo5 == null) {
|
|
return false;
|
|
}
|
|
final Either<LevelChunk, ChunkHolder.ChunkLoadingFailure> either6 = function.apply(wo5).getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK);
|
|
return either6.left().isPresent();
|
|
}
|
|
|
|
public void save(final boolean boolean1) {
|
|
this.runDistanceManagerUpdates();
|
|
this.chunkMap.saveAllChunks(boolean1);
|
|
}
|
|
|
|
@Override
|
|
public void close() throws IOException {
|
|
this.save(true);
|
|
this.lightEngine.close();
|
|
this.chunkMap.close();
|
|
}
|
|
|
|
@Override
|
|
public void tick(final BooleanSupplier booleanSupplier) {
|
|
this.level.getProfiler().push("purge");
|
|
this.distanceManager.purgeStaleTickets();
|
|
this.runDistanceManagerUpdates();
|
|
this.level.getProfiler().popPush("chunks");
|
|
this.tickChunks();
|
|
this.level.getProfiler().popPush("unload");
|
|
this.chunkMap.tick(booleanSupplier);
|
|
this.level.getProfiler().pop();
|
|
this.clearCache();
|
|
}
|
|
|
|
private void tickChunks() {
|
|
final long long2 = this.level.getGameTime();
|
|
final long long3 = long2 - this.lastInhabitedUpdate;
|
|
this.lastInhabitedUpdate = long2;
|
|
final LevelData crj6 = this.level.getLevelData();
|
|
final boolean boolean7 = crj6.getGeneratorType() == LevelType.DEBUG_ALL_BLOCK_STATES;
|
|
final boolean boolean8 = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING);
|
|
if (!boolean7) {
|
|
this.level.getProfiler().push("pollingChunks");
|
|
final int integer9 = this.level.getGameRules().getInt(GameRules.RULE_RANDOMTICKING);
|
|
final BlockPos fk10 = this.level.getSharedSpawnPos();
|
|
final boolean boolean9 = crj6.getGameTime() % 400L == 0L;
|
|
this.level.getProfiler().push("naturalSpawnCount");
|
|
final int integer10 = this.distanceManager.getNaturalSpawnChunkCount();
|
|
final MobCategory[] arr13 = MobCategory.values();
|
|
final Object2IntMap<MobCategory> object2IntMap14 = this.level.getMobCategoryCounts();
|
|
this.level.getProfiler().pop();
|
|
final Optional<LevelChunk> optional12;
|
|
LevelChunk cai13;
|
|
ChunkPos bje14;
|
|
final long n;
|
|
final boolean b;
|
|
final MobCategory[] array;
|
|
int length;
|
|
int i = 0;
|
|
MobCategory aky18;
|
|
final boolean b2;
|
|
final int n2;
|
|
int integer11;
|
|
final Object2IntMap object2IntMap15;
|
|
final BlockPos fk11;
|
|
final int integer12;
|
|
this.chunkMap.getChunks().forEach(wo -> {
|
|
optional12 = (Optional<LevelChunk>)wo.getEntityTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK).left();
|
|
if (!optional12.isPresent()) {
|
|
return;
|
|
}
|
|
else {
|
|
cai13 = optional12.get();
|
|
this.level.getProfiler().push("broadcast");
|
|
wo.broadcastChanges(cai13);
|
|
this.level.getProfiler().pop();
|
|
bje14 = wo.getPos();
|
|
if (this.chunkMap.noPlayersCloseForSpawning(bje14)) {
|
|
return;
|
|
}
|
|
else {
|
|
cai13.setInhabitedTime(cai13.getInhabitedTime() + n);
|
|
if (b && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(cai13.getPos())) {
|
|
this.level.getProfiler().push("spawner");
|
|
for (length = array.length; i < length; ++i) {
|
|
aky18 = array[i];
|
|
if (aky18 != MobCategory.MISC) {
|
|
if (!aky18.isFriendly() || this.spawnFriendlies) {
|
|
if (aky18.isFriendly() || this.spawnEnemies) {
|
|
if (!aky18.isPersistent() || b2) {
|
|
integer11 = aky18.getMaxInstancesPerChunk() * n2 / ServerChunkCache.MAGIC_NUMBER;
|
|
if (object2IntMap15.getInt(aky18) <= integer11) {
|
|
NaturalSpawner.spawnCategoryForChunk(aky18, this.level, cai13, fk11);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
this.level.getProfiler().pop();
|
|
}
|
|
this.level.tickChunk(cai13, integer12);
|
|
return;
|
|
}
|
|
}
|
|
});
|
|
this.level.getProfiler().push("customSpawners");
|
|
if (boolean8) {
|
|
this.generator.tickCustomSpawners(this.level, this.spawnEnemies, this.spawnFriendlies);
|
|
}
|
|
this.level.getProfiler().pop();
|
|
this.level.getProfiler().pop();
|
|
}
|
|
this.chunkMap.tick();
|
|
}
|
|
|
|
@Override
|
|
public String gatherStats() {
|
|
return "ServerChunkCache: " + this.getLoadedChunksCount();
|
|
}
|
|
|
|
@VisibleForTesting
|
|
public int getPendingTasksCount() {
|
|
return this.mainThreadProcessor.getPendingTasksCount();
|
|
}
|
|
|
|
public ChunkGenerator<?> getGenerator() {
|
|
return this.generator;
|
|
}
|
|
|
|
public int getLoadedChunksCount() {
|
|
return this.chunkMap.size();
|
|
}
|
|
|
|
public void blockChanged(final BlockPos fk) {
|
|
final int integer3 = fk.getX() >> 4;
|
|
final int integer4 = fk.getZ() >> 4;
|
|
final ChunkHolder wo5 = this.getVisibleChunkIfPresent(ChunkPos.asLong(integer3, integer4));
|
|
if (wo5 != null) {
|
|
wo5.blockChanged(fk.getX() & 0xF, fk.getY(), fk.getZ() & 0xF);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onLightUpdate(final LightLayer bkc, final SectionPos gd) {
|
|
final ChunkHolder wo4;
|
|
this.mainThreadProcessor.execute(() -> {
|
|
wo4 = this.getVisibleChunkIfPresent(gd.chunk().toLong());
|
|
if (wo4 != null) {
|
|
wo4.sectionLightChanged(bkc, gd.y());
|
|
}
|
|
});
|
|
}
|
|
|
|
public <T> void addRegionTicket(final TicketType<T> xi, final ChunkPos bje, final int integer, final T object) {
|
|
this.distanceManager.<T>addRegionTicket(xi, bje, integer, object);
|
|
}
|
|
|
|
public <T> void removeRegionTicket(final TicketType<T> xi, final ChunkPos bje, final int integer, final T object) {
|
|
this.distanceManager.<T>removeRegionTicket(xi, bje, integer, object);
|
|
}
|
|
|
|
@Override
|
|
public void updateChunkForced(final ChunkPos bje, final boolean boolean2) {
|
|
this.distanceManager.updateChunkForced(bje, boolean2);
|
|
}
|
|
|
|
public void move(final ServerPlayer xe) {
|
|
this.chunkMap.move(xe);
|
|
}
|
|
|
|
public void removeEntity(final Entity akn) {
|
|
this.chunkMap.removeEntity(akn);
|
|
}
|
|
|
|
public void addEntity(final Entity akn) {
|
|
this.chunkMap.addEntity(akn);
|
|
}
|
|
|
|
public void broadcastAndSend(final Entity akn, final Packet<?> lt) {
|
|
this.chunkMap.broadcastAndSend(akn, lt);
|
|
}
|
|
|
|
public void broadcast(final Entity akn, final Packet<?> lt) {
|
|
this.chunkMap.broadcast(akn, lt);
|
|
}
|
|
|
|
public void setViewDistance(final int integer) {
|
|
this.chunkMap.setViewDistance(integer);
|
|
}
|
|
|
|
@Override
|
|
public void setSpawnSettings(final boolean boolean1, final boolean boolean2) {
|
|
this.spawnEnemies = boolean1;
|
|
this.spawnFriendlies = boolean2;
|
|
}
|
|
|
|
public String getChunkDebugData(final ChunkPos bje) {
|
|
return this.chunkMap.getChunkDebugData(bje);
|
|
}
|
|
|
|
public DimensionDataStorage getDataStorage() {
|
|
return this.dataStorage;
|
|
}
|
|
|
|
public PoiManager getPoiManager() {
|
|
return this.chunkMap.getPoiManager();
|
|
}
|
|
|
|
static {
|
|
MAGIC_NUMBER = (int)Math.pow(17.0, 2.0);
|
|
CHUNK_STATUSES = ChunkStatus.getStatusList();
|
|
}
|
|
|
|
final class MainThreadExecutor extends BlockableEventLoop<Runnable> {
|
|
private MainThreadExecutor(final Level bjt) {
|
|
super("Chunk source main thread executor for " + Registry.DIMENSION_TYPE.getKey(bjt.getDimension().getType()));
|
|
}
|
|
|
|
@Override
|
|
protected Runnable wrapRunnable(final Runnable runnable) {
|
|
return runnable;
|
|
}
|
|
|
|
@Override
|
|
protected boolean shouldRun(final Runnable runnable) {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
protected boolean scheduleExecutables() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
protected Thread getRunningThread() {
|
|
return ServerChunkCache.this.mainThread;
|
|
}
|
|
|
|
@Override
|
|
protected boolean pollTask() {
|
|
if (ServerChunkCache.this.runDistanceManagerUpdates()) {
|
|
return true;
|
|
}
|
|
ServerChunkCache.this.lightEngine.tryScheduleUpdate();
|
|
return super.pollTask();
|
|
}
|
|
}
|
|
}
|