From 0dd45cdfa25d61c211985bff7e6ee4a73c9ef630 Mon Sep 17 00:00:00 2001 From: Daniel Mills Date: Mon, 26 Oct 2020 03:50:36 -0400 Subject: [PATCH] Hunks Galore --- .../volmit/iris/gen/v2/scaffold/HunkView.java | 171 ---- .../iris/gen/v2/scaffold/hunk/ArrayHunk.java | 43 + .../v2/scaffold/hunk/AtomicDoubleHunk.java | 36 + .../iris/gen/v2/scaffold/hunk/AtomicHunk.java | 36 + .../v2/scaffold/hunk/AtomicIntegerHunk.java | 36 + .../gen/v2/scaffold/hunk/AtomicLongHunk.java | 36 + .../v2/scaffold/hunk/BiomeGridHunkView.java | 44 ++ .../v2/scaffold/hunk/ChunkDataHunkView.java | 51 ++ .../iris/gen/v2/scaffold/hunk/Hunk.java | 738 ++++++++++++++++++ .../gen/v2/scaffold/{ => hunk}/HunkFace.java | 2 +- .../iris/gen/v2/scaffold/hunk/HunkView.java | 69 ++ .../iris/gen/v2/scaffold/hunk/MappedHunk.java | 32 + .../gen/v2/scaffold/hunk/StorageHunk.java | 29 + .../scaffold/hunk/SynchronizedArrayHunk.java | 52 ++ 14 files changed, 1203 insertions(+), 172 deletions(-) delete mode 100644 src/main/java/com/volmit/iris/gen/v2/scaffold/HunkView.java create mode 100644 src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/ArrayHunk.java create mode 100644 src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/AtomicDoubleHunk.java create mode 100644 src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/AtomicHunk.java create mode 100644 src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/AtomicIntegerHunk.java create mode 100644 src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/AtomicLongHunk.java create mode 100644 src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/BiomeGridHunkView.java create mode 100644 src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/ChunkDataHunkView.java create mode 100644 src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/Hunk.java rename src/main/java/com/volmit/iris/gen/v2/scaffold/{ => hunk}/HunkFace.java (60%) create mode 100644 src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/HunkView.java create mode 100644 src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/MappedHunk.java create mode 100644 src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/StorageHunk.java create mode 100644 src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/SynchronizedArrayHunk.java diff --git a/src/main/java/com/volmit/iris/gen/v2/scaffold/HunkView.java b/src/main/java/com/volmit/iris/gen/v2/scaffold/HunkView.java deleted file mode 100644 index 6c596c889..000000000 --- a/src/main/java/com/volmit/iris/gen/v2/scaffold/HunkView.java +++ /dev/null @@ -1,171 +0,0 @@ -package com.volmit.iris.gen.v2.scaffold; - -public class HunkView implements Hunk -{ - private final int ox; - private final int oy; - private final int oz; - private final int w; - private final int h; - private final int d; - private final Hunk src; - - public HunkView(Hunk src) - { - this(src, src.getWidth(), src.getHeight(), src.getDepth()); - } - - public HunkView(Hunk src, int w, int h, int d) - { - this(src, w, h, d, 0, 0, 0); - } - - public HunkView(Hunk src, int w, int h, int d, int ox, int oy, int oz) - { - this.src = src; - this.w = w; - this.h = h; - this.d = d; - this.ox = ox; - this.oy = oy; - this.oz = oz; - } - - @Override - public Hunk croppedView(int x1, int y1, int z1, int x2, int y2, int z2) - { - return new HunkView(this, x2 - x1, y2 - y1, z2 - z1, x1 + ox, y1 + oy, z1 + oz); - } - - @Override - public ArrayHunk crop(int x1, int y1, int z1, int x2, int y2, int z2) - { - ArrayHunk h = new ArrayHunk(x2 - x1, y2 - y1, z2 - z1); - - for(int i = x1; i < x2; i++) - { - for(int j = y1; j < y2; j++) - { - for(int k = z1; k < z2; k++) - { - h.set(i - x1, j - y1, k - z1, get(i, j, k)); - } - } - } - - return h; - } - - @Override - public void insert(int offX, int offY, int offZ, Hunk hunk, boolean invertY) - { - if(offX + (hunk.getWidth() - 1) >= w || offY + (hunk.getHeight() - 1) >= h || offZ + (hunk.getDepth() - 1) >= d || offX < 0 || offY < 0 || offZ < 0) - { - throw new RuntimeException("Cannot insert hunk " + hunk.getWidth() + "," + hunk.getHeight() + "," + hunk.getDepth() + " into Hunk " + w + "," + h + "," + d + " with offset " + offZ + "," + offY + "," + offZ); - } - - for(int i = offX; i < offX + hunk.getWidth(); i++) - { - for(int j = offY; j < offY + hunk.getHeight(); j++) - { - for(int k = offZ; k < offZ + hunk.getDepth(); k++) - { - set(i, j, k, hunk.get(i - offX, j - offY, k - offZ)); - } - } - } - } - - @Override - public void set(int x1, int y1, int z1, int x2, int y2, int z2, T t) - { - if(x1 >= w || y1 >= h || z1 >= d || x2 >= w || y2 >= h || z2 >= d) - { - throw new RuntimeException(x1 + "-" + x2 + " " + y1 + "-" + y2 + " " + z1 + "-" + z2 + " is out of the bounds 0,0,0 - " + (w - 1) + "," + (h - 1) + "," + (d - 1)); - } - - src.set(x1, y1, z1, x2, y2, z2, t); - } - - @Override - public void set(int x, int y, int z, T t) - { - if(x >= w || y >= h || z >= d) - { - throw new RuntimeException(x + " " + y + " " + z + " is out of the bounds 0,0,0 - " + (w - 1) + "," + (h - 1) + "," + (d - 1)); - } - - src.set(x + ox, y + oy, z + oz, t); - } - - @Override - public T get(int x, int y, int z) - { - if(x >= w || y >= h || z >= d) - { - throw new RuntimeException(x + " " + y + " " + z + " is out of the bounds 0,0,0 - " + (w - 1) + "," + (h - 1) + "," + (d - 1)); - } - - return src.get(x + ox, y + oy, z + oz); - } - - @Override - public T getClosest(int x, int y, int z) - { - return src.get(x >= w ? w + ox - 1 : x + ox, y >= h ? h + oy - 1 : y + oy, z >= d ? d + oz - 1 : z + oz); - } - - @Override - public void fill(T t) - { - set(0 + ox, 0 + oy, 0 + oz, w - 1 + ox, h - 1 + oy, d - 1 + oz, t); - } - - @Override - public int getWidth() - { - return w; - } - - @Override - public int getDepth() - { - return d; - } - - @Override - public int getHeight() - { - return h; - } - - @Override - public Hunk getFace(HunkFace f) - { - switch(f) - { - case BOTTOM: - return croppedView(0, 0, 0, getWidth() - 1, 0, getDepth() - 1); - case EAST: - return croppedView(getWidth() - 1, 0, 0, getWidth() - 1, getHeight() - 1, getDepth() - 1); - case NORTH: - return croppedView(0, 0, 0, getWidth() - 1, getHeight() - 1, 0); - case SOUTH: - return croppedView(0, 0, 0, 0, getHeight() - 1, getDepth() - 1); - case TOP: - return croppedView(0, getHeight() - 1, 0, getWidth() - 1, getHeight() - 1, getDepth() - 1); - case WEST: - return croppedView(0, 0, getDepth() - 1, getWidth() - 1, getHeight() - 1, getDepth() - 1); - default: - break; - } - - return null; - } - - @Override - public Hunk getSource() - { - return src; - } -} diff --git a/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/ArrayHunk.java b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/ArrayHunk.java new file mode 100644 index 000000000..62bd489d8 --- /dev/null +++ b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/ArrayHunk.java @@ -0,0 +1,43 @@ +package com.volmit.iris.gen.v2.scaffold.hunk; + +import org.bouncycastle.util.Arrays; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = false) +public class ArrayHunk extends StorageHunk implements Hunk +{ + private final T[] data; + + @SuppressWarnings("unchecked") + protected ArrayHunk(int w, int h, int d) + { + super(w, h, d); + data = (T[]) new Object[w * h * d]; + } + + @Override + public void setRaw(int x, int y, int z, T t) + { + data[index(x, y, z)] = t; + } + + @Override + public T getRaw(int x, int y, int z) + { + return data[index(x, y, z)]; + } + + private int index(int x, int y, int z) + { + return (z * getWidth() * getHeight()) + (y * getWidth()) + x; + } + + @Override + public void fill(T t) + { + Arrays.fill(data, t); + } +} diff --git a/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/AtomicDoubleHunk.java b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/AtomicDoubleHunk.java new file mode 100644 index 000000000..e174075df --- /dev/null +++ b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/AtomicDoubleHunk.java @@ -0,0 +1,36 @@ +package com.volmit.iris.gen.v2.scaffold.hunk; + +import com.google.common.util.concurrent.AtomicDoubleArray; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = false) +public class AtomicDoubleHunk extends StorageHunk implements Hunk +{ + private final AtomicDoubleArray data; + + protected AtomicDoubleHunk(int w, int h, int d) + { + super(w, h, d); + data = new AtomicDoubleArray(w * h * d); + } + + @Override + public void setRaw(int x, int y, int z, Double t) + { + data.set(index(x, y, z), t); + } + + @Override + public Double getRaw(int x, int y, int z) + { + return data.get(index(x, y, z)); + } + + private int index(int x, int y, int z) + { + return (z * getWidth() * getHeight()) + (y * getWidth()) + x; + } +} diff --git a/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/AtomicHunk.java b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/AtomicHunk.java new file mode 100644 index 000000000..05025f81d --- /dev/null +++ b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/AtomicHunk.java @@ -0,0 +1,36 @@ +package com.volmit.iris.gen.v2.scaffold.hunk; + +import java.util.concurrent.atomic.AtomicReferenceArray; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = false) +public class AtomicHunk extends StorageHunk implements Hunk +{ + private final AtomicReferenceArray data; + + protected AtomicHunk(int w, int h, int d) + { + super(w, h, d); + data = new AtomicReferenceArray(w * h * d); + } + + @Override + public void setRaw(int x, int y, int z, T t) + { + data.set(index(x, y, z), t); + } + + @Override + public T getRaw(int x, int y, int z) + { + return data.get(index(x, y, z)); + } + + private int index(int x, int y, int z) + { + return (z * getWidth() * getHeight()) + (y * getWidth()) + x; + } +} diff --git a/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/AtomicIntegerHunk.java b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/AtomicIntegerHunk.java new file mode 100644 index 000000000..c6f836363 --- /dev/null +++ b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/AtomicIntegerHunk.java @@ -0,0 +1,36 @@ +package com.volmit.iris.gen.v2.scaffold.hunk; + +import java.util.concurrent.atomic.AtomicIntegerArray; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = false) +public class AtomicIntegerHunk extends StorageHunk implements Hunk +{ + private final AtomicIntegerArray data; + + protected AtomicIntegerHunk(int w, int h, int d) + { + super(w, h, d); + data = new AtomicIntegerArray(w * h * d); + } + + @Override + public void setRaw(int x, int y, int z, Integer t) + { + data.set(index(x, y, z), t); + } + + @Override + public Integer getRaw(int x, int y, int z) + { + return data.get(index(x, y, z)); + } + + private int index(int x, int y, int z) + { + return (z * getWidth() * getHeight()) + (y * getWidth()) + x; + } +} diff --git a/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/AtomicLongHunk.java b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/AtomicLongHunk.java new file mode 100644 index 000000000..396497eb8 --- /dev/null +++ b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/AtomicLongHunk.java @@ -0,0 +1,36 @@ +package com.volmit.iris.gen.v2.scaffold.hunk; + +import java.util.concurrent.atomic.AtomicLongArray; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = false) +public class AtomicLongHunk extends StorageHunk implements Hunk +{ + private final AtomicLongArray data; + + protected AtomicLongHunk(int w, int h, int d) + { + super(w, h, d); + data = new AtomicLongArray(w * h * d); + } + + @Override + public void setRaw(int x, int y, int z, Long t) + { + data.set(index(x, y, z), t); + } + + @Override + public Long getRaw(int x, int y, int z) + { + return data.get(index(x, y, z)); + } + + private int index(int x, int y, int z) + { + return (z * getWidth() * getHeight()) + (y * getWidth()) + x; + } +} diff --git a/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/BiomeGridHunkView.java b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/BiomeGridHunkView.java new file mode 100644 index 000000000..d1c7f5d6d --- /dev/null +++ b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/BiomeGridHunkView.java @@ -0,0 +1,44 @@ +package com.volmit.iris.gen.v2.scaffold.hunk; + +import org.bukkit.block.Biome; +import org.bukkit.generator.ChunkGenerator.BiomeGrid; + +public class BiomeGridHunkView implements Hunk +{ + private final BiomeGrid chunk; + + public BiomeGridHunkView(BiomeGrid chunk) + { + this.chunk = chunk; + } + + @Override + public int getWidth() + { + return 16; + } + + @Override + public int getDepth() + { + return 16; + } + + @Override + public int getHeight() + { + return 256; + } + + @Override + public void setRaw(int x, int y, int z, Biome t) + { + chunk.setBiome(x, y, z, t); + } + + @Override + public Biome getRaw(int x, int y, int z) + { + return chunk.getBiome(x, y, z); + } +} diff --git a/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/ChunkDataHunkView.java b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/ChunkDataHunkView.java new file mode 100644 index 000000000..e4e1852c2 --- /dev/null +++ b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/ChunkDataHunkView.java @@ -0,0 +1,51 @@ +package com.volmit.iris.gen.v2.scaffold.hunk; + +import org.bukkit.block.data.BlockData; +import org.bukkit.generator.ChunkGenerator.ChunkData; + +public class ChunkDataHunkView implements Hunk +{ + private final ChunkData chunk; + + public ChunkDataHunkView(ChunkData chunk) + { + this.chunk = chunk; + } + + @Override + public int getWidth() + { + return 16; + } + + @Override + public int getDepth() + { + return 16; + } + + @Override + public int getHeight() + { + return chunk.getMaxHeight(); + } + + @Override + public void set(int x1, int y1, int z1, int x2, int y2, int z2, BlockData t) + { + enforceBounds(x1, y1, z1, x2 - x1, y2 - y1, z2 - z1); + chunk.setRegion(x1, y1, z1, x2, y2, z2, t); + } + + @Override + public void setRaw(int x, int y, int z, BlockData t) + { + chunk.setBlock(x, y, z, t); + } + + @Override + public BlockData getRaw(int x, int y, int z) + { + return chunk.getBlockData(x, y, z); + } +} diff --git a/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/Hunk.java b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/Hunk.java new file mode 100644 index 000000000..d28378a9a --- /dev/null +++ b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/Hunk.java @@ -0,0 +1,738 @@ +package com.volmit.iris.gen.v2.scaffold.hunk; + +import java.util.function.Consumer; + +import org.bukkit.block.Biome; +import org.bukkit.block.data.BlockData; +import org.bukkit.generator.ChunkGenerator.BiomeGrid; +import org.bukkit.generator.ChunkGenerator.ChunkData; + +import com.volmit.iris.gen.v2.scaffold.multicore.BurstExecutor; +import com.volmit.iris.gen.v2.scaffold.multicore.MultiBurst; +import com.volmit.iris.util.Consumer2; +import com.volmit.iris.util.Consumer3; +import com.volmit.iris.util.Consumer4; +import com.volmit.iris.util.Consumer5; +import com.volmit.iris.util.Function3; +import com.volmit.iris.util.KList; + +public interface Hunk +{ + /** + * Create a hunk view from a source hunk. This view reads and writes through to + * the source hunk. Its is not a copy. + * + * @param + * the type + * @param src + * the source hunk + * @return the hunk view + */ + public static Hunk view(Hunk src) + { + return new HunkView(src); + } + + public static Hunk view(BiomeGrid biome) + { + return new BiomeGridHunkView(biome); + } + + public static Hunk view(ChunkData src) + { + return new ChunkDataHunkView(src); + } + + public static Hunk newHunk(int w, int h, int d) + { + return newArrayHunk(w, h, d); + } + + @SafeVarargs + public static Hunk newCombinedHunk(Hunk... hunks) + { + return newCombinedArrayHunk(hunks); + } + + public static Hunk newArrayHunk(int w, int h, int d) + { + return new ArrayHunk<>(w, h, d); + } + + @SafeVarargs + public static Hunk newCombinedArrayHunk(Hunk... hunks) + { + return combined(Hunk::newArrayHunk, hunks); + } + + public static Hunk newSynchronizedArrayHunk(int w, int h, int d) + { + return new SynchronizedArrayHunk<>(w, h, d); + } + + @SafeVarargs + public static Hunk newCombinedSynchronizedArrayHunk(Hunk... hunks) + { + return combined(Hunk::newSynchronizedArrayHunk, hunks); + } + + public static Hunk newMappedHunk(int w, int h, int d) + { + return new MappedHunk<>(w, h, d); + } + + @SafeVarargs + public static Hunk newCombinedMappedHunk(Hunk... hunks) + { + return combined(Hunk::newMappedHunk, hunks); + } + + public static Hunk newAtomicHunk(int w, int h, int d) + { + return new AtomicHunk<>(w, h, d); + } + + @SafeVarargs + public static Hunk newCombinedAtomicHunk(Hunk... hunks) + { + return combined(Hunk::newAtomicHunk, hunks); + } + + public static Hunk newAtomicDoubleHunk(int w, int h, int d) + { + return new AtomicDoubleHunk(w, h, d); + } + + @SafeVarargs + public static Hunk newCombinedAtomicDoubleHunk(Hunk... hunks) + { + return combined(Hunk::newAtomicDoubleHunk, hunks); + } + + public static Hunk newAtomicLongHunk(int w, int h, int d) + { + return new AtomicLongHunk(w, h, d); + } + + @SafeVarargs + public static Hunk newCombinedAtomicLongHunk(Hunk... hunks) + { + return combined(Hunk::newAtomicLongHunk, hunks); + } + + public static Hunk newAtomicIntegerHunk(int w, int h, int d) + { + return new AtomicIntegerHunk(w, h, d); + } + + @SafeVarargs + public static Hunk newCombinedAtomicIntegerHunk(Hunk... hunks) + { + return combined(Hunk::newAtomicIntegerHunk, hunks); + } + + /** + * Creates a new bounding hunk from the given hunks + * + * @param + * the type + * @param factory + * the factory that creates a hunk + * @param hunks + * the hunks + * @return the new bounding hunk + */ + @SafeVarargs + public static Hunk combined(Function3> factory, Hunk... hunks) + { + int w = 0; + int h = 0; + int d = 0; + + for(Hunk i : hunks) + { + w = Math.max(w, i.getWidth()); + h = Math.max(h, i.getHeight()); + d = Math.max(d, i.getDepth()); + } + + Hunk b = factory.apply(w, h, d); + + for(Hunk i : hunks) + { + b.insert(i); + } + + return b; + } + + default Hunk iterate(Consumer3 c) + { + for(int i = 0; i < getWidth(); i++) + { + for(int j = 0; j < getWidth(); j++) + { + for(int k = 0; k < getWidth(); k++) + { + c.accept(i, j, k); + } + } + } + + return this; + } + + default Hunk iterate(Consumer4 c) + { + for(int i = 0; i < getWidth(); i++) + { + for(int j = 0; j < getWidth(); j++) + { + for(int k = 0; k < getWidth(); k++) + { + c.accept(i, j, k, get(i, j, k)); + } + } + } + + return this; + } + + default Hunk compute3D(int parallelism, Consumer4> v) + { + BurstExecutor e = MultiBurst.burst.burst(parallelism); + KList rq = new KList(parallelism); + getSections3D(parallelism, (xx, yy, zz, h, r) -> e.queue(() -> + { + v.accept(xx, yy, zz, h); + synchronized(rq) + { + rq.add(r); + } + }), (xx, yy, zz, c) -> insert(xx, yy, zz, c)); + e.complete(); + rq.forEach(Runnable::run); + return this; + } + + default Hunk compute2D(int parallelism, Consumer4> v) + { + BurstExecutor e = MultiBurst.burst.burst(parallelism); + KList rq = new KList(parallelism); + getSections2D(parallelism, (xx, yy, zz, h, r) -> e.queue(() -> + { + v.accept(xx, yy, zz, h); + synchronized(rq) + { + rq.add(r); + } + }), (xx, yy, zz, c) -> insert(xx, yy, zz, c)); + e.complete(); + rq.forEach(Runnable::run); + return this; + } + + default Hunk compute2DAtomically(int parallelism, Consumer4> v) + { + BurstExecutor e = MultiBurst.burst.burst(parallelism); + KList rq = new KList(parallelism); + getAtomicSections2D(parallelism, (xx, yy, zz, h) -> e.queue(() -> v.accept(xx, yy, zz, h))); + e.complete(); + rq.forEach(Runnable::run); + return this; + } + + default Hunk compute3DAtomically(int parallelism, Consumer4> v) + { + BurstExecutor e = MultiBurst.burst.burst(parallelism); + KList rq = new KList(parallelism); + getAtomicSections3D(parallelism, (xx, yy, zz, h) -> e.queue(() -> v.accept(xx, yy, zz, h))); + e.complete(); + rq.forEach(Runnable::run); + return this; + } + + default Hunk getSections2D(int sections, Consumer5, Runnable> v) + { + return getSections2D(sections, v, (xx, yy, zz, c) -> insert(xx, yy, zz, c)); + } + + default Hunk getSections2D(int sections, Consumer5, Runnable> v, Consumer4> inserter) + { + int dim = (int) Math.ceil(Math.sqrt(sections)); + dim = dim < 2 ? 2 : dim; + dim = dim % 2 != 0 ? dim + 1 : dim; + int w = getWidth() / dim; + int d = getDepth() / dim; + int i, j; + + for(i = 0; i < getWidth(); i += w) + { + int ii = i; + + for(j = 0; j < getDepth(); j += d) + { + int jj = j; + getSection(i, 0, j, i + w - 1, getHeight() - 1, j + d - 1, (h, r) -> v.accept(ii, 0, jj, h, r), inserter); + } + } + + return this; + } + + default Hunk getAtomicSections2D(int sections, Consumer4> v) + { + int dim = (int) Math.ceil(Math.sqrt(sections)); + dim = dim < 2 ? 2 : dim; + dim = dim % 2 != 0 ? dim + 1 : dim; + int w = getWidth() / dim; + int d = getDepth() / dim; + int i, j; + + for(i = 0; i < getWidth(); i += w) + { + int ii = i; + + for(j = 0; j < getDepth(); j += d) + { + int jj = j; + getAtomicSection(i, 0, j, i + w - 1, getHeight() - 1, j + d - 1, (h) -> v.accept(ii, 0, jj, h)); + } + } + + return this; + } + + default Hunk getSections3D(int sections, Consumer5, Runnable> v) + { + return getSections3D(sections, v, (xx, yy, zz, c) -> insert(xx, yy, zz, c)); + } + + default Hunk getSections3D(int sections, Consumer5, Runnable> v, Consumer4> inserter) + { + int dim = (int) Math.ceil(Math.cbrt(sections)); + dim = dim < 2 ? 2 : dim; + dim = dim % 2 != 0 ? dim + 1 : dim; + int w = getWidth() / dim; + int h = getHeight() / dim; + int d = getDepth() / dim; + int i, j, k; + + for(i = 0; i < getWidth(); i += w) + { + int ii = i; + + for(j = 0; j < getHeight(); j += d) + { + int jj = j; + + for(k = 0; k < getDepth(); k += d) + { + int kk = k; + getSection(i, j, k, i + w - 1, j + h - 1, k + d - 1, (hh, r) -> v.accept(ii, jj, kk, hh, r), inserter); + } + } + } + + return this; + } + + default Hunk getAtomicSections3D(int sections, Consumer4> v) + { + int dim = (int) Math.ceil(Math.cbrt(sections)); + dim = dim < 2 ? 2 : dim; + dim = dim % 2 != 0 ? dim + 1 : dim; + int w = getWidth() / dim; + int h = getHeight() / dim; + int d = getDepth() / dim; + int i, j, k; + + for(i = 0; i < getWidth(); i += w) + { + int ii = i; + + for(j = 0; j < getHeight(); j += d) + { + int jj = j; + + for(k = 0; k < getDepth(); k += d) + { + int kk = k; + getAtomicSection(i, j, k, i + w - 1, j + h - 1, k + d - 1, (hh) -> v.accept(ii, jj, kk, hh)); + } + } + } + + return this; + } + + default Hunk getSection(int x, int y, int z, int x1, int y1, int z1, Consumer2, Runnable> v) + { + return getSection(x, y, z, x1, y1, z1, v, (xx, yy, zz, c) -> insert(xx, yy, zz, c)); + } + + default Hunk getSection(int x, int y, int z, int x1, int y1, int z1, Consumer2, Runnable> v, Consumer4> inserter) + { + Hunk copy = crop(x, y, z, x1, y1, z1); + v.accept(copy, () -> inserter.accept(x, y, z, copy)); + return this; + } + + default Hunk getAtomicSection(int x, int y, int z, int x1, int y1, int z1, Consumer> v) + { + v.accept(croppedView(x, y, z, x1, y1, z1)); + return this; + } + + default void enforceBounds(int x, int y, int z) + { + if(x < 0 || x >= getWidth() || y < 0 || y >= getHeight() || z < 0 || z >= getDepth()) + { + throw new IndexOutOfBoundsException(x + "," + y + "," + z + " does not fit within size " + getWidth() + "," + getHeight() + "," + getDepth() + " (0,0,0 to " + (getWidth() - 1) + "," + (getHeight() - 1) + "," + (getDepth() - 1) + ")"); + } + } + + default void enforceBounds(int x, int y, int z, int w, int h, int d) + { + if(x < 0 || x >= getWidth() || y < 0 || y >= getHeight() || z < 0 || z >= getDepth() || x + w < 0 || x + w >= getWidth() || y + h < 0 || y + h >= getHeight() || z + d < 0 || z + d >= getDepth()) + { + throw new IndexOutOfBoundsException("The hunk " + w + "," + h + "," + d + " with an offset of " + x + "," + y + "," + z + " does not fit within the parent hunk " + getWidth() + "," + getHeight() + "," + getDepth() + " (0,0,0 to " + (getWidth() - 1) + "," + (getHeight() - 1) + "," + (getDepth() - 1) + ")"); + } + } + + /** + * Create a new hunk from a section of this hunk. + * + * + * @param x1 + * The min x (inclusive) + * @param y1 + * The min y (inclusive) + * @param z1 + * The min z (inclusive) + * @param x2 + * The max x (exclusive) + * @param y2 + * The max y (exclusive) + * @param z2 + * The max z (exclusive) + * @return the new hunk (x2-x1, y2-y1, z2-z1) + */ + default ArrayHunk crop(int x1, int y1, int z1, int x2, int y2, int z2) + { + ArrayHunk h = new ArrayHunk(x2 - x1, y2 - y1, z2 - z1); + enforceBounds(x1, y1, z1, x2 - x1, y2 - y1, z2 - z1); + + for(int i = x1; i < x2; i++) + { + for(int j = y1; j < y2; j++) + { + for(int k = z1; k < z2; k++) + { + h.setRaw(i - x1, j - y1, k - z1, getRaw(i, j, k)); + } + } + } + + return h; + } + + /** + * Create a new view of this same hunk from a section of this hunk. + * Modifications are routed to this hunk! + * + * @param x1 + * The min x (inclusive) + * @param y1 + * The min y (inclusive) + * @param z1 + * The min z (inclusive) + * @param x2 + * The max x (exclusive) + * @param y2 + * The max y (exclusive) + * @param z2 + * The max z (exclusive) + * @return the cropped view of this hunk (x2-x1, y2-y1, z2-z1) + */ + default Hunk croppedView(int x1, int y1, int z1, int x2, int y2, int z2) + { + enforceBounds(x1, y1, z1, x2 - x1, y2 - y1, z2 - z1); + return new HunkView(this, x2 - x1, y2 - y1, z2 - z1, x1, y1, z1); + } + + /** + * @return The X length + */ + public int getWidth(); + + /** + * @return The Z length + */ + public int getDepth(); + + /** + * @return The Y length + */ + public int getHeight(); + + /** + * Set a region + * + * @param x1 + * inclusive 1st x + * @param y1 + * inclusive 1st y + * @param z1 + * inclusive 1st z + * @param x2 + * inclusive 2nd x + * @param y2 + * inclusive 2nd y + * @param z2 + * inclusive 2nd z + * @param t + * the value to set + */ + default void set(int x1, int y1, int z1, int x2, int y2, int z2, T t) + { + enforceBounds(x1, y1, z1, x2 - x1, y2 - y1, z2 - z1); + for(int i = x1; i <= x2; i++) + { + for(int j = y1; j <= y2; j++) + { + for(int k = z1; k <= z2; k++) + { + setRaw(i, j, k, t); + } + } + } + } + + /** + * Get the value to the closest valid position + * + * @param x + * the x + * @param y + * the y + * @param z + * the z + * @return the value closest to the border of the hunk + */ + default T getClosest(int x, int y, int z) + { + return getRaw(x >= getWidth() ? getWidth() - 1 : x, y >= getHeight() ? getHeight() - 1 : y, z >= getDepth() ? getDepth() - 1 : z); + } + + default void fill(T t) + { + set(0, 0, 0, getWidth() - 1, getHeight() - 1, getDepth() - 1, t); + } + + /** + * Get a 1 node thick hunk representing the face of this hunk + * + * @param f + * the face + * @return the hunk view of this hunk + */ + default Hunk viewFace(HunkFace f) + { + switch(f) + { + case BOTTOM: + return croppedView(0, 0, 0, getWidth() - 1, 0, getDepth() - 1); + case EAST: + return croppedView(getWidth() - 1, 0, 0, getWidth() - 1, getHeight() - 1, getDepth() - 1); + case NORTH: + return croppedView(0, 0, 0, getWidth() - 1, getHeight() - 1, 0); + case SOUTH: + return croppedView(0, 0, 0, 0, getHeight() - 1, getDepth() - 1); + case TOP: + return croppedView(0, getHeight() - 1, 0, getWidth() - 1, getHeight() - 1, getDepth() - 1); + case WEST: + return croppedView(0, 0, getDepth() - 1, getWidth() - 1, getHeight() - 1, getDepth() - 1); + default: + break; + } + + return null; + } + + /** + * Crop (copy) a 1 node thick hunk representing the face of this hunk + * + * @param f + * the face + * @return the hunk copy (face) of this hunk + */ + default Hunk cropFace(HunkFace f) + { + switch(f) + { + case BOTTOM: + return crop(0, 0, 0, getWidth() - 1, 0, getDepth() - 1); + case EAST: + return crop(getWidth() - 1, 0, 0, getWidth() - 1, getHeight() - 1, getDepth() - 1); + case NORTH: + return crop(0, 0, 0, getWidth() - 1, getHeight() - 1, 0); + case SOUTH: + return crop(0, 0, 0, 0, getHeight() - 1, getDepth() - 1); + case TOP: + return crop(0, getHeight() - 1, 0, getWidth() - 1, getHeight() - 1, getDepth() - 1); + case WEST: + return crop(0, 0, getDepth() - 1, getWidth() - 1, getHeight() - 1, getDepth() - 1); + default: + break; + } + + return null; + } + + /** + * Set a value at the given position + * + * @param x + * the x + * @param y + * the y + * @param z + * the z + * @param t + * the value + */ + default void set(int x, int y, int z, T t) + { + enforceBounds(x, y, z); + setRaw(x, y, z, t); + } + + /** + * Set a value at the given position without checking coordinate bounds + * + * @param x + * the x + * @param y + * the y + * @param z + * the z + * @param t + * the value + */ + public void setRaw(int x, int y, int z, T t); + + /** + * Get a value at the given position without checking coordinate bounds + * + * @param x + * the x + * @param y + * the y + * @param z + * the z + * @return the value or null + */ + public T getRaw(int x, int y, int z); + + /** + * Get a value at the given position + * + * @param x + * the x + * @param y + * the y + * @param z + * the z + * @return the value or null + */ + default T get(int x, int y, int z) + { + enforceBounds(x, y, z); + return getRaw(x, y, z); + } + + /** + * Insert a hunk into this one with an offset the inserted hunk + * + * @param offX + * the offset from zero for x + * @param offY + * the offset from zero for y + * @param offZ + * the offset from zero for z + * @param hunk + * the hunk to insert + */ + default void insert(int offX, int offY, int offZ, Hunk hunk) + { + insert(offX, offY, offZ, hunk, false); + } + + /** + * Insert a hunk into this one + * + * @param hunk + * the hunk to insert + */ + default void insert(Hunk hunk) + { + insert(0, 0, 0, hunk, false); + } + + /** + * Returns the source of this hunk view. This could return another hunk view, + * not an actual source, however it does return it's underlying data source. If + * this hunk is a data source and not a view, it will return null. + * + * @return the source or null if this is already the source + */ + default Hunk getSource() + { + return null; + } + + /** + * Insert a hunk into this one + * + * @param hunk + * the hunk to insert + * @param inverted + * invert the inserted hunk or not + */ + default void insert(Hunk hunk, boolean inverted) + { + insert(0, 0, 0, hunk, inverted); + } + + /** + * Insert a hunk into this one with an offset and possibly inverting the y of + * the inserted hunk + * + * @param offX + * the offset from zero for x + * @param offY + * the offset from zero for y + * @param offZ + * the offset from zero for z + * @param hunk + * the hunk to insert + * @param invertY + * should the inserted hunk be inverted + */ + default void insert(int offX, int offY, int offZ, Hunk hunk, boolean invertY) + { + enforceBounds(offX, offY, offZ, hunk.getWidth(), hunk.getHeight(), hunk.getDepth()); + + for(int i = offX; i < offX + hunk.getWidth(); i++) + { + for(int j = offY; j < offY + hunk.getHeight(); j++) + { + for(int k = offZ; k < offZ + hunk.getDepth(); k++) + { + setRaw(i, j, k, hunk.getRaw(i - offX, j - offY, k - offZ)); + } + } + } + } +} diff --git a/src/main/java/com/volmit/iris/gen/v2/scaffold/HunkFace.java b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/HunkFace.java similarity index 60% rename from src/main/java/com/volmit/iris/gen/v2/scaffold/HunkFace.java rename to src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/HunkFace.java index 14e944913..27d9e9157 100644 --- a/src/main/java/com/volmit/iris/gen/v2/scaffold/HunkFace.java +++ b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/HunkFace.java @@ -1,4 +1,4 @@ -package com.volmit.iris.gen.v2.scaffold; +package com.volmit.iris.gen.v2.scaffold.hunk; public enum HunkFace { diff --git a/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/HunkView.java b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/HunkView.java new file mode 100644 index 000000000..7009549de --- /dev/null +++ b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/HunkView.java @@ -0,0 +1,69 @@ +package com.volmit.iris.gen.v2.scaffold.hunk; + +public class HunkView implements Hunk +{ + private final int ox; + private final int oy; + private final int oz; + private final int w; + private final int h; + private final int d; + private final Hunk src; + + public HunkView(Hunk src) + { + this(src, src.getWidth(), src.getHeight(), src.getDepth()); + } + + public HunkView(Hunk src, int w, int h, int d) + { + this(src, w, h, d, 0, 0, 0); + } + + public HunkView(Hunk src, int w, int h, int d, int ox, int oy, int oz) + { + this.src = src; + this.w = w; + this.h = h; + this.d = d; + this.ox = ox; + this.oy = oy; + this.oz = oz; + } + + @Override + public void setRaw(int x, int y, int z, T t) + { + src.setRaw(x + ox, y + oy, z + oz, t); + } + + @Override + public T getRaw(int x, int y, int z) + { + return src.getRaw(x + ox, y + oy, z + oz); + } + + @Override + public int getWidth() + { + return w; + } + + @Override + public int getDepth() + { + return d; + } + + @Override + public int getHeight() + { + return h; + } + + @Override + public Hunk getSource() + { + return src; + } +} diff --git a/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/MappedHunk.java b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/MappedHunk.java new file mode 100644 index 000000000..92be58fa8 --- /dev/null +++ b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/MappedHunk.java @@ -0,0 +1,32 @@ +package com.volmit.iris.gen.v2.scaffold.hunk; + +import com.volmit.iris.util.BlockPosition; +import com.volmit.iris.util.KMap; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = false) +public class MappedHunk extends StorageHunk implements Hunk +{ + private final KMap data; + + protected MappedHunk(int w, int h, int d) + { + super(w, h, d); + data = new KMap<>(); + } + + @Override + public void setRaw(int x, int y, int z, T t) + { + data.put(new BlockPosition(x, y, z), t); + } + + @Override + public T getRaw(int x, int y, int z) + { + return data.get(new BlockPosition(x, y, z)); + } +} diff --git a/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/StorageHunk.java b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/StorageHunk.java new file mode 100644 index 000000000..64cd65355 --- /dev/null +++ b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/StorageHunk.java @@ -0,0 +1,29 @@ +package com.volmit.iris.gen.v2.scaffold.hunk; + +import lombok.Data; + +@Data +public abstract class StorageHunk implements Hunk +{ + private final int width; + private final int height; + private final int depth; + + protected StorageHunk(int width, int height, int depth) + { + if(width <= 0 || height <= 0 || depth <= 0) + { + throw new RuntimeException("Unsupported size " + width + " " + height + " " + depth); + } + + this.width = width; + this.height = height; + this.depth = depth; + } + + @Override + public abstract void setRaw(int x, int y, int z, T t); + + @Override + public abstract T getRaw(int x, int y, int z); +} diff --git a/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/SynchronizedArrayHunk.java b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/SynchronizedArrayHunk.java new file mode 100644 index 000000000..67cbcd7d3 --- /dev/null +++ b/src/main/java/com/volmit/iris/gen/v2/scaffold/hunk/SynchronizedArrayHunk.java @@ -0,0 +1,52 @@ +package com.volmit.iris.gen.v2.scaffold.hunk; + +import org.bouncycastle.util.Arrays; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = false) +public class SynchronizedArrayHunk extends StorageHunk implements Hunk +{ + private final T[] data; + + @SuppressWarnings("unchecked") + protected SynchronizedArrayHunk(int w, int h, int d) + { + super(w, h, d); + data = (T[]) new Object[w * h * d]; + } + + @Override + public void setRaw(int x, int y, int z, T t) + { + synchronized(data) + { + data[index(x, y, z)] = t; + } + } + + @Override + public T getRaw(int x, int y, int z) + { + synchronized(data) + { + return data[index(x, y, z)]; + } + } + + private int index(int x, int y, int z) + { + return (z * getWidth() * getHeight()) + (y * getWidth()) + x; + } + + @Override + public void fill(T t) + { + synchronized(data) + { + Arrays.fill(data, t); + } + } +}