2010-09-28 10:12:34 +02:00
|
|
|
// $Id$
|
|
|
|
/*
|
|
|
|
* WorldEdit
|
|
|
|
* 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/>.
|
|
|
|
*/
|
|
|
|
|
2010-09-30 08:41:05 +02:00
|
|
|
import java.util.HashMap;
|
2010-10-12 22:51:25 +02:00
|
|
|
import java.util.HashSet;
|
|
|
|
import java.util.Arrays;
|
2010-09-30 08:41:05 +02:00
|
|
|
import java.util.logging.Level;
|
|
|
|
import java.util.logging.Logger;
|
2010-10-02 10:21:48 +02:00
|
|
|
import java.io.*;
|
2010-10-02 22:46:33 +02:00
|
|
|
import com.sk89q.worldedit.*;
|
2010-09-28 10:12:34 +02:00
|
|
|
|
2010-09-30 08:41:05 +02:00
|
|
|
/**
|
2010-10-12 22:51:25 +02:00
|
|
|
* Plugin base.
|
2010-09-30 08:41:05 +02:00
|
|
|
*
|
|
|
|
* @author sk89q
|
|
|
|
*/
|
2010-10-12 22:51:25 +02:00
|
|
|
public class WorldEdit {
|
|
|
|
/**
|
|
|
|
* List of default allowed blocks.
|
|
|
|
*/
|
|
|
|
private final static Integer[] DEFAULT_ALLOWED_BLOCKS = {
|
|
|
|
0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
|
|
|
|
20, 35, 41, 42, 43, 44, 45, 47, 48, 49, 52, 53, 54, 56, 57, 58, 60,
|
|
|
|
61, 62, 67, 73, 78, 79, 80, 81, 82, 85
|
|
|
|
};
|
2010-10-03 01:28:02 +02:00
|
|
|
|
2010-10-12 22:51:25 +02:00
|
|
|
/**
|
|
|
|
* Logger.
|
|
|
|
*/
|
2010-10-05 22:07:39 +02:00
|
|
|
private static final Logger logger = Logger.getLogger("Minecraft");
|
2010-10-12 22:51:25 +02:00
|
|
|
/**
|
|
|
|
* Stores the WorldEdit sessions of players.
|
|
|
|
*/
|
2010-10-11 10:22:47 +02:00
|
|
|
private HashMap<WorldEditPlayer,WorldEditSession> sessions =
|
|
|
|
new HashMap<WorldEditPlayer,WorldEditSession>();
|
2010-10-12 22:51:25 +02:00
|
|
|
/**
|
|
|
|
* Stores the commands.
|
|
|
|
*/
|
2010-09-30 08:41:05 +02:00
|
|
|
private HashMap<String,String> commands = new HashMap<String,String>();
|
2010-09-28 10:12:34 +02:00
|
|
|
|
2010-10-12 22:51:25 +02:00
|
|
|
/**
|
|
|
|
* List of the blocks that can be used. If null, all blocks can be used.
|
|
|
|
*/
|
|
|
|
private HashSet<Integer> allowedBlocks;
|
|
|
|
/**
|
|
|
|
* Default block change limit. -1 for no limit.
|
|
|
|
*/
|
|
|
|
private int defaultChangeLimit = -1;
|
2010-10-03 01:28:02 +02:00
|
|
|
|
2010-10-03 21:16:09 +02:00
|
|
|
/**
|
|
|
|
* Construct an instance of the plugin.
|
|
|
|
*/
|
2010-09-30 08:41:05 +02:00
|
|
|
public WorldEdit() {
|
2010-09-28 10:12:34 +02:00
|
|
|
commands.put("/editpos1", "Set editing position #1");
|
|
|
|
commands.put("/editpos2", "Set editing position #2");
|
2010-10-06 06:16:55 +02:00
|
|
|
commands.put("/editwand", "Gives you the \"edit wand\"");
|
2010-10-13 07:10:17 +02:00
|
|
|
commands.put("/toggleeditwand", "Toggles edit wand selection");
|
2010-10-02 23:52:42 +02:00
|
|
|
commands.put("/editundo", "Undo");
|
|
|
|
commands.put("/editredo", "Redo");
|
2010-10-03 01:13:52 +02:00
|
|
|
commands.put("/clearhistory", "Clear history");
|
2010-10-03 21:37:32 +02:00
|
|
|
commands.put("/clearclipboard", "Clear clipboard");
|
2010-09-28 10:12:34 +02:00
|
|
|
commands.put("/editsize", "Get size of selected region");
|
2010-10-05 08:08:08 +02:00
|
|
|
commands.put("/editset", "[ID] - Set all blocks inside region");
|
|
|
|
commands.put("/editoutline", "[ID] - Outline the region with blocks");
|
2010-10-13 06:43:01 +02:00
|
|
|
commands.put("/editreplace", "<FromID> [ToID] - Replace all existing blocks inside region");
|
2010-10-05 08:08:08 +02:00
|
|
|
commands.put("/editoverlay", "[ID] - Overlay the area one layer");
|
2010-10-06 02:02:33 +02:00
|
|
|
commands.put("/removeabove", "<Size> <Height> - Remove blocks above head");
|
|
|
|
commands.put("/removebelow", "<Size> <Height> - Remove blocks below position");
|
2010-10-03 01:11:44 +02:00
|
|
|
commands.put("/editcopy", "Copies the currently selected region");
|
|
|
|
commands.put("/editpaste", "Pastes the clipboard");
|
|
|
|
commands.put("/editpasteair", "Pastes the clipboard (with air)");
|
2010-10-13 06:43:01 +02:00
|
|
|
commands.put("/editstack", "<Count> <Dir> - Stacks the selection");
|
|
|
|
commands.put("/editstackair", "<Count> <Dir> - Stacks the selection (with air)");
|
2010-10-03 19:44:52 +02:00
|
|
|
commands.put("/editload", "[Filename] - Load .schematic into clipboard");
|
|
|
|
commands.put("/editsave", "[Filename] - Save clipboard to .schematic");
|
2010-10-05 08:08:08 +02:00
|
|
|
commands.put("/editfill", "[ID] [Radius] <Depth> - Fill a hole");
|
2010-10-11 20:17:32 +02:00
|
|
|
commands.put("/editdrain", "[Radius] - Drain nearby water/lava pools");
|
2010-10-05 08:08:08 +02:00
|
|
|
commands.put("/editlimit", "[Num] - See documentation");
|
2010-10-13 06:41:06 +02:00
|
|
|
commands.put("/editexpand", "<Dir> [Num] - Expands the selection");
|
|
|
|
commands.put("/editcontract", "<Dir> [Num] - Contracts the selection");
|
2010-10-13 19:08:53 +02:00
|
|
|
commands.put("/editrotate", "[Angle] - Rotate the clipboard");
|
2010-10-13 07:38:05 +02:00
|
|
|
commands.put("/forestgen", "<Size> - Make an ugly pine tree forest");
|
2010-10-11 10:22:47 +02:00
|
|
|
commands.put("/unstuck", "Go up to the first free spot");
|
2010-10-13 07:06:46 +02:00
|
|
|
commands.put("/ascend", "Go up one level");
|
|
|
|
commands.put("/descend", "Go dowm one level");
|
2010-09-28 10:12:34 +02:00
|
|
|
}
|
|
|
|
|
2010-09-30 08:41:05 +02:00
|
|
|
/**
|
|
|
|
* Gets the WorldEdit session for a player.
|
|
|
|
*
|
|
|
|
* @param player
|
|
|
|
* @return
|
|
|
|
*/
|
2010-10-12 22:51:25 +02:00
|
|
|
public WorldEditSession getSession(WorldEditPlayer player) {
|
2010-10-11 10:22:47 +02:00
|
|
|
if (sessions.containsKey(player)) {
|
|
|
|
return sessions.get(player);
|
2010-09-30 08:41:05 +02:00
|
|
|
} else {
|
|
|
|
WorldEditSession session = new WorldEditSession();
|
2010-10-12 22:51:25 +02:00
|
|
|
session.setBlockChangeLimit(getDefaultChangeLimit());
|
2010-10-11 10:22:47 +02:00
|
|
|
sessions.put(player, session);
|
2010-09-30 08:41:05 +02:00
|
|
|
return session;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get an item ID from an item name or an item ID number.
|
|
|
|
*
|
|
|
|
* @param id
|
|
|
|
* @return
|
|
|
|
* @throws UnknownItemException
|
2010-10-02 10:36:33 +02:00
|
|
|
* @throws DisallowedItemException
|
2010-09-30 08:41:05 +02:00
|
|
|
*/
|
2010-10-12 22:51:25 +02:00
|
|
|
public int getItem(String id, boolean allAllowed)
|
2010-10-03 01:44:20 +02:00
|
|
|
throws UnknownItemException, DisallowedItemException {
|
2010-10-02 10:36:33 +02:00
|
|
|
int foundID;
|
|
|
|
|
2010-09-30 08:41:05 +02:00
|
|
|
try {
|
2010-10-02 10:36:33 +02:00
|
|
|
foundID = Integer.parseInt(id);
|
2010-09-30 08:41:05 +02:00
|
|
|
} catch (NumberFormatException e) {
|
|
|
|
try {
|
2010-10-05 07:44:55 +02:00
|
|
|
foundID = etc.getDataSource().getItem(id);
|
2010-09-30 08:41:05 +02:00
|
|
|
} catch (NumberFormatException e2) {
|
|
|
|
throw new UnknownItemException();
|
|
|
|
}
|
|
|
|
}
|
2010-10-02 10:36:33 +02:00
|
|
|
|
2010-10-12 22:51:25 +02:00
|
|
|
// Check if the item is allowed
|
|
|
|
if (allAllowed || allowedBlocks.isEmpty() || allowedBlocks.contains(foundID)) {
|
2010-10-02 10:36:33 +02:00
|
|
|
return foundID;
|
|
|
|
}
|
2010-10-03 01:28:02 +02:00
|
|
|
|
|
|
|
throw new DisallowedItemException();
|
2010-09-28 10:12:34 +02:00
|
|
|
}
|
|
|
|
|
2010-10-03 01:44:20 +02:00
|
|
|
/**
|
|
|
|
* Get an item ID from an item name or an item ID number.
|
|
|
|
*
|
|
|
|
* @param id
|
|
|
|
* @return
|
|
|
|
* @throws UnknownItemException
|
|
|
|
* @throws DisallowedItemException
|
|
|
|
*/
|
2010-10-12 22:51:25 +02:00
|
|
|
public int getItem(String id) throws UnknownItemException,
|
2010-10-03 01:44:20 +02:00
|
|
|
DisallowedItemException {
|
|
|
|
return getItem(id, false);
|
|
|
|
}
|
|
|
|
|
2010-10-03 21:16:09 +02:00
|
|
|
/**
|
2010-10-05 08:08:08 +02:00
|
|
|
* Checks to make sure that there are enough but not too many arguments.
|
2010-10-03 21:16:09 +02:00
|
|
|
*
|
|
|
|
* @param args
|
|
|
|
* @param min
|
2010-10-05 08:08:08 +02:00
|
|
|
* @param max -1 for no maximum
|
|
|
|
* @param cmd command name
|
2010-10-03 21:16:09 +02:00
|
|
|
* @throws InsufficientArgumentsException
|
|
|
|
*/
|
2010-10-05 08:08:08 +02:00
|
|
|
private void checkArgs(String[] args, int min, int max, String cmd)
|
|
|
|
throws InsufficientArgumentsException {
|
|
|
|
if (args.length <= min || (max != -1 && args.length - 1 > max)) {
|
|
|
|
if (commands.containsKey(cmd)) {
|
|
|
|
throw new InsufficientArgumentsException(cmd + " usage: " +
|
|
|
|
commands.get(cmd));
|
|
|
|
} else {
|
|
|
|
throw new InsufficientArgumentsException("Invalid number of arguments");
|
|
|
|
}
|
2010-10-03 21:16:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-30 08:41:05 +02:00
|
|
|
/**
|
2010-10-03 21:16:09 +02:00
|
|
|
* The main meat of command processing.
|
2010-09-30 08:41:05 +02:00
|
|
|
*
|
2010-10-03 21:16:09 +02:00
|
|
|
* @param player
|
2010-10-11 10:22:47 +02:00
|
|
|
* @param editPlayer
|
2010-10-05 01:39:35 +02:00
|
|
|
* @param session
|
|
|
|
* @param editSession
|
2010-10-03 21:16:09 +02:00
|
|
|
* @param split
|
|
|
|
* @return
|
|
|
|
* @throws UnknownItemException
|
|
|
|
* @throws IncompleteRegionException
|
2010-09-30 08:41:05 +02:00
|
|
|
* @throws InsufficientArgumentsException
|
2010-10-03 21:16:09 +02:00
|
|
|
* @throws DisallowedItemException
|
2010-09-30 08:41:05 +02:00
|
|
|
*/
|
2010-10-12 22:51:25 +02:00
|
|
|
public boolean performCommand(WorldEditPlayer player,
|
2010-10-11 10:22:47 +02:00
|
|
|
WorldEditSession session, EditSession editSession, String[] split)
|
2010-10-05 01:39:35 +02:00
|
|
|
throws WorldEditException
|
2010-09-30 08:41:05 +02:00
|
|
|
{
|
2010-10-09 05:53:03 +02:00
|
|
|
// Jump to the first free position
|
2010-10-11 10:22:47 +02:00
|
|
|
if (split[0].equalsIgnoreCase("/unstuck")) {
|
|
|
|
checkArgs(split, 0, 0, split[0]);
|
|
|
|
player.print("There you go!");
|
|
|
|
player.findFreePosition();
|
2010-10-09 05:53:03 +02:00
|
|
|
return true;
|
|
|
|
|
2010-10-13 07:06:46 +02:00
|
|
|
// Ascend a level
|
|
|
|
} else if(split[0].equalsIgnoreCase("/ascend")) {
|
|
|
|
checkArgs(split, 0, 0, split[0]);
|
|
|
|
if (player.ascendLevel()) {
|
|
|
|
player.print("Ascended a level.");
|
|
|
|
} else {
|
|
|
|
player.printError("No free spot above you found.");
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Descend a level
|
|
|
|
} else if(split[0].equalsIgnoreCase("/descend")) {
|
|
|
|
checkArgs(split, 0, 0, split[0]);
|
|
|
|
if (player.descendLevel()) {
|
|
|
|
player.print("Descended a level.");
|
|
|
|
} else {
|
|
|
|
player.printError("No free spot below you found.");
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
|
2010-09-28 10:12:34 +02:00
|
|
|
// Set edit position #1
|
2010-10-09 05:53:03 +02:00
|
|
|
} else if (split[0].equalsIgnoreCase("/editpos1")) {
|
2010-10-11 10:22:47 +02:00
|
|
|
checkArgs(split, 0, 0, split[0]);
|
|
|
|
session.setPos1(player.getBlockIn());
|
|
|
|
player.print("First edit position set.");
|
2010-09-28 10:12:34 +02:00
|
|
|
return true;
|
|
|
|
|
|
|
|
// Set edit position #2
|
|
|
|
} else if (split[0].equalsIgnoreCase("/editpos2")) {
|
2010-10-11 10:22:47 +02:00
|
|
|
checkArgs(split, 0, 0, split[0]);
|
|
|
|
session.setPos2(player.getBlockIn());
|
|
|
|
player.print("Second edit position set.");
|
2010-09-28 10:12:34 +02:00
|
|
|
return true;
|
2010-09-30 08:41:05 +02:00
|
|
|
|
2010-10-06 06:16:55 +02:00
|
|
|
// Edit wand
|
|
|
|
} else if (split[0].equalsIgnoreCase("/editwand")) {
|
2010-10-11 10:22:47 +02:00
|
|
|
checkArgs(split, 0, 0, split[0]);
|
2010-10-06 06:16:55 +02:00
|
|
|
player.giveItem(271, 1);
|
2010-10-11 10:22:47 +02:00
|
|
|
player.print("Right click = sel. pos 1; double right click = sel. pos 2");
|
2010-10-06 06:16:55 +02:00
|
|
|
return true;
|
|
|
|
|
2010-10-13 07:10:17 +02:00
|
|
|
// Toggle edit wand
|
|
|
|
} else if (split[0].equalsIgnoreCase("/toggleeditwand")) {
|
|
|
|
checkArgs(split, 0, 0, split[0]);
|
|
|
|
session.setToolControl(!session.isToolControlEnabled());
|
|
|
|
if (session.isToolControlEnabled()) {
|
|
|
|
player.print("Edit wand enabled.");
|
|
|
|
} else {
|
|
|
|
player.print("Edit wand disabled.");
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
|
2010-10-05 08:08:08 +02:00
|
|
|
// Set max number of blocks to change at a time
|
|
|
|
} else if (split[0].equalsIgnoreCase("/editlimit")) {
|
2010-10-11 10:22:47 +02:00
|
|
|
checkArgs(split, 1, 1, split[0]);
|
2010-10-05 01:39:35 +02:00
|
|
|
int limit = Math.max(-1, Integer.parseInt(split[1]));
|
|
|
|
session.setBlockChangeLimit(limit);
|
2010-10-11 10:22:47 +02:00
|
|
|
player.print("Block change limit set to " + limit + ".");
|
2010-10-05 01:39:35 +02:00
|
|
|
return true;
|
|
|
|
|
2010-10-02 23:52:42 +02:00
|
|
|
// Undo
|
|
|
|
} else if (split[0].equalsIgnoreCase("/editundo")) {
|
2010-10-11 10:22:47 +02:00
|
|
|
checkArgs(split, 0, 0, split[0]);
|
2010-10-02 23:52:42 +02:00
|
|
|
if (session.undo()) {
|
2010-10-11 10:22:47 +02:00
|
|
|
player.print("Undo successful.");
|
2010-10-02 23:52:42 +02:00
|
|
|
} else {
|
2010-10-11 10:22:47 +02:00
|
|
|
player.printError("Nothing to undo.");
|
2010-10-02 23:52:42 +02:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Redo
|
|
|
|
} else if (split[0].equalsIgnoreCase("/editredo")) {
|
2010-10-11 10:22:47 +02:00
|
|
|
checkArgs(split, 0, 0, split[0]);
|
2010-10-02 23:52:42 +02:00
|
|
|
if (session.redo()) {
|
2010-10-11 10:22:47 +02:00
|
|
|
player.print("Redo successful.");
|
2010-10-02 23:52:42 +02:00
|
|
|
} else {
|
2010-10-11 10:22:47 +02:00
|
|
|
player.printError("Nothing to redo.");
|
2010-10-02 23:52:42 +02:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
|
2010-10-03 01:13:52 +02:00
|
|
|
// Clear undo history
|
|
|
|
} else if (split[0].equalsIgnoreCase("/clearhistory")) {
|
2010-10-11 10:22:47 +02:00
|
|
|
checkArgs(split, 0, 0, split[0]);
|
2010-10-03 01:13:52 +02:00
|
|
|
session.clearHistory();
|
2010-10-11 10:22:47 +02:00
|
|
|
player.print("History cleared.");
|
2010-10-03 01:13:52 +02:00
|
|
|
return true;
|
|
|
|
|
|
|
|
// Clear clipboard
|
|
|
|
} else if (split[0].equalsIgnoreCase("/clearclipboard")) {
|
2010-10-11 10:22:47 +02:00
|
|
|
checkArgs(split, 0, 0, split[0]);
|
2010-10-03 01:13:52 +02:00
|
|
|
session.setClipboard(null);
|
2010-10-11 10:22:47 +02:00
|
|
|
player.print("Clipboard cleared.");
|
2010-10-03 01:13:52 +02:00
|
|
|
return true;
|
|
|
|
|
2010-10-03 01:11:44 +02:00
|
|
|
// Paste
|
|
|
|
} else if (split[0].equalsIgnoreCase("/editpasteair") ||
|
|
|
|
split[0].equalsIgnoreCase("/editpaste")) {
|
2010-10-13 19:08:53 +02:00
|
|
|
Vector pos = player.getBlockIn();
|
|
|
|
session.getClipboard().paste(editSession, pos,
|
|
|
|
split[0].equalsIgnoreCase("/editpaste"));
|
|
|
|
player.findFreePosition();
|
|
|
|
player.print("Pasted. Undo with /editundo");
|
2010-10-03 01:11:44 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
|
2010-09-30 08:41:05 +02:00
|
|
|
// Fill a hole
|
|
|
|
} else if (split[0].equalsIgnoreCase("/editfill")) {
|
2010-10-11 10:22:47 +02:00
|
|
|
checkArgs(split, 2, 3, split[0]);
|
2010-09-30 08:41:05 +02:00
|
|
|
int blockType = getItem(split[1]);
|
2010-10-05 08:08:08 +02:00
|
|
|
int radius = Math.max(1, Integer.parseInt(split[2]));
|
2010-10-03 01:15:10 +02:00
|
|
|
int depth = split.length > 3 ? Math.max(1, Integer.parseInt(split[3])) : 1;
|
2010-09-30 08:41:05 +02:00
|
|
|
|
2010-10-13 03:03:56 +02:00
|
|
|
Vector pos = player.getBlockIn();
|
2010-10-11 10:22:47 +02:00
|
|
|
int affected = editSession.fillXZ((int)pos.getX(), (int)pos.getZ(),
|
|
|
|
pos, blockType, radius, depth);
|
|
|
|
player.print(affected + " block(s) have been created.");
|
2010-09-30 08:41:05 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Remove blocks above current position
|
|
|
|
} else if (split[0].equalsIgnoreCase("/removeabove")) {
|
2010-10-11 10:22:47 +02:00
|
|
|
int size = split.length > 1 ? Math.max(1, Integer.parseInt(split[1])) : 1;
|
|
|
|
int height = split.length > 2 ? Math.min(128, Integer.parseInt(split[2]) + 2) : 128;
|
2010-10-06 02:02:33 +02:00
|
|
|
|
2010-10-11 10:22:47 +02:00
|
|
|
int affected = editSession.removeAbove(player.getBlockIn(), size, height);
|
|
|
|
player.print(affected + " block(s) have been removed.");
|
2010-10-06 02:02:33 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Remove blocks below current position
|
|
|
|
} else if (split[0].equalsIgnoreCase("/removebelow")) {
|
2010-10-11 10:22:47 +02:00
|
|
|
int size = split.length > 1 ? Math.max(1, Integer.parseInt(split[1])) : 1;
|
|
|
|
int height = split.length > 2 ? Math.max(1, Integer.parseInt(split[2])) : 128;
|
2010-09-30 08:41:05 +02:00
|
|
|
|
2010-10-11 10:22:47 +02:00
|
|
|
int affected = editSession.removeBelow(player.getBlockIn(), size, height);
|
|
|
|
player.print(affected + " block(s) have been removed.");
|
2010-10-05 22:07:39 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
|
2010-10-03 19:44:52 +02:00
|
|
|
// Load .schematic to clipboard
|
|
|
|
} else if (split[0].equalsIgnoreCase("/editload")) {
|
2010-10-11 10:22:47 +02:00
|
|
|
checkArgs(split, 1, 1, split[0]);
|
2010-10-03 19:44:52 +02:00
|
|
|
String filename = split[1].replace("\0", "") + ".schematic";
|
|
|
|
File dir = new File("schematics");
|
|
|
|
File f = new File("schematics", filename);
|
|
|
|
|
|
|
|
try {
|
|
|
|
String filePath = f.getCanonicalPath();
|
|
|
|
String dirPath = dir.getCanonicalPath();
|
|
|
|
|
|
|
|
if (!filePath.substring(0, dirPath.length()).equals(dirPath)) {
|
2010-10-11 10:22:47 +02:00
|
|
|
player.printError("Schematic could not read or it does not exist.");
|
2010-10-03 19:44:52 +02:00
|
|
|
} else {
|
2010-10-13 19:08:53 +02:00
|
|
|
session.setClipboard(CuboidClipboard.loadSchematic(filePath));
|
2010-10-03 19:44:52 +02:00
|
|
|
logger.log(Level.INFO, player.getName() + " loaded " + filePath);
|
2010-10-11 10:22:47 +02:00
|
|
|
player.print(filename + " loaded.");
|
2010-10-03 19:44:52 +02:00
|
|
|
}
|
2010-10-11 10:22:47 +02:00
|
|
|
/*} catch (SchematicException e) {
|
|
|
|
player.printError("Load error: " + e.getMessage());*/
|
2010-10-03 19:44:52 +02:00
|
|
|
} catch (IOException e) {
|
2010-10-11 10:22:47 +02:00
|
|
|
player.printError("Schematic could not read or it does not exist.");
|
2010-10-03 19:44:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Save clipboard to .schematic
|
2010-10-13 19:08:53 +02:00
|
|
|
} else if (split[0].equalsIgnoreCase("/editsave")) {
|
2010-10-11 10:22:47 +02:00
|
|
|
checkArgs(split, 1, 1, split[0]);
|
2010-10-03 19:44:52 +02:00
|
|
|
String filename = split[1].replace("\0", "") + ".schematic";
|
|
|
|
File dir = new File("schematics");
|
|
|
|
File f = new File("schematics", filename);
|
|
|
|
|
|
|
|
if (!dir.exists()) {
|
|
|
|
if (!dir.mkdir()) {
|
2010-10-11 10:22:47 +02:00
|
|
|
player.printError("A schematics/ folder could not be created.");
|
2010-10-03 19:44:52 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
String filePath = f.getCanonicalPath();
|
|
|
|
String dirPath = dir.getCanonicalPath();
|
|
|
|
|
|
|
|
if (!filePath.substring(0, dirPath.length()).equals(dirPath)) {
|
2010-10-11 10:22:47 +02:00
|
|
|
player.printError("Invalid path for Schematic.");
|
2010-10-03 19:44:52 +02:00
|
|
|
} else {
|
2010-10-05 02:04:28 +02:00
|
|
|
// Create parent directories
|
|
|
|
File parent = f.getParentFile();
|
|
|
|
if (parent != null && !parent.exists()) {
|
|
|
|
parent.mkdirs();
|
|
|
|
}
|
|
|
|
|
2010-10-03 19:44:52 +02:00
|
|
|
session.getClipboard().saveSchematic(filePath);
|
|
|
|
logger.log(Level.INFO, player.getName() + " saved " + filePath);
|
2010-10-11 10:22:47 +02:00
|
|
|
player.print(filename + " saved.");
|
2010-10-03 19:44:52 +02:00
|
|
|
}
|
2010-10-05 02:00:54 +02:00
|
|
|
} catch (SchematicException se) {
|
2010-10-11 10:22:47 +02:00
|
|
|
player.printError("Save error: " + se.getMessage());
|
2010-10-03 19:44:52 +02:00
|
|
|
} catch (IOException e) {
|
2010-10-11 10:22:47 +02:00
|
|
|
player.printError("Schematic could not written.");
|
2010-10-03 19:44:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
2010-10-11 22:27:37 +02:00
|
|
|
// Get size
|
2010-10-11 10:22:47 +02:00
|
|
|
} else if (split[0].equalsIgnoreCase("/editsize")) {
|
|
|
|
player.print("# of blocks: " + session.getRegion().getSize());
|
2010-09-28 10:12:34 +02:00
|
|
|
return true;
|
|
|
|
|
|
|
|
// Replace all blocks in the region
|
|
|
|
} else if(split[0].equalsIgnoreCase("/editset")) {
|
2010-10-11 10:22:47 +02:00
|
|
|
checkArgs(split, 1, 1, split[0]);
|
2010-09-30 08:41:05 +02:00
|
|
|
int blockType = getItem(split[1]);
|
2010-10-11 10:22:47 +02:00
|
|
|
int affected = editSession.setBlocks(session.getRegion(), blockType);
|
|
|
|
player.print(affected + " block(s) have been changed.");
|
2010-09-28 10:12:34 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
|
2010-10-04 02:04:06 +02:00
|
|
|
// Set the outline of a region
|
|
|
|
} else if(split[0].equalsIgnoreCase("/editoutline")) {
|
2010-10-11 10:22:47 +02:00
|
|
|
checkArgs(split, 1, 1, split[0]);
|
2010-10-04 02:04:06 +02:00
|
|
|
int blockType = getItem(split[1]);
|
2010-10-11 10:22:47 +02:00
|
|
|
int affected = editSession.makeCuboidFaces(session.getRegion(), blockType);
|
|
|
|
player.print(affected + " block(s) have been changed.");
|
2010-10-04 02:04:06 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
|
2010-10-11 20:17:32 +02:00
|
|
|
// Drain pools
|
|
|
|
} else if(split[0].equalsIgnoreCase("/editdrain")) {
|
|
|
|
checkArgs(split, 1, 1, split[0]);
|
|
|
|
int radius = Math.max(0, Integer.parseInt(split[1]));
|
|
|
|
int affected = editSession.drainArea(player.getBlockIn(), radius);
|
|
|
|
player.print(affected + " block(s) have been changed.");
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
2010-09-28 10:12:34 +02:00
|
|
|
// Replace all blocks in the region
|
|
|
|
} else if(split[0].equalsIgnoreCase("/editreplace")) {
|
2010-10-11 10:22:47 +02:00
|
|
|
checkArgs(split, 1, 2, split[0]);
|
|
|
|
int from, to;
|
|
|
|
if (split.length == 2) {
|
|
|
|
from = -1;
|
|
|
|
to = getItem(split[1]);
|
|
|
|
} else {
|
|
|
|
from = getItem(split[1]);
|
|
|
|
to = getItem(split[2]);
|
2010-09-28 10:12:34 +02:00
|
|
|
}
|
2010-10-11 10:22:47 +02:00
|
|
|
|
|
|
|
int affected = editSession.replaceBlocks(session.getRegion(), from, to);
|
|
|
|
player.print(affected + " block(s) have been replaced.");
|
2010-09-28 10:12:34 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Lay blocks over an area
|
|
|
|
} else if (split[0].equalsIgnoreCase("/editoverlay")) {
|
2010-10-11 10:22:47 +02:00
|
|
|
checkArgs(split, 1, 1, split[0]);
|
2010-09-30 08:41:05 +02:00
|
|
|
int blockType = getItem(split[1]);
|
2010-09-28 10:12:34 +02:00
|
|
|
|
2010-10-11 10:22:47 +02:00
|
|
|
Region region = session.getRegion();
|
|
|
|
int affected = editSession.overlayCuboidBlocks(region, blockType);
|
|
|
|
player.print(affected + " block(s) have been overlayed.");
|
2010-09-28 10:12:34 +02:00
|
|
|
|
2010-10-03 01:11:44 +02:00
|
|
|
return true;
|
|
|
|
|
|
|
|
// Copy
|
|
|
|
} else if (split[0].equalsIgnoreCase("/editcopy")) {
|
2010-10-11 10:22:47 +02:00
|
|
|
checkArgs(split, 0, 0, split[0]);
|
|
|
|
Region region = session.getRegion();
|
2010-10-13 03:03:56 +02:00
|
|
|
Vector min = region.getMinimumPoint();
|
|
|
|
Vector max = region.getMaximumPoint();
|
|
|
|
Vector pos = player.getBlockIn();
|
2010-10-03 01:11:44 +02:00
|
|
|
|
2010-10-13 19:08:53 +02:00
|
|
|
CuboidClipboard clipboard = new CuboidClipboard(
|
|
|
|
max.subtract(min).add(new Vector(1, 1, 1)),
|
|
|
|
min, min.subtract(pos));
|
2010-10-03 01:11:44 +02:00
|
|
|
clipboard.copy(editSession);
|
|
|
|
session.setClipboard(clipboard);
|
2010-10-11 10:22:47 +02:00
|
|
|
|
|
|
|
player.print("Block(s) copied.");
|
2010-10-03 01:11:44 +02:00
|
|
|
|
2010-10-05 22:46:31 +02:00
|
|
|
return true;
|
|
|
|
|
2010-10-13 07:38:05 +02:00
|
|
|
// Make pine tree forest
|
|
|
|
} else if (split[0].equalsIgnoreCase("/forestgen")) {
|
|
|
|
checkArgs(split, 0, 1, split[0]);
|
|
|
|
int size = split.length > 1 ? Math.max(1, Integer.parseInt(split[1])) : 10;
|
|
|
|
|
|
|
|
int affected = editSession.makePineTreeForest(player.getPosition(), size);
|
|
|
|
player.print(affected + " pine trees created.");
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
2010-10-05 22:46:31 +02:00
|
|
|
// Stack
|
|
|
|
} else if (split[0].equalsIgnoreCase("/editstackair") ||
|
|
|
|
split[0].equalsIgnoreCase("/editstack")) {
|
2010-10-06 06:08:52 +02:00
|
|
|
checkArgs(split, 0, 2, split[0]);
|
2010-10-11 10:22:47 +02:00
|
|
|
int count = split.length > 1 ? Math.max(1, Integer.parseInt(split[1])) : 1;
|
2010-10-13 06:41:06 +02:00
|
|
|
Vector dir = getDirection(player,
|
|
|
|
split.length > 2 ? split[2].toLowerCase() : "me");
|
2010-10-05 22:46:31 +02:00
|
|
|
boolean copyAir = split[0].equalsIgnoreCase("/editstackair");
|
|
|
|
|
2010-10-13 06:41:06 +02:00
|
|
|
int affected = editSession.stackCuboidRegion(session.getRegion(),
|
|
|
|
dir, count, copyAir);
|
|
|
|
player.print(affected + " blocks changed. Undo with /editundo");
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Expand
|
|
|
|
} else if (split[0].equalsIgnoreCase("/editexpand")) {
|
|
|
|
checkArgs(split, 1, 2, split[0]);
|
|
|
|
Vector dir;
|
|
|
|
int change;
|
|
|
|
if (split.length == 3) {
|
|
|
|
dir = getDirection(player, split[1].toLowerCase());
|
|
|
|
change = Integer.parseInt(split[2]);
|
|
|
|
} else {
|
|
|
|
dir = getDirection(player, "me");
|
|
|
|
change = Integer.parseInt(split[1]);
|
2010-10-05 22:46:31 +02:00
|
|
|
}
|
|
|
|
|
2010-10-13 06:41:06 +02:00
|
|
|
Region region = session.getRegion();
|
|
|
|
int oldSize = region.getSize();
|
|
|
|
region.expand(dir.multiply(change));
|
|
|
|
session.learnRegionChanges();
|
|
|
|
int newSize = region.getSize();
|
|
|
|
player.print("Region expanded " + (newSize - oldSize) + " blocks.");
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
2010-10-13 19:08:53 +02:00
|
|
|
// Contract
|
2010-10-13 06:41:06 +02:00
|
|
|
} else if (split[0].equalsIgnoreCase("/editcontract")) {
|
|
|
|
checkArgs(split, 1, 2, split[0]);
|
|
|
|
Vector dir;
|
|
|
|
int change;
|
|
|
|
if (split.length == 3) {
|
|
|
|
dir = getDirection(player, split[1].toLowerCase());
|
|
|
|
change = Integer.parseInt(split[2]);
|
2010-10-05 22:46:31 +02:00
|
|
|
} else {
|
2010-10-13 06:41:06 +02:00
|
|
|
dir = getDirection(player, "me");
|
|
|
|
change = Integer.parseInt(split[1]);
|
2010-10-05 22:46:31 +02:00
|
|
|
}
|
|
|
|
|
2010-10-13 06:41:06 +02:00
|
|
|
Region region = session.getRegion();
|
|
|
|
int oldSize = region.getSize();
|
|
|
|
region.contract(dir.multiply(change));
|
|
|
|
session.learnRegionChanges();
|
|
|
|
int newSize = region.getSize();
|
|
|
|
player.print("Region contracted " + (oldSize - newSize) + " blocks.");
|
2010-10-05 22:46:31 +02:00
|
|
|
|
2010-10-13 19:08:53 +02:00
|
|
|
return true;
|
|
|
|
|
|
|
|
// Rotate
|
|
|
|
} else if (split[0].equalsIgnoreCase("/editrotate")) {
|
|
|
|
checkArgs(split, 1, 1, split[0]);
|
|
|
|
int angle = Integer.parseInt(split[1]);
|
|
|
|
if (angle % 90 == 0) {
|
|
|
|
CuboidClipboard clipboard = session.getClipboard();
|
|
|
|
clipboard.rotate2D(angle);
|
|
|
|
player.print("Clipboard rotated by " + angle + " degrees.");
|
|
|
|
} else {
|
|
|
|
player.printError("Angles must be divisible by 90 degrees.");
|
|
|
|
}
|
|
|
|
|
2010-09-28 10:12:34 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-10-13 06:41:06 +02:00
|
|
|
/**
|
|
|
|
* Get the direction vector for a player's direction. May return
|
|
|
|
* null if a direction could not be found.
|
|
|
|
*
|
|
|
|
* @param player
|
|
|
|
* @param dir
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
public Vector getDirection(WorldEditPlayer player, String dir)
|
|
|
|
throws UnknownDirectionException {
|
|
|
|
int xm = 0;
|
|
|
|
int ym = 0;
|
|
|
|
int zm = 0;
|
|
|
|
|
|
|
|
if (dir.equals("me")) {
|
|
|
|
dir = player.getCardinalDirection();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dir.charAt(0) == 'w') {
|
|
|
|
zm += 1;
|
|
|
|
} else if (dir.charAt(0) == 'e') {
|
|
|
|
zm -= 1;
|
|
|
|
} else if (dir.charAt(0) == 's') {
|
|
|
|
xm += 1;
|
|
|
|
} else if (dir.charAt(0) == 'n') {
|
|
|
|
xm -= 1;
|
|
|
|
} else if (dir.charAt(0) == 'u') {
|
|
|
|
ym += 1;
|
|
|
|
} else if (dir.charAt(0) == 'd') {
|
|
|
|
ym -= 1;
|
|
|
|
} else {
|
|
|
|
throw new UnknownDirectionException(dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
return new Vector(xm, ym, zm);
|
|
|
|
}
|
|
|
|
|
2010-10-05 10:43:23 +02:00
|
|
|
/**
|
2010-10-12 22:51:25 +02:00
|
|
|
* Remove a session.
|
|
|
|
*
|
|
|
|
* @param player
|
|
|
|
*/
|
|
|
|
public void removeSession(WorldEditPlayer player) {
|
|
|
|
sessions.remove(player);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove all sessions.
|
|
|
|
*/
|
|
|
|
public void clearSessions() {
|
|
|
|
sessions.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the list of commands.
|
2010-10-05 10:43:23 +02:00
|
|
|
*
|
2010-10-12 22:51:25 +02:00
|
|
|
* @return List
|
|
|
|
*/
|
|
|
|
public HashMap<String,String> getCommands() {
|
|
|
|
return commands;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the list of allowed blocks. Provided null to use the default list.
|
|
|
|
*
|
|
|
|
* @param allowedBlocks
|
|
|
|
*/
|
|
|
|
public void setAllowedBlocks(HashSet<Integer> allowedBlocks) {
|
|
|
|
this.allowedBlocks = allowedBlocks != null ? allowedBlocks
|
|
|
|
: new HashSet<Integer>(Arrays.asList(DEFAULT_ALLOWED_BLOCKS));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a comma-delimited list of the default allowed blocks.
|
|
|
|
*
|
|
|
|
* @return comma-delimited list
|
|
|
|
*/
|
|
|
|
public static String getDefaultAllowedBlocks() {
|
|
|
|
StringBuilder b = new StringBuilder();
|
|
|
|
for (Integer id : DEFAULT_ALLOWED_BLOCKS) {
|
|
|
|
b.append(id).append(",");
|
|
|
|
}
|
|
|
|
return b.substring(0, b.length() - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return the defaultChangeLimit
|
|
|
|
*/
|
|
|
|
public int getDefaultChangeLimit() {
|
|
|
|
return defaultChangeLimit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the default limit on the number of blocks that can be changed
|
|
|
|
* in one operation.
|
|
|
|
*
|
|
|
|
* @param defaultChangeLimit the defaultChangeLimit to set
|
2010-10-05 10:43:23 +02:00
|
|
|
*/
|
2010-10-12 22:51:25 +02:00
|
|
|
public void setDefaultChangeLimit(int defaultChangeLimit) {
|
|
|
|
this.defaultChangeLimit = defaultChangeLimit;
|
2010-10-05 10:43:23 +02:00
|
|
|
}
|
2010-09-28 10:12:34 +02:00
|
|
|
}
|