minor world gen related refactoring
This commit is contained in:
@@ -1415,49 +1415,6 @@ public class Config
|
||||
+ "")
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Boolean> recalculateChunkHeightmaps = new ConfigEntry.Builder<Boolean>()
|
||||
.set(false)
|
||||
.comment(""
|
||||
+ "True: Recalculate chunk height maps before chunks can be used by DH.\n"
|
||||
+ " This can fix problems with worlds created by World Painter or \n"
|
||||
+ " other external tools where the heightmap format may be incorrect. \n"
|
||||
+ "False: Assume any height maps handled by Minecraft are correct. \n"
|
||||
+ "\n"
|
||||
+ "Fastest: False\n"
|
||||
+ "Most Compatible: True\n"
|
||||
+ "")
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Boolean> pullLightingForPregeneratedChunks = new ConfigEntry.Builder<Boolean>()
|
||||
.set(false)
|
||||
.comment(""
|
||||
+ "If true LOD generation for pre-existing chunks will attempt to pull the lighting data \n"
|
||||
+ "saved in Minecraft's Region files. \n"
|
||||
+ "If false DH will pull in chunks without lighting and re-light them. \n"
|
||||
+ " \n"
|
||||
+ "Setting this to true will result in faster LOD generation \n"
|
||||
+ "for already generated worlds, but is broken by most lighting mods. \n"
|
||||
+ " \n"
|
||||
+ "Set this to false if LODs are black. \n"
|
||||
+ "")
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Boolean> assumePreExistingChunksAreFinished = new ConfigEntry.Builder<Boolean>()
|
||||
.set(false)
|
||||
.comment(""
|
||||
+ "When DH pulls in pre-existing chunks it will attempt to \n"
|
||||
+ "run any missing world generation steps; for example: \n"
|
||||
+ "if a chunk has the status SURFACE, DH will skip BIOMES \n"
|
||||
+ "and SURFACE, but will run FEATURES. \n"
|
||||
+ " \n"
|
||||
+ "However if for some reason the chunks are malformed \n"
|
||||
+ "or there's some other issue that causes the status \n"
|
||||
+ "to be incorrect that can either cause world gen \n"
|
||||
+ "lock-ups and/or crashes. \n"
|
||||
+ "If either of those happen try setting this to True. \n"
|
||||
+ "")
|
||||
.build();
|
||||
|
||||
public static ConfigCategory experimental = new ConfigCategory.Builder().set(Experimental.class).build();
|
||||
|
||||
|
||||
|
||||
@@ -98,18 +98,14 @@ public class BatchGenerator implements IDhApiWorldGenerator
|
||||
ExecutorService worldGeneratorThreadPool,
|
||||
Consumer<Object[]> resultConsumer)
|
||||
{
|
||||
EDhApiWorldGenerationStep targetStep = null;
|
||||
EDhApiWorldGenerationStep targetStep;
|
||||
switch (generatorMode)
|
||||
{
|
||||
case PRE_EXISTING_ONLY: // Only load in existing chunks.
|
||||
//case BIOME_ONLY: // No blocks. Require fake height in LodBuilder
|
||||
targetStep = EDhApiWorldGenerationStep.EMPTY;
|
||||
targetStep = EDhApiWorldGenerationStep.EMPTY; // special logic
|
||||
break;
|
||||
//case BIOME_ONLY_SIMULATE_HEIGHT:
|
||||
// targetStep = EDhApiWorldGenerationStep.NOISE; // Stone only. Requires a fake surface
|
||||
// break;
|
||||
case SURFACE:
|
||||
targetStep = EDhApiWorldGenerationStep.SURFACE; // TODO could we ignore adjacent chunks for a speedup?
|
||||
targetStep = EDhApiWorldGenerationStep.SURFACE;
|
||||
break;
|
||||
case FEATURES:
|
||||
targetStep = EDhApiWorldGenerationStep.FEATURES;
|
||||
@@ -117,6 +113,9 @@ public class BatchGenerator implements IDhApiWorldGenerator
|
||||
case INTERNAL_SERVER:
|
||||
targetStep = EDhApiWorldGenerationStep.LIGHT;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("no target step defined for generator mode: ["+generatorMode+"].");
|
||||
}
|
||||
|
||||
// the consumer needs to be wrapped like this because the API can't use DH core objects (and IChunkWrapper can't be easily put into the API project)
|
||||
|
||||
+49
-36
@@ -154,14 +154,15 @@ public class DhLightingEngine
|
||||
// and get any necessary info from them
|
||||
for (int chunkIndex = 0; chunkIndex < nearbyChunkList.size(); chunkIndex++) // using iterators in high traffic areas can cause GC issues due to allocating a bunch of iterators, use an indexed for-loop instead
|
||||
{
|
||||
IChunkWrapper chunk = nearbyChunkList.get(chunkIndex);
|
||||
if (chunk != null && requestedAdjacentPositions.contains(chunk.getChunkPos()))
|
||||
IChunkWrapper neighborChunk = nearbyChunkList.get(chunkIndex);
|
||||
if (neighborChunk != null
|
||||
&& requestedAdjacentPositions.contains(neighborChunk.getChunkPos()))
|
||||
{
|
||||
// remove the newly found position
|
||||
requestedAdjacentPositions.remove(chunk.getChunkPos());
|
||||
requestedAdjacentPositions.remove(neighborChunk.getChunkPos());
|
||||
|
||||
// add the adjacent chunk
|
||||
adjacentChunkHolder.add(chunk);
|
||||
adjacentChunkHolder.add(neighborChunk);
|
||||
|
||||
// get and set the adjacent chunk's initial block lights
|
||||
final DhBlockPosMutable relLightBlockPos = PRIMARY_BLOCK_POS_REF.get();
|
||||
@@ -174,19 +175,19 @@ public class DhLightingEngine
|
||||
|
||||
if (updateBlockLight)
|
||||
{
|
||||
ArrayList<DhBlockPos> blockLightPosList = chunk.getWorldBlockLightPosList();
|
||||
ArrayList<DhBlockPos> blockLightPosList = neighborChunk.getWorldBlockLightPosList();
|
||||
for (int blockLightIndex = 0; blockLightIndex < blockLightPosList.size(); blockLightIndex++) // using iterators in high traffic areas can cause GC issues due to allocating a bunch of iterators, use an indexed for-loop instead
|
||||
{
|
||||
DhBlockPos blockLightPos = blockLightPosList.get(blockLightIndex);
|
||||
blockLightPos.mutateToChunkRelativePos(relLightBlockPos);
|
||||
|
||||
// get the light
|
||||
IBlockStateWrapper blockState = chunk.getBlockState(relLightBlockPos);
|
||||
IBlockStateWrapper blockState = neighborChunk.getBlockState(relLightBlockPos);
|
||||
int lightValue = blockState.getLightEmission();
|
||||
blockLightWorldPosQueue.push(blockLightPos.getX(), blockLightPos.getY(), blockLightPos.getZ(), lightValue);
|
||||
|
||||
// set the light
|
||||
chunk.setDhBlockLight(relLightBlockPos.getX(), relLightBlockPos.getY(), relLightBlockPos.getZ(), lightValue);
|
||||
neighborChunk.setDhBlockLight(relLightBlockPos.getX(), relLightBlockPos.getY(), relLightBlockPos.getZ(), lightValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,23 +199,24 @@ public class DhLightingEngine
|
||||
|
||||
// get and set the adjacent chunk's initial skylights,
|
||||
// if the dimension has skylights
|
||||
if (updateSkyLight && maxSkyLight > 0)
|
||||
if (updateSkyLight
|
||||
&& maxSkyLight > 0)
|
||||
{
|
||||
IMutableBlockPosWrapper mcBlockPos = chunk.getMutableBlockPosWrapper();
|
||||
IMutableBlockPosWrapper mcBlockPos = neighborChunk.getMutableBlockPosWrapper();
|
||||
IBlockStateWrapper previousBlockState = null;
|
||||
|
||||
int maxY = chunk.getMaxNonEmptyHeight();
|
||||
int minY = chunk.getInclusiveMinBuildHeight();
|
||||
int maxY = neighborChunk.getMaxNonEmptyHeight();
|
||||
int minY = neighborChunk.getInclusiveMinBuildHeight();
|
||||
|
||||
// get the adjacent chunk's sky lights
|
||||
for (int relX = 0; relX < LodUtil.CHUNK_WIDTH; relX++) // relative block pos
|
||||
{
|
||||
for (int relZ = 0; relZ < LodUtil.CHUNK_WIDTH; relZ++)
|
||||
{
|
||||
// set each pos' sky light all the way down until an opaque block is hit
|
||||
// set each pos sky light all the way down until an opaque block is hit
|
||||
for (int y = maxY; y >= minY; y--)
|
||||
{
|
||||
IBlockStateWrapper block = previousBlockState = chunk.getBlockState(relX, y, relZ, mcBlockPos, previousBlockState);
|
||||
IBlockStateWrapper block = previousBlockState = neighborChunk.getBlockState(relX, y, relZ, mcBlockPos, previousBlockState);
|
||||
if (block != null && block.getOpacity() != LodUtil.BLOCK_FULLY_TRANSPARENT)
|
||||
{
|
||||
// keep moving down until we find a non-transparent block
|
||||
@@ -223,12 +225,12 @@ public class DhLightingEngine
|
||||
|
||||
|
||||
// add sky light to the queue
|
||||
DhBlockPos skyLightPos = new DhBlockPos(chunk.getMinBlockX() + relX, y, chunk.getMinBlockZ() + relZ);
|
||||
DhBlockPos skyLightPos = new DhBlockPos(neighborChunk.getMinBlockX() + relX, y, neighborChunk.getMinBlockZ() + relZ);
|
||||
skyLightWorldPosQueue.push(skyLightPos.getX(), skyLightPos.getY(), skyLightPos.getZ(), maxSkyLight);
|
||||
|
||||
// set the chunk's sky light
|
||||
skyLightPos.mutateToChunkRelativePos(relLightBlockPos);
|
||||
chunk.setDhSkyLight(relLightBlockPos.getX(), relLightBlockPos.getY(), relLightBlockPos.getZ(), maxSkyLight);
|
||||
neighborChunk.setDhSkyLight(relLightBlockPos.getX(), relLightBlockPos.getY(), relLightBlockPos.getZ(), maxSkyLight);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -247,13 +249,12 @@ public class DhLightingEngine
|
||||
if (updateBlockLight)
|
||||
{
|
||||
// done to prevent a rare issue where the light values are incorrectly set to -1
|
||||
// TODO why could that happen?
|
||||
centerChunk.clearDhBlockLighting();
|
||||
|
||||
this.propagateChunkLightPosList(blockLightWorldPosQueue, adjacentChunkHolder,
|
||||
(neighbourChunk, relBlockPos) -> neighbourChunk.getDhBlockLight(relBlockPos.getX(), relBlockPos.getY(), relBlockPos.getZ()),
|
||||
(neighbourChunk, relBlockPos, newLightValue) -> neighbourChunk.setDhBlockLight(relBlockPos.getX(), relBlockPos.getY(), relBlockPos.getZ(), newLightValue),
|
||||
true);
|
||||
(neighbourChunk, relBlockPos) -> neighbourChunk.getDhBlockLight(relBlockPos.getX(), relBlockPos.getY(), relBlockPos.getZ()),
|
||||
(neighbourChunk, relBlockPos, newLightValue) -> neighbourChunk.setDhBlockLight(relBlockPos.getX(), relBlockPos.getY(), relBlockPos.getZ(), newLightValue),
|
||||
true);
|
||||
}
|
||||
|
||||
// sky light
|
||||
@@ -262,9 +263,9 @@ public class DhLightingEngine
|
||||
centerChunk.clearDhSkyLighting();
|
||||
|
||||
this.propagateChunkLightPosList(skyLightWorldPosQueue, adjacentChunkHolder,
|
||||
(neighbourChunk, relBlockPos) -> neighbourChunk.getDhSkyLight(relBlockPos.getX(), relBlockPos.getY(), relBlockPos.getZ()),
|
||||
(neighbourChunk, relBlockPos, newLightValue) -> neighbourChunk.setDhSkyLight(relBlockPos.getX(), relBlockPos.getY(), relBlockPos.getZ(), newLightValue),
|
||||
false);
|
||||
(neighbourChunk, relBlockPos) -> neighbourChunk.getDhSkyLight(relBlockPos.getX(), relBlockPos.getY(), relBlockPos.getZ()),
|
||||
(neighbourChunk, relBlockPos, newLightValue) -> neighbourChunk.setDhSkyLight(relBlockPos.getX(), relBlockPos.getY(), relBlockPos.getZ(), newLightValue),
|
||||
false);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -300,9 +301,25 @@ public class DhLightingEngine
|
||||
final DhBlockPosMutable neighbourBlockPos = PRIMARY_BLOCK_POS_REF.get();
|
||||
final DhBlockPosMutable relNeighbourBlockPos = SECONDARY_BLOCK_POS_REF.get();
|
||||
|
||||
// it doesn't matter what chunk we get the mutable block pos from
|
||||
IMutableBlockPosWrapper mcBlockPos = null;
|
||||
for (int i = 0; i < adjacentChunkHolder.chunkArray.length; i++)
|
||||
{
|
||||
IChunkWrapper chunkWrapper = adjacentChunkHolder.chunkArray[i];
|
||||
if (chunkWrapper != null)
|
||||
{
|
||||
mcBlockPos = chunkWrapper.getMutableBlockPosWrapper();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mcBlockPos == null)
|
||||
{
|
||||
LodUtil.assertNotReach("How did we try to light a chunk with no chunks?");
|
||||
}
|
||||
|
||||
IBlockStateWrapper previousBlockState = null;
|
||||
|
||||
|
||||
// update each light position
|
||||
while (!lightPosQueue.isEmpty())
|
||||
{
|
||||
@@ -346,15 +363,9 @@ public class DhLightingEngine
|
||||
}
|
||||
|
||||
|
||||
if (mcBlockPos == null)
|
||||
{
|
||||
// it doesn't matter what chunk we get the position object from
|
||||
// TODO move this getter logic out of ChunkWrapper
|
||||
mcBlockPos = neighbourChunk.getMutableBlockPosWrapper();
|
||||
}
|
||||
IBlockStateWrapper neighbourBlockState = neighbourChunk.getBlockState(relNeighbourBlockPos, mcBlockPos, previousBlockState);
|
||||
previousBlockState = neighbourBlockState;
|
||||
|
||||
|
||||
IBlockStateWrapper neighbourBlockState = previousBlockState = neighbourChunk.getBlockState(relNeighbourBlockPos, mcBlockPos, previousBlockState);
|
||||
// Math.max(1, ...) is used so that the propagated light level always drops by at least 1, preventing infinite cycles.
|
||||
int targetLevel = lightValue - Math.max(1, neighbourBlockState.getOpacity());
|
||||
if (targetLevel > currentBlockLight)
|
||||
@@ -370,12 +381,14 @@ public class DhLightingEngine
|
||||
}
|
||||
|
||||
|
||||
// can be enable if troubleshooting lighting issues
|
||||
if (RENDER_BLOCK_LIGHT_WIREFRAME && propagatingBlockLights)
|
||||
// can be enabled if troubleshooting lighting issues
|
||||
if (RENDER_BLOCK_LIGHT_WIREFRAME
|
||||
&& propagatingBlockLights)
|
||||
{
|
||||
RenderDhLightValuesAsWireframe(adjacentChunkHolder, true);
|
||||
}
|
||||
else if (RENDER_SKY_LIGHT_WIREFRAME && !propagatingBlockLights)
|
||||
else if (RENDER_SKY_LIGHT_WIREFRAME
|
||||
&& !propagatingBlockLights)
|
||||
{
|
||||
RenderDhLightValuesAsWireframe(adjacentChunkHolder, false);
|
||||
}
|
||||
@@ -462,7 +475,7 @@ public class DhLightingEngine
|
||||
point = FullDataPointUtil.setSkyLight(point, skylight);
|
||||
dataPoints.set(index, point);
|
||||
// now for the propagation.
|
||||
recursivelyLightAdjacentDataPoints(dataSource, airIDs, x, z, point);
|
||||
this.recursivelyLightAdjacentDataPoints(dataSource, airIDs, x, z, point);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -596,7 +609,7 @@ public class DhLightingEngine
|
||||
else if (!airIDs.get(FullDataPointUtil.getId(adjacentDataPoint)))
|
||||
{
|
||||
// assume for now that we cannot propagate into non-transparent data points.
|
||||
continue; // TODO how does this work with water? Do we care?
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -610,7 +623,7 @@ public class DhLightingEngine
|
||||
adjacentDataPoint = FullDataPointUtil.setSkyLight(adjacentDataPoint, lightLevel - 1);
|
||||
adjacentDataPoints.set(adjacentIndex, adjacentDataPoint);
|
||||
// if propagation succeeded, recursively propagate again starting at the adjacent data point.
|
||||
recursivelyLightAdjacentDataPoints(chunk, airIDs, adjacentX, adjacentZ, adjacentDataPoint);
|
||||
this.recursivelyLightAdjacentDataPoints(chunk, airIDs, adjacentX, adjacentZ, adjacentDataPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-19
@@ -66,15 +66,6 @@ public class WorldGenerationQueue implements IFullDataSourceRetrievalQueue, IDeb
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
private static final IWrapperFactory WRAPPER_FACTORY = SingletonInjector.INSTANCE.get(IWrapperFactory.class);
|
||||
|
||||
/**
|
||||
* Defines how many tasks can be queued per thread. <br><br>
|
||||
*
|
||||
* TODO the multiplier here should change dynamically based on how fast the generator is vs the queuing thread,
|
||||
* if this is too high it may cause issues when moving,
|
||||
* but if it is too low the generator threads won't have enough tasks to work on
|
||||
*/
|
||||
private static final int MAX_QUEUED_TASKS_PER_THREAD = 1;
|
||||
|
||||
|
||||
private final IDhApiWorldGenerator generator;
|
||||
private final IDhServerLevel level;
|
||||
@@ -241,9 +232,9 @@ public class WorldGenerationQueue implements IFullDataSourceRetrievalQueue, IDeb
|
||||
return true;
|
||||
}
|
||||
|
||||
// queue more tasks if any of the threads are available
|
||||
int worldGenThreadCount = Math.max(Config.Common.MultiThreading.numberOfThreads.get(), 1);
|
||||
int maxWorldGenTaskCount = worldGenThreadCount * MAX_QUEUED_TASKS_PER_THREAD;
|
||||
return this.inProgressGenTasksByLodPos.size() > maxWorldGenTaskCount;
|
||||
return this.inProgressGenTasksByLodPos.size() > worldGenThreadCount;
|
||||
}
|
||||
/**
|
||||
* @param targetPos the position to center the generation around
|
||||
@@ -412,15 +403,17 @@ public class WorldGenerationQueue implements IFullDataSourceRetrievalQueue, IDeb
|
||||
try
|
||||
{
|
||||
IChunkWrapper chunkWrapper = WRAPPER_FACTORY.createChunkWrapper(generatedObjectArray);
|
||||
|
||||
//// TODO light data should be pulled (if possible) from the ChunkAccess object itself via ChunkFileReader.readLight
|
||||
//// but this should work for now
|
||||
//ArrayList<IChunkWrapper> nearbyChunkList = new ArrayList<>();
|
||||
//nearbyChunkList.add(chunkWrapper);
|
||||
//byte maxSkyLight = this.level.getLevelWrapper().hasSkyLight() ? LodUtil.MAX_MC_LIGHT : LodUtil.MIN_MC_LIGHT;
|
||||
//DhLightingEngine.INSTANCE.bakeChunkBlockLighting(chunkWrapper, nearbyChunkList, maxSkyLight);
|
||||
|
||||
chunkWrapper.setIsDhBlockLightCorrect(true);
|
||||
// only light the chunk here if necessary,
|
||||
// lighting before this point is preferred but for potenial legacy API uses this
|
||||
// check should be done
|
||||
if (!chunkWrapper.isDhBlockLightingCorrect())
|
||||
{
|
||||
ArrayList<IChunkWrapper> nearbyChunkList = new ArrayList<>();
|
||||
nearbyChunkList.add(chunkWrapper);
|
||||
byte maxSkyLight = this.level.getLevelWrapper().hasSkyLight() ? LodUtil.MAX_MC_LIGHT : LodUtil.MIN_MC_LIGHT;
|
||||
DhLightingEngine.INSTANCE.bakeChunkBlockLighting(chunkWrapper, nearbyChunkList, maxSkyLight);
|
||||
}
|
||||
|
||||
try (FullDataSourceV2 dataSource = LodDataBuilder.createFromChunk(this.level.getLevelWrapper(), chunkWrapper))
|
||||
{
|
||||
|
||||
+6
@@ -158,6 +158,12 @@ public class ChunkLightStorage
|
||||
lightSection.set(x, y, z, lightLevel);
|
||||
}
|
||||
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return this.lightSections == null
|
||||
|| this.lightSections.length == 0;
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
if (this.lightSections != null)
|
||||
|
||||
Reference in New Issue
Block a user