2010-10-02 21:52:42 +00:00
|
|
|
// $Id$
|
|
|
|
/*
|
2010-11-03 23:46:47 +00:00
|
|
|
* WorldEditLibrary
|
2010-10-02 21:52:42 +00:00
|
|
|
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU 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 General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2011-01-01 18:33:18 +00:00
|
|
|
*/
|
2011-01-01 01:06:42 +00:00
|
|
|
package com.sk89q.worldedit;
|
|
|
|
|
2010-10-02 21:52:42 +00:00
|
|
|
import java.util.Map;
|
|
|
|
import java.util.HashMap;
|
2010-10-18 20:51:43 +00:00
|
|
|
import java.util.LinkedHashMap;
|
2010-10-14 19:06:14 +00:00
|
|
|
import java.util.Set;
|
2010-10-05 07:40:50 +00:00
|
|
|
import java.util.HashSet;
|
2010-10-11 18:30:11 +00:00
|
|
|
import java.util.Stack;
|
2010-11-17 06:59:53 +00:00
|
|
|
import java.util.List;
|
2010-10-20 09:12:16 +00:00
|
|
|
import java.util.ArrayList;
|
2010-11-17 06:59:53 +00:00
|
|
|
import java.util.Collections;
|
2010-10-31 01:20:15 +00:00
|
|
|
import java.util.Random;
|
2010-12-31 22:31:49 +00:00
|
|
|
import com.sk89q.worldedit.regions.*;
|
2011-01-30 22:54:42 +00:00
|
|
|
import com.sk89q.worldedit.util.TreeGenerator;
|
2010-12-31 22:31:49 +00:00
|
|
|
import com.sk89q.worldedit.bags.*;
|
|
|
|
import com.sk89q.worldedit.blocks.*;
|
2011-06-04 19:16:10 +00:00
|
|
|
import com.sk89q.worldedit.masks.Mask;
|
2010-12-31 22:31:49 +00:00
|
|
|
import com.sk89q.worldedit.patterns.*;
|
2010-10-02 21:52:42 +00:00
|
|
|
|
|
|
|
/**
|
2010-10-05 07:40:50 +00:00
|
|
|
* This class can wrap all block editing operations into one "edit session" that
|
2011-01-01 18:33:18 +00:00
|
|
|
* stores the state of the blocks before modification. This allows for easy undo
|
|
|
|
* or redo. In addition to that, this class can use a "queue mode" that will
|
|
|
|
* know how to handle some special types of items such as signs and torches. For
|
|
|
|
* example, torches must be placed only after there is already a block below it,
|
|
|
|
* otherwise the torch will be placed as an item.
|
|
|
|
*
|
2010-10-05 07:40:50 +00:00
|
|
|
* @author sk89q
|
2010-10-02 21:52:42 +00:00
|
|
|
*/
|
|
|
|
public class EditSession {
|
2011-08-07 00:40:48 +00:00
|
|
|
|
2010-12-31 22:31:49 +00:00
|
|
|
/**
|
|
|
|
* Random number generator.
|
|
|
|
*/
|
|
|
|
private static Random prng = new Random();
|
2011-01-01 18:33:18 +00:00
|
|
|
/**
|
|
|
|
* World.
|
|
|
|
*/
|
2011-01-09 19:14:55 +00:00
|
|
|
protected LocalWorld world;
|
2010-10-02 21:52:42 +00:00
|
|
|
/**
|
|
|
|
* Stores the original blocks before modification.
|
|
|
|
*/
|
2011-01-08 19:26:27 +00:00
|
|
|
private DoubleArrayList<BlockVector, BaseBlock> original =
|
2011-08-07 00:40:48 +00:00
|
|
|
new DoubleArrayList<BlockVector, BaseBlock>(
|
2011-01-01 18:33:18 +00:00
|
|
|
true);
|
2010-10-04 23:39:35 +00:00
|
|
|
/**
|
|
|
|
* Stores the current blocks.
|
|
|
|
*/
|
2011-01-08 19:26:27 +00:00
|
|
|
private DoubleArrayList<BlockVector, BaseBlock> current =
|
2011-08-07 00:40:48 +00:00
|
|
|
new DoubleArrayList<BlockVector, BaseBlock>(
|
2011-01-01 18:33:18 +00:00
|
|
|
false);
|
2010-10-05 07:40:50 +00:00
|
|
|
/**
|
2010-11-27 07:24:55 +00:00
|
|
|
* Blocks that should be placed before last.
|
2010-10-05 07:40:50 +00:00
|
|
|
*/
|
2011-01-08 19:26:27 +00:00
|
|
|
private DoubleArrayList<BlockVector, BaseBlock> queueAfter =
|
2011-08-07 00:40:48 +00:00
|
|
|
new DoubleArrayList<BlockVector, BaseBlock>(
|
2011-01-01 18:33:18 +00:00
|
|
|
false);
|
2010-11-27 07:24:55 +00:00
|
|
|
/**
|
|
|
|
* Blocks that should be placed last.
|
|
|
|
*/
|
2011-01-08 19:26:27 +00:00
|
|
|
private DoubleArrayList<BlockVector, BaseBlock> queueLast =
|
2011-08-07 00:40:48 +00:00
|
|
|
new DoubleArrayList<BlockVector, BaseBlock>(
|
2011-01-01 18:33:18 +00:00
|
|
|
false);
|
2011-01-08 19:26:27 +00:00
|
|
|
|
2010-10-04 23:39:35 +00:00
|
|
|
/**
|
|
|
|
* The maximum number of blocks to change at a time. If this number is
|
2011-01-01 18:33:18 +00:00
|
|
|
* exceeded, a MaxChangedBlocksException exception will be raised. -1
|
|
|
|
* indicates no limit.
|
2010-10-04 23:39:35 +00:00
|
|
|
*/
|
|
|
|
private int maxBlocks = -1;
|
2011-06-04 17:30:45 +00:00
|
|
|
|
2010-10-05 07:40:50 +00:00
|
|
|
/**
|
|
|
|
* Indicates whether some types of blocks should be queued for best
|
|
|
|
* reproduction.
|
|
|
|
*/
|
|
|
|
private boolean queued = false;
|
2011-06-04 17:30:45 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Use the fast mode, which may leave chunks not flagged "dirty".
|
|
|
|
*/
|
|
|
|
private boolean fastMode = false;
|
|
|
|
|
2010-10-31 01:20:15 +00:00
|
|
|
/**
|
2010-12-31 22:31:49 +00:00
|
|
|
* Block bag to use for getting blocks.
|
2010-10-31 01:20:15 +00:00
|
|
|
*/
|
2010-12-31 22:31:49 +00:00
|
|
|
private BlockBag blockBag;
|
2011-06-04 17:30:45 +00:00
|
|
|
|
2010-12-31 22:31:49 +00:00
|
|
|
/**
|
|
|
|
* List of missing blocks;
|
|
|
|
*/
|
|
|
|
private Set<Integer> missingBlocks = new HashSet<Integer>();
|
2011-06-04 19:16:10 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Mask to cover operations.
|
|
|
|
*/
|
|
|
|
private Mask mask;
|
2010-10-05 07:40:50 +00:00
|
|
|
|
2010-10-04 23:39:35 +00:00
|
|
|
/**
|
|
|
|
* Construct the object with a maximum number of blocks.
|
2011-01-01 18:33:18 +00:00
|
|
|
*
|
|
|
|
* @param world
|
|
|
|
* @param maxBlocks
|
2010-10-04 23:39:35 +00:00
|
|
|
*/
|
2011-02-18 23:14:43 +00:00
|
|
|
public EditSession(LocalWorld world, int maxBlocks) {
|
2010-10-04 23:39:35 +00:00
|
|
|
if (maxBlocks < -1) {
|
|
|
|
throw new IllegalArgumentException("Max blocks must be >= -1");
|
|
|
|
}
|
2011-01-01 18:33:18 +00:00
|
|
|
|
2010-10-04 23:39:35 +00:00
|
|
|
this.maxBlocks = maxBlocks;
|
2011-01-01 18:33:18 +00:00
|
|
|
this.world = world;
|
2010-10-04 23:39:35 +00:00
|
|
|
}
|
2010-10-02 21:52:42 +00:00
|
|
|
|
2010-12-31 22:31:49 +00:00
|
|
|
/**
|
|
|
|
* Construct the object with a maximum number of blocks and a block bag.
|
2011-01-01 18:33:18 +00:00
|
|
|
*
|
2011-02-18 23:14:43 +00:00
|
|
|
* @param world
|
2011-01-01 18:33:18 +00:00
|
|
|
* @param maxBlocks
|
2011-02-18 23:14:43 +00:00
|
|
|
* @param blockBag
|
2011-01-01 18:33:18 +00:00
|
|
|
* @blockBag
|
2010-12-31 22:31:49 +00:00
|
|
|
*/
|
2011-02-18 23:14:43 +00:00
|
|
|
public EditSession(LocalWorld world, int maxBlocks, BlockBag blockBag) {
|
2010-12-31 22:31:49 +00:00
|
|
|
if (maxBlocks < -1) {
|
|
|
|
throw new IllegalArgumentException("Max blocks must be >= -1");
|
|
|
|
}
|
2011-01-01 18:33:18 +00:00
|
|
|
|
2010-12-31 22:31:49 +00:00
|
|
|
this.maxBlocks = maxBlocks;
|
|
|
|
this.blockBag = blockBag;
|
2011-01-01 18:33:18 +00:00
|
|
|
this.world = world;
|
2010-12-31 22:31:49 +00:00
|
|
|
}
|
|
|
|
|
2010-10-02 21:52:42 +00:00
|
|
|
/**
|
|
|
|
* Sets a block without changing history.
|
|
|
|
*
|
2010-10-11 08:22:47 +00:00
|
|
|
* @param pt
|
2011-04-01 23:18:40 +00:00
|
|
|
* @param block
|
2010-10-02 21:52:42 +00:00
|
|
|
* @return Whether the block changed
|
|
|
|
*/
|
2011-03-19 00:08:38 +00:00
|
|
|
public boolean rawSetBlock(Vector pt, BaseBlock block) {
|
2010-11-05 06:36:54 +00:00
|
|
|
int y = pt.getBlockY();
|
2011-01-29 17:49:17 +00:00
|
|
|
int type = block.getType();
|
2011-08-07 00:40:48 +00:00
|
|
|
|
2010-11-05 06:36:54 +00:00
|
|
|
if (y < 0 || y > 127) {
|
|
|
|
return false;
|
|
|
|
}
|
2011-08-07 00:40:48 +00:00
|
|
|
|
2011-01-29 17:49:17 +00:00
|
|
|
// No invalid blocks
|
2011-06-05 05:22:23 +00:00
|
|
|
if (!world.isValidBlockType(type)) {
|
2011-01-29 17:49:17 +00:00
|
|
|
return false;
|
|
|
|
}
|
2011-08-07 00:40:48 +00:00
|
|
|
|
2011-06-04 19:16:10 +00:00
|
|
|
if (mask != null) {
|
|
|
|
if (!mask.matches(this, pt)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2011-08-07 00:40:48 +00:00
|
|
|
|
2011-01-08 19:30:05 +00:00
|
|
|
int existing = world.getBlockType(pt);
|
2010-11-16 08:15:06 +00:00
|
|
|
|
2011-01-23 08:36:26 +00:00
|
|
|
// Clear the container block so that it doesn't drop items
|
|
|
|
if (BlockType.isContainerBlock(existing) && blockBag == null) {
|
|
|
|
world.clearContainerBlockContents(pt);
|
2011-08-07 00:40:48 +00:00
|
|
|
// Ice turns until water so this has to be done first
|
2011-01-08 19:30:05 +00:00
|
|
|
} else if (existing == BlockID.ICE) {
|
|
|
|
world.setBlockType(pt, 0);
|
2010-11-16 08:15:06 +00:00
|
|
|
}
|
2010-11-17 04:39:48 +00:00
|
|
|
|
2011-01-16 17:39:11 +00:00
|
|
|
int id = block.getType();
|
2011-01-01 18:33:18 +00:00
|
|
|
|
2010-12-31 22:31:49 +00:00
|
|
|
if (blockBag != null) {
|
|
|
|
if (id > 0) {
|
|
|
|
try {
|
|
|
|
blockBag.fetchPlacedBlock(id);
|
|
|
|
} catch (UnplaceableBlockException e) {
|
|
|
|
return false;
|
|
|
|
} catch (BlockBagException e) {
|
|
|
|
missingBlocks.add(id);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (existing > 0) {
|
|
|
|
try {
|
|
|
|
blockBag.storeDroppedBlock(existing);
|
|
|
|
} catch (BlockBagException e) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-08-07 00:40:48 +00:00
|
|
|
|
2011-06-04 17:30:45 +00:00
|
|
|
boolean result;
|
2011-01-01 18:33:18 +00:00
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
if (BlockType.usesData(id)) {
|
|
|
|
if (fastMode) {
|
|
|
|
result = world.setTypeIdAndDataFast(pt, type, block.getData());
|
|
|
|
} else {
|
|
|
|
result = world.setTypeIdAndData(pt, type, block.getData());
|
|
|
|
}
|
2011-06-04 17:30:45 +00:00
|
|
|
} else {
|
2011-07-15 07:00:48 +00:00
|
|
|
if (fastMode) {
|
|
|
|
result = world.setBlockTypeFast(pt, id);
|
|
|
|
} else {
|
|
|
|
result = world.setBlockType(pt, id);
|
|
|
|
}
|
2011-06-04 17:30:45 +00:00
|
|
|
}
|
2011-07-15 07:00:48 +00:00
|
|
|
//System.out.println(pt + "" +result);
|
2011-08-07 00:40:48 +00:00
|
|
|
|
2010-11-17 04:39:48 +00:00
|
|
|
if (id != 0) {
|
2010-10-14 08:31:05 +00:00
|
|
|
|
2010-10-15 17:22:55 +00:00
|
|
|
// Signs
|
|
|
|
if (block instanceof SignBlock) {
|
2011-01-01 18:33:18 +00:00
|
|
|
SignBlock signBlock = (SignBlock) block;
|
2011-01-23 08:36:26 +00:00
|
|
|
world.copyToWorld(pt, signBlock);
|
2011-08-07 00:40:48 +00:00
|
|
|
// Chests
|
2010-12-31 22:31:49 +00:00
|
|
|
} else if (block instanceof ChestBlock && blockBag == null) {
|
2011-01-01 18:33:18 +00:00
|
|
|
ChestBlock chestBlock = (ChestBlock) block;
|
2011-01-23 08:36:26 +00:00
|
|
|
world.copyToWorld(pt, chestBlock);
|
2011-08-07 00:40:48 +00:00
|
|
|
// Furnaces
|
2011-01-23 08:36:26 +00:00
|
|
|
} else if (block instanceof FurnaceBlock && blockBag == null) {
|
|
|
|
FurnaceBlock furnaceBlock = (FurnaceBlock) block;
|
|
|
|
world.copyToWorld(pt, furnaceBlock);
|
2011-08-07 00:40:48 +00:00
|
|
|
// Dispenser
|
2011-01-23 08:36:26 +00:00
|
|
|
} else if (block instanceof DispenserBlock && blockBag == null) {
|
|
|
|
DispenserBlock dispenserBlock = (DispenserBlock) block;
|
|
|
|
world.copyToWorld(pt, dispenserBlock);
|
2011-08-07 00:40:48 +00:00
|
|
|
// Mob spawners
|
2010-11-27 03:33:28 +00:00
|
|
|
} else if (block instanceof MobSpawnerBlock) {
|
2011-01-01 18:33:18 +00:00
|
|
|
MobSpawnerBlock mobSpawnerblock = (MobSpawnerBlock) block;
|
2011-01-23 08:36:26 +00:00
|
|
|
world.copyToWorld(pt, mobSpawnerblock);
|
2011-08-07 00:40:48 +00:00
|
|
|
// Note blocks
|
2011-01-23 08:36:26 +00:00
|
|
|
} else if (block instanceof NoteBlock) {
|
|
|
|
NoteBlock noteBlock = (NoteBlock) block;
|
|
|
|
world.copyToWorld(pt, noteBlock);
|
2010-10-15 17:22:55 +00:00
|
|
|
}
|
2010-10-14 08:31:05 +00:00
|
|
|
}
|
2010-10-13 23:49:35 +00:00
|
|
|
return result;
|
2010-10-11 08:22:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the block at position x, y, z with a block type. If queue mode is
|
2011-01-01 18:33:18 +00:00
|
|
|
* enabled, blocks may not be actually set in world until flushQueue() is
|
|
|
|
* called.
|
|
|
|
*
|
2010-10-11 08:22:47 +00:00
|
|
|
* @param pt
|
2010-10-13 23:49:35 +00:00
|
|
|
* @param block
|
2010-10-11 08:22:47 +00:00
|
|
|
* @return Whether the block changed -- not entirely dependable
|
2011-02-18 23:14:43 +00:00
|
|
|
* @throws MaxChangedBlocksException
|
2010-10-11 08:22:47 +00:00
|
|
|
*/
|
2010-10-13 23:49:35 +00:00
|
|
|
public boolean setBlock(Vector pt, BaseBlock block)
|
2011-01-01 18:33:18 +00:00
|
|
|
throws MaxChangedBlocksException {
|
2010-10-13 05:38:05 +00:00
|
|
|
BlockVector blockPt = pt.toBlockVector();
|
2010-10-04 23:39:35 +00:00
|
|
|
|
2011-01-01 18:33:18 +00:00
|
|
|
// if (!original.containsKey(blockPt)) {
|
|
|
|
original.put(blockPt, getBlock(pt));
|
|
|
|
|
|
|
|
if (maxBlocks != -1 && original.size() > maxBlocks) {
|
|
|
|
throw new MaxChangedBlocksException(maxBlocks);
|
|
|
|
}
|
|
|
|
// }
|
2010-10-11 08:22:47 +00:00
|
|
|
|
2010-10-13 23:49:35 +00:00
|
|
|
current.put(pt.toBlockVector(), block);
|
2010-10-11 08:22:47 +00:00
|
|
|
|
2010-10-13 23:49:35 +00:00
|
|
|
return smartSetBlock(pt, block);
|
2010-10-05 07:40:50 +00:00
|
|
|
}
|
|
|
|
|
2011-03-13 00:37:07 +00:00
|
|
|
/**
|
|
|
|
* Insert a contrived block change into the history.
|
|
|
|
*
|
|
|
|
* @param pt
|
|
|
|
* @param existing
|
|
|
|
* @param block
|
|
|
|
*/
|
|
|
|
public void rememberChange(Vector pt, BaseBlock existing, BaseBlock block) {
|
|
|
|
BlockVector blockPt = pt.toBlockVector();
|
|
|
|
|
|
|
|
original.put(blockPt, existing);
|
|
|
|
current.put(pt.toBlockVector(), block);
|
|
|
|
}
|
|
|
|
|
2011-02-18 23:14:43 +00:00
|
|
|
/**
|
|
|
|
* Set a block with a pattern.
|
|
|
|
*
|
|
|
|
* @param pt
|
|
|
|
* @param pat
|
|
|
|
* @return Whether the block changed -- not entirely dependable
|
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
*/
|
|
|
|
public boolean setBlock(Vector pt, Pattern pat)
|
|
|
|
throws MaxChangedBlocksException {
|
|
|
|
return setBlock(pt, pat.next(pt));
|
|
|
|
}
|
|
|
|
|
2010-10-13 05:38:05 +00:00
|
|
|
/**
|
|
|
|
* Set a block only if there's no block already there.
|
|
|
|
*
|
|
|
|
* @param pt
|
2010-10-13 23:49:35 +00:00
|
|
|
* @param block
|
2010-10-13 05:38:05 +00:00
|
|
|
* @return if block was changed
|
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
*/
|
2010-10-13 23:49:35 +00:00
|
|
|
public boolean setBlockIfAir(Vector pt, BaseBlock block)
|
2010-10-13 05:38:05 +00:00
|
|
|
throws MaxChangedBlocksException {
|
2010-10-13 23:49:35 +00:00
|
|
|
if (!getBlock(pt).isAir()) {
|
2010-10-13 05:38:05 +00:00
|
|
|
return false;
|
|
|
|
} else {
|
2010-10-13 23:49:35 +00:00
|
|
|
return setBlock(pt, block);
|
2010-10-13 05:38:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-05 07:40:50 +00:00
|
|
|
/**
|
|
|
|
* Actually set the block. Will use queue.
|
|
|
|
*
|
2010-10-11 08:22:47 +00:00
|
|
|
* @param pt
|
2010-10-13 23:49:35 +00:00
|
|
|
* @param block
|
2010-10-05 07:40:50 +00:00
|
|
|
* @return
|
|
|
|
*/
|
2011-03-13 00:37:07 +00:00
|
|
|
public boolean smartSetBlock(Vector pt, BaseBlock block) {
|
2010-10-05 07:40:50 +00:00
|
|
|
if (queued) {
|
2010-11-27 07:24:55 +00:00
|
|
|
// Place torches, etc. last
|
2011-01-16 17:39:11 +00:00
|
|
|
if (BlockType.shouldPlaceLast(block.getType())) {
|
2010-11-27 07:24:55 +00:00
|
|
|
queueLast.put(pt.toBlockVector(), block);
|
2011-08-07 00:40:48 +00:00
|
|
|
return !(getBlockType(pt) == block.getType()
|
2011-07-15 07:00:48 +00:00
|
|
|
&& getBlockData(pt) == block.getData());
|
2011-01-01 18:33:18 +00:00
|
|
|
// Destroy torches, etc. first
|
2011-01-31 07:42:18 +00:00
|
|
|
} else if (BlockType.shouldPlaceLast(getBlockType(pt))) {
|
2010-11-27 07:24:55 +00:00
|
|
|
rawSetBlock(pt, new BaseBlock(0));
|
|
|
|
} else {
|
|
|
|
queueAfter.put(pt.toBlockVector(), block);
|
2011-08-07 00:40:48 +00:00
|
|
|
return !(getBlockType(pt) == block.getType()
|
2011-07-15 07:00:48 +00:00
|
|
|
&& getBlockData(pt) == block.getData());
|
2010-10-05 07:40:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-13 23:49:35 +00:00
|
|
|
return rawSetBlock(pt, block);
|
2010-10-02 21:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the block type at a position x, y, z.
|
2011-01-01 18:33:18 +00:00
|
|
|
*
|
2010-10-11 08:22:47 +00:00
|
|
|
* @param pt
|
2010-10-02 21:52:42 +00:00
|
|
|
* @return Block type
|
|
|
|
*/
|
2010-10-13 23:49:35 +00:00
|
|
|
public BaseBlock getBlock(Vector pt) {
|
2010-10-05 07:40:50 +00:00
|
|
|
// In the case of the queue, the block may have not actually been
|
|
|
|
// changed yet
|
|
|
|
if (queued) {
|
2011-01-01 18:33:18 +00:00
|
|
|
/*
|
|
|
|
* BlockVector blockPt = pt.toBlockVector();
|
|
|
|
*
|
|
|
|
* if (current.containsKey(blockPt)) { return current.get(blockPt);
|
|
|
|
* }
|
|
|
|
*/
|
2010-10-05 07:40:50 +00:00
|
|
|
}
|
2011-01-01 18:33:18 +00:00
|
|
|
|
2010-10-14 08:31:05 +00:00
|
|
|
return rawGetBlock(pt);
|
2010-10-11 08:22:47 +00:00
|
|
|
}
|
|
|
|
|
2011-01-31 06:15:08 +00:00
|
|
|
/**
|
|
|
|
* Gets the block type at a position x, y, z.
|
|
|
|
*
|
|
|
|
* @param pt
|
|
|
|
* @return Block type
|
|
|
|
*/
|
|
|
|
public int getBlockType(Vector pt) {
|
|
|
|
// In the case of the queue, the block may have not actually been
|
|
|
|
// changed yet
|
|
|
|
if (queued) {
|
|
|
|
/*
|
|
|
|
* BlockVector blockPt = pt.toBlockVector();
|
|
|
|
*
|
|
|
|
* if (current.containsKey(blockPt)) { return current.get(blockPt);
|
|
|
|
* }
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
return world.getBlockType(pt);
|
|
|
|
}
|
2011-08-07 00:40:48 +00:00
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
public int getBlockData(Vector pt) {
|
|
|
|
// In the case of the queue, the block may have not actually been
|
|
|
|
// changed yet
|
|
|
|
if (queued) {
|
|
|
|
/*
|
|
|
|
* BlockVector blockPt = pt.toBlockVector();
|
|
|
|
*
|
|
|
|
* if (current.containsKey(blockPt)) { return current.get(blockPt);
|
|
|
|
* }
|
|
|
|
*/
|
|
|
|
}
|
2011-01-31 06:15:08 +00:00
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
return world.getBlockData(pt);
|
|
|
|
}
|
2010-10-11 08:22:47 +00:00
|
|
|
/**
|
|
|
|
* Gets the block type at a position x, y, z.
|
2011-01-01 18:33:18 +00:00
|
|
|
*
|
2010-10-11 08:22:47 +00:00
|
|
|
* @param pt
|
2010-10-13 23:49:35 +00:00
|
|
|
* @return BaseBlock
|
2010-10-11 08:22:47 +00:00
|
|
|
*/
|
2011-01-01 01:06:42 +00:00
|
|
|
public BaseBlock rawGetBlock(Vector pt) {
|
2011-01-08 19:26:27 +00:00
|
|
|
int type = world.getBlockType(pt);
|
|
|
|
int data = world.getBlockData(pt);
|
2010-10-14 08:31:05 +00:00
|
|
|
|
|
|
|
// Sign
|
2011-01-23 08:36:26 +00:00
|
|
|
if (type == BlockID.WALL_SIGN || type == BlockID.SIGN_POST) {
|
|
|
|
SignBlock block = new SignBlock(type, data);
|
|
|
|
world.copyFromWorld(pt, block);
|
|
|
|
return block;
|
2011-08-07 00:40:48 +00:00
|
|
|
// Chest
|
2011-01-23 08:36:26 +00:00
|
|
|
} else if (type == BlockID.CHEST) {
|
|
|
|
ChestBlock block = new ChestBlock(data);
|
|
|
|
world.copyFromWorld(pt, block);
|
|
|
|
return block;
|
2011-08-07 00:40:48 +00:00
|
|
|
// Furnace
|
2011-01-23 08:36:26 +00:00
|
|
|
} else if (type == BlockID.FURNACE || type == BlockID.BURNING_FURNACE) {
|
|
|
|
FurnaceBlock block = new FurnaceBlock(type, data);
|
|
|
|
world.copyFromWorld(pt, block);
|
|
|
|
return block;
|
2011-08-07 00:40:48 +00:00
|
|
|
// Dispenser
|
2011-01-23 08:36:26 +00:00
|
|
|
} else if (type == BlockID.DISPENSER) {
|
|
|
|
DispenserBlock block = new DispenserBlock(data);
|
|
|
|
world.copyFromWorld(pt, block);
|
|
|
|
return block;
|
2011-08-07 00:40:48 +00:00
|
|
|
// Mob spawner
|
2011-01-23 08:36:26 +00:00
|
|
|
} else if (type == BlockID.MOB_SPAWNER) {
|
|
|
|
MobSpawnerBlock block = new MobSpawnerBlock(data);
|
|
|
|
world.copyFromWorld(pt, block);
|
|
|
|
return block;
|
2011-08-07 00:40:48 +00:00
|
|
|
// Note block
|
2011-01-23 08:36:26 +00:00
|
|
|
} else if (type == BlockID.NOTE_BLOCK) {
|
|
|
|
NoteBlock block = new NoteBlock(data);
|
|
|
|
world.copyFromWorld(pt, block);
|
|
|
|
return block;
|
2010-10-14 08:31:05 +00:00
|
|
|
} else {
|
|
|
|
return new BaseBlock(type, data);
|
|
|
|
}
|
2010-10-02 21:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Restores all blocks to their initial state.
|
2011-02-18 23:49:50 +00:00
|
|
|
*
|
|
|
|
* @param sess
|
2010-10-02 21:52:42 +00:00
|
|
|
*/
|
2011-02-18 23:14:43 +00:00
|
|
|
public void undo(EditSession sess) {
|
2011-01-01 18:33:18 +00:00
|
|
|
for (Map.Entry<BlockVector, BaseBlock> entry : original) {
|
|
|
|
BlockVector pt = (BlockVector) entry.getKey();
|
2011-02-18 23:14:43 +00:00
|
|
|
sess.smartSetBlock(pt, (BaseBlock) entry.getValue());
|
2010-10-02 21:52:42 +00:00
|
|
|
}
|
2011-02-18 23:14:43 +00:00
|
|
|
sess.flushQueue();
|
2010-10-02 21:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets to new state.
|
2011-02-18 23:49:50 +00:00
|
|
|
*
|
|
|
|
* @param sess
|
2010-10-02 21:52:42 +00:00
|
|
|
*/
|
2011-02-18 23:14:43 +00:00
|
|
|
public void redo(EditSession sess) {
|
2011-01-01 18:33:18 +00:00
|
|
|
for (Map.Entry<BlockVector, BaseBlock> entry : current) {
|
|
|
|
BlockVector pt = (BlockVector) entry.getKey();
|
2011-02-18 23:14:43 +00:00
|
|
|
sess.smartSetBlock(pt, (BaseBlock) entry.getValue());
|
2010-10-02 21:52:42 +00:00
|
|
|
}
|
2011-02-18 23:14:43 +00:00
|
|
|
sess.flushQueue();
|
2010-10-02 21:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the number of changed blocks.
|
|
|
|
*
|
2011-02-18 23:49:50 +00:00
|
|
|
* @return
|
2010-10-02 21:52:42 +00:00
|
|
|
*/
|
|
|
|
public int size() {
|
|
|
|
return original.size();
|
|
|
|
}
|
2010-10-04 23:39:35 +00:00
|
|
|
|
|
|
|
/**
|
2011-01-01 18:33:18 +00:00
|
|
|
* Get the maximum number of blocks that can be changed. -1 will be returned
|
|
|
|
* if disabled.
|
|
|
|
*
|
2010-10-11 15:56:19 +00:00
|
|
|
* @return block change limit
|
2010-10-04 23:39:35 +00:00
|
|
|
*/
|
|
|
|
public int getBlockChangeLimit() {
|
|
|
|
return maxBlocks;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the maximum number of blocks that can be changed.
|
|
|
|
*
|
2011-01-01 18:33:18 +00:00
|
|
|
* @param maxBlocks
|
|
|
|
* -1 to disable
|
2010-10-04 23:39:35 +00:00
|
|
|
*/
|
|
|
|
public void setBlockChangeLimit(int maxBlocks) {
|
|
|
|
if (maxBlocks < -1) {
|
|
|
|
throw new IllegalArgumentException("Max blocks must be >= -1");
|
|
|
|
}
|
|
|
|
this.maxBlocks = maxBlocks;
|
|
|
|
}
|
2010-10-05 07:40:50 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns queue status.
|
|
|
|
*
|
2010-10-11 15:56:19 +00:00
|
|
|
* @return whether the queue is enabled
|
2010-10-05 07:40:50 +00:00
|
|
|
*/
|
|
|
|
public boolean isQueueEnabled() {
|
|
|
|
return queued;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Queue certain types of block for better reproduction of those blocks.
|
|
|
|
*/
|
|
|
|
public void enableQueue() {
|
|
|
|
queued = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Disable the queue. This will flush the queue.
|
|
|
|
*/
|
|
|
|
public void disableQueue() {
|
|
|
|
if (queued != false) {
|
|
|
|
flushQueue();
|
|
|
|
}
|
|
|
|
queued = false;
|
|
|
|
}
|
2011-08-07 00:40:48 +00:00
|
|
|
|
2011-06-04 17:30:45 +00:00
|
|
|
/**
|
|
|
|
* Set fast mode.
|
|
|
|
*
|
|
|
|
* @param fastMode
|
|
|
|
*/
|
|
|
|
public void setFastMode(boolean fastMode) {
|
|
|
|
this.fastMode = fastMode;
|
|
|
|
}
|
2011-08-07 00:40:48 +00:00
|
|
|
|
2011-06-04 17:30:45 +00:00
|
|
|
/**
|
|
|
|
* Return fast mode status.
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
public boolean hasFastMode() {
|
|
|
|
return fastMode;
|
|
|
|
}
|
2010-10-05 07:40:50 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Finish off the queue.
|
|
|
|
*/
|
|
|
|
public void flushQueue() {
|
2011-01-01 18:33:18 +00:00
|
|
|
if (!queued) {
|
|
|
|
return;
|
|
|
|
}
|
2010-11-27 07:24:55 +00:00
|
|
|
|
2011-01-01 18:33:18 +00:00
|
|
|
for (Map.Entry<BlockVector, BaseBlock> entry : queueAfter) {
|
|
|
|
BlockVector pt = (BlockVector) entry.getKey();
|
|
|
|
rawSetBlock(pt, (BaseBlock) entry.getValue());
|
2010-11-27 07:24:55 +00:00
|
|
|
}
|
2010-12-31 22:31:49 +00:00
|
|
|
|
|
|
|
// We don't want to place these blocks if other blocks were missing
|
|
|
|
// because it might cause the items to drop
|
|
|
|
if (blockBag == null || missingBlocks.size() == 0) {
|
2011-01-01 18:33:18 +00:00
|
|
|
for (Map.Entry<BlockVector, BaseBlock> entry : queueLast) {
|
|
|
|
BlockVector pt = (BlockVector) entry.getKey();
|
|
|
|
rawSetBlock(pt, (BaseBlock) entry.getValue());
|
2010-12-31 22:31:49 +00:00
|
|
|
}
|
2010-10-05 07:40:50 +00:00
|
|
|
}
|
2010-11-27 07:24:55 +00:00
|
|
|
|
|
|
|
queueAfter.clear();
|
|
|
|
queueLast.clear();
|
2010-10-05 07:40:50 +00:00
|
|
|
}
|
2010-10-11 08:22:47 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Fills an area recursively in the X/Z directions.
|
2011-01-01 18:33:18 +00:00
|
|
|
*
|
2010-10-11 08:22:47 +00:00
|
|
|
* @param origin
|
2010-10-13 23:49:35 +00:00
|
|
|
* @param block
|
2010-10-11 08:22:47 +00:00
|
|
|
* @param radius
|
|
|
|
* @param depth
|
2010-11-17 04:03:54 +00:00
|
|
|
* @param recursive
|
2010-10-11 15:56:19 +00:00
|
|
|
* @return number of blocks affected
|
2011-02-18 23:49:50 +00:00
|
|
|
* @throws MaxChangedBlocksException
|
2010-10-11 08:22:47 +00:00
|
|
|
*/
|
2011-08-15 12:35:21 +00:00
|
|
|
public int fillXZ(Vector origin, BaseBlock block, double radius, int depth,
|
2011-01-01 18:33:18 +00:00
|
|
|
boolean recursive) throws MaxChangedBlocksException {
|
|
|
|
|
2010-10-11 08:22:47 +00:00
|
|
|
int affected = 0;
|
2010-10-30 08:28:00 +00:00
|
|
|
int originX = origin.getBlockX();
|
|
|
|
int originY = origin.getBlockY();
|
|
|
|
int originZ = origin.getBlockZ();
|
2010-10-11 08:22:47 +00:00
|
|
|
|
2010-10-30 08:28:00 +00:00
|
|
|
HashSet<BlockVector> visited = new HashSet<BlockVector>();
|
|
|
|
Stack<BlockVector> queue = new Stack<BlockVector>();
|
2010-10-11 08:22:47 +00:00
|
|
|
|
2010-11-17 04:03:54 +00:00
|
|
|
queue.push(new BlockVector(originX, originY, originZ));
|
2010-10-30 08:28:00 +00:00
|
|
|
|
|
|
|
while (!queue.empty()) {
|
|
|
|
BlockVector pt = queue.pop();
|
|
|
|
int cx = pt.getBlockX();
|
2010-11-17 04:03:54 +00:00
|
|
|
int cy = pt.getBlockY();
|
2010-10-30 08:28:00 +00:00
|
|
|
int cz = pt.getBlockZ();
|
|
|
|
|
2010-11-17 04:03:54 +00:00
|
|
|
if (cy < 0 || cy > originY || visited.contains(pt)) {
|
2010-10-30 08:28:00 +00:00
|
|
|
continue;
|
|
|
|
}
|
2010-10-11 08:22:47 +00:00
|
|
|
|
2010-10-30 08:28:00 +00:00
|
|
|
visited.add(pt);
|
|
|
|
|
2010-11-17 04:03:54 +00:00
|
|
|
if (recursive) {
|
|
|
|
if (origin.distance(pt) > radius) {
|
|
|
|
continue;
|
|
|
|
}
|
2010-10-30 08:28:00 +00:00
|
|
|
|
2010-11-17 04:03:54 +00:00
|
|
|
if (getBlock(pt).isAir()) {
|
|
|
|
if (setBlock(pt, block)) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-11-17 04:03:54 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
2010-10-30 08:28:00 +00:00
|
|
|
|
2010-11-17 04:03:54 +00:00
|
|
|
queue.push(new BlockVector(cx, cy - 1, cz));
|
|
|
|
queue.push(new BlockVector(cx, cy + 1, cz));
|
2010-10-30 08:28:00 +00:00
|
|
|
} else {
|
2010-11-17 04:03:54 +00:00
|
|
|
double dist = Math.sqrt(Math.pow(originX - cx, 2)
|
|
|
|
+ Math.pow(originZ - cz, 2));
|
|
|
|
int minY = originY - depth + 1;
|
|
|
|
|
|
|
|
if (dist > radius) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (getBlock(pt).isAir()) {
|
|
|
|
affected += fillY(cx, originY, cz, block, minY);
|
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
2010-10-30 08:28:00 +00:00
|
|
|
}
|
|
|
|
|
2010-11-17 04:03:54 +00:00
|
|
|
queue.push(new BlockVector(cx + 1, cy, cz));
|
|
|
|
queue.push(new BlockVector(cx - 1, cy, cz));
|
|
|
|
queue.push(new BlockVector(cx, cy, cz + 1));
|
|
|
|
queue.push(new BlockVector(cx, cy, cz - 1));
|
2010-10-30 08:28:00 +00:00
|
|
|
}
|
2010-10-11 08:22:47 +00:00
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Recursively fills a block and below until it hits another block.
|
2011-01-01 18:33:18 +00:00
|
|
|
*
|
2010-10-11 08:22:47 +00:00
|
|
|
* @param x
|
|
|
|
* @param cy
|
|
|
|
* @param z
|
2010-10-13 23:49:35 +00:00
|
|
|
* @param block
|
2010-10-11 08:22:47 +00:00
|
|
|
* @param minY
|
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
* @return
|
|
|
|
*/
|
2010-10-13 23:49:35 +00:00
|
|
|
private int fillY(int x, int cy, int z, BaseBlock block, int minY)
|
2011-01-01 18:33:18 +00:00
|
|
|
throws MaxChangedBlocksException {
|
2010-10-11 08:22:47 +00:00
|
|
|
int affected = 0;
|
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int y = cy; y >= minY; --y) {
|
2010-10-13 01:03:56 +00:00
|
|
|
Vector pt = new Vector(x, y, z);
|
2011-01-01 18:33:18 +00:00
|
|
|
|
2010-10-13 23:49:35 +00:00
|
|
|
if (getBlock(pt).isAir()) {
|
|
|
|
setBlock(pt, block);
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-10-11 08:22:47 +00:00
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
|
|
|
|
2010-11-16 22:07:52 +00:00
|
|
|
/**
|
|
|
|
* Fills an area recursively in the X/Z directions.
|
2011-01-01 18:33:18 +00:00
|
|
|
*
|
2010-11-16 22:07:52 +00:00
|
|
|
* @param origin
|
|
|
|
* @param pattern
|
|
|
|
* @param radius
|
|
|
|
* @param depth
|
2010-11-17 04:03:54 +00:00
|
|
|
* @param recursive
|
2010-11-16 22:07:52 +00:00
|
|
|
* @return number of blocks affected
|
2011-02-18 23:49:50 +00:00
|
|
|
* @throws MaxChangedBlocksException
|
2010-11-16 22:07:52 +00:00
|
|
|
*/
|
2011-08-15 12:35:21 +00:00
|
|
|
public int fillXZ(Vector origin, Pattern pattern, double radius, int depth,
|
2011-01-01 18:33:18 +00:00
|
|
|
boolean recursive) throws MaxChangedBlocksException {
|
2010-11-16 22:07:52 +00:00
|
|
|
|
|
|
|
int affected = 0;
|
|
|
|
int originX = origin.getBlockX();
|
|
|
|
int originY = origin.getBlockY();
|
|
|
|
int originZ = origin.getBlockZ();
|
|
|
|
|
|
|
|
HashSet<BlockVector> visited = new HashSet<BlockVector>();
|
|
|
|
Stack<BlockVector> queue = new Stack<BlockVector>();
|
|
|
|
|
2010-11-17 04:03:54 +00:00
|
|
|
queue.push(new BlockVector(originX, originY, originZ));
|
2010-11-16 22:07:52 +00:00
|
|
|
|
|
|
|
while (!queue.empty()) {
|
|
|
|
BlockVector pt = queue.pop();
|
|
|
|
int cx = pt.getBlockX();
|
2010-11-17 04:03:54 +00:00
|
|
|
int cy = pt.getBlockY();
|
2010-11-16 22:07:52 +00:00
|
|
|
int cz = pt.getBlockZ();
|
|
|
|
|
2010-11-17 04:03:54 +00:00
|
|
|
if (cy < 0 || cy > originY || visited.contains(pt)) {
|
2010-11-16 22:07:52 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
visited.add(pt);
|
|
|
|
|
2010-11-17 04:03:54 +00:00
|
|
|
if (recursive) {
|
|
|
|
if (origin.distance(pt) > radius) {
|
|
|
|
continue;
|
|
|
|
}
|
2010-11-16 22:07:52 +00:00
|
|
|
|
2010-11-17 04:03:54 +00:00
|
|
|
if (getBlock(pt).isAir()) {
|
|
|
|
if (setBlock(pt, pattern.next(pt))) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-11-17 04:03:54 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
2010-11-16 22:07:52 +00:00
|
|
|
|
2010-11-17 04:03:54 +00:00
|
|
|
queue.push(new BlockVector(cx, cy - 1, cz));
|
|
|
|
queue.push(new BlockVector(cx, cy + 1, cz));
|
2010-11-16 22:07:52 +00:00
|
|
|
} else {
|
2010-11-17 04:03:54 +00:00
|
|
|
double dist = Math.sqrt(Math.pow(originX - cx, 2)
|
|
|
|
+ Math.pow(originZ - cz, 2));
|
|
|
|
int minY = originY - depth + 1;
|
|
|
|
|
|
|
|
if (dist > radius) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (getBlock(pt).isAir()) {
|
|
|
|
affected += fillY(cx, originY, cz, pattern, minY);
|
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
2010-11-16 22:07:52 +00:00
|
|
|
}
|
|
|
|
|
2010-11-17 04:03:54 +00:00
|
|
|
queue.push(new BlockVector(cx + 1, cy, cz));
|
|
|
|
queue.push(new BlockVector(cx - 1, cy, cz));
|
|
|
|
queue.push(new BlockVector(cx, cy, cz + 1));
|
|
|
|
queue.push(new BlockVector(cx, cy, cz - 1));
|
2010-11-16 22:07:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Recursively fills a block and below until it hits another block.
|
2011-01-01 18:33:18 +00:00
|
|
|
*
|
2010-11-16 22:07:52 +00:00
|
|
|
* @param x
|
|
|
|
* @param cy
|
|
|
|
* @param z
|
|
|
|
* @param pattern
|
|
|
|
* @param minY
|
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
private int fillY(int x, int cy, int z, Pattern pattern, int minY)
|
2011-01-01 18:33:18 +00:00
|
|
|
throws MaxChangedBlocksException {
|
2010-11-16 22:07:52 +00:00
|
|
|
int affected = 0;
|
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int y = cy; y >= minY; --y) {
|
2010-11-16 22:07:52 +00:00
|
|
|
Vector pt = new Vector(x, y, z);
|
|
|
|
|
|
|
|
if (getBlock(pt).isAir()) {
|
|
|
|
setBlock(pt, pattern.next(pt));
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-11-16 22:07:52 +00:00
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
|
|
|
|
2010-10-11 08:22:47 +00:00
|
|
|
/**
|
|
|
|
* Remove blocks above.
|
|
|
|
*
|
|
|
|
* @param pos
|
2010-10-11 15:56:19 +00:00
|
|
|
* @param size
|
2010-10-11 08:22:47 +00:00
|
|
|
* @param height
|
2010-10-11 15:56:19 +00:00
|
|
|
* @return number of blocks affected
|
2011-02-18 23:49:50 +00:00
|
|
|
* @throws MaxChangedBlocksException
|
2010-10-11 08:22:47 +00:00
|
|
|
*/
|
2011-01-01 18:33:18 +00:00
|
|
|
public int removeAbove(Vector pos, int size, int height)
|
|
|
|
throws MaxChangedBlocksException {
|
2010-10-11 08:22:47 +00:00
|
|
|
int maxY = Math.min(127, pos.getBlockY() + height - 1);
|
2011-07-15 07:00:48 +00:00
|
|
|
--size;
|
2010-10-11 08:22:47 +00:00
|
|
|
int affected = 0;
|
|
|
|
|
2010-11-06 22:09:32 +00:00
|
|
|
int oX = pos.getBlockX();
|
|
|
|
int oY = pos.getBlockY();
|
|
|
|
int oZ = pos.getBlockZ();
|
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int x = oX - size; x <= oX + size; ++x) {
|
|
|
|
for (int z = oZ - size; z <= oZ + size; ++z) {
|
|
|
|
for (int y = oY; y <= maxY; ++y) {
|
2010-10-13 01:03:56 +00:00
|
|
|
Vector pt = new Vector(x, y, z);
|
2010-10-11 08:22:47 +00:00
|
|
|
|
2011-01-31 06:15:08 +00:00
|
|
|
if (getBlockType(pt) != 0) {
|
2010-10-13 23:49:35 +00:00
|
|
|
setBlock(pt, new BaseBlock(0));
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-10-11 08:22:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove blocks below.
|
2011-01-01 18:33:18 +00:00
|
|
|
*
|
2010-10-11 08:22:47 +00:00
|
|
|
* @param pos
|
2010-10-11 15:56:19 +00:00
|
|
|
* @param size
|
2010-10-11 08:22:47 +00:00
|
|
|
* @param height
|
2010-10-11 15:56:19 +00:00
|
|
|
* @return number of blocks affected
|
2011-02-18 23:49:50 +00:00
|
|
|
* @throws MaxChangedBlocksException
|
2010-10-11 08:22:47 +00:00
|
|
|
*/
|
2011-01-01 18:33:18 +00:00
|
|
|
public int removeBelow(Vector pos, int size, int height)
|
|
|
|
throws MaxChangedBlocksException {
|
2010-10-11 08:22:47 +00:00
|
|
|
int minY = Math.max(0, pos.getBlockY() - height);
|
2011-07-15 07:00:48 +00:00
|
|
|
--size;
|
2010-10-11 08:22:47 +00:00
|
|
|
int affected = 0;
|
|
|
|
|
2010-11-06 22:09:32 +00:00
|
|
|
int oX = pos.getBlockX();
|
|
|
|
int oY = pos.getBlockY();
|
|
|
|
int oZ = pos.getBlockZ();
|
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int x = oX - size; x <= oX + size; ++x) {
|
|
|
|
for (int z = oZ - size; z <= oZ + size; ++z) {
|
|
|
|
for (int y = oY; y >= minY; --y) {
|
2010-10-13 01:03:56 +00:00
|
|
|
Vector pt = new Vector(x, y, z);
|
2010-10-11 08:22:47 +00:00
|
|
|
|
2011-01-31 06:15:08 +00:00
|
|
|
if (getBlockType(pt) != 0) {
|
2010-10-13 23:49:35 +00:00
|
|
|
setBlock(pt, new BaseBlock(0));
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-10-11 08:22:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
|
|
|
|
2010-10-18 23:36:22 +00:00
|
|
|
/**
|
|
|
|
* Remove nearby blocks of a type.
|
2011-01-01 18:33:18 +00:00
|
|
|
*
|
2010-10-18 23:36:22 +00:00
|
|
|
* @param pos
|
|
|
|
* @param blockType
|
|
|
|
* @param size
|
|
|
|
* @return number of blocks affected
|
2011-02-18 23:49:50 +00:00
|
|
|
* @throws MaxChangedBlocksException
|
2010-10-18 23:36:22 +00:00
|
|
|
*/
|
2011-01-01 18:33:18 +00:00
|
|
|
public int removeNear(Vector pos, int blockType, int size)
|
|
|
|
throws MaxChangedBlocksException {
|
2010-10-18 23:36:22 +00:00
|
|
|
int affected = 0;
|
|
|
|
BaseBlock air = new BaseBlock(0);
|
|
|
|
|
2011-01-31 09:16:49 +00:00
|
|
|
int minX = pos.getBlockX() - size;
|
|
|
|
int maxX = pos.getBlockX() + size;
|
|
|
|
int minY = Math.max(0, pos.getBlockY() - size);
|
|
|
|
int maxY = Math.min(127, pos.getBlockY() + size);
|
|
|
|
int minZ = pos.getBlockZ() - size;
|
|
|
|
int maxZ = pos.getBlockZ() + size;
|
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int x = minX; x <= maxX; ++x) {
|
|
|
|
for (int y = minY; y <= maxY; ++y) {
|
|
|
|
for (int z = minZ; z <= maxZ; ++z) {
|
2011-01-31 09:16:49 +00:00
|
|
|
Vector p = new Vector(x, y, z);
|
2010-10-18 23:36:22 +00:00
|
|
|
|
2011-01-31 06:15:08 +00:00
|
|
|
if (getBlockType(p) == blockType) {
|
2010-10-18 23:36:22 +00:00
|
|
|
if (setBlock(p, air)) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-10-18 23:36:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
|
|
|
|
2010-10-11 08:22:47 +00:00
|
|
|
/**
|
|
|
|
* Sets all the blocks inside a region to a certain block type.
|
2011-01-01 18:33:18 +00:00
|
|
|
*
|
2010-10-11 08:22:47 +00:00
|
|
|
* @param region
|
2010-10-13 23:49:35 +00:00
|
|
|
* @param block
|
2010-10-11 15:56:19 +00:00
|
|
|
* @return number of blocks affected
|
2010-10-11 08:22:47 +00:00
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
*/
|
2010-10-13 23:49:35 +00:00
|
|
|
public int setBlocks(Region region, BaseBlock block)
|
2010-10-11 08:22:47 +00:00
|
|
|
throws MaxChangedBlocksException {
|
|
|
|
int affected = 0;
|
|
|
|
|
2010-11-06 21:43:56 +00:00
|
|
|
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();
|
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int x = minX; x <= maxX; ++x) {
|
|
|
|
for (int y = minY; y <= maxY; ++y) {
|
|
|
|
for (int z = minZ; z <= maxZ; ++z) {
|
2010-11-06 21:43:56 +00:00
|
|
|
Vector pt = new Vector(x, y, z);
|
|
|
|
|
|
|
|
if (setBlock(pt, block)) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-11-06 21:43:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (Vector pt : region) {
|
|
|
|
if (setBlock(pt, block)) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-11-06 21:43:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets all the blocks inside a region to a certain block type.
|
2011-01-01 18:33:18 +00:00
|
|
|
*
|
2010-11-06 21:43:56 +00:00
|
|
|
* @param region
|
2011-02-18 23:49:50 +00:00
|
|
|
* @param pattern
|
2010-11-06 21:43:56 +00:00
|
|
|
* @return number of blocks affected
|
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
*/
|
|
|
|
public int setBlocks(Region region, Pattern pattern)
|
|
|
|
throws MaxChangedBlocksException {
|
|
|
|
int affected = 0;
|
|
|
|
|
2010-10-11 08:22:47 +00:00
|
|
|
if (region instanceof CuboidRegion) {
|
|
|
|
// Doing this for speed
|
2010-10-13 01:03:56 +00:00
|
|
|
Vector min = region.getMinimumPoint();
|
|
|
|
Vector max = region.getMaximumPoint();
|
2010-10-11 08:22:47 +00:00
|
|
|
|
2010-11-06 22:09:32 +00:00
|
|
|
int minX = min.getBlockX();
|
|
|
|
int minY = min.getBlockY();
|
|
|
|
int minZ = min.getBlockZ();
|
|
|
|
int maxX = max.getBlockX();
|
|
|
|
int maxY = max.getBlockY();
|
|
|
|
int maxZ = max.getBlockZ();
|
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int x = minX; x <= maxX; ++x) {
|
|
|
|
for (int y = minY; y <= maxY; ++y) {
|
|
|
|
for (int z = minZ; z <= maxZ; ++z) {
|
2010-10-13 01:03:56 +00:00
|
|
|
Vector pt = new Vector(x, y, z);
|
2010-10-11 08:22:47 +00:00
|
|
|
|
2010-11-06 21:43:56 +00:00
|
|
|
if (setBlock(pt, pattern.next(pt))) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-10-11 08:22:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2010-10-13 01:03:56 +00:00
|
|
|
for (Vector pt : region) {
|
2010-11-06 21:43:56 +00:00
|
|
|
if (setBlock(pt, pattern.next(pt))) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-10-11 08:22:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Replaces all the blocks of a type inside a region to another block type.
|
2011-01-01 18:33:18 +00:00
|
|
|
*
|
2010-10-11 08:22:47 +00:00
|
|
|
* @param region
|
2011-02-18 23:49:50 +00:00
|
|
|
* @param fromBlockTypes -1 for non-air
|
|
|
|
* @param toBlock
|
2010-10-11 15:56:19 +00:00
|
|
|
* @return number of blocks affected
|
2010-10-11 08:22:47 +00:00
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
*/
|
2011-01-01 18:33:18 +00:00
|
|
|
public int replaceBlocks(Region region, Set<Integer> fromBlockTypes,
|
|
|
|
BaseBlock toBlock) throws MaxChangedBlocksException {
|
2010-10-11 08:22:47 +00:00
|
|
|
int affected = 0;
|
|
|
|
|
|
|
|
if (region instanceof CuboidRegion) {
|
|
|
|
// Doing this for speed
|
2010-10-13 01:03:56 +00:00
|
|
|
Vector min = region.getMinimumPoint();
|
|
|
|
Vector max = region.getMaximumPoint();
|
2010-10-11 08:22:47 +00:00
|
|
|
|
2010-11-06 22:09:32 +00:00
|
|
|
int minX = min.getBlockX();
|
|
|
|
int minY = min.getBlockY();
|
|
|
|
int minZ = min.getBlockZ();
|
|
|
|
int maxX = max.getBlockX();
|
|
|
|
int maxY = max.getBlockY();
|
|
|
|
int maxZ = max.getBlockZ();
|
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int x = minX; x <= maxX; ++x) {
|
|
|
|
for (int y = minY; y <= maxY; ++y) {
|
|
|
|
for (int z = minZ; z <= maxZ; ++z) {
|
2010-10-13 01:03:56 +00:00
|
|
|
Vector pt = new Vector(x, y, z);
|
2011-01-31 07:42:18 +00:00
|
|
|
int curBlockType = getBlockType(pt);
|
2010-10-11 08:22:47 +00:00
|
|
|
|
2011-01-01 18:33:18 +00:00
|
|
|
if ((fromBlockTypes == null && curBlockType != 0)
|
|
|
|
|| (fromBlockTypes != null && fromBlockTypes
|
|
|
|
.contains(curBlockType))) {
|
2010-10-13 23:49:35 +00:00
|
|
|
if (setBlock(pt, toBlock)) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-10-11 08:22:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2010-10-13 01:03:56 +00:00
|
|
|
for (Vector pt : region) {
|
2011-01-31 07:42:18 +00:00
|
|
|
int curBlockType = getBlockType(pt);
|
2010-10-11 08:22:47 +00:00
|
|
|
|
2011-01-01 18:33:18 +00:00
|
|
|
if (fromBlockTypes == null && curBlockType != 0
|
|
|
|
|| fromBlockTypes.contains(curBlockType)) {
|
2010-10-13 23:49:35 +00:00
|
|
|
if (setBlock(pt, toBlock)) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-10-11 08:22:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
2010-11-16 22:07:52 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Replaces all the blocks of a type inside a region to another block type.
|
2011-01-01 18:33:18 +00:00
|
|
|
*
|
2010-11-16 22:07:52 +00:00
|
|
|
* @param region
|
2011-02-18 23:49:50 +00:00
|
|
|
* @param fromBlockTypes -1 for non-air
|
2010-11-16 22:07:52 +00:00
|
|
|
* @param pattern
|
|
|
|
* @return number of blocks affected
|
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
*/
|
|
|
|
public int replaceBlocks(Region region, Set<Integer> fromBlockTypes,
|
2011-01-01 18:33:18 +00:00
|
|
|
Pattern pattern) throws MaxChangedBlocksException {
|
2010-11-16 22:07:52 +00:00
|
|
|
int affected = 0;
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int x = minX; x <= maxX; ++x) {
|
|
|
|
for (int y = minY; y <= maxY; ++y) {
|
|
|
|
for (int z = minZ; z <= maxZ; ++z) {
|
2010-11-16 22:07:52 +00:00
|
|
|
Vector pt = new Vector(x, y, z);
|
2011-01-31 07:42:18 +00:00
|
|
|
int curBlockType = getBlockType(pt);
|
2010-11-16 22:07:52 +00:00
|
|
|
|
2011-01-01 18:33:18 +00:00
|
|
|
if ((fromBlockTypes == null && curBlockType != 0)
|
|
|
|
|| (fromBlockTypes != null && fromBlockTypes
|
|
|
|
.contains(curBlockType))) {
|
2010-11-16 22:07:52 +00:00
|
|
|
if (setBlock(pt, pattern.next(pt))) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-11-16 22:07:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (Vector pt : region) {
|
2011-01-31 07:42:18 +00:00
|
|
|
int curBlockType = getBlockType(pt);
|
2010-11-16 22:07:52 +00:00
|
|
|
|
2011-01-01 18:33:18 +00:00
|
|
|
if (fromBlockTypes == null && curBlockType != 0
|
|
|
|
|| fromBlockTypes.contains(curBlockType)) {
|
2010-11-16 22:07:52 +00:00
|
|
|
if (setBlock(pt, pattern.next(pt))) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-11-16 22:07:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
2010-10-11 08:22:47 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Make faces of the region (as if it was a cuboid if it's not).
|
2011-01-01 18:33:18 +00:00
|
|
|
*
|
2010-10-11 08:22:47 +00:00
|
|
|
* @param region
|
2010-10-13 23:49:35 +00:00
|
|
|
* @param block
|
2010-10-11 15:56:19 +00:00
|
|
|
* @return number of blocks affected
|
2010-10-11 08:22:47 +00:00
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
*/
|
2010-10-13 23:49:35 +00:00
|
|
|
public int makeCuboidFaces(Region region, BaseBlock block)
|
2010-10-11 08:22:47 +00:00
|
|
|
throws MaxChangedBlocksException {
|
|
|
|
int affected = 0;
|
|
|
|
|
2010-10-13 01:03:56 +00:00
|
|
|
Vector min = region.getMinimumPoint();
|
|
|
|
Vector max = region.getMaximumPoint();
|
2010-10-18 17:45:03 +00:00
|
|
|
|
2010-11-06 22:09:32 +00:00
|
|
|
int minX = min.getBlockX();
|
|
|
|
int minY = min.getBlockY();
|
|
|
|
int minZ = min.getBlockZ();
|
|
|
|
int maxX = max.getBlockX();
|
|
|
|
int maxY = max.getBlockY();
|
|
|
|
int maxZ = max.getBlockZ();
|
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int x = minX; x <= maxX; ++x) {
|
|
|
|
for (int y = minY; y <= maxY; ++y) {
|
2011-01-01 18:33:18 +00:00
|
|
|
if (setBlock(new Vector(x, y, minZ), block)) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2011-01-01 18:33:18 +00:00
|
|
|
}
|
|
|
|
if (setBlock(new Vector(x, y, maxZ), block)) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2011-01-01 18:33:18 +00:00
|
|
|
}
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-10-11 08:22:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int y = minY; y <= maxY; ++y) {
|
|
|
|
for (int z = minZ; z <= maxZ; ++z) {
|
2011-01-01 18:33:18 +00:00
|
|
|
if (setBlock(new Vector(minX, y, z), block)) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2011-01-01 18:33:18 +00:00
|
|
|
}
|
|
|
|
if (setBlock(new Vector(maxX, y, z), block)) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2011-01-01 18:33:18 +00:00
|
|
|
}
|
2010-10-11 08:22:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int z = minZ; z <= maxZ; ++z) {
|
|
|
|
for (int x = minX; x <= maxX; ++x) {
|
2011-01-01 18:33:18 +00:00
|
|
|
if (setBlock(new Vector(x, minY, z), block)) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2011-01-01 18:33:18 +00:00
|
|
|
}
|
|
|
|
if (setBlock(new Vector(x, maxY, z), block)) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2011-01-01 18:33:18 +00:00
|
|
|
}
|
2010-10-11 08:22:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
|
|
|
|
2010-10-18 17:45:03 +00:00
|
|
|
/**
|
|
|
|
* Make walls of the region (as if it was a cuboid if it's not).
|
2011-01-01 18:33:18 +00:00
|
|
|
*
|
2010-10-18 17:45:03 +00:00
|
|
|
* @param region
|
|
|
|
* @param block
|
|
|
|
* @return number of blocks affected
|
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
*/
|
|
|
|
public int makeCuboidWalls(Region region, BaseBlock block)
|
|
|
|
throws MaxChangedBlocksException {
|
|
|
|
int affected = 0;
|
|
|
|
|
|
|
|
Vector min = region.getMinimumPoint();
|
|
|
|
Vector max = region.getMaximumPoint();
|
|
|
|
|
2010-11-06 22:09:32 +00:00
|
|
|
int minX = min.getBlockX();
|
|
|
|
int minY = min.getBlockY();
|
|
|
|
int minZ = min.getBlockZ();
|
|
|
|
int maxX = max.getBlockX();
|
|
|
|
int maxY = max.getBlockY();
|
|
|
|
int maxZ = max.getBlockZ();
|
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int x = minX; x <= maxX; ++x) {
|
|
|
|
for (int y = minY; y <= maxY; ++y) {
|
2011-01-01 18:33:18 +00:00
|
|
|
if (setBlock(new Vector(x, y, minZ), block)) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2011-01-01 18:33:18 +00:00
|
|
|
}
|
|
|
|
if (setBlock(new Vector(x, y, maxZ), block)) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2011-01-01 18:33:18 +00:00
|
|
|
}
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-10-18 17:45:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int y = minY; y <= maxY; ++y) {
|
|
|
|
for (int z = minZ; z <= maxZ; ++z) {
|
2011-01-01 18:33:18 +00:00
|
|
|
if (setBlock(new Vector(minX, y, z), block)) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2011-01-01 18:33:18 +00:00
|
|
|
}
|
|
|
|
if (setBlock(new Vector(maxX, y, z), block)) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2011-01-01 18:33:18 +00:00
|
|
|
}
|
2010-10-18 17:45:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
|
|
|
|
2010-10-11 08:22:47 +00:00
|
|
|
/**
|
|
|
|
* Overlays a layer of blocks over a cuboid area.
|
|
|
|
*
|
|
|
|
* @param region
|
2010-10-13 23:49:35 +00:00
|
|
|
* @param block
|
2010-10-11 15:56:19 +00:00
|
|
|
* @return number of blocks affected
|
2010-10-11 08:22:47 +00:00
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
*/
|
2010-10-13 23:49:35 +00:00
|
|
|
public int overlayCuboidBlocks(Region region, BaseBlock block)
|
2010-10-11 08:22:47 +00:00
|
|
|
throws MaxChangedBlocksException {
|
2010-10-13 01:03:56 +00:00
|
|
|
Vector min = region.getMinimumPoint();
|
|
|
|
Vector max = region.getMaximumPoint();
|
2011-01-01 18:33:18 +00:00
|
|
|
|
2010-10-11 08:22:47 +00:00
|
|
|
int upperY = Math.min(127, max.getBlockY() + 1);
|
2011-01-01 18:33:18 +00:00
|
|
|
int lowerY = Math.max(0, min.getBlockY() - 1);
|
2010-10-11 08:22:47 +00:00
|
|
|
|
|
|
|
int affected = 0;
|
|
|
|
|
2010-11-06 22:09:32 +00:00
|
|
|
int minX = min.getBlockX();
|
|
|
|
int minZ = min.getBlockZ();
|
|
|
|
int maxX = max.getBlockX();
|
|
|
|
int maxZ = max.getBlockZ();
|
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int x = minX; x <= maxX; ++x) {
|
|
|
|
for (int z = minZ; z <= maxZ; ++z) {
|
|
|
|
for (int y = upperY; y >= lowerY; --y) {
|
2010-10-13 23:49:35 +00:00
|
|
|
Vector above = new Vector(x, y + 1, z);
|
2011-01-01 18:33:18 +00:00
|
|
|
|
2010-10-13 23:49:35 +00:00
|
|
|
if (y + 1 <= 127 && !getBlock(new Vector(x, y, z)).isAir()
|
|
|
|
&& getBlock(above).isAir()) {
|
|
|
|
if (setBlock(above, block)) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-10-11 08:22:47 +00:00
|
|
|
}
|
|
|
|
break;
|
2011-01-30 08:47:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Overlays a layer of blocks over a cuboid area.
|
|
|
|
*
|
|
|
|
* @param region
|
|
|
|
* @param pattern
|
|
|
|
* @return number of blocks affected
|
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
*/
|
|
|
|
public int overlayCuboidBlocks(Region region, Pattern pattern)
|
|
|
|
throws MaxChangedBlocksException {
|
|
|
|
Vector min = region.getMinimumPoint();
|
|
|
|
Vector max = region.getMaximumPoint();
|
|
|
|
|
|
|
|
int upperY = Math.min(127, max.getBlockY() + 1);
|
|
|
|
int lowerY = Math.max(0, min.getBlockY() - 1);
|
|
|
|
|
|
|
|
int affected = 0;
|
|
|
|
|
|
|
|
int minX = min.getBlockX();
|
|
|
|
int minZ = min.getBlockZ();
|
|
|
|
int maxX = max.getBlockX();
|
|
|
|
int maxZ = max.getBlockZ();
|
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int x = minX; x <= maxX; ++x) {
|
|
|
|
for (int z = minZ; z <= maxZ; ++z) {
|
|
|
|
for (int y = upperY; y >= lowerY; --y) {
|
2011-01-30 08:47:02 +00:00
|
|
|
Vector above = new Vector(x, y + 1, z);
|
|
|
|
|
|
|
|
if (y + 1 <= 127 && !getBlock(new Vector(x, y, z)).isAir()
|
|
|
|
&& getBlock(above).isAir()) {
|
|
|
|
if (setBlock(above, pattern.next(above))) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2011-01-30 08:47:02 +00:00
|
|
|
}
|
|
|
|
break;
|
2010-10-11 08:22:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
|
|
|
|
2011-08-02 22:46:11 +00:00
|
|
|
/**
|
|
|
|
* Turns the first 3 layers into dirt/grass and the bottom layers
|
|
|
|
* into rock, like a natural Minecraft mountain.
|
|
|
|
*
|
|
|
|
* @param region
|
|
|
|
* @return number of blocks affected
|
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
*/
|
|
|
|
public int naturalizeCuboidBlocks(Region region)
|
|
|
|
throws MaxChangedBlocksException {
|
|
|
|
Vector min = region.getMinimumPoint();
|
|
|
|
Vector max = region.getMaximumPoint();
|
|
|
|
|
|
|
|
int upperY = Math.min(127, max.getBlockY() + 1);
|
|
|
|
int lowerY = Math.max(0, min.getBlockY() - 1);
|
|
|
|
|
|
|
|
int affected = 0;
|
|
|
|
|
|
|
|
int minX = min.getBlockX();
|
|
|
|
int minZ = min.getBlockZ();
|
|
|
|
int maxX = max.getBlockX();
|
|
|
|
int maxZ = max.getBlockZ();
|
|
|
|
|
|
|
|
BaseBlock grass = new BaseBlock(BlockID.GRASS);
|
|
|
|
BaseBlock dirt = new BaseBlock(BlockID.DIRT);
|
|
|
|
BaseBlock stone = new BaseBlock(BlockID.STONE);
|
|
|
|
|
|
|
|
for (int x = minX; x <= maxX; ++x) {
|
|
|
|
for (int z = minZ; z <= maxZ; ++z) {
|
|
|
|
int level = -1;
|
|
|
|
|
|
|
|
for (int y = upperY; y >= lowerY; --y) {
|
|
|
|
Vector pt = new Vector(x, y, z);
|
2011-08-07 00:19:26 +00:00
|
|
|
//Vector above = new Vector(x, y + 1, z);
|
2011-08-02 22:46:11 +00:00
|
|
|
int blockType = getBlockType(pt);
|
|
|
|
|
|
|
|
boolean isTransformable =
|
|
|
|
blockType == BlockID.GRASS
|
|
|
|
|| blockType == BlockID.DIRT
|
|
|
|
|| blockType == BlockID.STONE;
|
|
|
|
|
|
|
|
// Still searching for the top block
|
|
|
|
if (level == -1) {
|
|
|
|
if (!isTransformable) {
|
|
|
|
continue; // Not transforming this column yet
|
|
|
|
}
|
|
|
|
|
|
|
|
level = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (level >= 0) {
|
|
|
|
if (isTransformable) {
|
|
|
|
if (level == 0) {
|
|
|
|
setBlock(pt, grass);
|
|
|
|
affected++;
|
|
|
|
} else if (level <= 2) {
|
|
|
|
setBlock(pt, dirt);
|
|
|
|
affected++;
|
|
|
|
} else {
|
|
|
|
setBlock(pt, stone);
|
|
|
|
affected++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
level++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
|
|
|
|
2010-10-11 17:27:18 +00:00
|
|
|
/**
|
|
|
|
* Stack a cuboid region.
|
|
|
|
*
|
|
|
|
* @param region
|
2010-10-13 04:41:06 +00:00
|
|
|
* @param dir
|
2010-10-11 17:27:18 +00:00
|
|
|
* @param count
|
|
|
|
* @param copyAir
|
|
|
|
* @return number of blocks affected
|
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
*/
|
2011-01-01 18:33:18 +00:00
|
|
|
public int stackCuboidRegion(Region region, Vector dir, int count,
|
|
|
|
boolean copyAir) throws MaxChangedBlocksException {
|
2010-10-11 08:22:47 +00:00
|
|
|
int affected = 0;
|
|
|
|
|
2010-10-13 01:03:56 +00:00
|
|
|
Vector min = region.getMinimumPoint();
|
|
|
|
Vector max = region.getMaximumPoint();
|
2010-11-06 22:09:32 +00:00
|
|
|
|
|
|
|
int minX = min.getBlockX();
|
|
|
|
int minY = min.getBlockY();
|
|
|
|
int minZ = min.getBlockZ();
|
|
|
|
int maxX = max.getBlockX();
|
|
|
|
int maxY = max.getBlockY();
|
|
|
|
int maxZ = max.getBlockZ();
|
2011-01-01 18:33:18 +00:00
|
|
|
|
2010-10-11 08:22:47 +00:00
|
|
|
int xs = region.getWidth();
|
|
|
|
int ys = region.getHeight();
|
|
|
|
int zs = region.getLength();
|
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int x = minX; x <= maxX; ++x) {
|
|
|
|
for (int z = minZ; z <= maxZ; ++z) {
|
|
|
|
for (int y = minY; y <= maxY; ++y) {
|
2010-10-13 23:49:35 +00:00
|
|
|
BaseBlock block = getBlock(new Vector(x, y, z));
|
2010-10-11 08:22:47 +00:00
|
|
|
|
2010-10-13 23:49:35 +00:00
|
|
|
if (!block.isAir() || copyAir) {
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int i = 1; i <= count; ++i) {
|
2011-01-01 18:33:18 +00:00
|
|
|
Vector pos = new Vector(x + xs * dir.getBlockX()
|
|
|
|
* i, y + ys * dir.getBlockY() * i, z + zs
|
|
|
|
* dir.getBlockZ() * i);
|
|
|
|
|
2010-10-13 23:49:35 +00:00
|
|
|
if (setBlock(pos, block)) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-10-11 08:22:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
2010-10-11 18:17:32 +00:00
|
|
|
|
2010-10-18 20:51:43 +00:00
|
|
|
/**
|
|
|
|
* Move a cuboid region.
|
2011-01-01 18:33:18 +00:00
|
|
|
*
|
2010-10-18 20:51:43 +00:00
|
|
|
* @param region
|
|
|
|
* @param dir
|
|
|
|
* @param distance
|
|
|
|
* @param copyAir
|
|
|
|
* @param replace
|
|
|
|
* @return number of blocks moved
|
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
*/
|
2011-01-01 18:33:18 +00:00
|
|
|
public int moveCuboidRegion(Region region, Vector dir, int distance,
|
|
|
|
boolean copyAir, BaseBlock replace)
|
2010-10-18 20:51:43 +00:00
|
|
|
throws MaxChangedBlocksException {
|
|
|
|
int affected = 0;
|
|
|
|
|
|
|
|
Vector shift = dir.multiply(distance);
|
|
|
|
Vector min = region.getMinimumPoint();
|
|
|
|
Vector max = region.getMaximumPoint();
|
2010-11-06 22:09:32 +00:00
|
|
|
|
|
|
|
int minX = min.getBlockX();
|
|
|
|
int minY = min.getBlockY();
|
|
|
|
int minZ = min.getBlockZ();
|
|
|
|
int maxX = max.getBlockX();
|
|
|
|
int maxY = max.getBlockY();
|
|
|
|
int maxZ = max.getBlockZ();
|
|
|
|
|
2010-10-18 20:51:43 +00:00
|
|
|
Vector newMin = min.add(shift);
|
|
|
|
Vector newMax = min.add(shift);
|
|
|
|
|
2011-01-01 18:33:18 +00:00
|
|
|
Map<Vector, BaseBlock> delayed = new LinkedHashMap<Vector, BaseBlock>();
|
2010-10-18 20:51:43 +00:00
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int x = minX; x <= maxX; ++x) {
|
|
|
|
for (int z = minZ; z <= maxZ; ++z) {
|
|
|
|
for (int y = minY; y <= maxY; ++y) {
|
2010-10-18 20:51:43 +00:00
|
|
|
Vector pos = new Vector(x, y, z);
|
|
|
|
BaseBlock block = getBlock(pos);
|
|
|
|
|
|
|
|
if (!block.isAir() || copyAir) {
|
|
|
|
Vector newPos = pos.add(shift);
|
|
|
|
|
|
|
|
delayed.put(newPos, getBlock(pos));
|
|
|
|
|
|
|
|
// Don't want to replace the old block if it's in
|
|
|
|
// the new area
|
|
|
|
if (x >= newMin.getBlockX() && x <= newMax.getBlockX()
|
2011-01-01 18:33:18 +00:00
|
|
|
&& y >= newMin.getBlockY()
|
|
|
|
&& y <= newMax.getBlockY()
|
|
|
|
&& z >= newMin.getBlockZ()
|
|
|
|
&& z <= newMax.getBlockZ()) {
|
2010-10-18 20:51:43 +00:00
|
|
|
} else {
|
|
|
|
setBlock(pos, replace);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-01 18:33:18 +00:00
|
|
|
for (Map.Entry<Vector, BaseBlock> entry : delayed.entrySet()) {
|
2010-10-18 20:51:43 +00:00
|
|
|
setBlock(entry.getKey(), entry.getValue());
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-10-18 20:51:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
|
|
|
|
2010-10-11 18:17:32 +00:00
|
|
|
/**
|
|
|
|
* Drain nearby pools of water or lava.
|
2011-01-01 18:33:18 +00:00
|
|
|
*
|
2010-10-11 18:17:32 +00:00
|
|
|
* @param pos
|
|
|
|
* @param radius
|
|
|
|
* @return number of blocks affected
|
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
*/
|
2011-08-15 12:35:21 +00:00
|
|
|
public int drainArea(Vector pos, double radius)
|
2011-01-01 18:33:18 +00:00
|
|
|
throws MaxChangedBlocksException {
|
2010-10-11 18:17:32 +00:00
|
|
|
int affected = 0;
|
|
|
|
|
2010-10-13 01:03:56 +00:00
|
|
|
HashSet<BlockVector> visited = new HashSet<BlockVector>();
|
|
|
|
Stack<BlockVector> queue = new Stack<BlockVector>();
|
2010-10-11 18:17:32 +00:00
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int x = pos.getBlockX() - 1; x <= pos.getBlockX() + 1; ++x) {
|
|
|
|
for (int z = pos.getBlockZ() - 1; z <= pos.getBlockZ() + 1; ++z) {
|
|
|
|
for (int y = pos.getBlockY() - 1; y <= pos.getBlockY() + 1; ++y) {
|
2010-10-13 01:03:56 +00:00
|
|
|
queue.push(new BlockVector(x, y, z));
|
2010-10-11 18:17:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-11 18:30:11 +00:00
|
|
|
while (!queue.empty()) {
|
2010-10-13 01:03:56 +00:00
|
|
|
BlockVector cur = queue.pop();
|
2010-10-15 08:07:48 +00:00
|
|
|
|
2011-01-31 07:42:18 +00:00
|
|
|
int type = getBlockType(cur);
|
2010-10-11 18:17:32 +00:00
|
|
|
|
2010-10-11 18:30:11 +00:00
|
|
|
// Check block type
|
|
|
|
if (type != 8 && type != 9 && type != 10 && type != 11) {
|
|
|
|
continue;
|
|
|
|
}
|
2010-10-11 18:17:32 +00:00
|
|
|
|
2010-10-11 18:30:11 +00:00
|
|
|
// Don't want to revisit
|
|
|
|
if (visited.contains(cur)) {
|
|
|
|
continue;
|
|
|
|
}
|
2010-10-15 08:07:48 +00:00
|
|
|
|
2010-10-11 18:30:11 +00:00
|
|
|
visited.add(cur);
|
2010-10-11 18:17:32 +00:00
|
|
|
|
2010-10-11 18:30:11 +00:00
|
|
|
// Check radius
|
|
|
|
if (pos.distance(cur) > radius) {
|
|
|
|
continue;
|
|
|
|
}
|
2010-10-11 18:17:32 +00:00
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int x = cur.getBlockX() - 1; x <= cur.getBlockX() + 1; ++x) {
|
|
|
|
for (int z = cur.getBlockZ() - 1; z <= cur.getBlockZ() + 1; ++z) {
|
|
|
|
for (int y = cur.getBlockY() - 1; y <= cur.getBlockY() + 1; ++y) {
|
2010-10-13 01:03:56 +00:00
|
|
|
BlockVector newPos = new BlockVector(x, y, z);
|
2010-10-11 18:17:32 +00:00
|
|
|
|
2010-10-11 18:30:11 +00:00
|
|
|
if (!cur.equals(newPos)) {
|
|
|
|
queue.push(newPos);
|
|
|
|
}
|
2010-10-11 18:17:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-13 23:49:35 +00:00
|
|
|
if (setBlock(cur, new BaseBlock(0))) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-10-11 18:30:11 +00:00
|
|
|
}
|
2010-10-11 18:17:32 +00:00
|
|
|
}
|
2010-10-15 08:07:48 +00:00
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Level water.
|
2011-01-01 18:33:18 +00:00
|
|
|
*
|
2010-10-15 08:07:48 +00:00
|
|
|
* @param pos
|
|
|
|
* @param radius
|
2011-02-18 23:49:50 +00:00
|
|
|
* @param moving
|
|
|
|
* @param stationary
|
2010-10-15 08:07:48 +00:00
|
|
|
* @return number of blocks affected
|
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
*/
|
2011-08-15 12:35:21 +00:00
|
|
|
public int fixLiquid(Vector pos, double radius, int moving, int stationary)
|
2010-11-06 05:04:44 +00:00
|
|
|
throws MaxChangedBlocksException {
|
2010-10-15 08:07:48 +00:00
|
|
|
int affected = 0;
|
|
|
|
|
|
|
|
HashSet<BlockVector> visited = new HashSet<BlockVector>();
|
|
|
|
Stack<BlockVector> queue = new Stack<BlockVector>();
|
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int x = pos.getBlockX() - 1; x <= pos.getBlockX() + 1; ++x) {
|
|
|
|
for (int z = pos.getBlockZ() - 1; z <= pos.getBlockZ() + 1; ++z) {
|
|
|
|
for (int y = pos.getBlockY() - 1; y <= pos.getBlockY() + 1; ++y) {
|
2011-01-16 17:39:11 +00:00
|
|
|
int type = getBlock(new Vector(x, y, z)).getType();
|
2010-10-15 08:07:48 +00:00
|
|
|
|
|
|
|
// Check block type
|
2010-11-06 05:04:44 +00:00
|
|
|
if (type == moving || type == stationary) {
|
2010-10-15 08:07:48 +00:00
|
|
|
queue.push(new BlockVector(x, y, z));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-06 05:04:44 +00:00
|
|
|
BaseBlock stationaryBlock = new BaseBlock(stationary);
|
2010-10-15 08:07:48 +00:00
|
|
|
|
|
|
|
while (!queue.empty()) {
|
|
|
|
BlockVector cur = queue.pop();
|
|
|
|
|
2011-01-31 07:42:18 +00:00
|
|
|
int type = getBlockType(cur);
|
2010-10-15 08:07:48 +00:00
|
|
|
|
|
|
|
// Check block type
|
2010-11-06 05:04:44 +00:00
|
|
|
if (type != moving && type != stationary && type != 0) {
|
2010-10-15 08:07:48 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't want to revisit
|
|
|
|
if (visited.contains(cur)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
visited.add(cur);
|
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
if (setBlock(cur, stationaryBlock)){
|
|
|
|
++affected;
|
2010-10-15 08:07:48 +00:00
|
|
|
}
|
2011-08-07 00:40:48 +00:00
|
|
|
|
2010-10-15 08:07:48 +00:00
|
|
|
// Check radius
|
|
|
|
if (pos.distance(cur) > radius) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2010-11-27 07:02:18 +00:00
|
|
|
queue.push(cur.add(1, 0, 0).toBlockVector());
|
|
|
|
queue.push(cur.add(-1, 0, 0).toBlockVector());
|
|
|
|
queue.push(cur.add(0, 0, 1).toBlockVector());
|
|
|
|
queue.push(cur.add(0, 0, -1).toBlockVector());
|
2010-10-15 08:07:48 +00:00
|
|
|
}
|
2010-10-11 18:17:32 +00:00
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
2010-10-18 00:22:29 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper method to draw the cylinder.
|
|
|
|
*
|
|
|
|
* @param center
|
|
|
|
* @param x
|
|
|
|
* @param z
|
|
|
|
* @param height
|
|
|
|
* @param block
|
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
*/
|
2011-08-07 03:10:59 +00:00
|
|
|
private int makeHCylinderPoints(Vector center, int x, double z, int height,
|
2011-02-18 23:14:43 +00:00
|
|
|
Pattern block) throws MaxChangedBlocksException {
|
2011-08-07 03:10:59 +00:00
|
|
|
int ceilZ = (int) Math.ceil(z);
|
2010-10-18 00:22:29 +00:00
|
|
|
int affected = 0;
|
2011-01-01 18:33:18 +00:00
|
|
|
|
2010-10-18 00:22:29 +00:00
|
|
|
if (x == 0) {
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int y = 0; y < height; ++y) {
|
2011-08-07 03:10:59 +00:00
|
|
|
setBlock(center.add(0, y, ceilZ), block);
|
|
|
|
setBlock(center.add(0, y, -ceilZ), block);
|
|
|
|
setBlock(center.add(ceilZ, y, 0), block);
|
|
|
|
setBlock(center.add(-ceilZ, y, 0), block);
|
2010-10-18 00:22:29 +00:00
|
|
|
affected += 4;
|
|
|
|
}
|
|
|
|
} else if (x == z) {
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int y = 0; y < height; ++y) {
|
2011-08-07 03:10:59 +00:00
|
|
|
setBlock(center.add(x, y, ceilZ), block);
|
|
|
|
setBlock(center.add(-x, y, ceilZ), block);
|
|
|
|
setBlock(center.add(x, y, -ceilZ), block);
|
|
|
|
setBlock(center.add(-x, y, -ceilZ), block);
|
2010-10-18 00:22:29 +00:00
|
|
|
affected += 4;
|
|
|
|
}
|
|
|
|
} else if (x < z) {
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int y = 0; y < height; ++y) {
|
2011-08-07 03:10:59 +00:00
|
|
|
setBlock(center.add(x, y, ceilZ), block);
|
|
|
|
setBlock(center.add(-x, y, ceilZ), block);
|
|
|
|
setBlock(center.add(x, y, -ceilZ), block);
|
|
|
|
setBlock(center.add(-x, y, -ceilZ), block);
|
|
|
|
setBlock(center.add(ceilZ, y, x), block);
|
|
|
|
setBlock(center.add(-ceilZ, y, x), block);
|
|
|
|
setBlock(center.add(ceilZ, y, -x), block);
|
|
|
|
setBlock(center.add(-ceilZ, y, -x), block);
|
2010-10-18 00:22:29 +00:00
|
|
|
affected += 8;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Draw a hollow cylinder.
|
|
|
|
*
|
|
|
|
* @param pos
|
|
|
|
* @param block
|
|
|
|
* @param radius
|
|
|
|
* @param height
|
|
|
|
* @return number of blocks set
|
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
*/
|
2011-08-07 03:10:59 +00:00
|
|
|
public int makeHollowCylinder(Vector pos, Pattern block, double radius,
|
2011-01-01 18:33:18 +00:00
|
|
|
int height) throws MaxChangedBlocksException {
|
2010-10-18 00:22:29 +00:00
|
|
|
int x = 0;
|
2011-08-07 03:10:59 +00:00
|
|
|
double z = radius;
|
|
|
|
double d = (5 - radius * 4) / 4;
|
2010-10-18 00:22:29 +00:00
|
|
|
int affected = 0;
|
|
|
|
|
2010-10-18 00:39:20 +00:00
|
|
|
if (height == 0) {
|
|
|
|
return 0;
|
|
|
|
} else if (height < 0) {
|
|
|
|
height = -height;
|
|
|
|
pos = pos.subtract(0, height, 0);
|
|
|
|
}
|
|
|
|
|
2011-08-05 19:34:05 +00:00
|
|
|
// Only do this check if height is negative --Elizabeth
|
|
|
|
if (height < 0 && pos.getBlockY() - height - 1 < 0) {
|
2010-10-18 00:39:20 +00:00
|
|
|
height = pos.getBlockY() + 1;
|
|
|
|
} else if (pos.getBlockY() + height - 1 > 127) {
|
|
|
|
height = 127 - pos.getBlockY() + 1;
|
|
|
|
}
|
|
|
|
|
2010-10-18 00:22:29 +00:00
|
|
|
affected += makeHCylinderPoints(pos, x, z, height, block);
|
|
|
|
|
|
|
|
while (x < z) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++x;
|
2011-01-01 18:33:18 +00:00
|
|
|
|
2010-10-18 00:22:29 +00:00
|
|
|
if (d >= 0) {
|
2011-07-15 07:00:48 +00:00
|
|
|
d += 2 * (x - --z) + 1;
|
2010-10-18 00:22:29 +00:00
|
|
|
} else {
|
|
|
|
d += 2 * x + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
affected += makeHCylinderPoints(pos, x, z, height, block);
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper method to draw the cylinder.
|
2011-01-01 18:33:18 +00:00
|
|
|
*
|
2010-10-18 00:22:29 +00:00
|
|
|
* @param center
|
|
|
|
* @param x
|
|
|
|
* @param z
|
|
|
|
* @param height
|
|
|
|
* @param block
|
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
*/
|
2011-08-07 03:10:59 +00:00
|
|
|
private int makeCylinderPoints(Vector center, int x, double z, int height,
|
2011-02-18 23:14:43 +00:00
|
|
|
Pattern block) throws MaxChangedBlocksException {
|
2011-08-07 03:10:59 +00:00
|
|
|
int ceilZ = (int) Math.ceil(z);
|
|
|
|
int affected = 0;
|
2010-10-18 00:22:29 +00:00
|
|
|
|
|
|
|
if (x == z) {
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int y = 0; y < height; ++y) {
|
2011-08-07 03:10:59 +00:00
|
|
|
for (int z2 = -ceilZ; z2 <= ceilZ; ++z2) {
|
2010-10-18 00:22:29 +00:00
|
|
|
setBlock(center.add(x, y, z2), block);
|
|
|
|
setBlock(center.add(-x, y, z2), block);
|
|
|
|
affected += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (x < z) {
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int y = 0; y < height; ++y) {
|
|
|
|
for (int x2 = -x; x2 <= x; ++x2) {
|
2011-08-07 03:10:59 +00:00
|
|
|
for (int z2 = -ceilZ; z2 <= ceilZ; ++z2) {
|
2010-10-18 00:22:29 +00:00
|
|
|
setBlock(center.add(x2, y, z2), block);
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-10-18 00:22:29 +00:00
|
|
|
}
|
2011-08-07 03:10:59 +00:00
|
|
|
setBlock(center.add(ceilZ, y, x2), block);
|
|
|
|
setBlock(center.add(-ceilZ, y, x2), block);
|
2010-10-18 00:22:29 +00:00
|
|
|
affected += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Draw a filled cylinder.
|
|
|
|
*
|
|
|
|
* @param pos
|
|
|
|
* @param block
|
|
|
|
* @param radius
|
|
|
|
* @param height
|
|
|
|
* @return number of blocks set
|
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
*/
|
2011-08-07 03:10:59 +00:00
|
|
|
public int makeCylinder(Vector pos, Pattern block, double radius, int height)
|
2011-01-01 18:33:18 +00:00
|
|
|
throws MaxChangedBlocksException {
|
2010-10-18 00:22:29 +00:00
|
|
|
int x = 0;
|
2011-08-07 03:10:59 +00:00
|
|
|
double z = radius;
|
|
|
|
double d = (5 - radius * 4) / 4;
|
2010-10-18 00:22:29 +00:00
|
|
|
int affected = 0;
|
|
|
|
|
2010-10-18 00:39:20 +00:00
|
|
|
if (height == 0) {
|
|
|
|
return 0;
|
|
|
|
} else if (height < 0) {
|
|
|
|
height = -height;
|
|
|
|
pos = pos.subtract(0, height, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pos.getBlockY() - height - 1 < 0) {
|
|
|
|
height = pos.getBlockY() + 1;
|
|
|
|
} else if (pos.getBlockY() + height - 1 > 127) {
|
|
|
|
height = 127 - pos.getBlockY() + 1;
|
|
|
|
}
|
|
|
|
|
2010-10-18 00:22:29 +00:00
|
|
|
affected += makeCylinderPoints(pos, x, z, height, block);
|
|
|
|
|
|
|
|
while (x < z) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++x;
|
2010-10-18 00:22:29 +00:00
|
|
|
|
|
|
|
if (d >= 0) {
|
2011-07-15 07:00:48 +00:00
|
|
|
d += 2 * (x - --z) + 1;
|
2010-10-18 00:22:29 +00:00
|
|
|
} else {
|
|
|
|
d += 2 * x + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
affected += makeCylinderPoints(pos, x, z, height, block);
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
|
|
|
|
2010-10-18 17:39:32 +00:00
|
|
|
/**
|
|
|
|
* Makes a sphere.
|
2011-01-01 18:33:18 +00:00
|
|
|
*
|
2010-10-18 17:39:32 +00:00
|
|
|
* @param pos
|
|
|
|
* @param block
|
|
|
|
* @param radius
|
|
|
|
* @param filled
|
|
|
|
* @return number of blocks changed
|
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
*/
|
2011-08-07 03:10:59 +00:00
|
|
|
public int makeSphere(Vector pos, Pattern block, double radius,
|
2011-01-01 18:33:18 +00:00
|
|
|
boolean filled) throws MaxChangedBlocksException {
|
2010-10-18 17:39:32 +00:00
|
|
|
int affected = 0;
|
2011-01-01 18:33:18 +00:00
|
|
|
|
2011-08-12 06:16:53 +00:00
|
|
|
radius += 0.5;
|
|
|
|
final double radiusSq = radius*radius;
|
|
|
|
final double radius1Sq = (radius - 1)*(radius - 1);
|
|
|
|
|
|
|
|
final int ceilRadius = (int) Math.ceil(radius);
|
2011-08-07 03:10:59 +00:00
|
|
|
for (int x = 0; x <= ceilRadius; ++x) {
|
|
|
|
for (int y = 0; y <= ceilRadius; ++y) {
|
|
|
|
for (int z = 0; z <= ceilRadius; ++z) {
|
2011-08-12 06:16:53 +00:00
|
|
|
double dSq = lengthSq(x, y, z);
|
2010-10-18 17:39:32 +00:00
|
|
|
|
2011-08-12 06:16:53 +00:00
|
|
|
if (dSq > radiusSq)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!filled) {
|
|
|
|
if (dSq < radius1Sq)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (lengthSq(x+1, y, z) <= radiusSq && lengthSq(x, y+1, z) <= radiusSq && lengthSq(x, y, z+1) <= radiusSq)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (setBlock(pos.add(x, y, z), block)) {
|
|
|
|
++affected;
|
|
|
|
}
|
|
|
|
if (setBlock(pos.add(-x, y, z), block)) {
|
|
|
|
++affected;
|
|
|
|
}
|
|
|
|
if (setBlock(pos.add(x, -y, z), block)) {
|
|
|
|
++affected;
|
|
|
|
}
|
|
|
|
if (setBlock(pos.add(x, y, -z), block)) {
|
|
|
|
++affected;
|
|
|
|
}
|
|
|
|
if (setBlock(pos.add(-x, -y, z), block)) {
|
|
|
|
++affected;
|
|
|
|
}
|
|
|
|
if (setBlock(pos.add(x, -y, -z), block)) {
|
|
|
|
++affected;
|
|
|
|
}
|
|
|
|
if (setBlock(pos.add(-x, y, -z), block)) {
|
|
|
|
++affected;
|
|
|
|
}
|
|
|
|
if (setBlock(pos.add(-x, -y, -z), block)) {
|
|
|
|
++affected;
|
2010-10-18 17:39:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
|
|
|
|
2011-08-12 06:16:53 +00:00
|
|
|
private static final double lengthSq(int x, int y, int z) {
|
|
|
|
return x*x + y*y + z*z;
|
|
|
|
}
|
|
|
|
|
2011-08-07 00:40:48 +00:00
|
|
|
/**
|
|
|
|
* Makes a pyramid.
|
|
|
|
*
|
|
|
|
* @param pos
|
|
|
|
* @param block
|
|
|
|
* @param size
|
|
|
|
* @param filled
|
|
|
|
* @return number of blocks changed
|
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
*/
|
|
|
|
public int makePyramid(Vector pos, Pattern block, int size,
|
|
|
|
boolean filled) throws MaxChangedBlocksException {
|
|
|
|
int affected = 0;
|
|
|
|
|
|
|
|
int height = size;
|
|
|
|
|
|
|
|
for (int y = 0; y <= height; ++y) {
|
|
|
|
size--;
|
|
|
|
for (int x = 0; x <= size; ++x) {
|
|
|
|
for (int z = 0; z <= size; ++z) {
|
|
|
|
|
|
|
|
if ((filled && z <= size && x <= size) || z == size || x == size) {
|
|
|
|
|
|
|
|
if (setBlock(pos.add(x, y, z), block)) {
|
|
|
|
++affected;
|
|
|
|
}
|
|
|
|
if (setBlock(pos.add(-x, y, z), block)) {
|
|
|
|
++affected;
|
|
|
|
}
|
|
|
|
if (setBlock(pos.add(x, y, -z), block)) {
|
|
|
|
++affected;
|
|
|
|
}
|
|
|
|
if (setBlock(pos.add(-x, y, -z), block)) {
|
|
|
|
++affected;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
|
|
|
|
2011-01-08 19:40:18 +00:00
|
|
|
/**
|
|
|
|
* Thaw.
|
|
|
|
*
|
|
|
|
* @param pos
|
|
|
|
* @param radius
|
|
|
|
* @return number of blocks affected
|
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
*/
|
2011-08-15 12:35:21 +00:00
|
|
|
public int thaw(Vector pos, double radius)
|
2011-01-08 19:40:18 +00:00
|
|
|
throws MaxChangedBlocksException {
|
|
|
|
int affected = 0;
|
2011-08-16 16:42:29 +00:00
|
|
|
double radiusSq = radius*radius;
|
2011-01-08 19:40:18 +00:00
|
|
|
|
|
|
|
int ox = pos.getBlockX();
|
|
|
|
int oy = pos.getBlockY();
|
|
|
|
int oz = pos.getBlockZ();
|
|
|
|
|
|
|
|
BaseBlock air = new BaseBlock(0);
|
|
|
|
BaseBlock water = new BaseBlock(BlockID.STATIONARY_WATER);
|
|
|
|
|
2011-08-15 12:35:21 +00:00
|
|
|
int ceilRadius = (int) Math.ceil(radius);
|
|
|
|
for (int x = ox - ceilRadius; x <= ox + ceilRadius; ++x) {
|
|
|
|
for (int z = oz - ceilRadius; z <= oz + ceilRadius; ++z) {
|
2011-01-08 19:40:18 +00:00
|
|
|
if ((new Vector(x, oy, z)).distanceSq(pos) > radiusSq) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int y = 127; y >= 1; --y) {
|
2011-01-08 19:40:18 +00:00
|
|
|
Vector pt = new Vector(x, y, z);
|
2011-01-31 07:42:18 +00:00
|
|
|
int id = getBlockType(pt);
|
2011-01-08 19:40:18 +00:00
|
|
|
|
|
|
|
if (id == BlockID.ICE) { // Ice
|
|
|
|
if (setBlock(pt, water)) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2011-01-08 19:40:18 +00:00
|
|
|
}
|
|
|
|
} else if (id == BlockID.SNOW) {
|
|
|
|
if (setBlock(pt, air)) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2011-01-08 19:40:18 +00:00
|
|
|
}
|
|
|
|
} else if (id != 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
|
|
|
|
2010-11-07 04:26:52 +00:00
|
|
|
/**
|
|
|
|
* Make snow.
|
2011-01-01 18:33:18 +00:00
|
|
|
*
|
2010-11-07 04:26:52 +00:00
|
|
|
* @param pos
|
|
|
|
* @param radius
|
|
|
|
* @return number of blocks affected
|
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
*/
|
2011-08-15 12:35:21 +00:00
|
|
|
public int simulateSnow(Vector pos, double radius)
|
2010-11-07 04:26:52 +00:00
|
|
|
throws MaxChangedBlocksException {
|
|
|
|
int affected = 0;
|
2011-08-16 16:42:29 +00:00
|
|
|
double radiusSq = radius*radius;
|
2010-11-07 04:26:52 +00:00
|
|
|
|
|
|
|
int ox = pos.getBlockX();
|
|
|
|
int oy = pos.getBlockY();
|
|
|
|
int oz = pos.getBlockZ();
|
|
|
|
|
|
|
|
BaseBlock ice = new BaseBlock(79);
|
|
|
|
BaseBlock snow = new BaseBlock(78);
|
|
|
|
|
2011-08-15 12:35:21 +00:00
|
|
|
int ceilRadius = (int) Math.ceil(radius);
|
|
|
|
for (int x = ox - ceilRadius; x <= ox + ceilRadius; ++x) {
|
|
|
|
for (int z = oz - ceilRadius; z <= oz + ceilRadius; ++z) {
|
2011-01-08 18:59:06 +00:00
|
|
|
if ((new Vector(x, oy, z)).distanceSq(pos) > radiusSq) {
|
2010-11-07 04:26:52 +00:00
|
|
|
continue;
|
|
|
|
}
|
2011-01-01 18:33:18 +00:00
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int y = 127; y >= 1; --y) {
|
2010-11-07 04:26:52 +00:00
|
|
|
Vector pt = new Vector(x, y, z);
|
2011-01-31 07:42:18 +00:00
|
|
|
int id = getBlockType(pt);
|
2010-11-07 04:26:52 +00:00
|
|
|
|
|
|
|
// Snow should not cover these blocks
|
|
|
|
if (id == 6 // Saplings
|
|
|
|
|| id == 10 // Lava
|
|
|
|
|| id == 11 // Lava
|
|
|
|
|| id == 37 // Yellow flower
|
|
|
|
|| id == 38 // Red rose
|
|
|
|
|| id == 39 // Brown mushroom
|
|
|
|
|| id == 40 // Red mushroom
|
|
|
|
|| id == 44 // Step
|
|
|
|
|| id == 50 // Torch
|
|
|
|
|| id == 51 // Fire
|
|
|
|
|| id == 53 // Wood steps
|
|
|
|
|| id == 55 // Redstone wire
|
|
|
|
|| id == 59 // Crops
|
2011-01-01 18:33:18 +00:00
|
|
|
|| (id >= 63 && id <= 72) || id == 75 // Redstone
|
2011-08-07 00:40:48 +00:00
|
|
|
// torch
|
2010-11-07 04:26:52 +00:00
|
|
|
|| id == 76 // Redstone torch
|
|
|
|
|| id == 77 // Stone button
|
|
|
|
|| id == 78 // Snow
|
|
|
|
|| id == 79 // Ice
|
|
|
|
|| id == 81 // Cactus
|
|
|
|
|| id == 83 // Reed
|
|
|
|
|| id == 85 // Fence
|
|
|
|
|| id == 90) { // Portal
|
|
|
|
break;
|
|
|
|
}
|
2011-01-01 18:33:18 +00:00
|
|
|
|
2010-11-07 04:26:52 +00:00
|
|
|
// Ice!
|
|
|
|
if (id == 8 || id == 9) {
|
|
|
|
if (setBlock(pt, ice)) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-11-07 04:26:52 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cover
|
|
|
|
if (id != 0) {
|
|
|
|
if (y == 127) { // Too high!
|
|
|
|
break;
|
|
|
|
}
|
2011-01-01 18:33:18 +00:00
|
|
|
|
2010-11-07 04:26:52 +00:00
|
|
|
if (setBlock(pt.add(0, 1, 0), snow)) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-11-07 04:26:52 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
2011-01-01 18:33:18 +00:00
|
|
|
|
2011-08-16 16:43:13 +00:00
|
|
|
/**
|
|
|
|
* Green.
|
|
|
|
*
|
|
|
|
* @param pos
|
|
|
|
* @param radius
|
|
|
|
* @return number of blocks affected
|
|
|
|
* @throws MaxChangedBlocksException
|
|
|
|
*/
|
|
|
|
public int green(Vector pos, double radius)
|
|
|
|
throws MaxChangedBlocksException {
|
|
|
|
int affected = 0;
|
|
|
|
double radiusSq = radius*radius;
|
|
|
|
|
|
|
|
int ox = pos.getBlockX();
|
|
|
|
int oy = pos.getBlockY();
|
|
|
|
int oz = pos.getBlockZ();
|
|
|
|
|
|
|
|
BaseBlock grass = new BaseBlock(BlockID.GRASS);
|
|
|
|
|
|
|
|
int ceilRadius = (int) Math.ceil(radius);
|
|
|
|
for (int x = ox - ceilRadius; x <= ox + ceilRadius; ++x) {
|
|
|
|
for (int z = oz - ceilRadius; z <= oz + ceilRadius; ++z) {
|
|
|
|
if ((new Vector(x, oy, z)).distanceSq(pos) > radiusSq) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int y = 127; y >= 1; --y) {
|
|
|
|
Vector pt = new Vector(x, y, z);
|
|
|
|
int id = getBlockType(pt);
|
|
|
|
|
2011-08-20 13:17:29 +00:00
|
|
|
if (id == 0 || id == BlockID.SNOW)
|
2011-08-16 16:43:13 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (id == BlockID.DIRT) {
|
|
|
|
if (setBlock(pt, grass)) {
|
|
|
|
++affected;
|
|
|
|
}
|
|
|
|
}
|
2011-08-20 13:17:29 +00:00
|
|
|
break;
|
2011-08-16 16:43:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
|
|
|
|
2010-10-13 05:38:05 +00:00
|
|
|
/**
|
|
|
|
* Set a block by chance.
|
|
|
|
*
|
|
|
|
* @param pos
|
2010-10-13 23:49:35 +00:00
|
|
|
* @param block
|
2011-02-18 23:49:50 +00:00
|
|
|
* @param c 0-1 chance
|
2010-10-13 05:38:05 +00:00
|
|
|
* @return whether a block was changed
|
2011-02-18 23:49:50 +00:00
|
|
|
* @throws MaxChangedBlocksException
|
2010-10-13 05:38:05 +00:00
|
|
|
*/
|
2011-01-30 22:54:42 +00:00
|
|
|
public boolean setChanceBlockIfAir(Vector pos, BaseBlock block, double c)
|
2010-10-13 05:38:05 +00:00
|
|
|
throws MaxChangedBlocksException {
|
|
|
|
if (Math.random() <= c) {
|
2010-10-13 23:49:35 +00:00
|
|
|
return setBlockIfAir(pos, block);
|
2010-10-13 05:38:05 +00:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-10-31 01:20:15 +00:00
|
|
|
/**
|
|
|
|
* Makes a pumpkin patch.
|
2011-01-01 18:33:18 +00:00
|
|
|
*
|
2010-10-31 01:20:15 +00:00
|
|
|
* @param basePos
|
|
|
|
*/
|
|
|
|
private void makePumpkinPatch(Vector basePos)
|
|
|
|
throws MaxChangedBlocksException {
|
2011-01-01 18:33:18 +00:00
|
|
|
// BaseBlock logBlock = new BaseBlock(17);
|
2010-10-31 01:20:15 +00:00
|
|
|
BaseBlock leavesBlock = new BaseBlock(18);
|
|
|
|
|
2011-01-01 18:33:18 +00:00
|
|
|
// setBlock(basePos.subtract(0, 1, 0), logBlock);
|
2010-10-31 01:20:15 +00:00
|
|
|
setBlockIfAir(basePos, leavesBlock);
|
|
|
|
|
|
|
|
makePumpkinPatchVine(basePos, basePos.add(0, 0, 1));
|
|
|
|
makePumpkinPatchVine(basePos, basePos.add(0, 0, -1));
|
|
|
|
makePumpkinPatchVine(basePos, basePos.add(1, 0, 0));
|
|
|
|
makePumpkinPatchVine(basePos, basePos.add(-1, 0, 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Make a pumpkin patch fine.
|
|
|
|
*
|
|
|
|
* @param basePos
|
|
|
|
* @param pos
|
|
|
|
*/
|
|
|
|
private void makePumpkinPatchVine(Vector basePos, Vector pos)
|
|
|
|
throws MaxChangedBlocksException {
|
2011-08-07 00:40:48 +00:00
|
|
|
if (pos.distance(basePos) > 4)
|
2011-01-01 18:33:18 +00:00
|
|
|
return;
|
2011-08-07 00:40:48 +00:00
|
|
|
if (getBlockType(pos) != 0)
|
2011-01-01 18:33:18 +00:00
|
|
|
return;
|
2010-10-31 01:20:15 +00:00
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int i = -1; i > -3; --i) {
|
2010-10-31 01:20:15 +00:00
|
|
|
Vector testPos = pos.add(0, i, 0);
|
2011-01-31 07:42:18 +00:00
|
|
|
if (getBlockType(testPos) == 0) {
|
2010-10-31 01:20:15 +00:00
|
|
|
pos = testPos;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setBlockIfAir(pos, new BaseBlock(18));
|
|
|
|
|
|
|
|
int t = prng.nextInt(4);
|
|
|
|
int h = prng.nextInt(3) - 1;
|
|
|
|
|
|
|
|
if (t == 0) {
|
2011-08-07 00:40:48 +00:00
|
|
|
if (prng.nextBoolean())
|
2011-01-01 18:33:18 +00:00
|
|
|
makePumpkinPatchVine(basePos, pos.add(1, 0, 0));
|
2011-08-07 00:40:48 +00:00
|
|
|
if (prng.nextBoolean())
|
2011-01-01 18:33:18 +00:00
|
|
|
setBlockIfAir(pos.add(1, h, -1), new BaseBlock(18));
|
2010-10-31 01:20:15 +00:00
|
|
|
setBlockIfAir(pos.add(0, 0, -1), new BaseBlock(86));
|
|
|
|
} else if (t == 1) {
|
2011-08-07 00:40:48 +00:00
|
|
|
if (prng.nextBoolean())
|
2011-01-01 18:33:18 +00:00
|
|
|
makePumpkinPatchVine(basePos, pos.add(0, 0, 1));
|
2011-08-07 00:40:48 +00:00
|
|
|
if (prng.nextBoolean())
|
2011-01-01 18:33:18 +00:00
|
|
|
setBlockIfAir(pos.add(1, h, 0), new BaseBlock(18));
|
2010-10-31 01:20:15 +00:00
|
|
|
setBlockIfAir(pos.add(1, 0, 1), new BaseBlock(86));
|
|
|
|
} else if (t == 2) {
|
2011-08-07 00:40:48 +00:00
|
|
|
if (prng.nextBoolean())
|
2011-01-01 18:33:18 +00:00
|
|
|
makePumpkinPatchVine(basePos, pos.add(0, 0, -1));
|
2011-08-07 00:40:48 +00:00
|
|
|
if (prng.nextBoolean())
|
2011-01-01 18:33:18 +00:00
|
|
|
setBlockIfAir(pos.add(-1, h, 0), new BaseBlock(18));
|
2010-10-31 01:20:15 +00:00
|
|
|
setBlockIfAir(pos.add(-1, 0, 1), new BaseBlock(86));
|
|
|
|
} else if (t == 3) {
|
2011-08-07 00:40:48 +00:00
|
|
|
if (prng.nextBoolean())
|
2011-01-01 18:33:18 +00:00
|
|
|
makePumpkinPatchVine(basePos, pos.add(-1, 0, 0));
|
2011-08-07 00:40:48 +00:00
|
|
|
if (prng.nextBoolean())
|
2011-01-01 18:33:18 +00:00
|
|
|
setBlockIfAir(pos.add(-1, h, -1), new BaseBlock(18));
|
2010-10-31 01:20:15 +00:00
|
|
|
setBlockIfAir(pos.add(-1, 0, -1), new BaseBlock(86));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Makes pumpkin patches.
|
2011-01-01 18:33:18 +00:00
|
|
|
*
|
2010-10-31 01:20:15 +00:00
|
|
|
* @param basePos
|
|
|
|
* @param size
|
|
|
|
* @return number of trees created
|
2011-02-18 23:49:50 +00:00
|
|
|
* @throws MaxChangedBlocksException
|
2010-10-31 01:20:15 +00:00
|
|
|
*/
|
|
|
|
public int makePumpkinPatches(Vector basePos, int size)
|
|
|
|
throws MaxChangedBlocksException {
|
|
|
|
int affected = 0;
|
|
|
|
|
2011-01-01 18:33:18 +00:00
|
|
|
for (int x = basePos.getBlockX() - size; x <= basePos.getBlockX()
|
2011-07-15 07:00:48 +00:00
|
|
|
+ size; ++x) {
|
2011-01-01 18:33:18 +00:00
|
|
|
for (int z = basePos.getBlockZ() - size; z <= basePos.getBlockZ()
|
2011-07-15 07:00:48 +00:00
|
|
|
+ size; ++z) {
|
2010-10-31 01:20:15 +00:00
|
|
|
// Don't want to be in the ground
|
2011-08-07 00:40:48 +00:00
|
|
|
if (!getBlock(new Vector(x, basePos.getBlockY(), z)).isAir())
|
2010-10-31 01:20:15 +00:00
|
|
|
continue;
|
|
|
|
// The gods don't want a pumpkin patch here
|
2011-01-01 18:33:18 +00:00
|
|
|
if (Math.random() < 0.98) {
|
|
|
|
continue;
|
|
|
|
}
|
2010-10-31 01:20:15 +00:00
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int y = basePos.getBlockY(); y >= basePos.getBlockY() - 10; --y) {
|
2010-10-31 01:20:15 +00:00
|
|
|
// Check if we hit the ground
|
2011-01-16 17:39:11 +00:00
|
|
|
int t = getBlock(new Vector(x, y, z)).getType();
|
2010-10-31 01:20:15 +00:00
|
|
|
if (t == 2 || t == 3) {
|
|
|
|
makePumpkinPatch(new Vector(x, y + 1, z));
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-10-31 01:20:15 +00:00
|
|
|
break;
|
|
|
|
} else if (t != 0) { // Trees won't grow on this!
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
|
|
|
|
2010-10-13 05:38:05 +00:00
|
|
|
/**
|
2010-11-07 04:03:34 +00:00
|
|
|
* Makes a forest.
|
2010-10-13 05:38:05 +00:00
|
|
|
*
|
|
|
|
* @param basePos
|
|
|
|
* @param size
|
2010-11-07 04:03:34 +00:00
|
|
|
* @param density
|
2011-01-30 22:54:42 +00:00
|
|
|
* @param treeGenerator
|
2010-10-13 05:38:05 +00:00
|
|
|
* @return number of trees created
|
2011-02-18 23:49:50 +00:00
|
|
|
* @throws MaxChangedBlocksException
|
2010-10-13 05:38:05 +00:00
|
|
|
*/
|
2010-11-07 04:03:34 +00:00
|
|
|
public int makeForest(Vector basePos, int size, double density,
|
2011-01-30 22:54:42 +00:00
|
|
|
TreeGenerator treeGenerator) throws MaxChangedBlocksException {
|
2010-10-13 05:38:05 +00:00
|
|
|
int affected = 0;
|
2011-01-01 18:33:18 +00:00
|
|
|
|
|
|
|
for (int x = basePos.getBlockX() - size; x <= basePos.getBlockX()
|
2011-07-15 07:00:48 +00:00
|
|
|
+ size; ++x) {
|
2011-01-01 18:33:18 +00:00
|
|
|
for (int z = basePos.getBlockZ() - size; z <= basePos.getBlockZ()
|
2011-07-15 07:00:48 +00:00
|
|
|
+ size; ++z) {
|
2010-10-13 05:38:05 +00:00
|
|
|
// Don't want to be in the ground
|
2010-10-13 23:49:35 +00:00
|
|
|
if (!getBlock(new Vector(x, basePos.getBlockY(), z)).isAir())
|
|
|
|
continue;
|
2010-10-13 05:38:05 +00:00
|
|
|
// The gods don't want a tree here
|
2011-01-01 18:33:18 +00:00
|
|
|
if (Math.random() >= density) {
|
|
|
|
continue;
|
|
|
|
} // def 0.05
|
2010-10-13 05:38:05 +00:00
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int y = basePos.getBlockY(); y >= basePos.getBlockY() - 10; --y) {
|
2010-10-13 05:38:05 +00:00
|
|
|
// Check if we hit the ground
|
2011-01-16 17:39:11 +00:00
|
|
|
int t = getBlock(new Vector(x, y, z)).getType();
|
2010-10-13 05:38:05 +00:00
|
|
|
if (t == 2 || t == 3) {
|
2011-01-30 22:54:42 +00:00
|
|
|
treeGenerator.generate(this, new Vector(x, y + 1, z));
|
2011-07-15 07:00:48 +00:00
|
|
|
++affected;
|
2010-10-13 05:38:05 +00:00
|
|
|
break;
|
|
|
|
} else if (t != 0) { // Trees won't grow on this!
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return affected;
|
|
|
|
}
|
2010-11-07 04:03:34 +00:00
|
|
|
|
2010-11-17 06:59:53 +00:00
|
|
|
/**
|
|
|
|
* Count the number of blocks of a list of types in a region.
|
2011-01-01 18:33:18 +00:00
|
|
|
*
|
2010-11-17 06:59:53 +00:00
|
|
|
* @param region
|
|
|
|
* @param searchIDs
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
public int countBlocks(Region region, Set<Integer> searchIDs) {
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int x = minX; x <= maxX; ++x) {
|
|
|
|
for (int y = minY; y <= maxY; ++y) {
|
|
|
|
for (int z = minZ; z <= maxZ; ++z) {
|
2010-11-17 06:59:53 +00:00
|
|
|
Vector pt = new Vector(x, y, z);
|
|
|
|
|
2011-01-31 07:42:18 +00:00
|
|
|
if (searchIDs.contains(getBlockType(pt))) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++count;
|
2010-11-17 06:59:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (Vector pt : region) {
|
2011-01-31 07:42:18 +00:00
|
|
|
if (searchIDs.contains(getBlockType(pt))) {
|
2011-07-15 07:00:48 +00:00
|
|
|
++count;
|
2010-11-17 06:59:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the block distribution inside a region.
|
|
|
|
*
|
|
|
|
* @param region
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
public List<Countable<Integer>> getBlockDistribution(Region region) {
|
2011-01-01 18:33:18 +00:00
|
|
|
List<Countable<Integer>> distribution = new ArrayList<Countable<Integer>>();
|
|
|
|
Map<Integer, Countable<Integer>> map = new HashMap<Integer, Countable<Integer>>();
|
2010-11-17 06:59:53 +00:00
|
|
|
|
|
|
|
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();
|
|
|
|
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int x = minX; x <= maxX; ++x) {
|
|
|
|
for (int y = minY; y <= maxY; ++y) {
|
|
|
|
for (int z = minZ; z <= maxZ; ++z) {
|
2010-11-17 06:59:53 +00:00
|
|
|
Vector pt = new Vector(x, y, z);
|
|
|
|
|
2011-01-31 07:42:18 +00:00
|
|
|
int id = getBlockType(pt);
|
2010-11-17 06:59:53 +00:00
|
|
|
|
|
|
|
if (map.containsKey(id)) {
|
|
|
|
map.get(id).increment();
|
|
|
|
} else {
|
|
|
|
Countable<Integer> c = new Countable<Integer>(id, 1);
|
|
|
|
map.put(id, c);
|
|
|
|
distribution.add(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (Vector pt : region) {
|
2011-01-31 07:42:18 +00:00
|
|
|
int id = getBlockType(pt);
|
2010-11-17 06:59:53 +00:00
|
|
|
|
|
|
|
if (map.containsKey(id)) {
|
|
|
|
map.get(id).increment();
|
|
|
|
} else {
|
|
|
|
Countable<Integer> c = new Countable<Integer>(id, 1);
|
|
|
|
map.put(id, c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Collections.sort(distribution);
|
2011-01-01 18:33:18 +00:00
|
|
|
// Collections.reverse(distribution);
|
2010-11-17 06:59:53 +00:00
|
|
|
|
|
|
|
return distribution;
|
|
|
|
}
|
2011-01-01 18:33:18 +00:00
|
|
|
|
2010-11-21 21:58:05 +00:00
|
|
|
/**
|
|
|
|
* Returns the highest solid 'terrain' block which can occur naturally.
|
2011-08-17 20:24:27 +00:00
|
|
|
*
|
2010-11-21 21:58:05 +00:00
|
|
|
* @param x
|
|
|
|
* @param z
|
2011-01-01 18:33:18 +00:00
|
|
|
* @param minY
|
|
|
|
* minimal height
|
|
|
|
* @param maxY
|
|
|
|
* maximal height
|
2011-08-17 20:24:27 +00:00
|
|
|
* @param naturalOnly look at natural blocks or all blocks
|
2010-11-21 21:58:05 +00:00
|
|
|
* @return height of highest block found or 'minY'
|
|
|
|
*/
|
2011-08-17 07:33:46 +00:00
|
|
|
public int getHighestTerrainBlock(int x, int z, int minY, int maxY, boolean naturalOnly) {
|
2011-07-15 07:00:48 +00:00
|
|
|
for (int y = maxY; y >= minY; --y) {
|
2010-11-21 21:58:05 +00:00
|
|
|
Vector pt = new Vector(x, y, z);
|
2011-01-31 07:42:18 +00:00
|
|
|
int id = getBlockType(pt);
|
2011-08-17 20:24:27 +00:00
|
|
|
if (naturalOnly ? BlockType.isNaturalBlock(id) : !BlockType.canPassThrough(id)) {
|
2010-11-21 21:58:05 +00:00
|
|
|
return y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return minY;
|
|
|
|
}
|
2011-01-01 18:33:18 +00:00
|
|
|
|
2010-12-31 22:31:49 +00:00
|
|
|
/**
|
|
|
|
* Gets the list of missing blocks and clears the list for the next
|
|
|
|
* operation.
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
public Set<Integer> popMissingBlocks() {
|
|
|
|
Set<Integer> missingBlocks = this.missingBlocks;
|
|
|
|
this.missingBlocks = new HashSet<Integer>();
|
|
|
|
return missingBlocks;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return the blockBag
|
|
|
|
*/
|
|
|
|
public BlockBag getBlockBag() {
|
|
|
|
return blockBag;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-01-01 18:33:18 +00:00
|
|
|
* @param blockBag
|
|
|
|
* the blockBag to set
|
2010-12-31 22:31:49 +00:00
|
|
|
*/
|
|
|
|
public void setBlockBag(BlockBag blockBag) {
|
|
|
|
this.blockBag = blockBag;
|
|
|
|
}
|
2011-08-07 00:40:48 +00:00
|
|
|
|
2011-01-30 22:54:42 +00:00
|
|
|
/**
|
|
|
|
* Get the world.
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
public LocalWorld getWorld() {
|
|
|
|
return world;
|
|
|
|
}
|
2011-08-07 00:40:48 +00:00
|
|
|
|
2011-02-01 07:51:55 +00:00
|
|
|
/**
|
|
|
|
* Get the number of blocks changed, including repeated block changes.
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
public int getBlockChangeCount() {
|
|
|
|
return original.size();
|
|
|
|
}
|
2011-06-04 19:16:10 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the mask.
|
|
|
|
*
|
|
|
|
* @return mask, may be null
|
|
|
|
*/
|
|
|
|
public Mask getMask() {
|
|
|
|
return mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set a mask.
|
|
|
|
*
|
|
|
|
* @param mask mask or null
|
|
|
|
*/
|
|
|
|
public void setMask(Mask mask) {
|
|
|
|
this.mask = mask;
|
|
|
|
}
|
2010-10-02 21:52:42 +00:00
|
|
|
}
|