Added basic entity handling with copy and paste.

Paintings do not currently respawn properly, entity pastes cannot be undone yet, and schematics do not yet store entities
@celticminstrel needs to fix painting spawning
This commit is contained in:
zml2008 2012-03-29 21:16:59 -07:00
parent 03f7d4ecfb
commit c76f119fa4
14 changed files with 477 additions and 5 deletions

View File

@ -26,6 +26,9 @@ import com.sk89q.worldedit.schematic.SchematicFormat;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* The clipboard remembers the state of a cuboid region.
*
@ -45,6 +48,7 @@ public class CuboidClipboard {
private Vector offset;
private Vector origin;
private Vector size;
private List<CopiedEntity> entities = new ArrayList<CopiedEntity>();
/**
* Constructs the clipboard.
@ -263,6 +267,11 @@ public class CuboidClipboard {
}
}
public void paste(EditSession editSession, Vector newOrigin, boolean noAir)
throws MaxChangedBlocksException {
paste(editSession, newOrigin, noAir, false);
}
/**
* Paste from the clipboard.
*
@ -271,9 +280,12 @@ public class CuboidClipboard {
* @param noAir True to not paste air
* @throws MaxChangedBlocksException
*/
public void paste(EditSession editSession, Vector newOrigin, boolean noAir)
public void paste(EditSession editSession, Vector newOrigin, boolean noAir, boolean entities)
throws MaxChangedBlocksException {
place(editSession, newOrigin.add(offset), noAir);
if (entities) {
pasteEntities(newOrigin.add(offset));
}
}
/**
@ -298,6 +310,21 @@ public class CuboidClipboard {
}
}
public LocalEntity[] pasteEntities(Vector pos) {
LocalEntity[] entities = new LocalEntity[this.entities.size()];
for (int i = 0; i < this.entities.size(); ++i) {
CopiedEntity copied = this.entities.get(i);
if (copied.entity.spawn(copied.entity.getPosition().setPosition(copied.relativePosition.add(pos)))) {
entities[i] = copied.entity;
}
}
return entities;
}
public void storeEntity(LocalEntity entity) {
this.entities.add(new CopiedEntity(entity));
}
/**
* Get one point in the copy. The point is relative to the origin
* of the copy (0, 0, 0) and not to the actual copy origin.
@ -384,4 +411,14 @@ public class CuboidClipboard {
public void setOffset(Vector offset) {
this.offset = offset;
}
private class CopiedEntity {
private final LocalEntity entity;
private final Vector relativePosition;
public CopiedEntity(LocalEntity entity) {
this.entity = entity;
this.relativePosition = entity.getPosition().getPosition().subtract(getOrigin());
}
}
}

View File

@ -0,0 +1,40 @@
/*
* WorldEdit
* Copyright (C) 2012 sk89q <http://www.sk89q.com> and contributors
*
* 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/>.
*/
package com.sk89q.worldedit;
/**
* @author zml2008
*/
public abstract class LocalEntity {
private final Location position;
protected LocalEntity(Location position) {
this.position = position;
}
public Location getPosition() {
return position;
}
public boolean spawn() {
return spawn(getPosition());
}
public abstract boolean spawn(Location loc);
}

View File

@ -501,4 +501,12 @@ public abstract class LocalWorld {
return true;
}
public LocalEntity[] getEntities(Region region) {
return new LocalEntity[0];
}
public int killEntities(LocalEntity... entities) {
return 0;
}
}

View File

@ -23,8 +23,16 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.sk89q.worldedit.bukkit.entity.BukkitEntity;
import com.sk89q.worldedit.bukkit.entity.BukkitExpOrb;
import com.sk89q.worldedit.bukkit.entity.BukkitItem;
import com.sk89q.worldedit.bukkit.entity.BukkitPainting;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Entity;
import org.bukkit.entity.ExperienceOrb;
import org.bukkit.entity.Item;
import org.bukkit.entity.Painting;
import org.bukkit.entity.Player;
import org.bukkit.Server;
import org.bukkit.World;
@ -139,4 +147,18 @@ public class BukkitUtil {
public static World toWorld(final LocalWorld world) {
return ((BukkitWorld) world).getWorld();
}
public static BukkitEntity toLocalEntity(Entity e) {
switch (e.getType()) {
case EXPERIENCE_ORB:
return new BukkitExpOrb(toLocation(e.getLocation()), e.getUniqueId(), ((ExperienceOrb)e).getExperience());
/*case PAINTING: // TODO: Figure out what celticminstrel broke
Painting paint = (Painting) e;
return new BukkitPainting(toLocation(e.getLocation()), paint.getArt(), paint.getFacing(), e.getUniqueId());*/
case DROPPED_ITEM:
return new BukkitItem(toLocation(e.getLocation()), ((Item)e).getItemStack(), e.getUniqueId());
default:
return new BukkitEntity(toLocation(e.getLocation()), e.getType(), e.getUniqueId());
}
}
}

