Merge Moo0's data flag for distr.

Also added data flag to //count.
  //count -d 35 will now only search for white wool.
  //count 35:5 will only search for green wool.
  //count 35 will work as normal.
  //count 35:-1 will also work.
This commit is contained in:
Wizjany 2013-01-19 09:31:00 -05:00
parent c2154b0f86
commit d78bbc4f68
3 changed files with 193 additions and 34 deletions

View File

@ -20,10 +20,6 @@
package com.sk89q.worldedit;
import com.sk89q.worldedit.blocks.*;
import com.sk89q.worldedit.data.*;
import com.sk89q.worldedit.schematic.SchematicFormat;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
@ -32,6 +28,10 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.data.DataException;
import com.sk89q.worldedit.schematic.SchematicFormat;
/**
* The clipboard remembers the state of a cuboid region.
*
@ -459,4 +459,43 @@ public class CuboidClipboard {
return distribution;
}
/**
* Get the block distribution inside a clipboard with data values.
*
* @return
*/
// TODO reduce code duplication
public List<Countable<BaseBlock>> getBlockDistributionWithData() {
List<Countable<BaseBlock>> distribution = new ArrayList<Countable<BaseBlock>>();
Map<BaseBlock, Countable<BaseBlock>> map = new HashMap<BaseBlock, Countable<BaseBlock>>();
int maxX = getWidth();
int maxY = getHeight();
int maxZ = getLength();
for (int x = 0; x < maxX; ++x) {
for (int y = 0; y < maxY; ++y) {
for (int z = 0; z < maxZ; ++z) {
int id = data[x][y][z].getId();
int meta = data[x][y][z].getData();
BaseBlock blk = new BaseBlock(id, meta);
if (map.containsKey(blk)) {
map.get(blk).increment();
} else {
Countable<BaseBlock> c = new Countable<BaseBlock>(blk, 1);
map.put(blk, c);
distribution.add(c);
}
}
}
}
Collections.sort(distribution);
// Collections.reverse(distribution);
return distribution;
}
}

View File

@ -525,16 +525,40 @@ public class EditSession {
return false;
}
public int countBlock(Region region, Set<Integer> searchIDs) {
Set<BaseBlock> passOn = new HashSet<BaseBlock>();
for (Integer i : searchIDs) {
passOn.add(new BaseBlock(i, -1));
}
return countBlocks(region, passOn);
}
/**
* Count the number of blocks of a list of types in a region.
*
* @param region
* @param searchIDs
* @param searchBlocks
* @return
*/
public int countBlocks(Region region, Set<Integer> searchIDs) {
public int countBlocks(Region region, Set<BaseBlock> searchBlocks) {
int count = 0;
// allow -1 data in the searchBlocks to match any type
Set<BaseBlock> newSet = new HashSet<BaseBlock>() {
@Override
public boolean contains(Object o) {
for (BaseBlock b : this.toArray(new BaseBlock[this.size()])) {
if (o instanceof BaseBlock) {
if (b.equalsFuzzy((BaseBlock) o)) {
return true;
}
}
}
return false;
}
};
newSet.addAll(searchBlocks);
if (region instanceof CuboidRegion) {
// Doing this for speed
Vector min = region.getMinimumPoint();
@ -552,7 +576,8 @@ public class EditSession {
for (int z = minZ; z <= maxZ; ++z) {
Vector pt = new Vector(x, y, z);
if (searchIDs.contains(getBlockType(pt))) {
BaseBlock compare = new BaseBlock(getBlockType(pt), getBlockData(pt));
if (newSet.contains(compare)) {
++count;
}
}
@ -560,7 +585,8 @@ public class EditSession {
}
} else {
for (Vector pt : region) {
if (searchIDs.contains(getBlockType(pt))) {
BaseBlock compare = new BaseBlock(getBlockType(pt), getBlockData(pt));
if (newSet.contains(compare)) {
++count;
}
}
@ -2671,6 +2697,65 @@ public class EditSession {
return distribution;
}
/**
* Get the block distribution (with data values) inside a region.
*
* @param region
* @return
*/
// TODO reduce code duplication - probably during ops-redux
public List<Countable<BaseBlock>> getBlockDistributionWithData(Region region) {
List<Countable<BaseBlock>> distribution = new ArrayList<Countable<BaseBlock>>();
Map<BaseBlock, Countable<BaseBlock>> map = new HashMap<BaseBlock, Countable<BaseBlock>>();
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);
BaseBlock blk = new BaseBlock(getBlockType(pt), getBlockData(pt));
if (map.containsKey(blk)) {
map.get(blk).increment();
} else {
Countable<BaseBlock> c = new Countable<BaseBlock>(blk, 1);
map.put(blk, c);
distribution.add(c);
}
}
}
}
} else {
for (Vector pt : region) {
BaseBlock blk = new BaseBlock(getBlockType(pt), getBlockData(pt));
if (map.containsKey(blk)) {
map.get(blk).increment();
} else {
Countable<BaseBlock> c = new Countable<BaseBlock>(blk, 1);
map.put(blk, c);
}
}
}
Collections.sort(distribution);
// Collections.reverse(distribution);
return distribution;
}
public int makeShape(final Region region, final Vector zero, final Vector unit, final Pattern pattern, final String expressionString, final boolean hollow) throws ExpressionException, MaxChangedBlocksException {
final Expression expression = Expression.compile(expressionString, "x", "y", "z", "type", "data");
expression.optimize();
@ -2855,4 +2940,5 @@ public class EditSession {
}
} // while
}
}

