From 6873051bcb23b2195eb551885fc695bd610f9780 Mon Sep 17 00:00:00 2001 From: cyberpwn Date: Tue, 28 Jun 2022 03:47:23 -0400 Subject: [PATCH] Actually decent --- .../iris/platform/bukkit/IrisBukkit.java | 39 ++++++++++ .../bukkit/IrisBukkitChunkGenerator.java | 22 +++--- .../bukkit/util/ChunkDataHunkView.java | 4 +- .../engine/{IrisEngine.java => Engine.java} | 12 ++-- .../volmit/iris/engine/EngineBlockCache.java | 4 +- .../volmit/iris/engine/EngineExecutor.java | 6 +- .../iris/engine/feature/IrisFeature.java | 18 ++--- .../feature/IrisFeatureSizedTarget.java | 20 ++++-- .../engine/feature/IrisFeatureTarget.java | 14 ++-- .../iris/engine/feature/IrisFeatureTask.java | 44 +++++++++--- .../engine/feature/IrisFeatureTaskTiming.java | 6 ++ .../engine/feature/IrisPreparedFeature.java | 14 ++-- .../feature/features/FeatureTerrain.java | 20 ++++-- .../optimizer/HunkSlizeConfiguration.java | 58 +++++++++++++++ .../optimizer/IrisOptimizationAttempt.java | 37 ++++++++++ .../iris/engine/optimizer/IrisOptimizer.java | 72 +++++++++++++++++++ .../iris/engine/pipeline/EnginePipeline.java | 6 +- .../iris/engine/pipeline/EnginePlumbing.java | 8 +-- .../iris/engine/pipeline/PipedHunkStack.java | 10 +-- .../iris/engine/pipeline/PipelinePhase.java | 21 ++---- .../iris/engine/pipeline/PipelineTask.java | 34 +++++++-- 21 files changed, 364 insertions(+), 105 deletions(-) rename engine/src/main/java/com/volmit/iris/engine/{IrisEngine.java => Engine.java} (80%) create mode 100644 engine/src/main/java/com/volmit/iris/engine/feature/IrisFeatureTaskTiming.java create mode 100644 engine/src/main/java/com/volmit/iris/engine/optimizer/HunkSlizeConfiguration.java create mode 100644 engine/src/main/java/com/volmit/iris/engine/optimizer/IrisOptimizationAttempt.java create mode 100644 engine/src/main/java/com/volmit/iris/engine/optimizer/IrisOptimizer.java diff --git a/bukkit/src/main/java/com/volmit/iris/platform/bukkit/IrisBukkit.java b/bukkit/src/main/java/com/volmit/iris/platform/bukkit/IrisBukkit.java index 0a88f4aed..8b9fbff81 100644 --- a/bukkit/src/main/java/com/volmit/iris/platform/bukkit/IrisBukkit.java +++ b/bukkit/src/main/java/com/volmit/iris/platform/bukkit/IrisBukkit.java @@ -1,5 +1,6 @@ package com.volmit.iris.platform.bukkit; +import art.arcane.amulet.io.IO; import com.volmit.iris.engine.EngineConfiguration; import com.volmit.iris.platform.IrisPlatform; import com.volmit.iris.platform.PlatformBiome; @@ -14,9 +15,13 @@ import org.bukkit.Material; import org.bukkit.World; import org.bukkit.WorldCreator; import org.bukkit.block.Biome; +import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; import org.bukkit.plugin.java.JavaPlugin; +import java.io.Closeable; +import java.io.File; +import java.io.IOException; import java.util.Arrays; import java.util.UUID; import java.util.stream.Stream; @@ -30,11 +35,45 @@ public class IrisBukkit extends JavaPlugin implements IrisPlatform { getServer().getScheduler().scheduleSyncDelayedTask(this, () -> { World world = Bukkit.createWorld(new WorldCreator("iristests/" + UUID.randomUUID()).generator(new IrisBukkitChunkGenerator(this, EngineConfiguration.builder() .build()))); + for(Player i : Bukkit.getOnlinePlayers()) + { + i.teleport(world.getSpawnLocation()); + } }, 10); } public void onDisable() { + World w = null; + for(World i : Bukkit.getWorlds()) { + if(!i.getName().startsWith("iristest")) { + w = i; + break; + } + } + for(World i : Bukkit.getWorlds()) { + if(i.getName().startsWith("iristest")) + { + for(Player j : i.getPlayers()) + { + j.teleport(w.getSpawnLocation()); + } + + if(i.getGenerator() instanceof Closeable c) + { + try { + c.close(); + } catch(IOException e) { + throw new RuntimeException(e); + } + } + + i.bukkitWorld().unloadChunks(false, true); + File folder = i.getWorldFolder(); + Bukkit.unloadWorld(i, false); + IO.delete(folder); + } + } } public static IrisBukkit getInstance() { diff --git a/bukkit/src/main/java/com/volmit/iris/platform/bukkit/IrisBukkitChunkGenerator.java b/bukkit/src/main/java/com/volmit/iris/platform/bukkit/IrisBukkitChunkGenerator.java index 6bc862824..fda561617 100644 --- a/bukkit/src/main/java/com/volmit/iris/platform/bukkit/IrisBukkitChunkGenerator.java +++ b/bukkit/src/main/java/com/volmit/iris/platform/bukkit/IrisBukkitChunkGenerator.java @@ -4,10 +4,9 @@ import art.arcane.amulet.collections.hunk.Hunk; import art.arcane.amulet.metric.Average; import art.arcane.amulet.metric.PrecisionStopwatch; import com.volmit.iris.engine.EngineConfiguration; -import com.volmit.iris.engine.IrisEngine; +import com.volmit.iris.engine.Engine; import com.volmit.iris.engine.feature.IrisFeatureSizedTarget; import com.volmit.iris.engine.feature.IrisFeatureTarget; -import com.volmit.iris.engine.feature.features.FeatureTerrain; import com.volmit.iris.engine.pipeline.PipedHunkStack; import com.volmit.iris.platform.IrisPlatform; import com.volmit.iris.platform.PlatformBlock; @@ -16,16 +15,17 @@ import org.bukkit.World; import org.bukkit.generator.ChunkGenerator; import com.volmit.iris.platform.bukkit.util.ChunkDataHunkView; -import java.nio.channels.Pipe; +import java.io.Closeable; +import java.io.IOException; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.ReentrantLock; -public class IrisBukkitChunkGenerator extends ChunkGenerator { +public class IrisBukkitChunkGenerator extends ChunkGenerator implements Closeable { private final IrisPlatform platform; private final EngineConfiguration configuration; - private final AtomicReference engine; + private final AtomicReference engine; private final ReentrantLock engineLock; private final AtomicInteger perSecond; private final PrecisionStopwatch p = PrecisionStopwatch.start(); @@ -46,8 +46,6 @@ public class IrisBukkitChunkGenerator extends ChunkGenerator { initEngine(world); ChunkData data = Bukkit.createChunkData(world); Hunk chunk = new ChunkDataHunkView(data); - PipedHunkStack stack = new PipedHunkStack(); - stack.register(PlatformBlock.class, chunk); IrisFeatureSizedTarget targetSize = IrisFeatureSizedTarget.builder() .width(chunk.getWidth()) .height(chunk.getHeight()) @@ -56,6 +54,9 @@ public class IrisBukkitChunkGenerator extends ChunkGenerator { .offsetZ(z << 4) .offsetY(0) .build(); + IrisFeatureTarget blockTarget = new IrisFeatureTarget<>(chunk, targetSize); + PipedHunkStack stack = new PipedHunkStack(); + stack.register(PlatformBlock.class, blockTarget); engine.get().getPlumbing().generate(engine.get(), targetSize, stack); perSecond.incrementAndGet(); a.put(pp.getMilliseconds()); @@ -77,7 +78,7 @@ public class IrisBukkitChunkGenerator extends ChunkGenerator { if(engine.get() == null) { - engine.set(new IrisEngine(platform, world.bukkitWorld(), configuration)); + engine.set(new Engine(platform, world.bukkitWorld(), configuration)); } engineLock.unlock(); @@ -88,4 +89,9 @@ public class IrisBukkitChunkGenerator extends ChunkGenerator { public boolean canSpawn(World world, int x, int z) { return false; } + + @Override + public void close() throws IOException { + engine.get().close(); + } } diff --git a/bukkit/src/main/java/com/volmit/iris/platform/bukkit/util/ChunkDataHunkView.java b/bukkit/src/main/java/com/volmit/iris/platform/bukkit/util/ChunkDataHunkView.java index 525c45f66..2ba7dad4b 100644 --- a/bukkit/src/main/java/com/volmit/iris/platform/bukkit/util/ChunkDataHunkView.java +++ b/bukkit/src/main/java/com/volmit/iris/platform/bukkit/util/ChunkDataHunkView.java @@ -29,7 +29,7 @@ public class ChunkDataHunkView implements Hunk { } @Override - public void set(int x1, int y1, int z1, int x2, int y2, int z2, PlatformBlock t) { + public synchronized void set(int x1, int y1, int z1, int x2, int y2, int z2, PlatformBlock t) { if(t == null) { return; } @@ -38,7 +38,7 @@ public class ChunkDataHunkView implements Hunk { } @Override - public void setRaw(int x, int y, int z, PlatformBlock t) { + public synchronized void setRaw(int x, int y, int z, PlatformBlock t) { if(t == null) { return; } diff --git a/engine/src/main/java/com/volmit/iris/engine/IrisEngine.java b/engine/src/main/java/com/volmit/iris/engine/Engine.java similarity index 80% rename from engine/src/main/java/com/volmit/iris/engine/IrisEngine.java rename to engine/src/main/java/com/volmit/iris/engine/Engine.java index 884884edd..20fe4f711 100644 --- a/engine/src/main/java/com/volmit/iris/engine/IrisEngine.java +++ b/engine/src/main/java/com/volmit/iris/engine/Engine.java @@ -20,8 +20,8 @@ import java.util.Map; import java.util.Optional; @Data -public class IrisEngine implements Closeable { - private static final Map> engineContext = new ConcurrentWeakHashMap<>(); +public class Engine implements Closeable { + private static final Map> engineContext = new ConcurrentWeakHashMap<>(); private final IrisPlatform platform; private final EngineRegistry registry; private final EngineConfiguration configuration; @@ -30,7 +30,7 @@ public class IrisEngine implements Closeable { private final EngineExecutor executor; private final EnginePlumbing plumbing; - public IrisEngine(IrisPlatform platform, PlatformWorld world, EngineConfiguration configuration) { + public Engine(IrisPlatform platform, PlatformWorld world, EngineConfiguration configuration) { this.configuration = configuration; this.platform = platform; this.world = world; @@ -43,7 +43,7 @@ public class IrisEngine implements Closeable { this.plumbing = EnginePlumbing.builder().engine(this) .pipeline(EnginePipeline.builder() .phase(PipelinePhase.builder() - .task(PipelineTask.builder().target(PlatformBlock.class).feature(new FeatureTerrain(this)).build()) + .task(new PipelineTask<>(new FeatureTerrain(this), PlatformBlock.class)) .build()) .build()) .build(); @@ -59,9 +59,9 @@ public class IrisEngine implements Closeable { return getPlatform().key(nsk); } - public static Optional context() + public static Optional context() { - WeakReference reference = engineContext.get(Thread.currentThread()); + WeakReference reference = engineContext.get(Thread.currentThread()); if(reference != null) { diff --git a/engine/src/main/java/com/volmit/iris/engine/EngineBlockCache.java b/engine/src/main/java/com/volmit/iris/engine/EngineBlockCache.java index b00519e13..6dc2045e0 100644 --- a/engine/src/main/java/com/volmit/iris/engine/EngineBlockCache.java +++ b/engine/src/main/java/com/volmit/iris/engine/EngineBlockCache.java @@ -7,10 +7,10 @@ import java.util.concurrent.ConcurrentHashMap; public class EngineBlockCache { - private final IrisEngine engine; + private final Engine engine; private final Map cache; - public EngineBlockCache(IrisEngine engine) + public EngineBlockCache(Engine engine) { this.engine = engine; this.cache = new ConcurrentHashMap<>(); diff --git a/engine/src/main/java/com/volmit/iris/engine/EngineExecutor.java b/engine/src/main/java/com/volmit/iris/engine/EngineExecutor.java index f1cec4a01..382edc9a2 100644 --- a/engine/src/main/java/com/volmit/iris/engine/EngineExecutor.java +++ b/engine/src/main/java/com/volmit/iris/engine/EngineExecutor.java @@ -9,13 +9,13 @@ import java.util.concurrent.ForkJoinWorkerThread; @Data public class EngineExecutor implements ForkJoinPool.ForkJoinWorkerThreadFactory, Thread.UncaughtExceptionHandler, Closeable { - private final IrisEngine engine; + private final Engine engine; private final ForkJoinPool forks; - public EngineExecutor(IrisEngine engine) + public EngineExecutor(Engine engine) { this.engine = engine; - forks = new ForkJoinPool(engine.getConfiguration().getThreads(), this, this, false); + forks = new ForkJoinPool(engine.getConfiguration().getThreads(), this, this, true); } @Override diff --git a/engine/src/main/java/com/volmit/iris/engine/feature/IrisFeature.java b/engine/src/main/java/com/volmit/iris/engine/feature/IrisFeature.java index d2f5eb238..dda45969c 100644 --- a/engine/src/main/java/com/volmit/iris/engine/feature/IrisFeature.java +++ b/engine/src/main/java/com/volmit/iris/engine/feature/IrisFeature.java @@ -1,33 +1,33 @@ package com.volmit.iris.engine.feature; -import com.volmit.iris.engine.IrisEngine; +import com.volmit.iris.engine.Engine; import com.volmit.iris.platform.PlatformNamespaced; import lombok.Data; @Data public abstract class IrisFeature { private final String name; - private final IrisEngine engine; + private final Engine engine; private boolean heightAgnostic; - public IrisFeature(String name, IrisEngine engine) + public IrisFeature(String name, Engine engine) { this.engine = engine; this.name = name; this.heightAgnostic = true; } - public IrisFeatureTask task(IrisFeatureSizedTarget target, int verticalExecutionSize, int horizontalExecutionSize) + public IrisFeatureTask task(IrisFeatureSizedTarget target, IrisFeatureTarget origin, int verticalExecutionSize, int horizontalExecutionSize, IrisFeatureTaskTiming timings) { - return new IrisFeatureTask<>(engine, this, target, verticalExecutionSize, horizontalExecutionSize, heightAgnostic); + return new IrisFeatureTask<>(engine, this, target, origin, verticalExecutionSize, horizontalExecutionSize, heightAgnostic, timings); } - public IrisFeatureTask task(IrisFeatureSizedTarget target, int horizontalExecutionSize) + public IrisFeatureTask task(IrisFeatureSizedTarget target, IrisFeatureTarget origin, int horizontalExecutionSize, IrisFeatureTaskTiming timings) { - return new IrisFeatureTask<>(engine, this, target, Integer.MAX_VALUE, horizontalExecutionSize, heightAgnostic); + return new IrisFeatureTask<>(engine, this, target, origin, Integer.MAX_VALUE, horizontalExecutionSize, heightAgnostic, timings); } - public abstract S prepare(IrisEngine engine, IrisFeatureSizedTarget target); + public abstract S prepare(Engine engine, IrisFeatureSizedTarget target); - public abstract void generate(IrisEngine engine, S state, IrisFeatureTarget target); + public abstract void generate(Engine engine, S state, IrisFeatureTarget target); } diff --git a/engine/src/main/java/com/volmit/iris/engine/feature/IrisFeatureSizedTarget.java b/engine/src/main/java/com/volmit/iris/engine/feature/IrisFeatureSizedTarget.java index b3953fdea..b397525dc 100644 --- a/engine/src/main/java/com/volmit/iris/engine/feature/IrisFeatureSizedTarget.java +++ b/engine/src/main/java/com/volmit/iris/engine/feature/IrisFeatureSizedTarget.java @@ -2,6 +2,7 @@ package com.volmit.iris.engine.feature; import art.arcane.amulet.collections.hunk.Hunk; import art.arcane.amulet.collections.hunk.storage.ArrayHunk; +import art.arcane.amulet.collections.hunk.view.HunkView; import art.arcane.amulet.geometry.Vec; import art.arcane.amulet.range.IntegerRange; import com.volmit.iris.platform.PlatformNamespaced; @@ -37,6 +38,11 @@ public class IrisFeatureSizedTarget { return new IrisFeatureTarget<>(new ArrayHunk<>(width, height, depth), this); } + public IrisFeatureTarget hunked(IrisFeatureTarget origin) + { + return new IrisFeatureTarget<>(new HunkView<>(origin.getHunk(), width, height, depth, offsetX - origin.getOffsetX(), offsetY - origin.getOffsetY(), offsetZ - origin.getOffsetZ()), this); + } + Stream splitX() { if(width <= 1) { return Stream.of(this); @@ -121,15 +127,15 @@ public class IrisFeatureSizedTarget { return new IntegerRange(0, getDepth() - 1); } - public static IrisFeatureSizedTarget mergedSize(Stream targets) { + public static IrisFeatureSizedTarget mergedSize(Stream targets, boolean x, boolean y, boolean z) { List t = targets.toList(); return IrisFeatureSizedTarget.builder() - .width(t.stream().mapToInt(IrisFeatureSizedTarget::getWidth).sum()) - .height(t.stream().mapToInt(IrisFeatureSizedTarget::getHeight).sum()) - .depth(t.stream().mapToInt(IrisFeatureSizedTarget::getDepth).sum()) - .offsetX(t.stream().mapToInt(IrisFeatureSizedTarget::getOffsetX).min().orElse(0)) - .offsetY(t.stream().mapToInt(IrisFeatureSizedTarget::getOffsetY).min().orElse(0)) - .offsetZ(t.stream().mapToInt(IrisFeatureSizedTarget::getOffsetZ).min().orElse(0)) + .width(x ? t.stream().mapToInt(IrisFeatureSizedTarget::getWidth).sum() : t[0].getWidth()) + .height(y ? t.stream().mapToInt(IrisFeatureSizedTarget::getHeight).sum() : t[0].getHeight()) + .depth(z ? t.stream().mapToInt(IrisFeatureSizedTarget::getDepth).sum() : t[0].getDepth()) + .offsetX(x ? t.stream().mapToInt(IrisFeatureSizedTarget::getOffsetX).min().orElse(0) : t[0].getOffsetX()) + .offsetY(y ? t.stream().mapToInt(IrisFeatureSizedTarget::getOffsetY).min().orElse(0) : t[0].getOffsetY()) + .offsetZ(z ? t.stream().mapToInt(IrisFeatureSizedTarget::getOffsetZ).min().orElse(0) : t[0].getOffsetZ()) .build(); } } diff --git a/engine/src/main/java/com/volmit/iris/engine/feature/IrisFeatureTarget.java b/engine/src/main/java/com/volmit/iris/engine/feature/IrisFeatureTarget.java index 25417e5bc..54aa1722b 100644 --- a/engine/src/main/java/com/volmit/iris/engine/feature/IrisFeatureTarget.java +++ b/engine/src/main/java/com/volmit/iris/engine/feature/IrisFeatureTarget.java @@ -1,6 +1,7 @@ package com.volmit.iris.engine.feature; import art.arcane.amulet.collections.hunk.Hunk; +import art.arcane.amulet.collections.hunk.view.HunkView; import com.volmit.iris.platform.PlatformNamespaced; import lombok.AllArgsConstructor; import lombok.Builder; @@ -28,15 +29,14 @@ public class IrisFeatureTarget extends IrisFeature this(hunk, target.getOffsetX(), target.getOffsetY(), target.getOffsetZ()); } - public static IrisFeatureTarget mergedTarget(Stream> targets) + public static IrisFeatureTarget mergedTarget(Stream> targets, IrisFeatureTarget origin, boolean x, boolean y, boolean z) { List> t = targets.toList(); - IrisFeatureSizedTarget mergedSize = IrisFeatureSizedTarget.mergedSize(t.stream().map(i -> i)); - Hunk hunk = Hunk.newArrayHunk(mergedSize.getWidth(), mergedSize.getHeight(), mergedSize.getDepth()); - t.forEach(i -> hunk.insert( - i.getOffsetX() - mergedSize.getOffsetX(), - i.getOffsetY() - mergedSize.getOffsetY(), - i.getOffsetZ() - mergedSize.getOffsetZ(), i.getHunk())); + IrisFeatureSizedTarget mergedSize = IrisFeatureSizedTarget.mergedSize(t.stream().map(i -> i), x, y, z); + Hunk hunk = new HunkView<>(origin.getHunk(), mergedSize.getWidth(), mergedSize.getHeight(), mergedSize.getDepth(), + mergedSize.getOffsetX() - origin.getOffsetX(), + mergedSize.getOffsetY() - origin.getOffsetY(), + mergedSize.getOffsetZ() - origin.getOffsetZ()); return new IrisFeatureTarget<>(hunk, mergedSize); } } diff --git a/engine/src/main/java/com/volmit/iris/engine/feature/IrisFeatureTask.java b/engine/src/main/java/com/volmit/iris/engine/feature/IrisFeatureTask.java index e76cadc44..5ff5c96a5 100644 --- a/engine/src/main/java/com/volmit/iris/engine/feature/IrisFeatureTask.java +++ b/engine/src/main/java/com/volmit/iris/engine/feature/IrisFeatureTask.java @@ -1,14 +1,14 @@ package com.volmit.iris.engine.feature; -import art.arcane.amulet.collections.hunk.Hunk; -import com.volmit.iris.engine.IrisEngine; +import art.arcane.amulet.metric.PrecisionStopwatch; +import com.volmit.iris.engine.Engine; import com.volmit.iris.platform.PlatformNamespaced; import lombok.AllArgsConstructor; import lombok.Builder; import java.util.concurrent.Callable; +import java.util.concurrent.ForkJoinTask; import java.util.concurrent.RecursiveTask; -import java.util.stream.Collectors; /** * Continuously splits up a hunk of work in all 3 dimensions until the job size is within the @@ -19,34 +19,58 @@ import java.util.stream.Collectors; @Builder @AllArgsConstructor public class IrisFeatureTask extends RecursiveTask> implements Callable> { - private final IrisEngine engine; + private final Engine engine; private final IrisFeature feature; private final IrisFeatureSizedTarget size; + private final IrisFeatureTarget origin; private final int verticalPrepareSize; private final int horizontalPrepareSize; private final boolean heightAgnostic; + private final IrisFeatureTaskTiming timings; @Override protected IrisFeatureTarget compute() { + IrisFeatureTarget result; + PrecisionStopwatch p = null; + + if(timings != null) + { + p = PrecisionStopwatch.start(); + } + if(!heightAgnostic && size.getHeight() > verticalPrepareSize * 2) { - return IrisFeatureTarget.mergedTarget(size.splitY().map(i -> engine.getExecutor().getForks().invoke(with(i)))); + + result = IrisFeatureTarget.mergedTarget(size.splitY() + .map(i -> engine.getExecutor().getForks().submit((ForkJoinTask>) with(i))) + .map(ForkJoinTask::join), origin, false, true, false); } else if(size.getWidth() > horizontalPrepareSize * 2) { - return IrisFeatureTarget.mergedTarget(size.splitX().map(i -> engine.getExecutor().getForks().invoke(with(i)))); + result = IrisFeatureTarget.mergedTarget(size.splitX().map(i -> engine.getExecutor().getForks().submit((ForkJoinTask>) with(i))) + .map(ForkJoinTask::join), origin, true, false, false); } else if(size.getDepth() > horizontalPrepareSize * 2) { - return IrisFeatureTarget.mergedTarget(size.splitZ().map(i -> engine.getExecutor().getForks().invoke(with(i)))); + result = IrisFeatureTarget.mergedTarget(size.splitZ().map(i -> engine.getExecutor().getForks().submit((ForkJoinTask>) with(i))) + .map(ForkJoinTask::join), origin, false, false, true); } - IrisPreparedFeature preparedFeature = new IrisPreparedFeature<>(engine, feature, size, feature.prepare(engine, size)); - return preparedFeature.generate(); + else { + IrisPreparedFeature preparedFeature = new IrisPreparedFeature<>(engine, feature, size, feature.prepare(engine, size)); + result = preparedFeature.generate(origin); + } + + if(timings != null) + { + timings.onCompleted(p.getMilliseconds()); + } + + return result; } private IrisFeatureTask with(IrisFeatureSizedTarget size) { - return new IrisFeatureTask<>(engine, feature, size, verticalPrepareSize, horizontalPrepareSize, heightAgnostic); + return new IrisFeatureTask<>(engine, feature, size, origin, verticalPrepareSize, horizontalPrepareSize, heightAgnostic, null); } @Override diff --git a/engine/src/main/java/com/volmit/iris/engine/feature/IrisFeatureTaskTiming.java b/engine/src/main/java/com/volmit/iris/engine/feature/IrisFeatureTaskTiming.java new file mode 100644 index 000000000..14a5d6b96 --- /dev/null +++ b/engine/src/main/java/com/volmit/iris/engine/feature/IrisFeatureTaskTiming.java @@ -0,0 +1,6 @@ +package com.volmit.iris.engine.feature; + +@FunctionalInterface +public interface IrisFeatureTaskTiming { + void onCompleted(double ms); +} diff --git a/engine/src/main/java/com/volmit/iris/engine/feature/IrisPreparedFeature.java b/engine/src/main/java/com/volmit/iris/engine/feature/IrisPreparedFeature.java index ee2665b9d..9d36b4d3c 100644 --- a/engine/src/main/java/com/volmit/iris/engine/feature/IrisPreparedFeature.java +++ b/engine/src/main/java/com/volmit/iris/engine/feature/IrisPreparedFeature.java @@ -1,6 +1,6 @@ package com.volmit.iris.engine.feature; -import com.volmit.iris.engine.IrisEngine; +import com.volmit.iris.engine.Engine; import com.volmit.iris.platform.PlatformNamespaced; import lombok.Builder; import lombok.Data; @@ -8,19 +8,15 @@ import lombok.Data; @Builder @Data public class IrisPreparedFeature { - private final IrisEngine engine; + private final Engine engine; private final IrisFeature feature; private final IrisFeatureSizedTarget size; private final S state; - public IrisFeatureTarget generate() + public IrisFeatureTarget generate(IrisFeatureTarget origin) { - IrisFeatureTarget target = size.hunked(); - - if(Math.r(0.25)) - { - feature.generate(engine, state, target); - } + IrisFeatureTarget target = size.hunked(origin); + feature.generate(engine, state, target); return target; } diff --git a/engine/src/main/java/com/volmit/iris/engine/feature/features/FeatureTerrain.java b/engine/src/main/java/com/volmit/iris/engine/feature/features/FeatureTerrain.java index 732fea9fa..41e308205 100644 --- a/engine/src/main/java/com/volmit/iris/engine/feature/features/FeatureTerrain.java +++ b/engine/src/main/java/com/volmit/iris/engine/feature/features/FeatureTerrain.java @@ -1,9 +1,13 @@ package com.volmit.iris.engine.feature.features; import art.arcane.amulet.range.IntegerRange; +import art.arcane.source.api.NoisePlane; +import art.arcane.source.api.fractal.FractalFBMProvider; +import art.arcane.source.api.interpolator.StarcastInterpolator; import art.arcane.source.api.noise.Generator; +import art.arcane.source.api.noise.provider.CellularProvider; import art.arcane.source.api.noise.provider.SimplexProvider; -import com.volmit.iris.engine.IrisEngine; +import com.volmit.iris.engine.Engine; import com.volmit.iris.engine.feature.IrisFeature; import com.volmit.iris.engine.feature.IrisFeatureSizedTarget; import com.volmit.iris.engine.feature.IrisFeatureState; @@ -16,20 +20,22 @@ import lombok.Data; public class FeatureTerrain extends IrisFeature { private final PlatformBlock stone; - private final Generator generator; + private final NoisePlane generator; - public FeatureTerrain(IrisEngine engine) + public FeatureTerrain(Engine engine) { super("terrain", engine); stone = engine.block("stone"); - this.generator = new Generator(new SimplexProvider(engine.getWorld().getSeed())) + Generator g = new Generator(new FractalFBMProvider((s) -> new CellularProvider(s), 1234)); + g.scale(0.01); + this.generator = new StarcastInterpolator(new Generator(new SimplexProvider(engine.getWorld().getSeed())) .maxOutput(64) .minOutput(0) - .scale(0.01); + .scale(0.01).warp(g), 8, 96); } @Override - public TerrainFeatureState prepare(IrisEngine engine, IrisFeatureSizedTarget target) { + public TerrainFeatureState prepare(Engine engine, IrisFeatureSizedTarget target) { final ShortNoiseCache noise = new ShortNoiseCache(target.getWidth(), target.getDepth()); int cx,cz; @@ -48,7 +54,7 @@ public class FeatureTerrain extends IrisFeature target) { + public void generate(Engine engine, TerrainFeatureState state, IrisFeatureTarget target) { for(int x : target.localX()) { for(int z : target.localZ()) { int h = state.getNoise().get(x, z); diff --git a/engine/src/main/java/com/volmit/iris/engine/optimizer/HunkSlizeConfiguration.java b/engine/src/main/java/com/volmit/iris/engine/optimizer/HunkSlizeConfiguration.java new file mode 100644 index 000000000..20533a751 --- /dev/null +++ b/engine/src/main/java/com/volmit/iris/engine/optimizer/HunkSlizeConfiguration.java @@ -0,0 +1,58 @@ +package com.volmit.iris.engine.optimizer; + +import art.arcane.amulet.range.IntegerRange; +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +@Data +@AllArgsConstructor +public class HunkSlizeConfiguration { + private final int verticalSlice; + private final int horizontalSlize; + + public static List generateConfigurations(IntegerRange vertical, IntegerRange horizontal) + { + List configurations = new ArrayList<>(); + + for(int i : slice(vertical)) + { + for(int j : slice(horizontal)) + { + configurations.add(new HunkSlizeConfiguration(i, j)); + } + } + + return configurations; + } + + public static List generateConfigurations(int vertical, IntegerRange horizontal) + { + List configurations = new ArrayList<>(); + + for(int j : slice(horizontal)) + { + configurations.add(new HunkSlizeConfiguration(vertical, j)); + } + + return configurations; + } + + private static List slice(IntegerRange range) + { + List v = new ArrayList<>(); + v.add(range.getRightEndpoint()); + v.add(range.getLeftEndpoint()); + int i = (int) (range.getRightEndpoint() / 1.25); + + while(i > range.getLeftEndpoint() && i >= 1) + { + v.add(i); + i /= 1.25; + } + + return v.withoutDuplicates(); + } +} diff --git a/engine/src/main/java/com/volmit/iris/engine/optimizer/IrisOptimizationAttempt.java b/engine/src/main/java/com/volmit/iris/engine/optimizer/IrisOptimizationAttempt.java new file mode 100644 index 000000000..6ee65836f --- /dev/null +++ b/engine/src/main/java/com/volmit/iris/engine/optimizer/IrisOptimizationAttempt.java @@ -0,0 +1,37 @@ +package com.volmit.iris.engine.optimizer; + +import art.arcane.amulet.metric.Average; +import lombok.Data; + +import java.util.concurrent.atomic.AtomicInteger; + +@Data +public class IrisOptimizationAttempt { + private final Average average; + private final AtomicInteger runs; + private final int testRuns; + private final T parameters; + + public IrisOptimizationAttempt(T parameters, int testRuns) + { + this.parameters = parameters; + this.testRuns = testRuns; + this.average = new Average(testRuns); + this.runs = new AtomicInteger(0); + } + + public double getAverageTime() + { + return average.getAverage(); + } + + public boolean isComplete() + { + return runs.get() >= testRuns; + } + + public void report(double ms) { + average.put(ms); + runs.incrementAndGet(); + } +} diff --git a/engine/src/main/java/com/volmit/iris/engine/optimizer/IrisOptimizer.java b/engine/src/main/java/com/volmit/iris/engine/optimizer/IrisOptimizer.java new file mode 100644 index 000000000..79d92b636 --- /dev/null +++ b/engine/src/main/java/com/volmit/iris/engine/optimizer/IrisOptimizer.java @@ -0,0 +1,72 @@ +package com.volmit.iris.engine.optimizer; + +import lombok.Builder; +import lombok.Data; +import lombok.Singular; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Data +public class IrisOptimizer { + private final int testRuns; + private final List options; + private final Map> attempts = new ConcurrentHashMap<>(); + private T defaultOption; + private final double chanceToTest; + private double bestTime; + + public IrisOptimizer(int testRuns, List options, T defaultOption, double chanceToTest) + { + this.bestTime = Double.MAX_VALUE; + this.testRuns = testRuns; + this.options = options; + this.defaultOption = defaultOption; + this.chanceToTest = chanceToTest; + + for(T i : options) + { + attempts.put(i, new IrisOptimizationAttempt<>(i, testRuns)); + } + } + + public String toString() + { + return "optimizer"; + } + + public synchronized void report(T parameters, double ms) + { + IrisOptimizationAttempt attempt = attempts.get(parameters); + + if(attempt != null) + { + attempt.report(ms); + + if(attempt.isComplete()) + { + attempts.remove(parameters); + double result = attempt.getAverageTime(); + + if(result < bestTime) + { + bestTime = result; + defaultOption = attempt.getParameters(); + } + } + } + } + + public T nextParameters() + { + if(!attempts.isEmpty() && Math.r(chanceToTest)) + { + return attempts.k().popRandom(); + } + + return defaultOption; + } +} diff --git a/engine/src/main/java/com/volmit/iris/engine/pipeline/EnginePipeline.java b/engine/src/main/java/com/volmit/iris/engine/pipeline/EnginePipeline.java index a473e821a..1ce72033a 100644 --- a/engine/src/main/java/com/volmit/iris/engine/pipeline/EnginePipeline.java +++ b/engine/src/main/java/com/volmit/iris/engine/pipeline/EnginePipeline.java @@ -1,14 +1,12 @@ package com.volmit.iris.engine.pipeline; -import com.volmit.iris.engine.EngineExecutor; -import com.volmit.iris.engine.IrisEngine; +import com.volmit.iris.engine.Engine; import com.volmit.iris.engine.feature.IrisFeatureSizedTarget; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.Singular; -import java.util.ArrayList; import java.util.List; @Data @@ -19,7 +17,7 @@ public class EnginePipeline @Singular private final List phases; - public void generate(IrisEngine engine,IrisFeatureSizedTarget target, PipedHunkStack stack) + public void generate(Engine engine, IrisFeatureSizedTarget target, PipedHunkStack stack) { for(PipelinePhase i : phases) { diff --git a/engine/src/main/java/com/volmit/iris/engine/pipeline/EnginePlumbing.java b/engine/src/main/java/com/volmit/iris/engine/pipeline/EnginePlumbing.java index 239ae296f..805ae46d7 100644 --- a/engine/src/main/java/com/volmit/iris/engine/pipeline/EnginePlumbing.java +++ b/engine/src/main/java/com/volmit/iris/engine/pipeline/EnginePlumbing.java @@ -1,25 +1,23 @@ package com.volmit.iris.engine.pipeline; -import com.volmit.iris.engine.IrisEngine; +import com.volmit.iris.engine.Engine; import com.volmit.iris.engine.feature.IrisFeatureSizedTarget; -import com.volmit.iris.engine.pipeline.EnginePipeline; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.Singular; -import java.util.ArrayList; import java.util.List; @Data @Builder @AllArgsConstructor public class EnginePlumbing { - private final IrisEngine engine; + private final Engine engine; @Singular private final List pipelines; - public void generate(IrisEngine engine, IrisFeatureSizedTarget target, PipedHunkStack stack) + public void generate(Engine engine, IrisFeatureSizedTarget target, PipedHunkStack stack) { for(EnginePipeline i : pipelines) { diff --git a/engine/src/main/java/com/volmit/iris/engine/pipeline/PipedHunkStack.java b/engine/src/main/java/com/volmit/iris/engine/pipeline/PipedHunkStack.java index dcd9a945c..0db732dda 100644 --- a/engine/src/main/java/com/volmit/iris/engine/pipeline/PipedHunkStack.java +++ b/engine/src/main/java/com/volmit/iris/engine/pipeline/PipedHunkStack.java @@ -1,27 +1,27 @@ package com.volmit.iris.engine.pipeline; -import art.arcane.amulet.collections.hunk.Hunk; +import com.volmit.iris.engine.feature.IrisFeatureTarget; import com.volmit.iris.platform.PlatformNamespaced; import java.util.HashMap; import java.util.Map; public class PipedHunkStack { - private final Map, Hunk> hunks; + private final Map, IrisFeatureTarget> hunks; public PipedHunkStack() { this.hunks = new HashMap<>(); } - public void register(Class clazz, Hunk hunk) + public void register(Class clazz, IrisFeatureTarget hunk) { hunks.put(clazz, hunk); } @SuppressWarnings("unchecked") - public Hunk hunk(Class hunk) + public IrisFeatureTarget hunk(Class hunk) { - return (Hunk) hunks.get(hunk); + return (IrisFeatureTarget) hunks.get(hunk); } } diff --git a/engine/src/main/java/com/volmit/iris/engine/pipeline/PipelinePhase.java b/engine/src/main/java/com/volmit/iris/engine/pipeline/PipelinePhase.java index bcb338901..d8922b9dd 100644 --- a/engine/src/main/java/com/volmit/iris/engine/pipeline/PipelinePhase.java +++ b/engine/src/main/java/com/volmit/iris/engine/pipeline/PipelinePhase.java @@ -1,23 +1,16 @@ package com.volmit.iris.engine.pipeline; -import art.arcane.amulet.collections.ObjectBiset; -import art.arcane.amulet.collections.hunk.Hunk; -import com.volmit.iris.engine.IrisEngine; -import com.volmit.iris.engine.feature.IrisFeature; +import com.volmit.iris.engine.Engine; import com.volmit.iris.engine.feature.IrisFeatureSizedTarget; import com.volmit.iris.engine.feature.IrisFeatureTarget; -import com.volmit.iris.engine.feature.IrisFeatureTask; -import com.volmit.iris.platform.PlatformNamespaced; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.Singular; -import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; -import static art.arcane.amulet.MagicalSugar.*; @Data @Builder @@ -27,20 +20,14 @@ public class PipelinePhase @Singular private final List> tasks; - @SuppressWarnings({"unchecked"}) - public void generate(IrisEngine engine, IrisFeatureSizedTarget target, PipedHunkStack stack) { - List> targets = engine.getExecutor().getForks().invokeAll(tasks.stream().map(i -> i.task(target)).collect(Collectors.toList())).stream().map(i -> { + public List> generate(Engine engine, IrisFeatureSizedTarget target, PipedHunkStack stack) { + return engine.getExecutor().getForks().invokeAll(tasks.stream().map(i -> i.task(target, stack.hunk(i.getTarget()))) + .collect(Collectors.toList())).stream().map(i -> { try { return i.get(); } catch(InterruptedException | ExecutionException e) { throw new RuntimeException(e); } }).collect(Collectors.toList()); - - for(int i : index targets) - { - IrisFeatureTarget targetResult = targets[i]; - stack.hunk(tasks[i].getTarget()).insert((Hunk) targetResult.getHunk()); - } } } diff --git a/engine/src/main/java/com/volmit/iris/engine/pipeline/PipelineTask.java b/engine/src/main/java/com/volmit/iris/engine/pipeline/PipelineTask.java index d159aa1de..fb31722c0 100644 --- a/engine/src/main/java/com/volmit/iris/engine/pipeline/PipelineTask.java +++ b/engine/src/main/java/com/volmit/iris/engine/pipeline/PipelineTask.java @@ -1,22 +1,48 @@ package com.volmit.iris.engine.pipeline; +import art.arcane.amulet.range.IntegerRange; +import com.volmit.iris.engine.optimizer.HunkSlizeConfiguration; import com.volmit.iris.engine.feature.IrisFeature; import com.volmit.iris.engine.feature.IrisFeatureSizedTarget; +import com.volmit.iris.engine.feature.IrisFeatureTarget; import com.volmit.iris.engine.feature.IrisFeatureTask; +import com.volmit.iris.engine.optimizer.IrisOptimizer; import com.volmit.iris.platform.PlatformNamespaced; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; +import java.util.List; + +import static art.arcane.amulet.MagicalSugar.*; + @AllArgsConstructor -@Builder @Data public class PipelineTask { private final IrisFeature feature; private final Class target; + private final IntegerRange verticalEnvelope; + private final IntegerRange horizontalEnvelope; + private final IrisOptimizer optimizer; - public IrisFeatureTask task(IrisFeatureSizedTarget target){ - return feature.task(target, 1000, 4); + public PipelineTask(IrisFeature feature, Class target, IntegerRange verticalEnvelope, IntegerRange horizontalEnvelope) + { + this.feature = feature; + this.target = target; + this.verticalEnvelope = verticalEnvelope; + this.horizontalEnvelope = horizontalEnvelope; + List configurations = feature.isHeightAgnostic() ? HunkSlizeConfiguration.generateConfigurations(Integer.MAX_VALUE, horizontalEnvelope) + : HunkSlizeConfiguration.generateConfigurations(verticalEnvelope, horizontalEnvelope); + this.optimizer = new IrisOptimizer<>(256, configurations, configurations[0], 0.75); + } + + public PipelineTask(IrisFeature feature, Class target) + { + this(feature, target, 1 to 16, 1 to 16); + } + + public IrisFeatureTask task(IrisFeatureSizedTarget target, IrisFeatureTarget origin){ + HunkSlizeConfiguration configuration = optimizer.nextParameters(); + return feature.task(target, origin,configuration.getVerticalSlice(), configuration.getHorizontalSlize(), (ms) -> optimizer.report(configuration, ms)); } }