From 0eddcf429cb005f429ee0cdfd3785635f4e008ac Mon Sep 17 00:00:00 2001 From: dfsek Date: Sun, 13 Sep 2020 02:18:26 -0700 Subject: [PATCH] Implement new parsing library, implement TerraProfiler --- pom.xml | 2 +- src/main/java/com/dfsek/terra/Terra.java | 62 ------------------- .../java/com/dfsek/terra/TerraCommand.java | 44 ++++++++++--- .../java/com/dfsek/terra/TerraProfiler.java | 30 +++++++++ .../dfsek/terra/biome/UserDefinedBiome.java | 25 ++++++-- .../terra/biome/UserDefinedGenerator.java | 56 ++++++++++------- .../com/dfsek/terra/config/BiomeConfig.java | 1 + .../com/dfsek/terra/config/WorldConfig.java | 6 +- .../com/dfsek/terra/math/NoiseFunction2.java | 14 ++--- .../com/dfsek/terra/math/NoiseFunction3.java | 15 ++--- .../terra/population/FaunaPopulator.java | 10 ++- .../dfsek/terra/population/TreePopulator.java | 4 ++ 12 files changed, 146 insertions(+), 123 deletions(-) create mode 100644 src/main/java/com/dfsek/terra/TerraProfiler.java diff --git a/pom.xml b/pom.xml index eb6f46f8c..9c6b5c5fc 100644 --- a/pom.xml +++ b/pom.xml @@ -83,7 +83,7 @@ org.polydev gaea - 1.4.0 + 1.5.7 diff --git a/src/main/java/com/dfsek/terra/Terra.java b/src/main/java/com/dfsek/terra/Terra.java index f2f674247..99e40b31f 100644 --- a/src/main/java/com/dfsek/terra/Terra.java +++ b/src/main/java/com/dfsek/terra/Terra.java @@ -1,75 +1,13 @@ package com.dfsek.terra; import com.dfsek.terra.config.ConfigUtil; -import com.dfsek.terra.config.WorldConfig; -import com.dfsek.terra.math.NoiseFunction2; -import com.dfsek.terra.math.NoiseFunction3; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.generator.ChunkGenerator; import org.bukkit.plugin.java.JavaPlugin; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.polydev.gaea.math.parsii.eval.Expression; -import org.polydev.gaea.math.parsii.eval.Function; -import org.polydev.gaea.math.parsii.eval.Parser; - -import java.util.List; public class Terra extends JavaPlugin { - - static { - Parser.registerFunction("floor", new Function() { - @Override - public int getNumberOfArguments() { - return 1; - } - - @Override - public double eval(List list) { - return Math.floor(list.get(0).evaluate()); - } - - @Override - public boolean isNaturalFunction() { - return true; - } - }); - Parser.registerFunction("ceil", new Function() { - @Override - public int getNumberOfArguments() { - return 1; - } - - @Override - public double eval(List list) { - return Math.ceil(list.get(0).evaluate()); - } - - @Override - public boolean isNaturalFunction() { - return true; - } - }); - Parser.registerFunction("round", new Function() { - @Override - public int getNumberOfArguments() { - return 1; - } - - @Override - public double eval(List list) { - return Math.round(list.get(0).evaluate()); - } - - @Override - public boolean isNaturalFunction() { - return true; - } - }); - Parser.registerFunction("noise2", new NoiseFunction2()); - Parser.registerFunction("noise3", new NoiseFunction3()); - } - private static FileConfiguration config; private static Terra instance; diff --git a/src/main/java/com/dfsek/terra/TerraCommand.java b/src/main/java/com/dfsek/terra/TerraCommand.java index 7e7a5979d..c5d97ca7e 100644 --- a/src/main/java/com/dfsek/terra/TerraCommand.java +++ b/src/main/java/com/dfsek/terra/TerraCommand.java @@ -8,21 +8,45 @@ import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; +import org.polydev.gaea.profiler.WorldProfiler; public class TerraCommand implements CommandExecutor { @Override public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - if(args.length == 1) { - switch(args[0]) { - case "reload": - ConfigUtil.loadConfig(Terra.getInstance()); - sender.sendMessage("Reloaded Terra config."); - break; - case "biome": - if(!(sender instanceof Player)) return false; - sender.sendMessage("You are in " + ((UserDefinedBiome) TerraBiomeGrid.fromWorld(((Player) sender).getWorld()).getBiome(((Player) sender).getLocation())).getConfig().getFriendlyName()); + switch(args[0]) { + case "reload": + ConfigUtil.loadConfig(Terra.getInstance()); + sender.sendMessage("Reloaded Terra config."); + break; + case "biome": + if(!(sender instanceof Player)) return false; + sender.sendMessage("You are in " + ((UserDefinedBiome) TerraBiomeGrid.fromWorld(((Player) sender).getWorld()).getBiome(((Player) sender).getLocation())).getConfig().getFriendlyName()); + case "profile": + if(! (sender instanceof Player)) { + sender.sendMessage("Command is for players only."); + return true; + } + Player p = (Player) sender; + if(p.getWorld().getGenerator() instanceof TerraChunkGenerator) { + WorldProfiler profile = TerraProfiler.fromWorld(p.getWorld()); + if(args.length > 1 && "query".equals(args[1])) { + sender.sendMessage(profile.getResultsFormatted()); + return true; + } else if(args.length > 1 && "reset".equals(args[1])) { + profile.reset(); + sender.sendMessage("Profiler has been reset."); + return true; + } else if(args.length > 1 && "start".equals(args[1])) { + profile.setProfiling(true); + sender.sendMessage("Profiler has started."); + return true; + } else if(args.length > 1 && "stop".equals(args[1])) { + profile.setProfiling(false); + sender.sendMessage("Profiler has stopped."); + return true; + } + } else sender.sendMessage("World is not a Terra world!"); } - } return true; } } diff --git a/src/main/java/com/dfsek/terra/TerraProfiler.java b/src/main/java/com/dfsek/terra/TerraProfiler.java new file mode 100644 index 000000000..c7844f6b2 --- /dev/null +++ b/src/main/java/com/dfsek/terra/TerraProfiler.java @@ -0,0 +1,30 @@ +package com.dfsek.terra; + +import org.bukkit.World; +import org.polydev.gaea.profiler.DataType; +import org.polydev.gaea.profiler.Measurement; +import org.polydev.gaea.profiler.WorldProfiler; + +import java.util.HashMap; +import java.util.Map; + +public class TerraProfiler extends WorldProfiler { + private static final Map profilerMap = new HashMap<>(); + public TerraProfiler(World w) { + super(w); + this.addMeasurement(new Measurement(2500000, DataType.PERIOD_MILLISECONDS), "TotalChunkGenTime") + .addMeasurement(new Measurement(2500000, DataType.PERIOD_MILLISECONDS), "ChunkBaseGenTime") + .addMeasurement(new Measurement(2000000, DataType.PERIOD_MILLISECONDS), "BiomeSetTime") + .addMeasurement(new Measurement(25000000, DataType.PERIOD_MILLISECONDS), "TreeGenTime") + .addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "FaunaTime"); + profilerMap.put(w, this); + } + public static TerraProfiler fromWorld(World w) { + if(w.getGenerator() instanceof TerraChunkGenerator) { + if(profilerMap.containsKey(w)) return profilerMap.get(w); + TerraProfiler p = new TerraProfiler(w); + profilerMap.put(w, p); + return p; + } else throw new IllegalArgumentException("Attempted to instantiate/fetch Profiler for non-Terra world!"); + } +} diff --git a/src/main/java/com/dfsek/terra/biome/UserDefinedBiome.java b/src/main/java/com/dfsek/terra/biome/UserDefinedBiome.java index afdec9f27..0a5dda37e 100644 --- a/src/main/java/com/dfsek/terra/biome/UserDefinedBiome.java +++ b/src/main/java/com/dfsek/terra/biome/UserDefinedBiome.java @@ -2,14 +2,18 @@ package com.dfsek.terra.biome; import com.dfsek.terra.config.BiomeConfig; import com.dfsek.terra.config.ConfigUtil; +import org.bukkit.Bukkit; +import org.bukkit.block.data.BlockData; import org.bukkit.configuration.file.FileConfiguration; import org.polydev.gaea.biome.Biome; import org.polydev.gaea.biome.BiomeTerrain; import org.polydev.gaea.biome.Decorator; +import org.polydev.gaea.math.ProbabilityCollection; import org.polydev.gaea.math.parsii.eval.Parser; import org.polydev.gaea.math.parsii.eval.Scope; import org.polydev.gaea.math.parsii.tokenizer.ParseException; import org.polydev.gaea.structures.features.Feature; +import org.polydev.gaea.tree.Tree; import org.polydev.gaea.world.BlockPalette; import java.util.Collections; @@ -24,16 +28,27 @@ public class UserDefinedBiome implements Biome { private final UserDefinedDecorator decorator; public UserDefinedBiome(BiomeConfig config) throws ParseException { this.config = config; - Scope s = Scope.create(); TreeMap paletteMap = new TreeMap<>(); - for(Map.Entry e : config.getConfigurationSection("palette").getValues(false).entrySet()) { - paletteMap.put((Integer) e.getValue(), ConfigUtil.getPalette(e.getKey()).getPalette()); + for(Map e : config.getMapList("palette")) { + for(Map.Entry entry : e.entrySet()) { + try { + if(((String) entry.getKey()).startsWith("BLOCK:")) { + try { + paletteMap.put((Integer) entry.getValue(), new BlockPalette().addBlockData(new ProbabilityCollection().add(Bukkit.createBlockData((String) entry.getKey()), 1), 1)); + } catch(IllegalArgumentException ex) { + Bukkit.getLogger().severe("SEVERE configuration error for BlockPalettes in biome" + config.getFriendlyName() + ", ID: " + config.getBiomeID() + ". BlockData " + entry.getKey() + " is invalid!"); + } + } + else paletteMap.put((Integer) entry.getValue(), ConfigUtil.getPalette((String) entry.getKey()).getPalette()); + } catch(ClassCastException ex) { + Bukkit.getLogger().severe("SEVERE configuration error for BlockPalettes in biome" + config.getFriendlyName() + ", ID: " + config.getBiomeID()); + } + } } - this.decorator = new UserDefinedDecorator(config); - gen = new UserDefinedGenerator(s, Parser.parse(Objects.requireNonNull(config.getString("noise-equation")), s), Collections.emptyList(), paletteMap); + gen = new UserDefinedGenerator(Objects.requireNonNull(config.getString("noise-equation")), Collections.emptyList(), paletteMap); } public BiomeConfig getConfig() { diff --git a/src/main/java/com/dfsek/terra/biome/UserDefinedGenerator.java b/src/main/java/com/dfsek/terra/biome/UserDefinedGenerator.java index 5e73cf150..8baf1772c 100644 --- a/src/main/java/com/dfsek/terra/biome/UserDefinedGenerator.java +++ b/src/main/java/com/dfsek/terra/biome/UserDefinedGenerator.java @@ -1,12 +1,15 @@ package com.dfsek.terra.biome; +import com.dfsek.terra.Terra; import com.dfsek.terra.math.NoiseFunction2; import com.dfsek.terra.math.NoiseFunction3; import org.polydev.gaea.biome.BiomeTerrain; import org.polydev.gaea.math.FastNoise; import org.polydev.gaea.math.parsii.eval.Expression; +import org.polydev.gaea.math.parsii.eval.Parser; import org.polydev.gaea.math.parsii.eval.Scope; import org.polydev.gaea.math.parsii.eval.Variable; +import org.polydev.gaea.math.parsii.tokenizer.ParseException; import org.polydev.gaea.world.BlockPalette; import java.util.List; @@ -16,19 +19,26 @@ import java.util.TreeMap; public class UserDefinedGenerator extends BiomeTerrain { private final Expression noiseExp; private final List vars; - private final Variable xVar; - private final Variable yVar; - private final Variable zVar; + private final Scope s = new Scope(); + private final Variable xVar = s.getVariable("x");; + private final Variable yVar = s.getVariable("y"); + private final Variable zVar = s.getVariable("z");; private final TreeMap paletteMap; + private final NoiseFunction2 n2 = new NoiseFunction2(); + private final NoiseFunction3 n3 = new NoiseFunction3(); + private final Parser p = new Parser(); + { + p.registerFunction("noise2", n2); + p.registerFunction("noise3", n3); + } + + private static final Object noiseLock = new Object(); - public UserDefinedGenerator(Scope s, Expression e, List v, TreeMap p) { - this.noiseExp = e; + public UserDefinedGenerator(String e, List v, TreeMap pa) throws ParseException { this.vars = v; - this.paletteMap = p; - this.xVar = s.getVariable("x"); - this.yVar = s.getVariable("y"); - this.zVar = s.getVariable("z"); + this.paletteMap = pa; + this.noiseExp = p.parse(e, s); } /** * Gets the 2D noise at a pair of coordinates using the provided FastNoise instance. @@ -40,12 +50,14 @@ public class UserDefinedGenerator extends BiomeTerrain { */ @Override public double getNoise(FastNoise gen, int x, int z) { - xVar.setValue(x); - yVar.setValue(0); - zVar.setValue(z); - NoiseFunction2.setNoise(gen); - NoiseFunction3.setNoise(gen); - return noiseExp.evaluate(); + synchronized(noiseLock) { + xVar.setValue(x); + yVar.setValue(0); + zVar.setValue(z); + n2.setNoise(gen, false); + n3.setNoise(gen, false); + return noiseExp.evaluate(); + } } /** @@ -59,12 +71,14 @@ public class UserDefinedGenerator extends BiomeTerrain { */ @Override public double getNoise(FastNoise gen, int x, int y, int z) { - xVar.setValue(x); - yVar.setValue(y); - zVar.setValue(z); - NoiseFunction2.setNoise(gen); - NoiseFunction3.setNoise(gen); - return noiseExp.evaluate(); + synchronized(noiseLock) { + xVar.setValue(x); + yVar.setValue(y); + zVar.setValue(z); + n2.setNoise(gen, false); + n3.setNoise(gen, false); + return noiseExp.evaluate(); + } } /** diff --git a/src/main/java/com/dfsek/terra/config/BiomeConfig.java b/src/main/java/com/dfsek/terra/config/BiomeConfig.java index 8ceab9707..dfad80417 100644 --- a/src/main/java/com/dfsek/terra/config/BiomeConfig.java +++ b/src/main/java/com/dfsek/terra/config/BiomeConfig.java @@ -39,6 +39,7 @@ public class BiomeConfig extends YamlConfiguration { if(!contains("name")) throw new InvalidConfigurationException("Biome Name unspecified!"); this.friendlyName = getString("name"); if(!contains("vanilla")) throw new InvalidConfigurationException("Vanila Biome unspecified!"); + if(!contains("palette")) throw new InvalidConfigurationException("Palette unspecified!"); try { this.vanillaBiome = org.bukkit.block.Biome.valueOf(getString("vanilla")); } catch(IllegalArgumentException e) { diff --git a/src/main/java/com/dfsek/terra/config/WorldConfig.java b/src/main/java/com/dfsek/terra/config/WorldConfig.java index bf85947eb..b6dab4143 100644 --- a/src/main/java/com/dfsek/terra/config/WorldConfig.java +++ b/src/main/java/com/dfsek/terra/config/WorldConfig.java @@ -66,9 +66,9 @@ public class WorldConfig { } seaLevel = config.getInt("sea-level", 63); - zoneFreq = config.getInt("frequencies.zone", 1536); - freq1 = config.getInt("frequencies.grid-1", 256); - freq2 = config.getInt("frequencies.grid-2", 512); + zoneFreq = 1f/config.getInt("frequencies.zone", 1536); + freq1 = 1f/config.getInt("frequencies.grid-1", 256); + freq2 = 1f/config.getInt("frequencies.grid-2", 512); try (Stream paths = Files.walk(Paths.get(main.getDataFolder() + File.separator + "grids"))) { paths diff --git a/src/main/java/com/dfsek/terra/math/NoiseFunction2.java b/src/main/java/com/dfsek/terra/math/NoiseFunction2.java index d2349eaf4..94d1416fa 100644 --- a/src/main/java/com/dfsek/terra/math/NoiseFunction2.java +++ b/src/main/java/com/dfsek/terra/math/NoiseFunction2.java @@ -7,7 +7,7 @@ import org.polydev.gaea.math.parsii.eval.Function; import java.util.List; public class NoiseFunction2 implements Function { - private static FastNoise gen = new FastNoise(); + private FastNoise gen; @Override public int getNumberOfArguments() { @@ -19,16 +19,12 @@ public class NoiseFunction2 implements Function { return gen.getSimplexFractal((float) list.get(0).evaluate(), (float) list.get(1).evaluate()); } + public void setNoise(FastNoise gen, boolean override) { + if(this.gen == null || override) this.gen = gen; + } + @Override public boolean isNaturalFunction() { return true; } - - public static void setNoise(FastNoise gen) { - NoiseFunction2.gen = gen; - } - - public static FastNoise getNoise() { - return gen; - } } diff --git a/src/main/java/com/dfsek/terra/math/NoiseFunction3.java b/src/main/java/com/dfsek/terra/math/NoiseFunction3.java index e368cb749..a1c5ac416 100644 --- a/src/main/java/com/dfsek/terra/math/NoiseFunction3.java +++ b/src/main/java/com/dfsek/terra/math/NoiseFunction3.java @@ -7,8 +7,7 @@ import org.polydev.gaea.math.parsii.eval.Function; import java.util.List; public class NoiseFunction3 implements Function { - private static FastNoise gen = new FastNoise(); - + private FastNoise gen; @Override public int getNumberOfArguments() { return 3; @@ -19,16 +18,12 @@ public class NoiseFunction3 implements Function { return gen.getSimplexFractal((float) list.get(0).evaluate(), (float) list.get(1).evaluate(), (float) list.get(2).evaluate()); } + public void setNoise(FastNoise gen, boolean override) { + if(this.gen == null || override) this.gen = gen; + } + @Override public boolean isNaturalFunction() { return true; } - - public static void setNoise(FastNoise gen) { - NoiseFunction3.gen = gen; - } - - public static FastNoise getNoise() { - return gen; - } } diff --git a/src/main/java/com/dfsek/terra/population/FaunaPopulator.java b/src/main/java/com/dfsek/terra/population/FaunaPopulator.java index a7672abee..1770fe96e 100644 --- a/src/main/java/com/dfsek/terra/population/FaunaPopulator.java +++ b/src/main/java/com/dfsek/terra/population/FaunaPopulator.java @@ -1,5 +1,7 @@ package com.dfsek.terra.population; +import com.dfsek.terra.Terra; +import com.dfsek.terra.TerraProfiler; import com.dfsek.terra.biome.TerraBiomeGrid; import org.bukkit.Chunk; import org.bukkit.World; @@ -7,6 +9,7 @@ import org.bukkit.block.Block; import org.bukkit.generator.BlockPopulator; import org.jetbrains.annotations.NotNull; import org.polydev.gaea.biome.Biome; +import org.polydev.gaea.profiler.ProfileFuture; import org.polydev.gaea.world.Fauna; import java.util.Random; @@ -14,16 +17,19 @@ import java.util.Random; public class FaunaPopulator extends BlockPopulator { @Override public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk chunk) { + ProfileFuture fauna = TerraProfiler.fromWorld(world).measure("FaunaTime"); for(int x = 0; x < 16; x++) { for(int z = 0; z < 16; z++) { Biome biome = TerraBiomeGrid.fromWorld(world).getBiome((chunk.getX() << 4) + x, (chunk.getZ() << 4) + z); if(biome.getDecorator().getFaunaChance() <= 0 || random.nextInt(100) > biome.getDecorator().getFaunaChance()) continue; - Block highest = Fauna.getHighestValidSpawnAt(chunk, x, z); + Fauna item = biome.getDecorator().getFauna().get(random); + Block highest = item.getHighestValidSpawnAt(chunk, x, z); try { - if(highest != null) biome.getDecorator().getFauna().get(random).plant(highest.getLocation()); + if(highest != null) item.plant(highest.getLocation()); } catch(NullPointerException ignored) {} } } + if(fauna!=null) fauna.complete(); } } diff --git a/src/main/java/com/dfsek/terra/population/TreePopulator.java b/src/main/java/com/dfsek/terra/population/TreePopulator.java index 602bd8ffb..ab8020c3c 100644 --- a/src/main/java/com/dfsek/terra/population/TreePopulator.java +++ b/src/main/java/com/dfsek/terra/population/TreePopulator.java @@ -1,6 +1,7 @@ package com.dfsek.terra.population; import com.dfsek.terra.Terra; +import com.dfsek.terra.TerraProfiler; import com.dfsek.terra.biome.TerraBiomeGrid; import com.dfsek.terra.biome.UserDefinedDecorator; import org.bukkit.Chunk; @@ -10,6 +11,7 @@ import org.jetbrains.annotations.NotNull; import org.polydev.gaea.biome.Biome; import org.polydev.gaea.population.GaeaBlockPopulator; import org.polydev.gaea.population.PopulationManager; +import org.polydev.gaea.profiler.ProfileFuture; import org.polydev.gaea.util.WorldUtil; import java.util.Random; @@ -22,6 +24,7 @@ public class TreePopulator extends GaeaBlockPopulator { @Override public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk chunk) { + ProfileFuture tree = TerraProfiler.fromWorld(world).measure("TreeGenTime"); int x = random.nextInt(16); // Decrease chances of chunk-crossing trees int z = random.nextInt(16); Location origin = chunk.getBlock(x, 0, z).getLocation(); @@ -41,5 +44,6 @@ public class TreePopulator extends GaeaBlockPopulator { x = random.nextInt(16); // Decrease chances of chunk-crossing trees z = random.nextInt(16); } + if(tree!=null) tree.complete(); } }