diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/ICubeGenerator.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/ICubeGenerator.java index c7022b018..475296ae4 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/ICubeGenerator.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/ICubeGenerator.java @@ -1,9 +1,10 @@ package io.github.opencubicchunks.cubicchunks.chunk; +import io.github.opencubicchunks.cubicchunks.chunk.cube.CubePrimer; import io.github.opencubicchunks.cubicchunks.world.CubeWorldGenRegion; import net.minecraft.world.level.StructureFeatureManager; public interface ICubeGenerator { - default void decorate(CubeWorldGenRegion region, StructureFeatureManager structureManager) { + default void decorate(CubeWorldGenRegion region, StructureFeatureManager structureManager, CubePrimer chunkAccess) { } } \ No newline at end of file diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/util/CCWorldGenUtils.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/util/CCWorldGenUtils.java new file mode 100644 index 000000000..022f23616 --- /dev/null +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/util/CCWorldGenUtils.java @@ -0,0 +1,25 @@ +package io.github.opencubicchunks.cubicchunks.chunk.util; + +import io.github.opencubicchunks.cubicchunks.chunk.IBigCube; +import io.github.opencubicchunks.cubicchunks.utils.Coords; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.LevelChunkSection; + +public class CCWorldGenUtils { + + public static boolean areSectionsEmpty(int cubeY, ChunkPos pos, IBigCube cube) { + int emptySections = 0; + for (int yScan = 0; yScan < IBigCube.DIAMETER_IN_SECTIONS; yScan++) { + int sectionY = Coords.cubeToSection(cubeY, yScan); + int sectionIndex = Coords.sectionToIndex(pos.x, sectionY, pos.z); + LevelChunkSection cubeSection = cube.getCubeSections()[sectionIndex]; + if (LevelChunkSection.isEmpty(cubeSection)) { + emptySections++; + } + if (emptySections == IBigCube.DIAMETER_IN_SECTIONS) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunkGenerator.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunkGenerator.java index df37f55ae..e0fa3ac7f 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunkGenerator.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunkGenerator.java @@ -9,6 +9,8 @@ import io.github.opencubicchunks.cubicchunks.chunk.ICubeGenerator; import io.github.opencubicchunks.cubicchunks.chunk.NonAtomicWorldgenRandom; import io.github.opencubicchunks.cubicchunks.chunk.carver.CubicCarvingContext; +import io.github.opencubicchunks.cubicchunks.chunk.cube.CubePrimer; +import io.github.opencubicchunks.cubicchunks.chunk.util.CCWorldGenUtils; import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos; import io.github.opencubicchunks.cubicchunks.mixin.access.common.OverworldBiomeSourceAccess; import io.github.opencubicchunks.cubicchunks.server.CubicLevelHeightAccessor; @@ -219,7 +221,7 @@ private void do3DLocateStructure(ServerLevel serverLevel, StructureFeature st } @Override - public void decorate(CubeWorldGenRegion region, StructureFeatureManager structureManager) { + public void decorate(CubeWorldGenRegion region, StructureFeatureManager structureManager, CubePrimer chunk) { int mainCubeX = region.getMainCubeX(); int mainCubeY = region.getMainCubeY(); int mainCubeZ = region.getMainCubeZ(); @@ -233,8 +235,14 @@ public void decorate(CubeWorldGenRegion region, StructureFeatureManager structur //Get each individual column from a given cube no matter the size. Where y height is the same per column. //Feed the given columnMinPos into the feature decorators. + int cubeY = chunk.getCubePos().getY(); for (int columnX = 0; columnX < IBigCube.DIAMETER_IN_SECTIONS; columnX++) { for (int columnZ = 0; columnZ < IBigCube.DIAMETER_IN_SECTIONS; columnZ++) { + chunk.moveColumns(columnX, columnZ); + if (CCWorldGenUtils.areSectionsEmpty(cubeY, chunk.getPos(), chunk)) { + continue; + } + BlockPos columnMinPos = new BlockPos(xStart + (sectionToMinBlock(columnX)), yStart, zStart + (sectionToMinBlock(columnZ))); long seed = worldgenRandom.setDecorationSeed(region.getSeed(), columnMinPos.getX(), columnMinPos.getY(), columnMinPos.getZ()); diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunkStatus.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunkStatus.java index d68bd7597..b525f195f 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunkStatus.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunkStatus.java @@ -14,19 +14,23 @@ import io.github.opencubicchunks.cubicchunks.chunk.NoiseAndSurfaceBuilderHelper; import io.github.opencubicchunks.cubicchunks.chunk.biome.ColumnBiomeContainer; import io.github.opencubicchunks.cubicchunks.chunk.cube.CubePrimer; +import io.github.opencubicchunks.cubicchunks.chunk.util.CCWorldGenUtils; import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos; import io.github.opencubicchunks.cubicchunks.mixin.access.common.StructureFeatureManagerAccess; import io.github.opencubicchunks.cubicchunks.server.CubicLevelHeightAccessor; +import io.github.opencubicchunks.cubicchunks.utils.Coords; import io.github.opencubicchunks.cubicchunks.world.CubeWorldGenRegion; import io.github.opencubicchunks.cubicchunks.world.server.IServerWorldLightManager; import net.minecraft.core.Registry; import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.StructureFeatureManager; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.levelgen.GenerationStep; @@ -180,6 +184,7 @@ private static void cubicChunksBiome(ServerLevel world, ChunkGenerator chunkGene ((ProtoChunk) chunkAccess).setBiomes(biomeContainer); } + // biomes -> handled by MixinChunkGenerator @SuppressWarnings({ "UnresolvedMixinReference", "target" }) @Inject( @@ -204,8 +209,10 @@ private static void cubicChunksNoise(ChunkStatus status, Executor executor, Serv if (chunk instanceof IBigCube) { CubeWorldGenRegion cubeWorldGenRegion = new CubeWorldGenRegion(world, unsafeCast(neighbors), chunk); - CubePrimer cubeAbove = new CubePrimer(CubePos.of(((IBigCube) chunk).getCubePos().getX(), ((IBigCube) chunk).getCubePos().getY() + 1, - ((IBigCube) chunk).getCubePos().getZ()), UpgradeData.EMPTY, cubeWorldGenRegion); + CubePos cubePos = ((IBigCube) chunk).getCubePos(); + int cubeY = cubePos.getY(); + CubePrimer cubeAbove = new CubePrimer(CubePos.of(cubePos.getX(), cubeY + 1, + cubePos.getZ()), UpgradeData.EMPTY, cubeWorldGenRegion); CompletableFuture completableFuture = null; @@ -216,12 +223,22 @@ private static void cubicChunksNoise(ChunkStatus status, Executor executor, Serv ((CubePrimer) chunk).moveColumns(columnX, columnZ); } + ChunkPos pos = chunk.getPos(); + NoiseAndSurfaceBuilderHelper cubeAccessWrapper = new NoiseAndSurfaceBuilderHelper((IBigCube) chunk, cubeAbove); cubeAccessWrapper.moveColumn(columnX, columnZ); CompletableFuture chunkAccessCompletableFuture = generator.fillFromNoise(executor, world.structureFeatureManager().forWorldGenRegion(cubeWorldGenRegion), cubeAccessWrapper).thenApply(chunkAccess -> { cubeAccessWrapper.applySections(); + + + // Exit early and don't waste time on empty sections. + if (areSectionsEmpty(cubeY, pos, ((NoiseAndSurfaceBuilderHelper) chunkAccess).getDelegateByIndex(0))) { + return chunkAccess; + } + generator.buildSurfaceAndBedrock(cubeWorldGenRegion, chunkAccess); + // Carvers generator.applyCarvers(world.getSeed(), world.getBiomeManager(), cubeAccessWrapper, GenerationStep.Carving.AIR); generator.applyCarvers(world.getSeed(), world.getBiomeManager(), cubeAccessWrapper, GenerationStep.Carving.LIQUID); @@ -239,6 +256,9 @@ private static void cubicChunksNoise(ChunkStatus status, Executor executor, Serv if (chunk instanceof CubePrimer) { ((CubePrimer) chunk).setCubeStatus(status); } + +// System.out.println("Total time taken for cycle: " + totalTimeForCycle + "ms. Skipped Carvers: " + skipped); + return Either.left(chunk); })); } else { @@ -246,6 +266,22 @@ private static void cubicChunksNoise(ChunkStatus status, Executor executor, Serv } } + private static boolean areSectionsEmpty(int cubeY, ChunkPos pos, IBigCube cube) { + int emptySections = 0; + for (int yScan = 0; yScan < IBigCube.DIAMETER_IN_SECTIONS; yScan++) { + int sectionY = Coords.cubeToSection(cubeY, yScan); + int sectionIndex = Coords.sectionToIndex(pos.x, sectionY, pos.z); + LevelChunkSection cubeSection = cube.getCubeSections()[sectionIndex]; + if (LevelChunkSection.isEmpty(cubeSection)) { + emptySections++; + } + if (emptySections == IBigCube.DIAMETER_IN_SECTIONS) { + return true; + } + } + return false; + } + @SuppressWarnings({ "UnresolvedMixinReference", "target" }) @Inject( method = "lambda$static$7(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/level/chunk/ChunkGenerator;Ljava/util/List;Lnet/minecraft/world/level/chunk/ChunkAccess;)V", @@ -379,7 +415,8 @@ private static void featuresSetStatus( new StructureFeatureManager(cubeWorldGenRegion, ((StructureFeatureManagerAccess) world.structureFeatureManager()).getWorldGenSettings()); // if (cubePrimer.getCubePos().getY() >= 0) - ((ICubeGenerator) generator).decorate(cubeWorldGenRegion, structureFeatureManager); + + ((ICubeGenerator) generator).decorate(cubeWorldGenRegion, structureFeatureManager, (CubePrimer) chunk); cubePrimer.setCubeStatus(status); } cir.setReturnValue(CompletableFuture.completedFuture(Either.left(chunk))); @@ -424,10 +461,16 @@ private static void cubicChunksSpawnMobs(ServerLevel world, ChunkGenerator gener ci.cancel(); if (chunk instanceof IBigCube) { + int cubeY = ((IBigCube) chunk).getCubePos().getY(); + CubeWorldGenRegion cubeWorldGenRegion = new CubeWorldGenRegion(world, unsafeCast(neighbors), chunk); for (int columnX = 0; columnX < IBigCube.DIAMETER_IN_SECTIONS; columnX++) { for (int columnZ = 0; columnZ < IBigCube.DIAMETER_IN_SECTIONS; columnZ++) { cubeWorldGenRegion.moveCenterCubeChunkPos(columnX, columnZ); + if (CCWorldGenUtils.areSectionsEmpty(cubeY, chunk.getPos(), (IBigCube) chunk)) { + continue; + } + generator.spawnOriginalMobs(cubeWorldGenRegion); } }