From 0bf5da2ca1e5730f28704c9627464835d6faec85 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sun, 26 Oct 2025 13:48:11 +0100 Subject: [PATCH] optimize object maps --- .../iris/core/commands/CommandObject.java | 3 +- .../engine/modifier/IrisDepositModifier.java | 2 +- .../volmit/iris/engine/object/IrisObject.java | 143 ++++++------ .../com/volmit/iris/util/data/VectorMap.java | 220 ++++++++++++++++++ .../com/volmit/iris/util/matter/Matter.java | 4 +- 5 files changed, 293 insertions(+), 79 deletions(-) create mode 100644 core/src/main/java/com/volmit/iris/util/data/VectorMap.java diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandObject.java b/core/src/main/java/com/volmit/iris/core/commands/CommandObject.java index bc6937a2c..2cfd03e6f 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandObject.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandObject.java @@ -38,7 +38,6 @@ import com.volmit.iris.util.decree.specialhandlers.ObjectHandler; import com.volmit.iris.util.format.C; import com.volmit.iris.util.math.Direction; import com.volmit.iris.util.math.RNG; -import com.volmit.iris.util.scheduling.Queue; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; @@ -140,7 +139,7 @@ public class CommandObject implements DecreeExecutor { sender().sendMessage("Object Size: " + o.getW() + " * " + o.getH() + " * " + o.getD() + ""); sender().sendMessage("Blocks Used: " + NumberFormat.getIntegerInstance().format(o.getBlocks().size())); - Queue queue = o.getBlocks().enqueueValues(); + var queue = o.getBlocks().values(); Map> unsorted = new HashMap<>(); Map amounts = new HashMap<>(); Map materials = new HashMap<>(); diff --git a/core/src/main/java/com/volmit/iris/engine/modifier/IrisDepositModifier.java b/core/src/main/java/com/volmit/iris/engine/modifier/IrisDepositModifier.java index dfa7bc1e8..f6fcd52c0 100644 --- a/core/src/main/java/com/volmit/iris/engine/modifier/IrisDepositModifier.java +++ b/core/src/main/java/com/volmit/iris/engine/modifier/IrisDepositModifier.java @@ -119,7 +119,7 @@ public class IrisDepositModifier extends EngineAssignedModifier { if (y > k.getMaxHeight() || y < k.getMinHeight() || y > height - 2) continue; - for (BlockVector j : clump.getBlocks().keySet()) { + for (BlockVector j : clump.getBlocks().keys()) { int nx = j.getBlockX() + x; int ny = j.getBlockY() + y; int nz = j.getBlockZ() + z; diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisObject.java b/core/src/main/java/com/volmit/iris/engine/object/IrisObject.java index fb6a85d4e..24e9e685b 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisObject.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisObject.java @@ -30,6 +30,7 @@ import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.context.IrisContext; import com.volmit.iris.util.data.B; import com.volmit.iris.util.data.IrisCustomData; +import com.volmit.iris.util.data.VectorMap; import com.volmit.iris.util.format.Form; import com.volmit.iris.util.interpolation.IrisInterpolation; import com.volmit.iris.util.json.JSONObject; @@ -63,6 +64,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiConsumer; +import java.util.stream.StreamSupport; @Accessors(chain = true) @EqualsAndHashCode(callSuper = false) @@ -81,8 +83,8 @@ public class IrisObject extends IrisRegistrant { protected transient IrisLock lock = new IrisLock("Preloadcache"); @Setter protected transient AtomicCache aabb = new AtomicCache<>(); - private KMap blocks; - private KMap states; + private VectorMap blocks; + private VectorMap states; @Getter @Setter private int w; @@ -97,8 +99,8 @@ public class IrisObject extends IrisRegistrant { private transient Vector3i center; public IrisObject(int w, int h, int d) { - blocks = new KMap<>(); - states = new KMap<>(); + blocks = new VectorMap<>(); + states = new VectorMap<>(); this.w = w; this.h = h; this.d = d; @@ -170,7 +172,7 @@ public class IrisObject extends IrisRegistrant { BlockVector max = new BlockVector(Double.MIN_VALUE, Double.MIN_VALUE, Double.MIN_VALUE); BlockVector min = new BlockVector(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE); - for (BlockVector i : getBlocks().keySet()) { + for (BlockVector i : getBlocks().keys()) { max.setX(Math.max(i.getX(), max.getX())); min.setX(Math.min(i.getX(), min.getX())); max.setY(Math.max(i.getY(), max.getY())); @@ -281,13 +283,8 @@ public class IrisObject extends IrisRegistrant { o.setLoadFile(getLoadFile()); o.setCenter(getCenter().clone()); - for (Vector3i i : getBlocks().keySet()) { - o.getBlocks().put(i.clone(), Objects.requireNonNull(getBlocks().get(i)).clone()); - } - - for (Vector3i i : getStates().keySet()) { - o.getStates().put(i.clone(), Objects.requireNonNull(getStates().get(i)).clone()); - } + getBlocks().forEach((i, v) -> o.getBlocks().put(i.clone(), v.clone())); + getStates().forEach((i, v) -> o.getStates().put(i.clone(), v.clone())); return o; } @@ -366,19 +363,21 @@ public class IrisObject extends IrisRegistrant { dos.writeInt(getBlocks().size()); - for (Vector3i i : getBlocks().keySet()) { + for (var entry : getBlocks()) { + var i = entry.getKey(); dos.writeShort(i.getBlockX()); dos.writeShort(i.getBlockY()); dos.writeShort(i.getBlockZ()); - dos.writeShort(palette.indexOf(getBlocks().get(i).getAsString())); + dos.writeShort(palette.indexOf(entry.getValue().getAsString())); } dos.writeInt(getStates().size()); - for (Vector3i i : getStates().keySet()) { + for (var entry : getStates()) { + var i = entry.getKey(); dos.writeShort(i.getBlockX()); dos.writeShort(i.getBlockY()); dos.writeShort(i.getBlockZ()); - getStates().get(i).toBinary(dos); + entry.getValue().toBinary(dos); } } @@ -420,20 +419,22 @@ public class IrisObject extends IrisRegistrant { dos.writeInt(getBlocks().size()); - for (Vector3i i : getBlocks().keySet()) { + for (var entry : getBlocks()) { + var i = entry.getKey(); dos.writeShort(i.getBlockX()); dos.writeShort(i.getBlockY()); dos.writeShort(i.getBlockZ()); - dos.writeShort(palette.indexOf(getBlocks().get(i).getAsString())); + dos.writeShort(palette.indexOf(entry.getValue().getAsString())); ++c; } dos.writeInt(getStates().size()); - for (Vector3i i : getStates().keySet()) { + for (var entry : getStates()) { + var i = entry.getKey(); dos.writeShort(i.getBlockX()); dos.writeShort(i.getBlockY()); dos.writeShort(i.getBlockZ()); - getStates().get(i).toBinary(dos); + entry.getValue().toBinary(dos); ++c; } } catch (IOException e) { @@ -502,7 +503,7 @@ public class IrisObject extends IrisRegistrant { BlockVector min = new BlockVector(); BlockVector max = new BlockVector(); - for (BlockVector i : getBlocks().keySet()) { + for (BlockVector i : getBlocks().keys()) { min.setX(Math.min(min.getX(), i.getX())); min.setY(Math.min(min.getY(), i.getY())); min.setZ(Math.min(min.getZ(), i.getZ())); @@ -518,21 +519,11 @@ public class IrisObject extends IrisRegistrant { } public void clean() { - KMap d = new KMap<>(); + VectorMap d = new VectorMap<>(); + d.putAll(getBlocks()); - for (Vector3i i : getBlocks().keySet()) { - d.put(new Vector3i(i.getBlockX(), i.getBlockY(), i.getBlockZ()), Objects.requireNonNull(getBlocks().get(i))); - } - - KMap dx = new KMap<>(); - - for (Vector3i i : getBlocks().keySet()) { - d.put(new Vector3i(i.getBlockX(), i.getBlockY(), i.getBlockZ()), Objects.requireNonNull(getBlocks().get(i))); - } - - for (Vector3i i : getStates().keySet()) { - dx.put(new Vector3i(i.getBlockX(), i.getBlockY(), i.getBlockZ()), Objects.requireNonNull(getStates().get(i))); - } + VectorMap dx = new VectorMap<>(); + dx.putAll(getStates()); blocks = d; states = dx; @@ -866,6 +857,9 @@ public class IrisObject extends IrisRegistrant { try { if (config.getMarkers().isNotEmpty() && placer.getEngine() != null) { markers = new KMap<>(); + var list = StreamSupport.stream(getBlocks().keys().spliterator(), false) + .collect(KList.collector()); + for (IrisObjectMarker j : config.getMarkers()) { IrisMarker marker = getLoader().getMarkerLoader().load(j.getMarker()); @@ -874,8 +868,7 @@ public class IrisObject extends IrisRegistrant { } int max = j.getMaximumMarkers(); - - for (Vector3i i : getBlocks().k().shuffle()) { + for (BlockVector i : list.shuffle()) { if (max <= 0) { break; } @@ -888,8 +881,8 @@ public class IrisObject extends IrisRegistrant { } if (j.isExact() ? k.matches(data) : k.getMaterial().equals(data.getMaterial())) { - boolean a = !blocks.containsKey((Vector3i) i.clone().add(new BlockVector(0, 1, 0))); - boolean fff = !blocks.containsKey((Vector3i) i.clone().add(new BlockVector(0, 2, 0))); + boolean a = !blocks.containsKey((BlockVector) i.clone().add(new BlockVector(0, 1, 0))); + boolean fff = !blocks.containsKey((BlockVector) i.clone().add(new BlockVector(0, 2, 0))); if (!marker.isEmptyAbove() || (a && fff)) { markers.put(i, j.getMarker()); @@ -901,7 +894,7 @@ public class IrisObject extends IrisRegistrant { } } - for (var entry : getBlocks().entrySet()) { + for (var entry : getBlocks()) { var g = entry.getKey(); BlockData d; TileData tile = null; @@ -1026,7 +1019,7 @@ public class IrisObject extends IrisRegistrant { if (stilting) { readLock.lock(); IrisStiltSettings settings = config.getStiltSettings(); - for (Vector3i g : getBlocks().keySet()) { + for (BlockVector g : getBlocks().keys()) { BlockData d; if (settings == null || settings.getPalette() == null) { @@ -1138,16 +1131,16 @@ public class IrisObject extends IrisRegistrant { } public void rotate(IrisObjectRotation r, int spinx, int spiny, int spinz) { - KMap d = new KMap<>(); + VectorMap d = new VectorMap<>(); - for (Vector3i i : getBlocks().keySet()) { - d.put(new Vector3i(r.rotate(i, spinx, spiny, spinz)), r.rotate(getBlocks().get(i).clone(), spinx, spiny, spinz)); + for (var entry : getBlocks()) { + d.put(r.rotate(entry.getKey(), spinx, spiny, spinz), r.rotate(entry.getValue(), spinx, spiny, spinz)); } - KMap dx = new KMap<>(); + VectorMap dx = new VectorMap<>(); - for (Vector3i i : getStates().keySet()) { - dx.put(new Vector3i(r.rotate(i, spinx, spiny, spinz)), getStates().get(i)); + for (var entry : getStates()) { + dx.put(r.rotate(entry.getKey(), spinx, spiny, spinz), entry.getValue()); } blocks = d; @@ -1156,9 +1149,10 @@ public class IrisObject extends IrisRegistrant { } public void place(Location at) { - for (Vector3i i : getBlocks().keySet()) { + for (var entry : getBlocks()) { + var i = entry.getKey(); Block b = at.clone().add(0, getCenter().getY(), 0).add(i).getBlock(); - b.setBlockData(Objects.requireNonNull(getBlocks().get(i)), false); + b.setBlockData(Objects.requireNonNull(entry.getValue()), false); if (getStates().containsKey(i)) { Iris.info(Objects.requireNonNull(states.get(i)).toString()); @@ -1168,9 +1162,10 @@ public class IrisObject extends IrisRegistrant { } public void placeCenterY(Location at) { - for (Vector3i i : getBlocks().keySet()) { + for (var entry : getBlocks()) { + var i = entry.getKey(); Block b = at.clone().add(getCenter().getX(), getCenter().getY(), getCenter().getZ()).add(i).getBlock(); - b.setBlockData(Objects.requireNonNull(getBlocks().get(i)), false); + b.setBlockData(Objects.requireNonNull(entry.getValue()), false); if (getStates().containsKey(i)) { Objects.requireNonNull(getStates().get(i)).toBukkitTry(b); @@ -1178,16 +1173,16 @@ public class IrisObject extends IrisRegistrant { } } - public synchronized KMap getBlocks() { + public synchronized VectorMap getBlocks() { return blocks; } - public synchronized KMap getStates() { + public synchronized VectorMap getStates() { return states; } public void unplaceCenterY(Location at) { - for (BlockVector i : getBlocks().keySet()) { + for (BlockVector i : getBlocks().keys()) { at.clone().add(getCenter().getX(), getCenter().getY(), getCenter().getZ()).add(i).getBlock().setBlockData(AIR, false); } } @@ -1201,7 +1196,7 @@ public class IrisObject extends IrisRegistrant { IrisPosition l1 = getAABB().max(); IrisPosition l2 = getAABB().min(); - @SuppressWarnings({"unchecked", "rawtypes"}) HashMap placeBlock = new HashMap(); + VectorMap placeBlock = new VectorMap<>(); Vector center = getCenter(); if (getH() == 2) { @@ -1216,17 +1211,17 @@ public class IrisObject extends IrisRegistrant { IrisObject oo = new IrisObject((int) Math.ceil((w * scale) + (scale * 2)), (int) Math.ceil((h * scale) + (scale * 2)), (int) Math.ceil((d * scale) + (scale * 2))); - for (Map.Entry entry : blocks.entrySet()) { + for (var entry : blocks) { BlockData bd = entry.getValue(); placeBlock.put(entry.getKey().clone().add(HALF).subtract(center) .multiply(scale).add(sm1).toBlockVector(), bd); } - for (Map.Entry entry : placeBlock.entrySet()) { + for (var entry : placeBlock) { BlockVector v = entry.getKey(); if (scale > 1) { for (BlockVector vec : blocksBetweenTwoPoints(v.clone().add(center), v.clone().add(center).add(sm1))) { - oo.getBlocks().put(new Vector3i(vec), entry.getValue()); + oo.getBlocks().put(vec, entry.getValue()); } } else { oo.setUnsigned(v.getBlockX(), v.getBlockY(), v.getBlockZ(), entry.getValue()); @@ -1245,8 +1240,8 @@ public class IrisObject extends IrisRegistrant { } public void trilinear(int rad) { - KMap v = getBlocks().copy(); - KMap b = new KMap<>(); + VectorMap v = getBlocks(); + VectorMap b = new VectorMap<>(); BlockVector min = getAABB().minbv(); BlockVector max = getAABB().maxbv(); @@ -1254,7 +1249,7 @@ public class IrisObject extends IrisRegistrant { for (int y = min.getBlockY(); y <= max.getBlockY(); y++) { for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) { if (IrisInterpolation.getTrilinear(x, y, z, rad, (xx, yy, zz) -> { - BlockData data = v.get(new Vector3i((int) xx, (int) yy, (int) zz)); + BlockData data = v.get(new BlockVector((int) xx, (int) yy, (int) zz)); if (data == null || data.getMaterial().isAir()) { return 0; @@ -1262,9 +1257,9 @@ public class IrisObject extends IrisRegistrant { return 1; }) >= 0.5) { - b.put(new Vector3i(x, y, z), nearestBlockData(x, y, z)); + b.put(new BlockVector(x, y, z), nearestBlockData(x, y, z)); } else { - b.put(new Vector3i(x, y, z), AIR); + b.put(new BlockVector(x, y, z), AIR); } } } @@ -1274,8 +1269,8 @@ public class IrisObject extends IrisRegistrant { } public void tricubic(int rad) { - KMap v = getBlocks().copy(); - KMap b = new KMap<>(); + VectorMap v = getBlocks(); + VectorMap b = new VectorMap<>(); BlockVector min = getAABB().minbv(); BlockVector max = getAABB().maxbv(); @@ -1283,7 +1278,7 @@ public class IrisObject extends IrisRegistrant { for (int y = min.getBlockY(); y <= max.getBlockY(); y++) { for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) { if (IrisInterpolation.getTricubic(x, y, z, rad, (xx, yy, zz) -> { - BlockData data = v.get(new Vector3i((int) xx, (int) yy, (int) zz)); + BlockData data = v.get(new BlockVector((int) xx, (int) yy, (int) zz)); if (data == null || data.getMaterial().isAir()) { return 0; @@ -1291,9 +1286,9 @@ public class IrisObject extends IrisRegistrant { return 1; }) >= 0.5) { - b.put(new Vector3i(x, y, z), nearestBlockData(x, y, z)); + b.put(new BlockVector(x, y, z), nearestBlockData(x, y, z)); } else { - b.put(new Vector3i(x, y, z), AIR); + b.put(new BlockVector(x, y, z), AIR); } } } @@ -1307,8 +1302,8 @@ public class IrisObject extends IrisRegistrant { } public void trihermite(int rad, double tension, double bias) { - KMap v = getBlocks().copy(); - KMap b = new KMap<>(); + VectorMap v = getBlocks(); + VectorMap b = new VectorMap<>(); BlockVector min = getAABB().minbv(); BlockVector max = getAABB().maxbv(); @@ -1316,7 +1311,7 @@ public class IrisObject extends IrisRegistrant { for (int y = min.getBlockY(); y <= max.getBlockY(); y++) { for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) { if (IrisInterpolation.getTrihermite(x, y, z, rad, (xx, yy, zz) -> { - BlockData data = v.get(new Vector3i((int) xx, (int) yy, (int) zz)); + BlockData data = v.get(new BlockVector((int) xx, (int) yy, (int) zz)); if (data == null || data.getMaterial().isAir()) { return 0; @@ -1324,9 +1319,9 @@ public class IrisObject extends IrisRegistrant { return 1; }, tension, bias) >= 0.5) { - b.put(new Vector3i(x, y, z), nearestBlockData(x, y, z)); + b.put(new BlockVector(x, y, z), nearestBlockData(x, y, z)); } else { - b.put(new Vector3i(x, y, z), AIR); + b.put(new BlockVector(x, y, z), AIR); } } } @@ -1345,7 +1340,7 @@ public class IrisObject extends IrisRegistrant { double d = Double.MAX_VALUE; - for (Map.Entry entry : blocks.entrySet()) { + for (var entry : blocks) { BlockData dat = entry.getValue(); if (dat.getMaterial().isAir()) { diff --git a/core/src/main/java/com/volmit/iris/util/data/VectorMap.java b/core/src/main/java/com/volmit/iris/util/data/VectorMap.java new file mode 100644 index 000000000..0b3108252 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/data/VectorMap.java @@ -0,0 +1,220 @@ +package com.volmit.iris.util.data; + +import com.volmit.iris.util.collection.KMap; +import lombok.NonNull; +import org.bukkit.util.BlockVector; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Iterator; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Function; + +public class VectorMap implements Iterable> { + private final Map> map = new KMap<>(); + + public int size() { + return map.values().stream().mapToInt(Map::size).sum(); + } + + public boolean isEmpty() { + return map.values().stream().allMatch(Map::isEmpty); + } + + public boolean containsKey(@NonNull BlockVector vector) { + var chunk = map.get(chunk(vector)); + return chunk != null && chunk.containsKey(relative(vector)); + } + + public boolean containsValue(@NonNull T value) { + return map.values().stream().anyMatch(m -> m.containsValue(value)); + } + + public @Nullable T get(@NonNull BlockVector vector) { + var chunk = map.get(chunk(vector)); + return chunk == null ? null : chunk.get(relative(vector)); + } + + public @Nullable T put(@NonNull BlockVector vector, @NonNull T value) { + return map.computeIfAbsent(chunk(vector), k -> new KMap<>()) + .put(relative(vector), value); + } + + public @Nullable T computeIfAbsent(@NonNull BlockVector vector, @NonNull Function<@NonNull BlockVector, @NonNull T> mappingFunction) { + return map.computeIfAbsent(chunk(vector), k -> new KMap<>()) + .computeIfAbsent(relative(vector), $ -> mappingFunction.apply(vector)); + } + + public @Nullable T remove(@NonNull BlockVector vector) { + var chunk = map.get(chunk(vector)); + return chunk == null ? null : chunk.remove(relative(vector)); + } + + public void putAll(@NonNull VectorMap map) { + map.forEach(this::put); + } + + public void clear() { + map.clear(); + } + + public void forEach(@NonNull BiConsumer<@NonNull BlockVector, @NonNull T> consumer) { + map.forEach((chunk, values) -> { + int rX = chunk.x << 10; + int rY = chunk.y << 10; + int rZ = chunk.z << 10; + + values.forEach((relative, value) -> consumer.accept( + relative.resolve(rX, rY, rZ), + value + )); + }); + } + + private static Key chunk(BlockVector vector) { + return new Key(vector.getBlockX() >> 10, vector.getBlockY() >> 10, vector.getBlockZ() >> 10); + } + + private static Key relative(BlockVector vector) { + return new Key(vector.getBlockX() & 0x3FF, vector.getBlockY() & 0x3FF, vector.getBlockZ() & 0x3FF); + } + + @Override + public @NotNull EntryIterator iterator() { + return new EntryIterator(); + } + + public @NotNull KeyIterator keys() { + return new KeyIterator(); + } + + public @NotNull ValueIterator values() { + return new ValueIterator(); + } + + public class EntryIterator implements Iterator> { + private final Iterator>> chunkIterator = map.entrySet().iterator(); + private Iterator> relativeIterator; + private int rX, rY, rZ; + + @Override + public boolean hasNext() { + return relativeIterator != null && relativeIterator.hasNext() || chunkIterator.hasNext(); + } + + @Override + public Map.Entry next() { + if (relativeIterator == null || !relativeIterator.hasNext()) { + if (!chunkIterator.hasNext()) throw new IllegalStateException("No more elements"); + var chunk = chunkIterator.next(); + rX = chunk.getKey().x << 10; + rY = chunk.getKey().y << 10; + rZ = chunk.getKey().z << 10; + relativeIterator = chunk.getValue().entrySet().iterator(); + } + + var entry = relativeIterator.next(); + return Map.entry(entry.getKey().resolve(rX, rY, rZ), entry.getValue()); + } + + @Override + public void remove() { + if (relativeIterator == null) throw new IllegalStateException("No element to remove"); + relativeIterator.remove(); + } + } + + public class KeyIterator implements Iterator, Iterable { + private final Iterator>> chunkIterator = map.entrySet().iterator(); + private Iterator relativeIterator; + private int rX, rY, rZ; + + @Override + public boolean hasNext() { + return relativeIterator != null && relativeIterator.hasNext() || chunkIterator.hasNext(); + } + + @Override + public BlockVector next() { + if (relativeIterator == null || !relativeIterator.hasNext()) { + var chunk = chunkIterator.next(); + rX = chunk.getKey().x << 10; + rY = chunk.getKey().y << 10; + rZ = chunk.getKey().z << 10; + relativeIterator = chunk.getValue().keySet().iterator(); + } + + return relativeIterator.next().resolve(rX, rY, rZ); + } + + @Override + public void remove() { + if (relativeIterator == null) throw new IllegalStateException("No element to remove"); + relativeIterator.remove(); + } + + @Override + public @NotNull Iterator iterator() { + return this; + } + } + + public class ValueIterator implements Iterator, Iterable { + private final Iterator> chunkIterator = map.values().iterator(); + private Iterator relativeIterator; + + @Override + public boolean hasNext() { + return relativeIterator != null && relativeIterator.hasNext() || chunkIterator.hasNext(); + } + + @Override + public T next() { + if (relativeIterator == null || !relativeIterator.hasNext()) { + relativeIterator = chunkIterator.next().values().iterator(); + } + return relativeIterator.next(); + } + + @Override + public void remove() { + if (relativeIterator == null) throw new IllegalStateException("No element to remove"); + relativeIterator.remove(); + } + + @Override + public @NotNull Iterator iterator() { + return this; + } + } + + private static final class Key { + private final int x; + private final int y; + private final int z; + private final int hashCode; + + private Key(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + this.hashCode = (x << 20) | (y << 10) | z; + } + + private BlockVector resolve(int rX, int rY, int rZ) { + return new BlockVector(rX + x, rY + y, rZ + z); + } + + @Override + public int hashCode() { + return hashCode; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof Key key)) return false; + return x == key.x && y == key.y && z == key.z; + } + } +} diff --git a/core/src/main/java/com/volmit/iris/util/matter/Matter.java b/core/src/main/java/com/volmit/iris/util/matter/Matter.java index 0fe0dca0c..384835bbf 100644 --- a/core/src/main/java/com/volmit/iris/util/matter/Matter.java +++ b/core/src/main/java/com/volmit/iris/util/matter/Matter.java @@ -85,13 +85,13 @@ public interface Matter { BlockVector min = new BlockVector(); Matter m = new IrisMatter(Math.max(object.getW(), 1) + 1, Math.max(object.getH(), 1) + 1, Math.max(object.getD(), 1) + 1); - for (BlockVector i : object.getBlocks().keySet()) { + for (BlockVector i : object.getBlocks().keys()) { min.setX(Math.min(min.getX(), i.getX())); min.setY(Math.min(min.getY(), i.getY())); min.setZ(Math.min(min.getZ(), i.getZ())); } - for (BlockVector i : object.getBlocks().keySet()) { + for (BlockVector i : object.getBlocks().keys()) { m.slice(BlockData.class).set(i.getBlockX() - min.getBlockX(), i.getBlockY() - min.getBlockY(), i.getBlockZ() - min.getBlockZ(), object.getBlocks().get(i)); }