From 28ca9e54d8e6dfbe34a6d43120474fda3380c889 Mon Sep 17 00:00:00 2001 From: TomyLobo Date: Tue, 23 May 2023 19:48:50 +0200 Subject: [PATCH] Improve ArbitraryShape caching Every point is now only evaluated once. --- .../regions/shape/ArbitraryShape.java | 148 ++++++++---------- 1 file changed, 69 insertions(+), 79 deletions(-) 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..97fd991b77 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,17 @@ * {@link #getMaterial} method. */ public abstract class ArbitraryShape { + /** + * This Object instance is used for cache entries that are known to be outside the shape. + */ + 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 +49,15 @@ public abstract class ArbitraryShape { /** * Cache for expression results. * - *

- * Cache entries: - * 0 = unknown - * -1 = outside - * 1 = inside - *

+ *

Possible cache entries: + *

*/ - private final byte[] cache; + private final Object[] cache; public ArbitraryShape(Region extent) { this.extent = extent; @@ -67,7 +73,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 +104,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 +114,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; + } }