mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-02-16 10:30:42 +00:00
remove ChunkLocalCachingBiomeProvider
This commit is contained in:
@@ -92,17 +92,13 @@ public interface BiomeProvider {
|
||||
return StreamSupport.stream(getBiomes().spliterator(), false);
|
||||
}
|
||||
|
||||
default CachingBiomeProvider caching(int minY, int maxY) {
|
||||
return new CachingBiomeProvider(this, minY, maxY);
|
||||
}
|
||||
|
||||
default CachingBiomeProvider caching(WorldProperties worldProperties) {
|
||||
return caching(worldProperties.getMinHeight(), worldProperties.getMaxHeight());
|
||||
}
|
||||
|
||||
default ChunkLocalCachingBiomeProvider caching(WorldProperties worldProperties, int chunkX, int chunkZ) {
|
||||
return new ChunkLocalCachingBiomeProvider(this, worldProperties, chunkX, chunkZ);
|
||||
default CachingBiomeProvider caching() {
|
||||
if(this instanceof CachingBiomeProvider cachingBiomeProvider) {
|
||||
return cachingBiomeProvider;
|
||||
}
|
||||
return new CachingBiomeProvider(this);
|
||||
}
|
||||
|
||||
|
||||
default int resolution() {
|
||||
return 1;
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
package com.dfsek.terra.api.world.biome.generation;
|
||||
|
||||
import com.dfsek.terra.api.Handle;
|
||||
import com.dfsek.terra.api.util.Column;
|
||||
import com.dfsek.terra.api.util.MathUtil;
|
||||
import com.dfsek.terra.api.util.vector.Vector3;
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
import com.dfsek.terra.api.world.info.WorldProperties;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
|
||||
@@ -19,15 +16,23 @@ import java.util.Optional;
|
||||
*/
|
||||
public class CachingBiomeProvider implements BiomeProvider, Handle {
|
||||
protected final BiomeProvider delegate;
|
||||
protected final int minY;
|
||||
protected final int maxY;
|
||||
private final Map<Long, Biome[]> cache = new HashMap<>();
|
||||
private final Map<Long, Column<Biome>> columnCache = new HashMap<>();
|
||||
private final int res;
|
||||
private final LoadingCache<SeededVector3, Biome> cache;
|
||||
private final LoadingCache<SeededVector2, Optional<Biome>> baseCache;
|
||||
|
||||
protected CachingBiomeProvider(BiomeProvider delegate, int minY, int maxY) {
|
||||
protected CachingBiomeProvider(BiomeProvider delegate) {
|
||||
this.delegate = delegate;
|
||||
this.minY = minY;
|
||||
this.maxY = maxY;
|
||||
this.res = delegate.resolution();
|
||||
this.cache = Caffeine
|
||||
.newBuilder()
|
||||
.maximumSize(98304) // 1 full chunk (high res)
|
||||
.build(vec -> delegate.getBiome(vec.x * res, vec.y * res, vec.z * res, vec.seed));
|
||||
|
||||
this.baseCache = Caffeine
|
||||
.newBuilder()
|
||||
.maximumSize(256) // 1 full chunk (high res)
|
||||
.build(vec -> delegate.getBaseBiome(vec.x * res, vec.z * res, vec.seed));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -37,23 +42,12 @@ public class CachingBiomeProvider implements BiomeProvider, Handle {
|
||||
|
||||
@Override
|
||||
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];
|
||||
return cache.get(new SeededVector3(x / res, y / res, z / res, seed));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Biome> getBaseBiome(int x, int z, long seed) {
|
||||
return delegate.getBaseBiome(x, z, seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Column<Biome> getColumn(int x, int z, long seed, int min, int max) {
|
||||
return columnCache.computeIfAbsent(MathUtil.squash(x, z), k -> new BiomeColumn(this, min, max, x, z, seed));
|
||||
return baseCache.get(new SeededVector2(x / res, z / res, seed));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -65,4 +59,38 @@ public class CachingBiomeProvider implements BiomeProvider, Handle {
|
||||
public int resolution() {
|
||||
return delegate.resolution();
|
||||
}
|
||||
|
||||
private record SeededVector3(int x, int y, int z, long seed) {
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if(obj instanceof SeededVector3 that) {
|
||||
return this.y == that.y && this.z == that.z && this.x == that.x && this.seed == that.seed;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int code = x;
|
||||
code = 31 * code + y;
|
||||
code = 31 * code + z;
|
||||
return 31 * code + ((int) (seed ^ (seed >>> 32)));
|
||||
}
|
||||
}
|
||||
private record SeededVector2(int x, int z, long seed) {
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if(obj instanceof SeededVector2 that) {
|
||||
return this.z == that.z && this.x == that.x && this.seed == that.seed;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int code = x;
|
||||
code = 31 * code + z;
|
||||
return 31 * code + ((int) (seed ^ (seed >>> 32)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
package com.dfsek.terra.api.world.biome.generation;
|
||||
|
||||
import net.jafama.FastMath;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.dfsek.terra.api.util.Column;
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
import com.dfsek.terra.api.world.info.WorldProperties;
|
||||
|
||||
|
||||
/**
|
||||
* A biome provider implementation that lazily evaluates biomes, and caches them.
|
||||
* <p>
|
||||
* This is for use in chunk generators, it makes the assumption that <b>the seed remains the same for the duration of its use!</b>
|
||||
* <p>
|
||||
* 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 BiomeChunk[] chunks = new BiomeChunk[9];
|
||||
private final Column<Biome>[] columnCache; // x + z * 16
|
||||
|
||||
private final int chunkX;
|
||||
private final int chunkZ;
|
||||
private final int height;
|
||||
|
||||
private final int zMul;
|
||||
private final int yMul;
|
||||
private final int resolution;
|
||||
|
||||
protected ChunkLocalCachingBiomeProvider(BiomeProvider delegate, WorldProperties worldProperties, int chunkX, int chunkZ) {
|
||||
super(delegate, worldProperties.getMinHeight(), worldProperties.getMaxHeight());
|
||||
this.height = maxY - minY;
|
||||
this.chunkX = chunkX;
|
||||
this.chunkZ = chunkZ;
|
||||
this.resolution = delegate.resolution();
|
||||
this.zMul = 16 / resolution;
|
||||
this.yMul = zMul * zMul;
|
||||
this.columnCache = new Column[yMul];
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeProvider getHandle() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Biome getBiome(int x, int y, int z, long seed) {
|
||||
int localChunkX = FastMath.floorDiv(x, 16) - this.chunkX + 1;
|
||||
int localChunkZ = FastMath.floorDiv(z, 16) - this.chunkZ + 1;
|
||||
|
||||
|
||||
if(localChunkX >= 0 && localChunkZ >= 0 && localChunkX <= 2 && localChunkZ <= 2) {
|
||||
int chunkIndex = localChunkX + localChunkZ * 3;
|
||||
|
||||
BiomeChunk chunk = chunks[chunkIndex];
|
||||
if(chunk == null) {
|
||||
chunk = new BiomeChunk(height / resolution, yMul);
|
||||
chunks[chunkIndex] = chunk;
|
||||
}
|
||||
|
||||
int scaledX = FastMath.floorDiv(x & 15, resolution);
|
||||
int scaledY = FastMath.floorDiv(y - minY, resolution);
|
||||
int scaledZ = FastMath.floorDiv(z & 15, resolution);
|
||||
|
||||
int biomeIndex = scaledX + zMul * scaledZ + yMul * scaledY;
|
||||
Biome biome = chunk.cache[biomeIndex];
|
||||
if(biome == null) {
|
||||
biome = delegate.getBiome(x, y, z, seed);
|
||||
chunk.cache[biomeIndex] = biome;
|
||||
}
|
||||
return biome;
|
||||
}
|
||||
|
||||
return super.getBiome(x, y, z, seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Biome> getBaseBiome(int x, int z, long seed) {
|
||||
return delegate.getBaseBiome(x, z, seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Column<Biome> getColumn(int x, int z, long seed, int min, int max) {
|
||||
int scaledX = (x & 15) / resolution;
|
||||
int scaledZ = (z & 15) / resolution;
|
||||
|
||||
if(FastMath.floorDiv(x, 16) == chunkX && FastMath.floorDiv(z, 16) == chunkZ) {
|
||||
int index = scaledX + (zMul * scaledZ);
|
||||
Column<Biome> column = columnCache[index];
|
||||
if(column == null) {
|
||||
column = new BiomeColumn(this, min, max, x, z, seed);
|
||||
columnCache[index] = column;
|
||||
}
|
||||
return column;
|
||||
}
|
||||
return super.getColumn(x, z, seed, min, max);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Biome> getBiomes() {
|
||||
return delegate.getBiomes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int resolution() {
|
||||
return resolution;
|
||||
}
|
||||
|
||||
private static class BiomeChunk {
|
||||
final Biome[] cache; // x + z * 16 + y * 256
|
||||
|
||||
private BiomeChunk(int height, int widthSq) {
|
||||
this.cache = new Biome[widthSq * height];
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user