From 8a83f7f70e398023630349ed73e9b1c2af683249 Mon Sep 17 00:00:00 2001 From: TomyLobo Date: Mon, 31 Oct 2011 22:03:35 +0100 Subject: [PATCH] Added support for custom materials to ArbitraryShape and adjusted //generate accordingly. --- .../com/sk89q/worldedit/ArbitraryShape.java | 121 ++++++++++++++++-- .../commands/GenerationCommands.java | 19 +-- 2 files changed, 118 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/sk89q/worldedit/ArbitraryShape.java b/src/main/java/com/sk89q/worldedit/ArbitraryShape.java index b5248b358..5b9a87b0f 100644 --- a/src/main/java/com/sk89q/worldedit/ArbitraryShape.java +++ b/src/main/java/com/sk89q/worldedit/ArbitraryShape.java @@ -19,56 +19,151 @@ package com.sk89q.worldedit; +import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.patterns.Pattern; import com.sk89q.worldedit.regions.Region; public abstract class ArbitraryShape { - private Region extent; + private final Region extent; + private int cacheSizeX; + private int cacheSizeY; + private int cacheSizeZ; + private int cacheX; + private int cacheY; + private int cacheZ; public ArbitraryShape(Region extent) { this.extent = extent; + + Vector min = extent.getMinimumPoint(); + Vector max = extent.getMaximumPoint(); + + cacheSizeX = (int)(max.getX() - min.getX() + 1 + 2); + cacheSizeY = (int)(max.getY() - min.getY() + 1 + 2); + cacheSizeZ = (int)(max.getZ() - min.getZ() + 1 + 2); + + cacheX = min.getBlockX() - 1; + cacheY = min.getBlockY() - 1; + cacheZ = min.getBlockZ() - 1; + + cache = new short[cacheSizeX * cacheSizeY * cacheSizeZ]; } protected Region getExtent() { return extent; } - protected abstract boolean isInside(double x, double y, double z); + + /** + * Cache entries: + * 0 = unknown + * -1 = outside + * -2 = inside but type and data 0 + * > 0 = inside, value = (type | (data << 8)), not handling data < -1 + */ + private final short[] cache; + + protected abstract BaseBlock getMaterial(int x, int y, int z, BaseBlock defaultMaterial); + + private BaseBlock getMaterialCached(int x, int y, int z, Pattern pattern) { + final int index = (y - cacheY) + (z - cacheZ) * cacheSizeY + (x - cacheX) * cacheSizeY * cacheSizeZ; + + final short cacheEntry = cache[index]; + switch (cacheEntry) { + case 0: + // unknown, fetch material + final BaseBlock material = getMaterial(x, y, z, pattern.next(new BlockVector(x, y, z))); + if (material == null) { + // outside + cache[index] = -1; + return null; + } + + short newCacheEntry = (short) (material.getType() | ((material.getData()+1) << 8)); + if (newCacheEntry == 0) { + // type and data 0 + newCacheEntry = -2; + } + + cache[index] = newCacheEntry; + return material; + + case -1: + // outside + return null; + + case -2: + // type and data 0 + return new BaseBlock(0, 0); + } + + return new BaseBlock(cacheEntry & 255, ((cacheEntry >> 8) - 1) & 15); + } + + private boolean isInsideCached(int x, int y, int z, Pattern pattern) { + final int index = (y - cacheY) + (z - cacheZ) * cacheSizeY + (x - cacheX) * cacheSizeY * cacheSizeZ; + + switch (cache[index]) { + case 0: + // unknown block, meaning they must be outside the extent at this stage, but might still be inside the shape + return getMaterialCached(x, y, z, pattern) != null; + + case -1: + // outside + return false; + + default: + // inside + return true; + } + } public int generate(EditSession editSession, Pattern pattern, boolean hollow) throws MaxChangedBlocksException { int affected = 0; for (BlockVector position : getExtent()) { - double x = position.getX(); - double y = position.getY(); - double z = position.getZ(); + int x = position.getBlockX(); + int y = position.getBlockY(); + int z = position.getBlockZ(); - if (!isInside(x, y, z)) continue; + if (!hollow) { + final BaseBlock material = getMaterial(x, y, z, pattern.next(position)); + if (material != null && editSession.setBlock(position, material)) { + ++affected; + } + + continue; + } + + final BaseBlock material = getMaterialCached(x, y, z, pattern); + if (material == null) { + continue; + } if (hollow) { boolean draw = false; do { - if (!isInside(x + 1, y, z)) { + if (!isInsideCached(x + 1, y, z, pattern)) { draw = true; break; } - if (!isInside(x - 1, y, z)) { + if (!isInsideCached(x - 1, y, z, pattern)) { draw = true; break; } - if (!isInside(x, y + 1, z)) { + if (!isInsideCached(x, y + 1, z, pattern)) { draw = true; break; } - if (!isInside(x, y - 1, z)) { + if (!isInsideCached(x, y - 1, z, pattern)) { draw = true; break; } - if (!isInside(x, y, z + 1)) { + if (!isInsideCached(x, y, z + 1, pattern)) { draw = true; break; } - if (!isInside(x, y, z - 1)) { + if (!isInsideCached(x, y, z - 1, pattern)) { draw = true; break; } @@ -79,7 +174,7 @@ public abstract class ArbitraryShape { } } - if (editSession.setBlock(position, pattern)) { + if (editSession.setBlock(position, material)) { ++affected; } } diff --git a/src/main/java/com/sk89q/worldedit/commands/GenerationCommands.java b/src/main/java/com/sk89q/worldedit/commands/GenerationCommands.java index 85fded4de..ccff176ba 100644 --- a/src/main/java/com/sk89q/worldedit/commands/GenerationCommands.java +++ b/src/main/java/com/sk89q/worldedit/commands/GenerationCommands.java @@ -25,6 +25,7 @@ import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.minecraft.util.commands.Logging; import static com.sk89q.minecraft.util.commands.Logging.LogMode.*; import com.sk89q.worldedit.*; +import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.expression.Expression; import com.sk89q.worldedit.expression.ExpressionException; import com.sk89q.worldedit.patterns.Pattern; @@ -332,12 +333,12 @@ public class GenerationCommands { if (args.hasFlag('r')) { shape = new ArbitraryShape(region) { @Override - protected boolean isInside(double x, double y, double z) { + protected BaseBlock getMaterial(int x, int y, int z, BaseBlock defaultMaterial) { try { - return expression.evaluate(x, y, z) > 0; + return expression.evaluate(x, y, z) > 0 ? defaultMaterial : null; } catch (Exception e) { e.printStackTrace(); - return false; + return null; } } }; @@ -350,12 +351,12 @@ public class GenerationCommands { shape = new ArbitraryShape(region) { @Override - protected boolean isInside(double x, double y, double z) { + protected BaseBlock getMaterial(int x, int y, int z, BaseBlock defaultMaterial) { try { - return expression.evaluate(x - placementX, y - placementY, z - placementZ) > 0; + return expression.evaluate(x - placementX, y - placementY, z - placementZ) > 0 ? defaultMaterial : null; } catch (Exception e) { e.printStackTrace(); - return false; + return null; } } }; @@ -366,14 +367,14 @@ public class GenerationCommands { final Vector stretch = max.subtract(center); shape = new ArbitraryShape(region) { @Override - protected boolean isInside(double x, double y, double z) { + protected BaseBlock getMaterial(int x, int y, int z, BaseBlock defaultMaterial) { final Vector scaled = new Vector(x, y, z).subtract(center).divide(stretch); try { - return expression.evaluate(scaled.getX(), scaled.getY(), scaled.getZ()) > 0; + return expression.evaluate(scaled.getX(), scaled.getY(), scaled.getZ()) > 0 ? defaultMaterial : null; } catch (Exception e) { e.printStackTrace(); - return false; + return null; } } };