diff --git a/common/src/main/java/com/dfsek/terra/TerraWorld.java b/common/src/main/java/com/dfsek/terra/TerraWorld.java index 6fddf3da5..350b6b67f 100644 --- a/common/src/main/java/com/dfsek/terra/TerraWorld.java +++ b/common/src/main/java/com/dfsek/terra/TerraWorld.java @@ -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; } diff --git a/common/src/main/java/com/dfsek/terra/api/structures/script/StructureScript.java b/common/src/main/java/com/dfsek/terra/api/structures/script/StructureScript.java index 1b02c9df9..2187eb2cb 100644 --- a/common/src/main/java/com/dfsek/terra/api/structures/script/StructureScript.java +++ b/common/src/main/java/com/dfsek/terra/api/structures/script/StructureScript.java @@ -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 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()) diff --git a/common/src/main/java/com/dfsek/terra/api/structures/script/builders/CheckFunctionBuilder.java b/common/src/main/java/com/dfsek/terra/api/structures/script/builders/CheckFunctionBuilder.java index d5e1ce757..bac7b422f 100644 --- a/common/src/main/java/com/dfsek/terra/api/structures/script/builders/CheckFunctionBuilder.java +++ b/common/src/main/java/com/dfsek/terra/api/structures/script/builders/CheckFunctionBuilder.java @@ -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 { 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> argumentList, Position position) throws ParseException { - return new CheckFunction(main, (Returnable) argumentList.get(0), (Returnable) argumentList.get(1), (Returnable) argumentList.get(2), position); + return new CheckFunction(main, (Returnable) argumentList.get(0), (Returnable) argumentList.get(1), (Returnable) argumentList.get(2), cache, position); } @Override diff --git a/common/src/main/java/com/dfsek/terra/api/structures/script/functions/CheckFunction.java b/common/src/main/java/com/dfsek/terra/api/structures/script/functions/CheckFunction.java index 69a3cc73f..bef383108 100644 --- a/common/src/main/java/com/dfsek/terra/api/structures/script/functions/CheckFunction.java +++ b/common/src/main/java/com/dfsek/terra/api/structures/script/functions/CheckFunction.java @@ -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 { private final TerraPlugin main; private final Returnable x, y, z; private final Position position; + private final CheckCache cache; - public CheckFunction(TerraPlugin main, Returnable x, Returnable y, Returnable z, Position position) { + public CheckFunction(TerraPlugin main, Returnable x, Returnable y, Returnable 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 { } 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 diff --git a/common/src/main/java/com/dfsek/terra/api/structures/world/AirCheck.java b/common/src/main/java/com/dfsek/terra/api/structures/world/AirCheck.java deleted file mode 100644 index 27440a22a..000000000 --- a/common/src/main/java/com/dfsek/terra/api/structures/world/AirCheck.java +++ /dev/null @@ -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; - } -} diff --git a/common/src/main/java/com/dfsek/terra/api/structures/world/CheckCache.java b/common/src/main/java/com/dfsek/terra/api/structures/world/CheckCache.java new file mode 100644 index 000000000..da51a69c0 --- /dev/null +++ b/common/src/main/java/com/dfsek/terra/api/structures/world/CheckCache.java @@ -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 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() { + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > main.getTerraConfig().getCheckCache(); + } + })).get(x, z); + } + + + private class Container { + private final World world; + private final Map cache; + + private Container(World world, Map 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)); + } + } +} diff --git a/common/src/main/java/com/dfsek/terra/api/structures/world/LandCheck.java b/common/src/main/java/com/dfsek/terra/api/structures/world/LandCheck.java deleted file mode 100644 index fbf566903..000000000 --- a/common/src/main/java/com/dfsek/terra/api/structures/world/LandCheck.java +++ /dev/null @@ -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; - } -} diff --git a/common/src/main/java/com/dfsek/terra/api/structures/world/OceanCheck.java b/common/src/main/java/com/dfsek/terra/api/structures/world/OceanCheck.java deleted file mode 100644 index 248dfdb8a..000000000 --- a/common/src/main/java/com/dfsek/terra/api/structures/world/OceanCheck.java +++ /dev/null @@ -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; - } -} diff --git a/common/src/main/java/com/dfsek/terra/api/structures/world/SpawnCheck.java b/common/src/main/java/com/dfsek/terra/api/structures/world/SpawnCheck.java deleted file mode 100644 index fe6e23947..000000000 --- a/common/src/main/java/com/dfsek/terra/api/structures/world/SpawnCheck.java +++ /dev/null @@ -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 cache; - - protected SpawnCheck(World world, TerraPlugin main) { - this.world = world; - this.main = main; - cache = new LinkedHashMap() { - @Override - protected boolean removeEldestEntry(Map.Entry 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)); - } -} diff --git a/common/src/main/java/com/dfsek/terra/config/base/ConfigPack.java b/common/src/main/java/com/dfsek/terra/config/base/ConfigPack.java index dc48794c7..3fd7e09b1 100644 --- a/common/src/main/java/com/dfsek/terra/config/base/ConfigPack.java +++ b/common/src/main/java/com/dfsek/terra/config/base/ConfigPack.java @@ -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();