View File

@ -19,11 +19,19 @@
package com.sk89q.worldedit.bukkit;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.WeakHashMap;
import com.sk89q.worldedit.LocalEntity;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.bukkit.entity.BukkitEntity;
import com.sk89q.worldedit.util.TreeGenerator;
import org.bukkit.block.Biome;
import org.bukkit.block.Block;
@ -892,4 +900,34 @@ public class BukkitWorld extends LocalWorld {
public void simulateBlockMine(Vector pt) {
world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).breakNaturally();
}
public LocalEntity[] getEntities(Region region) {
List<BukkitEntity> entities = new ArrayList<BukkitEntity>();
for (Vector2D pt : region.getChunks()) {
if (world.isChunkLoaded(pt.getBlockX(), pt.getBlockZ())) {
Entity[] ents = world.getChunkAt(pt.getBlockX(), pt.getBlockZ()).getEntities();
for (Entity ent : ents) {
if (region.contains(BukkitUtil.toVector(ent.getLocation()))) {
entities.add(BukkitUtil.toLocalEntity(ent));
}
}
}
}
return entities.toArray(new BukkitEntity[entities.size()]);
}
public int killEntities(LocalEntity... entities) {
int amount = 0;
Set<UUID> toKill = new HashSet<UUID>();
for (LocalEntity entity : entities) {
toKill.add(((BukkitEntity) entity).getEntityId());
}
for (Entity entity : world.getEntities()) {
if (toKill.contains(entity.getUniqueId())) {
entity.remove();
++amount;
}
}
return amount;
}
}

View File

@ -0,0 +1,50 @@
/*
* WorldEdit
* Copyright (C) 2012 sk89q <http://www.sk89q.com> and contributors
*
* 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/>.
*/
package com.sk89q.worldedit.bukkit.entity;
import com.sk89q.worldedit.LocalEntity;
import com.sk89q.worldedit.Location;
import com.sk89q.worldedit.bukkit.BukkitUtil;
import org.bukkit.entity.EntityType;
import java.util.UUID;
/**
* @author zml2008
*/
public class BukkitEntity extends LocalEntity {
private final EntityType type;
private final UUID entityId;
public BukkitEntity(Location loc, EntityType type, UUID entityId) {
super(loc);
this.type = type;
this.entityId = entityId;
}
public UUID getEntityId() {
return entityId;
}
@Override
public boolean spawn(Location weLoc) {
org.bukkit.Location loc = BukkitUtil.toLocation(weLoc);
return loc.getWorld().spawnCreature(loc, type) != null;
}
}

View File

@ -0,0 +1,49 @@
/*
* WorldEdit
* Copyright (C) 2012 sk89q <http://www.sk89q.com> and contributors
*
* 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/>.
*/
package com.sk89q.worldedit.bukkit.entity;
import com.sk89q.worldedit.Location;
import com.sk89q.worldedit.bukkit.BukkitUtil;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.ExperienceOrb;
import java.util.UUID;
/**
* @author zml2008
*/
public class BukkitExpOrb extends BukkitEntity {
private final int amount;
public BukkitExpOrb(Location loc, UUID entityId, int amount) {
super(loc, EntityType.EXPERIENCE_ORB, entityId);
this.amount = amount;
}
@Override
public boolean spawn(Location weLoc) {
org.bukkit.Location loc = BukkitUtil.toLocation(weLoc);
ExperienceOrb orb = loc.getWorld().spawn(loc, ExperienceOrb.class);
if (orb != null) {
orb.setExperience(amount);
return true;
}
return false;
}
}

View File

