diff --git a/contrib/nmsblocks/CBXNmsBlock_146.class b/contrib/nmsblocks/CBXNmsBlock_146.class deleted file mode 100644 index 0eca14c79..000000000 Binary files a/contrib/nmsblocks/CBXNmsBlock_146.class and /dev/null differ diff --git a/contrib/nmsblocks/MCPCPXNmsBlock.class b/contrib/nmsblocks/MCPCPXNmsBlock.class deleted file mode 100644 index 95ba91ea0..000000000 Binary files a/contrib/nmsblocks/MCPCPXNmsBlock.class and /dev/null differ diff --git a/contrib/nmsblocks/MCPCPXNmsBlock.java b/contrib/nmsblocks/MCPCPXNmsBlock.java deleted file mode 100644 index 6197a942a..000000000 --- a/contrib/nmsblocks/MCPCPXNmsBlock.java +++ /dev/null @@ -1,449 +0,0 @@ -// $Id$ -/* - * This file is a part of WorldEdit. - * Copyright (c) sk89q - * Copyright (c) the 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 - * (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 - * GNU 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 . - */ - -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.logging.Logger; - -import net.minecraft.server.v1_4_R1.NBTBase; -import net.minecraft.server.v1_4_R1.NBTTagByte; -import net.minecraft.server.v1_4_R1.NBTTagByteArray; -import net.minecraft.server.v1_4_R1.NBTTagCompound; -import net.minecraft.server.v1_4_R1.NBTTagDouble; -import net.minecraft.server.v1_4_R1.NBTTagEnd; -import net.minecraft.server.v1_4_R1.NBTTagFloat; -import net.minecraft.server.v1_4_R1.NBTTagInt; -import net.minecraft.server.v1_4_R1.NBTTagIntArray; -import net.minecraft.server.v1_4_R1.NBTTagList; -import net.minecraft.server.v1_4_R1.NBTTagLong; -import net.minecraft.server.v1_4_R1.NBTTagShort; -import net.minecraft.server.v1_4_R1.NBTTagString; -import net.minecraft.server.v1_4_R1.TileEntity; - -import org.bukkit.World; -import org.bukkit.craftbukkit.v1_4_R1.CraftWorld; - -import com.sk89q.jnbt.ByteArrayTag; -import com.sk89q.jnbt.ByteTag; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.DoubleTag; -import com.sk89q.jnbt.EndTag; -import com.sk89q.jnbt.FloatTag; -import com.sk89q.jnbt.IntArrayTag; -import com.sk89q.jnbt.IntTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.LongTag; -import com.sk89q.jnbt.NBTConstants; -import com.sk89q.jnbt.ShortTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.blocks.TileEntityBlock; -import com.sk89q.worldedit.bukkit.BukkitWorld; -import com.sk89q.worldedit.bukkit.NmsBlock; -import com.sk89q.worldedit.data.DataException; -import com.sk89q.worldedit.foundation.Block; - -/** - * This class needs to be obfuscated and compiled in a forge environment - */ -public class MCPCPXNmsBlock extends NmsBlock { - - private static final Logger logger = Logger.getLogger(MCPCPXNmsBlock.class.getCanonicalName()); - 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 { - // this part is important, has to be updated manually whenever it changes - field = net.minecraft.server.v1_4_R1.Block.class.getDeclaredField("cs"); // isTileEntity or isContainerBlock - field.setAccessible(true); - } catch (Throwable e) { - // logger.severe("Could not find NMS block tile entity field!"); - field = null; - } - nmsBlock_isTileEntityField = field; - } - - public static boolean verify() { - try { - Class.forName("org.bukkit.craftbukkit.v1_4_R1.CraftWorld"); - } catch (Throwable e) { - return false; - } - 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 MCPCPXNmsBlock(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 MCPCPXNmsBlock(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("x", pt.getBlockX())); - nbtData.set("y", new NBTTagInt("y", pt.getBlockY())); - nbtData.set("z", new NBTTagInt("z", 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()); - } - return (CompoundTag) toNative(nbtData); - } - - @Override - public void setNbtData(CompoundTag tag) throws DataException { - 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 MCPCPXNmsBlock 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 MCPCPXNmsBlock(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 MCPCPXNmsBlock) { - MCPCPXNmsBlock nmsProxyBlock = (MCPCPXNmsBlock) block; - data = nmsProxyBlock.getNmsData(position); - } else if (block instanceof TileEntityBlock) { - MCPCPXNmsBlock nmsProxyBlock = new MCPCPXNmsBlock( - 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()); - - boolean changed = craftWorld.getHandle().setRawTypeIdAndData( - x, y, z, block.getId(), block.getData()); - - if (block instanceof BaseBlock) { - world.copyToWorld(position, (BaseBlock) block); - } - - if (changed) { - if (notifyAdjacent) { - craftWorld.getHandle().update(x, y, z, block.getId()); - } else { - craftWorld.getHandle().notify(x, y, z); - } - } - - return changed; - } - - public static boolean hasTileEntity(int type) { - net.minecraft.server.v1_4_R1.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_4_R1.Block getNmsBlock(int type) { - if (type < 0 || type >= net.minecraft.server.v1_4_R1.Block.byId.length) { - return null; - } - return net.minecraft.server.v1_4_R1.Block.byId[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 - */ - @SuppressWarnings("unchecked") - private static Tag toNative(NBTBase foreign) { - if (foreign == null) { - return null; - } - if (foreign instanceof NBTTagCompound) { - Map values = new HashMap(); - Collection foreignValues = null; - - if (compoundMapField == null) { - try { - // Method name may change! - foreignValues = ((NBTTagCompound) foreign).c(); - } catch (Throwable t) { - try { - // this shouldn't happen here since we are reobfuscating to the correct name - logger.warning("WorldEdit: Couldn't get NBTTagCompound.getLists(), " + - "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 { - foreignValues = ((HashMap) compoundMapField.get(foreign)).values(); - } catch (Throwable e) { - // Can't do much beyond this - throw new RuntimeException(e); - } - } - - for (Object obj : foreignValues) { - NBTBase base = (NBTBase) obj; - values.put(base.getName(), toNative(base)); - } - return new CompoundTag(foreign.getName(), values); - } else if (foreign instanceof NBTTagByte) { - return new ByteTag(foreign.getName(), ((NBTTagByte) foreign).data); - } else if (foreign instanceof NBTTagByteArray) { - return new ByteArrayTag(foreign.getName(), - ((NBTTagByteArray) foreign).data); - } else if (foreign instanceof NBTTagDouble) { - return new DoubleTag(foreign.getName(), - ((NBTTagDouble) foreign).data); - } else if (foreign instanceof NBTTagFloat) { - return new FloatTag(foreign.getName(), ((NBTTagFloat) foreign).data); - } else if (foreign instanceof NBTTagInt) { - return new IntTag(foreign.getName(), ((NBTTagInt) foreign).data); - } else if (foreign instanceof NBTTagIntArray) { - return new IntArrayTag(foreign.getName(), - ((NBTTagIntArray) foreign).data); - } else if (foreign instanceof NBTTagList) { - List values = new ArrayList(); - NBTTagList foreignList = (NBTTagList) foreign; - int type = NBTConstants.TYPE_BYTE; - for (int i = 0; i < foreignList.size(); i++) { - NBTBase foreignTag = foreignList.get(i); - values.add(toNative(foreignTag)); - type = foreignTag.getTypeId(); - } - Class cls = NBTConstants.getClassFromType(type); - return new ListTag(foreign.getName(), cls, values); - } else if (foreign instanceof NBTTagLong) { - return new LongTag(foreign.getName(), ((NBTTagLong) foreign).data); - } else if (foreign instanceof NBTTagShort) { - return new ShortTag(foreign.getName(), ((NBTTagShort) foreign).data); - } else if (foreign instanceof NBTTagString) { - return new StringTag(foreign.getName(), - ((NBTTagString) foreign).data); - } else if (foreign instanceof NBTTagEnd) { - return new EndTag(); - } else { - throw new IllegalArgumentException("Don't know how to make native " - + foreign.getClass().getCanonicalName()); - } - } - - /** - * 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(foreign.getName()); - for (Map.Entry entry : ((CompoundTag) foreign) - .getValue().entrySet()) { - tag.set(entry.getKey(), fromNative(entry.getValue())); - } - return tag; - } else if (foreign instanceof ByteTag) { - return new NBTTagByte(foreign.getName(), - ((ByteTag) foreign).getValue()); - } else if (foreign instanceof ByteArrayTag) { - return new NBTTagByteArray(foreign.getName(), - ((ByteArrayTag) foreign).getValue()); - } else if (foreign instanceof DoubleTag) { - return new NBTTagDouble(foreign.getName(), - ((DoubleTag) foreign).getValue()); - } else if (foreign instanceof FloatTag) { - return new NBTTagFloat(foreign.getName(), - ((FloatTag) foreign).getValue()); - } else if (foreign instanceof IntTag) { - return new NBTTagInt(foreign.getName(), - ((IntTag) foreign).getValue()); - } else if (foreign instanceof IntArrayTag) { - return new NBTTagIntArray(foreign.getName(), - ((IntArrayTag) foreign).getValue()); - } else if (foreign instanceof ListTag) { - NBTTagList tag = new NBTTagList(foreign.getName()); - ListTag foreignList = (ListTag) foreign; - for (Tag t : foreignList.getValue()) { - tag.add(fromNative(t)); - } - return tag; - } else if (foreign instanceof LongTag) { - return new NBTTagLong(foreign.getName(), - ((LongTag) foreign).getValue()); - } else if (foreign instanceof ShortTag) { - return new NBTTagShort(foreign.getName(), - ((ShortTag) foreign).getValue()); - } else if (foreign instanceof StringTag) { - return new NBTTagString(foreign.getName(), - ((StringTag) foreign).getValue()); - } else if (foreign instanceof EndTag) { - return new NBTTagEnd(); - } 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 && type < net.minecraft.server.v1_4_R1.Block.byId.length - && net.minecraft.server.v1_4_R1.Block.byId[type] != null); - } -} \ No newline at end of file diff --git a/pom.xml b/pom.xml index fc314cdc7..8d7627e08 100644 --- a/pom.xml +++ b/pom.xml @@ -135,6 +135,14 @@ config.yml + + nmsblocks/ + false + ${basedir}/src/main/resources/nmsblocks/ + + *.class + + diff --git a/src/main/assembly/default.xml b/src/main/assembly/default.xml index 76d6de02e..6d7f39dac 100644 --- a/src/main/assembly/default.xml +++ b/src/main/assembly/default.xml @@ -27,8 +27,6 @@ LICENSE.txt CHANGELOG.txt - contrib/craftscripts/* - contrib/nmsblocks/*.class diff --git a/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java index bb9cd30eb..7e80ed7fe 100644 --- a/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -122,6 +122,8 @@ public class BukkitWorld extends LocalWorld { this.world = world; // check if we have a class we can use for nms access + + // only run once per server startup if (nmsBlockType != null) return; Plugin plugin = Bukkit.getPluginManager().getPlugin("WorldEdit"); if (!(plugin instanceof WorldEditPlugin)) return; // hopefully never happens @@ -132,12 +134,20 @@ public class BukkitWorld extends LocalWorld { 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(); - Class testBlock = loader.loadClass("CL-NMS" + filename); + // 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 @@ -160,7 +170,7 @@ public class BukkitWorld extends LocalWorld { } } if (nmsBlockType != null) { - // logger.info("Found nms block class, using: " + nmsBlockType); + logger.info("[WorldEdit] Using external NmsBlock for this version: " + nmsBlockType.getName()); } else { // try our default try { @@ -172,7 +182,7 @@ public class BukkitWorld extends LocalWorld { 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 of WorldEdit."); + logger.info("[WorldEdit] Using inbuilt NmsBlock for this version."); } } catch (Throwable e) { // OMG DEVS WAI U NO SUPPORT SERVER diff --git a/src/main/java/com/sk89q/worldedit/bukkit/DefaultNmsBlock.java b/src/main/java/com/sk89q/worldedit/bukkit/DefaultNmsBlock.java index f1f451b04..d9ff64634 100644 --- a/src/main/java/com/sk89q/worldedit/bukkit/DefaultNmsBlock.java +++ b/src/main/java/com/sk89q/worldedit/bukkit/DefaultNmsBlock.java @@ -250,14 +250,17 @@ public class DefaultNmsBlock extends NmsBlock { 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().setRawTypeIdAndData( - x, y, z, block.getId(), block.getData()); + boolean changed = craftWorld.getHandle().setRawTypeId(x, y, z, block.getId()); if (block instanceof BaseBlock) { world.copyToWorld(position, (BaseBlock) block); } + changed = craftWorld.getHandle().setRawData(x, y, z, block.getData()) || changed; + if (changed) { if (notifyAdjacent) { craftWorld.getHandle().update(x, y, z, block.getId()); diff --git a/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java b/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java index b7b9826e1..d19de40d7 100644 --- a/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java +++ b/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java @@ -24,6 +24,8 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.Enumeration; +import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.logging.Handler; import java.util.zip.ZipEntry; @@ -96,7 +98,9 @@ public class WorldEditPlugin extends JavaPlugin { // Make the data folders that WorldEdit uses getDataFolder().mkdirs(); - new File(getDataFolder() + File.separator + "nmsblocks").mkdir(); + File targetDir = new File(getDataFolder() + File.separator + "nmsblocks"); + targetDir.mkdir(); + copyNmsBlockClasses(targetDir); // Create the default configuration file createDefaultConfiguration("config.yml"); @@ -121,7 +125,32 @@ public class WorldEditPlugin extends JavaPlugin { getServer().getScheduler().scheduleAsyncRepeatingTask(this, new SessionTimer(controller, getServer()), 120, 120); + } + private void copyNmsBlockClasses(File target) { + try { + JarFile jar = new JarFile(getFile()); + Enumeration entries = jar.entries(); + while (entries.hasMoreElements()) { + JarEntry jarEntry = (JarEntry) entries.nextElement(); + if (!jarEntry.getName().startsWith("nmsblocks") || jarEntry.isDirectory()) continue; + + 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) {} } /** diff --git a/src/main/resources/nmsblocks/CBXNmsBlock_146.class b/src/main/resources/nmsblocks/CBXNmsBlock_146.class new file mode 100644 index 000000000..e89c4a70b Binary files /dev/null and b/src/main/resources/nmsblocks/CBXNmsBlock_146.class differ diff --git a/contrib/nmsblocks/CBXNmsBlock_146.java b/src/main/resources/nmsblocks/CBXNmsBlock_146.java similarity index 96% rename from contrib/nmsblocks/CBXNmsBlock_146.java rename to src/main/resources/nmsblocks/CBXNmsBlock_146.java index 3e1d3693a..dc4764e20 100644 --- a/contrib/nmsblocks/CBXNmsBlock_146.java +++ b/src/main/resources/nmsblocks/CBXNmsBlock_146.java @@ -247,13 +247,14 @@ public class CBXNmsBlock_146 extends NmsBlock { CraftWorld craftWorld = ((CraftWorld) world.getWorld()); - boolean changed = craftWorld.getHandle().setRawTypeIdAndData( - x, y, z, block.getId(), block.getData()); + boolean changed = craftWorld.getHandle().setRawTypeId(x, y, z, block.getId()); if (block instanceof BaseBlock) { world.copyToWorld(position, (BaseBlock) block); } + changed = craftWorld.getHandle().setRawData(x, y, z, block.getData()) || changed; + if (changed) { if (notifyAdjacent) { craftWorld.getHandle().update(x, y, z, block.getId());