From 07cbd84d4419fb8a17c88f36640d62ce87d62ca3 Mon Sep 17 00:00:00 2001 From: Mike Primm Date: Sun, 9 Dec 2012 22:28:21 -0600 Subject: [PATCH] Combine support for pre 1.4.5 versions and new 1.4.x packaging crud --- .../dynmap/bukkit/BukkitVersionHelper.java | 434 ++++++++++++++++++ .../java/org/dynmap/bukkit/DynmapPlugin.java | 65 +-- .../org/dynmap/bukkit/NewMapChunkCache.java | 155 ++----- 3 files changed, 481 insertions(+), 173 deletions(-) create mode 100644 src/main/java/org/dynmap/bukkit/BukkitVersionHelper.java diff --git a/src/main/java/org/dynmap/bukkit/BukkitVersionHelper.java b/src/main/java/org/dynmap/bukkit/BukkitVersionHelper.java new file mode 100644 index 00000000..c235f9c0 --- /dev/null +++ b/src/main/java/org/dynmap/bukkit/BukkitVersionHelper.java @@ -0,0 +1,434 @@ +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 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 static final BukkitVersionHelper getHelper() { + if(helper == null) { + helper = new BukkitVersionHelper(); + } + 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; + } + + /* 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; + } + /** + * 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/DynmapPlugin.java b/src/main/java/org/dynmap/bukkit/DynmapPlugin.java index 4fc5935e..b75ec953 100644 --- a/src/main/java/org/dynmap/bukkit/DynmapPlugin.java +++ b/src/main/java/org/dynmap/bukkit/DynmapPlugin.java @@ -2,7 +2,6 @@ package org.dynmap.bukkit; import java.io.File; import java.io.IOException; -import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.InetSocketAddress; @@ -16,8 +15,6 @@ import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; import java.util.concurrent.Future; -import net.minecraft.server.BiomeBase; - import org.bukkit.ChatColor; import org.bukkit.Chunk; import org.bukkit.Location; @@ -60,8 +57,6 @@ import org.bukkit.event.world.SpawnChangeEvent; import org.bukkit.event.world.StructureGrowEvent; import org.bukkit.event.world.WorldLoadEvent; import org.bukkit.event.world.WorldUnloadEvent; -import org.bukkit.material.MaterialData; -import org.bukkit.material.Tree; import org.bukkit.permissions.Permission; import org.bukkit.permissions.PermissionDefault; import org.bukkit.plugin.Plugin; @@ -112,7 +107,9 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { /* Lookup cache */ private World last_world; private BukkitWorld last_bworld; - + + private BukkitVersionHelper helper = BukkitVersionHelper.getHelper(); + private final BukkitWorld getWorldByName(String name) { if((last_world != null) && (last_world.getName().equals(name))) { return last_bworld; @@ -636,57 +633,29 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { } public void loadExtraBiomes() { - Field tmpfld; - Field humfld; int cnt = 0; - try { - tmpfld = BiomeBase.class.getField("temperature"); - } catch (NoSuchFieldException nsfx) { - try { - tmpfld = BiomeBase.class.getField("F"); - } catch (NoSuchFieldException nsfx2) { - Log.warning("BiomeBase.temperature field not found"); - tmpfld = null; - } - } - if((tmpfld != null) && (tmpfld.getType().getClass().isAssignableFrom(float.class) == false)) { - tmpfld = null; - } - try { - humfld = BiomeBase.class.getField("humidity"); - } catch (NoSuchFieldException nsfx) { - try { - humfld = BiomeBase.class.getField("G"); - } catch (NoSuchFieldException nsfx2) { - Log.warning("BiomeBase.humidity field not found"); - humfld = null; - } - } - if((humfld != null) && (humfld.getType().getClass().isAssignableFrom(float.class) == false)) { - humfld = null; - } - for(int i = BiomeMap.LAST_WELL_KNOWN+1; i < BiomeBase.biomes.length; i++) { - BiomeBase bb = BiomeBase.biomes[i]; + /* Find array of biomes in biomebase */ + Object[] biomelist = helper.getBiomeBaseList(); + /* Loop through list, starting afer well known biomes */ + for(int i = BiomeMap.LAST_WELL_KNOWN+1; i < biomelist.length; i++) { + Object bb = biomelist[i]; if(bb != null) { - String id = "BIOME_" + i; - float tmp = 0.5F, hum = 0.5F; - try { - id = bb.y; - } catch (Exception x) {} - try { - if(tmpfld != null) - tmp = tmpfld.getFloat(bb); - if(humfld != null) - hum = humfld.getFloat(bb); - } catch (Exception x) { + String id = helper.getBiomeBaseIDString(bb); + if(id == null) { + id = "BIOME_" + i; } + float tmp = helper.getBiomeBaseTemperature(bb); + float hum = helper.getBiomeBaseHumidity(bb); + BiomeMap m = new BiomeMap(i, id, tmp, hum); Log.verboseinfo("Add custom biome [" + m.toString() + "] (" + i + ")"); cnt++; } } - Log.info("Added " + cnt + " custom biome mappings"); + if(cnt > 0) { + Log.info("Added " + cnt + " custom biome mappings"); + } } @Override diff --git a/src/main/java/org/dynmap/bukkit/NewMapChunkCache.java b/src/main/java/org/dynmap/bukkit/NewMapChunkCache.java index 3caf21c8..d83a23b0 100644 --- a/src/main/java/org/dynmap/bukkit/NewMapChunkCache.java +++ b/src/main/java/org/dynmap/bukkit/NewMapChunkCache.java @@ -1,33 +1,13 @@ package org.dynmap.bukkit; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; - -import net.minecraft.server.BiomeBase; -import net.minecraft.server.ChunkProviderServer; -import net.minecraft.server.NBTBase; -import net.minecraft.server.NBTTagByte; -import net.minecraft.server.NBTTagByteArray; -import net.minecraft.server.NBTTagCompound; -import net.minecraft.server.NBTTagDouble; -import net.minecraft.server.NBTTagFloat; -import net.minecraft.server.NBTTagInt; -import net.minecraft.server.NBTTagIntArray; -import net.minecraft.server.NBTTagLong; -import net.minecraft.server.NBTTagShort; -import net.minecraft.server.NBTTagString; -import net.minecraft.server.TileEntity; +import java.util.Map; import org.bukkit.World; import org.bukkit.Chunk; import org.bukkit.block.Biome; -import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.CraftChunkSnapshot; -import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.ChunkSnapshot; import org.dynmap.DynmapChunk; import org.dynmap.DynmapCore; @@ -48,11 +28,7 @@ import org.getspout.spoutapi.block.SpoutChunk; */ public class NewMapChunkCache implements MapChunkCache { private static boolean init = false; - private static boolean use_spout = false; - private static Field unloadqueue = null; - private static Method queuecontainskey = null; - private static Field biomesnapshot = null; - + private static boolean use_spout = false; private World w; private DynmapWorld dw; @@ -80,6 +56,8 @@ public class NewMapChunkCache implements MapChunkCache { private long exceptions; + private static BukkitVersionHelper helper = BukkitVersionHelper.getHelper(); + private static final BlockStep unstep[] = { BlockStep.X_MINUS, BlockStep.Y_MINUS, BlockStep.Z_MINUS, BlockStep.X_PLUS, BlockStep.Y_PLUS, BlockStep.Z_PLUS }; @@ -168,29 +146,23 @@ public class NewMapChunkCache implements MapChunkCache { sameneighborbiomecnt[i] = new byte[z_size]; biomemap[i] = new BiomeMap[z_size]; } - BiomeBase[] biomebase = null; + Object[] biomebase = null; ChunkSnapshot biome_css = null; for(int i = 0; i < x_size; i++) { initialize(i + x_base, 64, z_base); for(int j = 0; j < z_size; j++) { BiomeMap bm; - if((biomesnapshot != null) && (snap != biome_css)) { + if(snap != biome_css) { biomebase = null; biome_css = snap; - try { - if (biome_css instanceof SpoutChunkSnapshot) { - biome_css = ((SpoutChunkSnapshot)biome_css).chunk; - } - if(biome_css instanceof CraftChunkSnapshot) { - biomebase = (BiomeBase[]) biomesnapshot.get(biome_css); - } - } catch (IllegalArgumentException iax) { - } catch (IllegalAccessException e) { + if (biome_css instanceof SpoutChunkSnapshot) { + biome_css = ((SpoutChunkSnapshot)biome_css).chunk; } + biomebase = helper.getBiomeBaseFromSnapshot(biome_css); } if(biomebase != null) { - bm = BiomeMap.byBiomeID(biomebase[bz << 4 | bx].id); + bm = BiomeMap.byBiomeID(helper.getBiomeBaseID(biomebase[bz << 4 | bx])); } else { Biome bb = snap.getBiome(bx, bz); @@ -758,28 +730,6 @@ public class NewMapChunkCache implements MapChunkCache { if(!init) { use_spout = DynmapPlugin.plugin.hasSpout(); - try { - unloadqueue = ChunkProviderServer.class.getField("unloadQueue"); - Class cls = unloadqueue.getType(); - String nm = cls.getName(); - if (nm.equals("org.bukkit.craftbukkit.util.LongHashset")) { - queuecontainskey = unloadqueue.getType().getMethod("containsKey", new Class[] { int.class, int.class }); - } - else { - unloadqueue = null; - } - } catch (NoSuchFieldException nsfx) { - unloadqueue = null; - } catch (NoSuchMethodException nsmx) { - unloadqueue = null; - } - try { - biomesnapshot = CraftChunkSnapshot.class.getDeclaredField("biome"); - biomesnapshot.setAccessible(true); - } catch (NoSuchFieldException nsfx) { - biomesnapshot = null; - Log.warning("Unable to find biome field in ChunkSnapshot"); - } init = true; } } @@ -836,15 +786,8 @@ public class NewMapChunkCache implements MapChunkCache { if(dw.isLoaded() == false) return 0; long t0 = System.nanoTime(); - CraftWorld cw = (CraftWorld)w; - Object queue = null; - try { - if (unloadqueue != null) { - queue = unloadqueue.get(cw.getHandle().chunkProviderServer); - } - } catch (IllegalArgumentException iax) { - } catch (IllegalAccessException e) { - } + Object queue = helper.getUnloadQueue(helper.getNMSWorld(w)); + int cnt = 0; if(iterator == null) iterator = chunks.listIterator(); @@ -897,12 +840,7 @@ public class NewMapChunkCache implements MapChunkCache { boolean didload = false; boolean isunloadpending = false; if (queue != null) { - try { - isunloadpending = (Boolean)queuecontainskey.invoke(queue, chunk.x, chunk.z); - } catch (IllegalAccessException iax) { - } catch (IllegalArgumentException e) { - } catch (InvocationTargetException e) { - } + isunloadpending = helper.isInUnloadQueue(queue, chunk.x, chunk.z); } if (isunloadpending) { /* Workaround: can't be pending if not loaded */ wasLoaded = true; @@ -958,62 +896,30 @@ public class NewMapChunkCache implements MapChunkCache { } /* Get tile entity data */ List vals = new ArrayList(); - for(Object t : ((CraftChunk)c).getHandle().tileEntities.values()) { - TileEntity te = (TileEntity)t; - int cx = te.x & 0xF; - int cz = te.z & 0xF; - int blkid = ss.getBlockTypeId(cx, te.y, cz); - int blkdat = ss.getBlockData(cx, te.y, cz); + Map tileents = helper.getTileEntitiesForChunk(c); + for(Object t : tileents.values()) { + int te_x = helper.getTileEntityX(t); + int te_y = helper.getTileEntityY(t); + int te_z = helper.getTileEntityZ(t); + int cx = te_x & 0xF; + int cz = te_z & 0xF; + int blkid = ss.getBlockTypeId(cx, te_y, cz); + int blkdat = ss.getBlockData(cx, te_y, cz); String[] te_fields = HDBlockModels.getTileEntityFieldsNeeded(blkid, blkdat); if(te_fields != null) { - NBTTagCompound tc = new NBTTagCompound(); - try { - te.b(tc); - } catch (Exception x) { - } + Object nbtcompound = helper.readTileEntityNBT(t); + vals.clear(); for(String id: te_fields) { - NBTBase v = tc.get(id); /* Get field */ - if(v != null) { - Object val = null; - switch(v.getTypeId()) { - case 1: // Byte - val = Byte.valueOf(((NBTTagByte)v).data); - break; - case 2: // Short - val = Short.valueOf(((NBTTagShort)v).data); - break; - case 3: // Int - val = Integer.valueOf(((NBTTagInt)v).data); - break; - case 4: // Long - val = Long.valueOf(((NBTTagLong)v).data); - break; - case 5: // Float - val = Float.valueOf(((NBTTagFloat)v).data); - break; - case 6: // Double - val = Double.valueOf(((NBTTagDouble)v).data); - break; - case 7: // Byte[] - val = ((NBTTagByteArray)v).data; - break; - case 8: // String - val = ((NBTTagString)v).data; - break; - case 11: // Int[] - val = ((NBTTagIntArray)v).data; - break; - } - if(val != null) { - vals.add(id); - vals.add(val); - } + Object val = helper.getFieldValue(nbtcompound, id); + if(val != null) { + vals.add(id); + vals.add(val); } } if(vals.size() > 0) { Object[] vlist = vals.toArray(new Object[vals.size()]); - tileData.put(getIndexInChunk(cx,te.y,cz), vlist); + tileData.put(getIndexInChunk(cx,te_y,cz), vlist); } } } @@ -1036,8 +942,7 @@ public class NewMapChunkCache implements MapChunkCache { /* It looks like bukkit "leaks" entities - they don't get removed from the world-level table * when chunks are unloaded but not saved - removing them seems to do the trick */ if(!(didgenerate && do_save)) { - CraftChunk cc = (CraftChunk)c; - cc.getHandle().removeEntities(); + helper.removeEntitiesFromChunk(c); } /* Since we only remember ones we loaded, and we're synchronous, no player has * moved, so it must be safe (also prevent chunk leak, which appears to happen