Skip to content

Commit

Permalink
-Optimize world generation by checking if a column's sections are emp…
Browse files Browse the repository at this point in the history
…ty, if so, skip.
  • Loading branch information
CorgiTaco committed May 20, 2021
1 parent 0e8c355 commit 1d80085
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -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) {
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand All @@ -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());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -180,6 +184,7 @@ private static void cubicChunksBiome(ServerLevel world, ChunkGenerator chunkGene
((ProtoChunk) chunkAccess).setBiomes(biomeContainer);
}


// biomes -> handled by MixinChunkGenerator
@SuppressWarnings({ "UnresolvedMixinReference", "target" })
@Inject(
Expand All @@ -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<ChunkAccess> completableFuture = null;

Expand All @@ -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<ChunkAccess> 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);
Expand All @@ -239,13 +256,32 @@ 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 {
ci.setReturnValue(CompletableFuture.completedFuture(Either.left(chunk)));
}
}

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",
Expand Down Expand Up @@ -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)));
Expand Down Expand Up @@ -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);
}
}
Expand Down

0 comments on commit 1d80085

Please sign in to comment.