Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions src/main/java/mcjty/lostcities/worldgen/ChunkDriver.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,21 @@ private void setBlock(BlockPos p, BlockState state) {

// This version of getBlock() is less optimal but it will work for different chunks
private BlockState getBlockSafe(BlockPos p) {
return isThisChunk(p) ? getBlock(p) : region.getBlockState(p);
if (isThisChunk(p)) {
return getBlock(p);
}
// During parallel world generation a neighbouring chunk may not be part of (or ready in)
// the current WorldGenRegion. Reading it would throw "Requested chunk unavailable during
// world generation" and kill chunk generation. Treat unavailable neighbours as air:
// only cosmetic connection states (fences, walls, stairs) depend on these reads
if (!region.hasChunk(p.getX() >> 4, p.getZ() >> 4)) {
return Blocks.AIR.defaultBlockState();
}
try {
return region.getBlockState(p);
} catch (RuntimeException e) {
return Blocks.AIR.defaultBlockState();
}
}

private BlockState getBlock(BlockPos p) {
Expand Down Expand Up @@ -174,7 +188,17 @@ private BlockState updateAdjacent(BlockState state, Direction direction, BlockPo
return adjacent;
}
if (newAdjacent != adjacent) {
ChunkAccess chunk = region.getChunk(pos);
// The adjacent position may be outside the available region during parallel world
// generation. In that case just skip the (cosmetic) update
if (!region.hasChunk(pos.getX() >> 4, pos.getZ() >> 4)) {
return adjacent;
}
ChunkAccess chunk;
try {
chunk = region.getChunk(pos);
} catch (RuntimeException e) {
return adjacent;
}
if (chunk == thisChunk) {
setBlock(pos, newAdjacent);
} else if (chunk.getPersistedStatus().isOrAfter(ChunkStatus.FULL)) {
Expand Down
24 changes: 16 additions & 8 deletions src/main/java/mcjty/lostcities/worldgen/LostCityFeature.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,22 @@ public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> context) {

int chunkX = center.x;
int chunkZ = center.z;
diminfo.setWorld(level);
try {
diminfo.getFeature().generate(region, region.getChunk(chunkX, chunkZ));
} catch (Exception e) {
LostCities.getLogger().error("Error generating chunk {},{}: {}", chunkX, chunkZ, e.getMessage(), e);
e.printStackTrace();
ErrorLogger.logChunkInfo(chunkX, chunkZ, diminfo);
ErrorLogger.report("There was an error generating a chunk. See log for details!");
// The terrain feature (and its ChunkDriver) is shared per dimension while the
// feature step can run concurrently for different chunks. Serialize the world
// swap + generation on the shared feature instance so one thread can never tear
// down the driver or swap the region out from under another.
// LostCitySphereFeature locks the same monitor
LostCityTerrainFeature feature = diminfo.getFeature();
synchronized (feature) {
diminfo.setWorld(level);
try {
feature.generate(region, region.getChunk(chunkX, chunkZ));
} catch (Exception e) {
LostCities.getLogger().error("Error generating chunk {},{}: {}", chunkX, chunkZ, e.getMessage(), e);
e.printStackTrace();
ErrorLogger.logChunkInfo(chunkX, chunkZ, diminfo);
ErrorLogger.report("There was an error generating a chunk. See log for details!");
}
}
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,13 @@ public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> context) {

int chunkX = center.x;
int chunkZ = center.z;
diminfo.setWorld(level);
Spheres.generateSpheres(diminfo.getFeature(), region, region.getChunk(chunkX, chunkZ));
// See LostCityFeature.place: the terrain feature and its ChunkDriver are shared
// per dimension. Serialize on the same monitor to avoid concurrent driver teardown
LostCityTerrainFeature feature = diminfo.getFeature();
synchronized (feature) {
diminfo.setWorld(level);
Spheres.generateSpheres(feature, region, region.getChunk(chunkX, chunkZ));
}
return true;
}
}
Expand Down