View File

@ -41,6 +41,7 @@ import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.blocks.BlockType;
import com.sk89q.worldedit.data.ChunkStore;
import com.sk89q.worldedit.regions.CuboidRegionSelector;
@ -562,61 +563,94 @@ public class SelectionCommands {
aliases = { "/count" },
usage = "<block>",
desc = "Counts the number of a certain type of block",
flags = "d",
min = 1,
max = 1
)
@CommandPermissions("worldedit.analysis.count")
public void count(CommandContext args, LocalSession session, LocalPlayer player,
EditSession editSession) throws WorldEditException {
Set<Integer> searchIDs = we.getBlockIDs(player,
args.getString(0), true);
player.print("Counted: " +
editSession.countBlocks(session.getSelection(player.getWorld()), searchIDs));
boolean useData = args.hasFlag('d');
if (args.getString(0).contains(":")) {
useData = true; //override d flag, if they specified data they want it
}
if (useData) {
Set<BaseBlock> searchBlocks = we.getBlocks(player, args.getString(0), true);
int count = editSession.countBlocks(session.getSelection(player.getWorld()), searchBlocks);
player.print("Counted: " + count);
} else {
Set<Integer> searchIDs = we.getBlockIDs(player, args.getString(0), true);
int count = editSession.countBlock(session.getSelection(player.getWorld()), searchIDs);
player.print("Counted: " + count);
}
}
@Command(
aliases = { "/distr" },
usage = "",
desc = "Get the distribution of blocks in the selection",
desc = "Get the distribution of blocks in the selection",
help =
"Gets the distribution of blocks in the selection.\n" +
"The -c flag gets the distribution of your clipboard.",
flags = "c",
"The -c flag gets the distribution of your clipboard.\n" +
"The -d flag separates blocks by data",
flags = "cd",
min = 0,
max = 0
)
@CommandPermissions("worldedit.analysis.distr")
@CommandPermissions("worldedit.analysis.distr")
public void distr(CommandContext args, LocalSession session, LocalPlayer player,
EditSession editSession) throws WorldEditException {
List<Countable<Integer>> distribution;
int size;
boolean useData = args.hasFlag('d');
List<Countable<Integer>> distribution = null;
List<Countable<BaseBlock>> distributionData = null;
if (args.hasFlag('c')) {
CuboidClipboard clip = session.getClipboard();
distribution = clip.getBlockDistribution();
size = clip.getHeight() * clip.getLength() * clip.getWidth();
if (useData) {
distributionData = clip.getBlockDistributionWithData();
} else {
distribution = clip.getBlockDistribution();
}
size = clip.getHeight() * clip.getLength() * clip.getWidth();
} else {
distribution = editSession
.getBlockDistribution(session.getSelection(player.getWorld()));
if (useData) {
distributionData = editSession.getBlockDistributionWithData(session.getSelection(player.getWorld()));
} else {
distribution = editSession.getBlockDistribution(session.getSelection(player.getWorld()));
}
size = session.getSelection(player.getWorld()).getArea();
}
if (distribution.size() <= 0) { // *Should* always be true
if ((useData && distributionData.size() <= 0)
|| (!useData && distribution.size() <= 0)) { // *Should* always be false
player.printError("No blocks counted.");
return;
}
player.print("# total blocks: " + size);
for (Countable<Integer> c : distribution) {
BlockType block = BlockType.fromID(c.getID());
String str = String.format("%-7s (%.3f%%) %s #%d",
String.valueOf(c.getAmount()),
c.getAmount() / (double) size * 100,
block == null ? "Unknown" : block.getName(), c.getID());
player.print(str);
if (useData) {
for (Countable<BaseBlock> c : distributionData) {
String name = BlockType.fromID(c.getID().getId()).getName();
String str = String.format("%-7s (%.3f%%) %s #%d:%d",
String.valueOf(c.getAmount()),
c.getAmount() / (double) size * 100,
name == null ? "Unknown" : name,
c.getID().getType(), c.getID().getData());
player.print(str);
}
} else {
for (Countable<Integer> c : distribution) {
BlockType block = BlockType.fromID(c.getID());
String str = String.format("%-7s (%.3f%%) %s #%d",
String.valueOf(c.getAmount()),
c.getAmount() / (double) size * 100,
block == null ? "Unknown" : block.getName(), c.getID());
player.print(str);
}
}
}