Fix world gen tasks being incorrectly removed from the queue at long distances
This commit is contained in:
+6
@@ -45,6 +45,7 @@ import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Handles reading/writing {@link FullDataSourceV2}
|
||||
@@ -452,6 +453,11 @@ public class FullDataSourceProviderV2
|
||||
/** @return true if the position was queued, false if not */
|
||||
public boolean queuePositionForRetrieval(DhSectionPos genPos) { return false; }
|
||||
|
||||
/** does nothing if the given position isn't present in the queue */
|
||||
public void removeRetrievalRequestIf(Function<DhSectionPos, Boolean> removeIf) { }
|
||||
|
||||
public void clearRetrievalQueue() { }
|
||||
|
||||
/** Can be used to display how many total retrieval requests might be available. */
|
||||
public void setTotalRetrievalPositionCount(int newCount) { }
|
||||
|
||||
|
||||
+28
-34
@@ -65,40 +65,6 @@ public class GeneratedFullDataSourceProvider extends FullDataSourceProviderV2 im
|
||||
|
||||
|
||||
|
||||
//==================//
|
||||
// generation queue //
|
||||
//==================//
|
||||
|
||||
/**
|
||||
* Assigns the queue for handling world gen and does first time setup as well. <br>
|
||||
* Assumes there isn't a pre-existing queue.
|
||||
*/
|
||||
public void setWorldGenerationQueue(IFullDataSourceRetrievalQueue newWorldGenQueue)
|
||||
{
|
||||
boolean oldQueueExists = this.worldGenQueueRef.compareAndSet(null, newWorldGenQueue);
|
||||
LodUtil.assertTrue(oldQueueExists, "previous world gen queue is still here!");
|
||||
LOGGER.info("Set world gen queue for level ["+this.level+"].");
|
||||
}
|
||||
|
||||
public void clearGenerationQueue() { this.worldGenQueueRef.set(null); }
|
||||
|
||||
/** Can be used to remove positions that are outside the player's render distance. */
|
||||
public void removeGenRequestIf(Function<DhSectionPos, Boolean> removeIf)
|
||||
{
|
||||
// TODO there has to be a better way to do this
|
||||
|
||||
IFullDataSourceRetrievalQueue worldGenQueue = this.worldGenQueueRef.get();
|
||||
if (worldGenQueue != null)
|
||||
{
|
||||
worldGenQueue.removeGenRequestIf(removeIf);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUnsavedDataSourceCount() { return this.delayedFullDataSourceSaveCache.getUnsavedCount(); }
|
||||
|
||||
|
||||
|
||||
//=================//
|
||||
// event listeners //
|
||||
//=================//
|
||||
@@ -157,6 +123,17 @@ public class GeneratedFullDataSourceProvider extends FullDataSourceProviderV2 im
|
||||
// world gen (data source retrieval) //
|
||||
//===================================//
|
||||
|
||||
/**
|
||||
* Assigns the queue for handling world gen and does first time setup as well. <br>
|
||||
* Assumes there isn't a pre-existing queue.
|
||||
*/
|
||||
public void setWorldGenerationQueue(IFullDataSourceRetrievalQueue newWorldGenQueue)
|
||||
{
|
||||
boolean oldQueueExists = this.worldGenQueueRef.compareAndSet(null, newWorldGenQueue);
|
||||
LodUtil.assertTrue(oldQueueExists, "previous world gen queue is still here!");
|
||||
LOGGER.info("Set world gen queue for level ["+this.level+"].");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRetrieveMissingDataSources() { return true; }
|
||||
|
||||
@@ -226,6 +203,23 @@ public class GeneratedFullDataSourceProvider extends FullDataSourceProviderV2 im
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRetrievalRequestIf(Function<DhSectionPos, Boolean> removeIf)
|
||||
{
|
||||
IFullDataSourceRetrievalQueue worldGenQueue = this.worldGenQueueRef.get();
|
||||
if (worldGenQueue != null)
|
||||
{
|
||||
worldGenQueue.removeRetrievalRequestIf(removeIf);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearRetrievalQueue() { this.worldGenQueueRef.set(null); }
|
||||
|
||||
@Override
|
||||
public int getUnsavedDataSourceCount() { return this.delayedFullDataSourceSaveCache.getUnsavedCount(); }
|
||||
|
||||
|
||||
@Override
|
||||
public ArrayList<DhSectionPos> getPositionsToRetrieve(DhSectionPos pos)
|
||||
{
|
||||
|
||||
+5
-4
@@ -76,10 +76,11 @@ public interface IFullDataSourceRetrievalQueue extends Closeable
|
||||
// task handling //
|
||||
//===============//
|
||||
|
||||
/** @deprecated replace with {@link IFullDataSourceRetrievalQueue#removeGenTask(DhSectionPos)} */
|
||||
@Deprecated
|
||||
void removeGenRequestIf(Function<DhSectionPos, Boolean> removeIf);
|
||||
void removeGenTask(DhSectionPos pos);
|
||||
/**
|
||||
* Generally the retrieval queue should be fairly small, so its faster to iterate over the existing list
|
||||
* and check if each one is valid vs dumbly attempting to remove every position that just went out of range.
|
||||
*/
|
||||
void removeRetrievalRequestIf(Function<DhSectionPos, Boolean> removeIf);
|
||||
|
||||
CompletableFuture<WorldGenResult> submitGenTask(DhSectionPos pos, byte requiredDataDetail, IWorldGenTaskTracker tracker);
|
||||
|
||||
|
||||
+1
-11
@@ -159,7 +159,7 @@ public class WorldGenerationQueue implements IFullDataSourceRetrievalQueue, IDeb
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeGenRequestIf(Function<DhSectionPos, Boolean> removeIf)
|
||||
public void removeRetrievalRequestIf(Function<DhSectionPos, Boolean> removeIf)
|
||||
{
|
||||
this.waitingTasks.forEachKey(100, (genPos) ->
|
||||
{
|
||||
@@ -170,16 +170,6 @@ public class WorldGenerationQueue implements IFullDataSourceRetrievalQueue, IDeb
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeGenTask(DhSectionPos pos)
|
||||
{
|
||||
WorldGenTask task = this.waitingTasks.remove(pos);
|
||||
if (task != null)
|
||||
{
|
||||
task.future.cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -124,13 +124,6 @@ public class DhClientServerLevel extends AbstractDhLevel implements IDhClientLev
|
||||
|
||||
if (isWorldGenRunning)
|
||||
{
|
||||
ClientLevelModule.ClientRenderState renderState = this.clientside.ClientRenderStateRef.get();
|
||||
if (renderState != null && renderState.quadtree != null)
|
||||
{
|
||||
// remove any generator sections that are out of bounds
|
||||
this.serverside.dataFileHandler.removeGenRequestIf(pos -> !renderState.quadtree.isSectionPosInBounds(pos));
|
||||
}
|
||||
|
||||
this.serverside.worldGenModule.worldGenTick(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ public class WorldGenModule implements Closeable
|
||||
return;
|
||||
}
|
||||
}
|
||||
dataFileHandler.clearGenerationQueue();
|
||||
dataFileHandler.clearRetrievalQueue();
|
||||
worldGenState.closeAsync(true).join(); //TODO: Make it async.
|
||||
dataFileHandler.removeWorldGenCompleteListener(this.onWorldGenCompleteListener);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ import java.awt.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
/**
|
||||
@@ -345,6 +346,22 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable
|
||||
{
|
||||
this.renderSourceLoadingFuture.cancel(true);
|
||||
}
|
||||
|
||||
|
||||
// remove any active world gen requests that may be for this position
|
||||
ThreadPoolExecutor executor = ThreadPoolUtil.getCleanupExecutor();
|
||||
if (executor != null && !executor.isTerminated())
|
||||
{
|
||||
// while this should generally be a fast operation
|
||||
// this is run on a separate thread to prevent lag on the render thread
|
||||
|
||||
try
|
||||
{
|
||||
executor.execute(() -> this.fullDataSourceProvider.removeRetrievalRequestIf((genPos) -> this.pos.contains(genPos)));
|
||||
}
|
||||
catch (RejectedExecutionException ignore)
|
||||
{ /* If this happens that means everything is already shut down and no additional cleanup will be necessary */ }
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -61,6 +61,11 @@ public class ThreadPoolUtil
|
||||
@Nullable
|
||||
public static ThreadPoolExecutor getBufferUploaderExecutor() { return bufferUploaderThreadPool; }
|
||||
|
||||
public static final String CLEANUP_THREAD_NAME = "Cleanup";
|
||||
private static ThreadPoolExecutor cleanupThreadPool;
|
||||
@Nullable
|
||||
public static ThreadPoolExecutor getCleanupExecutor() { return cleanupThreadPool; }
|
||||
|
||||
|
||||
|
||||
//======================//
|
||||
@@ -108,6 +113,7 @@ public class ThreadPoolUtil
|
||||
updatePropagatorThreadPool = new ConfigThreadPool(UPDATE_PROPAGATOR_THREAD_FACTORY, Config.Client.Advanced.MultiThreading.numberOfUpdatePropagatorThreads, Config.Client.Advanced.MultiThreading.runTimeRatioForUpdatePropagatorThreads, null);
|
||||
worldGenThreadPool = new ConfigThreadPool(WORLD_GEN_THREAD_FACTORY, Config.Client.Advanced.MultiThreading.numberOfWorldGenerationThreads, Config.Client.Advanced.MultiThreading.runTimeRatioForWorldGenerationThreads, null);
|
||||
bufferUploaderThreadPool = ThreadUtil.makeSingleThreadPool(BUFFER_UPLOADER_THREAD_NAME);
|
||||
cleanupThreadPool = ThreadUtil.makeSingleThreadPool(CLEANUP_THREAD_NAME);
|
||||
|
||||
|
||||
|
||||
@@ -148,6 +154,7 @@ public class ThreadPoolUtil
|
||||
updatePropagatorThreadPool.shutdownExecutorService();
|
||||
worldGenThreadPool.shutdownExecutorService();
|
||||
bufferUploaderThreadPool.shutdown();
|
||||
cleanupThreadPool.shutdown();
|
||||
|
||||
|
||||
// worker threads
|
||||
|
||||
Reference in New Issue
Block a user