diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java b/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java index 6e556391d..b62ee3f40 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java @@ -173,7 +173,7 @@ public class CommandDeveloper implements DecreeExecutor { public void mca ( @Param(description = "String") World world) { try { - IrisWorldDump dump = new IrisWorldDump(world, sender(), IrisWorldDump.mode.PACKED); + IrisWorldDump dump = new IrisWorldDump(world, sender()); dump.start(); } catch (Exception e) { diff --git a/core/src/main/java/com/volmit/iris/core/tools/IrisNoiseBenchmark.java b/core/src/main/java/com/volmit/iris/core/tools/IrisNoiseBenchmark.java new file mode 100644 index 000000000..ef900432d --- /dev/null +++ b/core/src/main/java/com/volmit/iris/core/tools/IrisNoiseBenchmark.java @@ -0,0 +1,219 @@ +package com.volmit.iris.core.tools; + +import com.volmit.iris.Iris; +import com.volmit.iris.core.loader.IrisData; +import com.volmit.iris.core.project.IrisProject; +import com.volmit.iris.engine.object.*; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.decree.DecreeOrigin; +import com.volmit.iris.util.decree.annotations.Decree; +import com.volmit.iris.util.decree.annotations.Param; +import com.volmit.iris.util.format.C; +import com.volmit.iris.util.format.Form; +import com.volmit.iris.util.function.NoiseProvider; +import com.volmit.iris.util.interpolation.InterpolationMethod; +import com.volmit.iris.util.io.IO; +import com.volmit.iris.util.math.RNG; +import com.volmit.iris.util.noise.CNG; +import com.volmit.iris.util.plugin.VolmitSender; +import com.volmit.iris.util.scheduling.PrecisionStopwatch; + +import java.io.File; +import java.io.IOException; + +public class IrisNoiseBenchmark { + private IrisDimension dimension; + private VolmitSender sender; + + public IrisNoiseBenchmark(IrisDimension dimension, VolmitSender sender) { + this.dimension = dimension; + this.sender = sender; + } + + public void runAll() { + // Todo: Make this more accurate + File pack = dimension.getLoadFile().getParentFile().getParentFile(); + File report = Iris.instance.getDataFile("profile.txt"); + IrisProject project = new IrisProject(pack); + IrisData data = IrisData.get(pack); + + KList fileText = new KList<>(); + + KMap styleTimings = new KMap<>(); + KMap interpolatorTimings = new KMap<>(); + KMap generatorTimings = new KMap<>(); + KMap biomeTimings = new KMap<>(); + KMap regionTimings = new KMap<>(); + + sender.sendMessage("Calculating Performance Metrics for Noise generators"); + + for (NoiseStyle i : NoiseStyle.values()) { + CNG c = i.create(new RNG(i.hashCode())); + + for (int j = 0; j < 3000; j++) { + c.noise(j, j + 1000, j * j); + c.noise(j, -j); + } + + PrecisionStopwatch px = PrecisionStopwatch.start(); + + for (int j = 0; j < 100000; j++) { + c.noise(j, j + 1000, j * j); + c.noise(j, -j); + } + + styleTimings.put(i, px.getMilliseconds()); + } + + fileText.add("Noise Style Performance Impacts: "); + + for (NoiseStyle i : styleTimings.sortKNumber()) { + fileText.add(i.name() + ": " + styleTimings.get(i)); + } + + fileText.add(""); + + sender.sendMessage("Calculating Interpolator Timings..."); + + for (InterpolationMethod i : InterpolationMethod.values()) { + IrisInterpolator in = new IrisInterpolator(); + in.setFunction(i); + in.setHorizontalScale(8); + + NoiseProvider np = (x, z) -> Math.random(); + + for (int j = 0; j < 3000; j++) { + in.interpolate(j, -j, np); + } + + PrecisionStopwatch px = PrecisionStopwatch.start(); + + for (int j = 0; j < 100000; j++) { + in.interpolate(j + 10000, -j - 100000, np); + } + + interpolatorTimings.put(i, px.getMilliseconds()); + } + + fileText.add("Noise Interpolator Performance Impacts: "); + + for (InterpolationMethod i : interpolatorTimings.sortKNumber()) { + fileText.add(i.name() + ": " + interpolatorTimings.get(i)); + } + + fileText.add(""); + + sender.sendMessage("Processing Generator Scores: "); + + KMap> btx = new KMap<>(); + + for (String i : data.getGeneratorLoader().getPossibleKeys()) { + KList vv = new KList<>(); + IrisGenerator g = data.getGeneratorLoader().load(i); + KList composites = g.getAllComposites(); + double score = 0; + int m = 0; + for (IrisNoiseGenerator j : composites) { + m++; + score += styleTimings.get(j.getStyle().getStyle()); + vv.add("Composite Noise Style " + m + " " + j.getStyle().getStyle().name() + ": " + styleTimings.get(j.getStyle().getStyle())); + } + + score += interpolatorTimings.get(g.getInterpolator().getFunction()); + vv.add("Interpolator " + g.getInterpolator().getFunction().name() + ": " + interpolatorTimings.get(g.getInterpolator().getFunction())); + generatorTimings.put(i, score); + btx.put(i, vv); + } + + fileText.add("Project Generator Performance Impacts: "); + + for (String i : generatorTimings.sortKNumber()) { + fileText.add(i + ": " + generatorTimings.get(i)); + + btx.get(i).forEach((ii) -> fileText.add(" " + ii)); + } + + fileText.add(""); + + KMap> bt = new KMap<>(); + + for (String i : data.getBiomeLoader().getPossibleKeys()) { + KList vv = new KList<>(); + IrisBiome b = data.getBiomeLoader().load(i); + double score = 0; + + int m = 0; + for (IrisBiomePaletteLayer j : b.getLayers()) { + m++; + score += styleTimings.get(j.getStyle().getStyle()); + vv.add("Palette Layer " + m + ": " + styleTimings.get(j.getStyle().getStyle())); + } + + score += styleTimings.get(b.getBiomeStyle().getStyle()); + vv.add("Biome Style: " + styleTimings.get(b.getBiomeStyle().getStyle())); + score += styleTimings.get(b.getChildStyle().getStyle()); + vv.add("Child Style: " + styleTimings.get(b.getChildStyle().getStyle())); + biomeTimings.put(i, score); + bt.put(i, vv); + } + + fileText.add("Project Biome Performance Impacts: "); + + for (String i : biomeTimings.sortKNumber()) { + fileText.add(i + ": " + biomeTimings.get(i)); + + bt.get(i).forEach((ff) -> fileText.add(" " + ff)); + } + + fileText.add(""); + + for (String i : data.getRegionLoader().getPossibleKeys()) { + IrisRegion b = data.getRegionLoader().load(i); + double score = 0; + + score += styleTimings.get(b.getLakeStyle().getStyle()); + score += styleTimings.get(b.getRiverStyle().getStyle()); + regionTimings.put(i, score); + } + + fileText.add("Project Region Performance Impacts: "); + + for (String i : regionTimings.sortKNumber()) { + fileText.add(i + ": " + regionTimings.get(i)); + } + + fileText.add(""); + + double m = 0; + for (double i : biomeTimings.v()) { + m += i; + } + m /= biomeTimings.size(); + double mm = 0; + for (double i : generatorTimings.v()) { + mm += i; + } + mm /= generatorTimings.size(); + m += mm; + double mmm = 0; + for (double i : regionTimings.v()) { + mmm += i; + } + mmm /= regionTimings.size(); + m += mmm; + + fileText.add("Average Score: " + m); + sender.sendMessage("Score: " + Form.duration(m, 0)); + + try { + IO.writeAll(report, fileText.toString("\n")); + } catch (IOException e) { + Iris.reportError(e); + e.printStackTrace(); + } + + sender.sendMessage(C.GREEN + "Done! " + report.getPath()); + + } +} diff --git a/core/src/main/java/com/volmit/iris/core/tools/IrisWorldDump.java b/core/src/main/java/com/volmit/iris/core/tools/IrisWorldDump.java index 566a645f8..c6b8da0bf 100644 --- a/core/src/main/java/com/volmit/iris/core/tools/IrisWorldDump.java +++ b/core/src/main/java/com/volmit/iris/core/tools/IrisWorldDump.java @@ -5,7 +5,6 @@ import com.volmit.iris.core.IrisSettings; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; -import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.Form; import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.RollingSequence; @@ -15,6 +14,8 @@ import com.volmit.iris.util.nbt.mca.MCAUtil; import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.nbt.tag.StringTag; import com.volmit.iris.util.plugin.VolmitSender; +import lombok.Getter; +import lombok.Setter; import org.bukkit.World; import java.io.File; @@ -24,11 +25,11 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReferenceArray; public class IrisWorldDump { - private KList mcaList; - private KMap storage; + private KMap storage; private AtomicLong airStorage; private World world; private File MCADirectory; + private AtomicInteger threads; private AtomicInteger regionsProcessed; private AtomicInteger chunksProcessed; private AtomicInteger totalToProcess; @@ -41,7 +42,6 @@ public class IrisWorldDump { private ExecutorService executor; private ScheduledExecutorService scheduler; private AtomicLong startTime; - private mode mode; private File dumps; private File worldDump; private int mcaCacheSize; @@ -49,19 +49,17 @@ public class IrisWorldDump { private File blocks; private File structures; - public IrisWorldDump(World world, VolmitSender sender, mode mode) { + public IrisWorldDump(World world, VolmitSender sender) { sender.sendMessage("Initializing IrisWorldDump..."); this.world = world; this.sender = sender; this.MCADirectory = new File(world.getWorldFolder(), "region"); - this.totalMCAFiles = new AtomicInteger(MCACount()); this.dumps = new File("plugins" + File.separator + "iris", "dumps"); this.worldDump = new File(dumps, world.getName()); this.mcaCacheSize = IrisSettings.get().getWorldDump().mcaCacheSize; this.regionsProcessed = new AtomicInteger(0); this.chunksProcessed = new AtomicInteger(0); this.totalToProcess = new AtomicInteger(0); - this.totalMaxChunks = new AtomicInteger(totalMCAFiles.get() * 1024); this.chunksPerSecond = new RollingSequence(10); this.temp = new File(worldDump, "temp"); this.executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() - 1); @@ -69,9 +67,10 @@ public class IrisWorldDump { this.startTime = new AtomicLong(); this.storage = new KMap<>(); this.airStorage = new AtomicLong(0); + this.blocks = new File(worldDump, "blocks"); this.structures = new File(worldDump, "structures"); - initialize(); + try { this.engine = IrisToolbelt.access(world).getEngine(); this.IrisWorld = true; @@ -80,7 +79,9 @@ public class IrisWorldDump { } } - private void initialize() { + + public void start() { + if (!dumps.exists()) { if (!dumps.mkdirs()) { System.err.println("Failed to create dump directory."); @@ -88,59 +89,18 @@ public class IrisWorldDump { } } - if (worldDump.exists() && !worldDump.delete()) { - System.err.println("Failed to delete existing world dump directory."); - return; + try { + CompletableFuture mcaCount = CompletableFuture.supplyAsync(this::totalMcaFiles); + CompletableFuture chunkCount = CompletableFuture.supplyAsync(this::totalMCAChunks); + this.totalMCAFiles = new AtomicInteger(mcaCount.get()); + this.totalMaxChunks = new AtomicInteger(chunkCount.get()); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); } - - if (!worldDump.mkdir()) { - System.err.println("Failed to create world dump directory."); - return; - } - - if (!blocks.mkdir()) { - System.err.println("Failed to create blocks directory."); - return; - } - - if (!structures.mkdir()) { - System.err.println("Failed to create structures directory."); - return; - } - for (File mcaFile : MCADirectory.listFiles()) { - if (mcaFile.getName().endsWith(".mca")) { - totalToProcess.getAndIncrement(); - } - } - } - - public void start() { dump(); updater(); } - public enum mode { - RAW { - @Override - public void methodDump() { - - } - }, - DISK { - @Override - public void methodDump() { - - } - }, - PACKED { - @Override - public void methodDump() { - - } - }; - public abstract void methodDump(); - } - private void updater() { startTime.set(System.currentTimeMillis()); scheduler.scheduleAtFixedRate(() -> { @@ -156,6 +116,20 @@ public class IrisWorldDump { } + public class blockData { + @Getter + @Setter + private String block; + private int biome; + private int height; + + public blockData(String b, int bm, int h) { + this.block = b; + this.height = h; + this.biome = bm; + } + } + private void dump() { Iris.info("Starting the dump process."); @@ -189,6 +163,7 @@ public class IrisWorldDump { for (int z = 0; z < 16; z++) { for (int y = 0; y < CHUNK_HEIGHT; y++) { CompoundTag tag = chunk.getBlockStateAt(x, y, z); + int biome = chunk.getBiomeAt(x, y, z); if (tag == null) { String blockName = "minecraft:air"; //storage.compute(blockName, (key, count) -> (count == null) ? 1 : count + 1); @@ -197,7 +172,8 @@ public class IrisWorldDump { } else { StringTag nameTag = tag.getStringTag("Name"); String blockName = nameTag.getValue(); - storage.compute(blockName, (key, count) -> (count == null) ? 1 : count + 1); + blockData data = new blockData(blockName, biome, y); + storage.compute(data, (key, count) -> (count == null) ? 1 : count + 1); int ii = 0; } } @@ -209,7 +185,41 @@ public class IrisWorldDump { regionsProcessed.getAndIncrement(); } - private int MCACount() { + private int totalMCAChunks() { + AtomicInteger chunks = new AtomicInteger(); + CountDownLatch latch = new CountDownLatch(totalMcaFiles() * 1024); + for (File mcafile : MCADirectory.listFiles()) { + executor.submit(() -> { + try { + if (mcafile.getName().endsWith(".mca")) { + MCAFile mca = MCAUtil.read(mcafile); + for (int width = 0; width < 32; width++) { + for (int depth = 0; depth < 32; depth++) { + Chunk chunk = mca.getChunk(width, depth); + if (chunk != null) { + chunks.getAndIncrement(); + } + latch.countDown(); + } + } + } + } catch (Exception e) { + Iris.error("Failed to read mca file"); + e.printStackTrace(); + } + }); + } + + try { + latch.await(); + } catch (Exception e) { + e.printStackTrace(); + } + + return chunks.get(); + } + + private int totalMcaFiles() { int size = 0; for (File mca : MCADirectory.listFiles()) { if (mca.getName().endsWith(".mca")) { diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisBiome.java b/core/src/main/java/com/volmit/iris/engine/object/IrisBiome.java index d75dca7ad..669917ab2 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisBiome.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisBiome.java @@ -170,7 +170,6 @@ public class IrisBiome extends IrisRegistrant implements IRare { @Desc("Collection of ores to be generated") @ArrayType(type = IrisOreGenerator.class, min = 1) private KList ores = new KList<>(); - public BlockData generateOres(int x, int y, int z, RNG rng, IrisData data) { if (ores.isEmpty()) { return null;