mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2025-07-02 16:05:29 +00:00
implement caching biome provider
This commit is contained in:
parent
74237e7568
commit
d36fc7dec1
@ -22,7 +22,6 @@ import com.dfsek.terra.api.Platform;
|
||||
import com.dfsek.terra.api.block.state.BlockState;
|
||||
import com.dfsek.terra.api.config.ConfigPack;
|
||||
import com.dfsek.terra.api.profiler.ProfileFrame;
|
||||
import com.dfsek.terra.api.world.WritableWorld;
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
|
||||
import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
|
||||
@ -48,24 +47,23 @@ public class NoiseChunkGenerator3D implements ChunkGenerator {
|
||||
this.air = platform.getWorldHandle().air();
|
||||
this.carverHorizontalResolution = carverHorizontalResolution;
|
||||
this.carverVerticalResolution = carverVerticalResolution;
|
||||
this.samplerCache = new SamplerProvider(platform, c.getBiomeProvider(), elevationBlend);
|
||||
this.samplerCache = new SamplerProvider(platform, elevationBlend);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("try")
|
||||
public void generateChunkData(@NotNull ProtoChunk chunk, @NotNull WorldProperties world,
|
||||
@NotNull BiomeProvider biomeProvider,
|
||||
int chunkX, int chunkZ) {
|
||||
try(ProfileFrame ignore = platform.getProfiler().profile("chunk_base_3d")) {
|
||||
BiomeProvider grid = configPack.getBiomeProvider();
|
||||
|
||||
int xOrig = (chunkX << 4);
|
||||
int zOrig = (chunkZ << 4);
|
||||
|
||||
Sampler3D sampler = samplerCache.getChunk(chunkX, chunkZ, world);
|
||||
Sampler3D sampler = samplerCache.getChunk(chunkX, chunkZ, world, biomeProvider);
|
||||
|
||||
long seed = world.getSeed();
|
||||
|
||||
LazilyEvaluatedInterpolator carver = new LazilyEvaluatedInterpolator(configPack.getBiomeProvider(),
|
||||
LazilyEvaluatedInterpolator carver = new LazilyEvaluatedInterpolator(biomeProvider,
|
||||
chunkX,
|
||||
chunkZ,
|
||||
world.getMaxHeight(),
|
||||
@ -80,7 +78,7 @@ public class NoiseChunkGenerator3D implements ChunkGenerator {
|
||||
int cx = xOrig + x;
|
||||
int cz = zOrig + z;
|
||||
|
||||
Biome biome = grid.getBiome(cx, cz, seed);
|
||||
Biome biome = biomeProvider.getBiome(cx, cz, seed);
|
||||
|
||||
PaletteInfo paletteInfo = biome.getContext().get(PaletteInfo.class);
|
||||
|
||||
@ -113,7 +111,7 @@ public class NoiseChunkGenerator3D implements ChunkGenerator {
|
||||
public BlockState getBlock(WorldProperties world, int x, int y, int z) {
|
||||
BiomeProvider provider = configPack.getBiomeProvider();
|
||||
Biome biome = provider.getBiome(x, z, world.getSeed());
|
||||
Sampler3D sampler = samplerCache.get(x, z, world);
|
||||
Sampler3D sampler = samplerCache.get(x, z, world, configPack.getBiomeProvider());
|
||||
|
||||
PaletteInfo paletteInfo = biome.getContext().get(PaletteInfo.class);
|
||||
|
||||
|
@ -56,12 +56,9 @@ public class ChunkInterpolator {
|
||||
|
||||
double[][][] noiseStorage = new double[5][5][size + 1];
|
||||
|
||||
BiomeCache cache = new BiomeCache(provider);
|
||||
|
||||
|
||||
for(int x = 0; x < 5; x++) {
|
||||
for(int z = 0; z < 5; z++) {
|
||||
BiomeNoiseProperties generationSettings = cache.get(xOrigin + (x << 2), zOrigin + (z << 2), seed)
|
||||
BiomeNoiseProperties generationSettings = provider.getBiome(xOrigin + (x << 2), zOrigin + (z << 2), seed)
|
||||
.getContext()
|
||||
.get(BiomeNoiseProperties.class);
|
||||
Map<BiomeNoiseProperties, MutableInteger> genMap = new HashMap<>();
|
||||
@ -72,7 +69,7 @@ public class ChunkInterpolator {
|
||||
for(int xi = -blend; xi <= blend; xi++) {
|
||||
for(int zi = -blend; zi <= blend; zi++) {
|
||||
genMap.computeIfAbsent(
|
||||
cache.get(xOrigin + (x << 2) + (xi * step), zOrigin + (z << 2) + (zi * step), seed)
|
||||
provider.getBiome(xOrigin + (x << 2) + (xi * step), zOrigin + (z << 2) + (zi * step), seed)
|
||||
.getContext()
|
||||
.get(BiomeNoiseProperties.class),
|
||||
g -> new MutableInteger(0)).increment(); // Increment by 1
|
||||
@ -102,20 +99,6 @@ public class ChunkInterpolator {
|
||||
}
|
||||
}
|
||||
|
||||
private static final class BiomeCache {
|
||||
|
||||
private final BiomeProvider provider;
|
||||
private final Map<Vector2Int, Biome> cache = new HashMap<>();
|
||||
|
||||
private BiomeCache(BiomeProvider provider) {
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
public Biome get(int x, int z, long seed) {
|
||||
return cache.computeIfAbsent(Vector2Int.of(x, z), vec -> provider.getBiome(x, z, seed));
|
||||
}
|
||||
}
|
||||
|
||||
private static int reRange(int value, int high) {
|
||||
return FastMath.max(FastMath.min(value, high), 0);
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ package com.dfsek.terra.addons.chunkgenerator.generation.math.samplers;
|
||||
|
||||
import com.dfsek.terra.api.world.info.WorldProperties;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
@ -31,30 +32,32 @@ import com.dfsek.terra.api.util.generic.pair.Pair;
|
||||
import com.dfsek.terra.api.world.World;
|
||||
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
|
||||
public class SamplerProvider {
|
||||
private final LoadingCache<WorldContext, Sampler3D> cache;
|
||||
private final Cache<WorldContext, Sampler3D> cache;
|
||||
private final int elevationSmooth;
|
||||
|
||||
|
||||
public SamplerProvider(Platform platform, BiomeProvider provider, int elevationSmooth) {
|
||||
cache = CacheBuilder.newBuilder().maximumSize(platform.getTerraConfig().getSamplerCache())
|
||||
.build(new CacheLoader<>() {
|
||||
@Override
|
||||
public Sampler3D load(@NotNull WorldContext context) {
|
||||
return new Sampler3D(context.cx, context.cz, context.seed, context.minHeight, context.maxHeight, provider,
|
||||
elevationSmooth);
|
||||
}
|
||||
});
|
||||
public SamplerProvider(Platform platform, int elevationSmooth) {
|
||||
this.elevationSmooth = elevationSmooth;
|
||||
cache = CacheBuilder.newBuilder().maximumSize(platform.getTerraConfig().getSamplerCache()).build();
|
||||
}
|
||||
|
||||
public Sampler3D get(int x, int z, WorldProperties world) {
|
||||
public Sampler3D get(int x, int z, WorldProperties world, BiomeProvider provider) {
|
||||
int cx = FastMath.floorDiv(x, 16);
|
||||
int cz = FastMath.floorDiv(z, 16);
|
||||
return getChunk(cx, cz, world);
|
||||
return getChunk(cx, cz, world, provider);
|
||||
}
|
||||
|
||||
public Sampler3D getChunk(int cx, int cz, WorldProperties world) {
|
||||
return cache.getUnchecked(new WorldContext(cx, cz, world.getSeed(), world.getMinHeight(), world.getMaxHeight()));
|
||||
public Sampler3D getChunk(int cx, int cz, WorldProperties world, BiomeProvider provider) {
|
||||
WorldContext context = new WorldContext(cx, cz, world.getSeed(), world.getMinHeight(), world.getMaxHeight());
|
||||
try {
|
||||
return cache.get(context, () -> new Sampler3D(context.cx, context.cz, context.seed, context.minHeight, context.maxHeight, provider,
|
||||
elevationSmooth));
|
||||
} catch(ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private record WorldContext(int cx, int cz, long seed, int minHeight, int maxHeight) {
|
||||
|
@ -86,6 +86,6 @@ public class CheckFunction implements Function<String> {
|
||||
private double sample(double x, double y, double z, SamplerProvider cache, World world) {
|
||||
int cx = FastMath.floorDiv((int) x, 16);
|
||||
int cz = FastMath.floorDiv((int) z, 16);
|
||||
return cache.getChunk(cx, cz, world).sample(x - (cx << 4), y, z - (cz << 4));
|
||||
return cache.getChunk(cx, cz, world, world.getBiomeProvider()).sample(x - (cx << 4), y, z - (cz << 4));
|
||||
}
|
||||
}
|
||||
|
@ -59,4 +59,8 @@ public interface BiomeProvider {
|
||||
* @return {@link Iterable} of all biomes this provider can generate.
|
||||
*/
|
||||
Iterable<Biome> getBiomes();
|
||||
|
||||
default BiomeProvider caching() {
|
||||
return new CachingBiomeProvider(this);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
package com.dfsek.terra.api.world.biome.generation;
|
||||
|
||||
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.
|
||||
*
|
||||
* 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>
|
||||
*/
|
||||
public class CachingBiomeProvider implements BiomeProvider, Handle {
|
||||
private final BiomeProvider delegate;
|
||||
private final Map<Long, Biome> cache = new HashMap<>();
|
||||
|
||||
protected CachingBiomeProvider(BiomeProvider delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeProvider getHandle() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Biome getBiome(int x, int z, long seed) {
|
||||
return cache.computeIfAbsent(MathUtil.squash(x, z), key -> delegate.getBiome(x, z, seed));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Biome> getBiomes() {
|
||||
return delegate.getBiomes();
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@
|
||||
|
||||
package com.dfsek.terra.api.world.chunk.generation;
|
||||
|
||||
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
|
||||
import com.dfsek.terra.api.world.info.WorldProperties;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -18,7 +19,7 @@ import com.dfsek.terra.api.world.WritableWorld;
|
||||
|
||||
|
||||
public interface ChunkGenerator {
|
||||
void generateChunkData(@NotNull ProtoChunk chunk, @NotNull WorldProperties world,
|
||||
void generateChunkData(@NotNull ProtoChunk chunk, @NotNull WorldProperties world, @NotNull BiomeProvider biomeProvider,
|
||||
int chunkX, int chunkZ);
|
||||
|
||||
BlockState getBlock(WorldProperties world, int x, int y, int z);
|
||||
|
@ -21,7 +21,6 @@ import com.dfsek.terra.api.block.state.BlockState;
|
||||
|
||||
import com.dfsek.terra.bukkit.world.BukkitWorldProperties;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.generator.BiomeProvider;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
@ -35,11 +34,9 @@ import java.util.Random;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.dfsek.terra.api.config.ConfigPack;
|
||||
import com.dfsek.terra.api.world.ServerWorld;
|
||||
import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
|
||||
import com.dfsek.terra.api.world.chunk.generation.util.GeneratorWrapper;
|
||||
import com.dfsek.terra.bukkit.world.BukkitProtoWorld;
|
||||
import com.dfsek.terra.bukkit.world.BukkitServerWorld;
|
||||
|
||||
|
||||
public class BukkitChunkGeneratorWrapper extends org.bukkit.generator.ChunkGenerator implements GeneratorWrapper {
|
||||
@ -60,7 +57,7 @@ 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), x, z);
|
||||
delegate.generateChunkData(new BukkitProtoChunk(chunkData), new BukkitWorldProperties(worldInfo), pack.getBiomeProvider().caching(), x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -88,7 +88,7 @@ public class CLIWorld implements ServerWorld, NBTSerializable<Stream<Pair<Vector
|
||||
try {
|
||||
int num = amount.getAndIncrement();
|
||||
CLIChunk chunk = getChunkAt(finalX, finalZ);
|
||||
chunkGenerator.generateChunkData(chunk, this, finalX, finalZ);
|
||||
chunkGenerator.generateChunkData(chunk, this, pack.getBiomeProvider().caching(), finalX, finalZ);
|
||||
CLIProtoWorld protoWorld = new CLIProtoWorld(this, finalX, finalZ);
|
||||
pack.getStages().forEach(stage -> stage.populate(protoWorld));
|
||||
if(num % 240 == 239) {
|
||||
|
@ -155,7 +155,7 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C
|
||||
public CompletableFuture<Chunk> populateNoise(Executor executor, Blender arg, StructureAccessor structureAccessor, Chunk chunk) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
ProtoWorld world = (ProtoWorld) ((StructureAccessorAccessor) structureAccessor).getWorld();
|
||||
delegate.generateChunkData((ProtoChunk) chunk, world, chunk.getPos().x, chunk.getPos().z);
|
||||
delegate.generateChunkData((ProtoChunk) chunk, world, pack.getBiomeProvider().caching(), chunk.getPos().x, chunk.getPos().z);
|
||||
pack.getStages().forEach(populator -> {
|
||||
if(populator instanceof Chunkified) {
|
||||
populator.populate(world);
|
||||
|
Loading…
x
Reference in New Issue
Block a user