implement check cache

This commit is contained in:
dfsek
2020-12-30 21:03:28 -07:00
parent 8049824170
commit bccfcdf9a1
10 changed files with 92 additions and 116 deletions

View File

@@ -13,6 +13,7 @@ public class TerraWorld {
private final ConfigPack config;
private final boolean safe;
private final TerraProfiler profiler;
private final World world;
public TerraWorld(World w, ConfigPack c, TerraPlugin main) {
@@ -20,9 +21,14 @@ public class TerraWorld {
profiler = new TerraProfiler(w);
this.grid = new TerraBiomeGrid.TerraBiomeGridBuilder(w.getSeed(), c, main).build();
this.zone = grid.getZone();
this.world = w;
safe = true;
}
public World getWorld() {
return world;
}
public static boolean isTerraWorld(World w) {
return w.getGenerator().getHandle() instanceof GeneratorWrapper;
}

View File

@@ -17,6 +17,7 @@ import com.dfsek.terra.api.structures.script.builders.StructureFunctionBuilder;
import com.dfsek.terra.api.structures.structure.Rotation;
import com.dfsek.terra.api.structures.structure.buffer.Buffer;
import com.dfsek.terra.api.structures.structure.buffer.StructureBuffer;
import com.dfsek.terra.api.structures.world.CheckCache;
import com.dfsek.terra.registry.ScriptRegistry;
import org.apache.commons.io.IOUtils;
@@ -31,7 +32,7 @@ public class StructureScript {
private final String id;
private final LinkedHashMap<Location, StructureBuffer> cache;
public StructureScript(InputStream inputStream, TerraPlugin main, ScriptRegistry registry) {
public StructureScript(InputStream inputStream, TerraPlugin main, ScriptRegistry registry, CheckCache cache) {
Parser parser;
try {
parser = new Parser(IOUtils.toString(inputStream));
@@ -39,7 +40,7 @@ public class StructureScript {
throw new RuntimeException(e);
}
parser.addFunction("block", new BlockFunctionBuilder(main))
.addFunction("check", new CheckFunctionBuilder(main))
.addFunction("check", new CheckFunctionBuilder(main, cache))
.addFunction("structure", new StructureFunctionBuilder(registry, main))
.addFunction("randomInt", new RandomFunctionBuilder())
.addFunction("recursions", new RecursionsFunctionBuilder())

View File

@@ -6,20 +6,23 @@ import com.dfsek.terra.api.structures.parser.lang.Returnable;
import com.dfsek.terra.api.structures.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.api.structures.script.functions.CheckFunction;
import com.dfsek.terra.api.structures.tokenizer.Position;
import com.dfsek.terra.api.structures.world.CheckCache;
import java.util.List;
public class CheckFunctionBuilder implements FunctionBuilder<CheckFunction> {
private final TerraPlugin main;
private final CheckCache cache;
public CheckFunctionBuilder(TerraPlugin main) {
public CheckFunctionBuilder(TerraPlugin main, CheckCache cache) {
this.main = main;
this.cache = cache;
}
@SuppressWarnings("unchecked")
@Override
public CheckFunction build(List<Returnable<?>> argumentList, Position position) throws ParseException {
return new CheckFunction(main, (Returnable<Number>) argumentList.get(0), (Returnable<Number>) argumentList.get(1), (Returnable<Number>) argumentList.get(2), position);
return new CheckFunction(main, (Returnable<Number>) argumentList.get(0), (Returnable<Number>) argumentList.get(1), (Returnable<Number>) argumentList.get(2), cache, position);
}
@Override

View File

@@ -1,5 +1,6 @@
package com.dfsek.terra.api.structures.script.functions;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.math.vector.Vector2;
import com.dfsek.terra.api.math.vector.Vector3;
@@ -11,8 +12,11 @@ import com.dfsek.terra.api.structures.structure.Rotation;
import com.dfsek.terra.api.structures.structure.RotationUtil;
import com.dfsek.terra.api.structures.structure.buffer.Buffer;
import com.dfsek.terra.api.structures.tokenizer.Position;
import com.dfsek.terra.api.structures.world.LandCheck;
import com.dfsek.terra.api.structures.world.OceanCheck;
import com.dfsek.terra.api.structures.world.CheckCache;
import com.dfsek.terra.api.world.generation.GenerationPhase;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.biome.grid.master.TerraBiomeGrid;
import com.dfsek.terra.config.templates.BiomeTemplate;
import net.jafama.FastMath;
import java.util.Random;
@@ -21,13 +25,15 @@ public class CheckFunction implements Function<String> {
private final TerraPlugin main;
private final Returnable<Number> x, y, z;
private final Position position;
private final CheckCache cache;
public CheckFunction(TerraPlugin main, Returnable<Number> x, Returnable<Number> y, Returnable<Number> z, Position position) {
public CheckFunction(TerraPlugin main, Returnable<Number> x, Returnable<Number> y, Returnable<Number> z, CheckCache cache, Position position) {
this.main = main;
this.x = x;
this.y = y;
this.z = z;
this.position = position;
this.cache = cache;
}
@Override
@@ -49,11 +55,23 @@ public class CheckFunction implements Function<String> {
}
private String apply(Location vector, World world) {
if(new LandCheck(world, main).check(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ()))
return "LAND";
if(new OceanCheck(world, main).check(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ()))
return "OCEAN";
return "AIR";
TerraWorld tw = main.getWorld(world);
double comp = sample(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ(), world);
if(comp > 0) return "LAND"; // If noise val is greater than zero, location will always be land.
TerraBiomeGrid grid = tw.getGrid();
UserDefinedBiome b = (UserDefinedBiome) grid.getBiome(vector.getBlockX(), vector.getBlockZ(), GenerationPhase.POPULATE);
BiomeTemplate c = b.getConfig();
if(vector.getY() > c.getSeaLevel()) return "AIR"; // Above sea level
return "OCEAN"; // Below sea level
}
private double sample(int x, int y, int z, World w) {
int cx = FastMath.floorDiv(x, 16);
int cz = FastMath.floorDiv(z, 16);
return cache.get(w, x, z).sample(x - (cx << 4), y, z - (cz << 4));
}
@Override

View File

@@ -1,25 +0,0 @@
package com.dfsek.terra.api.structures.world;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.world.generation.GenerationPhase;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.biome.grid.master.TerraBiomeGrid;
import com.dfsek.terra.config.templates.BiomeTemplate;
public class AirCheck extends SpawnCheck {
public AirCheck(World world, TerraPlugin main) {
super(world, main);
}
@Override
public boolean check(int x, int y, int z) {
TerraWorld tw = main.getWorld(world);
TerraBiomeGrid g = tw.getGrid();
UserDefinedBiome b = (UserDefinedBiome) g.getBiome(x, z, GenerationPhase.POPULATE);
BiomeTemplate c = b.getConfig();
if(y <= c.getSeaLevel()) return false;
return sample(x, y, z, g) <= 0;
}
}

View File

@@ -0,0 +1,49 @@
package com.dfsek.terra.api.structures.world;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.generation.math.Sampler;
import net.jafama.FastMath;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
public class CheckCache {
private final Map<Long, Container> cache;
private final TerraPlugin main;
public CheckCache(TerraPlugin main) {
cache = new HashMap<>();
this.main = main;
}
public Sampler get(World world, int x, int z) {
return cache.computeIfAbsent(world.getSeed(), seed -> new Container(world, new LinkedHashMap<Long, Sampler>() {
@Override
protected boolean removeEldestEntry(Map.Entry<Long, Sampler> eldest) {
return size() > main.getTerraConfig().getCheckCache();
}
})).get(x, z);
}
private class Container {
private final World world;
private final Map<Long, Sampler> cache;
private Container(World world, Map<Long, Sampler> cache) {
this.world = world;
this.cache = cache;
}
public Sampler get(int x, int z) {
int cx = FastMath.floorDiv(x, 16);
int cz = FastMath.floorDiv(z, 16);
long key = (((long) cx) << 32) | (cz & 0xffffffffL);
TerraWorld tw = main.getWorld(world);
return cache.computeIfAbsent(key, k -> new Sampler(cx, cz, tw.getGrid(), world, 4, 8));
}
}
}

View File

@@ -1,17 +0,0 @@
package com.dfsek.terra.api.structures.world;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.platform.world.World;
public class LandCheck extends SpawnCheck {
public LandCheck(World world, TerraPlugin main) {
super(world, main);
}
@Override
public boolean check(int x, int y, int z) {
TerraWorld tw = main.getWorld(world);
return sample(x, y, z, tw.getGrid()) > 0;
}
}

View File

@@ -1,25 +0,0 @@
package com.dfsek.terra.api.structures.world;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.world.generation.GenerationPhase;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.biome.grid.master.TerraBiomeGrid;
import com.dfsek.terra.config.templates.BiomeTemplate;
public class OceanCheck extends SpawnCheck {
public OceanCheck(World world, TerraPlugin main) {
super(world, main);
}
@Override
public boolean check(int x, int y, int z) {
TerraWorld tw = main.getWorld(world);
TerraBiomeGrid grid = tw.getGrid();
UserDefinedBiome b = (UserDefinedBiome) grid.getBiome(x, z, GenerationPhase.POPULATE);
BiomeTemplate c = b.getConfig();
if(y > c.getSeaLevel()) return false;
return sample(x, y, z, grid) <= 0;
}
}

View File

@@ -1,36 +0,0 @@
package com.dfsek.terra.api.structures.world;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.biome.grid.master.TerraBiomeGrid;
import com.dfsek.terra.generation.math.Sampler;
import net.jafama.FastMath;
import java.util.LinkedHashMap;
import java.util.Map;
public abstract class SpawnCheck {
protected final World world;
protected final TerraPlugin main;
private final Map<Long, Sampler> cache;
protected SpawnCheck(World world, TerraPlugin main) {
this.world = world;
this.main = main;
cache = new LinkedHashMap<Long, Sampler>() {
@Override
protected boolean removeEldestEntry(Map.Entry<Long, Sampler> eldest) {
return size() > main.getTerraConfig().getCheckCache();
}
};
}
public abstract boolean check(int x, int y, int z);
protected double sample(int x, int y, int z, TerraBiomeGrid grid) {
int cx = FastMath.floorDiv(x, 16);
int cz = FastMath.floorDiv(z, 16);
long key = (((long) cx) << 32) | (cz & 0xffffffffL);
return cache.computeIfAbsent(key, k -> new Sampler(cx, cz, grid, world, 4, 8)).sample(x - (cx << 4), y, z - (cz << 4));
}
}

View File

@@ -9,6 +9,7 @@ import com.dfsek.terra.api.LoaderRegistrar;
import com.dfsek.terra.api.loot.LootTable;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.structures.script.StructureScript;
import com.dfsek.terra.api.structures.world.CheckCache;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.flora.Flora;
import com.dfsek.terra.api.world.palette.Palette;
@@ -148,8 +149,9 @@ public class ConfigPack implements LoaderRegistrar {
abstractConfigLoader
.registerLoader(LootTable.class, new LootTableLoader(loader, main)); // These loaders need access to the Loader instance to get files.
CheckCache checkCache = new CheckCache(main);
loader.open("structures/data", ".tesf").then(streams -> streams.forEach(stream -> {
StructureScript structureScript = new StructureScript(stream, main, scriptRegistry);
StructureScript structureScript = new StructureScript(stream, main, scriptRegistry, checkCache);
scriptRegistry.add(structureScript.getId(), structureScript);
})).close();