Add tile entity data collection

This commit is contained in:
Mike Primm 2012-11-22 00:50:55 -06:00
parent 3a57261120
commit c6d345d8f1
2 changed files with 128 additions and 20 deletions

View File

@ -4,12 +4,23 @@ import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import net.minecraft.server.BiomeBase; import net.minecraft.server.BiomeBase;
import net.minecraft.server.ChunkProviderServer; 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 org.bukkit.World; import org.bukkit.World;
import org.bukkit.Chunk; import org.bukkit.Chunk;
@ -17,16 +28,16 @@ import org.bukkit.block.Biome;
import org.bukkit.craftbukkit.CraftChunk; import org.bukkit.craftbukkit.CraftChunk;
import org.bukkit.craftbukkit.CraftChunkSnapshot; import org.bukkit.craftbukkit.CraftChunkSnapshot;
import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.util.LongHashset;
import org.bukkit.ChunkSnapshot; import org.bukkit.ChunkSnapshot;
import org.dynmap.DynmapChunk; import org.dynmap.DynmapChunk;
import org.dynmap.DynmapCore; import org.dynmap.DynmapCore;
import org.dynmap.DynmapWorld; import org.dynmap.DynmapWorld;
import org.dynmap.Log; import org.dynmap.Log;
import org.dynmap.bukkit.SnapshotCache.SnapshotRec;
import org.dynmap.common.BiomeMap; import org.dynmap.common.BiomeMap;
import org.dynmap.hdmap.HDBlockModels; import org.dynmap.hdmap.HDBlockModels;
import org.dynmap.hdmap.HDBlockModels.HDBlockModel;
import org.dynmap.renderer.RenderPatchFactory; import org.dynmap.renderer.RenderPatchFactory;
import org.dynmap.utils.DynIntHashMap;
import org.dynmap.utils.MapChunkCache; import org.dynmap.utils.MapChunkCache;
import org.dynmap.utils.MapIterator; import org.dynmap.utils.MapIterator;
import org.dynmap.utils.BlockStep; import org.dynmap.utils.BlockStep;
@ -58,6 +69,7 @@ public class NewMapChunkCache implements MapChunkCache {
private boolean do_save = false; private boolean do_save = false;
private boolean isempty = true; private boolean isempty = true;
private ChunkSnapshot[] snaparray; /* Index = (x-x_min) + ((z-z_min)*x_dim) */ private ChunkSnapshot[] snaparray; /* Index = (x-x_min) + ((z-z_min)*x_dim) */
private DynIntHashMap[] snaptile;
private byte[][] sameneighborbiomecnt; private byte[][] sameneighborbiomecnt;
private BiomeMap[][] biomemap; private BiomeMap[][] biomemap;
private boolean[][] isSectionNotEmpty; /* Indexed by snapshot index, then by section index */ private boolean[][] isSectionNotEmpty; /* Indexed by snapshot index, then by section index */
@ -73,6 +85,10 @@ public class NewMapChunkCache implements MapChunkCache {
private static BiomeMap[] biome_to_bmap; private static BiomeMap[] biome_to_bmap;
private static final int getIndexInChunk(int cx, int cy, int cz) {
return (cy << 8) | (cz << 4) | cx;
}
/** /**
* Iterator for traversing map chunk cache (base is for non-snapshot) * Iterator for traversing map chunk cache (base is for non-snapshot)
*/ */
@ -552,6 +568,16 @@ public class NewMapChunkCache implements MapChunkCache {
} }
@Override @Override
public Object getBlockTileEntityField(String fieldId) { public Object getBlockTileEntityField(String fieldId) {
try {
int idx = getIndexInChunk(bx,y,bz);
Object[] vals = (Object[])snaptile[chunkindex].get(idx);
for (int i = 0; i < vals.length; i += 2) {
if (vals[i].equals(fieldId)) {
return vals[i+1];
}
}
} catch (Exception x) {
}
return null; return null;
} }
@Override @Override
@ -789,8 +815,10 @@ public class NewMapChunkCache implements MapChunkCache {
x_dim = x_max - x_min + 1; x_dim = x_max - x_min + 1;
} }
snaparray = new ChunkSnapshot[x_dim * (z_max-z_min+1)]; int snapcnt = x_dim * (z_max-z_min+1);
isSectionNotEmpty = new boolean[x_dim * (z_max-z_min+1)][]; snaparray = new ChunkSnapshot[snapcnt];
snaptile = new DynIntHashMap[snapcnt];
isSectionNotEmpty = new boolean[snapcnt][];
} }
private ChunkSnapshot checkSpoutData(Chunk c, ChunkSnapshot ss) { private ChunkSnapshot checkSpoutData(Chunk c, ChunkSnapshot ss) {
@ -845,8 +873,11 @@ public class NewMapChunkCache implements MapChunkCache {
} }
} }
/* Check if cached chunk snapshot found */ /* Check if cached chunk snapshot found */
ChunkSnapshot ss = DynmapPlugin.plugin.sscache.getSnapshot(dw.getName(), chunk.x, chunk.z, blockdata, biome, biomeraw, highesty); ChunkSnapshot ss = null;
if(ss != null) { DynIntHashMap tileData = null;
SnapshotRec ssr = DynmapPlugin.plugin.sscache.getSnapshot(dw.getName(), chunk.x, chunk.z, blockdata, biome, biomeraw, highesty);
if(ssr != null) {
ss = ssr.ss;
if(!vis) { if(!vis) {
if(hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) if(hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN)
ss = STONE; ss = STONE;
@ -855,7 +886,10 @@ public class NewMapChunkCache implements MapChunkCache {
else else
ss = EMPTY; ss = EMPTY;
} }
snaparray[(chunk.x-x_min) + (chunk.z - z_min)*x_dim] = ss; int idx = (chunk.x-x_min) + (chunk.z - z_min)*x_dim;
snaparray[idx] = ss;
snaptile[idx] = ssr.tileData;
continue; continue;
} }
chunks_attempted++; chunks_attempted++;
@ -892,6 +926,8 @@ public class NewMapChunkCache implements MapChunkCache {
didgenerate = didload = w.loadChunk(chunk.x, chunk.z, true); didgenerate = didload = w.loadChunk(chunk.x, chunk.z, true);
/* If it did load, make cache of it */ /* If it did load, make cache of it */
if(didload) { if(didload) {
tileData = new DynIntHashMap();
Chunk c = w.getChunkAt(chunk.x, chunk.z); /* Get the chunk */ Chunk c = w.getChunkAt(chunk.x, chunk.z); /* Get the chunk */
/* Test if chunk isn't populated */ /* Test if chunk isn't populated */
boolean populated = true; boolean populated = true;
@ -920,14 +956,80 @@ public class NewMapChunkCache implements MapChunkCache {
if(use_spout) { if(use_spout) {
ss = checkSpoutData(c, ss); ss = checkSpoutData(c, ss);
} }
/* Get tile entity data */
List<Object> vals = new ArrayList<Object>();
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);
String[] te_fields = HDBlockModels.getTileEntityFieldsNeeded(blkid, blkdat);
if(te_fields != null) {
NBTTagCompound tc = new NBTTagCompound();
try {
te.b(tc);
} catch (Exception x) {
}
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);
}
}
}
if(vals.size() > 0) {
Object[] vlist = vals.toArray(new Object[vals.size()]);
tileData.put(getIndexInChunk(cx,te.y,cz), vlist);
}
}
}
} }
else else
ss = w.getEmptyChunkSnapshot(chunk.x, chunk.z, biome, biomeraw); ss = w.getEmptyChunkSnapshot(chunk.x, chunk.z, biome, biomeraw);
if(ss != null) { if(ss != null) {
DynmapPlugin.plugin.sscache.putSnapshot(dw.getName(), chunk.x, chunk.z, ss, blockdata, biome, biomeraw, highesty); ssr = new SnapshotRec();
ssr.ss = ss;
ssr.tileData = tileData;
DynmapPlugin.plugin.sscache.putSnapshot(dw.getName(), chunk.x, chunk.z, ssr, blockdata, biome, biomeraw, highesty);
} }
} }
snaparray[(chunk.x-x_min) + (chunk.z - z_min)*x_dim] = ss; snaparray[(chunk.x-x_min) + (chunk.z - z_min)*x_dim] = ss;
snaptile[(chunk.x-x_min) + (chunk.z - z_min)*x_dim] = tileData;
/* If wasn't loaded before, we need to do unload */ /* If wasn't loaded before, we need to do unload */
if (!wasLoaded) { if (!wasLoaded) {
chunks_read++; chunks_read++;

View File

@ -8,15 +8,21 @@ import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import org.bukkit.ChunkSnapshot; import org.bukkit.ChunkSnapshot;
import org.dynmap.utils.DynIntHashMap;
public class SnapshotCache { public class SnapshotCache {
public static class SnapshotRec {
public ChunkSnapshot ss;
public DynIntHashMap tileData;
};
private CacheHashMap snapcache; private CacheHashMap snapcache;
private ReferenceQueue<ChunkSnapshot> refqueue; private ReferenceQueue<SnapshotRec> refqueue;
private long cache_attempts; private long cache_attempts;
private long cache_success; private long cache_success;
private static class CacheRec { private static class CacheRec {
WeakReference<ChunkSnapshot> ref; WeakReference<SnapshotRec> ref;
boolean hasbiome; boolean hasbiome;
boolean hasrawbiome; boolean hasrawbiome;
boolean hasblockdata; boolean hasblockdata;
@ -26,12 +32,12 @@ public class SnapshotCache {
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class CacheHashMap extends LinkedHashMap<String, CacheRec> { public class CacheHashMap extends LinkedHashMap<String, CacheRec> {
private int limit; private int limit;
private IdentityHashMap<WeakReference<ChunkSnapshot>, String> reverselookup; private IdentityHashMap<WeakReference<SnapshotRec>, String> reverselookup;
public CacheHashMap(int lim) { public CacheHashMap(int lim) {
super(16, (float)0.75, true); super(16, (float)0.75, true);
limit = lim; limit = lim;
reverselookup = new IdentityHashMap<WeakReference<ChunkSnapshot>, String>(); reverselookup = new IdentityHashMap<WeakReference<SnapshotRec>, String>();
} }
protected boolean removeEldestEntry(Map.Entry<String, CacheRec> last) { protected boolean removeEldestEntry(Map.Entry<String, CacheRec> last) {
boolean remove = (size() >= limit); boolean remove = (size() >= limit);
@ -47,7 +53,7 @@ public class SnapshotCache {
*/ */
public SnapshotCache(int max_size) { public SnapshotCache(int max_size) {
snapcache = new CacheHashMap(max_size); snapcache = new CacheHashMap(max_size);
refqueue = new ReferenceQueue<ChunkSnapshot>(); refqueue = new ReferenceQueue<SnapshotRec>();
} }
private String getKey(String w, int cx, int cz) { private String getKey(String w, int cx, int cz) {
return w + ":" + cx + ":" + cz; return w + ":" + cx + ":" + cz;
@ -83,11 +89,11 @@ public class SnapshotCache {
/** /**
* Look for chunk snapshot in cache * Look for chunk snapshot in cache
*/ */
public ChunkSnapshot getSnapshot(String w, int chunkx, int chunkz, public SnapshotRec getSnapshot(String w, int chunkx, int chunkz,
boolean blockdata, boolean biome, boolean biomeraw, boolean highesty) { boolean blockdata, boolean biome, boolean biomeraw, boolean highesty) {
String key = getKey(w, chunkx, chunkz); String key = getKey(w, chunkx, chunkz);
processRefQueue(); processRefQueue();
ChunkSnapshot ss = null; SnapshotRec ss = null;
CacheRec rec = snapcache.get(key); CacheRec rec = snapcache.get(key);
if(rec != null) { if(rec != null) {
ss = rec.ref.get(); ss = rec.ref.get();
@ -112,7 +118,7 @@ public class SnapshotCache {
/** /**
* Add chunk snapshot to cache * Add chunk snapshot to cache
*/ */
public void putSnapshot(String w, int chunkx, int chunkz, ChunkSnapshot ss, public void putSnapshot(String w, int chunkx, int chunkz, SnapshotRec ss,
boolean blockdata, boolean biome, boolean biomeraw, boolean highesty) { boolean blockdata, boolean biome, boolean biomeraw, boolean highesty) {
String key = getKey(w, chunkx, chunkz); String key = getKey(w, chunkx, chunkz);
processRefQueue(); processRefQueue();
@ -121,7 +127,7 @@ public class SnapshotCache {
rec.hasbiome = biome; rec.hasbiome = biome;
rec.hasrawbiome = biomeraw; rec.hasrawbiome = biomeraw;
rec.hashighesty = highesty; rec.hashighesty = highesty;
rec.ref = new WeakReference<ChunkSnapshot>(ss, refqueue); rec.ref = new WeakReference<SnapshotRec>(ss, refqueue);
CacheRec prevrec = snapcache.put(key, rec); CacheRec prevrec = snapcache.put(key, rec);
if(prevrec != null) { if(prevrec != null) {
snapcache.reverselookup.remove(prevrec.ref); snapcache.reverselookup.remove(prevrec.ref);
@ -132,7 +138,7 @@ public class SnapshotCache {
* Process reference queue * Process reference queue
*/ */
private void processRefQueue() { private void processRefQueue() {
Reference<? extends ChunkSnapshot> ref; Reference<? extends SnapshotRec> ref;
while((ref = refqueue.poll()) != null) { while((ref = refqueue.poll()) != null) {
String k = snapcache.reverselookup.remove(ref); String k = snapcache.reverselookup.remove(ref);
if(k != null) { if(k != null) {