diff --git a/core/src/main/java/com/boydti/fawe/object/brush/heightmap/HeightMap.java b/core/src/main/java/com/boydti/fawe/object/brush/heightmap/HeightMap.java index 162afd77..cf3024fd 100644 --- a/core/src/main/java/com/boydti/fawe/object/brush/heightmap/HeightMap.java +++ b/core/src/main/java/com/boydti/fawe/object/brush/heightmap/HeightMap.java @@ -33,7 +33,7 @@ public interface HeightMap { 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); - com.sk89q.worldedit.math.convolution.HeightMap heightMap = new com.sk89q.worldedit.math.convolution.HeightMap(session, region, data[0]); + com.sk89q.worldedit.math.convolution.HeightMap heightMap = new com.sk89q.worldedit.math.convolution.HeightMap(session, region, data[0], layers); if (smooth) { try { HeightMapFilter filter = (HeightMapFilter) HeightMapFilter.class.getConstructors()[0].newInstance(GaussianKernel.class.getConstructors()[0].newInstance(5, 1)); diff --git a/core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index 98ee3ca3..3c5db286 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -22,9 +22,12 @@ package com.sk89q.worldedit.command; import com.boydti.fawe.FaweAPI; import com.boydti.fawe.config.BBC; import com.boydti.fawe.example.NMSMappedFaweQueue; +import com.boydti.fawe.object.FaweLimit; import com.boydti.fawe.object.FaweLocation; import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.FaweQueue; +import com.boydti.fawe.object.exception.FaweException; +import com.boydti.fawe.object.visitor.Fast2DIterator; import com.boydti.fawe.util.MathMan; import com.boydti.fawe.util.SetQueue; import com.sk89q.jnbt.CompoundTag; @@ -34,6 +37,7 @@ import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.minecraft.util.commands.Logging; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.MutableBlockVector; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.WorldEdit; @@ -62,6 +66,7 @@ import com.sk89q.worldedit.regions.ConvexPolyhedralRegion; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.RegionOperationException; +import com.sk89q.worldedit.regions.Regions; import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.util.command.binding.Range; @@ -72,6 +77,7 @@ import com.sk89q.worldedit.world.biome.BaseBiome; import com.sk89q.worldedit.world.biome.Biomes; import com.sk89q.worldedit.world.registry.BiomeRegistry; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; @@ -307,23 +313,23 @@ public class RegionCommands { if (!FawePlayer.wrap(player).hasPermission("fawe.tips")) BBC.TIP_REPLACE_ID.or(BBC.TIP_REPLACE_LIGHT, BBC.TIP_REPLACE_MARKER, BBC.TIP_TAB_COMPLETE).send(player); } - @Command( - aliases = { "/mapreplace", "/mr", "/maprep" }, - usage = " ", - desc = "Replace all blocks in a selection 1:1 with the ", - flags = "f", - min = 1, - max = 2 - ) - @CommandPermissions("worldedit.region.mapreplace") - @Logging(REGION) - public void mapreplace(Player player, EditSession editSession, @Selection Region region, @Optional Mask from, Pattern to) throws WorldEditException { - if (from == null) { - from = new ExistingBlockMask(editSession); - } - int affected = editSession.replaceBlocks(region, from, to); - BBC.VISITOR_BLOCK.send(player, affected); - } +// @Command( +// aliases = { "/mapreplace", "/mr", "/maprep" }, +// usage = " ", +// desc = "Replace all blocks in a selection 1:1 with the ", +// flags = "f", +// min = 1, +// max = 2 +// ) +// @CommandPermissions("worldedit.region.mapreplace") +// @Logging(REGION) +// public void mapreplace(Player player, EditSession editSession, @Selection Region region, @Optional Mask from, Pattern to) throws WorldEditException { +// if (from == null) { +// from = new ExistingBlockMask(editSession); +// } +// int affected = editSession.replaceBlocks(region, from, to); +// BBC.VISITOR_BLOCK.send(player, affected); +// } @Command( aliases = { "/set" }, @@ -361,6 +367,39 @@ public class RegionCommands { BBC.VISITOR_BLOCK.send(player, affected); } + @Command( + aliases = { "/lay" }, + usage = "", + desc = "Set the top block in the region", + min = 1, + max = 1 + ) + @CommandPermissions("worldedit.region.overlay") + @Logging(REGION) + public void lay(Player player, EditSession editSession, @Selection Region region, Pattern pattern) throws WorldEditException { + Vector min = region.getMinimumPoint(); + Vector max = region.getMaximumPoint(); + int maxY = max.getBlockY(); + int width = region.getWidth(); + int height = region.getLength(); + int bx = min.getBlockX(); + int bz = min.getBlockZ(); + Iterable flat = Regions.asFlatRegion(region).asFlatRegion(); + Iterator iter = new Fast2DIterator(flat, editSession).iterator(); + int y = 0; + int affected = 0; + MutableBlockVector mutable = new MutableBlockVector(); + while (iter.hasNext()) { + Vector2D pos = iter.next(); + int x = pos.getBlockX(); + int z = pos.getBlockZ(); + y = editSession.getNearestSurfaceTerrainBlock(x, z, y, 0, maxY); + editSession.setBlock(x, y, z, pattern); + affected++; + } + BBC.VISITOR_BLOCK.send(player, affected); + } + @Command( aliases = { "/center", "/middle" }, usage = "", @@ -424,15 +463,23 @@ public class RegionCommands { desc = "Smooth the elevation in the selection", help = "Smooths the elevation in the selection.\n" + - "The -n flag makes it only consider naturally occuring blocks.", + "The -n flag makes it only consider naturally occuring blocks.\n" + + "The -s flag makes it only consider snow.", min = 0, - max = 1 + max = 2 ) - @CommandPermissions("worldedit.region.smooth") + @CommandPermissions("worldedit.region.smoothsnow") @Logging(REGION) - public void smooth(Player player, EditSession editSession, @Selection Region region, @Optional("1") int iterations, @Switch('n') boolean affectNatural) throws WorldEditException { - HeightMap heightMap = new HeightMap(editSession, region, affectNatural); + public void smooth(Player player, EditSession editSession, @Selection Region region, @Optional("1") int iterations, @Switch('n') boolean affectNatural, @Switch('s') boolean snow) throws WorldEditException { try { + Vector min = region.getMinimumPoint(); + Vector max = region.getMaximumPoint(); + long volume = (((long)max.getX() - (long)min.getX() + 1) * ((long)max.getY() - (long)min.getY() + 1) * ((long)max.getZ() - (long)min.getZ() + 1)); + FaweLimit limit = FawePlayer.wrap(player).getLimit(); + if (volume >= limit.MAX_CHECKS) { + throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS); + } + HeightMap heightMap = new HeightMap(editSession, region, affectNatural, snow); HeightMapFilter filter = (HeightMapFilter) HeightMapFilter.class.getConstructors()[0].newInstance(GaussianKernel.class.getConstructors()[0].newInstance(5, 1)); int affected = heightMap.applyFilter(filter, iterations); BBC.VISITOR_BLOCK.send(player, affected); diff --git a/core/src/main/java/com/sk89q/worldedit/math/convolution/HeightMap.java b/core/src/main/java/com/sk89q/worldedit/math/convolution/HeightMap.java index 7315b2c6..18bd6d46 100644 --- a/core/src/main/java/com/sk89q/worldedit/math/convolution/HeightMap.java +++ b/core/src/main/java/com/sk89q/worldedit/math/convolution/HeightMap.java @@ -1,12 +1,17 @@ package com.sk89q.worldedit.math.convolution; import com.boydti.fawe.FaweCache; +import com.boydti.fawe.object.visitor.Fast2DIterator; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.MutableBlockVector; import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.Regions; +import java.util.Iterator; import static com.google.common.base.Preconditions.checkNotNull; @@ -18,6 +23,7 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public class HeightMap { + private final boolean layers; private int[] data; private int width; private int height; @@ -36,6 +42,10 @@ public class HeightMap { } public HeightMap(EditSession session, Region region, boolean naturalOnly) { + this(session, region, naturalOnly, false); + } + + public HeightMap(EditSession session, Region region, boolean naturalOnly, boolean layers) { checkNotNull(session); checkNotNull(region); @@ -45,21 +55,44 @@ public class HeightMap { this.width = region.getWidth(); this.height = region.getLength(); + this.layers = layers; + int minX = region.getMinimumPoint().getBlockX(); int minY = region.getMinimumPoint().getBlockY(); int minZ = region.getMinimumPoint().getBlockZ(); int maxY = region.getMaximumPoint().getBlockY(); - // Store current heightmap data - data = new int[width * height]; - for (int z = 0; z < height; ++z) { - for (int x = 0; x < width; ++x) { - data[z * width + x] = session.getHighestTerrainBlock(x + minX, z + minZ, minY, maxY, naturalOnly); + if (layers) { + Vector min = region.getMinimumPoint(); + Vector max = region.getMaximumPoint(); + int width = region.getWidth(); + int height = region.getLength(); + data = new int[width * height]; + int bx = min.getBlockX(); + int bz = min.getBlockZ(); + Iterable flat = Regions.asFlatRegion(region).asFlatRegion(); + Iterator iter = new Fast2DIterator(flat, session).iterator(); + int y = 0; + MutableBlockVector mutable = new MutableBlockVector(); + while (iter.hasNext()) { + Vector2D pos = iter.next(); + int x = pos.getBlockX(); + int z = pos.getBlockZ(); + y = session.getNearestSurfaceLayer(x, z, y, 0, maxY); + data[(z - bz) * width + (x - bx)] = y; + } + } else { + // Store current heightmap data + data = new int[width * height]; + for (int z = 0; z < height; ++z) { + for (int x = 0; x < width; ++x) { + data[z * width + x] = session.getHighestTerrainBlock(x + minX, z + minZ, minY, maxY, naturalOnly); + } } } } - public HeightMap(EditSession session, Region region, int[] data) { + public HeightMap(EditSession session, Region region, int[] data, boolean layers) { this.session = session; this.region = region; @@ -67,6 +100,8 @@ public class HeightMap { this.height = region.getLength(); this.data = data; + + this.layers = layers; } /** @@ -77,7 +112,6 @@ public class HeightMap { * @return number of blocks affected * @throws MaxChangedBlocksException */ - public int applyFilter(HeightMapFilter filter, int iterations) throws WorldEditException { checkNotNull(filter); @@ -88,7 +122,7 @@ public class HeightMap { newData = filter.filter(newData, width, height); } - return apply(newData); + return layers ? applyLayers(newData) : apply(newData); } public int applyLayers(int[] data) throws WorldEditException {