diff --git a/pom.xml b/pom.xml
index a80613d9e..eaa910c8b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -30,6 +30,10 @@
bukkit-releases
http://repo.bukkit.org/content/repositories/releases
+
+ spout-repo
+ http://repo.getspout.org
+
@@ -79,6 +83,13 @@
1.9.0-rc1
test
+
+
+
+ org.getspout
+ spoutapi
+ dev-SNAPSHOT
+
@@ -183,6 +194,7 @@
org.apache.maven.plugins
maven-surefire-plugin
+ 2.7.2
**/TestOfflinePermissible.java
diff --git a/src/main/java/com/sk89q/util/yaml/YAMLFormat.java b/src/main/java/com/sk89q/util/yaml/YAMLFormat.java
index aa1cc9016..a6181b5c3 100644
--- a/src/main/java/com/sk89q/util/yaml/YAMLFormat.java
+++ b/src/main/java/com/sk89q/util/yaml/YAMLFormat.java
@@ -1,6 +1,6 @@
// $Id$
/*
- * RegionBook
+ * WorldEdit
* Copyright (C) 2010, 2011 sk89q and contributors
*
* This program is free software: you can redistribute it and/or modify
diff --git a/src/main/java/com/sk89q/util/yaml/YAMLNode.java b/src/main/java/com/sk89q/util/yaml/YAMLNode.java
index 4c1a79370..4283fe682 100644
--- a/src/main/java/com/sk89q/util/yaml/YAMLNode.java
+++ b/src/main/java/com/sk89q/util/yaml/YAMLNode.java
@@ -1,6 +1,6 @@
// $Id$
/*
- * RegionBook
+ * WorldEdit
* Copyright (C) 2010, 2011 sk89q
*
* This program is free software: you can redistribute it and/or modify
@@ -24,7 +24,7 @@ import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -111,7 +111,7 @@ public class YAMLNode {
*/
private Object prepareSerialization(Object value) {
if (value instanceof Vector) {
- Map out = new HashMap();
+ Map out = new LinkedHashMap();
Vector vec = (Vector) value;
out.put("x", vec.getX());
out.put("y", vec.getY());
@@ -152,7 +152,7 @@ public class YAMLNode {
if (o == null || !(o instanceof Map)) {
// This will override existing configuration data!
- o = new HashMap();
+ o = new LinkedHashMap();
node.put(parts[i], o);
}
@@ -169,7 +169,7 @@ public class YAMLNode {
* @return
*/
public YAMLNode addNode(String path) {
- Map map = new HashMap();
+ Map map = new LinkedHashMap();
YAMLNode node = new YAMLNode(map, writeDefaults);
setProperty(path, map);
return node;
@@ -696,7 +696,7 @@ public class YAMLNode {
return null;
} else if (o instanceof Map) {
Map nodes =
- new HashMap();
+ new LinkedHashMap();
for (Map.Entry entry : ((Map) o).entrySet()) {
if (entry.getValue() instanceof Map) {
diff --git a/src/main/java/com/sk89q/util/yaml/YAMLProcessor.java b/src/main/java/com/sk89q/util/yaml/YAMLProcessor.java
index 7c742255a..eec16c575 100644
--- a/src/main/java/com/sk89q/util/yaml/YAMLProcessor.java
+++ b/src/main/java/com/sk89q/util/yaml/YAMLProcessor.java
@@ -1,6 +1,6 @@
// $Id$
/*
- * RegionBook
+ * WorldEdit
* Copyright (C) 2010, 2011 sk89q
*
* This program is free software: you can redistribute it and/or modify
@@ -27,6 +27,7 @@ import org.yaml.snakeyaml.representer.Representer;
import java.io.*;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.Map;
/**
@@ -98,7 +99,7 @@ public class YAMLProcessor extends YAMLNode {
if (stream == null) throw new IOException("Stream is null!");
read(yaml.load(new UnicodeReader(stream)));
} catch (YAMLProcessorException e) {
- root = new HashMap();
+ root = new LinkedHashMap();
} finally {
try {
if (stream != null) {
@@ -189,7 +190,7 @@ public class YAMLProcessor extends YAMLNode {
private void read(Object input) throws YAMLProcessorException {
try {
if (null == input) {
- root = new HashMap();
+ root = new LinkedHashMap();
} else {
root = (Map) input;
}
diff --git a/src/main/java/com/sk89q/util/yaml/YAMLProcessorException.java b/src/main/java/com/sk89q/util/yaml/YAMLProcessorException.java
index 642b826dc..ac0eb3611 100644
--- a/src/main/java/com/sk89q/util/yaml/YAMLProcessorException.java
+++ b/src/main/java/com/sk89q/util/yaml/YAMLProcessorException.java
@@ -1,6 +1,6 @@
// $Id$
/*
- * RegionBook
+ * WorldEdit
* Copyright (C) 2010, 2011 sk89q
*
* This program is free software: you can redistribute it and/or modify
diff --git a/src/main/java/com/sk89q/worldedit/spout/SessionTimer.java b/src/main/java/com/sk89q/worldedit/spout/SessionTimer.java
new file mode 100644
index 000000000..fdfa3cb2d
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/spout/SessionTimer.java
@@ -0,0 +1,51 @@
+// $Id$
+/*
+ * WorldEdit
+ * Copyright (C) 2010, 2011 sk89q
+ *
+ * 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 .
+*/
+
+package com.sk89q.worldedit.spout;
+
+import com.sk89q.worldedit.SessionCheck;
+import com.sk89q.worldedit.WorldEdit;
+import org.getspout.api.Game;
+import org.getspout.api.player.Player;
+
+/**
+ * Used to remove expired sessions in Bukkit.
+ *
+ * @author sk89q
+ */
+public class SessionTimer implements Runnable {
+
+ private WorldEdit worldEdit;
+ private SessionCheck checker;
+
+ public SessionTimer(WorldEdit worldEdit, final Game game) {
+ this.worldEdit = worldEdit;
+ this.checker = new SessionCheck() {
+ public boolean isOnlinePlayer(String name) {
+ Player player = game.getPlayer(name, true);
+ return player != null && player.isOnline();
+ }
+ };
+ }
+
+ public void run() {
+ worldEdit.flushExpiredSessions(checker);
+ }
+
+}
diff --git a/src/main/java/com/sk89q/worldedit/spout/SpoutCommandSender.java b/src/main/java/com/sk89q/worldedit/spout/SpoutCommandSender.java
new file mode 100644
index 000000000..02d4032ad
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/spout/SpoutCommandSender.java
@@ -0,0 +1,110 @@
+package com.sk89q.worldedit.spout;
+
+import com.sk89q.worldedit.LocalPlayer;
+import com.sk89q.worldedit.LocalWorld;
+import com.sk89q.worldedit.PlayerNeededException;
+import com.sk89q.worldedit.ServerInterface;
+import com.sk89q.worldedit.Vector;
+import com.sk89q.worldedit.WorldVector;
+import com.sk89q.worldedit.bags.BlockBag;
+import org.getspout.api.ChatColor;
+import org.getspout.api.Spout;
+import org.getspout.api.command.CommandSource;
+import org.getspout.api.player.Player;
+
+import java.util.logging.Level;
+
+public class SpoutCommandSender extends LocalPlayer {
+ private CommandSource sender;
+ private WorldEditPlugin plugin;
+
+ public SpoutCommandSender(WorldEditPlugin plugin, ServerInterface server, CommandSource sender) {
+ super(server);
+ this.plugin = plugin;
+ this.sender = sender;
+ }
+
+ @Override
+ public String getName() {
+ //return sender.getName();
+ return "Console";
+ }
+
+ @Override
+ public void printRaw(String msg) {
+ sender.sendRawMessage(msg);
+ }
+
+ @Override
+ public void printDebug(String msg) {
+ sender.sendMessage(ChatColor.GRAY + msg);
+
+ }
+
+ @Override
+ public void print(String msg) {
+ sender.sendMessage(ChatColor.PURPLE + msg);
+ }
+
+ @Override
+ public void printError(String msg) {
+ sender.sendMessage(ChatColor.RED + msg);
+ }
+
+ @Override
+ public String[] getGroups() {
+ return new String[0];
+ }
+
+ @Override
+ public boolean hasPermission(String perm) {
+ // TODO: Implement permissions
+ // return sender.isOp():
+ return true;
+ }
+
+ @Override
+ public boolean isPlayer() {
+ return sender instanceof Player;
+ }
+
+ @Override
+ public int getItemInHand() {
+ throw new PlayerNeededException();
+ }
+
+ @Override
+ public WorldVector getPosition() {
+ throw new PlayerNeededException();
+ }
+
+ @Override
+ public LocalWorld getWorld() {
+ throw new PlayerNeededException();
+ }
+
+ @Override
+ public double getPitch() {
+ throw new PlayerNeededException();
+ }
+
+ @Override
+ public double getYaw() {
+ throw new PlayerNeededException();
+ }
+
+ @Override
+ public void giveItem(int type, int amt) {
+ throw new PlayerNeededException();
+ }
+
+ @Override
+ public void setPosition(Vector pos, float pitch, float yaw) {
+ throw new PlayerNeededException();
+ }
+
+ @Override
+ public BlockBag getInventoryBlockBag() {
+ throw new PlayerNeededException();
+ }
+}
diff --git a/src/main/java/com/sk89q/worldedit/spout/SpoutPlayer.java b/src/main/java/com/sk89q/worldedit/spout/SpoutPlayer.java
new file mode 100644
index 000000000..062d0bfa0
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/spout/SpoutPlayer.java
@@ -0,0 +1,156 @@
+// $Id$
+/*
+ * WorldEdit
+ * Copyright (C) 2010 sk89q
+ *
+ * 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 .
+*/
+
+package com.sk89q.worldedit.spout;
+
+import com.sk89q.util.StringUtil;
+import com.sk89q.worldedit.LocalPlayer;
+import com.sk89q.worldedit.LocalWorld;
+import com.sk89q.worldedit.ServerInterface;
+import com.sk89q.worldedit.Vector;
+import com.sk89q.worldedit.WorldVector;
+import com.sk89q.worldedit.bags.BlockBag;
+import com.sk89q.worldedit.cui.CUIEvent;
+import org.getspout.api.geo.discrete.Point;
+import org.getspout.api.geo.discrete.Transform;
+import org.getspout.api.inventory.ItemStack;
+import org.getspout.api.math.MathHelper;
+import org.getspout.api.math.Quaternion;
+import org.getspout.api.math.Vector3;
+import org.getspout.api.player.Player;
+
+public class SpoutPlayer extends LocalPlayer {
+ private Player player;
+ private WorldEditPlugin plugin;
+
+ public SpoutPlayer(WorldEditPlugin plugin, ServerInterface server, Player player) {
+ super(server);
+ this.plugin = plugin;
+ this.player = player;
+ }
+
+ @Override
+ public int getItemInHand() {
+ ItemStack itemStack = null;//player.getItemInHand();
+ return itemStack != null ? itemStack.getMaterial().getRawId() : 0;
+ }
+
+ @Override
+ public String getName() {
+ return player.getName();
+ }
+
+ @Override
+ public WorldVector getPosition() {
+ Point loc = player.getEntity().getTransform().getPosition();
+ return new WorldVector(SpoutUtil.getLocalWorld(loc.getWorld()),
+ loc.getX(), loc.getY(), loc.getZ());
+ }
+
+ @Override
+ public double getPitch() {
+ return MathHelper.getDirectionVector(player.getEntity().getTransform().getRotation()).getY();
+ }
+
+ @Override
+ public double getYaw() {
+ return MathHelper.getDirectionVector(player.getEntity().getTransform().getRotation()).getZ();
+ }
+
+ @Override
+ public void giveItem(int type, int amt) {
+ //player.getInventory().addItem(new ItemStack(type, amt));
+ }
+
+ @Override
+ public void printRaw(String msg) {
+ for (String part : msg.split("\n")) {
+ player.sendMessage(part);
+ }
+ }
+
+ @Override
+ public void print(String msg) {
+ for (String part : msg.split("\n")) {
+ player.sendMessage("\u00A7d" + part);
+ }
+ }
+
+ @Override
+ public void printDebug(String msg) {
+ for (String part : msg.split("\n")) {
+ player.sendMessage("\u00A77" + part);
+ }
+ }
+
+ @Override
+ public void printError(String msg) {
+ for (String part : msg.split("\n")) {
+ player.sendMessage("\u00A7c" + part);
+ }
+ }
+
+ @Override
+ public void setPosition(Vector pos, float pitch, float yaw) {
+ Transform t = player.getEntity().getTransform();
+ t.setPosition(new Point(t.getPosition().getWorld(), (float) pos.getX(), (float) pos.getY(), (float) pos.getZ()));
+ t.setRotation(new Quaternion(pitch, Vector3.UNIT_Z).rotate(yaw, Vector3.UNIT_Y));
+ }
+
+ @Override
+ public String[] getGroups() {
+ return new String[0];
+ }
+
+ @Override
+ public BlockBag getInventoryBlockBag() {
+ return new SpoutPlayerBlockBag(player);
+ }
+
+ @Override
+ public boolean hasPermission(String perm) {
+ return true; // TODO: Implement permissions
+ }
+
+ @Override
+ public LocalWorld getWorld() {
+ return SpoutUtil.getLocalWorld(player.getEntity().getTransform().getPosition().getWorld());
+ }
+
+ @Override
+ public void dispatchCUIEvent(CUIEvent event) {
+ String[] params = event.getParameters();
+
+ if (params.length > 0) {
+ player.sendRawMessage("\u00A75\u00A76\u00A74\u00A75" + event.getTypeId()
+ + "|" + StringUtil.joinString(params, "|"));
+ } else {
+ player.sendRawMessage("\u00A75\u00A76\u00A74\u00A75" + event.getTypeId());
+ }
+ }
+
+ @Override
+ public void dispatchCUIHandshake() {
+ player.sendRawMessage("\u00A75\u00A76\u00A74\u00A75");
+ }
+
+ public Player getPlayer() {
+ return player;
+ }
+}
diff --git a/src/main/java/com/sk89q/worldedit/spout/SpoutPlayerBlockBag.java b/src/main/java/com/sk89q/worldedit/spout/SpoutPlayerBlockBag.java
new file mode 100644
index 000000000..8c9d5d97c
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/spout/SpoutPlayerBlockBag.java
@@ -0,0 +1,233 @@
+// $Id$
+/*
+ * WorldEdit
+ * Copyright (C) 2010 sk89q
+ *
+ * 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 .
+*/
+
+package com.sk89q.worldedit.spout;
+
+import com.sk89q.worldedit.Vector;
+import com.sk89q.worldedit.bags.BlockBag;
+import com.sk89q.worldedit.bags.BlockBagException;
+import com.sk89q.worldedit.bags.OutOfBlocksException;
+import com.sk89q.worldedit.bags.OutOfSpaceException;
+import com.sk89q.worldedit.blocks.BaseItem;
+import com.sk89q.worldedit.blocks.BaseItemStack;
+import com.sk89q.worldedit.blocks.BlockID;
+import com.sk89q.worldedit.blocks.ItemType;
+import org.getspout.api.inventory.ItemStack;
+import org.getspout.api.material.MaterialData;
+import org.getspout.api.player.Player;
+
+public class SpoutPlayerBlockBag extends BlockBag {
+ /**
+ * Player instance.
+ */
+ private Player player;
+ /**
+ * The player's inventory;
+ */
+ private ItemStack[] items;
+
+ /**
+ * Construct the object.
+ *
+ * @param player
+ */
+ public SpoutPlayerBlockBag(Player player) {
+ this.player = player;
+ }
+
+ /**
+ * Loads inventory on first use.
+ */
+ private void loadInventory() {
+ if (items == null) {
+ items = new ItemStack[0];
+ //items = player.getInventory().getContents();
+ }
+ }
+
+ /**
+ * Get the player.
+ *
+ * @return
+ */
+ public Player getPlayer() {
+ return player;
+ }
+
+ /**
+ * Get a block.
+ *
+ * @param item
+ */
+ @Override
+ public void fetchItem(BaseItem item) throws BlockBagException {
+ final int id = item.getType();
+ final int damage = item.getDamage();
+ int amount = (item instanceof BaseItemStack) ? ((BaseItemStack) item).getAmount() : 1;
+ assert(amount == 1);
+ boolean usesDamageValue = ItemType.usesDamageValue(id);
+
+ if (id == BlockID.AIR) {
+ throw new IllegalArgumentException("Can't fetch air block");
+ }
+
+ loadInventory();
+
+ boolean found = false;
+
+ for (int slot = 0; slot < items.length; ++slot) {
+ ItemStack bukkitItem = items[slot];
+
+ if (bukkitItem == null) {
+ continue;
+ }
+
+ if (bukkitItem.getMaterial().getRawId() != id) {
+ // Type id doesn't fit
+ continue;
+ }
+
+ if (usesDamageValue && bukkitItem.getDamage() != damage) {
+ // Damage value doesn't fit.
+ continue;
+ }
+
+ int currentAmount = bukkitItem.getAmount();
+ if (currentAmount < 0) {
+ // Unlimited
+ return;
+ }
+
+ if (currentAmount > 1) {
+ bukkitItem.setAmount(currentAmount - 1);
+ found = true;
+ } else {
+ items[slot] = null;
+ found = true;
+ }
+
+ break;
+ }
+
+ if (!found) {
+ throw new OutOfBlocksException();
+ }
+ }
+
+ /**
+ * Store a block.
+ *
+ * @param item
+ */
+ @Override
+ public void storeItem(BaseItem item) throws BlockBagException {
+ final int id = item.getType();
+ final int damage = item.getDamage();
+ int amount = (item instanceof BaseItemStack) ? ((BaseItemStack) item).getAmount() : 1;
+ assert(amount <= 64);
+ boolean usesDamageValue = ItemType.usesDamageValue(id);
+
+ if (id == BlockID.AIR) {
+ throw new IllegalArgumentException("Can't store air block");
+ }
+
+ loadInventory();
+
+ int freeSlot = -1;
+
+ for (int slot = 0; slot < items.length; ++slot) {
+ ItemStack bukkitItem = items[slot];
+
+ if (bukkitItem == null) {
+ // Delay using up a free slot until we know there are no stacks
+ // of this item to merge into
+
+ if (freeSlot == -1) {
+ freeSlot = slot;
+ }
+ continue;
+ }
+
+ if (bukkitItem.getMaterial().getRawId() != id) {
+ // Type id doesn't fit
+ continue;
+ }
+
+ if (usesDamageValue && bukkitItem.getDamage() != damage) {
+ // Damage value doesn't fit.
+ continue;
+ }
+
+ int currentAmount = bukkitItem.getAmount();
+ if (currentAmount < 0) {
+ // Unlimited
+ return;
+ }
+ if (currentAmount >= 64) {
+ // Full stack
+ continue;
+ }
+
+ int spaceLeft = 64 - currentAmount;
+ if (spaceLeft >= amount) {
+ bukkitItem.setAmount(currentAmount + amount);
+ return;
+ }
+
+ bukkitItem.setAmount(64);
+ amount -= spaceLeft;
+ }
+
+ if (freeSlot > -1) {
+ items[freeSlot] = new ItemStack(MaterialData.getMaterial((short)id), amount);
+ return;
+ }
+
+ throw new OutOfSpaceException(id);
+ }
+
+ /**
+ * Flush any changes. This is called at the end.
+ */
+ @Override
+ public void flushChanges() {
+ if (items != null) {
+ //player.getInventory().setContents(items);
+ items = null;
+ }
+ }
+
+ /**
+ * Adds a position to be used a source.
+ *
+ * @param pos
+ */
+ @Override
+ public void addSourcePosition(Vector pos) {
+ }
+
+ /**
+ * Adds a position to be used a source.
+ *
+ * @param pos
+ */
+ @Override
+ public void addSingleSourcePosition(Vector pos) {
+ }
+}
diff --git a/src/main/java/com/sk89q/worldedit/spout/SpoutRawCommandExecutor.java b/src/main/java/com/sk89q/worldedit/spout/SpoutRawCommandExecutor.java
new file mode 100644
index 000000000..c1d31cea2
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/spout/SpoutRawCommandExecutor.java
@@ -0,0 +1,46 @@
+/*
+ * WorldEdit
+ * Copyright (C) 2012 sk89q
+ *
+ * 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 .
+ */
+
+package com.sk89q.worldedit.spout;
+
+import org.bukkit.Bukkit;
+import org.getspout.api.command.CommandException;
+import org.getspout.api.command.CommandSource;
+import org.getspout.api.command.RawCommandExecutor;
+import org.getspout.api.util.MiscCompatibilityUtils;
+
+/**
+ * @author zml2008
+ */
+public class SpoutRawCommandExecutor implements RawCommandExecutor {
+
+ private final WorldEditPlugin plugin;
+
+ public SpoutRawCommandExecutor(WorldEditPlugin plugin) {
+ this.plugin = plugin;
+ }
+
+ @Override
+ public void execute(CommandSource source, String[] args, int baseIndex, boolean fuzzyLookup) throws CommandException {
+ Bukkit.getServer().getCommandAliases();
+ args[baseIndex] = "/" + args[baseIndex];
+ if (!plugin.getWorldEdit().handleCommand(plugin.wrapCommandSender(source), MiscCompatibilityUtils.arrayCopyOfRange(args, baseIndex, args.length))) {
+ throw new CommandException("Unknown command: '" + args[baseIndex] + "'!");
+ }
+ }
+}
diff --git a/src/main/java/com/sk89q/worldedit/spout/SpoutServerInterface.java b/src/main/java/com/sk89q/worldedit/spout/SpoutServerInterface.java
new file mode 100644
index 000000000..d41060442
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/spout/SpoutServerInterface.java
@@ -0,0 +1,87 @@
+// $Id$
+/*
+ * WorldEdit
+ * Copyright (C) 2010 sk89q
+ *
+ * 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 .
+*/
+
+package com.sk89q.worldedit.spout;
+
+import com.sk89q.minecraft.util.commands.Command;
+import com.sk89q.worldedit.LocalWorld;
+import com.sk89q.worldedit.ServerInterface;
+import org.getspout.api.Game;
+import org.getspout.api.Spout;
+import org.getspout.api.geo.World;
+import org.getspout.api.material.Material;
+import org.getspout.api.material.MaterialData;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+public class SpoutServerInterface extends ServerInterface {
+ public Game game;
+ public WorldEditPlugin plugin;
+ private final SpoutRawCommandExecutor executor;
+
+ public SpoutServerInterface(WorldEditPlugin plugin, Game game) {
+ this.plugin = plugin;
+ this.game = game;
+ this.executor = new SpoutRawCommandExecutor(plugin);
+ }
+
+ @Override
+ public int resolveItem(String name) {
+ Material mat = MaterialData.getMaterial(name);
+ return mat == null ? 0 : mat.getRawId();
+ }
+
+ @Override
+ public boolean isValidMobType(String type) {
+ return false;
+ //return CreatureType.fromName(type) != null;
+ }
+
+ @Override
+ public void reload() {
+ plugin.loadConfiguration();
+ }
+
+ @Override
+ public int schedule(long delay, long period, Runnable task) {
+ return game.getScheduler().scheduleSyncRepeatingTask(plugin, task, delay, period);
+ }
+
+ @Override
+ public List getWorlds() {
+ Collection worlds = game.getWorlds();
+ List ret = new ArrayList(worlds.size());
+
+ for (World world : worlds) {
+ ret.add(SpoutUtil.getLocalWorld(world));
+ }
+
+ return ret;
+ }
+
+ @Override
+ public void onCommandRegistration(List commands) {
+ for (Command command : commands) {
+ Spout.getGame().getRootCommand().sub(plugin, command.aliases()[0])
+ .addAlias(command.aliases()).setRawExecutor(executor).closeSubCommand();
+ }
+ }
+}
diff --git a/src/main/java/com/sk89q/worldedit/spout/SpoutUtil.java b/src/main/java/com/sk89q/worldedit/spout/SpoutUtil.java
new file mode 100644
index 000000000..2fa85a25e
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/spout/SpoutUtil.java
@@ -0,0 +1,105 @@
+// $Id$
+/*
+ * WorldEdit
+ * Copyright (C) 2010 sk89q
+ *
+ * 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 .
+*/
+
+package com.sk89q.worldedit.spout;
+
+import com.sk89q.worldedit.BlockVector;
+import com.sk89q.worldedit.BlockWorldVector;
+import com.sk89q.worldedit.LocalWorld;
+import com.sk89q.worldedit.Vector;
+import com.sk89q.worldedit.WorldVector;
+import org.getspout.api.Game;
+import org.getspout.api.geo.World;
+import org.getspout.api.geo.cuboid.Block;
+import org.getspout.api.geo.discrete.Point;
+import org.getspout.api.material.block.BlockFace;
+import org.getspout.api.math.Vector3;
+import org.getspout.api.player.Player;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class SpoutUtil {
+ private SpoutUtil() {
+ }
+
+ private static final Map wlw = new HashMap();
+
+ public static LocalWorld getLocalWorld(World w) {
+ LocalWorld lw = wlw.get(w);
+ if (lw == null) {
+ lw = new SpoutWorld(w);
+ wlw.put(w, lw);
+ }
+ return lw;
+ }
+
+ public static BlockVector toVector(Block block) {
+ return new BlockVector(block.getX(), block.getY(), block.getZ());
+ }
+
+ public static BlockVector toVector(BlockFace face) {
+ return toBlockVector(face.getOffset());
+ }
+
+ public static BlockVector toBlockVector(Vector3 vector) {
+ return new BlockVector(vector.getX(), vector.getY(), vector.getZ());
+ }
+
+ public static BlockWorldVector toWorldVector(Block block) {
+ return new BlockWorldVector(getLocalWorld(block.getWorld()), block.getX(), block.getY(), block.getZ());
+ }
+
+ public static Vector toVector(Point loc) {
+ return new Vector(loc.getX(), loc.getY(), loc.getZ());
+ }
+
+ public static Vector toVector(org.getspout.api.math.Vector3 vector) {
+ return new Vector(vector.getX(), vector.getY(), vector.getZ());
+ }
+
+ public static Point toPoint(WorldVector pt) {
+ return new Point(toWorld(pt), (float)pt.getX(), (float)pt.getY(), (float)pt.getZ());
+ }
+
+ public static Point toPoint(World world, Vector pt) {
+ return new Point(world, (float)pt.getX(), (float)pt.getY(), (float)pt.getZ());
+ }
+
+ public static Point center(Point loc) {
+ return new Point(
+ loc.getWorld(),
+ loc.getX() + 0.5F,
+ loc.getY() + 0.5F,
+ loc.getZ() + 0.5F
+ );
+ }
+
+ public static Player matchSinglePlayer(Game game, String name) {
+ return game.getPlayer(name, false);
+ }
+
+ public static Block toBlock(BlockWorldVector pt) {
+ return toWorld(pt).getBlock(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
+ }
+
+ public static World toWorld(WorldVector pt) {
+ return ((SpoutWorld) pt.getWorld()).getWorld();
+ }
+}
diff --git a/src/main/java/com/sk89q/worldedit/spout/SpoutWorld.java b/src/main/java/com/sk89q/worldedit/spout/SpoutWorld.java
new file mode 100644
index 000000000..89a7e202b
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/spout/SpoutWorld.java
@@ -0,0 +1,758 @@
+// $Id$
+/*
+ * WorldEdit
+ * Copyright (C) 2010 sk89q
+ *
+ * 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 .
+*/
+
+package com.sk89q.worldedit.spout;
+
+import com.sk89q.worldedit.BlockVector2D;
+import com.sk89q.worldedit.EditSession;
+import com.sk89q.worldedit.EntityType;
+import com.sk89q.worldedit.LocalWorld;
+import com.sk89q.worldedit.Vector;
+import com.sk89q.worldedit.blocks.BaseBlock;
+import com.sk89q.worldedit.blocks.BaseItemStack;
+import com.sk89q.worldedit.regions.Region;
+
+import org.getspout.api.geo.World;
+import org.getspout.api.geo.discrete.Point;
+import org.getspout.api.material.MaterialData;
+
+public class SpoutWorld extends LocalWorld {
+ private World world;
+
+ /**
+ * Construct the object.
+ * @param world
+ */
+ public SpoutWorld(World world) {
+ this.world = world;
+ }
+
+ /**
+ * Get the world handle.
+ *
+ * @return
+ */
+ public World getWorld() {
+ return world;
+ }
+
+ /**
+ * Get the name of the world
+ *
+ * @return
+ */
+ @Override
+ public String getName() {
+ return world.getName();
+ }
+
+ /**
+ * Set block type.
+ *
+ * @param pt
+ * @param type
+ * @return
+ */
+ @Override
+ public boolean setBlockType(Vector pt, int type) {
+ return world.getBlock(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setBlockId((short)type) != type;
+ }
+
+ /**
+ * Set block type.
+ *
+ * @param pt
+ * @param type
+ * @return
+ */
+ @Override
+ public boolean setBlockTypeFast(Vector pt, int type) {
+ return setBlockType(pt, type);
+ }
+
+ /**
+ * set block type & data
+ * @param pt
+ * @param type
+ * @param data
+ * @return
+ */
+ @Override
+ public boolean setTypeIdAndData(Vector pt, int type, int data) {
+ return world.setBlockId(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ(), (short)type) != type
+ && world.setBlockData(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ(), (byte)data) != data;
+ }
+
+ /**
+ * set block type & data
+ * Everything is threaded, so no need for fastmode here.
+ * @param pt
+ * @param type
+ * @param data
+ * @return
+ */
+ @Override
+ public boolean setTypeIdAndDataFast(Vector pt, int type, int data) {
+ return setTypeIdAndData(pt, type, data);
+ //return world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setTypeIdAndData(type, (byte) data, false);
+ }
+
+ /**
+ * Get block type.
+ *
+ * @param pt
+ * @return
+ */
+ @Override
+ public int getBlockType(Vector pt) {
+ return world.getBlockId(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
+ }
+
+ /**
+ * Set block data.
+ *
+ * @param pt
+ * @param data
+ */
+ @Override
+ public void setBlockData(Vector pt, int data) {
+ world.setBlockData(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ(), (byte)data);
+ }
+
+ /**
+ * Set block data.
+ *
+ * @param pt
+ * @param data
+ */
+ @Override
+ public void setBlockDataFast(Vector pt, int data) {
+ setBlockData(pt, data);
+ }
+
+ /**
+ * Get block data.
+ *
+ * @param pt
+ * @return
+ */
+ @Override
+ public int getBlockData(Vector pt) {
+ return world.getBlockData(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
+ }
+
+ /**
+ * Get block light level.
+ *
+ * @param pt
+ * @return
+ */
+ @Override
+ public int getBlockLightLevel(Vector pt) {
+ return world.getBlockMaterial(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).getLightLevel();
+ }
+
+ /**
+ * Regenerate an area.
+ *
+ * @param region
+ * @param editSession
+ * @return
+ */
+ @Override
+ public boolean regenerate(Region region, EditSession editSession) {
+ /*BaseBlock[] history = new BaseBlock[16 * 16 * (getMaxY() + 1)];
+
+ for (Vector2D chunk : region.getChunks()) {
+ Vector min = new Vector(chunk.getBlockX() * 16, 0, chunk.getBlockZ() * 16);
+
+ // First save all the blocks inside
+ for (int x = 0; x < 16; ++x) {
+ for (int y = 0; y < (getMaxY() + 1); ++y) {
+ for (int z = 0; z < 16; ++z) {
+ Vector pt = min.add(x, y, z);
+ int index = y * 16 * 16 + z * 16 + x;
+ history[index] = editSession.getBlock(pt);
+ }
+ }
+ }
+
+ try {
+ world.regenerateChunk(chunk.getBlockX(), chunk.getBlockZ());
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+
+ // Then restore
+ for (int x = 0; x < 16; ++x) {
+ for (int y = 0; y < (getMaxY() + 1); ++y) {
+ for (int z = 0; z < 16; ++z) {
+ Vector pt = min.add(x, y, z);
+ int index = y * 16 * 16 + z * 16 + x;
+
+ // We have to restore the block if it was outside
+ if (!region.contains(pt)) {
+ editSession.smartSetBlock(pt, history[index]);
+ } else { // Otherwise fool with history
+ editSession.rememberChange(pt, history[index],
+ editSession.rawGetBlock(pt));
+ }
+ }
+ }
+ }
+ }
+
+ return true;*/
+ return false;
+ }
+
+ /**
+ * Attempts to accurately copy a BaseBlock's extra data to the world.
+ *
+ * @param pt
+ * @param block
+ * @return
+ */
+ @Override
+ public boolean copyToWorld(Vector pt, BaseBlock block) {
+ /*if (block instanceof SignBlock) {
+ // Signs
+ setSignText(pt, ((SignBlock) block).getText());
+ return true;
+ }
+
+ if (block instanceof FurnaceBlock) {
+ // Furnaces
+ Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
+ if (bukkitBlock == null) return false;
+ BlockState state = bukkitBlock.getState();
+ if (!(state instanceof Furnace)) return false;
+ Furnace bukkit = (Furnace) state;
+ FurnaceBlock we = (FurnaceBlock) block;
+ bukkit.setBurnTime(we.getBurnTime());
+ bukkit.setCookTime(we.getCookTime());
+ return setContainerBlockContents(pt, ((ContainerBlock) block).getItems());
+ }
+
+ if (block instanceof ContainerBlock) {
+ // Chests/dispenser
+ return setContainerBlockContents(pt, ((ContainerBlock) block).getItems());
+ }
+
+ if (block instanceof MobSpawnerBlock) {
+ // Mob spawners
+ Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
+ if (bukkitBlock == null) return false;
+ BlockState state = bukkitBlock.getState();
+ if (!(state instanceof CreatureSpawner)) return false;
+ CreatureSpawner bukkit = (CreatureSpawner) state;
+ MobSpawnerBlock we = (MobSpawnerBlock) block;
+ bukkit.setCreatureTypeId(we.getMobType());
+ bukkit.setDelay(we.getDelay());
+ return true;
+ }
+
+ if (block instanceof NoteBlock) {
+ // Note block
+ Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
+ if (bukkitBlock == null) return false;
+ BlockState state = bukkitBlock.getState();
+ if (!(state instanceof org.bukkit.block.NoteBlock)) return false;
+ org.bukkit.block.NoteBlock bukkit = (org.bukkit.block.NoteBlock) state;
+ NoteBlock we = (NoteBlock) block;
+ bukkit.setRawNote(we.getNote());
+ return true;
+ }*/
+
+ return false;
+ }
+
+ /**
+ * Attempts to read a BaseBlock's extra data from the world.
+ *
+ * @param pt
+ * @param block
+ * @return
+ */
+ @Override
+ public boolean copyFromWorld(Vector pt, BaseBlock block) {
+ /*if (block instanceof SignBlock) {
+ // Signs
+ ((SignBlock) block).setText(getSignText(pt));
+ return true;
+ }
+
+ if (block instanceof FurnaceBlock) {
+ // Furnaces
+ Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
+ if (bukkitBlock == null) return false;
+ BlockState state = bukkitBlock.getState();
+ if (!(state instanceof Furnace)) return false;
+ Furnace bukkit = (Furnace) state;
+ FurnaceBlock we = (FurnaceBlock) block;
+ we.setBurnTime(bukkit.getBurnTime());
+ we.setCookTime(bukkit.getCookTime());
+ ((ContainerBlock) block).setItems(getContainerBlockContents(pt));
+ return true;
+ }
+
+ if (block instanceof ContainerBlock) {
+ // Chests/dispenser
+ ((ContainerBlock) block).setItems(getContainerBlockContents(pt));
+ return true;
+ }
+
+ if (block instanceof MobSpawnerBlock) {
+ // Mob spawners
+ Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
+ if (bukkitBlock == null) return false;
+ BlockState state = bukkitBlock.getState();
+ if (!(state instanceof CreatureSpawner)) return false;
+ CreatureSpawner bukkit = (CreatureSpawner) state;
+ MobSpawnerBlock we = (MobSpawnerBlock) block;
+ we.setMobType(bukkit.getCreatureTypeId());
+ we.setDelay((short) bukkit.getDelay());
+ return true;
+ }
+
+ if (block instanceof NoteBlock) {
+ // Note block
+ Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
+ if (bukkitBlock == null) return false;
+ BlockState state = bukkitBlock.getState();
+ if (!(state instanceof org.bukkit.block.NoteBlock)) return false;
+ org.bukkit.block.NoteBlock bukkit = (org.bukkit.block.NoteBlock) state;
+ NoteBlock we = (NoteBlock) block;
+ we.setNote(bukkit.getRawNote());
+ }*/
+
+ return false;
+ }
+
+ /**
+ * Clear a chest's contents.
+ *
+ * @param pt
+ */
+ @Override
+ public boolean clearContainerBlockContents(Vector pt) {
+ /* Block block = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
+ if (block == null) {
+ return false;
+ }
+ BlockState state = block.getState();
+ if (!(state instanceof org.bukkit.block.ContainerBlock)) {
+ return false;
+ }
+
+ org.bukkit.block.ContainerBlock chest = (org.bukkit.block.ContainerBlock) state;
+ Inventory inven = chest.getInventory();
+ inven.clear();
+ return true;*/
+ return false;
+ }
+
+ /**
+ * Generate a tree at a location.
+ *
+ * @param pt
+ * @return
+ */
+ @Override
+ public boolean generateTree(EditSession editSession, Vector pt) {
+ /*return world.generateTree(SpoutUtil.toLocation(world, pt), TreeType.TREE,
+ new EditSessionBlockChangeDelegate(editSession));*/
+ return false;
+ }
+
+ /**
+ * Generate a big tree at a location.
+ *
+ * @param pt
+ * @return
+ */
+ @Override
+ public boolean generateBigTree(EditSession editSession, Vector pt) {
+ /*return world.generateTree(SpoutUtil.toLocation(world, pt), TreeType.BIG_TREE,
+ new EditSessionBlockChangeDelegate(editSession));*/
+ return false;
+ }
+
+ /**
+ * Generate a birch tree at a location.
+ *
+ * @param pt
+ * @return
+ */
+ @Override
+ public boolean generateBirchTree(EditSession editSession, Vector pt) {
+ /*return world.generateTree(SpoutUtil.toLocation(world, pt), TreeType.BIRCH,
+ new EditSessionBlockChangeDelegate(editSession));*/
+ return false;
+ }
+
+ /**
+ * Generate a redwood tree at a location.
+ *
+ * @param pt
+ * @return
+ */
+ @Override
+ public boolean generateRedwoodTree(EditSession editSession, Vector pt) {
+ /*return world.generateTree(SpoutUtil.toLocation(world, pt), TreeType.REDWOOD,
+ new EditSessionBlockChangeDelegate(editSession));*/
+ return false;
+ }
+
+ /**
+ * Generate a redwood tree at a location.
+ *
+ * @param pt
+ * @return
+ */
+ @Override
+ public boolean generateTallRedwoodTree(EditSession editSession, Vector pt) {
+ /*return world.generateTree(SpoutUtil.toLocation(world, pt), TreeType.TALL_REDWOOD,
+ new EditSessionBlockChangeDelegate(editSession));*/
+ return false;
+ }
+
+ /**
+ * Drop an item.
+ *
+ * @param pt
+ * @param item
+ */
+ @Override
+ public void dropItem(Vector pt, BaseItemStack item) {
+ /*ItemStack bukkitItem = new ItemStack(item.getType(), item.getAmount(),
+ (byte) item.getDamage());
+ world.dropItemNaturally(toLocation(pt), bukkitItem);*/
+
+ }
+
+ /**
+ * Kill mobs in an area.
+ *
+ * @param origin The center of the area to kill mobs in.
+ * @param radius Maximum distance to kill mobs at; radius < 0 means kill all mobs
+ * @param flags various flags that determine what to kill
+ * @return
+ */
+ @Override
+ public int killMobs(Vector origin, double radius, int flags) {
+ boolean killPets = (flags & KillFlags.PETS) != 0;
+ boolean killNPCs = (flags & KillFlags.NPCS) != 0;
+ boolean killAnimals = (flags & KillFlags.ANIMALS) != 0;
+
+ int num = 0;
+ double radiusSq = radius * radius;
+
+ Point bukkitOrigin = SpoutUtil.toPoint(world, origin);
+
+ /*
+ for (LivingEntity ent : world.getLivingEntities()) {
+ if (ent instanceof HumanEntity) {
+ continue;
+ }
+
+ if (!killAnimals && ent instanceof Animals) {
+ continue;
+ }
+
+ if (!killPets && ent instanceof Tameable && ((Tameable) ent).isTamed()) {
+ continue; // tamed wolf
+ }
+
+ try {
+ // Temporary solution until org.bukkit.entity.NPC is widely deployed.
+ if (!killNPCs && Class.forName("org.bukkit.entity.NPC").isAssignableFrom(ent.getClass())) {
+ continue;
+ }
+ } catch (ClassNotFoundException e) {}
+
+ if (radius < 0 || bukkitOrigin.distanceSquared(ent.getLocation()) <= radiusSq) {
+ ent.remove();
+ ++num;
+ }
+ }*/
+
+ return num;
+ }
+
+ /**
+ * Remove entities in an area.
+ *
+ * @param origin
+ * @param radius
+ * @return
+ */
+ @Override
+ public int removeEntities(EntityType type, Vector origin, int radius) {
+ int num = 0;
+ double radiusSq = radius * radius;
+
+ /*for (Entity ent : world.getEntities()) {
+ if (radius != -1
+ && origin.distanceSq(SpoutUtil.toVector(ent.getTransform().getPosition())) > radiusSq) {
+ continue;
+ }
+
+ if (type == EntityType.ARROWS) {
+ if (ent instanceof Arrow) {
+ ent.remove();
+ ++num;
+ }
+ } else if (type == EntityType.BOATS) {
+ if (ent instanceof Boat) {
+ ent.remove();
+ ++num;
+ }
+ } else if (type == EntityType.ITEMS) {
+ if (ent instanceof Item) {
+ ent.remove();
+ ++num;
+ }
+ } else if (type == EntityType.MINECARTS) {
+ if (ent instanceof Minecart) {
+ ent.remove();
+ ++num;
+ }
+ } else if (type == EntityType.PAINTINGS) {
+ if (ent instanceof Painting) {
+ ent.remove();
+ ++num;
+ }
+ } else if (type == EntityType.TNT) {
+ if (ent instanceof TNTPrimed) {
+ ent.remove();
+ ++num;
+ }
+ } else if (type == EntityType.XP_ORBS) {
+ if (ent instanceof ExperienceOrb) {
+ ent.remove();
+ ++num;
+ }
+ }
+ }*/
+
+ return num;
+ }
+
+ private Point toLocation(Vector pt) {
+ return new Point(world, (float)pt.getX(), (float)pt.getY(), (float)pt.getZ());
+ }
+
+ /**
+ * Set a sign's text.
+ *
+ * @param pt
+ * @param text
+ * @return
+ */
+ private boolean setSignText(Vector pt, String[] text) {
+ /*Block block = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
+ if (block == null) return false;
+ BlockState state = block.getState();
+ if (state == null || !(state instanceof Sign)) return false;
+ Sign sign = (Sign) state;
+ sign.setLine(0, text[0]);
+ sign.setLine(1, text[1]);
+ sign.setLine(2, text[2]);
+ sign.setLine(3, text[3]);
+ sign.update();
+ return true;*/
+ return false;
+ }
+
+ /**
+ * Get a sign's text.
+ *
+ * @param pt
+ * @return
+ */
+ private String[] getSignText(Vector pt) {
+ /*Block block = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
+ if (block == null) return new String[] { "", "", "", "" };
+ BlockState state = block.getState();
+ if (state == null || !(state instanceof Sign)) return new String[] { "", "", "", "" };
+ Sign sign = (Sign) state;
+ String line0 = sign.getLine(0);
+ String line1 = sign.getLine(1);
+ String line2 = sign.getLine(2);
+ String line3 = sign.getLine(3);
+ return new String[] {
+ line0 != null ? line0 : "",
+ line1 != null ? line1 : "",
+ line2 != null ? line2 : "",
+ line3 != null ? line3 : "",
+ };
+ */
+ return new String[] {"", "", "", ""};
+ }
+
+ /**
+ * Get a container block's contents.
+ *
+ * @param pt
+ * @return
+ */
+ private BaseItemStack[] getContainerBlockContents(Vector pt) {
+ /*Block block = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
+ if (block == null) {
+ return new BaseItemStack[0];
+ }
+ BlockState state = block.getState();
+ if (!(state instanceof org.bukkit.block.ContainerBlock)) {
+ return new BaseItemStack[0];
+ }
+
+ org.bukkit.block.ContainerBlock container = (org.bukkit.block.ContainerBlock) state;
+ Inventory inven = container.getInventory();
+ int size = inven.getContents().length
+ BaseItemStack[] contents = new BaseItemStack[size];
+
+ for (int i = 0; i < size; ++i) {
+ ItemStack bukkitStack = inven.getItem(i);
+ if (bukkitStack.getMaterial() != MaterialData.air) {
+ contents[i] = new BaseItemStack(
+ bukkitStack.getMaterial().getRawId(),
+ bukkitStack.getAmount(),
+ bukkitStack.getDamage());
+ try {
+ for (Map.Entry entry : bukkitStack.getEnchantments().entrySet()) {
+ contents[i].getEnchantments().put(entry.getKey().getId(), entry.getValue());
+ }
+ } catch (Throwable ignore) {}
+ }
+ }*/
+
+ return new BaseItemStack[0];
+ }
+
+ /**
+ * Set a container block's contents.
+ *
+ * @param pt
+ * @param contents
+ * @return
+ */
+ private boolean setContainerBlockContents(Vector pt, BaseItemStack[] contents) {
+ /*Block block = world.getBlock(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
+ if (block == null) {
+ return false;
+ }
+ BlockState state = block.getState();
+ if (!(state instanceof org.bukkit.block.ContainerBlock)) {
+ return false;
+ }
+
+ org.bukkit.block.ContainerBlock chest = (org.bukkit.block.ContainerBlock) state;
+ Inventory inven = chest.getInventory();
+ int size = inven.getSize();
+
+ for (int i = 0; i < size; ++i) {
+ if (i >= contents.length) {
+ break;
+ }
+
+ if (contents[i] != null) {
+ ItemStack toAdd = new ItemStack(contents[i].getType(),
+ contents[i].getAmount(),
+ (byte) contents[i].getDamage());
+ try {
+ for (Map.Entry entry : contents[i].getEnchantments().entrySet()) {
+ toAdd.addEnchantment(Enchantment.getById(entry.getKey()), entry.getValue());
+ }
+ } catch (Throwable ignore) {}
+ inven.setItem(i, toAdd);
+ } else {
+ inven.setItem(i, null);
+ }
+ }
+
+ return true;*/
+ return false;
+ }
+
+ /**
+ * Returns whether a block has a valid ID.
+ *
+ * @param type
+ * @return
+ */
+ @Override
+ public boolean isValidBlockType(int type) {
+ return type <= 255 && MaterialData.getMaterial((short)type) != null;
+ }
+
+ @Override
+ public void checkLoadedChunk(Vector pt) {
+ /*if (!world.isChunkLoaded(pt.getBlockX() >> 4, pt.getBlockZ() >> 4)) {
+ world.loadChunk(pt.getBlockX() >> 4, pt.getBlockZ() >> 4);
+ }*/
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof SpoutWorld)) {
+ return false;
+ }
+
+ return ((SpoutWorld) other).world.equals(world);
+ }
+
+ @Override
+ public int hashCode() {
+ return world.hashCode();
+ }
+
+ @Override
+ public int getMaxY() {
+ return world.getHeight() - 1;
+ }
+
+ @Override
+ public void fixAfterFastMode(Iterable chunks) {
+ /*for (BlockVector2D chunkPos : chunks) {
+ world.refreshChunk(chunkPos.getBlockX(), chunkPos.getBlockZ());
+ }*/
+ }
+
+ /*private static final Map effects = new HashMap();
+ static {
+ for (Effect effect : Effect.values()) {
+ effects.put(effect.getId(), effect);
+ }
+ }*/
+
+ @Override
+ public boolean playEffect(Vector position, int type, int data) {
+ /*final Effect effect = effects.get(type);
+ if (effect == null) {
+ return false;
+ }
+
+ world.playEffect(SpoutUtil.toLocation(world, position), effect, data);
+
+ return true;
+ */
+ return false;
+ }
+}
diff --git a/src/main/java/com/sk89q/worldedit/spout/WorldEditPlayerListener.java b/src/main/java/com/sk89q/worldedit/spout/WorldEditPlayerListener.java
new file mode 100644
index 000000000..5fa41457e
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/spout/WorldEditPlayerListener.java
@@ -0,0 +1,178 @@
+// $Id$
+/*
+ * WorldEdit
+ * Copyright (C) 2010 sk89q
+ *
+ * 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 .
+*/
+
+package com.sk89q.worldedit.spout;
+
+import com.sk89q.util.StringUtil;
+import com.sk89q.worldedit.LocalPlayer;
+import com.sk89q.worldedit.LocalWorld;
+import com.sk89q.worldedit.WorldEdit;
+import com.sk89q.worldedit.WorldVector;
+import org.getspout.api.Spout;
+import org.getspout.api.event.EventHandler;
+import org.getspout.api.event.Listener;
+import org.getspout.api.event.Order;
+import org.getspout.api.event.player.PlayerChatEvent;
+import org.getspout.api.event.player.PlayerInteractEvent;
+import org.getspout.api.event.player.PlayerInteractEvent.Action;
+import org.getspout.api.event.player.PlayerJoinEvent;
+import org.getspout.api.event.player.PlayerLeaveEvent;
+import org.getspout.api.event.server.PreCommandEvent;
+import org.getspout.api.geo.discrete.Point;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Handles all events thrown in relation to a Player
+ */
+public class WorldEditPlayerListener implements Listener {
+ /**
+ * Plugin.
+ */
+ private WorldEditPlugin plugin;
+
+ private boolean ignoreLeftClickAir = false;
+
+ private final static Pattern cuipattern = Pattern.compile("u00a74u00a75u00a73u00a74([^|]*)\\|?(.*)");
+
+ /**
+ * Construct the object;
+ *
+ * @param plugin
+ */
+ public WorldEditPlayerListener(WorldEditPlugin plugin) {
+ this.plugin = plugin;
+ }
+
+ @EventHandler(event = PlayerJoinEvent.class, order = Order.EARLIEST)
+ public void onPlayerJoin(PlayerJoinEvent event) {
+ plugin.wrapPlayer(event.getPlayer()).dispatchCUIHandshake();
+ }
+
+ /**
+ * Called when a player leaves a server
+ *
+ * @param event Relevant event details
+ */
+ @EventHandler(event = PlayerLeaveEvent.class)
+ public void onPlayerQuit(PlayerLeaveEvent event) {
+ plugin.getWorldEdit().markExpire(plugin.wrapPlayer(event.getPlayer()));
+ }
+
+ /**
+ * Called when a player attempts to use a command
+ *
+ * @param event Relevant event details
+ */
+ //@EventHandler(event = PreCommandEvent.class, order = Order.EARLY)
+ public void onPlayerCommandPreprocess(PreCommandEvent event) {
+
+ String[] split = event.getMessage().split(" ");
+
+ if (split.length > 0) {
+ split[0] = "/" + split[0];
+ split = plugin.getWorldEdit().commandDetection(split);
+ event.setMessage(StringUtil.joinString(split, " "));
+ }
+ }
+
+ /**
+ * Called when a player interacts
+ *
+ * @param event Relevant event details
+ */
+ @EventHandler(event = PlayerInteractEvent.class)
+ public void onPlayerInteract(PlayerInteractEvent event) {
+
+ final LocalPlayer player = plugin.wrapPlayer(event.getPlayer());
+ final LocalWorld world = player.getWorld();
+ final WorldEdit we = plugin.getWorldEdit();
+
+ PlayerInteractEvent.Action action = event.getAction();
+ if (action == Action.LEFT_CLICK) {
+ if (event.isAir() && ignoreLeftClickAir) {
+ return;
+ }
+
+ if (!event.isAir()) {
+ final Point clickedBlock = event.getInteractedPoint();
+ final WorldVector pos = new WorldVector(world, clickedBlock.getX(),
+ clickedBlock.getY(), clickedBlock.getZ());
+
+
+ if (we.handleBlockLeftClick(player, pos)) {
+ event.setCancelled(true);
+ }
+ }
+
+ if (we.handleArmSwing(player)) {
+ event.setCancelled(true);
+ }
+
+ if (!event.isAir() && !ignoreLeftClickAir) {
+ final int taskId = Spout.getGame().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
+ public void run() {
+ ignoreLeftClickAir = false;
+ }
+ }, 2);
+
+ if (taskId != -1) {
+ ignoreLeftClickAir = true;
+ }
+ }
+ } else if (action == Action.RIGHT_CLICK) {
+ if (!event.isAir()) {
+ final Point clickedBlock = event.getInteractedPoint();
+ final WorldVector pos = new WorldVector(world, clickedBlock.getX(),
+ clickedBlock.getY(), clickedBlock.getZ());
+
+ if (we.handleBlockRightClick(player, pos)) {
+ event.setCancelled(true);
+ }
+ }
+
+ if (we.handleRightClick(player)) {
+ event.setCancelled(true);
+ }
+ }
+ }
+
+ @EventHandler(event = PlayerChatEvent.class)
+ public void onPlayerChat(PlayerChatEvent event) {
+ if (event.isCancelled()) {
+ return;
+ }
+
+ Matcher matcher = cuipattern.matcher(event.getMessage());
+ if (matcher.find()) {
+ String type = matcher.group(1);
+ String args = matcher.group(2);
+
+ if( type.equals("v") ) {
+ try {
+ plugin.getSession(event.getPlayer()).setCUIVersion(Integer.parseInt(args));
+ event.setCancelled(true);
+ } catch( NumberFormatException e ) {
+ }
+ }
+
+ }
+ }
+}
diff --git a/src/main/java/com/sk89q/worldedit/spout/WorldEditPlugin.java b/src/main/java/com/sk89q/worldedit/spout/WorldEditPlugin.java
new file mode 100644
index 000000000..91b297951
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/spout/WorldEditPlugin.java
@@ -0,0 +1,354 @@
+// $Id$
+/*
+ * WorldEdit
+ * Copyright (C) 2010 sk89q
+ *
+ * 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 .
+*/
+
+package com.sk89q.worldedit.spout;
+
+import com.sk89q.util.yaml.YAMLProcessor;
+import com.sk89q.worldedit.*;
+import com.sk89q.worldedit.bags.BlockBag;
+import com.sk89q.worldedit.regions.CuboidRegion;
+import com.sk89q.worldedit.regions.Polygonal2DRegion;
+import com.sk89q.worldedit.regions.Region;
+import com.sk89q.worldedit.regions.RegionSelector;
+import com.sk89q.worldedit.spout.selections.CuboidSelection;
+import com.sk89q.worldedit.spout.selections.Polygonal2DSelection;
+import com.sk89q.worldedit.spout.selections.Selection;
+import com.sk89q.worldedit.util.YAMLConfiguration;
+import org.getspout.api.command.CommandSource;
+import org.getspout.api.geo.World;
+import org.getspout.api.player.Player;
+import org.getspout.api.plugin.CommonPlugin;
+import org.getspout.api.util.Named;
+
+import java.io.*;
+import java.util.jar.JarFile;
+import java.util.logging.Logger;
+import java.util.zip.ZipEntry;
+
+/**
+ * Plugin for Spout.
+ *
+ * @author sk89q
+ */
+public class WorldEditPlugin extends CommonPlugin implements Named {
+ /**
+ * WorldEdit messages get sent here.
+ */
+ private static final Logger logger = Logger.getLogger("Minecraft.WorldEdit");
+
+ /**
+ * The server interface that all server-related API goes through.
+ */
+ private ServerInterface server;
+ /**
+ * Main WorldEdit instance.
+ */
+ private WorldEdit controller;
+
+ /**
+ * Holds the configuration for WorldEdit.
+ */
+ private YAMLConfiguration config;
+
+ /**
+ * Called on plugin enable.
+ */
+ public void onEnable() {
+ final String pluginYmlVersion = getDescription().getVersion();
+ final String manifestVersion = WorldEdit.getVersion();
+
+ logger.info("WorldEdit " + pluginYmlVersion + " enabled.");
+ if (!manifestVersion.equalsIgnoreCase(pluginYmlVersion)) {
+ WorldEdit.setVersion(manifestVersion + " (" + pluginYmlVersion + ")");
+ }
+
+ // Make the data folders that WorldEdit uses
+ getDataFolder().mkdirs();
+
+ // Create the default configuration file
+ createDefaultConfiguration("config.yml");
+
+ // Set up configuration and such, including the permissions
+ // resolver
+ config = new YAMLConfiguration(new YAMLProcessor(new File(getDataFolder(), "config.yml"), true), logger);
+
+ // Load the configuration
+ loadConfiguration();
+
+ // Setup interfaces
+ server = new SpoutServerInterface(this, getGame());
+ controller = new WorldEdit(server, config);
+
+ // Now we can register events!
+ registerEvents();
+
+ getGame().getScheduler().scheduleAsyncRepeatingTask(this,
+ new SessionTimer(controller, getGame()), 120, 120);
+ }
+
+ /**
+ * Called on plugin disable.
+ */
+ public void onDisable() {
+ for (Player player : getGame().getOnlinePlayers()) {
+ LocalPlayer lPlayer = wrapPlayer(player);
+ if (controller.getSession(lPlayer).hasCUISupport()) {
+ lPlayer.dispatchCUIHandshake();
+ }
+ }
+ controller.clearSessions();
+ config.unload();
+ getGame().getScheduler().cancelTasks(this);
+ }
+
+ /**
+ * Loads and reloads all configuration.
+ */
+ protected void loadConfiguration() {
+ config.unload();
+ config.load();
+ }
+
+ /**
+ * Register the events used by WorldEdit.
+ */
+ protected void registerEvents() {
+ getGame().getEventManager().registerEvents(new WorldEditPlayerListener(this), this);
+ }
+
+ /**
+ * Create a default configuration file from the .jar.
+ *
+ * @param name
+ */
+ protected void createDefaultConfiguration(String name) {
+ File actual = new File(getDataFolder(), name);
+ if (!actual.exists()) {
+ InputStream input =
+ null;
+ try {
+ JarFile file = new JarFile(getFile());
+ ZipEntry copy = file.getEntry("defaults/" + name);
+ if (copy == null) throw new FileNotFoundException();
+ input = file.getInputStream(copy);
+ } catch (IOException e) {
+ logger.severe(getDescription().getName() + ": Unable to read default configuration: " + name);
+ }
+ if (input != null) {
+ FileOutputStream output = null;
+
+ try {
+ output = new FileOutputStream(actual);
+ byte[] buf = new byte[8192];
+ int length = 0;
+ while ((length = input.read(buf)) > 0) {
+ output.write(buf, 0, length);
+ }
+
+ logger.info(getDescription().getName()
+ + ": Default configuration file written: " + name);
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ if (input != null) {
+ input.close();
+ }
+ } catch (IOException e) {}
+
+ try {
+ if (output != null) {
+ output.close();
+ }
+ } catch (IOException e) {}
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the session for the player.
+ *
+ * @param player
+ * @return
+ */
+ public LocalSession getSession(Player player) {
+ return controller.getSession(wrapPlayer(player));
+ }
+
+ /**
+ * Gets the session for the player.
+ *
+ * @param player
+ * @return
+ */
+ public EditSession createEditSession(Player player) {
+ LocalPlayer wePlayer = wrapPlayer(player);
+ LocalSession session = controller.getSession(wePlayer);
+ BlockBag blockBag = session.getBlockBag(wePlayer);
+
+ EditSession editSession =
+ new EditSession(wePlayer.getWorld(), session.getBlockChangeLimit(), blockBag);
+ editSession.enableQueue();
+
+ return editSession;
+ }
+
+ /**
+ * Remember an edit session.
+ *
+ * @param player
+ * @param editSession
+ */
+ public void remember(Player player, EditSession editSession) {
+ LocalPlayer wePlayer = wrapPlayer(player);
+ LocalSession session = controller.getSession(wePlayer);
+
+ session.remember(editSession);
+ editSession.flushQueue();
+
+ controller.flushBlockBag(wePlayer, editSession);
+ }
+
+ /**
+ * Wrap an operation into an EditSession.
+ *
+ * @param player
+ * @param op
+ * @throws Throwable
+ */
+ public void perform(Player player, WorldEditOperation op)
+ throws Throwable {
+ LocalPlayer wePlayer = wrapPlayer(player);
+ LocalSession session = controller.getSession(wePlayer);
+
+ EditSession editSession = createEditSession(player);
+ try {
+ op.run(session, wePlayer, editSession);
+ } finally {
+ remember(player, editSession);
+ }
+ }
+
+ /**
+ * Returns the configuration used by WorldEdit.
+ *
+ * @return
+ */
+ public YAMLConfiguration getLocalConfiguration() {
+ return config;
+ }
+
+ /**
+ * Used to wrap a Bukkit Player as a LocalPlayer.
+ *
+ * @param player
+ * @return
+ */
+ public SpoutPlayer wrapPlayer(Player player) {
+ return new SpoutPlayer(this, this.server, player);
+ }
+
+ public LocalPlayer wrapCommandSender(CommandSource sender) {
+ if (sender instanceof Player) {
+ return wrapPlayer((Player) sender);
+ }
+
+ return new SpoutCommandSender(this, this.server, sender);
+ }
+
+ /**
+ * Get the server interface.
+ *
+ * @return
+ */
+ public ServerInterface getServerInterface() {
+ return server;
+ }
+
+ /**
+ * Get WorldEdit.
+ *
+ * @return
+ */
+ public WorldEdit getWorldEdit() {
+ return controller;
+ }
+
+ /**
+ * Gets the region selection for the player.
+ *
+ * @param player
+ * @return the selection or null if there was none
+ */
+ public Selection getSelection(Player player) {
+ if (player == null) {
+ throw new IllegalArgumentException("Null player not allowed");
+ }
+ if (!player.isOnline()) {
+ throw new IllegalArgumentException("Offline player not allowed");
+ }
+
+ LocalSession session = controller.getSession(wrapPlayer(player));
+ RegionSelector selector = session.getRegionSelector(SpoutUtil.getLocalWorld(player.getEntity().getTransform().getPosition().getWorld()));
+
+ try {
+ Region region = selector.getRegion();
+ World world = ((SpoutWorld) session.getSelectionWorld()).getWorld();
+
+ if (region instanceof CuboidRegion) {
+ return new CuboidSelection(world, selector, (CuboidRegion) region);
+ } else if (region instanceof Polygonal2DRegion) {
+ return new Polygonal2DSelection(world, selector, (Polygonal2DRegion) region);
+ } else {
+ return null;
+ }
+ } catch (IncompleteRegionException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Sets the region selection for a player.
+ *
+ * @param player
+ * @param selection
+ */
+ public void setSelection(Player player, Selection selection) {
+ if (player == null) {
+ throw new IllegalArgumentException("Null player not allowed");
+ }
+ if (!player.isOnline()) {
+ throw new IllegalArgumentException("Offline player not allowed");
+ }
+ if (selection == null) {
+ throw new IllegalArgumentException("Null selection not allowed");
+ }
+
+ LocalSession session = controller.getSession(wrapPlayer(player));
+ RegionSelector sel = selection.getRegionSelector();
+ session.setRegionSelector(SpoutUtil.getLocalWorld(player.getEntity().getTransform().getPosition().getWorld()), sel);
+ session.dispatchCUISelection(wrapPlayer(player));
+ }
+
+ @Override
+ public String getName() {
+ return getDescription().getName();
+ }
+}
diff --git a/src/main/java/com/sk89q/worldedit/spout/selections/CuboidSelection.java b/src/main/java/com/sk89q/worldedit/spout/selections/CuboidSelection.java
new file mode 100644
index 000000000..a389d524c
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/spout/selections/CuboidSelection.java
@@ -0,0 +1,70 @@
+/*
+ * WorldEdit
+ * Copyright (C) 2012 sk89q
+ *
+ * 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 .
+ */
+
+// $Id$
+
+package com.sk89q.worldedit.spout.selections;
+
+import com.sk89q.worldedit.Vector;
+import com.sk89q.worldedit.spout.SpoutUtil;
+import com.sk89q.worldedit.regions.CuboidRegion;
+import com.sk89q.worldedit.regions.CuboidRegionSelector;
+import com.sk89q.worldedit.regions.RegionSelector;
+import org.getspout.api.geo.World;
+import org.getspout.api.geo.discrete.Point;
+
+public class CuboidSelection extends RegionSelection {
+
+ protected CuboidRegion cuboid;
+
+ public CuboidSelection(World world, Point pt1, Point pt2) {
+ this(world, SpoutUtil.toVector(pt1), SpoutUtil.toVector(pt2));
+ }
+
+ public CuboidSelection(World world, Vector pt1, Vector pt2) {
+ super(world);
+
+ // Validate input
+ if (pt1 == null) {
+ throw new IllegalArgumentException("Null point 1 not permitted");
+ }
+
+ if (pt2 == null) {
+ throw new IllegalArgumentException("Null point 2 not permitted");
+ }
+
+ // Create new selector
+ CuboidRegionSelector sel = new CuboidRegionSelector(SpoutUtil.getLocalWorld(world));
+
+ // set up selector
+ sel.selectPrimary(pt1);
+ sel.selectSecondary(pt2);
+
+ // set up CuboidSelection
+ cuboid = sel.getIncompleteRegion();
+
+ // set up RegionSelection
+ setRegionSelector(sel);
+ setRegion(cuboid);
+ }
+
+ public CuboidSelection(World world, RegionSelector sel, CuboidRegion region) {
+ super(world, sel, region);
+ this.cuboid = region;
+ }
+}
diff --git a/src/main/java/com/sk89q/worldedit/spout/selections/Polygonal2DSelection.java b/src/main/java/com/sk89q/worldedit/spout/selections/Polygonal2DSelection.java
new file mode 100644
index 000000000..f56e4394c
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/spout/selections/Polygonal2DSelection.java
@@ -0,0 +1,66 @@
+/*
+ * WorldEdit
+ * Copyright (C) 2012 sk89q
+ *
+ * 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 .
+ */
+
+// $Id$
+
+
+package com.sk89q.worldedit.spout.selections;
+
+import com.sk89q.worldedit.BlockVector2D;
+import com.sk89q.worldedit.LocalWorld;
+import com.sk89q.worldedit.regions.Polygonal2DRegion;
+import com.sk89q.worldedit.regions.Polygonal2DRegionSelector;
+import com.sk89q.worldedit.regions.RegionSelector;
+import com.sk89q.worldedit.spout.SpoutUtil;
+import org.getspout.api.geo.World;
+
+import java.util.Collections;
+import java.util.List;
+
+public class Polygonal2DSelection extends RegionSelection {
+
+ protected Polygonal2DRegion poly2d;
+
+ public Polygonal2DSelection(World world, RegionSelector sel, Polygonal2DRegion region) {
+ super(world, sel, region);
+ this.poly2d = region;
+ }
+
+ public Polygonal2DSelection(World world, List points, int minY, int maxY) {
+ super(world);
+ LocalWorld lWorld = SpoutUtil.getLocalWorld(world);
+
+ // Validate input
+ minY = Math.min(Math.max(0, minY), world.getHeight());
+ maxY = Math.min(Math.max(0, maxY), world.getHeight());
+
+ // Create and set up new selector
+ Polygonal2DRegionSelector sel = new Polygonal2DRegionSelector(lWorld, points, minY, maxY);
+
+ // set up CuboidSelection
+ poly2d = sel.getIncompleteRegion();
+
+ // set up RegionSelection
+ setRegionSelector(sel);
+ setRegion(poly2d);
+ }
+
+ public List getNativePoints() {
+ return Collections.unmodifiableList(poly2d.getPoints());
+ }
+}
diff --git a/src/main/java/com/sk89q/worldedit/spout/selections/RegionSelection.java b/src/main/java/com/sk89q/worldedit/spout/selections/RegionSelection.java
new file mode 100644
index 000000000..c0b39f313
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/spout/selections/RegionSelection.java
@@ -0,0 +1,107 @@
+/*
+ * WorldEdit
+ * Copyright (C) 2012 sk89q
+ *
+ * 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 .
+ */
+
+// $Id$
+
+
+package com.sk89q.worldedit.spout.selections;
+
+import com.sk89q.worldedit.Vector;
+import com.sk89q.worldedit.regions.Region;
+import com.sk89q.worldedit.regions.RegionSelector;
+import com.sk89q.worldedit.spout.SpoutUtil;
+import org.getspout.api.geo.World;
+import org.getspout.api.geo.discrete.Point;
+
+public abstract class RegionSelection implements Selection {
+
+ private World world;
+ private RegionSelector selector;
+ private Region region;
+
+ public RegionSelection(World world) {
+ this.world = world;
+ }
+
+ public RegionSelection(World world, RegionSelector selector, Region region) {
+ this.world = world;
+ this.region = region;
+ this.selector = selector;
+ }
+
+ protected Region getRegion() {
+ return region;
+ }
+
+ protected void setRegion(Region region) {
+ this.region = region;
+ }
+
+ public RegionSelector getRegionSelector() {
+ return selector;
+ }
+
+ protected void setRegionSelector(RegionSelector selector) {
+ this.selector = selector;
+ }
+
+ public Point getMinimumPoint() {
+ return SpoutUtil.toPoint(world, region.getMinimumPoint());
+ }
+
+ public Vector getNativeMinimumPoint() {
+ return region.getMinimumPoint();
+ }
+
+ public Point getMaximumPoint() {
+ return SpoutUtil.toPoint(world, region.getMaximumPoint());
+ }
+
+ public Vector getNativeMaximumPoint() {
+ return region.getMaximumPoint();
+ }
+
+ public World getWorld() {
+ return world;
+ }
+
+ public int getArea() {
+ return region.getArea();
+ }
+
+ public int getWidth() {
+ return region.getWidth();
+ }
+
+ public int getHeight() {
+ return region.getHeight();
+ }
+
+ public int getLength() {
+ return region.getLength();
+ }
+
+ public boolean contains(Point pt) {
+ if (!pt.getWorld().equals(world)) {
+ return false;
+ }
+
+ return region.contains(SpoutUtil.toVector(pt));
+ }
+
+}
diff --git a/src/main/java/com/sk89q/worldedit/spout/selections/Selection.java b/src/main/java/com/sk89q/worldedit/spout/selections/Selection.java
new file mode 100644
index 000000000..5695f64da
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/spout/selections/Selection.java
@@ -0,0 +1,107 @@
+/*
+ * WorldEdit
+ * Copyright (C) 2012 sk89q
+ *
+ * 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 .
+ */
+
+// $Id$
+
+
+package com.sk89q.worldedit.spout.selections;
+
+import com.sk89q.worldedit.Vector;
+import com.sk89q.worldedit.regions.RegionSelector;
+import org.getspout.api.geo.World;
+import org.getspout.api.geo.discrete.Point;
+
+public interface Selection {
+ /**
+ * Get the lower point of a region.
+ *
+ * @return min. point
+ */
+ public Point getMinimumPoint();
+
+ /**
+ * Get the lower point of a region.
+ *
+ * @return min. point
+ */
+ public Vector getNativeMinimumPoint();
+
+ /**
+ * Get the upper point of a region.
+ *
+ * @return max. point
+ */
+ public Point getMaximumPoint();
+
+ /**
+ * Get the upper point of a region.
+ *
+ * @return max. point
+ */
+ public Vector getNativeMaximumPoint();
+
+ /**
+ * Get the region selector. This is for internal use.
+ *
+ * @return
+ */
+ public RegionSelector getRegionSelector();
+
+ /**
+ * Get the world.
+ *
+ * @return
+ */
+ public World getWorld();
+
+ /**
+ * Get the number of blocks in the region.
+ *
+ * @return number of blocks
+ */
+ public int getArea();
+
+ /**
+ * Get X-size.
+ *
+ * @return width
+ */
+ public int getWidth();
+
+ /**
+ * Get Y-size.
+ *
+ * @return height
+ */
+ public int getHeight();
+
+ /**
+ * Get Z-size.
+ *
+ * @return length
+ */
+ public int getLength();
+
+ /**
+ * Returns true based on whether the region contains the point,
+ *
+ * @param pt
+ * @return
+ */
+ public boolean contains(Point pt);
+}
diff --git a/src/main/resources/spoutplugin.yml b/src/main/resources/spoutplugin.yml
new file mode 100644
index 000000000..69b5d3f79
--- /dev/null
+++ b/src/main/resources/spoutplugin.yml
@@ -0,0 +1,7 @@
+name: WorldEdit
+main: com.sk89q.worldedit.spout.WorldEditPlugin
+version: ${project.version}
+platform: BOTH
+
+# Permissions aren't here. Read http://wiki.sk89q.com/wiki/WEPIF/DinnerPerms
+# for how WorldEdit permissions actually work.