diff --git a/common/build.gradle b/common/build.gradle index 5cfee816..a5b16f42 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -23,3 +23,8 @@ sourceSets { } } } + +dependencies { + // Biolith for BiomePerimeters in the VolcanoStructure + modImplementation "com.terraformersmc:biolith-fabric:${biolith_version}" +} diff --git a/common/src/main/java/com/terraformersmc/terrestria/feature/structure/volcano/VolcanoStructure.java b/common/src/main/java/com/terraformersmc/terrestria/feature/structure/volcano/VolcanoStructure.java index b541cca5..48e2121a 100644 --- a/common/src/main/java/com/terraformersmc/terrestria/feature/structure/volcano/VolcanoStructure.java +++ b/common/src/main/java/com/terraformersmc/terrestria/feature/structure/volcano/VolcanoStructure.java @@ -3,15 +3,21 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import com.terraformersmc.biolith.api.biomeperimeters.BiomePerimeters; import com.terraformersmc.terrestria.Terrestria; import com.terraformersmc.terrestria.init.TerrestriaBiomes; import com.terraformersmc.terrestria.init.TerrestriaStructures; +import net.minecraft.registry.RegistryKeys; import net.minecraft.registry.entry.RegistryEntry; import net.minecraft.structure.*; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.intprovider.IntProvider; import net.minecraft.world.Heightmap; import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.source.BiomeAccess; import net.minecraft.world.biome.source.BiomeCoords; +import net.minecraft.world.biome.source.BiomeSource; +import net.minecraft.world.biome.source.util.MultiNoiseUtil; import net.minecraft.world.gen.structure.Structure; import net.minecraft.world.gen.structure.StructureType; @@ -41,11 +47,26 @@ public Optional getStructurePosition(Structure.Context contex int x = context.chunkPos().getCenterX(); int z = context.chunkPos().getCenterZ(); int y = context.chunkGenerator().getHeightInGround(x, z, Heightmap.Type.OCEAN_FLOOR_WG, context.world(), context.noiseConfig()); + int seaLevel = context.chunkGenerator().getSeaLevel(); RegistryEntry biome = context.chunkGenerator().getBiomeSource().getBiome(BiomeCoords.fromBlock(x), BiomeCoords.fromBlock(y), BiomeCoords.fromBlock(z), context.noiseConfig().getMultiNoiseSampler()); - if (!biome.matchesKey(TerrestriaBiomes.VOLCANIC_ISLAND) && - !Terrestria.getConfigManager().getGeneralConfig().areOceanVolcanoesEnabled()) { + if (biome.matchesKey(TerrestriaBiomes.VOLCANIC_ISLAND)) { + // Shore volcanoes at the edges and regular volcanoes in the center. + int distance = BiomePerimeters.getOrCreateInstance( + context.dynamicRegistryManager().get(RegistryKeys.BIOME).getOrThrow(TerrestriaBiomes.VOLCANIC_ISLAND), 40) + .getPerimeterDistance(new BiomeAccess( + new BiomeAccessStorage(context.biomeSource(), context.noiseConfig().getMultiNoiseSampler()), + context.seed()), new BlockPos(x, seaLevel, z)); + + if (this.baseY < seaLevel - 10 && distance >= 20) { + return Optional.empty(); + } + if (this.baseY >= seaLevel - 10 && distance < 20) { + return Optional.empty(); + } + } else if (!Terrestria.getConfigManager().getGeneralConfig().areOceanVolcanoesEnabled()) { + // No need to consider starting a structure outside Volcanic Island unless sea volcanoes are enabled. return Optional.empty(); } @@ -60,4 +81,12 @@ private void addPieces(StructurePiecesCollector collector, Structure.Context con public StructureType getType() { return TerrestriaStructures.VOLCANO_STRUCTURE_TYPE; } + + // Shim class to instantiate a BiomeAccess.Storage from available information. + private record BiomeAccessStorage(BiomeSource biomeSource, MultiNoiseUtil.MultiNoiseSampler noiseSampler) implements BiomeAccess.Storage { + @Override + public RegistryEntry getBiomeForNoiseGen(int biomeX, int biomeY, int biomeZ) { + return biomeSource.getBiome(biomeX, biomeY, biomeZ, noiseSampler); + } + } } diff --git a/worldgen/src/main/java/com/terraformersmc/terrestria/TerrestriaWorldgen.java b/worldgen/src/main/java/com/terraformersmc/terrestria/TerrestriaWorldgen.java index d4dacbf1..84b27553 100644 --- a/worldgen/src/main/java/com/terraformersmc/terrestria/TerrestriaWorldgen.java +++ b/worldgen/src/main/java/com/terraformersmc/terrestria/TerrestriaWorldgen.java @@ -3,9 +3,13 @@ import com.terraformersmc.terrestria.biomegen.TerrestriaBiolithGeneration; import com.terraformersmc.terrestria.surfacebuilders.TerrestriaSurfaceBuilders; import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.server.world.ServerWorld; +import org.jetbrains.annotations.Nullable; public class TerrestriaWorldgen implements ModInitializer { + private static ServerWorld OVERWORLD = null; @Override public void onInitialize() { @@ -17,5 +21,17 @@ public void onInitialize() { } else { Terrestria.LOGGER.warn("Terrestria world generation disabled; Biolith is not present."); } + + // We need access to the Overworld for some surface builders. + ServerLifecycleEvents.SERVER_STARTED.register(server -> { + OVERWORLD = server.getOverworld(); + }); + ServerLifecycleEvents.SERVER_STOPPED.register(server -> { + OVERWORLD = null; + }); + } + + public static @Nullable ServerWorld getOverworld() { + return OVERWORLD; } } diff --git a/worldgen/src/main/java/com/terraformersmc/terrestria/surfacebuilders/CanyonSurfaceBuilder.java b/worldgen/src/main/java/com/terraformersmc/terrestria/surfacebuilders/CanyonSurfaceBuilder.java index 744daee0..fae3c6d8 100644 --- a/worldgen/src/main/java/com/terraformersmc/terrestria/surfacebuilders/CanyonSurfaceBuilder.java +++ b/worldgen/src/main/java/com/terraformersmc/terrestria/surfacebuilders/CanyonSurfaceBuilder.java @@ -11,7 +11,6 @@ import net.minecraft.world.gen.chunk.BlockColumn; public class CanyonSurfaceBuilder extends BiolithSurfaceBuilder { - private static final OpenSimplexNoise CLIFF_NOISE = new OpenSimplexNoise(346987); private final BlockState cliffMaterial; diff --git a/worldgen/src/main/java/com/terraformersmc/terrestria/surfacebuilders/DuneSurfaceBuilder.java b/worldgen/src/main/java/com/terraformersmc/terrestria/surfacebuilders/DuneSurfaceBuilder.java index 88db847c..ed33819c 100644 --- a/worldgen/src/main/java/com/terraformersmc/terrestria/surfacebuilders/DuneSurfaceBuilder.java +++ b/worldgen/src/main/java/com/terraformersmc/terrestria/surfacebuilders/DuneSurfaceBuilder.java @@ -13,7 +13,6 @@ import net.minecraft.world.gen.chunk.BlockColumn; public class DuneSurfaceBuilder extends BiolithSurfaceBuilder { - private static final OpenSimplexNoise NOISE = new OpenSimplexNoise(3445); private final BlockState topMaterial; diff --git a/worldgen/src/main/java/com/terraformersmc/terrestria/surfacebuilders/OceanIslandSurfaceBuilder.java b/worldgen/src/main/java/com/terraformersmc/terrestria/surfacebuilders/OceanIslandSurfaceBuilder.java index cace6346..2f081ff7 100644 --- a/worldgen/src/main/java/com/terraformersmc/terrestria/surfacebuilders/OceanIslandSurfaceBuilder.java +++ b/worldgen/src/main/java/com/terraformersmc/terrestria/surfacebuilders/OceanIslandSurfaceBuilder.java @@ -3,58 +3,68 @@ import com.terraformersmc.biolith.api.biomeperimeters.BiomePerimeters; import com.terraformersmc.biolith.api.surface.BiolithSurfaceBuilder; import com.terraformersmc.terraform.noise.OpenSimplexNoise; +import com.terraformersmc.terrestria.TerrestriaWorldgen; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; +import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.noise.DoublePerlinNoiseSampler; import net.minecraft.util.math.random.Random; import net.minecraft.world.Heightmap; import net.minecraft.world.biome.Biome; import net.minecraft.world.biome.source.BiomeAccess; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.gen.chunk.BlockColumn; +import net.minecraft.world.gen.noise.NoiseParametersKeys; public class OceanIslandSurfaceBuilder extends BiolithSurfaceBuilder { private static final OpenSimplexNoise ISLAND_NOISE = new OpenSimplexNoise(346987); - private static final int DEEP_DEPTH = 32; - private static final int SHALLOW_DEPTH = 16; - private static final double HEIGHT_FACTOR = 1.1; + private static final int ISLAND_HEIGHT = 12; + private static final double NOISE_SCALE = 9.5d; private final BlockState topMaterial; private final BlockState midMaterial; private final BlockState lowMaterial; private final BlockState beachMaterial; private final BlockState underwaterMaterial; - private final boolean deepOcean; - public OceanIslandSurfaceBuilder(BlockState topMaterial, BlockState midMaterial, BlockState lowMaterial, BlockState beachMaterial, BlockState underwaterMaterial, boolean deepOcean) { + public OceanIslandSurfaceBuilder(BlockState topMaterial, BlockState midMaterial, BlockState lowMaterial, BlockState beachMaterial, BlockState underwaterMaterial) { this.topMaterial = topMaterial; this.midMaterial = midMaterial; this.lowMaterial = lowMaterial; this.beachMaterial = beachMaterial; this.underwaterMaterial = underwaterMaterial; - this.deepOcean = deepOcean; } @Override public void generate(BiomeAccess biomeAccess, BlockColumn column, Random rand, Chunk chunk, Biome biome, int x, int z, int vHeight, int seaLevel) { - int delta = (int)((deepOcean ? DEEP_DEPTH : SHALLOW_DEPTH) * HEIGHT_FACTOR); + ServerWorld overworld = TerrestriaWorldgen.getOverworld(); + if (overworld == null) { + throw new IllegalStateException("Overworld does not exist during Overworld surface generation..."); + } + DoublePerlinNoiseSampler surface = overworld.getChunkManager().chunkLoadingManager.noiseConfig + .getOrCreateSampler(NoiseParametersKeys.SURFACE); - // We are going to accept the ocean surface noise and just raise it so we need the ocean surface. + // Find the original top Y value, the desired top Y value, and the delta between them. + // We can't trust the provided vHeight because we need the ocean floor instead of surface. vHeight = chunk.sampleHeightmap(Heightmap.Type.OCEAN_FLOOR_WG, x & 0xf, z & 0xf); + int top = seaLevel + ISLAND_HEIGHT + (int) (NOISE_SCALE * surface.sample(x, seaLevel, z)); + int delta = MathHelper.clamp(top - vHeight, 0, 128); // Work around noise-adapting structures (like villages)... - if (vHeight >= 60) { + if (vHeight >= seaLevel - 2) { vHeight = seaLevel - delta; } // Delta is how much we are raising the surface. Reduce it as we approach the edge of the island biome. int borderAdjustment = BiomePerimeters.getOrCreateInstance(biome, 40) - .getPerimeterDistance(biomeAccess, new BlockPos(x, 62, z)); + .getPerimeterDistance(biomeAccess, new BlockPos(x, seaLevel, z)); if (borderAdjustment < 32) { delta = delta * borderAdjustment / 32; } - int top = vHeight + delta; + top = vHeight + delta; for (int y = 0; y <= top; y++) { BlockState originalState = column.getState(y); if (originalState.isOf(Blocks.STONE) || originalState.isOf(Blocks.WATER) || originalState.isAir()) { diff --git a/worldgen/src/main/java/com/terraformersmc/terrestria/surfacebuilders/TerrestriaSurfaceBuilders.java b/worldgen/src/main/java/com/terraformersmc/terrestria/surfacebuilders/TerrestriaSurfaceBuilders.java index e57f959a..c7a89d40 100644 --- a/worldgen/src/main/java/com/terraformersmc/terrestria/surfacebuilders/TerrestriaSurfaceBuilders.java +++ b/worldgen/src/main/java/com/terraformersmc/terrestria/surfacebuilders/TerrestriaSurfaceBuilders.java @@ -37,8 +37,7 @@ public static void init() { TerrestriaBlocks.ANDISOL.getDirt().getDefaultState(), TerrestriaBlocks.VOLCANIC_ROCK.plain.full.getDefaultState(), TerrestriaBlocks.BLACK_SAND.getDefaultState(), - Blocks.SAND.getDefaultState(), - true + Blocks.SAND.getDefaultState() ).setBiomeKey(TerrestriaBiomes.VOLCANIC_ISLAND)); } diff --git a/worldgen/src/main/resources/terrestria-worldgen.accesswidener b/worldgen/src/main/resources/terrestria-worldgen.accesswidener index d77451ed..0df9713c 100644 --- a/worldgen/src/main/resources/terrestria-worldgen.accesswidener +++ b/worldgen/src/main/resources/terrestria-worldgen.accesswidener @@ -1,2 +1,3 @@ accessWidener v1 named +accessible field net/minecraft/server/world/ServerChunkLoadingManager noiseConfig Lnet/minecraft/world/gen/noise/NoiseConfig;