From 9144bff25bdb882ea6e178e1492a7796ad641720 Mon Sep 17 00:00:00 2001 From: Mike Primm Date: Mon, 21 Jan 2013 23:54:13 -0600 Subject: [PATCH] Add support for MCPC-Plus --- .../dynmap/bukkit/BukkitVersionHelper.java | 451 +++--------------- .../dynmap/bukkit/BukkitVersionHelperCB.java | 86 ++++ .../bukkit/BukkitVersionHelperGeneric.java | 380 +++++++++++++++ .../bukkit/BukkitVersionHelperMCPC.java | 81 ++++ 4 files changed, 608 insertions(+), 390 deletions(-) create mode 100644 src/main/java/org/dynmap/bukkit/BukkitVersionHelperCB.java create mode 100644 src/main/java/org/dynmap/bukkit/BukkitVersionHelperGeneric.java create mode 100644 src/main/java/org/dynmap/bukkit/BukkitVersionHelperMCPC.java diff --git a/src/main/java/org/dynmap/bukkit/BukkitVersionHelper.java b/src/main/java/org/dynmap/bukkit/BukkitVersionHelper.java index c235f9c0..c6a2f421 100644 --- a/src/main/java/org/dynmap/bukkit/BukkitVersionHelper.java +++ b/src/main/java/org/dynmap/bukkit/BukkitVersionHelper.java @@ -15,420 +15,91 @@ import org.dynmap.Log; /** * Helper for isolation of bukkit version specific issues */ -public class BukkitVersionHelper { - private String obc_package; // Package used for org.bukkit.craftbukkit - private String nms_package; // Package used for net.minecraft.server - private static BukkitVersionHelper helper; - private boolean failed; - private static final Object[] nullargs = new Object[0]; - private static final Map nullmap = Collections.emptyMap(); - /** BiomeBase related helpers */ - private Class biomebase; - private Class biomebasearray; - private Field biomebaselist; - private Field biomebasetemp; - private Field biomebasehumi; - private Field biomebaseidstring; - private Field biomebaseid; - /** CraftWorld */ - private Class craftworld; - private Method cw_gethandle; - /** n.m.s.World */ - private Class nmsworld; - private Class chunkprovserver; - private Class longhashset; - private Field nmsw_chunkproviderserver; - private Field cps_unloadqueue; - private Method lhs_containskey; - /** CraftChunkSnapshot */ - private Class craftchunksnapshot; - private Field ccss_biome; - /** CraftChunk */ - private Class craftchunk; - private Method cc_gethandle; - /** o.m.s.Chunk */ - private Class nmschunk; - private Method nmsc_removeentities; - private Field nmsc_tileentities; - /** nbt classes */ - private Class nbttagcompound; - private Class nbttagbyte; - private Class nbttagshort; - private Class nbttagint; - private Class nbttaglong; - private Class nbttagfloat; - private Class nbttagdouble; - private Class nbttagbytearray; - private Class nbttagstring; - private Class nbttagintarray; - private Method compound_get; - private Field nbttagbyte_val; - private Field nbttagshort_val; - private Field nbttagint_val; - private Field nbttaglong_val; - private Field nbttagfloat_val; - private Field nbttagdouble_val; - private Field nbttagbytearray_val; - private Field nbttagstring_val; - private Field nbttagintarray_val; - - /** Tile entity */ - private Class nms_tileentity; - private Method nmst_readnbt; - private Field nmst_x; - private Field nmst_y; - private Field nmst_z; +public abstract class BukkitVersionHelper { + private static BukkitVersionHelper helper = null; + public static final BukkitVersionHelper getHelper() { if(helper == null) { - helper = new BukkitVersionHelper(); + if(Bukkit.getServer().getVersion().contains("MCPC")) { + Log.info("Loader version helper for MCPC"); + helper = new BukkitVersionHelperMCPC(); + } + else { + helper = new BukkitVersionHelperCB(); + } } return helper; } - - private BukkitVersionHelper() { - failed = false; - Server srv = Bukkit.getServer(); - /* Look up base classname for bukkit server - tells us OBC package */ - obc_package = Bukkit.getServer().getClass().getPackage().getName(); - /* Get getHandle() method */ - try { - Method m = srv.getClass().getMethod("getHandle"); - Object scm = m.invoke(srv); /* And use it to get SCM (nms object) */ - nms_package = scm.getClass().getPackage().getName(); - } catch (Exception x) { - Log.severe("Error finding net.minecraft.server packages"); - nms_package = "net.minecraft.server" + obc_package.substring("org.bukkit.craftbukkit".length()); - failed = true; - } + protected BukkitVersionHelper() { - /* Set up biomebase fields */ - biomebase = getNMSClass("net.minecraft.server.BiomeBase"); - biomebasearray = getNMSClass("[Lnet.minecraft.server.BiomeBase;"); - biomebaselist = getField(biomebase, new String[] { "biomes" }, biomebasearray); - biomebasetemp = getField(biomebase, new String[] { "temperature", "F" }, float.class); - biomebasehumi = getField(biomebase, new String[] { "humidity", "G" }, float.class); - biomebaseidstring = getField(biomebase, new String[] { "y" }, String.class); - biomebaseid = getField(biomebase, new String[] { "id" }, int.class); - /* Craftworld fields */ - craftworld = getOBCClass("org.bukkit.craftbukkit.CraftWorld"); - cw_gethandle = getMethod(craftworld, new String[] { "getHandle" }, new Class[0]); - /* n.m.s.World */ - nmsworld = getNMSClass("net.minecraft.server.WorldServer"); - chunkprovserver = getNMSClass("net.minecraft.server.ChunkProviderServer"); - longhashset = getOBCClassNoFail("org.bukkit.craftbukkit.util.LongHashSet"); - if(longhashset != null) { - lhs_containskey = getMethod(longhashset, new String[] { "contains" }, new Class[] { int.class, int.class }); - } - else { - longhashset = getOBCClass("org.bukkit.craftbukkit.util.LongHashset"); - lhs_containskey = getMethod(longhashset, new String[] { "containsKey" }, new Class[] { int.class, int.class }); - } - nmsw_chunkproviderserver = getField(nmsworld, new String[] { "chunkProviderServer" }, chunkprovserver); - cps_unloadqueue = getFieldNoFail(chunkprovserver, new String[] { "unloadQueue" }, longhashset); - if(cps_unloadqueue == null) { - Log.info("Unload queue not found - default to unload all chunks"); - } - /* CraftChunkSnapshot */ - craftchunksnapshot = getOBCClass("org.bukkit.craftbukkit.CraftChunkSnapshot"); - ccss_biome = getPrivateField(craftchunksnapshot, new String[] { "biome" }, biomebasearray); - /** CraftChunk */ - craftchunk = getOBCClass("org.bukkit.craftbukkit.CraftChunk"); - cc_gethandle = getMethod(craftchunk, new String[] { "getHandle" }, new Class[0]); - /** n.m.s.Chunk */ - nmschunk = getNMSClass("net.minecraft.server.Chunk"); - nmsc_removeentities = getMethod(nmschunk, new String[] { "removeEntities" }, new Class[0]); - nmsc_tileentities = getField(nmschunk, new String[] { "tileEntities" }, Map.class); - /** nbt classes */ - nbttagcompound = getNMSClass("net.minecraft.server.NBTTagCompound"); - nbttagbyte = getNMSClass("net.minecraft.server.NBTTagByte"); - nbttagshort = getNMSClass("net.minecraft.server.NBTTagShort"); - nbttagint = getNMSClass("net.minecraft.server.NBTTagInt"); - nbttaglong = getNMSClass("net.minecraft.server.NBTTagLong"); - nbttagfloat = getNMSClass("net.minecraft.server.NBTTagFloat"); - nbttagdouble = getNMSClass("net.minecraft.server.NBTTagDouble"); - nbttagbytearray = getNMSClass("net.minecraft.server.NBTTagByteArray"); - nbttagstring = getNMSClass("net.minecraft.server.NBTTagString"); - nbttagintarray = getNMSClass("net.minecraft.server.NBTTagIntArray"); - compound_get = getMethod(nbttagcompound, new String[] { "get" }, new Class[] { String.class }); - nbttagbyte_val = getField(nbttagbyte, new String[] { "data" }, byte.class); - nbttagshort_val = getField(nbttagshort, new String[] { "data" }, short.class); - nbttagint_val = getField(nbttagint, new String[] { "data" }, int.class); - nbttaglong_val = getField(nbttaglong, new String[] { "data" }, long.class); - nbttagfloat_val = getField(nbttagfloat, new String[] { "data" }, float.class); - nbttagdouble_val = getField(nbttagdouble, new String[] { "data" }, double.class); - nbttagbytearray_val = getField(nbttagbytearray, new String[] { "data" }, byte[].class); - nbttagstring_val = getField(nbttagstring, new String[] { "data" }, String.class); - nbttagintarray_val = getField(nbttagintarray, new String[] { "data" }, int[].class); - - /** Tile entity */ - nms_tileentity = getNMSClass("net.minecraft.server.TileEntity"); - nmst_readnbt = getMethod(nms_tileentity, new String[] { "b" }, new Class[] { nbttagcompound }); - nmst_x = getField(nms_tileentity, new String[] { "x" }, int.class); - nmst_y = getField(nms_tileentity, new String[] { "y" }, int.class); - nmst_z = getField(nms_tileentity, new String[] { "z" }, int.class); - - if(failed) - throw new IllegalArgumentException("Error initializing dynmap - bukkit version incompatible!"); } - - public Class getOBCClass(String classname) { - return getClassByName(classname, "org.bukkit.craftbukkit", obc_package, false); - } - - public Class getOBCClassNoFail(String classname) { - return getClassByName(classname, "org.bukkit.craftbukkit", obc_package, true); - } - - public Class getNMSClass(String classname) { - return getClassByName(classname, "net.minecraft.server", nms_package, false); - } - - public Class getClassByName(String classname, String base, String mapping, boolean nofail) { - String n = classname; - int idx = classname.indexOf(base); - if(idx >= 0) { - n = classname.substring(0, idx) + mapping + classname.substring(idx + base.length()); - } - try { - return Class.forName(n); - } catch (ClassNotFoundException cnfx) { - try { - return Class.forName(classname); - } catch (ClassNotFoundException cnfx2) { - if(!nofail) { - Log.severe("Cannot find " + classname); - failed = true; - } - return null; - } - } - } - /** - * Get field - */ - private Field getField(Class cls, String[] ids, Class type) { - return getField(cls, ids, type, false); - } - private Field getFieldNoFail(Class cls, String[] ids, Class type) { - return getField(cls, ids, type, true); - } - /** - * Get field - */ - private Field getField(Class cls, String[] ids, Class type, boolean nofail) { - if((cls == null) || (type == null)) return null; - for(String id : ids) { - try { - Field f = cls.getField(id); - if(f.getType().isAssignableFrom(type)) { - return f; - } - } catch (NoSuchFieldException nsfx) { - } - } - if(!nofail) { - Log.severe("Unable to find field " + ids[0] + " for " + cls.getName()); - failed = true; - } - return null; - } - /** - * Get private field - */ - private Field getPrivateField(Class cls, String[] ids, Class type) { - if((cls == null) || (type == null)) return null; - for(String id : ids) { - try { - Field f = cls.getDeclaredField(id); - if(f.getType().isAssignableFrom(type)) { - f.setAccessible(true); - return f; - } - } catch (NoSuchFieldException nsfx) { - } - } - Log.severe("Unable to find field " + ids[0] + " for " + cls.getName()); - failed = true; - return null; - } - private Object getFieldValue(Object obj, Field field, Object def) { - if((obj != null) && (field != null)) { - try { - return field.get(obj); - } catch (IllegalArgumentException e) { - } catch (IllegalAccessException e) { - } - } - return def; - } - /** - * Get method - */ - private Method getMethod(Class cls, String[] ids, Class[] args) { - if(cls == null) return null; - for(String id : ids) { - try { - return cls.getMethod(id, args); - } catch (SecurityException e) { - } catch (NoSuchMethodException e) { - } - } - Log.severe("Unable to find method " + ids[0] + " for " + cls.getName()); - failed = true; - return null; - } - private Object callMethod(Object obj, Method meth, Object[] args, Object def) { - if((obj == null) || (meth == null)) { - return def; - } - try { - return meth.invoke(obj, args); - } catch (IllegalArgumentException iax) { - } catch (IllegalAccessException e) { - } catch (InvocationTargetException e) { - } - return def; - } - - /** * Get list of defined biomebase objects */ - public Object[] getBiomeBaseList() { - return (Object[]) getFieldValue(biomebase, biomebaselist, new Object[0]); - } - /** Get temperature from biomebase */ - public float getBiomeBaseTemperature(Object bb) { - return (Float) getFieldValue(bb, biomebasetemp, 0.5F); - } - /** Get humidity from biomebase */ - public float getBiomeBaseHumidity(Object bb) { - return (Float) getFieldValue(bb, biomebasehumi, 0.5F); - } - /** Get ID string from biomebase */ - public String getBiomeBaseIDString(Object bb) { - return (String) getFieldValue(bb, biomebaseidstring, null); - } - /** Get ID from biomebase */ - public int getBiomeBaseID(Object bb) { - return (Integer) getFieldValue(bb, biomebaseid, -1); - } - - /* Get net.minecraft.server.world for given world */ - public Object getNMSWorld(World w) { - return callMethod(w, cw_gethandle, nullargs, null); - } - - /* Get unload queue for given NMS world */ - public Object getUnloadQueue(Object nmsworld) { - Object cps = getFieldValue(nmsworld, nmsw_chunkproviderserver, null); // Get chunkproviderserver - if(cps != null) { - return getFieldValue(cps, cps_unloadqueue, null); - } - return null; - } - - /* For testing unload queue for presence of givne chunk */ - public boolean isInUnloadQueue(Object unloadqueue, int x, int z) { - if(unloadqueue != null) { - return (Boolean)callMethod(unloadqueue, lhs_containskey, new Object[] { x, z }, true); - } - return true; - } - - public Object[] getBiomeBaseFromSnapshot(ChunkSnapshot css) { - return (Object[])getFieldValue(css, ccss_biome, null); - } - public boolean isCraftChunkSnapshot(ChunkSnapshot css) { - if(craftchunksnapshot != null) { - return craftchunksnapshot.isAssignableFrom(css.getClass()); - } - return false; - } - /** Remove entities from given chunk */ - public void removeEntitiesFromChunk(Chunk c) { - Object omsc = callMethod(c, cc_gethandle, nullargs, null); - if(omsc != null) { - callMethod(omsc, nmsc_removeentities, nullargs, null); - } - } - /** Get tile entities map from chunk */ - public Map getTileEntitiesForChunk(Chunk c) { - Object omsc = callMethod(c, cc_gethandle, nullargs, null); - if(omsc != null) { - return (Map)getFieldValue(omsc, nmsc_tileentities, nullmap); - } - return nullmap; - } + public abstract Object[] getBiomeBaseList(); + /** + * Get temperature from biomebase + */ + public abstract float getBiomeBaseTemperature(Object bb); + /** + * Get humidity from biomebase + */ + public abstract float getBiomeBaseHumidity(Object bb); + /** + * Get ID string from biomebase + */ + public abstract String getBiomeBaseIDString(Object bb); + /** + * Get ID from biomebase + */ + public abstract int getBiomeBaseID(Object bb); + /** + * Get net.minecraft.server.world for given world + */ + public abstract Object getNMSWorld(World w); + /** + * Get unload queue for given NMS world + */ + public abstract Object getUnloadQueue(Object nmsworld); + /** + * For testing unload queue for presence of givne chunk + */ + public abstract boolean isInUnloadQueue(Object unloadqueue, int x, int z); + /** + * Read raw biome ID from snapshot + */ + public abstract Object[] getBiomeBaseFromSnapshot(ChunkSnapshot css); + /** + * Test if normal chunk snapshot + */ + public abstract boolean isCraftChunkSnapshot(ChunkSnapshot css); + /** + * Remove entities from given chunk + */ + public abstract void removeEntitiesFromChunk(Chunk c); + /** + * Get tile entities map from chunk + */ + public abstract Map getTileEntitiesForChunk(Chunk c); /** * Get X coordinate of tile entity */ - public int getTileEntityX(Object te) { - return (Integer)getFieldValue(te, nmst_x, 0); - } + public abstract int getTileEntityX(Object te); /** * Get Y coordinate of tile entity */ - public int getTileEntityY(Object te) { - return (Integer)getFieldValue(te, nmst_y, 0); - } + public abstract int getTileEntityY(Object te); /** * Get Z coordinate of tile entity */ - public int getTileEntityZ(Object te) { - return (Integer)getFieldValue(te, nmst_z, 0); - } + public abstract int getTileEntityZ(Object te); /** * Read tile entity NBT */ - public Object readTileEntityNBT(Object te) { - if(nbttagcompound == null) return null; - Object nbt = null; - try { - nbt = nbttagcompound.newInstance(); - } catch (InstantiationException e) { - } catch (IllegalAccessException e) { - } - if(nbt != null) { - callMethod(te, nmst_readnbt, new Object[] { nbt }, null); - } - return nbt; - } + public abstract Object readTileEntityNBT(Object te); /** * Get field value from NBT compound */ - public Object getFieldValue(Object nbt, String field) { - Object val = callMethod(nbt, compound_get, new Object[] { field }, null); - if(val == null) return null; - Class valcls = val.getClass(); - if(valcls.equals(nbttagbyte)) { - return getFieldValue(val, nbttagbyte_val, null); - } - else if(valcls.equals(nbttagshort)) { - return getFieldValue(val, nbttagshort_val, null); - } - else if(valcls.equals(nbttagint)) { - return getFieldValue(val, nbttagint_val, null); - } - else if(valcls.equals(nbttaglong)) { - return getFieldValue(val, nbttaglong_val, null); - } - else if(valcls.equals(nbttagfloat)) { - return getFieldValue(val, nbttagfloat_val, null); - } - else if(valcls.equals(nbttagdouble)) { - return getFieldValue(val, nbttagdouble_val, null); - } - else if(valcls.equals(nbttagbytearray)) { - return getFieldValue(val, nbttagbytearray_val, null); - } - else if(valcls.equals(nbttagstring)) { - return getFieldValue(val, nbttagstring_val, null); - } - else if(valcls.equals(nbttagintarray)) { - return getFieldValue(val, nbttagintarray_val, null); - } - return null; - } + public abstract Object getFieldValue(Object nbt, String field); } diff --git a/src/main/java/org/dynmap/bukkit/BukkitVersionHelperCB.java b/src/main/java/org/dynmap/bukkit/BukkitVersionHelperCB.java new file mode 100644 index 00000000..6a0e8d60 --- /dev/null +++ b/src/main/java/org/dynmap/bukkit/BukkitVersionHelperCB.java @@ -0,0 +1,86 @@ +package org.dynmap.bukkit; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.Map; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.ChunkSnapshot; +import org.bukkit.Server; +import org.bukkit.World; +import org.dynmap.Log; + +/** + * Helper for isolation of bukkit version specific issues + */ +public class BukkitVersionHelperCB extends BukkitVersionHelperGeneric { + + BukkitVersionHelperCB() { + } + @Override + protected String getNMSPackage() { + Server srv = Bukkit.getServer(); + /* Get getHandle() method */ + try { + Method m = srv.getClass().getMethod("getHandle"); + Object scm = m.invoke(srv); /* And use it to get SCM (nms object) */ + return scm.getClass().getPackage().getName(); + } catch (Exception x) { + Log.severe("Error finding net.minecraft.server packages"); + return null; + } + } + @Override + protected void loadNMS() { + /* Set up biomebase fields */ + biomebase = getNMSClass("net.minecraft.server.BiomeBase"); + biomebasearray = getNMSClass("[Lnet.minecraft.server.BiomeBase;"); + biomebaselist = getField(biomebase, new String[] { "biomes" }, biomebasearray); + biomebasetemp = getField(biomebase, new String[] { "temperature", "F" }, float.class); + biomebasehumi = getField(biomebase, new String[] { "humidity", "G" }, float.class); + biomebaseidstring = getField(biomebase, new String[] { "y" }, String.class); + biomebaseid = getField(biomebase, new String[] { "id" }, int.class); + /* n.m.s.World */ + nmsworld = getNMSClass("net.minecraft.server.WorldServer"); + chunkprovserver = getNMSClass("net.minecraft.server.ChunkProviderServer"); + nmsw_chunkproviderserver = getField(nmsworld, new String[] { "chunkProviderServer" }, chunkprovserver); + cps_unloadqueue = getFieldNoFail(chunkprovserver, new String[] { "unloadQueue" }, longhashset); + if(cps_unloadqueue == null) { + Log.info("Unload queue not found - default to unload all chunks"); + } + /** n.m.s.Chunk */ + nmschunk = getNMSClass("net.minecraft.server.Chunk"); + nmsc_removeentities = getMethod(nmschunk, new String[] { "removeEntities" }, new Class[0]); + nmsc_tileentities = getField(nmschunk, new String[] { "tileEntities" }, Map.class); + /** nbt classes */ + nbttagcompound = getNMSClass("net.minecraft.server.NBTTagCompound"); + nbttagbyte = getNMSClass("net.minecraft.server.NBTTagByte"); + nbttagshort = getNMSClass("net.minecraft.server.NBTTagShort"); + nbttagint = getNMSClass("net.minecraft.server.NBTTagInt"); + nbttaglong = getNMSClass("net.minecraft.server.NBTTagLong"); + nbttagfloat = getNMSClass("net.minecraft.server.NBTTagFloat"); + nbttagdouble = getNMSClass("net.minecraft.server.NBTTagDouble"); + nbttagbytearray = getNMSClass("net.minecraft.server.NBTTagByteArray"); + nbttagstring = getNMSClass("net.minecraft.server.NBTTagString"); + nbttagintarray = getNMSClass("net.minecraft.server.NBTTagIntArray"); + compound_get = getMethod(nbttagcompound, new String[] { "get" }, new Class[] { String.class }); + nbttagbyte_val = getField(nbttagbyte, new String[] { "data" }, byte.class); + nbttagshort_val = getField(nbttagshort, new String[] { "data" }, short.class); + nbttagint_val = getField(nbttagint, new String[] { "data" }, int.class); + nbttaglong_val = getField(nbttaglong, new String[] { "data" }, long.class); + nbttagfloat_val = getField(nbttagfloat, new String[] { "data" }, float.class); + nbttagdouble_val = getField(nbttagdouble, new String[] { "data" }, double.class); + nbttagbytearray_val = getField(nbttagbytearray, new String[] { "data" }, byte[].class); + nbttagstring_val = getField(nbttagstring, new String[] { "data" }, String.class); + nbttagintarray_val = getField(nbttagintarray, new String[] { "data" }, int[].class); + + /** Tile entity */ + nms_tileentity = getNMSClass("net.minecraft.server.TileEntity"); + nmst_readnbt = getMethod(nms_tileentity, new String[] { "b" }, new Class[] { nbttagcompound }); + nmst_x = getField(nms_tileentity, new String[] { "x" }, int.class); + nmst_y = getField(nms_tileentity, new String[] { "y" }, int.class); + nmst_z = getField(nms_tileentity, new String[] { "z" }, int.class); + } +} diff --git a/src/main/java/org/dynmap/bukkit/BukkitVersionHelperGeneric.java b/src/main/java/org/dynmap/bukkit/BukkitVersionHelperGeneric.java new file mode 100644 index 00000000..10faa379 --- /dev/null +++ b/src/main/java/org/dynmap/bukkit/BukkitVersionHelperGeneric.java @@ -0,0 +1,380 @@ +package org.dynmap.bukkit; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.Map; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.ChunkSnapshot; +import org.bukkit.Server; +import org.bukkit.World; +import org.dynmap.Log; + +/** + * Helper for isolation of bukkit version specific issues + */ +public abstract class BukkitVersionHelperGeneric extends BukkitVersionHelper { + private String obc_package; // Package used for org.bukkit.craftbukkit + protected String nms_package; // Package used for net.minecraft.server + private boolean failed; + private static final Object[] nullargs = new Object[0]; + private static final Map nullmap = Collections.emptyMap(); + + /** CraftChunkSnapshot */ + private Class craftchunksnapshot; + private Field ccss_biome; + /** CraftChunk */ + private Class craftchunk; + private Method cc_gethandle; + /** CraftWorld */ + private Class craftworld; + private Method cw_gethandle; + + /** BiomeBase related helpers */ + protected Class biomebase; + protected Class biomebasearray; + protected Field biomebaselist; + protected Field biomebasetemp; + protected Field biomebasehumi; + protected Field biomebaseidstring; + protected Field biomebaseid; + /** n.m.s.World */ + protected Class nmsworld; + protected Class chunkprovserver; + protected Class longhashset; + protected Field nmsw_chunkproviderserver; + protected Field cps_unloadqueue; + protected Method lhs_containskey; + /** n.m.s.Chunk */ + protected Class nmschunk; + protected Method nmsc_removeentities; + protected Field nmsc_tileentities; + /** nbt classes */ + protected Class nbttagcompound; + protected Class nbttagbyte; + protected Class nbttagshort; + protected Class nbttagint; + protected Class nbttaglong; + protected Class nbttagfloat; + protected Class nbttagdouble; + protected Class nbttagbytearray; + protected Class nbttagstring; + protected Class nbttagintarray; + protected Method compound_get; + protected Field nbttagbyte_val; + protected Field nbttagshort_val; + protected Field nbttagint_val; + protected Field nbttaglong_val; + protected Field nbttagfloat_val; + protected Field nbttagdouble_val; + protected Field nbttagbytearray_val; + protected Field nbttagstring_val; + protected Field nbttagintarray_val; + /** Tile entity */ + protected Class nms_tileentity; + protected Method nmst_readnbt; + protected Field nmst_x; + protected Field nmst_y; + protected Field nmst_z; + + BukkitVersionHelperGeneric() { + failed = false; + Server srv = Bukkit.getServer(); + /* Look up base classname for bukkit server - tells us OBC package */ + obc_package = Bukkit.getServer().getClass().getPackage().getName(); + /* Get NMS package */ + nms_package = getNMSPackage(); + if(nms_package == null) { + failed = true; + } + /* Craftworld fields */ + craftworld = getOBCClass("org.bukkit.craftbukkit.CraftWorld"); + cw_gethandle = getMethod(craftworld, new String[] { "getHandle" }, new Class[0]); + longhashset = getOBCClassNoFail("org.bukkit.craftbukkit.util.LongHashSet"); + if(longhashset != null) { + lhs_containskey = getMethod(longhashset, new String[] { "contains" }, new Class[] { int.class, int.class }); + } + else { + longhashset = getOBCClass("org.bukkit.craftbukkit.util.LongHashset"); + lhs_containskey = getMethod(longhashset, new String[] { "containsKey" }, new Class[] { int.class, int.class }); + } + /* CraftChunkSnapshot */ + craftchunksnapshot = getOBCClass("org.bukkit.craftbukkit.CraftChunkSnapshot"); + ccss_biome = getPrivateField(craftchunksnapshot, new String[] { "biome" }, biomebasearray); + /* CraftChunk */ + craftchunk = getOBCClass("org.bukkit.craftbukkit.CraftChunk"); + cc_gethandle = getMethod(craftchunk, new String[] { "getHandle" }, new Class[0]); + /* Get NMS classes and fields */ + if(!failed) + loadNMS(); + + if(failed) + throw new IllegalArgumentException("Error initializing dynmap - bukkit version incompatible!"); + } + + protected abstract void loadNMS(); + + protected abstract String getNMSPackage(); + + protected Class getOBCClass(String classname) { + return getClassByName(classname, "org.bukkit.craftbukkit", obc_package, false); + } + + protected Class getOBCClassNoFail(String classname) { + return getClassByName(classname, "org.bukkit.craftbukkit", obc_package, true); + } + + protected Class getNMSClass(String classname) { + return getClassByName(classname, "net.minecraft.server", nms_package, false); + } + + protected Class getClassByName(String classname, String base, String mapping, boolean nofail) { + String n = classname; + int idx = classname.indexOf(base); + if(idx >= 0) { + n = classname.substring(0, idx) + mapping + classname.substring(idx + base.length()); + } + try { + return Class.forName(n); + } catch (ClassNotFoundException cnfx) { + try { + return Class.forName(classname); + } catch (ClassNotFoundException cnfx2) { + if(!nofail) { + Log.severe("Cannot find " + classname); + failed = true; + } + return null; + } + } + } + /** + * Get field + */ + protected Field getField(Class cls, String[] ids, Class type) { + return getField(cls, ids, type, false); + } + protected Field getFieldNoFail(Class cls, String[] ids, Class type) { + return getField(cls, ids, type, true); + } + /** + * Get field + */ + private Field getField(Class cls, String[] ids, Class type, boolean nofail) { + if((cls == null) || (type == null)) return null; + for(String id : ids) { + try { + Field f = cls.getField(id); + if(f.getType().isAssignableFrom(type)) { + return f; + } + } catch (NoSuchFieldException nsfx) { + } + } + if(!nofail) { + Log.severe("Unable to find field " + ids[0] + " for " + cls.getName()); + failed = true; + } + return null; + } + /** + * Get private field + */ + private Field getPrivateField(Class cls, String[] ids, Class type) { + if((cls == null) || (type == null)) return null; + for(String id : ids) { + try { + Field f = cls.getDeclaredField(id); + if(f.getType().isAssignableFrom(type)) { + f.setAccessible(true); + return f; + } + } catch (NoSuchFieldException nsfx) { + } + } + Log.severe("Unable to find field " + ids[0] + " for " + cls.getName()); + failed = true; + return null; + } + private Object getFieldValue(Object obj, Field field, Object def) { + if((obj != null) && (field != null)) { + try { + return field.get(obj); + } catch (IllegalArgumentException e) { + } catch (IllegalAccessException e) { + } + } + return def; + } + /** + * Get method + */ + protected Method getMethod(Class cls, String[] ids, Class[] args) { + if(cls == null) return null; + for(String id : ids) { + try { + return cls.getMethod(id, args); + } catch (SecurityException e) { + } catch (NoSuchMethodException e) { + } + } + Log.severe("Unable to find method " + ids[0] + " for " + cls.getName()); + failed = true; + return null; + } + private Object callMethod(Object obj, Method meth, Object[] args, Object def) { + if((obj == null) || (meth == null)) { + return def; + } + try { + return meth.invoke(obj, args); + } catch (IllegalArgumentException iax) { + } catch (IllegalAccessException e) { + } catch (InvocationTargetException e) { + } + return def; + } + + + /** + * Get list of defined biomebase objects + */ + public Object[] getBiomeBaseList() { + return (Object[]) getFieldValue(biomebase, biomebaselist, new Object[0]); + } + /** Get temperature from biomebase */ + public float getBiomeBaseTemperature(Object bb) { + return (Float) getFieldValue(bb, biomebasetemp, 0.5F); + } + /** Get humidity from biomebase */ + public float getBiomeBaseHumidity(Object bb) { + return (Float) getFieldValue(bb, biomebasehumi, 0.5F); + } + /** Get ID string from biomebase */ + public String getBiomeBaseIDString(Object bb) { + return (String) getFieldValue(bb, biomebaseidstring, null); + } + /** Get ID from biomebase */ + public int getBiomeBaseID(Object bb) { + return (Integer) getFieldValue(bb, biomebaseid, -1); + } + + /* Get net.minecraft.server.world for given world */ + public Object getNMSWorld(World w) { + return callMethod(w, cw_gethandle, nullargs, null); + } + + /* Get unload queue for given NMS world */ + public Object getUnloadQueue(Object nmsworld) { + Object cps = getFieldValue(nmsworld, nmsw_chunkproviderserver, null); // Get chunkproviderserver + if(cps != null) { + return getFieldValue(cps, cps_unloadqueue, null); + } + return null; + } + + /* For testing unload queue for presence of givne chunk */ + public boolean isInUnloadQueue(Object unloadqueue, int x, int z) { + if(unloadqueue != null) { + return (Boolean)callMethod(unloadqueue, lhs_containskey, new Object[] { x, z }, true); + } + return true; + } + + public Object[] getBiomeBaseFromSnapshot(ChunkSnapshot css) { + return (Object[])getFieldValue(css, ccss_biome, null); + } + public boolean isCraftChunkSnapshot(ChunkSnapshot css) { + if(craftchunksnapshot != null) { + return craftchunksnapshot.isAssignableFrom(css.getClass()); + } + return false; + } + /** Remove entities from given chunk */ + public void removeEntitiesFromChunk(Chunk c) { + Object omsc = callMethod(c, cc_gethandle, nullargs, null); + if(omsc != null) { + callMethod(omsc, nmsc_removeentities, nullargs, null); + } + } + /** Get tile entities map from chunk */ + public Map getTileEntitiesForChunk(Chunk c) { + Object omsc = callMethod(c, cc_gethandle, nullargs, null); + if(omsc != null) { + return (Map)getFieldValue(omsc, nmsc_tileentities, nullmap); + } + return nullmap; + } + /** + * Get X coordinate of tile entity + */ + public int getTileEntityX(Object te) { + return (Integer)getFieldValue(te, nmst_x, 0); + } + /** + * Get Y coordinate of tile entity + */ + public int getTileEntityY(Object te) { + return (Integer)getFieldValue(te, nmst_y, 0); + } + /** + * Get Z coordinate of tile entity + */ + public int getTileEntityZ(Object te) { + return (Integer)getFieldValue(te, nmst_z, 0); + } + /** + * Read tile entity NBT + */ + public Object readTileEntityNBT(Object te) { + if(nbttagcompound == null) return null; + Object nbt = null; + try { + nbt = nbttagcompound.newInstance(); + } catch (InstantiationException e) { + } catch (IllegalAccessException e) { + } + if(nbt != null) { + callMethod(te, nmst_readnbt, new Object[] { nbt }, null); + } + return nbt; + } + /** + * Get field value from NBT compound + */ + public Object getFieldValue(Object nbt, String field) { + Object val = callMethod(nbt, compound_get, new Object[] { field }, null); + if(val == null) return null; + Class valcls = val.getClass(); + if(valcls.equals(nbttagbyte)) { + return getFieldValue(val, nbttagbyte_val, null); + } + else if(valcls.equals(nbttagshort)) { + return getFieldValue(val, nbttagshort_val, null); + } + else if(valcls.equals(nbttagint)) { + return getFieldValue(val, nbttagint_val, null); + } + else if(valcls.equals(nbttaglong)) { + return getFieldValue(val, nbttaglong_val, null); + } + else if(valcls.equals(nbttagfloat)) { + return getFieldValue(val, nbttagfloat_val, null); + } + else if(valcls.equals(nbttagdouble)) { + return getFieldValue(val, nbttagdouble_val, null); + } + else if(valcls.equals(nbttagbytearray)) { + return getFieldValue(val, nbttagbytearray_val, null); + } + else if(valcls.equals(nbttagstring)) { + return getFieldValue(val, nbttagstring_val, null); + } + else if(valcls.equals(nbttagintarray)) { + return getFieldValue(val, nbttagintarray_val, null); + } + return null; + } +} diff --git a/src/main/java/org/dynmap/bukkit/BukkitVersionHelperMCPC.java b/src/main/java/org/dynmap/bukkit/BukkitVersionHelperMCPC.java new file mode 100644 index 00000000..0068dee5 --- /dev/null +++ b/src/main/java/org/dynmap/bukkit/BukkitVersionHelperMCPC.java @@ -0,0 +1,81 @@ +package org.dynmap.bukkit; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.Map; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.ChunkSnapshot; +import org.bukkit.Server; +import org.bukkit.World; +import org.dynmap.Log; + +/** + * Helper for isolation of bukkit version specific issues + */ +public class BukkitVersionHelperMCPC extends BukkitVersionHelperGeneric { + BukkitVersionHelperMCPC() { + } + @Override + protected String getNMSPackage() { + return ""; + } + @Override + protected void loadNMS() { + /* biomebase */ + biomebase = getNMSClass("yy"); + biomebasearray = getNMSClass("[Lyy;"); + /* world */ + nmsworld = getNMSClass("in"); + /* chunk */ + chunkprovserver = getNMSClass("im"); + nmschunk = getNMSClass("zz"); + /* nbt */ + nbttagcompound = getNMSClass("bq"); + nbttagbyte = getNMSClass("bp"); + nbttagshort = getNMSClass("cb"); + nbttagint = getNMSClass("bx"); + nbttaglong = getNMSClass("bz"); + nbttagfloat = getNMSClass("bv"); + nbttagdouble = getNMSClass("bt"); + nbttagbytearray = getNMSClass("bo"); + nbttagstring = getNMSClass("cc"); + nbttagintarray = getNMSClass("bw"); + /* tileentity */ + nms_tileentity = getNMSClass("any"); + + /** Set up NMS fields **/ + /* biomebase */ + biomebaselist = getField(biomebase, new String[] { "a" }, biomebasearray); + biomebasetemp = getField(biomebase, new String[] { "F" }, float.class); + biomebasehumi = getField(biomebase, new String[] { "G" }, float.class); + biomebaseidstring = getField(biomebase, new String[] { "y" }, String.class); + biomebaseid = getField(biomebase, new String[] { "N" }, int.class); + /* chunk */ + nmsw_chunkproviderserver = getField(nmsworld, new String[] { "b" }, chunkprovserver); + cps_unloadqueue = getFieldNoFail(chunkprovserver, new String[] { "b" }, longhashset); + if(cps_unloadqueue == null) { + Log.info("Unload queue not found - default to unload all chunks"); + } + nmsc_removeentities = getMethod(nmschunk, new String[] { "d" }, new Class[0]); + nmsc_tileentities = getField(nmschunk, new String[] { "i" }, Map.class); + /* nbt */ + compound_get = getMethod(nbttagcompound, new String[] { "a" }, new Class[] { String.class }); + nbttagbyte_val = getField(nbttagbyte, new String[] { "a" }, byte.class); + nbttagshort_val = getField(nbttagshort, new String[] { "a" }, short.class); + nbttagint_val = getField(nbttagint, new String[] { "a" }, int.class); + nbttaglong_val = getField(nbttaglong, new String[] { "a" }, long.class); + nbttagfloat_val = getField(nbttagfloat, new String[] { "a" }, float.class); + nbttagdouble_val = getField(nbttagdouble, new String[] { "a" }, double.class); + nbttagbytearray_val = getField(nbttagbytearray, new String[] { "a" }, byte[].class); + nbttagstring_val = getField(nbttagstring, new String[] { "a" }, String.class); + nbttagintarray_val = getField(nbttagintarray, new String[] { "a" }, int[].class); + /* tileentity */ + nmst_readnbt = getMethod(nms_tileentity, new String[] { "b" }, new Class[] { nbttagcompound }); + nmst_x = getField(nms_tileentity, new String[] { "l" }, int.class); + nmst_y = getField(nms_tileentity, new String[] { "m" }, int.class); + nmst_z = getField(nms_tileentity, new String[] { "n" }, int.class); + } +}