@ -0,0 +1,43 @@
/*
* WorldEdit
* Copyright (C) 2012 sk89q <http://www.sk89q.com> and contributors
*
* 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/>.
*/
package com.sk89q.worldedit.bukkit.entity;
import com.sk89q.worldedit.Location;
import com.sk89q.worldedit.bukkit.BukkitUtil;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack;
import java.util.UUID;
/**
* @author zml2008
*/
public class BukkitItem extends BukkitEntity {
private final ItemStack stack;
public BukkitItem(Location loc, ItemStack stack, UUID entityId) {
super(loc, EntityType.DROPPED_ITEM, entityId);
this.stack = stack;
}
@Override
public boolean spawn(Location weLoc) {
org.bukkit.Location loc = BukkitUtil.toLocation(weLoc);
return loc.getWorld().dropItem(loc, stack) != null;
}
}

View File

@ -0,0 +1,52 @@
/*
* WorldEdit
* Copyright (C) 2012 sk89q <http://www.sk89q.com> and contributors
*
* 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/>.
*/
package com.sk89q.worldedit.bukkit.entity;
import com.sk89q.worldedit.Location;
import com.sk89q.worldedit.bukkit.BukkitUtil;
import org.bukkit.Art;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Painting;
import java.util.UUID;
/**
* @author zml2008
*/
public class BukkitPainting extends BukkitEntity {
private final Art art;
private final BlockFace facingDirection;
public BukkitPainting(Location loc, Art art, BlockFace facingDirection, UUID entityId) {
super(loc, EntityType.PAINTING, entityId);
this.art = art;
this.facingDirection = facingDirection;
}
public boolean spawn(Location weLoc) {
org.bukkit.Location loc = BukkitUtil.toLocation(weLoc);
Painting paint = loc.getWorld().spawn(loc, Painting.class);
if (paint != null) {
paint.setFacingDirection(facingDirection);
paint.setArt(art);
return true;
}
return false;
}
}

View File

