From ad7a4503e0a7f17b855632ffb757c6e76cb0b587 Mon Sep 17 00:00:00 2001 From: Daniel Mills Date: Wed, 8 Jan 2020 13:50:43 -0500 Subject: [PATCH] Faster Schematic Placement --- src/main/java/ninja/bytecode/iris/Iris.java | 46 +++---- .../java/ninja/bytecode/iris/Settings.java | 7 +- .../iris/generator/IrisGenerator.java | 22 +--- .../generator/populator/ObjectPopulator.java | 121 ++++++++++++++++++ .../iris/schematic/SchematicGroup.java | 49 ++++++- .../bytecode/iris/spec/IrisDimension.java | 5 +- .../bytecode/iris/util/PerformanceMode.java | 1 + 7 files changed, 201 insertions(+), 50 deletions(-) create mode 100644 src/main/java/ninja/bytecode/iris/generator/populator/ObjectPopulator.java diff --git a/src/main/java/ninja/bytecode/iris/Iris.java b/src/main/java/ninja/bytecode/iris/Iris.java index ace1ac92a..506edb8f0 100644 --- a/src/main/java/ninja/bytecode/iris/Iris.java +++ b/src/main/java/ninja/bytecode/iris/Iris.java @@ -38,6 +38,7 @@ import ninja.bytecode.shuriken.collections.GMap; import ninja.bytecode.shuriken.collections.GSet; import ninja.bytecode.shuriken.execution.J; import ninja.bytecode.shuriken.execution.TaskExecutor; +import ninja.bytecode.shuriken.execution.TaskExecutor.TaskGroup; import ninja.bytecode.shuriken.format.F; import ninja.bytecode.shuriken.io.IO; import ninja.bytecode.shuriken.json.JSONException; @@ -49,7 +50,6 @@ public class Iris extends JavaPlugin implements Listener public static GSet refresh = new GSet<>(); public static Profiler profiler; public static TaskExecutor genPool; - public static TaskExecutor buildPool; public static IrisGenerator gen; public static Settings settings; public static Iris instance; @@ -60,7 +60,6 @@ public class Iris extends JavaPlugin implements Listener public void onEnable() { - PrecisionStopwatch stopwatch = PrecisionStopwatch.start(); Direction.calculatePermutations(); dimensions = new GMap<>(); biomes = new GMap<>(); @@ -69,19 +68,19 @@ public class Iris extends JavaPlugin implements Listener values = new GMap<>(); instance = this; settings = new Settings(); - buildPool = new TaskExecutor(getTC(), settings.performance.threadPriority, "Iris Compiler"); J.attempt(() -> createTempCache()); loadContent(); - processContent(); gen = new IrisGenerator(); genPool = new TaskExecutor(getTC(), settings.performance.threadPriority, "Iris Generator"); getServer().getPluginManager().registerEvents((Listener) this, this); getCommand("iris").setExecutor(new CommandIris()); getCommand("ish").setExecutor(new CommandIsh()); new WandManager(); + loadComplete(); + } - // Debug world regens - + private void loadComplete() + { if(settings.performance.loadonstart) { GSet ws = new GSet<>(); @@ -101,24 +100,6 @@ public class Iris extends JavaPlugin implements Listener Bukkit.unloadWorld(i, false); } } - - double ms = stopwatch.getMilliseconds(); - - J.a(() -> - { - J.sleep(5000); - L.i("Iris Startup Took " + F.duration(ms, 2)); - }); - } - - private void processContent() - { - L.v("Processing Content"); - - for(SchematicGroup i : schematics.v()) - { - i.processVariants(); - } } private static File internalResource(String resource) @@ -158,6 +139,7 @@ public class Iris extends JavaPlugin implements Listener private void loadContent() { + PrecisionStopwatch p = PrecisionStopwatch.start(); L.i("Loading Content"); try @@ -177,11 +159,23 @@ public class Iris extends JavaPlugin implements Listener { m += i.size(); } + + L.v("Processing Content"); + + TaskExecutor exf = new TaskExecutor(settings.performance.compilerThreads, settings.performance.compilerPriority, "Iris Compiler"); + TaskGroup gg = exf.startWork(); + for(SchematicGroup i : schematics.v()) + { + gg.queue(i::processVariants); + } + gg.execute(); + exf.close(); + L.i("Dimensions: " + dimensions.size()); L.i("Biomes: " + biomes.size()); L.i("Object Groups: " + schematics.size()); L.i("Objects: " + F.f(m)); - + L.i("Compilation Time: " + F.duration(p.getMilliseconds(), 2)); L.flush(); } @@ -195,6 +189,8 @@ public class Iris extends JavaPlugin implements Listener return Runtime.getRuntime().availableProcessors(); case SINGLE_THREADED: return 1; + case DOUBLE_CPU: + return Runtime.getRuntime().availableProcessors() * 2; case UNLIMITED: return -1; case EXPLICIT: diff --git a/src/main/java/ninja/bytecode/iris/Settings.java b/src/main/java/ninja/bytecode/iris/Settings.java index 6f4b46996..ac6e8e09a 100644 --- a/src/main/java/ninja/bytecode/iris/Settings.java +++ b/src/main/java/ninja/bytecode/iris/Settings.java @@ -9,11 +9,14 @@ public class Settings public static class PerformanceSettings { - public PerformanceMode performanceMode = PerformanceMode.MATCH_CPU; + public PerformanceMode performanceMode = PerformanceMode.DOUBLE_CPU; public int threadCount = 1; public int threadPriority = Thread.MIN_PRIORITY; - public boolean loadonstart = false; + public boolean loadonstart = true; public boolean fastPlacement = false; + public int compilerThreads = 4; + public int compilerPriority = Thread.MAX_PRIORITY; + public int decorationAccuracy = 3; } public static class GeneratorSettings diff --git a/src/main/java/ninja/bytecode/iris/generator/IrisGenerator.java b/src/main/java/ninja/bytecode/iris/generator/IrisGenerator.java index 74e01c2c5..ee31a7a75 100644 --- a/src/main/java/ninja/bytecode/iris/generator/IrisGenerator.java +++ b/src/main/java/ninja/bytecode/iris/generator/IrisGenerator.java @@ -20,8 +20,7 @@ import ninja.bytecode.iris.generator.layer.GenLayerOreGold; import ninja.bytecode.iris.generator.layer.GenLayerOreIron; import ninja.bytecode.iris.generator.layer.GenLayerOreLapis; import ninja.bytecode.iris.generator.layer.GenLayerRidge; -import ninja.bytecode.iris.generator.populator.BiomeBiasSchematicPopulator; -import ninja.bytecode.iris.schematic.Schematic; +import ninja.bytecode.iris.generator.populator.ObjectPopulator; import ninja.bytecode.iris.schematic.SchematicGroup; import ninja.bytecode.iris.spec.IrisBiome; import ninja.bytecode.iris.spec.IrisDimension; @@ -255,28 +254,13 @@ public class IrisGenerator extends ParallelChunkGenerator if(Iris.settings.gen.doSchematics) { - int b = 0; - int sch = 0; - for(IrisBiome i : IrisBiome.getAllBiomes().copy().add(dim.getBiomes())) - { - b++; - L.i("Processing Populators for Biome " + i.getName()); - - for(String j : i.getSchematicGroups().keySet()) - { - SchematicGroup gs = loadSchematics(j); - sch += gs.size(); - p.add(new BiomeBiasSchematicPopulator(i.getSchematicGroups().get(j), i, gs.getSchematics().toArray(new Schematic[gs.size()]))); - } - } - - L.i("Initialized " + b + " Biomes with " + p.size() + " Populators using " + sch + " Schematics"); + p.add(new ObjectPopulator(this)); } return p; } - private SchematicGroup loadSchematics(String folder) + public SchematicGroup loadSchematics(String folder) { return Iris.schematics.get(folder); } diff --git a/src/main/java/ninja/bytecode/iris/generator/populator/ObjectPopulator.java b/src/main/java/ninja/bytecode/iris/generator/populator/ObjectPopulator.java new file mode 100644 index 000000000..fe489f666 --- /dev/null +++ b/src/main/java/ninja/bytecode/iris/generator/populator/ObjectPopulator.java @@ -0,0 +1,121 @@ +package ninja.bytecode.iris.generator.populator; + +import java.util.Random; + +import org.bukkit.Chunk; +import org.bukkit.World; +import org.bukkit.block.Biome; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.generator.BlockPopulator; + +import ninja.bytecode.iris.Iris; +import ninja.bytecode.iris.generator.IrisGenerator; +import ninja.bytecode.iris.schematic.SchematicGroup; +import ninja.bytecode.iris.spec.IrisBiome; +import ninja.bytecode.shuriken.collections.GMap; +import ninja.bytecode.shuriken.collections.GSet; +import ninja.bytecode.shuriken.math.M; + +public class ObjectPopulator extends BlockPopulator +{ + private GMap biomeMap; + private GMap> populationCache; + + public ObjectPopulator(IrisGenerator generator) + { + biomeMap = new GMap<>(); + populationCache = new GMap<>(); + + for(IrisBiome i : generator.getLoadedBiomes()) + { + biomeMap.put(i.getRealBiome(), i); + + GMap gk = new GMap<>(); + + for(String j : i.getSchematicGroups().k()) + { + gk.put(Iris.schematics.get(j), i.getSchematicGroups().get(j)); + } + + populationCache.put(i.getRealBiome(), gk); + } + } + + @Override + public void populate(World world, Random random, Chunk source) + { + GSet hits = new GSet<>(); + + for(int i = 0; i < Iris.settings.performance.decorationAccuracy; i++) + { + int x = (source.getX() << 4) + random.nextInt(16); + int z = (source.getZ() << 4) + random.nextInt(16); + Biome biome = world.getBiome(x, z); + + if(hits.contains(biome)) + { + continue; + } + + IrisBiome ibiome = biomeMap.get(biome); + + if(ibiome == null) + { + continue; + } + + GMap objects = populationCache.get(biome); + + if(objects == null) + { + continue; + } + + hits.add(biome); + populate(world, random, source, biome, objects); + } + } + + private void populate(World world, Random random, Chunk source, Biome biome, GMap objects) + { + for(SchematicGroup i : objects.k()) + { + for(int j = 0; j < getTries(objects.get(i)); j++) + { + int x = (source.getX() << 4) + random.nextInt(16); + int z = (source.getZ() << 4) + random.nextInt(16); + Block b = world.getHighestBlockAt(x, z); + + if(!b.getRelative(BlockFace.DOWN).getType().isSolid()) + { + return; + } + + i.getSchematics().get(random.nextInt(i.getSchematics().size())).place(world, x, b.getY() - 1, z); + } + } + } + + public int getTries(double chance) + { + if(chance <= 0) + { + return 0; + } + + if(Math.floor(chance) == chance) + { + return (int) chance; + } + + int floor = (int) Math.floor(chance); + + if(chance - floor > 0 && M.r(chance - floor)) + { + floor++; + } + + return floor; + } +} diff --git a/src/main/java/ninja/bytecode/iris/schematic/SchematicGroup.java b/src/main/java/ninja/bytecode/iris/schematic/SchematicGroup.java index 0f4792b3a..36bff375a 100644 --- a/src/main/java/ninja/bytecode/iris/schematic/SchematicGroup.java +++ b/src/main/java/ninja/bytecode/iris/schematic/SchematicGroup.java @@ -7,6 +7,7 @@ import java.util.concurrent.locks.ReentrantLock; import ninja.bytecode.iris.Iris; import ninja.bytecode.iris.util.Direction; import ninja.bytecode.shuriken.collections.GList; +import ninja.bytecode.shuriken.execution.TaskExecutor; import ninja.bytecode.shuriken.execution.TaskExecutor.TaskGroup; import ninja.bytecode.shuriken.io.IO; import ninja.bytecode.shuriken.logging.L; @@ -122,9 +123,10 @@ public class SchematicGroup GList inject = new GList<>(); L.v("Processing " + name + " Objects"); L.v("# Creating Rotations for " + getSchematics().size() + " Objects"); - + String x = Thread.currentThread().getName(); ReentrantLock rr = new ReentrantLock(); - TaskGroup gg = Iris.buildPool.startWork(); + TaskExecutor ex = new TaskExecutor(Iris.settings.performance.compilerThreads, Iris.settings.performance.compilerPriority, x + "/Subroutine "); + TaskGroup gg = ex.startWork(); for(Schematic i : getSchematics()) { for(Direction j : new Direction[] {Direction.S, Direction.E, Direction.W}) @@ -142,7 +144,7 @@ public class SchematicGroup } gg.execute(); - gg = Iris.buildPool.startWork(); + gg = ex.startWork(); getSchematics().add(inject); L.v("# Generated " + inject.size() + " Rotated Objects to " + getName()); @@ -159,5 +161,46 @@ public class SchematicGroup } gg.execute(); + ex.close(); + } + + @Override + public int hashCode() + { + final int prime = 31; + int result = 1; + result = prime * result + ((flags == null) ? 0 : flags.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + priority; + return result; + } + + @Override + public boolean equals(Object obj) + { + if(this == obj) + return true; + if(obj == null) + return false; + if(getClass() != obj.getClass()) + return false; + SchematicGroup other = (SchematicGroup) obj; + if(flags == null) + { + if(other.flags != null) + return false; + } + else if(!flags.equals(other.flags)) + return false; + if(name == null) + { + if(other.name != null) + return false; + } + else if(!name.equals(other.name)) + return false; + if(priority != other.priority) + return false; + return true; } } diff --git a/src/main/java/ninja/bytecode/iris/spec/IrisDimension.java b/src/main/java/ninja/bytecode/iris/spec/IrisDimension.java index 2e34f7b44..d441559ed 100644 --- a/src/main/java/ninja/bytecode/iris/spec/IrisDimension.java +++ b/src/main/java/ninja/bytecode/iris/spec/IrisDimension.java @@ -8,6 +8,7 @@ import org.bukkit.World.Environment; import ninja.bytecode.iris.Iris; import ninja.bytecode.shuriken.collections.GList; import ninja.bytecode.shuriken.execution.J; +import ninja.bytecode.shuriken.execution.TaskExecutor; import ninja.bytecode.shuriken.execution.TaskExecutor.TaskGroup; import ninja.bytecode.shuriken.json.JSONArray; import ninja.bytecode.shuriken.json.JSONException; @@ -74,7 +75,8 @@ public class IrisDimension private GList biomesFromArray(JSONArray a) throws JSONException, IOException { GList b = new GList<>(); - TaskGroup g = Iris.buildPool.startWork(); + TaskExecutor ex= new TaskExecutor(Iris.settings.performance.compilerThreads, Iris.settings.performance.compilerPriority, "Iris Dim Compiler"); + TaskGroup g = ex.startWork(); ReentrantLock lock = new ReentrantLock(); for(int i = 0; i < a.length(); i++) @@ -90,6 +92,7 @@ public class IrisDimension } g.execute(); + ex.close(); return b; } diff --git a/src/main/java/ninja/bytecode/iris/util/PerformanceMode.java b/src/main/java/ninja/bytecode/iris/util/PerformanceMode.java index e2acaa934..3dfc3279f 100644 --- a/src/main/java/ninja/bytecode/iris/util/PerformanceMode.java +++ b/src/main/java/ninja/bytecode/iris/util/PerformanceMode.java @@ -5,6 +5,7 @@ public enum PerformanceMode SINGLE_THREADED, UNLIMITED, MATCH_CPU, + DOUBLE_CPU, HALF_CPU, EXPLICIT, }