mirror of
https://github.com/webbukkit/dynmap.git
synced 2024-12-27 11:07:38 +01:00
Combine support for pre 1.4.5 versions and new 1.4.x packaging crud
This commit is contained in:
parent
da5e2cf24a
commit
07cbd84d44
434
src/main/java/org/dynmap/bukkit/BukkitVersionHelper.java
Normal file
434
src/main/java/org/dynmap/bukkit/BukkitVersionHelper.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,6 @@ package org.dynmap.bukkit;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
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.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
@ -16,8 +15,6 @@ import java.util.concurrent.Callable;
|
|||||||
import java.util.concurrent.CancellationException;
|
import java.util.concurrent.CancellationException;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
import net.minecraft.server.BiomeBase;
|
|
||||||
|
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.Chunk;
|
import org.bukkit.Chunk;
|
||||||
import org.bukkit.Location;
|
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.StructureGrowEvent;
|
||||||
import org.bukkit.event.world.WorldLoadEvent;
|
import org.bukkit.event.world.WorldLoadEvent;
|
||||||
import org.bukkit.event.world.WorldUnloadEvent;
|
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.Permission;
|
||||||
import org.bukkit.permissions.PermissionDefault;
|
import org.bukkit.permissions.PermissionDefault;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
@ -113,6 +108,8 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
|||||||
private World last_world;
|
private World last_world;
|
||||||
private BukkitWorld last_bworld;
|
private BukkitWorld last_bworld;
|
||||||
|
|
||||||
|
private BukkitVersionHelper helper = BukkitVersionHelper.getHelper();
|
||||||
|
|
||||||
private final BukkitWorld getWorldByName(String name) {
|
private final BukkitWorld getWorldByName(String name) {
|
||||||
if((last_world != null) && (last_world.getName().equals(name))) {
|
if((last_world != null) && (last_world.getName().equals(name))) {
|
||||||
return last_bworld;
|
return last_bworld;
|
||||||
@ -636,57 +633,29 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void loadExtraBiomes() {
|
public void loadExtraBiomes() {
|
||||||
Field tmpfld;
|
|
||||||
Field humfld;
|
|
||||||
int cnt = 0;
|
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++) {
|
/* Find array of biomes in biomebase */
|
||||||
BiomeBase bb = BiomeBase.biomes[i];
|
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) {
|
if(bb != null) {
|
||||||
String id = "BIOME_" + i;
|
String id = helper.getBiomeBaseIDString(bb);
|
||||||
float tmp = 0.5F, hum = 0.5F;
|
if(id == null) {
|
||||||
try {
|
id = "BIOME_" + i;
|
||||||
id = bb.y;
|
|
||||||
} catch (Exception x) {}
|
|
||||||
try {
|
|
||||||
if(tmpfld != null)
|
|
||||||
tmp = tmpfld.getFloat(bb);
|
|
||||||
if(humfld != null)
|
|
||||||
hum = humfld.getFloat(bb);
|
|
||||||
} catch (Exception x) {
|
|
||||||
}
|
}
|
||||||
|
float tmp = helper.getBiomeBaseTemperature(bb);
|
||||||
|
float hum = helper.getBiomeBaseHumidity(bb);
|
||||||
|
|
||||||
BiomeMap m = new BiomeMap(i, id, tmp, hum);
|
BiomeMap m = new BiomeMap(i, id, tmp, hum);
|
||||||
Log.verboseinfo("Add custom biome [" + m.toString() + "] (" + i + ")");
|
Log.verboseinfo("Add custom biome [" + m.toString() + "] (" + i + ")");
|
||||||
cnt++;
|
cnt++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Log.info("Added " + cnt + " custom biome mappings");
|
if(cnt > 0) {
|
||||||
|
Log.info("Added " + cnt + " custom biome mappings");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,33 +1,13 @@
|
|||||||
package org.dynmap.bukkit;
|
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.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ListIterator;
|
import java.util.ListIterator;
|
||||||
|
import java.util.Map;
|
||||||
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 org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.Chunk;
|
import org.bukkit.Chunk;
|
||||||
import org.bukkit.block.Biome;
|
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.bukkit.ChunkSnapshot;
|
||||||
import org.dynmap.DynmapChunk;
|
import org.dynmap.DynmapChunk;
|
||||||
import org.dynmap.DynmapCore;
|
import org.dynmap.DynmapCore;
|
||||||
@ -49,10 +29,6 @@ import org.getspout.spoutapi.block.SpoutChunk;
|
|||||||
public class NewMapChunkCache implements MapChunkCache {
|
public class NewMapChunkCache implements MapChunkCache {
|
||||||
private static boolean init = false;
|
private static boolean init = false;
|
||||||
private static boolean use_spout = false;
|
private static boolean use_spout = false;
|
||||||
private static Field unloadqueue = null;
|
|
||||||
private static Method queuecontainskey = null;
|
|
||||||
private static Field biomesnapshot = null;
|
|
||||||
|
|
||||||
|
|
||||||
private World w;
|
private World w;
|
||||||
private DynmapWorld dw;
|
private DynmapWorld dw;
|
||||||
@ -80,6 +56,8 @@ public class NewMapChunkCache implements MapChunkCache {
|
|||||||
|
|
||||||
private long exceptions;
|
private long exceptions;
|
||||||
|
|
||||||
|
private static BukkitVersionHelper helper = BukkitVersionHelper.getHelper();
|
||||||
|
|
||||||
private static final BlockStep unstep[] = { BlockStep.X_MINUS, BlockStep.Y_MINUS, BlockStep.Z_MINUS,
|
private static final BlockStep unstep[] = { BlockStep.X_MINUS, BlockStep.Y_MINUS, BlockStep.Z_MINUS,
|
||||||
BlockStep.X_PLUS, BlockStep.Y_PLUS, BlockStep.Z_PLUS };
|
BlockStep.X_PLUS, BlockStep.Y_PLUS, BlockStep.Z_PLUS };
|
||||||
|
|
||||||
@ -168,29 +146,23 @@ public class NewMapChunkCache implements MapChunkCache {
|
|||||||
sameneighborbiomecnt[i] = new byte[z_size];
|
sameneighborbiomecnt[i] = new byte[z_size];
|
||||||
biomemap[i] = new BiomeMap[z_size];
|
biomemap[i] = new BiomeMap[z_size];
|
||||||
}
|
}
|
||||||
BiomeBase[] biomebase = null;
|
Object[] biomebase = null;
|
||||||
ChunkSnapshot biome_css = null;
|
ChunkSnapshot biome_css = null;
|
||||||
for(int i = 0; i < x_size; i++) {
|
for(int i = 0; i < x_size; i++) {
|
||||||
initialize(i + x_base, 64, z_base);
|
initialize(i + x_base, 64, z_base);
|
||||||
for(int j = 0; j < z_size; j++) {
|
for(int j = 0; j < z_size; j++) {
|
||||||
BiomeMap bm;
|
BiomeMap bm;
|
||||||
|
|
||||||
if((biomesnapshot != null) && (snap != biome_css)) {
|
if(snap != biome_css) {
|
||||||
biomebase = null;
|
biomebase = null;
|
||||||
biome_css = snap;
|
biome_css = snap;
|
||||||
try {
|
if (biome_css instanceof SpoutChunkSnapshot) {
|
||||||
if (biome_css instanceof SpoutChunkSnapshot) {
|
biome_css = ((SpoutChunkSnapshot)biome_css).chunk;
|
||||||
biome_css = ((SpoutChunkSnapshot)biome_css).chunk;
|
|
||||||
}
|
|
||||||
if(biome_css instanceof CraftChunkSnapshot) {
|
|
||||||
biomebase = (BiomeBase[]) biomesnapshot.get(biome_css);
|
|
||||||
}
|
|
||||||
} catch (IllegalArgumentException iax) {
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
}
|
}
|
||||||
|
biomebase = helper.getBiomeBaseFromSnapshot(biome_css);
|
||||||
}
|
}
|
||||||
if(biomebase != null) {
|
if(biomebase != null) {
|
||||||
bm = BiomeMap.byBiomeID(biomebase[bz << 4 | bx].id);
|
bm = BiomeMap.byBiomeID(helper.getBiomeBaseID(biomebase[bz << 4 | bx]));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Biome bb = snap.getBiome(bx, bz);
|
Biome bb = snap.getBiome(bx, bz);
|
||||||
@ -758,28 +730,6 @@ public class NewMapChunkCache implements MapChunkCache {
|
|||||||
if(!init) {
|
if(!init) {
|
||||||
use_spout = DynmapPlugin.plugin.hasSpout();
|
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;
|
init = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -836,15 +786,8 @@ public class NewMapChunkCache implements MapChunkCache {
|
|||||||
if(dw.isLoaded() == false)
|
if(dw.isLoaded() == false)
|
||||||
return 0;
|
return 0;
|
||||||
long t0 = System.nanoTime();
|
long t0 = System.nanoTime();
|
||||||
CraftWorld cw = (CraftWorld)w;
|
Object queue = helper.getUnloadQueue(helper.getNMSWorld(w));
|
||||||
Object queue = null;
|
|
||||||
try {
|
|
||||||
if (unloadqueue != null) {
|
|
||||||
queue = unloadqueue.get(cw.getHandle().chunkProviderServer);
|
|
||||||
}
|
|
||||||
} catch (IllegalArgumentException iax) {
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
}
|
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
if(iterator == null)
|
if(iterator == null)
|
||||||
iterator = chunks.listIterator();
|
iterator = chunks.listIterator();
|
||||||
@ -897,12 +840,7 @@ public class NewMapChunkCache implements MapChunkCache {
|
|||||||
boolean didload = false;
|
boolean didload = false;
|
||||||
boolean isunloadpending = false;
|
boolean isunloadpending = false;
|
||||||
if (queue != null) {
|
if (queue != null) {
|
||||||
try {
|
isunloadpending = helper.isInUnloadQueue(queue, chunk.x, chunk.z);
|
||||||
isunloadpending = (Boolean)queuecontainskey.invoke(queue, chunk.x, chunk.z);
|
|
||||||
} catch (IllegalAccessException iax) {
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (isunloadpending) { /* Workaround: can't be pending if not loaded */
|
if (isunloadpending) { /* Workaround: can't be pending if not loaded */
|
||||||
wasLoaded = true;
|
wasLoaded = true;
|
||||||
@ -958,62 +896,30 @@ public class NewMapChunkCache implements MapChunkCache {
|
|||||||
}
|
}
|
||||||
/* Get tile entity data */
|
/* Get tile entity data */
|
||||||
List<Object> vals = new ArrayList<Object>();
|
List<Object> vals = new ArrayList<Object>();
|
||||||
for(Object t : ((CraftChunk)c).getHandle().tileEntities.values()) {
|
Map tileents = helper.getTileEntitiesForChunk(c);
|
||||||
TileEntity te = (TileEntity)t;
|
for(Object t : tileents.values()) {
|
||||||
int cx = te.x & 0xF;
|
int te_x = helper.getTileEntityX(t);
|
||||||
int cz = te.z & 0xF;
|
int te_y = helper.getTileEntityY(t);
|
||||||
int blkid = ss.getBlockTypeId(cx, te.y, cz);
|
int te_z = helper.getTileEntityZ(t);
|
||||||
int blkdat = ss.getBlockData(cx, te.y, cz);
|
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);
|
String[] te_fields = HDBlockModels.getTileEntityFieldsNeeded(blkid, blkdat);
|
||||||
if(te_fields != null) {
|
if(te_fields != null) {
|
||||||
NBTTagCompound tc = new NBTTagCompound();
|
Object nbtcompound = helper.readTileEntityNBT(t);
|
||||||
try {
|
|
||||||
te.b(tc);
|
|
||||||
} catch (Exception x) {
|
|
||||||
}
|
|
||||||
vals.clear();
|
vals.clear();
|
||||||
for(String id: te_fields) {
|
for(String id: te_fields) {
|
||||||
NBTBase v = tc.get(id); /* Get field */
|
Object val = helper.getFieldValue(nbtcompound, id);
|
||||||
if(v != null) {
|
if(val != null) {
|
||||||
Object val = null;
|
vals.add(id);
|
||||||
switch(v.getTypeId()) {
|
vals.add(val);
|
||||||
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) {
|
if(vals.size() > 0) {
|
||||||
Object[] vlist = vals.toArray(new Object[vals.size()]);
|
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
|
/* 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 */
|
* when chunks are unloaded but not saved - removing them seems to do the trick */
|
||||||
if(!(didgenerate && do_save)) {
|
if(!(didgenerate && do_save)) {
|
||||||
CraftChunk cc = (CraftChunk)c;
|
helper.removeEntitiesFromChunk(c);
|
||||||
cc.getHandle().removeEntities();
|
|
||||||
}
|
}
|
||||||
/* Since we only remember ones we loaded, and we're synchronous, no player has
|
/* 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
|
* moved, so it must be safe (also prevent chunk leak, which appears to happen
|
||||||
|
Loading…
Reference in New Issue
Block a user