diff --git a/pom.xml b/pom.xml index 79970fe8..07847991 100644 --- a/pom.xml +++ b/pom.xml @@ -179,5 +179,10 @@ system ${project.basedir}/PermissionsBukkit.jar + + org.bukkit + craftbukkit + 1.2.5-R5.1-SNAPSHOT + diff --git a/src/main/java/org/dynmap/bukkit/NewMapChunkCache.java b/src/main/java/org/dynmap/bukkit/NewMapChunkCache.java index 9493226c..c1a8b74e 100644 --- a/src/main/java/org/dynmap/bukkit/NewMapChunkCache.java +++ b/src/main/java/org/dynmap/bukkit/NewMapChunkCache.java @@ -1,8 +1,5 @@ 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.Arrays; import java.util.List; @@ -11,7 +8,9 @@ import java.util.ListIterator; import org.bukkit.World; import org.bukkit.Chunk; import org.bukkit.block.Biome; -import org.bukkit.entity.Entity; +import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.util.LongHashset; import org.bukkit.ChunkSnapshot; import org.dynmap.DynmapChunk; import org.dynmap.DynmapCore; @@ -28,11 +27,7 @@ import org.getspout.spoutapi.block.SpoutChunk; */ public class NewMapChunkCache implements MapChunkCache { private static boolean init = false; - private static Method gethandle = null; - private static Method removeentities = null; - private static Field doneflag = null; private static boolean use_spout = false; - private static boolean use_sections = false; private World w; private DynmapWorld dw; @@ -660,32 +655,8 @@ public class NewMapChunkCache implements MapChunkCache { /** * Construct empty cache */ - @SuppressWarnings({ "rawtypes", "unchecked" }) public NewMapChunkCache() { if(!init) { - /* Get CraftChunk.getChunkSnapshot(boolean,boolean,boolean) and CraftChunk.getHandle() */ - try { - Class c = Class.forName("org.bukkit.craftbukkit.CraftChunk"); - gethandle = c.getDeclaredMethod("getHandle", new Class[0]); - } catch (ClassNotFoundException cnfx) { - } catch (NoSuchMethodException nsmx) { - } - /* Get Chunk.removeEntities() */ - try { - Class c = Class.forName("net.minecraft.server.Chunk"); - removeentities = c.getDeclaredMethod("removeEntities", new Class[0]); - doneflag = c.getField("done"); - } catch (ClassNotFoundException cnfx) { - } catch (NoSuchMethodException nsmx) { - } catch (NoSuchFieldException nsfx) { - } - /* Check for ChunkSnapshot.isSectionEmpty(int) method */ - try { - ChunkSnapshot.class.getDeclaredMethod("isSectionEmpty", new Class[] { int.class }); - use_sections = true; - } catch (NoSuchMethodException nsmx) { - } - use_spout = DynmapPlugin.plugin.hasSpout(); init = true; @@ -737,6 +708,8 @@ public class NewMapChunkCache implements MapChunkCache { public int loadChunks(int max_to_load) { long t0 = System.nanoTime(); + CraftWorld cw = (CraftWorld)w; + LongHashset unloadqueue = cw.getHandle().chunkProviderServer.unloadQueue; int cnt = 0; if(iterator == null) iterator = chunks.listIterator(); @@ -781,8 +754,17 @@ public class NewMapChunkCache implements MapChunkCache { chunks_attempted++; boolean wasLoaded = w.isChunkLoaded(chunk.x, chunk.z); boolean didload = false; + boolean isunloadpending = unloadqueue.containsKey(chunk.x, chunk.z); + if (isunloadpending) { /* Workaround: can't be pending if not loaded */ + wasLoaded = true; + } try { - didload = w.loadChunk(chunk.x, chunk.z, false); + if (!wasLoaded) { + didload = w.loadChunk(chunk.x, chunk.z, false); + } + else { /* If already was loaded, no need to load */ + didload = true; + } } catch (Throwable t) { /* Catch chunk error from Bukkit */ Log.warning("Bukkit error loading chunk " + chunk.x + "," + chunk.z + " on " + w.getName()); if(!wasLoaded) { /* If wasn't loaded, we loaded it if it now is */ @@ -796,16 +778,6 @@ public class NewMapChunkCache implements MapChunkCache { /* If it did load, make cache of it */ if(didload) { Chunk c = w.getChunkAt(chunk.x, chunk.z); /* Get the chunk */ - /* Try to get n.m.s.Chunk handle */ - Object nmschunk = null; - if(gethandle != null) { - try { - nmschunk = gethandle.invoke(c); - } catch (InvocationTargetException itx) { - } catch (IllegalArgumentException e) { - } catch (IllegalAccessException e) { - } - } /* Test if chunk isn't populated */ boolean populated = true; //TODO: figure out why this doesn't appear to be reliable in Bukkit @@ -847,24 +819,8 @@ 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)) { - boolean did_remove = false; - if(removeentities != null) { - try { - if(nmschunk != null) { - removeentities.invoke(nmschunk); - did_remove = true; - } - } catch (InvocationTargetException itx) { - } catch (IllegalArgumentException e) { - } catch (IllegalAccessException e) { - } - } - if(!did_remove) { - if(c != null) { - for(Entity e: c.getEntities()) - e.remove(); - } - } + CraftChunk cc = (CraftChunk)c; + cc.getHandle().removeEntities(); } /* 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 @@ -874,6 +830,9 @@ public class NewMapChunkCache implements MapChunkCache { * Also, if we did generate it, need to save it */ w.unloadChunk(chunk.x, chunk.z, didgenerate && do_save, false); } + else if (isunloadpending) { /* Else, if loaded and unload is pending */ + w.unloadChunkRequest(chunk.x, chunk.z); /* Request new unload */ + } } cnt++; } @@ -960,14 +919,9 @@ public class NewMapChunkCache implements MapChunkCache { private void initSectionData(int idx) { isSectionNotEmpty[idx] = new boolean[nsect + 1]; if(snaparray[idx] != EMPTY) { - if(!use_sections) { - Arrays.fill(isSectionNotEmpty[idx], true); - } - else { - for(int i = 0; i < nsect; i++) { - if(snaparray[idx].isSectionEmpty(i) == false) { - isSectionNotEmpty[idx][i] = true; - } + for(int i = 0; i < nsect; i++) { + if(snaparray[idx].isSectionEmpty(i) == false) { + isSectionNotEmpty[idx][i] = true; } } } @@ -1083,8 +1037,8 @@ public class NewMapChunkCache implements MapChunkCache { static { Biome[] b = Biome.values(); BiomeMap[] bm = BiomeMap.values(); - biome_to_bmap = new BiomeMap[b.length]; - for(int i = 0; i < b.length; i++) { + biome_to_bmap = new BiomeMap[256]; + for(int i = 0; i < biome_to_bmap.length; i++) { biome_to_bmap[i] = BiomeMap.NULL; } for(int i = 0; i < b.length; i++) {