@ -48,8 +48,12 @@ public class ClipboardCommands {
@Command(
aliases = { "/copy" },
usage = "",
flags = "e",
desc = "Copy the selection to the clipboard",
help = "Copy the selection to the clipboard\n" +
"Flags:\n" +
" -e controls whether entities are copied\n" +
"WARNING: Pasting entities cannot yet be undone!",
min = 0,
max = 0
)
@ -66,6 +70,11 @@ public class ClipboardCommands {
max.subtract(min).add(new Vector(1, 1, 1)),
min, min.subtract(pos));
clipboard.copy(editSession);
if (args.hasFlag('e')) {
for (LocalEntity entity : player.getWorld().getEntities(region)) {
clipboard.storeEntity(entity);
}
}
session.setClipboard(clipboard);
player.print("Block(s) copied.");
@ -75,6 +84,11 @@ public class ClipboardCommands {
aliases = { "/cut" },
usage = "[leave-id]",
desc = "Cut the selection to the clipboard",
help = "Copy the selection to the clipboard\n" +
"Flags:\n" +
" -e controls whether entities are copied\n" +
"WARNING: Cutting and pasting entities cannot yet be undone!",
flags = "e",
min = 0,
max = 1
)
@ -84,12 +98,13 @@ public class ClipboardCommands {
EditSession editSession) throws WorldEditException {
BaseBlock block = new BaseBlock(BlockID.AIR);
LocalWorld world = player.getWorld();
if (args.argsLength() > 0) {
block = we.getBlock(player, args.getString(0));
}
Region region = session.getSelection(player.getWorld());
Region region = session.getSelection(world);
Vector min = region.getMinimumPoint();
Vector max = region.getMaximumPoint();
Vector pos = session.getPlacementPosition(player);
@ -98,9 +113,16 @@ public class ClipboardCommands {
max.subtract(min).add(new Vector(1, 1, 1)),
min, min.subtract(pos));
clipboard.copy(editSession);
if (args.hasFlag('e')) {
LocalEntity[] entities = world.getEntities(region);
for (LocalEntity entity : entities) {
clipboard.storeEntity(entity);
}
world.killEntities(entities);
}
session.setClipboard(clipboard);
editSession.setBlocks(session.getSelection(player.getWorld()), block);
editSession.setBlocks(session.getSelection(world), block);
player.print("Block(s) cut.");
}
@ -128,11 +150,12 @@ public class ClipboardCommands {
if (atOrigin) {
Vector pos = session.getClipboard().getOrigin();
session.getClipboard().place(editSession, pos, pasteNoAir);
session.getClipboard().pasteEntities(pos);
player.findFreePosition();
player.print("Pasted to copy origin. Undo with //undo");
} else {
Vector pos = session.getPlacementPosition(player);
session.getClipboard().paste(editSession, pos, pasteNoAir);
session.getClipboard().paste(editSession, pos, pasteNoAir, true);
player.findFreePosition();
player.print("Pasted relative to you. Undo with //undo");
}

View File

@ -80,6 +80,11 @@ public class SchematicCommands {
return;
}
if (!format.isOfFormat(f)) {
player.printError(fileName + " is not of the " + format.getName() + " schematic format!");
return;
}
try {
String filePath = f.getCanonicalPath();
String dirPath = dir.getCanonicalPath();

View File

@ -0,0 +1,64 @@
/*
* WorldEdit
* Copyright (C) 2012 sk89q <http://www.sk89q.com> and contributors
*
* 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/>.
*/
package com.sk89q.worldedit.spout;
import com.sk89q.worldedit.LocalEntity;
import com.sk89q.worldedit.Location;
import org.spout.api.entity.Controller;
import org.spout.api.entity.Entity;
import org.spout.api.entity.type.ControllerType;
import org.spout.api.geo.World;
import org.spout.api.geo.discrete.Point;
/**
* @author zml2008
*/
public class SpoutEntity extends LocalEntity {
private final ControllerType type;
private final int entityId;
public SpoutEntity(Location position, int id, Controller controller) {
super(position);
type = controller.getType();
this.entityId = id;
}
public int getEntityId() {
return entityId;
}
@Override
public boolean spawn(Location loc) {
World world = ((SpoutWorld) loc.getWorld()).getWorld();
Point pos = SpoutUtil.toPoint(world, loc.getPosition());
Controller controller = type.createController();
if (controller == null) {
return false;
}
Entity e = world.createAndSpawnEntity(pos, controller);
if (e != null) {
e.setPitch(loc.getPitch());
e.setYaw(loc.getYaw());
// TODO: Copy datatable info
return true;
}
return false;
}
}

View File

@ -24,9 +24,11 @@ package com.sk89q.worldedit.spout;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.BlockWorldVector;
import com.sk89q.worldedit.LocalWorld;
import com.sk89q.worldedit.Location;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldVector;
import org.spout.api.Game;
import org.spout.api.entity.Entity;
import org.spout.api.geo.World;
import org.spout.api.geo.cuboid.Block;
import org.spout.api.geo.discrete.Point;
@ -105,4 +107,8 @@ public class SpoutUtil {
public static World toWorld(WorldVector pt) {
return ((SpoutWorld) pt.getWorld()).getWorld();
}
public static Location toLocation(Entity ent) {
return new Location(getLocalWorld(ent.getWorld()), toVector(ent.getPosition()), ent.getYaw(), ent.getPitch());
}
}

View File

@ -25,6 +25,7 @@ import com.sk89q.worldedit.BiomeType;
import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.EntityType;
import com.sk89q.worldedit.LocalEntity;
import com.sk89q.worldedit.LocalWorld;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector;
@ -49,6 +50,9 @@ import org.spout.vanilla.controller.object.projectile.Arrow;
import org.spout.vanilla.controller.object.vehicle.Boat;
import org.spout.vanilla.controller.object.vehicle.Minecart;
import java.util.ArrayList;
import java.util.List;
public class SpoutWorld extends LocalWorld {
private World world;
@ -732,4 +736,35 @@ public class SpoutWorld extends LocalWorld {
*/
return false;
}
@Override
public SpoutEntity[] getEntities(Region region) {
List<SpoutEntity> entities = new ArrayList<SpoutEntity>();
for (Vector pt : region.getChunkCubes()) {
Chunk chunk = world.getChunk(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ(), false);
if (chunk == null) {
continue;
}
for (Entity ent : chunk.getEntities()) {
if (region.contains(SpoutUtil.toVector(ent.getPosition()))) {
entities.add(new SpoutEntity(SpoutUtil.toLocation(ent), ent.getId(), ent.getController()));
}
}
}
return entities.toArray(new SpoutEntity[entities.size()]);
}
@Override
public int killEntities(LocalEntity[] entities) {
int amount = 0;
for (LocalEntity weEnt : entities) {
SpoutEntity entity = (SpoutEntity) weEnt;
Entity spoutEntity = world.getEntity(entity.getEntityId());
if (spoutEntity != null) {
spoutEntity.kill();
++amount;
}
}
return amount;
}
}