replace server tick/world gen tick with a timer

This commit is contained in:
James Seibel
2025-11-15 09:47:15 -06:00
parent a6ddc561a0
commit 3257ae8480
15 changed files with 224 additions and 223 deletions
@@ -338,12 +338,6 @@ public class ClientApi
if (clientWorld != null)
{
clientWorld.clientTick();
// Ignore local world gen, as it's managed by server ticking
if (!(clientWorld instanceof DhClientServerWorld))
{
SharedApi.worldGenTick(clientWorld::worldGenTick);
}
}
}
catch (Exception e)
@@ -53,30 +53,6 @@ public class ServerApi
//=============//
// tick events //
//=============//
public void serverTickEvent()
{
try
{
IDhServerWorld serverWorld = SharedApi.tryGetDhServerWorld();
if (serverWorld != null)
{
serverWorld.serverTick();
SharedApi.worldGenTick(serverWorld::worldGenTick);
}
}
catch (Exception e)
{
// try catch is necessary to prevent crashing the internal server when an exception is thrown
LOGGER.error("ServerTickEvent error: " + e.getMessage(), e);
}
}
//===============//
// server events //
//===============//
@@ -141,16 +141,6 @@ public class SharedApi
}
}
public static void worldGenTick(Runnable worldGenRunnable)
{
lastWorldGenTickDelta--;
if (lastWorldGenTickDelta <= 0)
{
worldGenRunnable.run();
lastWorldGenTickDelta = 20;
}
}
@Nullable
public static AbstractDhWorld getAbstractDhWorld() { return currentWorld; }
@@ -24,7 +24,7 @@ import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSour
import com.seibel.distanthorizons.core.file.structure.ISaveStructure;
import com.seibel.distanthorizons.core.generation.RemoteWorldRetrievalQueue;
import com.seibel.distanthorizons.core.level.IDhLevel;
import com.seibel.distanthorizons.core.level.WorldGenModule;
import com.seibel.distanthorizons.core.level.LodRequestModule;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.multiplayer.client.SyncOnLoadRequestQueue;
import com.seibel.distanthorizons.core.logging.DhLogger;
@@ -37,7 +37,7 @@ import java.util.concurrent.TimeUnit;
/**
* Only handles {@link SyncOnLoadRequestQueue} requests (IE updating existing LODs based on a timestamp).
* Missing data is handled by {@link WorldGenModule} and {@link RemoteWorldRetrievalQueue}.
* Missing data is handled by {@link LodRequestModule} and {@link RemoteWorldRetrievalQueue}.
*/
public class RemoteFullDataSourceProvider extends GeneratedFullDataSourceProvider
{
@@ -48,7 +48,8 @@ public abstract class AbstractDhServerLevel extends AbstractDhLevel implements I
*/
protected final ConcurrentLinkedQueue<IServerPlayerWrapper> worldGenPlayerCenteringQueue = new ConcurrentLinkedQueue<>();
private final FullDataSourceRequestHandler requestHandler = new FullDataSourceRequestHandler(this);
private final FullDataSourceRequestHandler requestHandler;
//=============//
@@ -81,6 +82,7 @@ public abstract class AbstractDhServerLevel extends AbstractDhLevel implements I
LOGGER.info("Started "+this.getClass().getSimpleName()+" for ["+serverLevelWrapper+"] at ["+saveStructure+"].");
this.serverPlayerStateManager = serverPlayerStateManager;
this.requestHandler = new FullDataSourceRequestHandler(this);
}
@@ -89,12 +91,6 @@ public abstract class AbstractDhServerLevel extends AbstractDhLevel implements I
// ticks //
//=======//
@Override
public void serverTick()
{
this.requestHandler.tick();
}
@Override
public boolean shouldDoWorldGen()
{ return Config.Common.WorldGenerator.enableDistantGeneration.get() && !this.worldGenPlayerCenteringQueue.isEmpty(); }
@@ -118,9 +114,6 @@ public abstract class AbstractDhServerLevel extends AbstractDhLevel implements I
return new DhBlockPos2D((int) position.x, (int) position.z);
}
@Override
public void worldGenTick() { this.serverside.worldGenModule.worldGenTick(); }
//==================//
@@ -297,7 +290,7 @@ public abstract class AbstractDhServerLevel extends AbstractDhLevel implements I
public void addDebugMenuStringsToList(List<String> messageList)
{
this.serverside.fullDataFileHandler.addDebugMenuStringsToList(messageList);
this.serverside.worldGenModule.addDebugMenuStringsToList(messageList);
this.serverside.lodRequestModule.addDebugMenuStringsToList(messageList);
}
@@ -330,7 +323,10 @@ public abstract class AbstractDhServerLevel extends AbstractDhLevel implements I
{
super.close();
this.serverside.close();
this.requestHandler.close();
LOGGER.info("Closed DHLevel for [" + this.getLevelWrapper() + "].");
}
}
@@ -83,7 +83,7 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
.asMap()
);
public final WorldGenModule worldGenModule;
public final LodRequestModule lodRequestModule;
@Nullable
private final SyncOnLoadRequestQueue syncOnLoadRequestQueue;
@@ -131,7 +131,7 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
}
this.remoteDataSourceProvider = new RemoteFullDataSourceProvider(this, saveStructure, fullDataSaveDirOverride, this.syncOnLoadRequestQueue);
this.worldGenModule = new WorldGenModule(this, this.remoteDataSourceProvider, () -> new WorldGenState(this, networkState));
this.lodRequestModule = new LodRequestModule(this,this, this.remoteDataSourceProvider, () -> new LodRequestState(this, networkState));
this.clientside = new ClientLevelModule(this);
@@ -239,11 +239,6 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
@Nullable
public DhBlockPos2D getTargetPosForGeneration() { return new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()); }
@Override
public void worldGenTick() { this.worldGenModule.worldGenTick(); }
public void startRenderer() { this.clientside.startRenderer(); }
//===========//
@@ -325,7 +320,7 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
// world gen
this.worldGenModule.addDebugMenuStringsToList(messageList);
this.lodRequestModule.addDebugMenuStringsToList(messageList);
if (this.syncOnLoadRequestQueue != null)
{
assert this.networkState != null;
@@ -348,9 +343,9 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
@Override
public void close()
{
if (this.worldGenModule != null)
if (this.lodRequestModule != null)
{
this.worldGenModule.close();
this.lodRequestModule.close();
}
if (this.networkEventSource != null)
@@ -371,11 +366,11 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
// helper classes //
//================//
private static class WorldGenState extends WorldGenModule.AbstractWorldGenState
private static class LodRequestState extends LodRequestModule.AbstractLodRequestState
{
WorldGenState(DhClientLevel level, ClientNetworkState networkState)
LodRequestState(DhClientLevel level, ClientNetworkState networkState)
{
this.worldGenerationQueue = new RemoteWorldRetrievalQueue(networkState, level);
this.retrievalQueue = new RemoteWorldRetrievalQueue(networkState, level);
}
}
@@ -56,9 +56,6 @@ import java.util.concurrent.CompletableFuture;
*/
public interface IDhLevel extends AutoCloseable, GeneratedFullDataSourceProvider.IOnWorldGenCompleteListener
{
@Deprecated
void worldGenTick();
/**
* May return either a client or server level wrapper. <br>
* Should not return null
@@ -23,8 +23,6 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapp
public interface IDhServerLevel extends IDhLevel
{
void serverTick();
IServerLevelWrapper getServerLevelWrapper();
}
@@ -47,16 +47,17 @@ import java.util.function.Supplier;
* Handles both single-player/server-side world gen and client side LOD requests.
* TODO rename
*/
public class WorldGenModule implements Closeable
public class LodRequestModule implements Closeable
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private final GeneratedFullDataSourceProvider.IOnWorldGenCompleteListener onWorldGenCompleteListener;
private final ThreadPoolExecutor tickerThread;
private final GeneratedFullDataSourceProvider dataSourceProvider;
private final Supplier<? extends AbstractWorldGenState> worldGenStateSupplier;
private final Supplier<? extends AbstractLodRequestState> worldGenStateSupplier;
private final AtomicReference<AbstractWorldGenState> worldGenStateRef = new AtomicReference<>();
private final AtomicReference<AbstractLodRequestState> lodRequestStateRef = new AtomicReference<>();
@@ -64,59 +65,41 @@ public class WorldGenModule implements Closeable
// constructor //
//=============//
public WorldGenModule(
public LodRequestModule(
IDhLevel level,
GeneratedFullDataSourceProvider.IOnWorldGenCompleteListener onWorldGenCompleteListener,
GeneratedFullDataSourceProvider dataSourceProvider,
Supplier<? extends AbstractWorldGenState> worldGenStateSupplier
Supplier<? extends AbstractLodRequestState> worldGenStateSupplier
)
{
this.onWorldGenCompleteListener = onWorldGenCompleteListener;
this.dataSourceProvider = dataSourceProvider;
this.worldGenStateSupplier = worldGenStateSupplier;
}
//===================//
// world gen control //
//===================//
public void startWorldGen(GeneratedFullDataSourceProvider dataFileHandler, AbstractWorldGenState newWgs)
{
// create the new world generator
if (!this.worldGenStateRef.compareAndSet(null, newWgs))
{
LOGGER.warn("Failed to start world gen due to concurrency");
newWgs.closeAsync(false);
}
dataFileHandler.addWorldGenCompleteListener(this.onWorldGenCompleteListener);
dataFileHandler.setWorldGenerationQueue(newWgs.worldGenerationQueue);
}
public void stopWorldGen(GeneratedFullDataSourceProvider dataFileHandler)
{
AbstractWorldGenState worldGenState = this.worldGenStateRef.get();
if (worldGenState == null)
{
LOGGER.warn("Attempted to stop world gen when it was not running");
return;
}
// shut down the world generator
while (!this.worldGenStateRef.compareAndSet(worldGenState, null))
String levelId = level.getLevelWrapper().getDhIdentifier();
this.tickerThread = ThreadUtil.makeSingleDaemonThreadPool("Request Module Ticker ["+levelId+"]");
this.tickerThread.execute(this::tickLoop);
}
//=========//
// ticking //
//=========//
private void tickLoop()
{
try
{
worldGenState = this.worldGenStateRef.get();
if (worldGenState == null)
while (!Thread.interrupted())
{
return;
Thread.sleep(20);
this.tick();
}
}
dataFileHandler.clearRetrievalQueue();
worldGenState.closeAsync(true).join(); //TODO: Make it async.
dataFileHandler.removeWorldGenCompleteListener(this.onWorldGenCompleteListener);
catch (InterruptedException ignore) { }
}
public void worldGenTick()
private void tick()
{
boolean shouldDoWorldGen = this.onWorldGenCompleteListener.shouldDoWorldGen();
// if the world is read only don't generate anything
@@ -136,13 +119,13 @@ public class WorldGenModule implements Closeable
if (this.isWorldGenRunning())
{
AbstractWorldGenState worldGenState = this.worldGenStateRef.get();
if (worldGenState != null)
AbstractLodRequestState lodRequestState = this.lodRequestStateRef.get();
if (lodRequestState != null)
{
DhBlockPos2D targetPosForGeneration = this.onWorldGenCompleteListener.getTargetPosForGeneration();
if (targetPosForGeneration != null)
{
worldGenState.startGenerationQueueAndSetTargetPos(targetPosForGeneration);
lodRequestState.startRequestQueueAndSetTargetPos(targetPosForGeneration);
}
}
}
@@ -150,6 +133,48 @@ public class WorldGenModule implements Closeable
//===================//
// world gen control //
//===================//
public void startWorldGen(GeneratedFullDataSourceProvider dataFileHandler, AbstractLodRequestState newWgs)
{
// create the new world generator
if (!this.lodRequestStateRef.compareAndSet(null, newWgs))
{
LOGGER.warn("Failed to start world gen due to concurrency");
newWgs.closeAsync(false);
}
dataFileHandler.addWorldGenCompleteListener(this.onWorldGenCompleteListener);
dataFileHandler.setWorldGenerationQueue(newWgs.retrievalQueue);
}
public void stopWorldGen(GeneratedFullDataSourceProvider dataFileHandler)
{
AbstractLodRequestState worldGenState = this.lodRequestStateRef.get();
if (worldGenState == null)
{
LOGGER.warn("Attempted to stop world gen when it was not running");
return;
}
// shut down the world generator
while (!this.lodRequestStateRef.compareAndSet(worldGenState, null))
{
worldGenState = this.lodRequestStateRef.get();
if (worldGenState == null)
{
return;
}
}
dataFileHandler.clearRetrievalQueue();
worldGenState.closeAsync(true).join(); //TODO: Make it async.
dataFileHandler.removeWorldGenCompleteListener(this.onWorldGenCompleteListener);
}
//=======================//
// base method overrides //
//=======================//
@@ -157,13 +182,15 @@ public class WorldGenModule implements Closeable
@Override
public void close()
{
this.tickerThread.shutdownNow();
// shutdown the world-gen
AbstractWorldGenState worldGenState = this.worldGenStateRef.get();
AbstractLodRequestState worldGenState = this.lodRequestStateRef.get();
if (worldGenState != null)
{
while (!this.worldGenStateRef.compareAndSet(worldGenState, null))
while (!this.lodRequestStateRef.compareAndSet(worldGenState, null))
{
worldGenState = this.worldGenStateRef.get();
worldGenState = this.lodRequestStateRef.get();
if (worldGenState == null)
{
break;
@@ -183,12 +210,12 @@ public class WorldGenModule implements Closeable
// getters //
//=========//
public boolean isWorldGenRunning() { return this.worldGenStateRef.get() != null; }
public boolean isWorldGenRunning() { return this.lodRequestStateRef.get() != null; }
/** mutates a list so it can be added to an existing {@link IDhLevel}'s debug list */
public void addDebugMenuStringsToList(List<String> messageList)
{
AbstractWorldGenState worldGenState = this.worldGenStateRef.get();
AbstractLodRequestState worldGenState = this.lodRequestStateRef.get();
if (worldGenState == null)
{
return;
@@ -196,9 +223,9 @@ public class WorldGenModule implements Closeable
// estimated tasks
String waitingCountStr = F3Screen.NUMBER_FORMAT.format(worldGenState.worldGenerationQueue.getWaitingTaskCount());
String inProgressCountStr = F3Screen.NUMBER_FORMAT.format(worldGenState.worldGenerationQueue.getInProgressTaskCount());
String totalCountEstimateStr = F3Screen.NUMBER_FORMAT.format(worldGenState.worldGenerationQueue.getRetrievalEstimatedRemainingChunkCount());
String waitingCountStr = F3Screen.NUMBER_FORMAT.format(worldGenState.retrievalQueue.getWaitingTaskCount());
String inProgressCountStr = F3Screen.NUMBER_FORMAT.format(worldGenState.retrievalQueue.getInProgressTaskCount());
String totalCountEstimateStr = F3Screen.NUMBER_FORMAT.format(worldGenState.retrievalQueue.getRetrievalEstimatedRemainingChunkCount());
String message = "World Gen/Import Tasks: "+waitingCountStr+"/"+totalCountEstimateStr+" (in progress "+inProgressCountStr+")";
// estimated chunks/sec
@@ -210,7 +237,7 @@ public class WorldGenModule implements Closeable
messageList.add(message);
worldGenState.worldGenerationQueue.addDebugMenuStringsToList(messageList);
worldGenState.retrievalQueue.addDebugMenuStringsToList(messageList);
}
@@ -220,40 +247,22 @@ public class WorldGenModule implements Closeable
//================//
/** Handles the {@link IFullDataSourceRetrievalQueue} and any other necessary world gen information. */
public static abstract class AbstractWorldGenState
public static abstract class AbstractLodRequestState
{
/** static so we only send the disable message once per session */
private static long firstProgressMessageSentMs = 0;
public IFullDataSourceRetrievalQueue worldGenerationQueue;
public IFullDataSourceRetrievalQueue retrievalQueue;
private static final ThreadPoolExecutor PROGRESS_UPDATER_THREAD = ThreadUtil.makeSingleDaemonThreadPool("World Gen Progress Updater");
private boolean progressUpdateThreadRunning = false;
CompletableFuture<Void> closeAsync(boolean doInterrupt)
{
// this should stop the updater thread
this.progressUpdateThreadRunning = false;
return this.worldGenerationQueue.startClosingAsync(true, doInterrupt)
.exceptionally(e ->
{
LOGGER.error("Error during first stage of generation queue shutdown, Error: ["+e.getMessage()+"].", e);
return null;
}
).thenRun(this.worldGenerationQueue::close)
.exceptionally(e ->
{
LOGGER.error("Error during second stage of generation queue shutdown, Error: ["+e.getMessage()+"].", e);
return null;
});
}
/** @param targetPosForGeneration the position that world generation should be centered around */
public void startGenerationQueueAndSetTargetPos(DhBlockPos2D targetPosForGeneration)
/** @param targetPosForRequest the position that world generation should be centered around */
public void startRequestQueueAndSetTargetPos(DhBlockPos2D targetPosForRequest)
{
this.worldGenerationQueue.startAndSetTargetPos(targetPosForGeneration);
this.retrievalQueue.startAndSetTargetPos(targetPosForRequest);
this.startProgressUpdateThread();
}
private void startProgressUpdateThread()
@@ -286,8 +295,8 @@ public class WorldGenModule implements Closeable
private void sendRetrievalProgress()
{
// format the remaining chunks
int remainingChunkCount = this.worldGenerationQueue.getRetrievalEstimatedRemainingChunkCount();
remainingChunkCount += this.worldGenerationQueue.getQueuedChunkCount();
int remainingChunkCount = this.retrievalQueue.getRetrievalEstimatedRemainingChunkCount();
remainingChunkCount += this.retrievalQueue.getQueuedChunkCount();
String remainingChunkCountStr = F3Screen.NUMBER_FORMAT.format(remainingChunkCount);
String message = "DH is generating chunks. " + remainingChunkCountStr + " left.";
@@ -350,7 +359,7 @@ public class WorldGenModule implements Closeable
/** @return -1 if this method isn't supported or available */
public double getEstimatedChunksPerSecond()
{
RollingAverage avg = this.worldGenerationQueue.getRollingAverageChunkGenTimeInMs();
RollingAverage avg = this.retrievalQueue.getRollingAverageChunkGenTimeInMs();
if (avg == null)
{
return -1;
@@ -373,6 +382,27 @@ public class WorldGenModule implements Closeable
return chunksPerSecond;
}
CompletableFuture<Void> closeAsync(boolean doInterrupt)
{
// this should stop the updater thread
this.progressUpdateThreadRunning = false;
return this.retrievalQueue.startClosingAsync(true, doInterrupt)
.exceptionally(e ->
{
LOGGER.error("Error during first stage of generation queue shutdown, Error: ["+e.getMessage()+"].", e);
return null;
}
).thenRun(this.retrievalQueue::close)
.exceptionally(e ->
{
LOGGER.error("Error during second stage of generation queue shutdown, Error: ["+e.getMessage()+"].", e);
return null;
});
}
}
@@ -36,7 +36,7 @@ public class ServerLevelModule implements AutoCloseable
public final ISaveStructure saveStructure;
public final GeneratedFullDataSourceProvider fullDataFileHandler;
public final WorldGenModule worldGenModule;
public final LodRequestModule lodRequestModule;
@@ -49,7 +49,7 @@ public class ServerLevelModule implements AutoCloseable
this.parentServerLevel = parentServerLevel;
this.saveStructure = saveStructure;
this.fullDataFileHandler = new GeneratedFullDataSourceProvider(parentServerLevel, saveStructure);
this.worldGenModule = new WorldGenModule(this.parentServerLevel, this.fullDataFileHandler, () -> new ServerLevelModule.WorldGenState(this.parentServerLevel));
this.lodRequestModule = new LodRequestModule(this.parentServerLevel, this.parentServerLevel, this.fullDataFileHandler, () -> new LodRequestState(this.parentServerLevel));
}
@@ -62,7 +62,7 @@ public class ServerLevelModule implements AutoCloseable
public void close()
{
// shutdown the world-gen
this.worldGenModule.close();
this.lodRequestModule.close();
this.fullDataFileHandler.close();
}
@@ -72,9 +72,9 @@ public class ServerLevelModule implements AutoCloseable
// helper classes //
//================//
public static class WorldGenState extends WorldGenModule.AbstractWorldGenState
public static class LodRequestState extends LodRequestModule.AbstractLodRequestState
{
WorldGenState(IDhServerLevel level)
LodRequestState(IDhServerLevel level)
{
IDhApiWorldGenerator worldGenerator = WorldGeneratorInjector.INSTANCE.get(level.getLevelWrapper());
if (worldGenerator == null)
@@ -85,7 +85,7 @@ public class ServerLevelModule implements AutoCloseable
// since core world generator's should have the lowest override priority
WorldGeneratorInjector.INSTANCE.bind(level.getLevelWrapper(), worldGenerator);
}
this.worldGenerationQueue = new WorldGenerationQueue(worldGenerator, level);
this.retrievalQueue = new WorldGenerationQueue(worldGenerator, level);
}
}
@@ -14,6 +14,7 @@ import com.seibel.distanthorizons.core.network.messages.fullData.FullDataSourceR
import com.seibel.distanthorizons.core.network.messages.fullData.FullDataSourceResponseMessage;
import com.seibel.distanthorizons.core.pos.DhSectionPos;
import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO;
import com.seibel.distanthorizons.core.util.ThreadUtil;
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
import java.util.List;
@@ -21,7 +22,7 @@ import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
public class FullDataSourceRequestHandler
public class FullDataSourceRequestHandler implements AutoCloseable
{
private static final DhLogger LOGGER = new DhLoggerBuilder()
.fileLevelConfig(Config.Common.Logging.logNetworkEventToFile)
@@ -29,6 +30,8 @@ public class FullDataSourceRequestHandler
private final AbstractDhServerLevel serverLevel;
private final ThreadPoolExecutor tickerThread;
private String getLevelIdentifier() { return this.serverLevel.getLevelWrapper().getDhIdentifier(); }
private GeneratedFullDataSourceProvider fullDataSourceProvider() { return this.serverLevel.serverside.fullDataFileHandler; }
private List<BeaconBeamDTO> getAllBeamsForPos(long pos) { return this.serverLevel.beaconBeamRepo.getAllBeamsForPos(pos); }
@@ -37,12 +40,22 @@ public class FullDataSourceRequestHandler
private final ConcurrentMap<Long, DataSourceRequestGroup> requestGroupsByFutureId = new ConcurrentHashMap<>();
//=============//
// constructor //
//=============//
public FullDataSourceRequestHandler(AbstractDhServerLevel serverLevel)
{
this.serverLevel = serverLevel;
String levelId = this.serverLevel.getServerLevelWrapper().getDhIdentifier();
this.tickerThread = ThreadUtil.makeSingleDaemonThreadPool("DataSource Request Ticker ["+levelId+"]");
this.tickerThread.execute(this::tickLoop);
}
//==================//
// network handling //
//==================//
@@ -214,52 +227,6 @@ public class FullDataSourceRequestHandler
}
}
public void tick()
{
// Send finished data source requests
for (Map.Entry<Long, DataSourceRequestGroup> entry : this.requestGroupsByPos.entrySet())
{
DataSourceRequestGroup requestGroup = entry.getValue();
if (requestGroup.fullDataSource == null)
{
continue;
}
LOGGER.debug("[" + this.getLevelIdentifier() + "] Fulfilled request group [" + DhSectionPos.toString(entry.getKey()) + "]");
// Make this group unavailable for adding into
this.requestGroupsByPos.remove(entry.getKey());
if (!requestGroup.tryClose())
{
continue;
}
AbstractExecutorService executor = ThreadPoolUtil.getNetworkCompressionExecutor();
if (executor == null)
{
LOGGER.warn("Unable to send FullDataSourceResponseMessage - getNetworkCompressionExecutor() is null");
continue;
}
CompletableFuture.runAsync(() ->
{
FullDataPayload payload = new FullDataPayload(requestGroup.fullDataSource, this.getAllBeamsForPos(entry.getKey()));
requestGroup.fullDataSource.close();
for (DataSourceRequestGroup.RequestData requestData : requestGroup.requestMessages.values())
{
this.requestGroupsByFutureId.remove(requestData.futureId());
requestData.serverPlayerState.fullDataPayloadSender.sendInChunks(payload, () -> {
requestData.message.sendResponse(new FullDataSourceResponseMessage(payload));
requestData.rateLimiterSet.generationRequestRateLimiter.release();
});
}
}, executor);
}
}
private void tryFulfillDataSourceRequestGroup(DataSourceRequestGroup requestGroup, long pos)
{
this.fullDataSourceProvider().getAsync(pos).thenAccept(fullDataSource ->
@@ -313,4 +280,80 @@ public class FullDataSourceRequestHandler
}
}
//=========//
// ticking //
//=========//
private void tickLoop()
{
try
{
while (!Thread.interrupted())
{
Thread.sleep(20);
this.tick();
}
}
catch (InterruptedException ignore) { }
}
private void tick()
{
// Send finished data source requests
for (Map.Entry<Long, DataSourceRequestGroup> entry : this.requestGroupsByPos.entrySet())
{
DataSourceRequestGroup requestGroup = entry.getValue();
if (requestGroup.fullDataSource == null)
{
continue;
}
LOGGER.debug("[" + this.getLevelIdentifier() + "] Fulfilled request group [" + DhSectionPos.toString(entry.getKey()) + "]");
// Make this group unavailable for adding into
this.requestGroupsByPos.remove(entry.getKey());
if (!requestGroup.tryClose())
{
continue;
}
AbstractExecutorService executor = ThreadPoolUtil.getNetworkCompressionExecutor();
if (executor == null)
{
LOGGER.warn("Unable to send FullDataSourceResponseMessage - getNetworkCompressionExecutor() is null");
continue;
}
CompletableFuture.runAsync(() ->
{
FullDataPayload payload = new FullDataPayload(requestGroup.fullDataSource, this.getAllBeamsForPos(entry.getKey()));
requestGroup.fullDataSource.close();
for (DataSourceRequestGroup.RequestData requestData : requestGroup.requestMessages.values())
{
this.requestGroupsByFutureId.remove(requestData.futureId());
requestData.serverPlayerState.fullDataPayloadSender.sendInChunks(payload, () -> {
requestData.message.sendResponse(new FullDataSourceResponseMessage(payload));
requestData.rateLimiterSet.generationRequestRateLimiter.release();
});
}
}, executor);
}
}
//================//
// base overrides //
//================//
@Override
public void close()
{
this.tickerThread.shutdownNow();
}
}
@@ -117,18 +117,6 @@ public abstract class AbstractDhServerWorld<TDhServerLevel extends AbstractDhSer
//==============//
// tick methods //
//==============//
@Override
public void serverTick() { this.dhLevelByLevelWrapper.values().forEach(TDhServerLevel::serverTick); }
@Override
public void worldGenTick() { this.dhLevelByLevelWrapper.values().forEach(TDhServerLevel::worldGenTick); }
//================//
// base overrides //
//================//
@@ -115,9 +115,6 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
@Override
public void clientTick() { this.eventLoop.tick(); }
@Override
public void worldGenTick() { this.levels.values().forEach(DhClientLevel::worldGenTick); }
@Override
public void addDebugMenuStringsToList(List<String> messageList)
{
@@ -32,7 +32,6 @@ public interface IDhServerWorld extends IDhWorld
void addPlayer(IServerPlayerWrapper serverPlayer);
void removePlayer(IServerPlayerWrapper serverPlayer);
void changePlayerLevel(IServerPlayerWrapper player, IServerLevelWrapper originLevel, IServerLevelWrapper destinationLevel);
void serverTick();
default IDhServerLevel getOrLoadServerLevel(ILevelWrapper levelWrapper) { return (IDhServerLevel) this.getOrLoadLevel(levelWrapper); }
@@ -39,6 +39,4 @@ public interface IDhWorld extends Closeable
void unloadLevel(@NotNull ILevelWrapper levelWrapper);
void worldGenTick();
}