mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2025-07-12 08:18:35 +00:00
Add new Bukkit implementation adapter system to access MC internals.
Replaces the old NMSBlocks.
This commit is contained in:
@ -98,6 +98,21 @@ final class BukkitAdapter {
|
||||
(float) Math.toDegrees(location.getPitch()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Bukkit location from a WorldEdit position with a Bukkit world.
|
||||
*
|
||||
* @param world the Bukkit world
|
||||
* @param position the WorldEdit position
|
||||
* @return a Bukkit location
|
||||
*/
|
||||
public static org.bukkit.Location adapt(org.bukkit.World world, Vector position) {
|
||||
checkNotNull(world);
|
||||
checkNotNull(position);
|
||||
return new org.bukkit.Location(
|
||||
world,
|
||||
position.getX(), position.getY(), position.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WorldEdit entity from a Bukkit entity.
|
||||
*
|
||||
|
@ -31,36 +31,23 @@ import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.blocks.BlockID;
|
||||
import com.sk89q.worldedit.blocks.ContainerBlock;
|
||||
import com.sk89q.worldedit.blocks.FurnaceBlock;
|
||||
import com.sk89q.worldedit.blocks.LazyBlock;
|
||||
import com.sk89q.worldedit.blocks.MobSpawnerBlock;
|
||||
import com.sk89q.worldedit.blocks.NoteBlock;
|
||||
import com.sk89q.worldedit.blocks.SignBlock;
|
||||
import com.sk89q.worldedit.blocks.SkullBlock;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.Enums;
|
||||
import com.sk89q.worldedit.util.TreeGenerator;
|
||||
import com.sk89q.worldedit.world.registry.LegacyWorldData;
|
||||
import com.sk89q.worldedit.world.registry.WorldData;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Effect;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.SkullType;
|
||||
import org.bukkit.TreeType;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.Chest;
|
||||
import org.bukkit.block.CreatureSpawner;
|
||||
import org.bukkit.block.Furnace;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.block.Skull;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Ambient;
|
||||
import org.bukkit.entity.Animals;
|
||||
import org.bukkit.entity.Boat;
|
||||
@ -82,15 +69,9 @@ import org.bukkit.entity.Villager;
|
||||
import org.bukkit.inventory.DoubleChestInventory;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
@ -107,118 +88,26 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
public class BukkitWorld extends LocalWorld {
|
||||
|
||||
private static final Logger logger = WorldEdit.logger;
|
||||
private final WeakReference<World> worldRef;
|
||||
private static boolean skipNmsAccess = false;
|
||||
private static boolean skipNmsSafeSet = false;
|
||||
private static boolean skipNmsValidBlockCheck = false;
|
||||
private static final org.bukkit.entity.EntityType tntMinecartType =
|
||||
Enums.findByValue(org.bukkit.entity.EntityType.class, "MINECART_TNT");
|
||||
|
||||
/*
|
||||
* holder for the nmsblock class that we should use
|
||||
*/
|
||||
private static Class<? extends NmsBlock> nmsBlockType;
|
||||
private static Method nmsSetMethod;
|
||||
private static Method nmsValidBlockMethod;
|
||||
private static Method nmsGetMethod;
|
||||
private static Method nmsSetSafeMethod;
|
||||
|
||||
// copied from WG
|
||||
private static <T extends Enum<T>> T tryEnum(Class<T> enumType, String ... values) {
|
||||
for (String val : values) {
|
||||
try {
|
||||
return Enum.valueOf(enumType, val);
|
||||
} catch (IllegalArgumentException e) {}
|
||||
private static final Map<Integer, Effect> effects = new HashMap<Integer, Effect>();
|
||||
static {
|
||||
for (Effect effect : Effect.values()) {
|
||||
effects.put(effect.getId(), effect);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private static org.bukkit.entity.EntityType tntMinecartType;
|
||||
private static boolean checkMinecartType = true;
|
||||
|
||||
private final WeakReference<World> worldRef;
|
||||
|
||||
/**
|
||||
* Construct the object.
|
||||
* @param world
|
||||
*
|
||||
* @param world the world
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public BukkitWorld(World world) {
|
||||
this.worldRef = new WeakReference<World>(world);
|
||||
|
||||
if (checkMinecartType) {
|
||||
tntMinecartType = tryEnum(org.bukkit.entity.EntityType.class, "MINECART_TNT");
|
||||
checkMinecartType = false;
|
||||
}
|
||||
// check if we have a class we can use for nms access
|
||||
|
||||
// only run once per server startup
|
||||
if (nmsBlockType != null || skipNmsAccess || skipNmsSafeSet || skipNmsValidBlockCheck) return;
|
||||
Plugin plugin = Bukkit.getPluginManager().getPlugin("WorldEdit");
|
||||
if (!(plugin instanceof WorldEditPlugin)) return; // hopefully never happens
|
||||
WorldEditPlugin wePlugin = ((WorldEditPlugin) plugin);
|
||||
File nmsBlocksDir = new File(wePlugin.getDataFolder() + File.separator + "nmsblocks" + File.separator);
|
||||
if (nmsBlocksDir.listFiles() == null) { // no files to use
|
||||
skipNmsAccess = true; skipNmsSafeSet = true; skipNmsValidBlockCheck = true;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// make a classloader that can handle our blocks
|
||||
NmsBlockClassLoader loader = new NmsBlockClassLoader(BukkitWorld.class.getClassLoader(), nmsBlocksDir);
|
||||
String filename;
|
||||
for (File f : nmsBlocksDir.listFiles()) {
|
||||
if (!f.isFile()) continue;
|
||||
filename = f.getName();
|
||||
// load class using magic keyword
|
||||
Class<?> testBlock = null;
|
||||
try {
|
||||
testBlock = loader.loadClass("CL-NMS" + filename);
|
||||
} catch (Throwable e) {
|
||||
// someone is putting things where they don't belong
|
||||
continue;
|
||||
}
|
||||
filename = filename.replaceFirst(".class$", ""); // get rid of extension
|
||||
if (NmsBlock.class.isAssignableFrom(testBlock)) {
|
||||
// got a NmsBlock, test it now
|
||||
Class<? extends NmsBlock> nmsClass = (Class<? extends NmsBlock>) testBlock;
|
||||
boolean canUse = false;
|
||||
try {
|
||||
canUse = (Boolean) nmsClass.getMethod("verify").invoke(null);
|
||||
} catch (Throwable e) {
|
||||
continue;
|
||||
}
|
||||
if (!canUse) continue; // not for this server
|
||||
nmsBlockType = nmsClass;
|
||||
nmsSetMethod = nmsBlockType.getMethod("set", World.class, Vector.class, BaseBlock.class);
|
||||
nmsValidBlockMethod = nmsBlockType.getMethod("isValidBlockType", int.class);
|
||||
nmsGetMethod = nmsBlockType.getMethod("get", World.class, Vector.class, int.class, int.class);
|
||||
nmsSetSafeMethod = nmsBlockType.getMethod("setSafely",
|
||||
BukkitWorld.class, Vector.class, com.sk89q.worldedit.foundation.Block.class, boolean.class);
|
||||
// phew
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nmsBlockType != null) {
|
||||
logger.info("[WorldEdit] Using external NmsBlock for this version: " + nmsBlockType.getName());
|
||||
} else {
|
||||
// try our default
|
||||
try {
|
||||
nmsBlockType = (Class<? extends NmsBlock>) Class.forName("com.sk89q.worldedit.bukkit.DefaultNmsBlock");
|
||||
boolean canUse = (Boolean) nmsBlockType.getMethod("verify").invoke(null);
|
||||
if (canUse) {
|
||||
nmsSetMethod = nmsBlockType.getMethod("set", World.class, Vector.class, BaseBlock.class);
|
||||
nmsValidBlockMethod = nmsBlockType.getMethod("isValidBlockType", int.class);
|
||||
nmsGetMethod = nmsBlockType.getMethod("get", World.class, Vector.class, int.class, int.class);
|
||||
nmsSetSafeMethod = nmsBlockType.getMethod("setSafely",
|
||||
BukkitWorld.class, Vector.class, com.sk89q.worldedit.foundation.Block.class, boolean.class);
|
||||
logger.info("[WorldEdit] Using inbuilt NmsBlock for this version.");
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
// OMG DEVS WAI U NO SUPPORT <xyz> SERVER
|
||||
skipNmsAccess = true; skipNmsSafeSet = true; skipNmsValidBlockCheck = true;
|
||||
logger.warning("[WorldEdit] No compatible nms block class found.");
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
logger.warning("[WorldEdit] Unable to load NmsBlock classes, make sure they are installed correctly.");
|
||||
e.printStackTrace();
|
||||
skipNmsAccess = true; skipNmsSafeSet = true; skipNmsValidBlockCheck = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -256,41 +145,6 @@ public class BukkitWorld extends LocalWorld {
|
||||
throw new UnsupportedOperationException("Not implemented yet");
|
||||
}
|
||||
|
||||
private class NmsBlockClassLoader extends ClassLoader {
|
||||
public File searchDir;
|
||||
public NmsBlockClassLoader(ClassLoader parent, File searchDir) {
|
||||
super(parent);
|
||||
this.searchDir = searchDir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> loadClass(String name) throws ClassNotFoundException {
|
||||
if (!name.startsWith("CL-NMS")) {
|
||||
return super.loadClass(name);
|
||||
} else {
|
||||
name = name.replace("CL-NMS", ""); // hacky lol
|
||||
}
|
||||
try {
|
||||
URL url = new File(searchDir, name).toURI().toURL();
|
||||
InputStream input = url.openConnection().getInputStream();
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
|
||||
int data = input.read();
|
||||
while (data != -1) {
|
||||
buffer.write(data);
|
||||
data = input.read();
|
||||
}
|
||||
input.close();
|
||||
|
||||
byte[] classData = buffer.toByteArray();
|
||||
|
||||
return defineClass(name.replaceFirst(".class$", ""), classData, 0, classData.length);
|
||||
} catch (Throwable e) {
|
||||
throw new ClassNotFoundException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the world handle.
|
||||
*
|
||||
@ -318,66 +172,6 @@ public class BukkitWorld extends LocalWorld {
|
||||
return getWorld().getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set block type.
|
||||
*
|
||||
* @param pt
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean setBlockType(Vector pt, int type) {
|
||||
return getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setTypeId(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set block type.
|
||||
*
|
||||
* @param pt
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean setBlockTypeFast(Vector pt, int type) {
|
||||
return getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setTypeId(type, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setTypeIdAndData(Vector pt, int type, int data) {
|
||||
return getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setTypeIdAndData(type, (byte) data, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setTypeIdAndDataFast(Vector pt, int type, int data) {
|
||||
return getWorld().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 getWorld().getBlockTypeIdAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlockData(Vector pt, int data) {
|
||||
getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setData((byte) data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlockDataFast(Vector pt, int data) {
|
||||
getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setData((byte) data, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockData(Vector pt) {
|
||||
return getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).getData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockLightLevel(Vector pt) {
|
||||
return getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).getLightLevel();
|
||||
@ -423,7 +217,7 @@ public class BukkitWorld extends LocalWorld {
|
||||
try {
|
||||
getWorld().regenerateChunk(chunk.getBlockX(), chunk.getBlockZ());
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
logger.log(Level.WARNING, "Chunk generation via Bukkit raised an error", t);
|
||||
}
|
||||
|
||||
// Then restore
|
||||
@ -448,303 +242,6 @@ public class BukkitWorld extends LocalWorld {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean copyToWorld(Vector pt, BaseBlock block) {
|
||||
World world = getWorld();
|
||||
|
||||
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.setCreatureTypeByName(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;
|
||||
}
|
||||
|
||||
if (block instanceof SkullBlock) {
|
||||
// Skull 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.Skull)) return false;
|
||||
Skull bukkit = (Skull) state;
|
||||
SkullBlock we = (SkullBlock) block;
|
||||
// this is dumb
|
||||
SkullType skullType = SkullType.SKELETON;
|
||||
switch (we.getSkullType()) {
|
||||
case 0:
|
||||
skullType = SkullType.SKELETON;
|
||||
break;
|
||||
case 1:
|
||||
skullType = SkullType.WITHER;
|
||||
break;
|
||||
case 2:
|
||||
skullType = SkullType.ZOMBIE;
|
||||
break;
|
||||
case 3:
|
||||
skullType = SkullType.PLAYER;
|
||||
break;
|
||||
case 4:
|
||||
skullType = SkullType.CREEPER;
|
||||
break;
|
||||
}
|
||||
bukkit.setSkullType(skullType);
|
||||
BlockFace rotation;
|
||||
switch (we.getRot()) {
|
||||
// soooo dumb
|
||||
case 0:
|
||||
rotation = BlockFace.NORTH;
|
||||
break;
|
||||
case 1:
|
||||
rotation = BlockFace.NORTH_NORTH_EAST;
|
||||
break;
|
||||
case 2:
|
||||
rotation = BlockFace.NORTH_EAST;
|
||||
break;
|
||||
case 3:
|
||||
rotation = BlockFace.EAST_NORTH_EAST;
|
||||
break;
|
||||
case 4:
|
||||
rotation = BlockFace.EAST;
|
||||
break;
|
||||
case 5:
|
||||
rotation = BlockFace.EAST_SOUTH_EAST;
|
||||
break;
|
||||
case 6:
|
||||
rotation = BlockFace.SOUTH_EAST;
|
||||
break;
|
||||
case 7:
|
||||
rotation = BlockFace.SOUTH_SOUTH_EAST;
|
||||
break;
|
||||
case 8:
|
||||
rotation = BlockFace.SOUTH;
|
||||
break;
|
||||
case 9:
|
||||
rotation = BlockFace.SOUTH_SOUTH_WEST;
|
||||
break;
|
||||
case 10:
|
||||
rotation = BlockFace.SOUTH_WEST;
|
||||
break;
|
||||
case 11:
|
||||
rotation = BlockFace.WEST_SOUTH_WEST;
|
||||
break;
|
||||
case 12:
|
||||
rotation = BlockFace.WEST;
|
||||
break;
|
||||
case 13:
|
||||
rotation = BlockFace.WEST_NORTH_WEST;
|
||||
break;
|
||||
case 14:
|
||||
rotation = BlockFace.NORTH_WEST;
|
||||
break;
|
||||
case 15:
|
||||
rotation = BlockFace.NORTH_NORTH_WEST;
|
||||
break;
|
||||
default:
|
||||
rotation = BlockFace.NORTH;
|
||||
break;
|
||||
}
|
||||
bukkit.setRotation(rotation);
|
||||
if (we.getOwner() != null && !we.getOwner().isEmpty()) bukkit.setOwner(we.getOwner());
|
||||
bukkit.update(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!skipNmsAccess) {
|
||||
try {
|
||||
return (Boolean) nmsSetMethod.invoke(null, world, pt, block);
|
||||
} catch (Throwable t) {
|
||||
logger.log(Level.WARNING, "WorldEdit: Failed to do NMS access for direct NBT data copy", t);
|
||||
skipNmsAccess = true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean copyFromWorld(Vector pt, BaseBlock block) {
|
||||
World world = getWorld();
|
||||
|
||||
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.getCreatureTypeName());
|
||||
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 true;
|
||||
}
|
||||
|
||||
if (block instanceof SkullBlock) {
|
||||
// Skull 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.Skull)) return false;
|
||||
Skull bukkit = (Skull) state;
|
||||
SkullBlock we = (SkullBlock) block;
|
||||
byte skullType = 0;
|
||||
switch (bukkit.getSkullType()) {
|
||||
// this is dumb but whoever wrote the class is stupid
|
||||
case SKELETON:
|
||||
skullType = 0;
|
||||
break;
|
||||
case WITHER:
|
||||
skullType = 1;
|
||||
break;
|
||||
case ZOMBIE:
|
||||
skullType = 2;
|
||||
break;
|
||||
case PLAYER:
|
||||
skullType = 3;
|
||||
break;
|
||||
case CREEPER:
|
||||
skullType = 4;
|
||||
break;
|
||||
}
|
||||
we.setSkullType(skullType);
|
||||
byte rot = 0;
|
||||
switch (bukkit.getRotation()) {
|
||||
// this is even more dumb, hurray for copy/paste
|
||||
case NORTH:
|
||||
rot = (byte) 0;
|
||||
break;
|
||||
case NORTH_NORTH_EAST:
|
||||
rot = (byte) 1;
|
||||
break;
|
||||
case NORTH_EAST:
|
||||
rot = (byte) 2;
|
||||
break;
|
||||
case EAST_NORTH_EAST:
|
||||
rot = (byte) 3;
|
||||
break;
|
||||
case EAST:
|
||||
rot = (byte) 4;
|
||||
break;
|
||||
case EAST_SOUTH_EAST:
|
||||
rot = (byte) 5;
|
||||
break;
|
||||
case SOUTH_EAST:
|
||||
rot = (byte) 6;
|
||||
break;
|
||||
case SOUTH_SOUTH_EAST:
|
||||
rot = (byte) 7;
|
||||
break;
|
||||
case SOUTH:
|
||||
rot = (byte) 8;
|
||||
break;
|
||||
case SOUTH_SOUTH_WEST:
|
||||
rot = (byte) 9;
|
||||
break;
|
||||
case SOUTH_WEST:
|
||||
rot = (byte) 10;
|
||||
break;
|
||||
case WEST_SOUTH_WEST:
|
||||
rot = (byte) 11;
|
||||
break;
|
||||
case WEST:
|
||||
rot = (byte) 12;
|
||||
break;
|
||||
case WEST_NORTH_WEST:
|
||||
rot = (byte) 13;
|
||||
break;
|
||||
case NORTH_WEST:
|
||||
rot = (byte) 14;
|
||||
break;
|
||||
case NORTH_NORTH_WEST:
|
||||
rot = (byte) 15;
|
||||
break;
|
||||
}
|
||||
we.setRot(rot);
|
||||
we.setOwner(bukkit.hasOwner() ? bukkit.getOwner() : "");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the single block inventory for a potentially double chest.
|
||||
* Handles people who have an old version of Bukkit.
|
||||
@ -1032,159 +529,9 @@ public class BukkitWorld extends LocalWorld {
|
||||
return num;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a sign's text.
|
||||
*
|
||||
* @param pt
|
||||
* @param text
|
||||
* @return
|
||||
*/
|
||||
private boolean setSignText(Vector pt, String[] text) {
|
||||
World world = getWorld();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a sign's text.
|
||||
*
|
||||
* @param pt
|
||||
* @return
|
||||
*/
|
||||
private String[] getSignText(Vector pt) {
|
||||
World world = getWorld();
|
||||
|
||||
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 : "",
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a container block's contents.
|
||||
*
|
||||
* @param pt
|
||||
* @return
|
||||
*/
|
||||
private BaseItemStack[] getContainerBlockContents(Vector pt) {
|
||||
Block block = getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
|
||||
if (block == null) {
|
||||
return new BaseItemStack[0];
|
||||
}
|
||||
BlockState state = block.getState();
|
||||
if (!(state instanceof org.bukkit.inventory.InventoryHolder)) {
|
||||
return new BaseItemStack[0];
|
||||
}
|
||||
|
||||
org.bukkit.inventory.InventoryHolder container = (org.bukkit.inventory.InventoryHolder) state;
|
||||
Inventory inven = container.getInventory();
|
||||
if (container instanceof Chest) {
|
||||
inven = getBlockInventory((Chest) container);
|
||||
}
|
||||
int size = inven.getSize();
|
||||
BaseItemStack[] contents = new BaseItemStack[size];
|
||||
|
||||
for (int i = 0; i < size; ++i) {
|
||||
ItemStack bukkitStack = inven.getItem(i);
|
||||
if (bukkitStack != null && bukkitStack.getTypeId() > 0) {
|
||||
contents[i] = new BaseItemStack(
|
||||
bukkitStack.getTypeId(),
|
||||
bukkitStack.getAmount(),
|
||||
bukkitStack.getDurability());
|
||||
try {
|
||||
for (Map.Entry<Enchantment, Integer> entry : bukkitStack.getEnchantments().entrySet()) {
|
||||
contents[i].getEnchantments().put(entry.getKey().getId(), entry.getValue());
|
||||
}
|
||||
} catch (Throwable ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
return contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a container block's contents.
|
||||
*
|
||||
* @param pt
|
||||
* @param contents
|
||||
* @return
|
||||
*/
|
||||
private boolean setContainerBlockContents(Vector pt, BaseItemStack[] contents) {
|
||||
Block block = getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
|
||||
if (block == null) {
|
||||
return false;
|
||||
}
|
||||
BlockState state = block.getState();
|
||||
if (!(state instanceof org.bukkit.inventory.InventoryHolder)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
org.bukkit.inventory.InventoryHolder chest = (org.bukkit.inventory.InventoryHolder) state;
|
||||
Inventory inven = chest.getInventory();
|
||||
if (chest instanceof Chest) {
|
||||
inven = getBlockInventory((Chest) chest);
|
||||
}
|
||||
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(),
|
||||
contents[i].getData());
|
||||
try {
|
||||
for (Map.Entry<Integer, Integer> 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a block has a valid ID.
|
||||
*
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public boolean isValidBlockType(int type) {
|
||||
if (!skipNmsValidBlockCheck) {
|
||||
try {
|
||||
return (Boolean) nmsValidBlockMethod.invoke(null, type);
|
||||
} catch (Throwable e) {
|
||||
skipNmsValidBlockCheck = true;
|
||||
}
|
||||
}
|
||||
return Material.getMaterial(type) != null && Material.getMaterial(type).isBlock();
|
||||
}
|
||||
|
||||
@ -1228,13 +575,6 @@ public class BukkitWorld extends LocalWorld {
|
||||
}
|
||||
}
|
||||
|
||||
private static final Map<Integer, Effect> effects = new HashMap<Integer, Effect>();
|
||||
static {
|
||||
for (Effect effect : Effect.values()) {
|
||||
effects.put(effect.getId(), effect);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean playEffect(Vector position, int type, int data) {
|
||||
World world = getWorld();
|
||||
@ -1278,38 +618,25 @@ public class BukkitWorld extends LocalWorld {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getBlock(Vector pt) {
|
||||
int type = getBlockType(pt);
|
||||
int data = getBlockData(pt);
|
||||
|
||||
switch (type) {
|
||||
case BlockID.WALL_SIGN:
|
||||
case BlockID.SIGN_POST:
|
||||
//case BlockID.CHEST: // Prevent data loss for now
|
||||
//case BlockID.FURNACE:
|
||||
//case BlockID.BURNING_FURNACE:
|
||||
//case BlockID.DISPENSER:
|
||||
//case BlockID.MOB_SPAWNER:
|
||||
case BlockID.NOTE_BLOCK:
|
||||
case BlockID.HEAD:
|
||||
return super.getBlock(pt);
|
||||
default:
|
||||
if (!skipNmsAccess) {
|
||||
try {
|
||||
NmsBlock block = null;
|
||||
block = (NmsBlock) nmsGetMethod.invoke(null, getWorld(), pt, type, data);
|
||||
if (block != null) {
|
||||
return block;
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
logger.log(Level.WARNING,
|
||||
"WorldEdit: Failed to do NMS access for direct NBT data copy", t);
|
||||
skipNmsAccess = true;
|
||||
}
|
||||
}
|
||||
public BaseBlock getBlock(Vector position) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
if (adapter != null) {
|
||||
return adapter.getBlock(BukkitAdapter.adapt(getWorld(), position));
|
||||
} else {
|
||||
Block bukkitBlock = getWorld().getBlockAt(position.getBlockX(), position.getBlockY(), position.getBlockZ());
|
||||
return new BaseBlock(bukkitBlock.getTypeId(), bukkitBlock.getData());
|
||||
}
|
||||
}
|
||||
|
||||
return super.getBlock(pt);
|
||||
@Override
|
||||
public boolean setBlock(Vector position, BaseBlock block, boolean notifyAndLight) throws WorldEditException {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
if (adapter != null) {
|
||||
return adapter.setBlock(BukkitAdapter.adapt(getWorld(), position), block, notifyAndLight);
|
||||
} else {
|
||||
Block bukkitBlock = getWorld().getBlockAt(position.getBlockX(), position.getBlockY(), position.getBlockZ());
|
||||
return bukkitBlock.setTypeIdAndData(block.getType(), (byte) block.getData(), notifyAndLight);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@ -1320,20 +647,6 @@ public class BukkitWorld extends LocalWorld {
|
||||
return new LazyBlock(bukkitBlock.getTypeId(), bukkitBlock.getData(), this, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(Vector pt, BaseBlock block, boolean notifyAdjacent) throws WorldEditException {
|
||||
if (!skipNmsSafeSet) {
|
||||
try {
|
||||
return (Boolean) nmsSetSafeMethod.invoke(null, this, pt, block, notifyAdjacent);
|
||||
} catch (Throwable t) {
|
||||
logger.log(Level.WARNING, "WorldEdit: Failed to do NMS safe block set", t);
|
||||
skipNmsSafeSet = true;
|
||||
}
|
||||
}
|
||||
|
||||
return super.setBlock(pt, block, notifyAdjacent);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #setBlock(Vector, BaseBlock, boolean)}
|
||||
*/
|
||||
|
@ -1,472 +0,0 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser 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 Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.bukkit;
|
||||
import com.sk89q.jnbt.*;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.blocks.TileEntityBlock;
|
||||
import com.sk89q.worldedit.world.DataException;
|
||||
import com.sk89q.worldedit.foundation.Block;
|
||||
import net.minecraft.server.v1_7_R3.*;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.craftbukkit.v1_7_R3.CraftWorld;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* A blind handler of blocks with TileEntity data that directly access Minecraft's
|
||||
* classes through CraftBukkit.
|
||||
* </p>
|
||||
* Usage of this class may break terribly in the future, and therefore usage should
|
||||
* be trapped in a handler for {@link Throwable}.
|
||||
*/
|
||||
public class DefaultNmsBlock extends NmsBlock {
|
||||
|
||||
private static final Logger logger = WorldEdit.logger;
|
||||
private static Field compoundMapField;
|
||||
private static final Field nmsBlock_isTileEntityField; // The field is deobfuscated but the method isn't. No idea why.
|
||||
private NBTTagCompound nbtData = null;
|
||||
|
||||
static {
|
||||
Field field;
|
||||
try {
|
||||
field = net.minecraft.server.v1_7_R3.Block.class.getDeclaredField("isTileEntity");
|
||||
field.setAccessible(true);
|
||||
} catch (NoSuchFieldException e) {
|
||||
// logger.severe("Could not find NMS block tile entity field!");
|
||||
field = null;
|
||||
}
|
||||
nmsBlock_isTileEntityField = field;
|
||||
}
|
||||
|
||||
public static boolean verify() {
|
||||
return nmsBlock_isTileEntityField != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance with a given type ID, data value, and previous
|
||||
* {@link TileEntityBlock}-implementing object.
|
||||
*
|
||||
* @param type block type ID
|
||||
* @param data data value
|
||||
* @param tileEntityBlock tile entity block
|
||||
*/
|
||||
public DefaultNmsBlock(int type, int data, TileEntityBlock tileEntityBlock) {
|
||||
super(type, data);
|
||||
|
||||
nbtData = (NBTTagCompound) fromNative(tileEntityBlock.getNbtData());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance with a given type ID, data value, and raw
|
||||
* {@link NBTTagCompound} copy.
|
||||
*
|
||||
* @param type block type ID
|
||||
* @param data data value
|
||||
* @param nbtData raw NBT data
|
||||
*/
|
||||
public DefaultNmsBlock(int type, int data, NBTTagCompound nbtData) {
|
||||
super(type, data);
|
||||
|
||||
this.nbtData = nbtData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a {@link NBTTagCompound} that has valid coordinates.
|
||||
*
|
||||
* @param pt coordinates to set
|
||||
* @return the tag compound
|
||||
*/
|
||||
private NBTTagCompound getNmsData(Vector pt) {
|
||||
if (nbtData == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
nbtData.set("x", new NBTTagInt(pt.getBlockX()));
|
||||
nbtData.set("y", new NBTTagInt(pt.getBlockY()));
|
||||
nbtData.set("z", new NBTTagInt(pt.getBlockZ()));
|
||||
|
||||
return nbtData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNbtData() {
|
||||
return nbtData != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNbtId() {
|
||||
if (nbtData == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return nbtData.getString("id");
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getNbtData() {
|
||||
if (nbtData == null) {
|
||||
return new CompoundTag(getNbtId(),
|
||||
new HashMap<String, Tag>());
|
||||
}
|
||||
return (CompoundTag) toNative(nbtData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNbtData(CompoundTag tag) {
|
||||
if (tag == null) {
|
||||
this.nbtData = null;
|
||||
}
|
||||
this.nbtData = (NBTTagCompound) fromNative(tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an instance from the given information.
|
||||
*
|
||||
* @param world world to get the block from
|
||||
* @param position position to get the block at
|
||||
* @param type type ID of block
|
||||
* @param data data value of block
|
||||
* @return the block, or null
|
||||
*/
|
||||
public static DefaultNmsBlock get(World world, Vector position, int type, int data) {
|
||||
if (!hasTileEntity(type)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TileEntity te = ((CraftWorld) world).getHandle().getTileEntity(
|
||||
position.getBlockX(), position.getBlockY(), position.getBlockZ());
|
||||
|
||||
if (te != null) {
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
te.b(tag); // Load data
|
||||
return new DefaultNmsBlock(type, data, tag);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an instance or a {@link TileEntityBlock} to the given position.
|
||||
*
|
||||
* @param world world to set the block in
|
||||
* @param position position to set the block at
|
||||
* @param block the block to set
|
||||
* @return true if tile entity data was copied to the world
|
||||
*/
|
||||
public static boolean set(World world, Vector position, BaseBlock block) {
|
||||
NBTTagCompound data = null;
|
||||
if (!hasTileEntity(world.getBlockTypeIdAt(position.getBlockX(), position.getBlockY(), position.getBlockZ()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (block instanceof DefaultNmsBlock) {
|
||||
DefaultNmsBlock nmsProxyBlock = (DefaultNmsBlock) block;
|
||||
data = nmsProxyBlock.getNmsData(position);
|
||||
} else if (block instanceof TileEntityBlock) {
|
||||
DefaultNmsBlock nmsProxyBlock = new DefaultNmsBlock(
|
||||
block.getId(), block.getData(), block);
|
||||
data = nmsProxyBlock.getNmsData(position);
|
||||
}
|
||||
|
||||
if (data != null) {
|
||||
TileEntity te = ((CraftWorld) world).getHandle().getTileEntity(
|
||||
position.getBlockX(), position.getBlockY(), position.getBlockZ());
|
||||
if (te != null) {
|
||||
te.a(data); // Load data
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to set a block 'safely', as in setting the block data to the location, and
|
||||
* then triggering physics only at the end.
|
||||
*
|
||||
* @param world world to set the block in
|
||||
* @param position position to set the block at
|
||||
* @param block the block to set
|
||||
* @param notifyAdjacent true to notify physics and what not
|
||||
* @return true if block id or data was changed
|
||||
*/
|
||||
public static boolean setSafely(BukkitWorld world, Vector position,
|
||||
Block block, boolean notifyAdjacent) {
|
||||
|
||||
int x = position.getBlockX();
|
||||
int y = position.getBlockY();
|
||||
int z = position.getBlockZ();
|
||||
|
||||
CraftWorld craftWorld = ((CraftWorld) world.getWorld());
|
||||
// TileEntity te = craftWorld.getHandle().getTileEntity(x, y, z);
|
||||
// craftWorld.getHandle().tileEntityList.remove(te);
|
||||
|
||||
boolean changed = craftWorld.getHandle().setTypeAndData(x, y, z, getNmsBlock(block.getId()), block.getData(), 0);
|
||||
|
||||
if (block instanceof BaseBlock) {
|
||||
world.copyToWorld(position, (BaseBlock) block);
|
||||
}
|
||||
|
||||
changed = craftWorld.getHandle().setData(x, y, z, block.getData(), 0) || changed;
|
||||
if (changed && notifyAdjacent) {
|
||||
craftWorld.getHandle().notify(x, y, z);
|
||||
craftWorld.getHandle().update(x, y, z, getNmsBlock(block.getId()));
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
public static boolean hasTileEntity(int type) {
|
||||
net.minecraft.server.v1_7_R3.Block nmsBlock = getNmsBlock(type);
|
||||
if (nmsBlock == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return nmsBlock_isTileEntityField.getBoolean(nmsBlock); // Once we have the field stord, gets are fast
|
||||
} catch (IllegalAccessException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static net.minecraft.server.v1_7_R3.Block getNmsBlock(int type) {
|
||||
return net.minecraft.server.v1_7_R3.Block.e(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts from a non-native NMS NBT structure to a native WorldEdit NBT
|
||||
* structure.
|
||||
*
|
||||
* @param foreign non-native NMS NBT structure
|
||||
* @return native WorldEdit NBT structure
|
||||
*/
|
||||
private static Tag toNative(NBTBase foreign) {
|
||||
// temporary fix since mojang removed names from tags
|
||||
// our nbt spec will need to be updated to theirs
|
||||
return toNative(getTagName(foreign.getTypeId()), foreign);
|
||||
}
|
||||
|
||||
// seriously these two methods are hacky - our jnbt spec needs updating
|
||||
// copied from NMS 1.7.5- code, since it was removed in 1.7.8
|
||||
private static String getTagName(int i) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
return "TAG_End";
|
||||
case 1:
|
||||
return "TAG_Byte";
|
||||
case 2:
|
||||
return "TAG_Short";
|
||||
case 3:
|
||||
return "TAG_Int";
|
||||
case 4:
|
||||
return "TAG_Long";
|
||||
case 5:
|
||||
return "TAG_Float";
|
||||
case 6:
|
||||
return "TAG_Double";
|
||||
case 7:
|
||||
return "TAG_Byte_Array";
|
||||
case 8:
|
||||
return "TAG_String";
|
||||
case 9:
|
||||
return "TAG_List";
|
||||
case 10:
|
||||
return "TAG_Compound";
|
||||
case 11:
|
||||
return "TAG_Int_Array";
|
||||
case 99:
|
||||
return "Any Numeric Tag";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts from a non-native NMS NBT structure to a native WorldEdit NBT
|
||||
* structure.
|
||||
*
|
||||
* @param foreign non-native NMS NBT structure
|
||||
* @param name name for the tag, if it has one
|
||||
* @return native WorldEdit NBT structure
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Tag toNative(String name, NBTBase foreign) {
|
||||
if (foreign == null) {
|
||||
return null;
|
||||
}
|
||||
if (foreign instanceof NBTTagCompound) {
|
||||
Map<String, Tag> values = new HashMap<String, Tag>();
|
||||
Collection<Object> foreignKeys = null;
|
||||
|
||||
if (compoundMapField == null) {
|
||||
try {
|
||||
// Method name may change!
|
||||
foreignKeys = ((NBTTagCompound) foreign).c();
|
||||
} catch (Throwable t) {
|
||||
try {
|
||||
logger.warning("WorldEdit: Couldn't get NBTTagCompound.c(), " +
|
||||
"so we're going to try to get at the 'map' field directly from now on");
|
||||
|
||||
if (compoundMapField == null) {
|
||||
compoundMapField = NBTTagCompound.class.getDeclaredField("map");
|
||||
compoundMapField.setAccessible(true);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
// Can't do much beyond this
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (compoundMapField != null) {
|
||||
try {
|
||||
foreignKeys = ((HashMap<Object, Object>) compoundMapField.get(foreign)).keySet();
|
||||
} catch (Throwable e) {
|
||||
// Can't do much beyond this
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
for (Object obj : foreignKeys) {
|
||||
String key = (String) obj;
|
||||
NBTBase base = (NBTBase) ((NBTTagCompound) foreign).get(key);
|
||||
values.put(key, toNative(key, base));
|
||||
}
|
||||
return new CompoundTag(name, values);
|
||||
} else if (foreign instanceof NBTTagByte) {
|
||||
return new ByteTag(name, ((NBTTagByte) foreign).f()); // getByte
|
||||
} else if (foreign instanceof NBTTagByteArray) {
|
||||
return new ByteArrayTag(name,
|
||||
((NBTTagByteArray) foreign).c()); // data
|
||||
} else if (foreign instanceof NBTTagDouble) {
|
||||
return new DoubleTag(name,
|
||||
((NBTTagDouble) foreign).g()); // getDouble
|
||||
} else if (foreign instanceof NBTTagFloat) {
|
||||
return new FloatTag(name, ((NBTTagFloat) foreign).h()); // getFloat
|
||||
} else if (foreign instanceof NBTTagInt) {
|
||||
return new IntTag(name, ((NBTTagInt) foreign).d()); // getInt
|
||||
} else if (foreign instanceof NBTTagIntArray) {
|
||||
return new IntArrayTag(name,
|
||||
((NBTTagIntArray) foreign).c()); // data
|
||||
} else if (foreign instanceof NBTTagList) {
|
||||
try {
|
||||
return transmorgifyList(name, (NBTTagList) foreign);
|
||||
} catch (NoSuchFieldException e) {
|
||||
} catch (SecurityException e) {
|
||||
} catch (IllegalArgumentException e) {
|
||||
} catch (IllegalAccessException e) {}
|
||||
return new ListTag(name, ByteTag.class, new ArrayList<ByteTag>());
|
||||
} else if (foreign instanceof NBTTagLong) {
|
||||
return new LongTag(name, ((NBTTagLong) foreign).c()); // getLong
|
||||
} else if (foreign instanceof NBTTagShort) {
|
||||
return new ShortTag(name, ((NBTTagShort) foreign).e()); // getShort
|
||||
} else if (foreign instanceof NBTTagString) {
|
||||
return new StringTag(name,
|
||||
((NBTTagString) foreign).a_()); // data
|
||||
} else if (foreign instanceof NBTTagEnd) {
|
||||
return new EndTag();
|
||||
} else {
|
||||
throw new IllegalArgumentException("Don't know how to make native "
|
||||
+ foreign.getClass().getCanonicalName());
|
||||
}
|
||||
}
|
||||
|
||||
private static ListTag transmorgifyList(String name, NBTTagList foreign)
|
||||
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
|
||||
List<Tag> values = new ArrayList<Tag>();
|
||||
int type = foreign.d();
|
||||
Field listField = NBTTagList.class.getDeclaredField("list");
|
||||
listField.setAccessible(true);
|
||||
List foreignList;
|
||||
foreignList = (List) listField.get(foreign);
|
||||
for (int i = 0; i < foreign.size(); i++) {
|
||||
NBTBase element = (NBTBase) foreignList.get(i);
|
||||
values.add(toNative(null, element)); // list elements shouldn't have names
|
||||
}
|
||||
Class<? extends Tag> cls = NBTConstants.getClassFromType(type);
|
||||
return new ListTag(name, cls, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a WorldEdit-native NBT structure to a NMS structure.
|
||||
*
|
||||
* @param foreign structure to convert
|
||||
* @return non-native structure
|
||||
*/
|
||||
private static NBTBase fromNative(Tag foreign) {
|
||||
if (foreign == null) {
|
||||
return null;
|
||||
}
|
||||
if (foreign instanceof CompoundTag) {
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
for (Map.Entry<String, Tag> entry : ((CompoundTag) foreign)
|
||||
.getValue().entrySet()) {
|
||||
tag.set(entry.getKey(), fromNative(entry.getValue()));
|
||||
}
|
||||
return tag;
|
||||
} else if (foreign instanceof ByteTag) {
|
||||
return new NBTTagByte(((ByteTag) foreign).getValue());
|
||||
} else if (foreign instanceof ByteArrayTag) {
|
||||
return new NBTTagByteArray(((ByteArrayTag) foreign).getValue());
|
||||
} else if (foreign instanceof DoubleTag) {
|
||||
return new NBTTagDouble(((DoubleTag) foreign).getValue());
|
||||
} else if (foreign instanceof FloatTag) {
|
||||
return new NBTTagFloat(((FloatTag) foreign).getValue());
|
||||
} else if (foreign instanceof IntTag) {
|
||||
return new NBTTagInt(((IntTag) foreign).getValue());
|
||||
} else if (foreign instanceof IntArrayTag) {
|
||||
return new NBTTagIntArray(((IntArrayTag) foreign).getValue());
|
||||
} else if (foreign instanceof ListTag) {
|
||||
NBTTagList tag = new NBTTagList();
|
||||
ListTag foreignList = (ListTag) foreign;
|
||||
for (Tag t : foreignList.getValue()) {
|
||||
tag.add(fromNative(t));
|
||||
}
|
||||
return tag;
|
||||
} else if (foreign instanceof LongTag) {
|
||||
return new NBTTagLong(((LongTag) foreign).getValue());
|
||||
} else if (foreign instanceof ShortTag) {
|
||||
return new NBTTagShort(((ShortTag) foreign).getValue());
|
||||
} else if (foreign instanceof StringTag) {
|
||||
return new NBTTagString(((StringTag) foreign).getValue());
|
||||
} else if (foreign instanceof EndTag) {
|
||||
try {
|
||||
Method tagMaker = NBTBase.class.getDeclaredMethod("createTag", byte.class);
|
||||
tagMaker.setAccessible(true);
|
||||
return (NBTBase) tagMaker.invoke(null, (byte) 0);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Don't know how to make NMS "
|
||||
+ foreign.getClass().getCanonicalName());
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isValidBlockType(int type) throws NoClassDefFoundError {
|
||||
return type == 0 || (type >= 1 && net.minecraft.server.v1_7_R3.Block.e(type) != null);
|
||||
}
|
||||
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser 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 Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.bukkit;
|
||||
|
||||
import org.bukkit.World;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.foundation.Block;
|
||||
|
||||
public abstract class NmsBlock extends BaseBlock {
|
||||
|
||||
protected NmsBlock(int type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
protected NmsBlock(int type, int data) {
|
||||
super(type, data);
|
||||
}
|
||||
|
||||
public static boolean verify() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static NmsBlock get(World world, Vector vector, int type, int data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean set(World world, Vector vector, Block block) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean setSafely(World world, Vector vector, Block block, boolean notify) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean hasTileEntity(int type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isValidBlockType(int type) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -22,7 +22,16 @@ package com.sk89q.worldedit.bukkit;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.sk89q.util.yaml.YAMLProcessor;
|
||||
import com.sk89q.wepif.PermissionsResolverManager;
|
||||
import com.sk89q.worldedit.*;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.IncompleteRegionException;
|
||||
import com.sk89q.worldedit.LocalPlayer;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.ServerInterface;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.WorldEditOperation;
|
||||
import com.sk89q.worldedit.bukkit.adapter.AdapterLoadException;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplLoader;
|
||||
import com.sk89q.worldedit.bukkit.selections.CuboidSelection;
|
||||
import com.sk89q.worldedit.bukkit.selections.CylinderSelection;
|
||||
import com.sk89q.worldedit.bukkit.selections.Polygonal2DSelection;
|
||||
@ -32,7 +41,11 @@ import com.sk89q.worldedit.event.platform.CommandSuggestionEvent;
|
||||
import com.sk89q.worldedit.event.platform.PlatformReadyEvent;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.extent.inventory.BlockBag;
|
||||
import com.sk89q.worldedit.regions.*;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.CylinderRegion;
|
||||
import com.sk89q.worldedit.regions.Polygonal2DRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.regions.RegionSelector;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@ -40,13 +53,20 @@ import org.bukkit.command.TabCompleter;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Enumeration;
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Plugin for Bukkit.
|
||||
*
|
||||
@ -54,27 +74,13 @@ import java.util.zip.ZipEntry;
|
||||
*/
|
||||
public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
|
||||
|
||||
/**
|
||||
* The name of the CUI's plugin channel registration
|
||||
*/
|
||||
private static final Logger log = Logger.getLogger(WorldEditPlugin.class.getCanonicalName());
|
||||
public static final String CUI_PLUGIN_CHANNEL = "WECUI";
|
||||
private static WorldEditPlugin INSTANCE;
|
||||
|
||||
/**
|
||||
* The server interface that all server-related API goes through.
|
||||
*/
|
||||
private BukkitImplAdapter bukkitAdapter;
|
||||
private BukkitServerInterface server;
|
||||
/**
|
||||
* Main WorldEdit instance.
|
||||
*/
|
||||
private WorldEdit controller;
|
||||
/**
|
||||
* Deprecated API.
|
||||
*/
|
||||
private WorldEditAPI api;
|
||||
|
||||
/**
|
||||
* Holds the configuration for WorldEdit.
|
||||
*/
|
||||
private final WorldEditAPI api = new WorldEditAPI(this);
|
||||
private BukkitConfiguration config;
|
||||
|
||||
/**
|
||||
@ -82,41 +88,27 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
|
||||
*/
|
||||
@Override
|
||||
public void onEnable() {
|
||||
final String pluginYmlVersion = getDescription().getVersion();
|
||||
final String manifestVersion = WorldEdit.getVersion();
|
||||
this.INSTANCE = this;
|
||||
|
||||
if (!manifestVersion.equalsIgnoreCase(pluginYmlVersion)) {
|
||||
WorldEdit.setVersion(manifestVersion + " (" + pluginYmlVersion + ")");
|
||||
}
|
||||
WorldEdit worldEdit = WorldEdit.getInstance();
|
||||
|
||||
// Make the data folders that WorldEdit uses
|
||||
getDataFolder().mkdirs();
|
||||
File targetDir = new File(getDataFolder() + File.separator + "nmsblocks");
|
||||
targetDir.mkdir();
|
||||
copyNmsBlockClasses(targetDir);
|
||||
loadAdapter(); // Need an adapter to work with special blocks with NBT data
|
||||
loadConfig(); // Load configuration
|
||||
PermissionsResolverManager.initialize(this); // Setup permission resolver
|
||||
|
||||
// Create the default configuration file
|
||||
createDefaultConfiguration("config.yml");
|
||||
|
||||
// Set up configuration and such, including the permissions
|
||||
// resolver
|
||||
config = new BukkitConfiguration(new YAMLProcessor(new File(getDataFolder(), "config.yml"), true), this);
|
||||
PermissionsResolverManager.initialize(this);
|
||||
|
||||
// Load the configuration
|
||||
config.load();
|
||||
|
||||
// Setup interfaces
|
||||
// Setup platform
|
||||
server = new BukkitServerInterface(this, getServer());
|
||||
controller = WorldEdit.getInstance();
|
||||
controller.getPlatformManager().register(server);
|
||||
api = new WorldEditAPI(this);
|
||||
worldEdit.getPlatformManager().register(server);
|
||||
|
||||
// Register CUI
|
||||
getServer().getMessenger().registerIncomingPluginChannel(this, CUI_PLUGIN_CHANNEL, new CUIChannelListener(this));
|
||||
getServer().getMessenger().registerOutgoingPluginChannel(this, CUI_PLUGIN_CHANNEL);
|
||||
// Now we can register events!
|
||||
|
||||
// Now we can register events
|
||||
getServer().getPluginManager().registerEvents(new WorldEditListener(this), this);
|
||||
|
||||
getServer().getScheduler().runTaskTimerAsynchronously(this, new SessionTimer(controller, getServer()), 120, 120);
|
||||
// Register session timer
|
||||
getServer().getScheduler().runTaskTimerAsynchronously(this, new SessionTimer(worldEdit, getServer()), 120, 120);
|
||||
|
||||
// If we are on MCPC+/Cauldron, then Forge will have already loaded
|
||||
// Forge WorldEdit and there's (probably) not going to be any other
|
||||
@ -124,31 +116,34 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
|
||||
WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent());
|
||||
}
|
||||
|
||||
private void copyNmsBlockClasses(File target) {
|
||||
private void loadConfig() {
|
||||
createDefaultConfiguration("config.yml"); // Create the default configuration file
|
||||
|
||||
config = new BukkitConfiguration(new YAMLProcessor(new File(getDataFolder(), "config.yml"), true), this);
|
||||
config.load();
|
||||
}
|
||||
|
||||
private void loadAdapter() {
|
||||
// Attempt to load a Bukkit adapter
|
||||
BukkitImplLoader adapterLoader = new BukkitImplLoader();
|
||||
|
||||
try {
|
||||
JarFile jar = new JarFile(getFile());
|
||||
@SuppressWarnings("rawtypes")
|
||||
Enumeration entries = jar.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
JarEntry jarEntry = (JarEntry) entries.nextElement();
|
||||
if (!jarEntry.getName().startsWith("nmsblocks") || jarEntry.isDirectory()) continue;
|
||||
adapterLoader.addFromPath(getClass().getClassLoader());
|
||||
} catch (IOException e) {
|
||||
log.log(Level.WARNING, "Failed to search path for Bukkit adapters");
|
||||
}
|
||||
|
||||
File file = new File(target + File.separator + jarEntry.getName().replace("nmsblocks", ""));
|
||||
if (file.exists()) continue;
|
||||
|
||||
InputStream is = jar.getInputStream(jarEntry);
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
|
||||
fos = new FileOutputStream(file);
|
||||
byte[] buf = new byte[8192];
|
||||
int length = 0;
|
||||
while ((length = is.read(buf)) > 0) {
|
||||
fos.write(buf, 0, length);
|
||||
}
|
||||
fos.close();
|
||||
is.close();
|
||||
}
|
||||
} catch (Throwable e) {}
|
||||
try {
|
||||
adapterLoader.addFromJar(getFile());
|
||||
} catch (IOException e) {
|
||||
log.log(Level.WARNING, "Failed to search " + getFile() + " for Bukkit adapters", e);
|
||||
}
|
||||
try {
|
||||
bukkitAdapter = adapterLoader.loadAdapter();
|
||||
log.log(Level.INFO, "Using " + bukkitAdapter.getClass().getCanonicalName() + " as the Bukkit adapter");
|
||||
} catch (AdapterLoadException e) {
|
||||
log.log(Level.WARNING, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -156,10 +151,13 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
|
||||
*/
|
||||
@Override
|
||||
public void onDisable() {
|
||||
if (controller != null) {
|
||||
controller.clearSessions();
|
||||
controller.getPlatformManager().unregister(server);
|
||||
WorldEdit worldEdit = WorldEdit.getInstance();
|
||||
worldEdit.clearSessions();
|
||||
worldEdit.getPlatformManager().unregister(server);
|
||||
if (config != null) {
|
||||
config.unload();
|
||||
}
|
||||
if (server != null) {
|
||||
server.unregisterCommands();
|
||||
}
|
||||
this.getServer().getScheduler().cancelTasks(this);
|
||||
@ -177,7 +175,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
|
||||
/**
|
||||
* Create a default configuration file from the .jar.
|
||||
*
|
||||
* @param name
|
||||
* @param name the filename
|
||||
*/
|
||||
protected void createDefaultConfiguration(String name) {
|
||||
File actual = new File(getDataFolder(), name);
|
||||
@ -257,7 +255,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
|
||||
* @return
|
||||
*/
|
||||
public LocalSession getSession(Player player) {
|
||||
return controller.getSession(wrapPlayer(player));
|
||||
return WorldEdit.getInstance().getSession(wrapPlayer(player));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -268,10 +266,10 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
|
||||
*/
|
||||
public EditSession createEditSession(Player player) {
|
||||
LocalPlayer wePlayer = wrapPlayer(player);
|
||||
LocalSession session = controller.getSession(wePlayer);
|
||||
LocalSession session = WorldEdit.getInstance().getSession(wePlayer);
|
||||
BlockBag blockBag = session.getBlockBag(wePlayer);
|
||||
|
||||
EditSession editSession = controller.getEditSessionFactory()
|
||||
EditSession editSession = WorldEdit.getInstance().getEditSessionFactory()
|
||||
.getEditSession(wePlayer.getWorld(), session.getBlockChangeLimit(), blockBag, wePlayer);
|
||||
editSession.enableQueue();
|
||||
|
||||
@ -286,12 +284,12 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
|
||||
*/
|
||||
public void remember(Player player, EditSession editSession) {
|
||||
LocalPlayer wePlayer = wrapPlayer(player);
|
||||
LocalSession session = controller.getSession(wePlayer);
|
||||
LocalSession session = WorldEdit.getInstance().getSession(wePlayer);
|
||||
|
||||
session.remember(editSession);
|
||||
editSession.flushQueue();
|
||||
|
||||
controller.flushBlockBag(wePlayer, editSession);
|
||||
WorldEdit.getInstance().flushBlockBag(wePlayer, editSession);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -301,10 +299,9 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
|
||||
* @param op
|
||||
* @throws Throwable
|
||||
*/
|
||||
public void perform(Player player, WorldEditOperation op)
|
||||
throws Throwable {
|
||||
public void perform(Player player, WorldEditOperation op) throws Throwable {
|
||||
LocalPlayer wePlayer = wrapPlayer(player);
|
||||
LocalSession session = controller.getSession(wePlayer);
|
||||
LocalSession session = WorldEdit.getInstance().getSession(wePlayer);
|
||||
|
||||
EditSession editSession = createEditSession(player);
|
||||
try {
|
||||
@ -379,7 +376,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
|
||||
* @return
|
||||
*/
|
||||
public WorldEdit getWorldEdit() {
|
||||
return controller;
|
||||
return WorldEdit.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -396,7 +393,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
|
||||
throw new IllegalArgumentException("Offline player not allowed");
|
||||
}
|
||||
|
||||
LocalSession session = controller.getSession(wrapPlayer(player));
|
||||
LocalSession session = WorldEdit.getInstance().getSession(wrapPlayer(player));
|
||||
RegionSelector selector = session.getRegionSelector(BukkitUtil.getLocalWorld(player.getWorld()));
|
||||
|
||||
try {
|
||||
@ -434,9 +431,30 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
|
||||
throw new IllegalArgumentException("Null selection not allowed");
|
||||
}
|
||||
|
||||
LocalSession session = controller.getSession(wrapPlayer(player));
|
||||
LocalSession session = WorldEdit.getInstance().getSession(wrapPlayer(player));
|
||||
RegionSelector sel = selection.getRegionSelector();
|
||||
session.setRegionSelector(BukkitUtil.getLocalWorld(player.getWorld()), sel);
|
||||
session.dispatchCUISelection(wrapPlayer(player));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance of this plugin.
|
||||
*
|
||||
* @return an instance of the plugin
|
||||
* @throws NullPointerException if the plugin hasn't been enabled
|
||||
*/
|
||||
static WorldEditPlugin getInstance() {
|
||||
return checkNotNull(INSTANCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Bukkit implementation adapter.
|
||||
*
|
||||
* @return the adapter
|
||||
*/
|
||||
@Nullable
|
||||
BukkitImplAdapter getBukkitImplAdapter() {
|
||||
return bukkitAdapter;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser 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 Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.bukkit.adapter;
|
||||
|
||||
/**
|
||||
* Thrown when no adapter can be found.
|
||||
*/
|
||||
public class AdapterLoadException extends Exception {
|
||||
|
||||
public AdapterLoadException() {
|
||||
}
|
||||
|
||||
public AdapterLoadException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public AdapterLoadException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public AdapterLoadException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser 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 Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.bukkit.adapter;
|
||||
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import org.bukkit.Location;
|
||||
|
||||
/**
|
||||
* An interface for adapters of various Bukkit implementations.
|
||||
*/
|
||||
public interface BukkitImplAdapter {
|
||||
|
||||
/**
|
||||
* Get the block at the given location.
|
||||
*
|
||||
* @param location the location
|
||||
* @return the block
|
||||
*/
|
||||
BaseBlock getBlock(Location location);
|
||||
|
||||
/**
|
||||
* Set the block at the given location.
|
||||
*
|
||||
* @param location the location
|
||||
* @param state the block
|
||||
* @param notifyAndLight notify and light if set
|
||||
* @return true if a block was likely changed
|
||||
*/
|
||||
boolean setBlock(Location location, BaseBlock state, boolean notifyAndLight);
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,197 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser 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 Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.bukkit.adapter;
|
||||
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.util.io.Closer;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Loads Bukkit implementation adapters.
|
||||
*/
|
||||
public class BukkitImplLoader {
|
||||
|
||||
private static final Logger log = Logger.getLogger(BukkitImplLoader.class.getCanonicalName());
|
||||
private final List<String> adapterCandidates = new ArrayList<String>();
|
||||
private String customCandidate;
|
||||
|
||||
private static final String SEARCH_PACKAGE = "com.sk89q.worldedit.bukkit.adapter.impl";
|
||||
private static final String SEARCH_PACKAGE_DOT = SEARCH_PACKAGE + ".";
|
||||
private static final String SEARCH_PATH = SEARCH_PACKAGE.replace(".", "/");
|
||||
private static final String CLASS_SUFFIX = ".class";
|
||||
|
||||
private static final String LOAD_ERROR_MESSAGE =
|
||||
"Failed to find an adapter for Bukkit!\n\n" +
|
||||
"This version of WorldEdit (%s) does not fully support your version of Bukkit (%s).\n\n" +
|
||||
"What this means:\n" +
|
||||
"1) Block operations will work, but chests will be empty, signs will be blank, and so on.\n" +
|
||||
"2) You won't be able to save and load chests, signs, etc. with .schematic files.\n" +
|
||||
"3) You won't be able to work with entities properly.\n" +
|
||||
"4) Undo will will not be able to restore chests, signs, and etc.\n\n" +
|
||||
"Possible solutions:\n" +
|
||||
"1) If this is a new version of Minecraft, please wait for us to update. " +
|
||||
"You can also put in a ticket at http://youtrack.sk89q.com (check for an existing ticket first).\n" +
|
||||
"2) If you are using an older version of Minecraft, you may need to downgrade WorldEdit.\n" +
|
||||
"3) If you are using an older version of WorldEdit, you may need to update your WorldEdit.\n" +
|
||||
"4) If you are not using CraftBukkit, then report this issue to http://youtrack.sk89q.com " +
|
||||
"(check for an existing ticket first).\n" +
|
||||
"5) If you are developing WorldEdit, you can force an adapter with " +
|
||||
"-Dworldedit.bukkit.adapter=the_class_name.\n\n" +
|
||||
"Can I ignore this error? Yes! Just be aware of the undo issue.\n" +
|
||||
"Am I using CraftBukkit? %s.\n";
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*/
|
||||
public BukkitImplLoader() {
|
||||
addDefaults();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add default candidates, such as any defined with
|
||||
* {@code -Dworldedit.bukkit.adapter}.
|
||||
*/
|
||||
private void addDefaults() {
|
||||
String className = System.getProperty("worldedit.bukkit.adapter");
|
||||
if (className != null) {
|
||||
customCandidate = className;
|
||||
adapterCandidates.add(className);
|
||||
log.log(Level.INFO, "-Dworldedit.bukkit.adapter used to add " + className + " to the list of available Bukkit adapters");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the given JAR for candidate implementations.
|
||||
*
|
||||
* @param file the file
|
||||
* @throws IOException thrown on I/O error
|
||||
*/
|
||||
public void addFromJar(File file) throws IOException {
|
||||
Closer closer = Closer.create();
|
||||
JarFile jar = closer.register(new JarFile(file));
|
||||
try {
|
||||
Enumeration entries = jar.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
JarEntry jarEntry = (JarEntry) entries.nextElement();
|
||||
|
||||
String className = jarEntry.getName().replaceAll("[/\\\\]+", ".");
|
||||
|
||||
if (!className.startsWith(SEARCH_PACKAGE_DOT) || jarEntry.isDirectory()) continue;
|
||||
|
||||
int beginIndex = 0;
|
||||
int endIndex = className.length() - CLASS_SUFFIX.length();
|
||||
className = className.substring(beginIndex, endIndex);
|
||||
adapterCandidates.add(className);
|
||||
}
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for classes stored as separate files available via the given
|
||||
* class loader.
|
||||
*
|
||||
* @param classLoader the class loader
|
||||
* @throws IOException thrown on error
|
||||
*/
|
||||
public void addFromPath(ClassLoader classLoader) throws IOException {
|
||||
Enumeration<URL> resources = classLoader.getResources(SEARCH_PATH);
|
||||
while (resources.hasMoreElements()) {
|
||||
File file = new File(resources.nextElement().getFile());
|
||||
addFromPath(file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for classes stored as separate files available via the given
|
||||
* path.
|
||||
*
|
||||
* @param file the path
|
||||
*/
|
||||
private void addFromPath(File file) {
|
||||
String resource = SEARCH_PACKAGE_DOT + file.getName();
|
||||
if (file.isDirectory()) {
|
||||
File[] files = file.listFiles();
|
||||
if (files != null) {
|
||||
for (File child : files) {
|
||||
addFromPath(child);
|
||||
}
|
||||
}
|
||||
} else if (resource.endsWith(CLASS_SUFFIX)) {
|
||||
int beginIndex = 0;
|
||||
int endIndex = resource.length() - CLASS_SUFFIX.length();
|
||||
String className = resource.substring(beginIndex, endIndex);
|
||||
adapterCandidates.add(className);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate through the list of candidates and load an adapter.
|
||||
*
|
||||
* @return an adapter
|
||||
* @throws AdapterLoadException thrown if no adapter could be found
|
||||
*/
|
||||
public BukkitImplAdapter loadAdapter() throws AdapterLoadException {
|
||||
for (String className : adapterCandidates) {
|
||||
try {
|
||||
Class<?> cls = Class.forName(className);
|
||||
if (BukkitImplAdapter.class.isAssignableFrom(cls)) {
|
||||
return (BukkitImplAdapter) cls.newInstance();
|
||||
} else {
|
||||
log.log(Level.WARNING, "Failed to load the Bukkit adapter class '" + className +
|
||||
"' because it does not implement " + BukkitImplAdapter.class.getCanonicalName());
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
log.log(Level.WARNING, "Failed to load the Bukkit adapter class '" + className +
|
||||
"' that is not supposed to be missing", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
log.log(Level.WARNING, "Failed to load the Bukkit adapter class '" + className +
|
||||
"' that is not supposed to be raising this error", e);
|
||||
} catch (Throwable e) {
|
||||
if (className.equals(customCandidate)) {
|
||||
log.log(Level.WARNING, "Failed to load the Bukkit adapter class '" + className + "'", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String weVersion = WorldEdit.getVersion();
|
||||
String bukkitVersion = Bukkit.getBukkitVersion() + " implemented by " + Bukkit.getName() + " " + Bukkit.getVersion();
|
||||
String usingCraftBukkit =
|
||||
Bukkit.getName().equals("CraftBukkit")
|
||||
? "Probably (if you got it from dl.bukkit.org, then yes)"
|
||||
: "No! You are using " + Bukkit.getName();
|
||||
|
||||
throw new AdapterLoadException(
|
||||
String.format(LOAD_ERROR_MESSAGE, weVersion, bukkitVersion, usingCraftBukkit));
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user