diff --git a/core/src/main/java/com/boydti/fawe/Fawe.java b/core/src/main/java/com/boydti/fawe/Fawe.java index cbbf509e..b4eeabf5 100644 --- a/core/src/main/java/com/boydti/fawe/Fawe.java +++ b/core/src/main/java/com/boydti/fawe/Fawe.java @@ -472,11 +472,6 @@ public class Fawe { // BlockData BlockData.inject(); // Temporary fix for 1.9.4 BundledBlockData.inject(); // Add custom rotation - try { - BundledBlockData.getInstance().loadFromResource(); - } catch (IOException e) { - MainUtil.handleError(e); - } File jar = MainUtil.getJarFile(); File extraBlocks = MainUtil.copyFile(jar, "extrablocks.json", null); if (extraBlocks != null && extraBlocks.exists()) { diff --git a/core/src/main/java/com/boydti/fawe/FaweCache.java b/core/src/main/java/com/boydti/fawe/FaweCache.java index 526b25c7..70bfbd98 100644 --- a/core/src/main/java/com/boydti/fawe/FaweCache.java +++ b/core/src/main/java/com/boydti/fawe/FaweCache.java @@ -16,6 +16,7 @@ import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.blocks.BlockType; import com.sk89q.worldedit.blocks.ImmutableBlock; import com.sk89q.worldedit.blocks.ImmutableDatalessBlock; import com.sk89q.worldedit.world.biome.BaseBiome; @@ -51,16 +52,8 @@ public class FaweCache { */ public final static byte[][] CACHE_Z = new byte[16][4096]; - /** - * [ combined ] => id - * (combined >> 4) = id - */ - public final static short[] CACHE_ID = new short[65535]; - /** - * [ combined ] => data - * (combined & 0xF) = data - */ - public final static byte[] CACHE_DATA = new byte[65535]; + public final static boolean[] CACHE_PASSTHROUGH = new boolean[65535]; + public final static boolean[] CACHE_TRANSLUSCENT = new boolean[65535]; /** * Immutable biome cache @@ -162,13 +155,24 @@ public class FaweCache { } } } - for (int i = 0; i < 65535; i++) { - final int j = i >> 4; - final int k = i & 0xF; - CACHE_ID[i] = (short) j; - CACHE_DATA[i] = (byte) k; - } - + try { + BundledBlockData bundled = BundledBlockData.getInstance(); + bundled.loadFromResource(); + for (int i = 0; i < Character.MAX_VALUE; i++) { + int id = i >> 4; + int data = i & 0xf; + CACHE_TRANSLUSCENT[i] = BlockType.isTranslucent(id); + CACHE_PASSTHROUGH[i] = BlockType.canPassThrough(id, data); + BundledBlockData.BlockEntry blockEntry = bundled.findById(id); + if (blockEntry != null) { + BundledBlockData.FaweBlockMaterial material = blockEntry.material; + if (material != null) { + CACHE_TRANSLUSCENT[i] = !material.isOpaque(); + CACHE_PASSTHROUGH[i] = !material.isMovementBlocker(); + } + } + } + } catch (Throwable ignore) {} for (int i = 0; i < Character.MAX_VALUE; i++) { int id = i >> 4; int data = i & 0xf; @@ -266,6 +270,14 @@ public class FaweCache { CACHE_COLOR[getCombined(35, 15)] = new Color(0, 0, 0); // Black } + public static boolean canPassThrough(int id, int data) { + return CACHE_PASSTHROUGH[FaweCache.getCombined(id, data)]; + } + + public static boolean isTranslucent(int id, int data) { + return CACHE_TRANSLUSCENT[FaweCache.getCombined(id, data)]; + } + public static boolean isLiquidOrGas(int id) { switch (id) { case 0: diff --git a/core/src/main/java/com/boydti/fawe/object/brush/StencilBrush.java b/core/src/main/java/com/boydti/fawe/object/brush/StencilBrush.java index e96b0e84..af4ee7af 100644 --- a/core/src/main/java/com/boydti/fawe/object/brush/StencilBrush.java +++ b/core/src/main/java/com/boydti/fawe/object/brush/StencilBrush.java @@ -1,11 +1,12 @@ package com.boydti.fawe.object.brush; +import com.boydti.fawe.object.PseudoRandom; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.Mask; -import com.sk89q.worldedit.function.mask.Masks; import com.sk89q.worldedit.function.pattern.Pattern; import java.io.InputStream; @@ -20,15 +21,15 @@ public class StencilBrush extends HeightBrush { @Override public void build(EditSession editSession, Vector position, Pattern pattern, double sizeDouble) throws MaxChangedBlocksException { int size = (int) sizeDouble; - Mask mask = editSession.getMask(); - if (mask == Masks.alwaysTrue() || mask == Masks.alwaysTrue2D()) { - mask = null; - } + Mask mask = new ExistingBlockMask(editSession); + int maxY = editSession.getMaxY(); + double scale = (yscale / sizeDouble) * (maxY + 1); heightMap.setSize(size); + int cutoff = onlyWhite ? maxY : 0; + for (int x = -size; x <= size; x++) { int xx = position.getBlockX() + x; for (int z = -size; z <= size; z++) { - int zz = position.getBlockZ() + z; double raise; switch (rotation) { default:raise = heightMap.getHeight(x, z); break; @@ -36,19 +37,16 @@ public class StencilBrush extends HeightBrush { case 2: raise = heightMap.getHeight(-x, -z); break; case 3: raise = heightMap.getHeight(-z, -x);break; } - raise *= yscale; - if (raise == 0 || (onlyWhite && raise < 255)) { + int val = (int) Math.ceil(raise * scale); + if (val <= cutoff) { continue; } + if (val >= 255 || PseudoRandom.random.random(maxY) < val) { + int zz = position.getBlockZ() + z; + int y = editSession.getNearestSurfaceTerrainBlock(xx, zz, position.getBlockY(), 0, maxY); + editSession.setBlock(xx, y, zz, pattern); + } } } - - - int[] data = heightMap.generateHeightData(editSession, mask, position, size, rotation, yscale, true, false); - int diameter = size * 2; - int x = position.getBlockX(); - int y = position.getBlockY(); - int z = position.getBlockZ(); } - -} +} \ No newline at end of file diff --git a/core/src/main/java/com/boydti/fawe/object/brush/heightmap/ScalableHeightMap.java b/core/src/main/java/com/boydti/fawe/object/brush/heightmap/ScalableHeightMap.java index 6b79238d..11e9450b 100644 --- a/core/src/main/java/com/boydti/fawe/object/brush/heightmap/ScalableHeightMap.java +++ b/core/src/main/java/com/boydti/fawe/object/brush/heightmap/ScalableHeightMap.java @@ -131,7 +131,7 @@ public class ScalableHeightMap { WorldVector min = new WorldVector(LocalWorldAdapter.adapt(session.getWorld()), pos.subtract(size, maxY, size)); Vector max = pos.add(size, maxY, size); Region region = new CuboidRegion(session.getWorld(), min, max); - HeightMap heightMap = new HeightMap(session, region, true); + HeightMap heightMap = new HeightMap(session, region, false); if (smooth) { try { HeightMapFilter filter = (HeightMapFilter) HeightMapFilter.class.getConstructors()[0].newInstance(GaussianKernel.class.getConstructors()[0].newInstance(5, 1)); @@ -178,7 +178,7 @@ public class ScalableHeightMap { raise = getHeight(-z, -x); break; } - int height = session.getHighestTerrainBlock(xx, zz, 0, 255, false); + int height = session.getNearestSurfaceTerrainBlock(xx, zz, pos.getBlockY(), 0, 255); if (height == 0) { newData[index] = centerY; continue; @@ -214,7 +214,7 @@ public class ScalableHeightMap { raise = getHeight(-z, -x); break; } - int height = session.getHighestTerrainBlock(xx, zz, 0, maxY, false); + int height = session.getNearestSurfaceTerrainBlock(xx, zz, pos.getBlockY(), 0, maxY); if (height == 0) { newData[index] = centerY; continue; diff --git a/core/src/main/java/com/sk89q/worldedit/EditSession.java b/core/src/main/java/com/sk89q/worldedit/EditSession.java index 23baac82..206df035 100644 --- a/core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -929,10 +929,14 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting */ @Deprecated public int getBlockType(final Vector position) { + return getBlockType(position.getBlockX(), position.getBlockY(), position.getBlockZ()); + } + + public int getBlockType(int x, int y, int z) { if (!limit.MAX_CHECKS()) { throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS); } - int combinedId4Data = queue.getCombinedId4DataDebug(position.getBlockX(), position.getBlockY(), position.getBlockZ(), 0, this); + int combinedId4Data = queue.getCombinedId4DataDebug(x, y, z, 0, this); return combinedId4Data >> 4; } @@ -977,6 +981,38 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting return this.getHighestTerrainBlock(x, z, minY, maxY, false); } + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) { + int clearanceAbove = maxY - y; + int clearanceBelow = y - minY; + int clearance = Math.min(clearanceAbove, clearanceBelow); + + BaseBlock block = getBlock(x, y, z); + boolean state = FaweCache.canPassThrough(block.getId(), block.getData()); + int offset = state ? 0 : 1; + for (int d = 0; d <= clearance; d++) { + int y1 = y + d; + block = getLazyBlock(x, y1, z); + if (FaweCache.canPassThrough(block.getId(), block.getData()) != state) return y1 - offset; + int y2 = y - d; + block = getLazyBlock(x, y2, z); + if (FaweCache.canPassThrough(block.getId(), block.getData()) != state) return y2 + offset; + } + if (clearanceAbove != clearanceBelow) { + if (clearanceAbove < clearanceBelow) { + for (int layer = y - clearance - 1; layer >= minY; layer--) { + block = getLazyBlock(x, layer, z); + if (FaweCache.canPassThrough(block.getId(), block.getData()) != state) return layer + offset; + } + } else { + for (int layer = y + clearance + 1; layer <= maxY; layer++) { + block = getLazyBlock(x, layer, z); + if (FaweCache.canPassThrough(block.getId(), block.getData()) != state) return layer - offset; + } + } + } + return maxY; + } + /** * Returns the highest solid 'terrain' block which can occur naturally. * @@ -990,100 +1026,19 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting public int getHighestTerrainBlock(final int x, final int z, int minY, int maxY, final boolean naturalOnly) { maxY = Math.min(maxY, Math.max(0, maxY)); minY = Math.max(0, minY); - for (int y = maxY; y >= minY; --y) { - BaseBlock block = getLazyBlock(x, y, z); - final int id = block.getId(); - int data; - switch (id) { - case 0: { - continue; - } - case 2: - case 4: - case 13: - case 14: - case 15: - case 20: - case 21: - case 22: - case 25: - case 30: - case 32: - case 37: - case 39: - case 40: - case 41: - case 42: - case 45: - case 46: - case 47: - case 48: - case 49: - case 51: - case 52: - case 54: - case 55: - case 56: - case 57: - case 58: - case 60: - case 61: - case 62: - case 7: - case 8: - case 9: - case 10: - case 11: - case 73: - case 74: - case 78: - case 79: - case 80: - case 81: - case 82: - case 83: - case 84: - case 85: - case 87: - case 88: - case 101: - case 102: - case 103: - case 110: - case 112: - case 113: - case 117: - case 121: - case 122: - case 123: - case 124: - case 129: - case 133: - case 138: - case 137: - case 140: - case 165: - case 166: - case 169: - case 170: - case 172: - case 173: - case 174: - case 176: - case 177: - case 181: - case 182: - case 188: - case 189: - case 190: - case 191: - case 192: + if (naturalOnly) { + for (int y = maxY; y >= minY; --y) { + BaseBlock block = getLazyBlock(x, y, z); + if (BlockType.isNaturalTerrainBlock(block.getId(), block.getData())) { return y; - default: - data = 0; + } } - if (naturalOnly ? BlockType.isNaturalTerrainBlock(id, data) : !BlockType.canPassThrough(id, data)) { - return y; + } else { + for (int y = maxY; y >= minY; --y) { + BaseBlock block = getLazyBlock(x, y, z); + if (!FaweCache.canPassThrough(block.getId(), block.getData())) { + return y; + } } } return minY;