diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryShape.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryShape.java
index 60ccf643db..9d9a22846c 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryShape.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/ArbitraryShape.java
@@ -31,12 +31,18 @@
* {@link #getMaterial} method.
*/
public abstract class ArbitraryShape {
+ /**
+ * This BaseBlock instance is used for cache entries that are known to be outside the shape.
+ * Do not use it for anything besides the cache.
+ */
+ private static final Object OUTSIDE = new Object();
protected final Region extent;
private final int cacheOffsetX;
private final int cacheOffsetY;
private final int cacheOffsetZ;
+ @SuppressWarnings("FieldCanBeLocal")
private final int cacheSizeX;
private final int cacheSizeY;
private final int cacheSizeZ;
@@ -44,14 +50,15 @@ public abstract class ArbitraryShape {
/**
* Cache for expression results.
*
- *
- * Cache entries:
- * 0 = unknown
- * -1 = outside
- * 1 = inside
- *
+ * Possible cache entries:
+ *
+ * - null = unknown
+ * - ArbitraryShape.OUTSIDE = outside
+ * - any BaseBlock = inside
+ * - anything else = (invalid, not used)
+ *
*/
- private final byte[] cache;
+ private final Object[] cache;
public ArbitraryShape(Region extent) {
this.extent = extent;
@@ -67,7 +74,7 @@ public ArbitraryShape(Region extent) {
cacheSizeY = max.getY() - cacheOffsetY + 2;
cacheSizeZ = max.getZ() - cacheOffsetZ + 2;
- cache = new byte[cacheSizeX * cacheSizeY * cacheSizeZ];
+ cache = new Object[cacheSizeX * cacheSizeY * cacheSizeZ];
}
protected Region getExtent() {
@@ -98,59 +105,9 @@ public int generate(EditSession editSession, Pattern pattern, boolean hollow) th
int affected = 0;
for (BlockVector3 position : getExtent()) {
- int x = position.getBlockX();
- int y = position.getBlockY();
- int z = position.getBlockZ();
-
- if (!hollow) {
- BaseBlock material = getMaterial(x, y, z, pattern.applyBlock(position));
- if (material != null && editSession.setBlock(position, material)) {
- ++affected;
- }
-
- continue;
- }
-
- BaseBlock material = getMaterial(x, y, z, pattern.applyBlock(position));
- if (material == null) {
- final int index = (y - cacheOffsetY) + (z - cacheOffsetZ) * cacheSizeY + (x - cacheOffsetX) * cacheSizeY * cacheSizeZ;
- cache[index] = -1;
- continue;
- }
+ final BaseBlock material = getMaterial(position, pattern, hollow);
- boolean draw = false;
- do {
- if (!isInsideCached(x + 1, y, z, pattern)) {
- draw = true;
- break;
- }
- if (!isInsideCached(x - 1, y, z, pattern)) {
- draw = true;
- break;
- }
- if (!isInsideCached(x, y, z + 1, pattern)) {
- draw = true;
- break;
- }
- if (!isInsideCached(x, y, z - 1, pattern)) {
- draw = true;
- break;
- }
- if (!isInsideCached(x, y + 1, z, pattern)) {
- draw = true;
- break;
- }
- if (!isInsideCached(x, y - 1, z, pattern)) {
- draw = true;
- break;
- }
- } while (false);
-
- if (!draw) {
- continue;
- }
-
- if (editSession.setBlock(position, material)) {
+ if (material != null && editSession.setBlock(position, material)) {
++affected;
}
}
@@ -158,27 +115,61 @@ public int generate(EditSession editSession, Pattern pattern, boolean hollow) th
return affected;
}
- private boolean isInsideCached(int x, int y, int z, Pattern pattern) {
- final int index = (y - cacheOffsetY) + (z - cacheOffsetZ) * cacheSizeY + (x - cacheOffsetX) * cacheSizeY * cacheSizeZ;
+ private BaseBlock getMaterial(BlockVector3 position, Pattern pattern, boolean hollow) {
+ int x = position.getBlockX();
+ int y = position.getBlockY();
+ int z = position.getBlockZ();
+
+ final BaseBlock defaultMaterial = pattern.applyBlock(position);
+
+ if (!hollow) {
+ return getMaterial(x, y, z, defaultMaterial);
+ }
+
+ final Object cacheEntry = getMaterialCached(x, y, z, defaultMaterial);
+ if (cacheEntry == OUTSIDE) {
+ return null;
+ }
+
+ final BaseBlock material = (BaseBlock) cacheEntry;
- switch (cache[index]) {
- case 0:
- BaseBlock mat = getMaterial(x, y, z, pattern.applyBlock(BlockVector3.at(x, y, z)));
- if (mat == null) {
- cache[index] = -1;
- return false;
- }
- cache[index] = 1;
- return true;
-
- case -1:
- // outside
- return false;
-
- default:
- // inside
- return true;
+ if (isOutsideCached(x + 1, y, z, pattern)) {
+ return material;
+ }
+ if (isOutsideCached(x - 1, y, z, pattern)) {
+ return material;
+ }
+ if (isOutsideCached(x, y, z + 1, pattern)) {
+ return material;
}
+ if (isOutsideCached(x, y, z - 1, pattern)) {
+ return material;
+ }
+ if (isOutsideCached(x, y + 1, z, pattern)) {
+ return material;
+ }
+ if (isOutsideCached(x, y - 1, z, pattern)) {
+ return material;
+ }
+
+ return null;
}
+ private boolean isOutsideCached(int x, int y, int z, Pattern pattern) {
+ return getMaterialCached(x, y, z, pattern.applyBlock(BlockVector3.at(x, y, z))) == OUTSIDE;
+ }
+
+ private Object getMaterialCached(int x, int y, int z, BaseBlock defaultMaterial) {
+ final int index = (y - cacheOffsetY) + (z - cacheOffsetZ) * cacheSizeY + (x - cacheOffsetX) * cacheSizeY * cacheSizeZ;
+ final Object cacheEntry = cache[index];
+ if (cacheEntry == null) {
+ final BaseBlock material = getMaterial(x, y, z, defaultMaterial);
+ if (material == null) {
+ return cache[index] = OUTSIDE;
+ } else {
+ return cache[index] = material;
+ }
+ }
+ return cacheEntry;
+ }
}