replace dumb caches with guava caches

This commit is contained in:
dfsek 2021-01-14 00:34:23 -07:00
parent 8fd3530653
commit cbc2885c16
7 changed files with 81 additions and 113 deletions

View File

@ -32,21 +32,21 @@ import com.dfsek.terra.debug.Debug;
import com.dfsek.terra.generation.math.SamplerCache;
import com.dfsek.terra.registry.LootRegistry;
import com.dfsek.terra.registry.ScriptRegistry;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import net.jafama.FastMath;
import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ExecutionException;
public class StructureScript {
private final Block block;
private final String id;
String tempID;
private final Map<Location, StructureBuffer> cache;
private final Cache<Location, StructureBuffer> cache;
private final TerraPlugin main;
public StructureScript(InputStream inputStream, TerraPlugin main, ScriptRegistry registry, LootRegistry lootRegistry, SamplerCache cache) throws ParseException {
@ -88,12 +88,7 @@ public class StructureScript {
this.id = parser.getID();
tempID = id;
this.main = main;
this.cache = Collections.synchronizedMap(new LinkedHashMap<Location, StructureBuffer>() {
@Override
protected boolean removeEldestEntry(Map.Entry<Location, StructureBuffer> eldest) {
return this.size() > main.getTerraConfig().getStructureCache();
}
});
this.cache = CacheBuilder.newBuilder().maximumSize(main.getTerraConfig().getStructureCache()).build();
}
/**
@ -122,12 +117,14 @@ public class StructureScript {
}
private StructureBuffer computeBuffer(Location location, Random random, Rotation rotation) {
synchronized(cache) {
return cache.computeIfAbsent(location, loc -> {
StructureBuffer buf = new StructureBuffer(loc);
try {
return cache.get(location, () -> {
StructureBuffer buf = new StructureBuffer(location);
buf.setSucceeded(applyBlock(new TerraImplementationArguments(buf, rotation, random, 0)));
return buf;
});
} catch(ExecutionException e) {
throw new RuntimeException(e);
}
}

View File

@ -1,25 +0,0 @@
package com.dfsek.terra.biome;
import com.dfsek.terra.api.math.vector.Vector2;
import com.dfsek.terra.biome.pipeline.BiomeHolder;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.jetbrains.annotations.NotNull;
public class BiomeCache {
LoadingCache<Vector2, BiomeHolder> cache;
public BiomeCache() {
cache = CacheBuilder.newBuilder()
.maximumSize(1024)
.build(
new CacheLoader<Vector2, BiomeHolder>() {
@Override
public BiomeHolder load(@NotNull Vector2 key) throws Exception {
return null;
}
}
);
}
}

View File

@ -50,11 +50,7 @@ public class StandardBiomeProvider implements BiomeProvider {
@Override
public TerraBiome getBiome(int x, int z) {
try {
return biomeCache.get(new Vector2(x, z));
} catch(ExecutionException e) {
throw new RuntimeException(e);
}
return biomeCache.getUnchecked(new Vector2(x, z));
}
public int getResolution() {

View File

@ -10,52 +10,50 @@ import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.carving.Worm;
import com.dfsek.terra.biome.BiomeProvider;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
public class CarverCache {
private final World w;
private final Map<Long, List<Worm.WormPoint>> carvers;
private final TerraPlugin main;
private final LoadingCache<Long, List<Worm.WormPoint>> cache;
private final UserDefinedCarver carver;
public CarverCache(World w, TerraPlugin main) {
this.w = w;
this.main = main;
carvers = Collections.synchronizedMap(new LinkedHashMap<Long, List<Worm.WormPoint>>() {
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
return this.size() > main.getTerraConfig().getCarverCacheSize();
}
});
public CarverCache(World w, TerraPlugin main, UserDefinedCarver carver) {
this.carver = carver;
cache = CacheBuilder.newBuilder().maximumSize(main.getTerraConfig().getCarverCacheSize())
.build(new CacheLoader<Long, List<Worm.WormPoint>>() {
@Override
public List<Worm.WormPoint> load(@NotNull Long key) {
int chunkX = (int) (key >> 32);
int chunkZ = (int) key.longValue();
BiomeProvider provider = main.getWorld(w).getBiomeProvider();
if(CarverCache.this.carver.isChunkCarved(w, chunkX, chunkZ, new FastRandom(MathUtil.getCarverChunkSeed(chunkX, chunkZ, w.getSeed() + CarverCache.this.carver.hashCode())))) {
long seed = MathUtil.getCarverChunkSeed(chunkX, chunkZ, w.getSeed());
CarverCache.this.carver.getSeedVar().setValue(seed);
Random r = new FastRandom(seed);
Worm carving = CarverCache.this.carver.getWorm(seed, new Vector3((chunkX << 4) + r.nextInt(16), CarverCache.this.carver.getConfig().getHeight().get(r), (chunkZ << 4) + r.nextInt(16)));
List<Worm.WormPoint> points = new GlueList<>();
for(int i = 0; i < carving.getLength(); i++) {
carving.step();
TerraBiome biome = provider.getBiome(carving.getRunning().toLocation(w));
if(!((UserDefinedBiome) biome).getConfig().getCarvers().containsKey(CarverCache.this.carver)) { // Stop if we enter a biome this carver is not present in
return new GlueList<>();
}
points.add(carving.getPoint());
}
return points;
}
return new GlueList<>();
}
});
}
public List<Worm.WormPoint> getPoints(int chunkX, int chunkZ, UserDefinedCarver carver) {
synchronized(carvers) {
return carvers.computeIfAbsent(MathUtil.squash(chunkX, chunkZ), key -> {
BiomeProvider provider = main.getWorld(w).getBiomeProvider();
if(carver.isChunkCarved(w, chunkX, chunkZ, new FastRandom(MathUtil.getCarverChunkSeed(chunkX, chunkZ, w.getSeed() + carver.hashCode())))) {
long seed = MathUtil.getCarverChunkSeed(chunkX, chunkZ, w.getSeed());
carver.getSeedVar().setValue(seed);
Random r = new FastRandom(seed);
Worm carving = carver.getWorm(seed, new Vector3((chunkX << 4) + r.nextInt(16), carver.getConfig().getHeight().get(r), (chunkZ << 4) + r.nextInt(16)));
List<Worm.WormPoint> points = new GlueList<>();
for(int i = 0; i < carving.getLength(); i++) {
carving.step();
TerraBiome biome = provider.getBiome(carving.getRunning().toLocation(w));
if(!((UserDefinedBiome) biome).getConfig().getCarvers().containsKey(carver)) { // Stop if we enter a biome this carver is not present in
return new GlueList<>();
}
points.add(carving.getPoint());
}
return points;
}
return new GlueList<>();
});
}
public List<Worm.WormPoint> getPoints(int chunkX, int chunkZ) {
return cache.getUnchecked(MathUtil.squash(chunkX, chunkZ));
}
}

View File

@ -11,6 +11,7 @@ import com.dfsek.terra.api.world.carving.Worm;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.config.templates.CarverTemplate;
import com.dfsek.terra.debug.Debug;
import net.jafama.FastMath;
import parsii.eval.Expression;
import parsii.eval.Parser;
@ -100,11 +101,12 @@ public class UserDefinedCarver extends Carver {
@Override
public void carve(int chunkX, int chunkZ, World w, BiConsumer<Vector3, CarvingType> consumer) {
CarverCache cache = cacheMap.computeIfAbsent(w, world -> new CarverCache(world, main));
CarverCache cache = cacheMap.computeIfAbsent(w, world -> new CarverCache(world, main, this));
if(cacheMap.size() > 1) Debug.info("Map size: " + cacheMap.size());
int carvingRadius = getCarvingRadius();
for(int x = chunkX - carvingRadius; x <= chunkX + carvingRadius; x++) {
for(int z = chunkZ - carvingRadius; z <= chunkZ + carvingRadius; z++) {
cache.getPoints(x, z, this).forEach(point -> {
cache.getPoints(x, z).forEach(point -> {
Vector3 origin = point.getOrigin();
if(FastMath.floorDiv(origin.getBlockX(), 16) != chunkX && FastMath.floorDiv(origin.getBlockZ(), 16) != chunkZ) // We only want to carve this chunk.
return;

View File

@ -4,11 +4,13 @@ import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.api.math.MathUtil;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.platform.world.World;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import net.jafama.FastMath;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
public class SamplerCache {
@ -35,14 +37,18 @@ public class SamplerCache {
private class Container {
private final World world;
private final TerraWorld terraWorld;
private final Map<Long, Sampler> cache = Collections.synchronizedMap(new LinkedHashMap<Long, Sampler>() {
@Override
protected boolean removeEldestEntry(Map.Entry<Long, Sampler> eldest) {
return this.size() > main.getTerraConfig().getSamplerCache();
}
});
private final LoadingCache<Long, Sampler> cache;
private Container(World world) {
cache = CacheBuilder.newBuilder().maximumSize(main.getTerraConfig().getSamplerCache())
.build(new CacheLoader<Long, Sampler>() {
@Override
public Sampler load(@NotNull Long key) {
int cx = (int) (key >> 32);
int cz = (int) key.longValue();
return new Sampler(cx, cz, terraWorld.getBiomeProvider(), world, terraWorld.getConfig().getTemplate().getBaseBlend(), terraWorld.getConfig().getTemplate().getElevationBlend());
}
});
this.world = world;
terraWorld = main.getWorld(world);
}
@ -55,9 +61,7 @@ public class SamplerCache {
public Sampler getChunk(int cx, int cz) {
long key = MathUtil.squash(cx, cz);
synchronized(cache) {
return cache.computeIfAbsent(key, k -> new Sampler(cx, cz, terraWorld.getBiomeProvider(), world, terraWorld.getConfig().getTemplate().getBaseBlend(), terraWorld.getConfig().getTemplate().getElevationBlend()));
}
return cache.getUnchecked(key);
}
}
}

View File

@ -61,25 +61,21 @@ public class BiomeTest {
BiomeSource source = new RandomSource(climate, sourceSampler);
BiomeProvider provider = new StandardBiomeProvider.StandardBiomeProviderBuilder((seed) -> {
BiomePipeline pipeline = new BiomePipeline.BiomePipelineBuilder(2)
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(1))))
.addStage(new MutatorStage(new ReplaceMutator("OCEAN_TEMP", oceanBiomes, whiteNoise(243))))
.addStage(new MutatorStage(new ReplaceMutator("LAND_TEMP", landBiomes, whiteNoise(243))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(2))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(2))))
.addStage(new MutatorStage(new SmoothMutator(whiteNoise(3))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(4))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(4))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(4))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(4))))
.addStage(new MutatorStage(new BorderMutator("OCEAN", "LAND", whiteNoise(1234), beachBiomes)))
.addStage(new MutatorStage(new SmoothMutator(whiteNoise(6))))
.addStage(new MutatorStage(new SmoothMutator(whiteNoise(6))))
.build(source);
System.out.println("Size: " + pipeline.getSize());
return pipeline;
}, null).build(0);
BiomeProvider provider = new StandardBiomeProvider.StandardBiomeProviderBuilder((seed) -> new BiomePipeline.BiomePipelineBuilder(2)
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(1))))
.addStage(new MutatorStage(new ReplaceMutator("OCEAN_TEMP", oceanBiomes, whiteNoise(243))))
.addStage(new MutatorStage(new ReplaceMutator("LAND_TEMP", landBiomes, whiteNoise(243))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(2))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(2))))
.addStage(new MutatorStage(new SmoothMutator(whiteNoise(3))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(4))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(4))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(4))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(4))))
.addStage(new MutatorStage(new BorderMutator("OCEAN", "LAND", whiteNoise(1234), beachBiomes)))
.addStage(new MutatorStage(new SmoothMutator(whiteNoise(6))))
.addStage(new MutatorStage(new SmoothMutator(whiteNoise(6))))
.build(source), null).build(0);
int size = 1000;