diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index 593f6ec91..b57ca8d6a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -25,6 +25,8 @@ import static com.sk89q.worldedit.regions.Regions.asFlatRegion; import static com.sk89q.worldedit.regions.Regions.maximumBlockY; import static com.sk89q.worldedit.regions.Regions.minimumBlockY; +import com.sk89q.worldedit.function.block.BlockDistributionCounter; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.event.extent.EditSessionEvent; @@ -1652,115 +1654,11 @@ public class EditSession implements Extent { * @param region a region * @return the results */ - public List> getBlockDistribution(Region region) { - List> distribution = new ArrayList<>(); - Map> map = new HashMap<>(); - - if (region instanceof CuboidRegion) { - // Doing this for speed - Vector min = region.getMinimumPoint(); - Vector max = region.getMaximumPoint(); - - int minX = min.getBlockX(); - int minY = min.getBlockY(); - int minZ = min.getBlockZ(); - int maxX = max.getBlockX(); - int maxY = max.getBlockY(); - int maxZ = max.getBlockZ(); - - for (int x = minX; x <= maxX; ++x) { - for (int y = minY; y <= maxY; ++y) { - for (int z = minZ; z <= maxZ; ++z) { - Vector pt = new Vector(x, y, z); - - BlockType type = getBlock(pt).getBlockType(); - - if (map.containsKey(type)) { - map.get(type).increment(); - } else { - Countable c = new Countable<>(type, 1); - map.put(type, c); - distribution.add(c); - } - } - } - } - } else { - for (Vector pt : region) { - BlockType type = getBlock(pt).getBlockType(); - - if (map.containsKey(type)) { - map.get(type).increment(); - } else { - Countable c = new Countable<>(type, 1); - map.put(type, c); - } - } - } - - Collections.sort(distribution); - // Collections.reverse(distribution); - - return distribution; - } - - /** - * Get the block distribution (with data values) inside a region. - * - * @param region a region - * @return the results - */ - // TODO reduce code duplication - probably during ops-redux - public List> getBlockDistributionWithData(Region region) { - List> distribution = new ArrayList<>(); - Map> map = new HashMap<>(); - - if (region instanceof CuboidRegion) { - // Doing this for speed - Vector min = region.getMinimumPoint(); - Vector max = region.getMaximumPoint(); - - int minX = min.getBlockX(); - int minY = min.getBlockY(); - int minZ = min.getBlockZ(); - int maxX = max.getBlockX(); - int maxY = max.getBlockY(); - int maxZ = max.getBlockZ(); - - for (int x = minX; x <= maxX; ++x) { - for (int y = minY; y <= maxY; ++y) { - for (int z = minZ; z <= maxZ; ++z) { - Vector pt = new Vector(x, y, z); - - BlockStateHolder blk = getBlock(pt); - - if (map.containsKey(blk)) { - map.get(blk).increment(); - } else { - Countable c = new Countable<>(blk, 1); - map.put(blk, c); - distribution.add(c); - } - } - } - } - } else { - for (Vector pt : region) { - BlockStateHolder blk = getBlock(pt); - - if (map.containsKey(blk)) { - map.get(blk).increment(); - } else { - Countable c = new Countable<>(blk, 1); - map.put(blk, c); - } - } - } - - Collections.sort(distribution); - // Collections.reverse(distribution); - - return distribution; + public List> getBlockDistribution(Region region, boolean fuzzy) { + BlockDistributionCounter count = new BlockDistributionCounter(this, fuzzy); + RegionVisitor visitor = new RegionVisitor(region, count); + Operations.completeBlindly(visitor); + return count.getDistribution(); } public int makeShape(final Region region, final Vector zero, final Vector unit, final Pattern pattern, final String expressionString, final boolean hollow) throws ExpressionException, MaxChangedBlocksException { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index fb4d9824e..5f4fca09c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -662,49 +662,40 @@ public class SelectionCommands { int size; boolean useData = args.hasFlag('d'); - List> distribution = null; - List> distributionData = null; + List> distribution; if (args.hasFlag('c')) { // TODO: Update for new clipboard throw new CommandException("Needs to be re-written again"); } else { - if (useData) { - distributionData = editSession.getBlockDistributionWithData(session.getSelection(player.getWorld())); - } else { - distribution = editSession.getBlockDistribution(session.getSelection(player.getWorld())); - } + distribution = editSession.getBlockDistribution(session.getSelection(player.getWorld()), !useData); size = session.getSelection(player.getWorld()).getArea(); } - if ((useData && distributionData.size() <= 0) || (!useData && distribution.size() <= 0)) { // *Should* always be false + if (distribution.isEmpty()) { // *Should* always be false player.printError("No blocks counted."); return; } player.print("# total blocks: " + size); - if (useData) { - for (Countable c : distributionData) { - String name = c.getID().getBlockType().getName(); - String str = String.format("%-7s (%.3f%%) %s #%s%s", + for (Countable c : distribution) { + String name = c.getID().getBlockType().getName(); + String str; + if (useData) { + str = String.format("%-7s (%.3f%%) %s #%s", String.valueOf(c.getAmount()), c.getAmount() / (double) size * 100, name, - c.getID().getBlockType().getId(), - c.getID().getStates()); - player.print(str); - } - } else { - for (Countable c : distribution) { - String name = c.getID().getName(); - String str = String.format("%-7s (%.3f%%) %s #%s", + c.getID().getAsString()); + } else { + str = String.format("%-7s (%.3f%%) %s #%s", String.valueOf(c.getAmount()), c.getAmount() / (double) size * 100, name, - c.getID().getId()); - player.print(str); + c.getID().getBlockType().getId()); } + player.print(str); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/BlockDistributionCounter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/BlockDistributionCounter.java new file mode 100644 index 000000000..8d282e9c3 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/BlockDistributionCounter.java @@ -0,0 +1,77 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.function.block; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.util.Countable; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class BlockDistributionCounter implements RegionFunction { + + private Extent extent; + private boolean fuzzy; + + private List> distribution = new ArrayList<>(); + private Map> map = new HashMap<>(); + + public BlockDistributionCounter(Extent extent, boolean fuzzy) { + this.extent = extent; + this.fuzzy = fuzzy; + } + + @Override + public boolean apply(Vector position) throws WorldEditException { + BlockStateHolder blk = extent.getBlock(position); + if (fuzzy) { + blk = ((BlockState) blk).toFuzzy(); + } + + if (map.containsKey(blk)) { + map.get(blk).increment(); + } else { + Countable c = new Countable<>(blk, 1); + map.put(blk, c); + distribution.add(c); + } + + return true; + } + + /** + * Gets the distribution list. + * + * @return The distribution + */ + public List> getDistribution() { + Collections.sort(distribution); + Collections.reverse(distribution); + return this.distribution; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java index e3dd5d7d3..d92979155 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java @@ -142,8 +142,7 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { final BaseBlock otherBlock = (BaseBlock) o; - return Objects.equals(this.toImmutableState(), otherBlock.toImmutableState()) && Objects.equals(getNbtData(), otherBlock.getNbtData()); - + return this.toImmutableState().equalsFuzzy(otherBlock.toImmutableState()) && Objects.equals(getNbtData(), otherBlock.getNbtData()); } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index de527baf4..ef2a9c281 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -239,4 +239,18 @@ public class BlockState implements BlockStateHolder { public String toString() { return getAsString(); } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof BlockState)) { + return false; + } + + return equalsFuzzy((BlockState) obj); + } + + @Override + public int hashCode() { + return Objects.hash(blockType, values, fuzzy); + } }