From b6b6cb185d520bd292f2f0ebc50355d534e0bf56 Mon Sep 17 00:00:00 2001 From: dfsek Date: Fri, 27 May 2022 14:40:50 -0700 Subject: [PATCH] implement API for 3d biomes --- .../biome/image/ImageBiomeProvider.java | 2 +- .../biome/pipeline/BiomePipelineProvider.java | 2 +- .../biome/single/SingleBiomeProvider.java | 2 +- .../generation/NoiseChunkGenerator3D.java | 6 +-- .../math/interpolation/ChunkInterpolator.java | 4 +- .../interpolation/ElevationInterpolator.java | 2 +- .../LazilyEvaluatedInterpolator.java | 2 +- .../feature/FeatureGenerationStage.java | 2 +- .../world/biome/generation/BiomeProvider.java | 39 ++++++++++++++----- .../generation/CachingBiomeProvider.java | 24 ++++++++---- .../bukkit/generator/BukkitBiomeProvider.java | 2 +- .../BukkitChunkGeneratorWrapper.java | 4 +- .../com/dfsek/terra/cli/world/CLIWorld.java | 2 +- .../FabricChunkGeneratorWrapper.java | 14 ++++--- .../fabric/generation/TerraBiomeSource.java | 2 +- 15 files changed, 72 insertions(+), 37 deletions(-) diff --git a/common/addons/biome-provider-image/src/main/java/com/dfsek/terra/addons/biome/image/ImageBiomeProvider.java b/common/addons/biome-provider-image/src/main/java/com/dfsek/terra/addons/biome/image/ImageBiomeProvider.java index 13d20a1bd..3c3fa90f5 100644 --- a/common/addons/biome-provider-image/src/main/java/com/dfsek/terra/addons/biome/image/ImageBiomeProvider.java +++ b/common/addons/biome-provider-image/src/main/java/com/dfsek/terra/addons/biome/image/ImageBiomeProvider.java @@ -37,7 +37,7 @@ public class ImageBiomeProvider implements BiomeProvider { } @Override - public Biome getBiome(int x, int z, long seed) { + public Biome getBiome(int x, int y, int z, long seed) { x /= resolution; z /= resolution; Color color = align.getColor(image, x, z); diff --git a/common/addons/biome-provider-pipeline/src/main/java/com/dfsek/terra/addons/biome/pipeline/BiomePipelineProvider.java b/common/addons/biome-provider-pipeline/src/main/java/com/dfsek/terra/addons/biome/pipeline/BiomePipelineProvider.java index 22c2c4c30..9feffbb34 100644 --- a/common/addons/biome-provider-pipeline/src/main/java/com/dfsek/terra/addons/biome/pipeline/BiomePipelineProvider.java +++ b/common/addons/biome-provider-pipeline/src/main/java/com/dfsek/terra/addons/biome/pipeline/BiomePipelineProvider.java @@ -81,7 +81,7 @@ public class BiomePipelineProvider implements BiomeProvider { } @Override - public Biome getBiome(int x, int z, long seed) { + public Biome getBiome(int x, int y, int z, long seed) { x += mutator.noise(seed + 1, x, z) * noiseAmp; z += mutator.noise(seed + 2, x, z) * noiseAmp; diff --git a/common/addons/biome-provider-single/src/main/java/com/dfsek/terra/addons/biome/single/SingleBiomeProvider.java b/common/addons/biome-provider-single/src/main/java/com/dfsek/terra/addons/biome/single/SingleBiomeProvider.java index a67007248..0ca97bfbc 100644 --- a/common/addons/biome-provider-single/src/main/java/com/dfsek/terra/addons/biome/single/SingleBiomeProvider.java +++ b/common/addons/biome-provider-single/src/main/java/com/dfsek/terra/addons/biome/single/SingleBiomeProvider.java @@ -21,7 +21,7 @@ public class SingleBiomeProvider implements BiomeProvider { } @Override - public Biome getBiome(int x, int z, long seed) { + public Biome getBiome(int x, int y, int z, long seed) { return biome; } diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/NoiseChunkGenerator3D.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/NoiseChunkGenerator3D.java index 514ccd36a..300cdbfcc 100644 --- a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/NoiseChunkGenerator3D.java +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/NoiseChunkGenerator3D.java @@ -73,7 +73,7 @@ public class NoiseChunkGenerator3D implements ChunkGenerator { int cx = xOrig + x; int cz = zOrig + z; - Biome biome = biomeProvider.getBiome(cx, cz, seed); + Biome biome = biomeProvider.getBiome(cx, 0, cz, seed); PaletteInfo paletteInfo = biome.getContext().get(PaletteInfo.class); @@ -104,7 +104,7 @@ public class NoiseChunkGenerator3D implements ChunkGenerator { @Override public BlockState getBlock(WorldProperties world, int x, int y, int z, BiomeProvider biomeProvider) { - Biome biome = biomeProvider.getBiome(x, z, world.getSeed()); + Biome biome = biomeProvider.getBiome(x, y, z, world.getSeed()); Sampler3D sampler = samplerCache.get(x, z, world, biomeProvider); PaletteInfo paletteInfo = biome.getContext().get(PaletteInfo.class); @@ -128,7 +128,7 @@ public class NoiseChunkGenerator3D implements ChunkGenerator { @Override public Palette getPalette(int x, int y, int z, WorldProperties world, BiomeProvider biomeProvider) { - return biomeProvider.getBiome(x, z, world.getSeed()).getContext().get(PaletteInfo.class).paletteHolder().getPalette(y); + return biomeProvider.getBiome(x, y, z, world.getSeed()).getContext().get(PaletteInfo.class).paletteHolder().getPalette(y); } public SamplerProvider samplerProvider() { diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/ChunkInterpolator.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/ChunkInterpolator.java index 66be151ba..9f8cb782f 100644 --- a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/ChunkInterpolator.java +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/ChunkInterpolator.java @@ -55,7 +55,7 @@ public class ChunkInterpolator { for(int x = 0; x < 5; x++) { for(int z = 0; z < 5; z++) { - BiomeNoiseProperties generationSettings = provider.getBiome(xOrigin + (x << 2), zOrigin + (z << 2), seed) + BiomeNoiseProperties generationSettings = provider.getBiome(xOrigin + (x << 2), 0, zOrigin + (z << 2), seed) .getContext() .get(BiomeNoiseProperties.class); Map genMap = new HashMap<>(); @@ -66,7 +66,7 @@ public class ChunkInterpolator { for(int xi = -blend; xi <= blend; xi++) { for(int zi = -blend; zi <= blend; zi++) { genMap.computeIfAbsent( - provider.getBiome(xOrigin + (x << 2) + (xi * step), zOrigin + (z << 2) + (zi * step), seed) + provider.getBiome(xOrigin + (x << 2) + (xi * step), 0, zOrigin + (z << 2) + (zi * step), seed) .getContext() .get(BiomeNoiseProperties.class), g -> new MutableInteger(0)).increment(); // Increment by 1 diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/ElevationInterpolator.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/ElevationInterpolator.java index 36ceb6810..0342ca751 100644 --- a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/ElevationInterpolator.java +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/ElevationInterpolator.java @@ -23,7 +23,7 @@ public class ElevationInterpolator { // Precompute generators. for(int x = -1 - smooth; x <= 16 + smooth; x++) { for(int z = -1 - smooth; z <= 16 + smooth; z++) { - gens[x + 1 + smooth][z + 1 + smooth] = provider.getBiome(xOrigin + x, zOrigin + z, seed).getContext().get( + gens[x + 1 + smooth][z + 1 + smooth] = provider.getBiome(xOrigin + x, 0, zOrigin + z, seed).getContext().get( BiomeNoiseProperties.class); } } diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/LazilyEvaluatedInterpolator.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/LazilyEvaluatedInterpolator.java index 800bea5c3..34c20ad97 100644 --- a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/LazilyEvaluatedInterpolator.java +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/interpolation/LazilyEvaluatedInterpolator.java @@ -48,7 +48,7 @@ public class LazilyEvaluatedInterpolator { NoiseSampler sampler = samplers[x][z]; if(sampler == null) { - sampler = biomeProvider.getBiome(xi, zi, seed).getContext().get(BiomeNoiseProperties.class).carving(); + sampler = biomeProvider.getBiome(xi, y, zi, seed).getContext().get(BiomeNoiseProperties.class).carving(); samplers[x][z] = sampler; } diff --git a/common/addons/generation-stage-feature/src/main/java/com/dfsek/terra/addons/generation/feature/FeatureGenerationStage.java b/common/addons/generation-stage-feature/src/main/java/com/dfsek/terra/addons/generation/feature/FeatureGenerationStage.java index ccbd7f97b..c60ecc6aa 100644 --- a/common/addons/generation-stage-feature/src/main/java/com/dfsek/terra/addons/generation/feature/FeatureGenerationStage.java +++ b/common/addons/generation-stage-feature/src/main/java/com/dfsek/terra/addons/generation/feature/FeatureGenerationStage.java @@ -49,7 +49,7 @@ public class FeatureGenerationStage implements GenerationStage, StringIdentifiab long coordinateSeed = (seed * 31 + tx) * 31 + tz; world.getBiomeProvider() - .getBiome(tx, tz, seed) + .getBiome(tx, 0, tz, seed) .getContext() .get(BiomeFeatures.class) .getFeatures() diff --git a/common/api/src/main/java/com/dfsek/terra/api/world/biome/generation/BiomeProvider.java b/common/api/src/main/java/com/dfsek/terra/api/world/biome/generation/BiomeProvider.java index e2597ddf5..282541720 100644 --- a/common/api/src/main/java/com/dfsek/terra/api/world/biome/generation/BiomeProvider.java +++ b/common/api/src/main/java/com/dfsek/terra/api/world/biome/generation/BiomeProvider.java @@ -7,10 +7,17 @@ package com.dfsek.terra.api.world.biome.generation; -import com.dfsek.terra.api.util.vector.Vector2; import com.dfsek.terra.api.util.vector.Vector3; +import com.dfsek.terra.api.util.vector.Vector3Int; import com.dfsek.terra.api.world.biome.Biome; +import com.dfsek.terra.api.world.info.WorldProperties; + +import org.jetbrains.annotations.Contract; + +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + /** * Provides locations of biomes in a world. @@ -20,23 +27,26 @@ public interface BiomeProvider { * Get the biome at a location. * * @param x X coordinate + * @param y * @param z Z coordinate * @param seed World seed * * @return Biome at the location */ - Biome getBiome(int x, int z, long seed); + @Contract(pure = true) + Biome getBiome(int x, int y, int z, long seed); /** * Get the biome at a location. * - * @param vector2 Location + * @param vector3 Location * @param seed World seed * * @return Biome at the location */ - default Biome getBiome(Vector2 vector2, long seed) { - return getBiome(vector2.getBlockX(), vector2.getBlockZ(), seed); + @Contract(pure = true) + default Biome getBiome(Vector3 vector3, long seed) { + return getBiome(vector3.getBlockX(), vector3.getBlockY(), vector3.getBlockZ(), seed); } /** @@ -47,8 +57,9 @@ public interface BiomeProvider { * * @return Biome at the location */ - default Biome getBiome(Vector3 vector3, long seed) { - return getBiome(vector3.getBlockX(), vector3.getBlockZ(), seed); + @Contract(pure = true) + default Biome getBiome(Vector3Int vector3, long seed) { + return getBiome(vector3.getX(), vector3.getY(), vector3.getZ(), seed); } /** @@ -58,9 +69,19 @@ public interface BiomeProvider { * * @return {@link Iterable} of all biomes this provider can generate. */ + @Contract(pure = true) Iterable getBiomes(); - default BiomeProvider caching() { - return new CachingBiomeProvider(this); + @Contract(pure = true) + default Stream stream() { + return StreamSupport.stream(getBiomes().spliterator(), false); + } + + default BiomeProvider caching(int minY, int maxY) { + return new CachingBiomeProvider(this, minY, maxY); + } + + default BiomeProvider caching(WorldProperties worldProperties) { + return caching(worldProperties.getMinHeight(), worldProperties.getMaxHeight()); } } diff --git a/common/api/src/main/java/com/dfsek/terra/api/world/biome/generation/CachingBiomeProvider.java b/common/api/src/main/java/com/dfsek/terra/api/world/biome/generation/CachingBiomeProvider.java index 7fc01b8e1..ee2b41dbc 100644 --- a/common/api/src/main/java/com/dfsek/terra/api/world/biome/generation/CachingBiomeProvider.java +++ b/common/api/src/main/java/com/dfsek/terra/api/world/biome/generation/CachingBiomeProvider.java @@ -1,12 +1,12 @@ package com.dfsek.terra.api.world.biome.generation; -import java.util.HashMap; -import java.util.Map; - import com.dfsek.terra.api.Handle; import com.dfsek.terra.api.util.MathUtil; import com.dfsek.terra.api.world.biome.Biome; +import java.util.HashMap; +import java.util.Map; + /** * A biome provider implementation that lazily evaluates biomes, and caches them. @@ -15,10 +15,14 @@ import com.dfsek.terra.api.world.biome.Biome; */ public class CachingBiomeProvider implements BiomeProvider, Handle { private final BiomeProvider delegate; - private final Map cache = new HashMap<>(); + private final int minY; + private final int maxY; + private final Map cache = new HashMap<>(); - protected CachingBiomeProvider(BiomeProvider delegate) { + protected CachingBiomeProvider(BiomeProvider delegate, int minY, int maxY) { this.delegate = delegate; + this.minY = minY; + this.maxY = maxY; } @Override @@ -27,8 +31,14 @@ public class CachingBiomeProvider implements BiomeProvider, Handle { } @Override - public Biome getBiome(int x, int z, long seed) { - return cache.computeIfAbsent(MathUtil.squash(x, z), key -> delegate.getBiome(x, z, seed)); + public Biome getBiome(int x, int y, int z, long seed) { + if(y >= maxY || y < minY) throw new IllegalArgumentException("Y out of range: " + y + " (min: " + minY + ", max: " + maxY + ")"); + Biome[] biomes = cache.computeIfAbsent(MathUtil.squash(x, z), key -> new Biome[maxY - minY]); + int yi = y - minY; + if(biomes[yi] == null) { + biomes[yi] = delegate.getBiome(x, y, z, seed); + } + return biomes[yi]; } @Override diff --git a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/generator/BukkitBiomeProvider.java b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/generator/BukkitBiomeProvider.java index c1eed4fc8..dfff71ccc 100644 --- a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/generator/BukkitBiomeProvider.java +++ b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/generator/BukkitBiomeProvider.java @@ -19,7 +19,7 @@ public class BukkitBiomeProvider extends BiomeProvider implements Handle { @Override public @NotNull org.bukkit.block.Biome getBiome(@NotNull WorldInfo worldInfo, int x, int y, int z) { - Biome biome = delegate.getBiome(x, z, worldInfo.getSeed()); + Biome biome = delegate.getBiome(x, y, z, worldInfo.getSeed()); return (org.bukkit.block.Biome) biome.getPlatformBiome().getHandle(); } diff --git a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/generator/BukkitChunkGeneratorWrapper.java b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/generator/BukkitChunkGeneratorWrapper.java index e3015ec8f..990fb4925 100644 --- a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/generator/BukkitChunkGeneratorWrapper.java +++ b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/generator/BukkitChunkGeneratorWrapper.java @@ -59,8 +59,8 @@ public class BukkitChunkGeneratorWrapper extends org.bukkit.generator.ChunkGener @Override public void generateNoise(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull ChunkData chunkData) { - delegate.generateChunkData(new BukkitProtoChunk(chunkData), new BukkitWorldProperties(worldInfo), pack.getBiomeProvider().caching(), - x, z); + BukkitWorldProperties properties = new BukkitWorldProperties(worldInfo); + delegate.generateChunkData(new BukkitProtoChunk(chunkData), properties, pack.getBiomeProvider().caching(properties), x, z); } @Override diff --git a/platforms/cli/src/main/java/com/dfsek/terra/cli/world/CLIWorld.java b/platforms/cli/src/main/java/com/dfsek/terra/cli/world/CLIWorld.java index ba5d16c41..c385ff8eb 100644 --- a/platforms/cli/src/main/java/com/dfsek/terra/cli/world/CLIWorld.java +++ b/platforms/cli/src/main/java/com/dfsek/terra/cli/world/CLIWorld.java @@ -85,7 +85,7 @@ public class CLIWorld implements ServerWorld, NBTSerializable stage.populate(protoWorld)); if(num % 240 == 239) { diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/FabricChunkGeneratorWrapper.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/FabricChunkGeneratorWrapper.java index cf653ff53..b5f328239 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/FabricChunkGeneratorWrapper.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/FabricChunkGeneratorWrapper.java @@ -17,6 +17,8 @@ package com.dfsek.terra.fabric.generation; +import com.dfsek.terra.api.world.info.WorldProperties; + import com.mojang.serialization.Codec; import net.minecraft.block.BlockState; import net.minecraft.structure.StructureSet; @@ -128,7 +130,7 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C public CompletableFuture populateNoise(Executor executor, Blender arg, StructureAccessor structureAccessor, Chunk chunk) { return CompletableFuture.supplyAsync(() -> { ProtoWorld world = (ProtoWorld) ((StructureAccessorAccessor) structureAccessor).getWorld(); - BiomeProvider biomeProvider = pack.getBiomeProvider().caching(); + BiomeProvider biomeProvider = pack.getBiomeProvider().caching(world); delegate.generateChunkData((ProtoChunk) chunk, world, biomeProvider, chunk.getPos().x, chunk.getPos().z); PreLoadCompatibilityOptions compatibilityOptions = pack.getContext().get(PreLoadCompatibilityOptions.class); @@ -163,9 +165,10 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C @Override public int getHeight(int x, int z, Heightmap.Type heightmap, HeightLimitView height) { int y = height.getTopY(); - BiomeProvider biomeProvider = pack.getBiomeProvider().caching(); + WorldProperties properties = FabricAdapter.adapt(height, seed); + BiomeProvider biomeProvider = pack.getBiomeProvider().caching(properties); while(y >= getMinimumY() && !heightmap.getBlockPredicate().test( - (BlockState) delegate.getBlock(FabricAdapter.adapt(height, seed), x, y - 1, z, biomeProvider))) { + (BlockState) delegate.getBlock(properties, x, y - 1, z, biomeProvider))) { y--; } return y; @@ -174,9 +177,10 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C @Override public VerticalBlockSample getColumnSample(int x, int z, HeightLimitView height) { BlockState[] array = new BlockState[height.getHeight()]; - BiomeProvider biomeProvider = pack.getBiomeProvider().caching(); + WorldProperties properties = FabricAdapter.adapt(height, seed); + BiomeProvider biomeProvider = pack.getBiomeProvider().caching(properties); for(int y = height.getTopY() - 1; y >= height.getBottomY(); y--) { - array[y - height.getBottomY()] = (BlockState) delegate.getBlock(FabricAdapter.adapt(height, seed), x, y, z, biomeProvider); + array[y - height.getBottomY()] = (BlockState) delegate.getBlock(properties, x, y, z, biomeProvider); } return new VerticalBlockSample(height.getBottomY(), array); } diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/TerraBiomeSource.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/TerraBiomeSource.java index de3196cf4..49bfedd28 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/TerraBiomeSource.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/TerraBiomeSource.java @@ -67,7 +67,7 @@ public class TerraBiomeSource extends BiomeSource { public RegistryEntry getBiome(int biomeX, int biomeY, int biomeZ, MultiNoiseSampler noiseSampler) { return biomeRegistry.getOrCreateEntry(((ProtoPlatformBiome) pack .getBiomeProvider() - .getBiome(biomeX << 2, biomeZ << 2, seed) + .getBiome(biomeX << 2, biomeY << 2, biomeZ << 2, seed) .getPlatformBiome()) .getDelegate()); }