From d58eb699f1fb96867f14cf8454c535cde633b0fd Mon Sep 17 00:00:00 2001 From: dfsek Date: Sat, 11 Jun 2022 21:39:15 -0700 Subject: [PATCH] create ChunkLocalCachingBiomeProvider --- .../world/biome/generation/BiomeProvider.java | 4 +- .../generation/CachingBiomeProvider.java | 6 +- .../ChunkLocalCachingBiomeProvider.java | 75 +++++++++++++++++++ 3 files changed, 80 insertions(+), 5 deletions(-) create mode 100644 common/api/src/main/java/com/dfsek/terra/api/world/biome/generation/ChunkLocalCachingBiomeProvider.java 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 37483b564..49726c835 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 @@ -92,11 +92,11 @@ public interface BiomeProvider { return StreamSupport.stream(getBiomes().spliterator(), false); } - default BiomeProvider caching(int minY, int maxY) { + default CachingBiomeProvider caching(int minY, int maxY) { return new CachingBiomeProvider(this, minY, maxY); } - default BiomeProvider caching(WorldProperties worldProperties) { + default CachingBiomeProvider 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 08877f968..bf954f2cd 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 @@ -18,9 +18,9 @@ import java.util.Optional; * This is for use in chunk generators, it makes the assumption that the seed remains the same for the duration of its use! */ public class CachingBiomeProvider implements BiomeProvider, Handle { - private final BiomeProvider delegate; - private final int minY; - private final int maxY; + protected final BiomeProvider delegate; + protected final int minY; + protected final int maxY; private final Map cache = new HashMap<>(); private final Map> columnCache = new HashMap<>(); diff --git a/common/api/src/main/java/com/dfsek/terra/api/world/biome/generation/ChunkLocalCachingBiomeProvider.java b/common/api/src/main/java/com/dfsek/terra/api/world/biome/generation/ChunkLocalCachingBiomeProvider.java new file mode 100644 index 000000000..deb74d97b --- /dev/null +++ b/common/api/src/main/java/com/dfsek/terra/api/world/biome/generation/ChunkLocalCachingBiomeProvider.java @@ -0,0 +1,75 @@ +package com.dfsek.terra.api.world.biome.generation; + +import com.dfsek.terra.api.util.Column; +import com.dfsek.terra.api.world.biome.Biome; +import com.dfsek.terra.api.world.info.WorldProperties; + +import net.jafama.FastMath; + +import java.util.Optional; + + +/** + * A biome provider implementation that lazily evaluates biomes, and caches them. + *

+ * This is for use in chunk generators, it makes the assumption that the seed remains the same for the duration of its use! + *

+ * The cache works the best when all biomes are within one chunk! This is because internally, there are two caches, one constant-size one + * for the chunk, and a slower dynamically-sized cache for out-of-chunk biomes. + */ +public class ChunkLocalCachingBiomeProvider extends CachingBiomeProvider { + private final Biome[][][] cache; + private final Column[][] columnCache = new Column<>[16][16]; + + private final int chunkX; + private final int chunkZ; + + protected ChunkLocalCachingBiomeProvider(BiomeProvider delegate, WorldProperties worldProperties, int chunkX, int chunkZ) { + super(delegate, worldProperties.getMinHeight(), worldProperties.getMaxHeight()); + this.cache = new Biome[16][maxY - minY][16]; + this.chunkX = chunkX; + this.chunkZ = chunkZ; + } + + @Override + public BiomeProvider getHandle() { + return delegate; + } + + @Override + public Biome getBiome(int x, int y, int z, long seed) { + if(FastMath.floorDiv(x, 16) == chunkX && FastMath.floorDiv(z, 16) == chunkZ) { + Biome biome = cache[x & 15][y - minY][z & 15]; + if(biome == null) { + biome = delegate.getBiome(x, y, z, seed); + cache[x & 15][y - minY][z & 15] = biome; + } + return biome; + } + + return super.getBiome(x, y, z, seed); + } + + @Override + public Optional getBaseBiome(int x, int z, long seed) { + return delegate.getBaseBiome(x, z, seed); + } + + @Override + public Column getColumn(int x, int z, long seed, int min, int max) { + if(FastMath.floorDiv(x, 16) == chunkX && FastMath.floorDiv(z, 16) == chunkZ) { + Column column = columnCache[x & 15][z & 15]; + if(column == null) { + column = delegate.getColumn(x, z, seed, min, max); + columnCache[x & 15][z & 15] = column; + } + return column; + } + return super.getColumn(x, z, seed, min, max); + } + + @Override + public Iterable getBiomes() { + return delegate.getBiomes(); + } +}