Potentially fix duplicate world generator issue?
This commit is contained in:
-20
@@ -255,26 +255,6 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu
|
||||
@Override
|
||||
public SingleColumnFullDataAccessor tryGet(int relativeX, int relativeZ) { return this.get(relativeX, relativeZ); }
|
||||
|
||||
@Override
|
||||
public ArrayList<DhSectionPos> getUngeneratedPosList()
|
||||
{
|
||||
ArrayList<DhSectionPos> posList = new ArrayList<>();
|
||||
|
||||
for (int x = 0; x < this.width; x++)
|
||||
{
|
||||
for (int z = 0; z < this.width; z++)
|
||||
{
|
||||
SingleColumnFullDataAccessor column = this.get(x,z);
|
||||
if (column == null || !column.doesColumnExist())
|
||||
{
|
||||
posList.add(new DhSectionPos(this.sectionPos.sectionDetailLevel, this.sectionPos.sectionX + x, this.sectionPos.sectionZ + z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return posList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(ChunkSizedFullDataAccessor chunkDataView)
|
||||
{
|
||||
|
||||
-20
@@ -392,26 +392,6 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo
|
||||
return chunk.get(relativeX % this.dataPointsPerSection, relativeZ % this.dataPointsPerSection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<DhSectionPos> getUngeneratedPosList()
|
||||
{
|
||||
ArrayList<DhSectionPos> posList = new ArrayList<>();
|
||||
|
||||
for (int x = 0; x < SECTION_SIZE; x++)
|
||||
{
|
||||
for (int z = 0; z < SECTION_SIZE; z++)
|
||||
{
|
||||
SingleColumnFullDataAccessor column = this.tryGet(x,z);
|
||||
if (column == null || !column.doesColumnExist())
|
||||
{
|
||||
posList.add(new DhSectionPos(this.sectionPos.sectionDetailLevel, this.sectionPos.sectionX + x, this.sectionPos.sectionZ + z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return posList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
|
||||
-20
@@ -265,26 +265,6 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp
|
||||
@Override
|
||||
public SingleColumnFullDataAccessor tryGet(int relativeX, int relativeZ) { return this.isColumnNotEmpty.get(relativeX * WIDTH + relativeZ) ? this.get(relativeX, relativeZ) : null; }
|
||||
|
||||
@Override
|
||||
public ArrayList<DhSectionPos> getUngeneratedPosList()
|
||||
{
|
||||
ArrayList<DhSectionPos> posList = new ArrayList<>();
|
||||
|
||||
for (int x = 0; x < this.width; x++)
|
||||
{
|
||||
for (int z = 0; z < this.width; z++)
|
||||
{
|
||||
SingleColumnFullDataAccessor column = this.get(x,z);
|
||||
if (column == null || !column.doesColumnExist())
|
||||
{
|
||||
posList.add(new DhSectionPos(this.sectionPos.sectionDetailLevel, this.sectionPos.sectionX + x, this.sectionPos.sectionZ + z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return posList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=====================//
|
||||
|
||||
+182
-4
@@ -5,15 +5,18 @@ import com.seibel.lod.core.dataObjects.fullData.FullDataPointIdMap;
|
||||
import com.seibel.lod.core.dataObjects.fullData.accessor.ChunkSizedFullDataAccessor;
|
||||
import com.seibel.lod.core.dataObjects.fullData.accessor.IFullDataAccessor;
|
||||
import com.seibel.lod.core.dataObjects.fullData.accessor.SingleColumnFullDataAccessor;
|
||||
import com.seibel.lod.core.dataObjects.fullData.sources.CompleteFullDataSource;
|
||||
import com.seibel.lod.core.dataObjects.render.ColumnRenderSource;
|
||||
import com.seibel.lod.core.file.fullDatafile.FullDataMetaFile;
|
||||
import com.seibel.lod.core.level.IDhLevel;
|
||||
import com.seibel.lod.core.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.util.objects.dataStreams.DhDataInputStream;
|
||||
import com.seibel.lod.core.util.objects.dataStreams.DhDataOutputStream;
|
||||
import com.seibel.lod.coreapi.util.BitShiftUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* Base for all Full Data Source objects. <br><br>
|
||||
@@ -65,10 +68,185 @@ public interface IFullDataSource
|
||||
|
||||
FullDataPointIdMap getMapping();
|
||||
|
||||
/** @return true if every datapoint in this object has been generated, false otherwise. */
|
||||
default boolean isCompletelyGenerated() { return this.getUngeneratedPosList().size() == 0; }
|
||||
/** @return the list of {@link DhSectionPos} that aren't generated in this data source. */
|
||||
ArrayList<DhSectionPos> getUngeneratedPosList();
|
||||
/**
|
||||
* @param highestGeneratorDetailLevel the smallest numerical detail level that the un-generated positions should be split into
|
||||
* @return the list of {@link DhSectionPos} that aren't generated in this data source.
|
||||
*/
|
||||
default ArrayList<DhSectionPos> getUngeneratedPosList(byte highestGeneratorDetailLevel, boolean onlyReturnPositionsTheGeneratorCanAccept)
|
||||
{
|
||||
ArrayList<DhSectionPos> posArray = this.getUngeneratedPosList(this.getSectionPos(), highestGeneratorDetailLevel);
|
||||
|
||||
if (onlyReturnPositionsTheGeneratorCanAccept)
|
||||
{
|
||||
LinkedList<DhSectionPos> posList = new LinkedList<>(posArray);
|
||||
|
||||
ArrayList<DhSectionPos> cleanedPosArray = new ArrayList<>();
|
||||
while (posList.size() > 0)
|
||||
{
|
||||
DhSectionPos pos = posList.remove();
|
||||
if (pos.sectionDetailLevel > highestGeneratorDetailLevel)
|
||||
{
|
||||
pos.forEachChild((childPos) -> { posList.push(childPos); });
|
||||
}
|
||||
else
|
||||
{
|
||||
cleanedPosArray.add(pos);
|
||||
}
|
||||
}
|
||||
|
||||
return cleanedPosArray;
|
||||
}
|
||||
else
|
||||
{
|
||||
return posArray;
|
||||
}
|
||||
}
|
||||
default ArrayList<DhSectionPos> getUngeneratedPosList(DhSectionPos quadrantPos, byte highestGeneratorDetailLevel)
|
||||
{
|
||||
ArrayList<DhSectionPos> ungeneratedPosList = new ArrayList<>();
|
||||
|
||||
int sourceRelWidth = this.getWidthInDataPoints();
|
||||
|
||||
|
||||
if (quadrantPos.sectionDetailLevel < highestGeneratorDetailLevel)
|
||||
{
|
||||
throw new IllegalArgumentException("detail level lower than world generator can accept.");
|
||||
}
|
||||
else if (quadrantPos.sectionDetailLevel == highestGeneratorDetailLevel)
|
||||
{
|
||||
// we are at the highest detail level the world generator can accept,
|
||||
// we either need to generate this whole section, or not at all
|
||||
|
||||
// TODO combine duplicate code
|
||||
|
||||
byte childDetailLevel = (byte) (quadrantPos.sectionDetailLevel);
|
||||
|
||||
int quadrantDetailLevelDiff = this.getSectionPos().sectionDetailLevel - childDetailLevel;
|
||||
int widthInSecPos = BitShiftUtil.powerOfTwo(quadrantDetailLevelDiff);
|
||||
int relWidthForSecPos = sourceRelWidth / widthInSecPos;
|
||||
|
||||
DhSectionPos minSecPos = this.getSectionPos().convertToDetailLevel(childDetailLevel);
|
||||
DhSectionPos inputPos = quadrantPos;
|
||||
|
||||
|
||||
|
||||
int minRelX = inputPos.sectionX - minSecPos.sectionX;
|
||||
int minRelZ = inputPos.sectionZ - minSecPos.sectionZ;
|
||||
int maxRelX = minRelX + 1;
|
||||
int maxRelZ = minRelZ + 1;
|
||||
|
||||
minRelX = minRelX * relWidthForSecPos;
|
||||
minRelZ = minRelZ * relWidthForSecPos;
|
||||
maxRelX = maxRelX * relWidthForSecPos;
|
||||
maxRelZ = maxRelZ * relWidthForSecPos;
|
||||
|
||||
if (this.getClass() != CompleteFullDataSource.class)
|
||||
{
|
||||
int breakpoint= 0;
|
||||
}
|
||||
|
||||
|
||||
boolean quadrantFullyGenerated = true;
|
||||
for (int relX = minRelX; relX < maxRelX; relX++)
|
||||
{
|
||||
for (int relZ = minRelZ; relZ < maxRelZ; relZ++)
|
||||
{
|
||||
SingleColumnFullDataAccessor column = this.tryGet(relX, relZ);
|
||||
if (column == null)
|
||||
{
|
||||
int breakpoi= 0;
|
||||
}
|
||||
|
||||
if (column == null || !column.doesColumnExist())// || column.hasNullDataPoints())
|
||||
{
|
||||
// no data for this relative position
|
||||
quadrantFullyGenerated = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!quadrantFullyGenerated)
|
||||
{
|
||||
// at least 1 data point is missing,
|
||||
// this whole section must be regenerated
|
||||
ungeneratedPosList.add(quadrantPos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO comment
|
||||
// TODO combine duplicate code
|
||||
|
||||
byte childDetailLevel = (byte) (quadrantPos.sectionDetailLevel-1);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
int quadrantDetailLevelDiff = this.getSectionPos().sectionDetailLevel - childDetailLevel;
|
||||
int widthInSecPos = BitShiftUtil.powerOfTwo(quadrantDetailLevelDiff);
|
||||
int relWidthForSecPos = sourceRelWidth / widthInSecPos;
|
||||
|
||||
DhSectionPos minSecPos = this.getSectionPos().convertToDetailLevel(childDetailLevel);
|
||||
DhSectionPos inputPos = quadrantPos.getChildByIndex(i);
|
||||
|
||||
|
||||
|
||||
int minRelX = inputPos.sectionX - minSecPos.sectionX;
|
||||
int minRelZ = inputPos.sectionZ - minSecPos.sectionZ;
|
||||
int maxRelX = minRelX + 1;
|
||||
int maxRelZ = minRelZ + 1;
|
||||
|
||||
minRelX = minRelX * relWidthForSecPos;
|
||||
minRelZ = minRelZ * relWidthForSecPos;
|
||||
maxRelX = maxRelX * relWidthForSecPos;
|
||||
maxRelZ = maxRelZ * relWidthForSecPos;
|
||||
|
||||
|
||||
|
||||
boolean quadrantFullyGenerated = true;
|
||||
boolean quadrantEmpty = true;
|
||||
for (int relX = minRelX; relX < maxRelX; relX++)
|
||||
{
|
||||
for (int relZ = minRelZ; relZ < maxRelZ; relZ++)
|
||||
{
|
||||
SingleColumnFullDataAccessor column = this.tryGet(relX, relZ);
|
||||
if (column == null || !column.doesColumnExist()) // || column.hasNullDataPoints())
|
||||
{
|
||||
// no data for this relative position
|
||||
quadrantFullyGenerated = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// data exists for this pos
|
||||
quadrantEmpty = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (quadrantFullyGenerated)
|
||||
{
|
||||
// no generation necessary
|
||||
continue;
|
||||
}
|
||||
else if (quadrantEmpty)
|
||||
{
|
||||
// nothing exists for this sub quadrant, add this sub-quadrant's position
|
||||
ungeneratedPosList.add(inputPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
// some data exists in this quadrant, but not all that we need
|
||||
// recurse down to determine which sub-quadrant positions will need generation
|
||||
|
||||
ungeneratedPosList.addAll(this.getUngeneratedPosList(inputPos, highestGeneratorDetailLevel));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return ungeneratedPosList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -30,14 +30,14 @@ import java.util.function.Function;
|
||||
public class FullDataFileHandler implements IFullDataSourceProvider
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
|
||||
// TODO add config option to set pool size
|
||||
final ExecutorService fileHandlerThread = ThreadUtil.makeThreadPool(4, FullDataFileHandler.class.getSimpleName()+"Thread");
|
||||
final ConcurrentHashMap<DhSectionPos, FullDataMetaFile> files = new ConcurrentHashMap<>();
|
||||
final IDhLevel level;
|
||||
final File saveDir;
|
||||
AtomicInteger topDetailLevel = new AtomicInteger(-1);
|
||||
final int minDetailLevel = CompleteFullDataSource.SECTION_SIZE_OFFSET;
|
||||
protected final ExecutorService fileHandlerThread = ThreadUtil.makeThreadPool(4, FullDataFileHandler.class.getSimpleName()+"Thread");
|
||||
protected final ConcurrentHashMap<DhSectionPos, FullDataMetaFile> fileBySectionPos = new ConcurrentHashMap<>();
|
||||
protected final IDhLevel level;
|
||||
protected final File saveDir;
|
||||
protected final AtomicInteger topDetailLevel = new AtomicInteger(-1);
|
||||
protected final int minDetailLevel = CompleteFullDataSource.SECTION_SIZE_OFFSET;
|
||||
|
||||
|
||||
|
||||
@@ -130,13 +130,13 @@ public class FullDataFileHandler implements IFullDataSourceProvider
|
||||
}
|
||||
// Add file to the list of files.
|
||||
this.topDetailLevel.updateAndGet(v -> Math.max(v, fileToUse.pos.sectionDetailLevel));
|
||||
this.files.put(pos, fileToUse);
|
||||
this.fileBySectionPos.put(pos, fileToUse);
|
||||
}
|
||||
}
|
||||
|
||||
protected FullDataMetaFile getOrMakeFile(DhSectionPos pos)
|
||||
{
|
||||
FullDataMetaFile metaFile = this.files.get(pos);
|
||||
FullDataMetaFile metaFile = this.fileBySectionPos.get(pos);
|
||||
if (metaFile == null)
|
||||
{
|
||||
FullDataMetaFile newMetaFile;
|
||||
@@ -149,7 +149,7 @@ public class FullDataFileHandler implements IFullDataSourceProvider
|
||||
LOGGER.error("IOException on creating new data file at {}", pos, e);
|
||||
return null;
|
||||
}
|
||||
metaFile = this.files.putIfAbsent(pos, newMetaFile); // This is a CAS with expected null value.
|
||||
metaFile = this.fileBySectionPos.putIfAbsent(pos, newMetaFile); // This is a CAS with expected null value.
|
||||
if (metaFile == null)
|
||||
{
|
||||
metaFile = newMetaFile;
|
||||
@@ -190,7 +190,7 @@ public class FullDataFileHandler implements IFullDataSourceProvider
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.files.containsKey(subPos))
|
||||
if (this.fileBySectionPos.containsKey(subPos))
|
||||
{
|
||||
allEmpty = false;
|
||||
break outerLoop;
|
||||
@@ -219,7 +219,7 @@ public class FullDataFileHandler implements IFullDataSourceProvider
|
||||
DhSectionPos childPos = pos.getChildByIndex(childIndex);
|
||||
if (CompleteFullDataSource.firstDataPosCanAffectSecond(basePos, childPos))
|
||||
{
|
||||
FullDataMetaFile metaFile = this.files.get(childPos);
|
||||
FullDataMetaFile metaFile = this.fileBySectionPos.get(childPos);
|
||||
if (metaFile != null)
|
||||
{
|
||||
// we have reached a populated leaf node in the quad tree
|
||||
@@ -285,7 +285,7 @@ public class FullDataFileHandler implements IFullDataSourceProvider
|
||||
}
|
||||
private void writeChunkDataToMetaFile(DhSectionPos sectionPos, ChunkSizedFullDataAccessor chunkData)
|
||||
{
|
||||
FullDataMetaFile metaFile = this.files.get(sectionPos);
|
||||
FullDataMetaFile metaFile = this.fileBySectionPos.get(sectionPos);
|
||||
if (metaFile != null)
|
||||
{
|
||||
// there is a file for this position
|
||||
@@ -304,7 +304,7 @@ public class FullDataFileHandler implements IFullDataSourceProvider
|
||||
public CompletableFuture<Void> flushAndSave()
|
||||
{
|
||||
ArrayList<CompletableFuture<Void>> futures = new ArrayList<>();
|
||||
for (FullDataMetaFile metaFile : this.files.values())
|
||||
for (FullDataMetaFile metaFile : this.fileBySectionPos.values())
|
||||
{
|
||||
futures.add(metaFile.flushAndSaveAsync());
|
||||
}
|
||||
@@ -392,7 +392,7 @@ public class FullDataFileHandler implements IFullDataSourceProvider
|
||||
|
||||
FileUtil.renameCorruptedFile(metaFile.file);
|
||||
// remove the FullDataMetaFile since the old one was corrupted
|
||||
this.files.remove(pos);
|
||||
this.fileBySectionPos.remove(pos);
|
||||
// create a new FullDataMetaFile to write new data to
|
||||
return this.getOrMakeFile(pos);
|
||||
}
|
||||
|
||||
@@ -344,7 +344,7 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile
|
||||
{
|
||||
if (exception != null)
|
||||
{
|
||||
LOGGER.error("Error refreshing data "+this.pos+": "+exception+" "+exception.getMessage());
|
||||
LOGGER.error("Error refreshing data "+this.pos+": "+exception+" "+exception.getMessage(), exception);
|
||||
future.complete(null);
|
||||
this.cachedFullDataSource = new SoftReference<>(null);
|
||||
}
|
||||
|
||||
+152
-107
@@ -9,6 +9,7 @@ import com.seibel.lod.core.generation.tasks.IWorldGenTaskTracker;
|
||||
import com.seibel.lod.core.generation.WorldGenerationQueue;
|
||||
import com.seibel.lod.core.generation.tasks.WorldGenResult;
|
||||
import com.seibel.lod.core.level.IDhServerLevel;
|
||||
import com.seibel.lod.core.pos.DhLodPos;
|
||||
import com.seibel.lod.core.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
@@ -24,21 +25,19 @@ import java.util.function.Consumer;
|
||||
|
||||
public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
private final AtomicReference<WorldGenerationQueue> worldGenQueueRef = new AtomicReference<>(null);
|
||||
private final AtomicReference<WorldGenerationQueue> worldGenQueueRef = new AtomicReference<>(null);
|
||||
|
||||
private final ArrayList<IOnWorldGenCompleteListener> onWorldGenTaskCompleteListeners = new ArrayList<>();
|
||||
|
||||
/**
|
||||
/**
|
||||
* Keeps track of which partially generated {@link IFullDataSource} {@link DhSectionPos}' are waiting to be generated.
|
||||
* This is done to prevent sending duplicate generation requests for the same position.
|
||||
*/
|
||||
private final HashSet<DhSectionPos> incompleteSourceGenRequests = new HashSet<>();
|
||||
|
||||
|
||||
|
||||
public GeneratedFullDataFileHandler(IDhServerLevel level, File saveRootDir) { super(level, saveRootDir); }
|
||||
public GeneratedFullDataFileHandler(IDhServerLevel level, File saveRootDir) { super(level, saveRootDir); }
|
||||
|
||||
|
||||
|
||||
@@ -46,11 +45,12 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
// data //
|
||||
//======//
|
||||
|
||||
@Override
|
||||
public CompletableFuture<IFullDataSource> read(DhSectionPos pos)
|
||||
{
|
||||
return super.read(pos).whenComplete((fullDataSource, ex) ->
|
||||
return super.read(pos).whenComplete((fullDataSource, ex) ->
|
||||
{
|
||||
this.checkIfSectionNeedsAdditionalGeneration(pos, fullDataSource);
|
||||
this.DISABLED_checkIfSectionNeedsAdditionalGeneration(pos, fullDataSource);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -61,11 +61,11 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
//==================//
|
||||
|
||||
/** Assumes there isn't a pre-existing queue. */
|
||||
public void setGenerationQueue(WorldGenerationQueue newWorldGenQueue)
|
||||
public void setGenerationQueue(WorldGenerationQueue newWorldGenQueue)
|
||||
{
|
||||
boolean oldQueueExists = this.worldGenQueueRef.compareAndSet(null, newWorldGenQueue);
|
||||
LodUtil.assertTrue(oldQueueExists, "previous world gen queue is still here!");
|
||||
}
|
||||
boolean oldQueueExists = this.worldGenQueueRef.compareAndSet(null, newWorldGenQueue);
|
||||
LodUtil.assertTrue(oldQueueExists, "previous world gen queue is still here!");
|
||||
}
|
||||
|
||||
public void clearGenerationQueue() { this.worldGenQueueRef.set(null); }
|
||||
|
||||
@@ -76,6 +76,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
//=================//
|
||||
|
||||
public void addWorldGenCompleteListener(IOnWorldGenCompleteListener listener) { this.onWorldGenTaskCompleteListeners.add(listener); }
|
||||
|
||||
public void removeWorldGenCompleteListener(IOnWorldGenCompleteListener listener) { this.onWorldGenTaskCompleteListeners.remove(listener); }
|
||||
|
||||
|
||||
@@ -84,17 +85,17 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
// events //
|
||||
//========//
|
||||
|
||||
@Override
|
||||
public CompletableFuture<IFullDataSource> onCreateDataFile(FullDataMetaFile file)
|
||||
@Override
|
||||
public CompletableFuture<IFullDataSource> onCreateDataFile(FullDataMetaFile file)
|
||||
{
|
||||
DhSectionPos pos = file.pos;
|
||||
|
||||
DhSectionPos pos = file.pos;
|
||||
|
||||
ArrayList<FullDataMetaFile> existingFiles = new ArrayList<>();
|
||||
ArrayList<DhSectionPos> missingPositions = new ArrayList<>();
|
||||
ArrayList<DhSectionPos> missingPositions = new ArrayList<>();
|
||||
this.getDataFilesForPosition(pos, pos, existingFiles, missingPositions);
|
||||
|
||||
// confirm the quad tree has at least one node in it
|
||||
LodUtil.assertTrue(!missingPositions.isEmpty() || !existingFiles.isEmpty());
|
||||
LodUtil.assertTrue(!missingPositions.isEmpty() || !existingFiles.isEmpty());
|
||||
|
||||
|
||||
// determine the type of dataSource that should be used for this position
|
||||
@@ -109,76 +110,84 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
}
|
||||
|
||||
|
||||
if (missingPositions.size() == 1 && existingFiles.isEmpty() && missingPositions.get(0).equals(pos))
|
||||
if (missingPositions.size() == 1 && existingFiles.isEmpty() && missingPositions.get(0).equals(pos))
|
||||
{
|
||||
// No LOD data exists for this position yet
|
||||
// No LOD data exists for this position yet
|
||||
|
||||
WorldGenerationQueue worldGenQueue = this.worldGenQueueRef.get();
|
||||
if (worldGenQueue != null)
|
||||
WorldGenerationQueue worldGenQueue = this.worldGenQueueRef.get();
|
||||
if (worldGenQueue != null)
|
||||
{
|
||||
this.incompleteSourceGenRequests.add(pos);
|
||||
|
||||
// queue this section to be generated
|
||||
GenTask genTask = new GenTask(pos, new WeakReference<>(incompleteFullDataSource));
|
||||
worldGenQueue.submitGenTask(incompleteFullDataSource.getSectionPos().getSectionBBoxPos(), incompleteFullDataSource.getDataDetailLevel(), genTask)
|
||||
.whenComplete((genTaskResult, ex) -> this.onWorldGenTaskComplete(genTaskResult, ex, genTask, pos));
|
||||
}
|
||||
worldGenQueue.submitGenTask(new DhLodPos(pos), incompleteFullDataSource.getDataDetailLevel(), genTask)
|
||||
.whenComplete((genTaskResult, ex) ->
|
||||
{
|
||||
this.onWorldGenTaskComplete(genTaskResult, ex, genTask, pos);
|
||||
this.fireOnGenPosSuccessListeners(pos);
|
||||
this.incompleteSourceGenRequests.remove(pos);
|
||||
});
|
||||
}
|
||||
|
||||
// return the empty dataSource (it will be populated later)
|
||||
return CompletableFuture.completedFuture(incompleteFullDataSource);
|
||||
}
|
||||
return CompletableFuture.completedFuture(incompleteFullDataSource);
|
||||
}
|
||||
else
|
||||
{
|
||||
// LOD data exists for this position
|
||||
|
||||
// create the missing metaData files
|
||||
for (DhSectionPos missingPos : missingPositions)
|
||||
for (DhSectionPos missingPos : missingPositions)
|
||||
{
|
||||
FullDataMetaFile newFile = this.getOrMakeFile(missingPos);
|
||||
if (newFile != null)
|
||||
FullDataMetaFile newFile = this.getOrMakeFile(missingPos);
|
||||
if (newFile != null)
|
||||
{
|
||||
existingFiles.add(newFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LOGGER.debug("Creating "+pos+" from sampling "+existingFiles.size()+" files: "+existingFiles);
|
||||
// LOGGER.debug("Creating "+pos+" from sampling "+existingFiles.size()+" files: "+existingFiles);
|
||||
|
||||
// read in the existing data
|
||||
final ArrayList<CompletableFuture<Void>> loadDataFutures = new ArrayList<>(existingFiles.size());
|
||||
for (FullDataMetaFile existingFile : existingFiles)
|
||||
for (FullDataMetaFile existingFile : existingFiles)
|
||||
{
|
||||
loadDataFutures.add(existingFile.loadOrGetCachedDataSourceAsync()
|
||||
.exceptionally((ex) -> /*Ignore file read errors*/null)
|
||||
.thenAccept((fullDataSource) ->
|
||||
{
|
||||
if (fullDataSource == null)
|
||||
loadDataFutures.add(existingFile.loadOrGetCachedDataSourceAsync()
|
||||
.exceptionally((ex) -> /*Ignore file read errors*/null)
|
||||
.thenAccept((fullDataSource) ->
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.checkIfSectionNeedsAdditionalGeneration(pos, fullDataSource);
|
||||
|
||||
//LOGGER.info("Merging data from {} into {}", data.getSectionPos(), pos);
|
||||
incompleteFullDataSource.sampleFrom(fullDataSource);
|
||||
})
|
||||
);
|
||||
}
|
||||
if (fullDataSource == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.DISABLED_checkIfSectionNeedsAdditionalGeneration(pos, fullDataSource);
|
||||
|
||||
//LOGGER.info("Merging data from {} into {}", data.getSectionPos(), pos);
|
||||
incompleteFullDataSource.sampleFrom(fullDataSource);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return CompletableFuture.allOf(loadDataFutures.toArray(new CompletableFuture[0]))
|
||||
.thenApply((voidValue) -> incompleteFullDataSource.tryPromotingToCompleteDataSource());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given {@link IFullDataSource} is fully generated and
|
||||
* if it isn't, new world gen request(s) will be created.
|
||||
*/
|
||||
private void checkIfSectionNeedsAdditionalGeneration(DhSectionPos pos, IFullDataSource fullDataSource)
|
||||
{
|
||||
boolean generateSection = fullDataSource == null || (!fullDataSource.isCompletelyGenerated() && !incompleteSourceGenRequests.contains(pos));
|
||||
if (!generateSection)
|
||||
{
|
||||
// this section doesn't need to be generated
|
||||
return;
|
||||
return CompletableFuture.allOf(loadDataFutures.toArray(new CompletableFuture[0]))
|
||||
.thenApply((voidValue) -> incompleteFullDataSource.tryPromotingToCompleteDataSource());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given {@link IFullDataSource} is fully generated and
|
||||
* if it isn't, creates the necessary world gen request(s) to finish it. <br>
|
||||
* Should be used to fill out partially generated {@link IFullDataSource}'s,
|
||||
* not populate empty ones.
|
||||
*/
|
||||
private void DISABLED_checkIfSectionNeedsAdditionalGeneration(DhSectionPos pos, IFullDataSource fullDataSource)
|
||||
{
|
||||
// FIXME method is disabled since it will often cause duplicate world gen requests which cause other issues
|
||||
// and James is out of ideas for how to fix it.
|
||||
if (true)
|
||||
return;
|
||||
|
||||
|
||||
WorldGenerationQueue worldGenQueue = this.worldGenQueueRef.get();
|
||||
if (worldGenQueue == null)
|
||||
@@ -188,34 +197,63 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
}
|
||||
|
||||
|
||||
// the data source could be null if no file exists for this position
|
||||
if (fullDataSource == null)
|
||||
if (fullDataSource == null || fullDataSource.isEmpty())
|
||||
{
|
||||
if (pos.sectionDetailLevel <= HighDetailIncompleteFullDataSource.MAX_SECTION_DETAIL)
|
||||
{
|
||||
fullDataSource = HighDetailIncompleteFullDataSource.createEmpty(pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
fullDataSource = LowDetailIncompleteFullDataSource.createEmpty(pos);
|
||||
}
|
||||
// none of the data source has been generated, those generation requests should be handled elsewhere
|
||||
return;
|
||||
}
|
||||
else if (this.incompleteSourceGenRequests.contains(pos))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ArrayList<DhSectionPos> ungeneratedPosList = fullDataSource.getUngeneratedPosList(worldGenQueue.maxGranularity, true);
|
||||
if (ungeneratedPosList.size() == 0)
|
||||
{
|
||||
// this section doesn't need to be generated
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
incompleteSourceGenRequests.add(pos);
|
||||
//LOGGER.info("["+ungeneratedPosList.size()+"] missing sub positions for pos: ["+pos+"]. Number of gen requests queued: ["+queuedGenRequests.size()+"].");
|
||||
|
||||
// note: this will potentially re-generate terrain, however due to the generator setup this is currently unavoidable and probably not worth worrying about
|
||||
GenTask genTask = new GenTask(pos, new WeakReference<>(fullDataSource));
|
||||
worldGenQueue.submitGenTask(fullDataSource.getSectionPos().getSectionBBoxPos(), fullDataSource.getDataDetailLevel(), genTask)
|
||||
//LOGGER.info("["+ungeneratedPosList.size()+"] missing sub positions for pos: ["+pos+"]. Number of gen requests queued: ["+this.incompleteSourceGenRequests.size()+"].");
|
||||
|
||||
List<CompletableFuture<WorldGenResult>> futureList = new ArrayList<>();
|
||||
for (DhSectionPos ungenChildPos : ungeneratedPosList)
|
||||
{
|
||||
// don't queue the same section twice
|
||||
if (this.incompleteSourceGenRequests.contains(ungenChildPos))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
this.incompleteSourceGenRequests.add(ungenChildPos);
|
||||
|
||||
|
||||
// FIXME this can cause duplicate terrain generation requests
|
||||
GenTask genTask = new GenTask(ungenChildPos, new WeakReference<>(fullDataSource));
|
||||
CompletableFuture<WorldGenResult> future = worldGenQueue.submitGenTask(new DhLodPos(ungenChildPos), fullDataSource.getDataDetailLevel(), genTask)
|
||||
.whenComplete((genTaskResult, ex) ->
|
||||
{
|
||||
incompleteSourceGenRequests.remove(pos);
|
||||
//LOGGER.info("Partial generation completed for pos: ["+pos+"]. Remaining gen requests queued: ["+queuedGenRequests.size()+"].");
|
||||
|
||||
this.onWorldGenTaskComplete(genTaskResult, ex, genTask, pos);
|
||||
//LOGGER.info("Partial generation completed for pos: ["+pos+"]. Remaining gen requests queued: ["+this.incompleteSourceGenRequests.size()+"].");
|
||||
|
||||
this.onWorldGenTaskComplete(genTaskResult, ex, genTask, ungenChildPos);
|
||||
this.fireOnGenPosSuccessListeners(pos);
|
||||
this.incompleteSourceGenRequests.remove(ungenChildPos);
|
||||
});
|
||||
futureList.add(future);
|
||||
}
|
||||
|
||||
|
||||
if (futureList.size() != 0)
|
||||
{
|
||||
CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0]))
|
||||
.whenComplete((genTaskResult, ex) ->
|
||||
{
|
||||
// parent pos has completed generation
|
||||
this.fireOnGenPosSuccessListeners(pos);
|
||||
this.incompleteSourceGenRequests.remove(pos);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void onWorldGenTaskComplete(WorldGenResult genTaskResult, Throwable exception, GenTask genTask, DhSectionPos pos)
|
||||
@@ -231,33 +269,39 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
else if (genTaskResult.success)
|
||||
{
|
||||
// generation completed, update the files and listener(s)
|
||||
|
||||
// LOGGER.info("gen task completed for pos: ["+pos+"].");
|
||||
this.files.get(genTask.pos).flushAndSaveAsync();
|
||||
|
||||
// fire the event listeners
|
||||
for (IOnWorldGenCompleteListener listener : this.onWorldGenTaskCompleteListeners)
|
||||
{
|
||||
listener.onWorldGenTaskComplete(genTask.pos);
|
||||
}
|
||||
|
||||
// this.files.get(genTask.pos).metaData.dataVersion.incrementAndGet();
|
||||
this.fireOnGenPosSuccessListeners(pos);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// generation didn't complete
|
||||
|
||||
// if the generation task was split up into smaller positions, wait for them to complete
|
||||
for (CompletableFuture<WorldGenResult> siblingFuture : genTaskResult.childFutures)
|
||||
{
|
||||
siblingFuture.whenComplete((siblingGenTaskResult, siblingEx) -> this.onWorldGenTaskComplete(siblingGenTaskResult, siblingEx, genTask, pos));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// if the generation task was split up into smaller positions, add the on-complete event to them
|
||||
for (CompletableFuture<WorldGenResult> siblingFuture : genTaskResult.childFutures)
|
||||
{
|
||||
siblingFuture.whenComplete((siblingGenTaskResult, siblingEx) -> this.onWorldGenTaskComplete(siblingGenTaskResult, siblingEx, genTask, pos));
|
||||
}
|
||||
|
||||
genTask.releaseStrongReference();
|
||||
}
|
||||
|
||||
private void fireOnGenPosSuccessListeners(DhSectionPos pos)
|
||||
{
|
||||
//LOGGER.info("gen task completed for pos: ["+pos+"].");
|
||||
|
||||
this.fileBySectionPos.get(pos).flushAndSaveAsync()
|
||||
.whenComplete((voidObj, ex) ->
|
||||
{
|
||||
// fire the event listeners
|
||||
for (IOnWorldGenCompleteListener listener : this.onWorldGenTaskCompleteListeners)
|
||||
{
|
||||
listener.onWorldGenTaskComplete(pos);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
@@ -292,11 +336,12 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
if (this.loadedTargetFullDataSource == null)
|
||||
{
|
||||
this.loadedTargetFullDataSource = this.targetFullDataSourceRef.get();
|
||||
if (this.loadedTargetFullDataSource == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (this.loadedTargetFullDataSource == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return (chunkSizedFullDataSource) ->
|
||||
{
|
||||
@@ -311,8 +356,8 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* used by external event listeners <br>
|
||||
/**
|
||||
* used by external event listeners <br>
|
||||
* TODO may or may not be best to have this in a separate file
|
||||
*/
|
||||
@FunctionalInterface
|
||||
|
||||
@@ -30,7 +30,7 @@ public class RenderMetaDataFile extends AbstractMetaDataContainerFile
|
||||
* When clearing, don't set to null, instead create a SoftReference containing null.
|
||||
* This will make null checks simpler.
|
||||
*/
|
||||
private SoftReference<ColumnRenderSource> cachedRenderDataSource = new SoftReference<>(null);
|
||||
private SoftReference<ColumnRenderSource> cachedRenderDataSourceRef = new SoftReference<>(null);
|
||||
|
||||
private final RenderSourceFileHandler fileHandler;
|
||||
private boolean doesFileExist;
|
||||
@@ -110,7 +110,7 @@ public class RenderMetaDataFile extends AbstractMetaDataContainerFile
|
||||
private CompletableFuture<ColumnRenderSource> getCachedDataSourceAsync()
|
||||
{
|
||||
// attempt to get the cached data source
|
||||
ColumnRenderSource cachedRenderDataSource = this.cachedRenderDataSource.get();
|
||||
ColumnRenderSource cachedRenderDataSource = this.cachedRenderDataSourceRef.get();
|
||||
if (cachedRenderDataSource != null)
|
||||
{
|
||||
return this.fileHandler.onReadRenderSourceLoadedFromCacheAsync(this, cachedRenderDataSource)
|
||||
@@ -127,7 +127,6 @@ public class RenderMetaDataFile extends AbstractMetaDataContainerFile
|
||||
|
||||
public CompletableFuture<ColumnRenderSource> loadOrGetCachedDataSourceAsync(Executor fileReaderThreads, IDhLevel level)
|
||||
{
|
||||
|
||||
CompletableFuture<ColumnRenderSource> getCachedFuture = this.getCachedDataSourceAsync();
|
||||
if (getCachedFuture != null)
|
||||
{
|
||||
@@ -157,12 +156,12 @@ public class RenderMetaDataFile extends AbstractMetaDataContainerFile
|
||||
{
|
||||
LOGGER.error("Uncaught error on creation {}: ", this.file, ex);
|
||||
loadRenderSourceFuture.complete(null);
|
||||
this.cachedRenderDataSource = new SoftReference<>(null);
|
||||
this.cachedRenderDataSourceRef = new SoftReference<>(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
loadRenderSourceFuture.complete(renderSource);
|
||||
this.cachedRenderDataSource = new SoftReference<>(renderSource);
|
||||
this.cachedRenderDataSourceRef = new SoftReference<>(renderSource);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -196,12 +195,12 @@ public class RenderMetaDataFile extends AbstractMetaDataContainerFile
|
||||
{
|
||||
LOGGER.error("Error loading file {}: ", this.file, ex);
|
||||
loadRenderSourceFuture.complete(null);
|
||||
this.cachedRenderDataSource = new SoftReference<>(null);
|
||||
this.cachedRenderDataSourceRef = new SoftReference<>(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
loadRenderSourceFuture.complete(renderSource);
|
||||
this.cachedRenderDataSource = new SoftReference<>(renderSource);
|
||||
this.cachedRenderDataSourceRef = new SoftReference<>(renderSource);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.dataObjects.fullData.accessor.ChunkSizedFullDataAccessor;
|
||||
import com.seibel.lod.core.dataObjects.transformers.LodDataBuilder;
|
||||
import com.seibel.lod.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.lod.core.file.fullDatafile.GeneratedFullDataFileHandler;
|
||||
import com.seibel.lod.core.generation.tasks.*;
|
||||
import com.seibel.lod.core.pos.*;
|
||||
import com.seibel.lod.core.util.ThreadUtil;
|
||||
@@ -19,6 +20,7 @@ import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.function.Consumer;
|
||||
@@ -35,11 +37,13 @@ public class WorldGenerationQueue implements Closeable
|
||||
private final ConcurrentHashMap<DhLodPos, InProgressWorldGenTaskGroup> inProgressGenTasksByLodPos = new ConcurrentHashMap<>();
|
||||
|
||||
// granularity is the detail level for batching world generator requests together
|
||||
private final byte maxGranularity;
|
||||
private final byte minGranularity;
|
||||
public final byte maxGranularity;
|
||||
public final byte minGranularity;
|
||||
|
||||
private final byte maxDataDetail;
|
||||
private final byte minDataDetail;
|
||||
/** largest numerical detail level allowed */
|
||||
final byte largestDataDetail;
|
||||
/** lowest numerical detail level allowed */
|
||||
public final byte smallestDataDetail;
|
||||
|
||||
/** If not null this generator is in the process of shutting down */
|
||||
private volatile CompletableFuture<Void> generatorClosingFuture = null;
|
||||
@@ -54,24 +58,26 @@ public class WorldGenerationQueue implements Closeable
|
||||
private DhBlockPos2D generationTargetPos = DhBlockPos2D.ZERO;
|
||||
/** can be used for debugging how many tasks are currently in the queue */
|
||||
private int numberOfTasksQueued = 0;
|
||||
/**
|
||||
* Settings this to true will cause the system to queue the first generation request it can find,
|
||||
* this improves generation thread feeding efficiency, but can potentially cause generation requests to queue out of order (IE they may not be closest to farthest). <br><br>
|
||||
*
|
||||
* Setting this to false will cause the system to queue the closest generation request it can find. <br>
|
||||
* This will reduce generation queuing efficiency.
|
||||
*/
|
||||
private boolean queueFirstGenerationRequestFound = true;
|
||||
|
||||
// debug variables to test for duplicate world generator requests //
|
||||
/** limits how many of the previous world gen requests we should track */
|
||||
private static final int MAX_ALREADY_GENERATED_COUNT = 400;
|
||||
private final HashSet<DhLodPos> alreadyGeneratedPosHashSet = new HashSet<>(MAX_ALREADY_GENERATED_COUNT);
|
||||
private final Queue<DhLodPos> alreadyGeneratedPosQueue = new LinkedList<>();
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
|
||||
public WorldGenerationQueue(IDhApiWorldGenerator generator)
|
||||
{
|
||||
this.generator = generator;
|
||||
this.maxGranularity = generator.getMaxGenerationGranularity();
|
||||
this.minGranularity = generator.getMinGenerationGranularity();
|
||||
this.maxDataDetail = generator.getLargestDataDetailLevel();
|
||||
this.minDataDetail = generator.getSmallestDataDetailLevel();
|
||||
this.largestDataDetail = generator.getLargestDataDetailLevel();
|
||||
this.smallestDataDetail = generator.getSmallestDataDetailLevel();
|
||||
|
||||
int treeWidth = Config.Client.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH * 2; // TODO the *2 is to allow for generation edge cases, and should probably be removed at some point
|
||||
byte treeMinDetailLevel = LodUtil.BLOCK_DETAIL_LEVEL; // the tree shouldn't need to go this low, but just in case
|
||||
@@ -105,13 +111,13 @@ public class WorldGenerationQueue implements Closeable
|
||||
|
||||
|
||||
// make sure the generator can provide the requested position
|
||||
if (requiredDataDetail < this.minDataDetail)
|
||||
if (requiredDataDetail < this.smallestDataDetail)
|
||||
{
|
||||
throw new UnsupportedOperationException("Current generator does not meet requiredDataDetail level");
|
||||
}
|
||||
if (requiredDataDetail > this.maxDataDetail)
|
||||
if (requiredDataDetail > this.largestDataDetail)
|
||||
{
|
||||
requiredDataDetail = this.maxDataDetail;
|
||||
requiredDataDetail = this.largestDataDetail;
|
||||
}
|
||||
|
||||
// TODO what does this assert mean?
|
||||
@@ -358,9 +364,36 @@ public class WorldGenerationQueue implements Closeable
|
||||
DhLodPos taskPos = inProgressTaskGroup.group.pos;
|
||||
byte granularity = (byte) (taskPos.detailLevel - taskDetailLevel);
|
||||
LodUtil.assertTrue(granularity >= this.minGranularity && granularity <= this.maxGranularity);
|
||||
LodUtil.assertTrue(taskDetailLevel >= this.minDataDetail && taskDetailLevel <= this.maxDataDetail);
|
||||
LodUtil.assertTrue(taskDetailLevel >= this.smallestDataDetail && taskDetailLevel <= this.largestDataDetail);
|
||||
|
||||
DhChunkPos chunkPosMin = new DhChunkPos(taskPos.getCornerBlockPos());
|
||||
|
||||
|
||||
// Could be enabled (change the if-false to true) to test for duplicate world generator requests
|
||||
if (false)
|
||||
{
|
||||
if (this.alreadyGeneratedPosHashSet.contains(inProgressTaskGroup.group.pos))
|
||||
{
|
||||
// temporary solution to prevent generating the same section multiple times
|
||||
LOGGER.warn("Duplicate generation section " + taskPos + " with granularity [" + granularity + "] at " + chunkPosMin + ". Skipping...");
|
||||
|
||||
// FIXME this prevents sections from generating, or from being updated in the LodQuadTree, James isn't sure which issue it is
|
||||
inProgressTaskGroup.group.worldGenTasks.forEach(worldGenTask -> worldGenTask.future.complete(WorldGenResult.CreateFail()));
|
||||
return;
|
||||
}
|
||||
|
||||
this.alreadyGeneratedPosHashSet.add(inProgressTaskGroup.group.pos);
|
||||
this.alreadyGeneratedPosQueue.add(inProgressTaskGroup.group.pos);
|
||||
|
||||
|
||||
// remove extra tracked positions
|
||||
while (this.alreadyGeneratedPosQueue.size() > MAX_ALREADY_GENERATED_COUNT)
|
||||
{
|
||||
DhLodPos posToRemove = this.alreadyGeneratedPosQueue.poll();
|
||||
this.alreadyGeneratedPosHashSet.remove(posToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
//LOGGER.info("Generating section "+taskPos+" with granularity "+granularity+" at "+chunkPosMin);
|
||||
|
||||
this.numberOfTasksQueued++;
|
||||
@@ -371,7 +404,8 @@ public class WorldGenerationQueue implements Closeable
|
||||
if (exception != null)
|
||||
{
|
||||
// don't log the shutdown exceptions
|
||||
if (!UncheckedInterruptedException.isThrowableInterruption(exception) && !(exception instanceof CancellationException || exception.getCause() instanceof CancellationException))
|
||||
if (!UncheckedInterruptedException.isThrowableInterruption(exception)
|
||||
&& !(exception instanceof CancellationException || exception.getCause() instanceof CancellationException))
|
||||
{
|
||||
LOGGER.error("Error generating data for section "+taskPos, exception);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user