private class Stage3Committer implements Operation {
@Override
public Operation resume(RunContext run) throws WorldEditException {
Extent extent = getExtent();
final Set<BlockVector> blocks = new HashSet<BlockVector>();
final Map<BlockVector, BaseBlock> blockTypes = new HashMap<BlockVector, BaseBlock>();
for (Map.Entry<BlockVector, BaseBlock> entry : stage3) {
final BlockVector pt = entry.getKey();
blocks.add(pt);
blockTypes.put(pt, entry.getValue());
}
while (!blocks.isEmpty()) {
BlockVector current = blocks.iterator().next();
if (!blocks.contains(current)) {
continue;
}
final Deque<BlockVector> walked = new LinkedList<BlockVector>();
while (true) {
walked.addFirst(current);
assert (blockTypes.containsKey(current));
final BaseBlock baseBlock = blockTypes.get(current);
final int type = baseBlock.getType();
final int data = baseBlock.getData();
switch (type) {
case BlockID.WOODEN_DOOR:
case BlockID.IRON_DOOR:
if ((data & 0x8) == 0) {
// Deal with lower door halves being attached to the floor AND the upper half
BlockVector upperBlock = current.add(0, 1, 0).toBlockVector();
if (blocks.contains(upperBlock) && !walked.contains(upperBlock)) {
walked.addFirst(upperBlock);
}
}
break;
case BlockID.MINECART_TRACKS:
case BlockID.POWERED_RAIL:
case BlockID.DETECTOR_RAIL:
case BlockID.ACTIVATOR_RAIL:
// Here, rails are hardcoded to be attached to the block below them.
// They're also attached to the block they're ascending towards via BlockType.getAttachment.
BlockVector lowerBlock = current.add(0, -1, 0).toBlockVector();
if (blocks.contains(lowerBlock) && !walked.contains(lowerBlock)) {
walked.addFirst(lowerBlock);
}
break;
}
final PlayerDirection attachment = BlockType.getAttachment(type, data);
if (attachment == null) {
// Block is not attached to anything => we can place it
break;
}
current = current.add(attachment.vector()).toBlockVector();
if (!blocks.contains(current)) {
// We ran outside the remaining set => assume we can place blocks on this
break;
}
if (walked.contains(current)) {
// Cycle detected => This will most likely go wrong, but there's nothing we can do about it.
break;
}
}
for (BlockVector pt : walked) {
extent.setBlock(pt, blockTypes.get(pt));
blocks.remove(pt);
}
}
stage1.clear();