mirror of
https://github.com/encounter/dynmap.git
synced 2026-03-30 11:08:39 -07:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3342977a92 | |||
| 07cbd84d44 | |||
| da5e2cf24a | |||
| c6d345d8f1 | |||
| 3a57261120 | |||
| a39f99cab8 | |||
| f0885abea2 | |||
| 2b17cb215b | |||
| 68f0c17f70 | |||
| a20e55beab | |||
| 413542fe61 | |||
| a250732d31 | |||
| 07f2496f2f | |||
| 2f6e52261c | |||
| a117987840 | |||
| cbb8cc061e | |||
| c03365d574 | |||
| 827f18b8e0 | |||
| 1603015631 | |||
| c2d97ba3d5 | |||
| 418b175923 |
Binary file not shown.
@@ -2,7 +2,6 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.dynmap</groupId>
|
||||
<artifactId>dynmap</artifactId>
|
||||
<version>0.80</version>
|
||||
<name>dynmap</name>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
@@ -128,7 +127,9 @@
|
||||
<dependency>
|
||||
<groupId>com.nijikokun.bukkit</groupId>
|
||||
<artifactId>Permissions</artifactId>
|
||||
<version>[2.5.4,)</version>
|
||||
<version>3.1.6</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${project.basedir}/Permissions.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
@@ -185,4 +186,5 @@
|
||||
<version>1.2.5-R5.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<version>1.2</version>
|
||||
</project>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -17,13 +17,36 @@ public class BukkitWorld extends DynmapWorld {
|
||||
private World world;
|
||||
private World.Environment env;
|
||||
private boolean skylight;
|
||||
private DynmapLocation spawnloc = new DynmapLocation();
|
||||
|
||||
public BukkitWorld(World w) {
|
||||
super(w.getName(), w.getMaxHeight(), w.getSeaLevel());
|
||||
this(w.getName(), w.getMaxHeight(), w.getSeaLevel(), w.getEnvironment());
|
||||
setWorldLoaded(w);
|
||||
new Permission("dynmap.world." + getName(), "Dynmap access for world " + getName(), PermissionDefault.OP);
|
||||
}
|
||||
public BukkitWorld(String name, int height, int sealevel, World.Environment env) {
|
||||
super(name, height, sealevel);
|
||||
world = null;
|
||||
this.env = env;
|
||||
skylight = (env == World.Environment.NORMAL);
|
||||
new Permission("dynmap.world." + getName(), "Dynmap access for world " + getName(), PermissionDefault.OP);
|
||||
}
|
||||
/**
|
||||
* Set world online
|
||||
* @param w - loaded world
|
||||
*/
|
||||
public void setWorldLoaded(World w) {
|
||||
world = w;
|
||||
env = world.getEnvironment();
|
||||
skylight = (env == World.Environment.NORMAL);
|
||||
new Permission("dynmap.world." + getName(), "Dynmap access for world " + getName(), PermissionDefault.OP);
|
||||
}
|
||||
/**
|
||||
* Set world unloaded
|
||||
*/
|
||||
@Override
|
||||
public void setWorldUnloaded() {
|
||||
getSpawnLocation(); /* Remember spawn location before unload */
|
||||
world = null;
|
||||
}
|
||||
/* Test if world is nether */
|
||||
@Override
|
||||
@@ -33,26 +56,44 @@ public class BukkitWorld extends DynmapWorld {
|
||||
/* Get world spawn location */
|
||||
@Override
|
||||
public DynmapLocation getSpawnLocation() {
|
||||
DynmapLocation dloc = new DynmapLocation();
|
||||
Location sloc = world.getSpawnLocation();
|
||||
dloc.x = sloc.getBlockX(); dloc.y = sloc.getBlockY();
|
||||
dloc.z = sloc.getBlockZ(); dloc.world = normalizeWorldName(sloc.getWorld().getName());
|
||||
return dloc;
|
||||
if(world != null) {
|
||||
Location sloc = world.getSpawnLocation();
|
||||
spawnloc.x = sloc.getBlockX();
|
||||
spawnloc.y = sloc.getBlockY();
|
||||
spawnloc.z = sloc.getBlockZ();
|
||||
spawnloc.world = normalizeWorldName(sloc.getWorld().getName());
|
||||
}
|
||||
return spawnloc;
|
||||
}
|
||||
/* Get world time */
|
||||
@Override
|
||||
public long getTime() {
|
||||
return world.getTime();
|
||||
if(world != null) {
|
||||
return world.getTime();
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* World is storming */
|
||||
@Override
|
||||
public boolean hasStorm() {
|
||||
return world.hasStorm();
|
||||
if(world != null) {
|
||||
return world.hasStorm();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/* World is thundering */
|
||||
@Override
|
||||
public boolean isThundering() {
|
||||
return world.isThundering();
|
||||
if(world != null) {
|
||||
return world.isThundering();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/* World is loaded */
|
||||
@Override
|
||||
@@ -62,22 +103,37 @@ public class BukkitWorld extends DynmapWorld {
|
||||
/* Get light level of block */
|
||||
@Override
|
||||
public int getLightLevel(int x, int y, int z) {
|
||||
return world.getBlockAt(x, y, z).getLightLevel();
|
||||
if(world != null) {
|
||||
return world.getBlockAt(x, y, z).getLightLevel();
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* Get highest Y coord of given location */
|
||||
@Override
|
||||
public int getHighestBlockYAt(int x, int z) {
|
||||
return world.getHighestBlockYAt(x, z);
|
||||
if(world != null) {
|
||||
return world.getHighestBlockYAt(x, z);
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* Test if sky light level is requestable */
|
||||
@Override
|
||||
public boolean canGetSkyLightLevel() {
|
||||
return skylight;
|
||||
return skylight && (world != null);
|
||||
}
|
||||
/* Return sky light level */
|
||||
@Override
|
||||
public int getSkyLightLevel(int x, int y, int z) {
|
||||
return world.getBlockAt(x, y, z).getLightFromSky();
|
||||
if(world != null) {
|
||||
return world.getBlockAt(x, y, z).getLightFromSky();
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get world environment ID (lower case - normal, the_end, nether)
|
||||
@@ -91,9 +147,14 @@ public class BukkitWorld extends DynmapWorld {
|
||||
*/
|
||||
@Override
|
||||
public MapChunkCache getChunkCache(List<DynmapChunk> chunks) {
|
||||
NewMapChunkCache c = new NewMapChunkCache();
|
||||
c.setChunks(this, chunks);
|
||||
return c;
|
||||
if(isLoaded()) {
|
||||
NewMapChunkCache c = new NewMapChunkCache();
|
||||
c.setChunks(this, chunks);
|
||||
return c;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public World getWorld() {
|
||||
|
||||
@@ -2,6 +2,8 @@ package org.dynmap.bukkit;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@@ -10,6 +12,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
@@ -48,13 +51,12 @@ import org.bukkit.event.player.PlayerChatEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.event.server.PluginEnableEvent;
|
||||
import org.bukkit.event.world.ChunkPopulateEvent;
|
||||
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;
|
||||
@@ -99,7 +101,46 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
public SpoutPluginBlocks spb;
|
||||
public PluginManager pm;
|
||||
private Metrics metrics;
|
||||
private BukkitEnableCoreCallback enabCoreCB = new BukkitEnableCoreCallback();
|
||||
private Method ismodloaded;
|
||||
private HashMap<String, BukkitWorld> world_by_name = new HashMap<String, BukkitWorld>();
|
||||
/* 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;
|
||||
}
|
||||
return world_by_name.get(name);
|
||||
}
|
||||
private final BukkitWorld getWorld(World w) {
|
||||
if(last_world == w) {
|
||||
return last_bworld;
|
||||
}
|
||||
BukkitWorld bw = world_by_name.get(w.getName());
|
||||
if(bw == null) {
|
||||
bw = new BukkitWorld(w);
|
||||
world_by_name.put(w.getName(), bw);
|
||||
}
|
||||
else if(bw.isLoaded() == false) {
|
||||
bw.setWorldLoaded(w);
|
||||
}
|
||||
last_world = w;
|
||||
last_bworld = bw;
|
||||
|
||||
return bw;
|
||||
}
|
||||
private final void removeWorld(World w) {
|
||||
world_by_name.remove(w.getName());
|
||||
if(w == last_world) {
|
||||
last_world = null;
|
||||
last_bworld = null;
|
||||
}
|
||||
}
|
||||
|
||||
private class BukkitEnableCoreCallback extends DynmapCore.EnableCoreCallbacks {
|
||||
@Override
|
||||
public void configurationLoaded() {
|
||||
@@ -108,8 +149,9 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
if(core.configuration.getBoolean("spout/enabled", true)) {
|
||||
has_spout = true;
|
||||
Log.info("Detected Spout");
|
||||
spb = new SpoutPluginBlocks();
|
||||
spb.processSpoutBlocks(DynmapPlugin.this, core);
|
||||
if(spb == null) {
|
||||
spb = new SpoutPluginBlocks(DynmapPlugin.this);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Log.info("Detected Spout - Support Disabled");
|
||||
@@ -135,6 +177,12 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
|
||||
public DynmapPlugin() {
|
||||
plugin = this;
|
||||
try {
|
||||
Class<?> c = Class.forName("cpw.mods.fml.common.Loader");
|
||||
ismodloaded = c.getMethod("isModLoaded", String.class);
|
||||
} catch (NoSuchMethodException nsmx) {
|
||||
} catch (ClassNotFoundException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,7 +257,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
pm.registerEvents(new Listener() {
|
||||
@EventHandler(priority=EventPriority.MONITOR)
|
||||
public void onSpawnChange(SpawnChangeEvent evt) {
|
||||
DynmapWorld w = new BukkitWorld(evt.getWorld());
|
||||
BukkitWorld w = getWorld(evt.getWorld());
|
||||
core.listenerManager.processWorldEvent(EventType.WORLD_SPAWN_CHANGE, w);
|
||||
}
|
||||
}, DynmapPlugin.this);
|
||||
@@ -268,7 +316,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
if(b == null) return; /* Work around for stupid mods.... */
|
||||
Location l = b.getLocation();
|
||||
core.listenerManager.processBlockEvent(EventType.BLOCK_BREAK, b.getType().getId(),
|
||||
BukkitWorld.normalizeWorldName(l.getWorld().getName()), l.getBlockX(), l.getBlockY(), l.getBlockZ());
|
||||
getWorld(l.getWorld()).getName(), l.getBlockX(), l.getBlockY(), l.getBlockZ());
|
||||
}
|
||||
}, DynmapPlugin.this);
|
||||
break;
|
||||
@@ -284,7 +332,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
Player p = evt.getPlayer();
|
||||
if(p != null) dp = new BukkitPlayer(p);
|
||||
core.listenerManager.processSignChangeEvent(EventType.SIGN_CHANGE, b.getType().getId(),
|
||||
BukkitWorld.normalizeWorldName(l.getWorld().getName()), l.getBlockX(), l.getBlockY(), l.getBlockZ(), lines, dp);
|
||||
getWorld(l.getWorld()).getName(), l.getBlockX(), l.getBlockY(), l.getBlockZ(), lines, dp);
|
||||
}
|
||||
}, DynmapPlugin.this);
|
||||
break;
|
||||
@@ -323,11 +371,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
}
|
||||
@Override
|
||||
public DynmapWorld getWorldByName(String wname) {
|
||||
World w = getServer().getWorld(wname); /* FInd world */
|
||||
if(w != null) {
|
||||
return new BukkitWorld(w);
|
||||
}
|
||||
return null;
|
||||
return DynmapPlugin.this.getWorldByName(wname);
|
||||
}
|
||||
@Override
|
||||
public DynmapPlayer getOfflinePlayer(String name) {
|
||||
@@ -365,6 +409,9 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
public MapChunkCache createMapChunkCache(DynmapWorld w, List<DynmapChunk> chunks,
|
||||
boolean blockdata, boolean highesty, boolean biome, boolean rawbiome) {
|
||||
MapChunkCache c = w.getChunkCache(chunks);
|
||||
if(c == null) { /* Can fail if not currently loaded */
|
||||
return null;
|
||||
}
|
||||
if(w.visibility_limits != null) {
|
||||
for(MapChunkCache.VisibilityLimit limit: w.visibility_limits) {
|
||||
c.setVisibleRange(limit);
|
||||
@@ -401,8 +448,9 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
public Boolean call() throws Exception {
|
||||
boolean exhausted;
|
||||
synchronized(loadlock) {
|
||||
if(chunks_in_cur_tick > 0)
|
||||
if(chunks_in_cur_tick > 0) {
|
||||
chunks_in_cur_tick -= cc.loadChunks(chunks_in_cur_tick);
|
||||
}
|
||||
exhausted = (chunks_in_cur_tick == 0);
|
||||
}
|
||||
return exhausted;
|
||||
@@ -411,6 +459,8 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
Boolean delay;
|
||||
try {
|
||||
delay = f.get();
|
||||
} catch (CancellationException cx) {
|
||||
return null;
|
||||
} catch (Exception ix) {
|
||||
Log.severe(ix);
|
||||
return null;
|
||||
@@ -419,6 +469,9 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
try { Thread.sleep(25); } catch (InterruptedException ix) {}
|
||||
}
|
||||
}
|
||||
/* If cancelled due to world unload return nothing */
|
||||
if(w.isLoaded() == false)
|
||||
return null;
|
||||
return c;
|
||||
}
|
||||
@Override
|
||||
@@ -429,6 +482,23 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
public int getCurrentPlayers() {
|
||||
return getServer().getOnlinePlayers().length;
|
||||
}
|
||||
@Override
|
||||
public boolean isModLoaded(String name) {
|
||||
if(ismodloaded != null) {
|
||||
try {
|
||||
Object rslt =ismodloaded.invoke(null, name);
|
||||
if(rslt instanceof Boolean) {
|
||||
if(((Boolean)rslt).booleanValue()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (IllegalArgumentException iax) {
|
||||
} catch (IllegalAccessException e) {
|
||||
} catch (InvocationTargetException e) {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Player access abstraction class
|
||||
@@ -480,7 +550,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
}
|
||||
World w = player.getWorld();
|
||||
if(w != null)
|
||||
return BukkitWorld.normalizeWorldName(w.getName());
|
||||
return DynmapPlugin.this.getWorld(w).getName();
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
@@ -562,6 +632,32 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
}
|
||||
}
|
||||
|
||||
public void loadExtraBiomes() {
|
||||
int cnt = 0;
|
||||
|
||||
/* 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 = 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++;
|
||||
}
|
||||
}
|
||||
if(cnt > 0) {
|
||||
Log.info("Added " + cnt + " custom biome mappings");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
pm = this.getServer().getPluginManager();
|
||||
@@ -569,6 +665,8 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
PluginDescriptionFile pdfFile = this.getDescription();
|
||||
version = pdfFile.getVersion();
|
||||
|
||||
/* Load extra biomes, if any */
|
||||
loadExtraBiomes();
|
||||
|
||||
/* Set up player login/quit event handler */
|
||||
registerPlayerLoginListener();
|
||||
@@ -615,8 +713,46 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
core.setDataFolder(dataDirectory);
|
||||
core.setServer(new BukkitServer());
|
||||
|
||||
/* Load configuration */
|
||||
if(!core.initConfiguration(enabCoreCB)) {
|
||||
this.setEnabled(false);
|
||||
return;
|
||||
}
|
||||
/* See if we need to wait before enabling core */
|
||||
if(!readyToEnable()) {
|
||||
Listener pl = new Listener() {
|
||||
@EventHandler(priority=EventPriority.MONITOR)
|
||||
public void onPluginEnabled(PluginEnableEvent evt) {
|
||||
if (!readyToEnable()) {
|
||||
spb.markPluginEnabled(evt.getPlugin());
|
||||
if (readyToEnable()) { /* If we;re ready now, finish enable */
|
||||
doEnable(); /* Finish enable */
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
pm.registerEvents(pl, this);
|
||||
}
|
||||
else {
|
||||
doEnable();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean readyToEnable() {
|
||||
if (spb != null) {
|
||||
return spb.isReady();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void doEnable() {
|
||||
/* Prep spout support, if needed */
|
||||
if(spb != null) {
|
||||
spb.processSpoutBlocks(this, core);
|
||||
}
|
||||
|
||||
/* Enable core */
|
||||
if(!core.enableCore(new BukkitEnableCoreCallback())) {
|
||||
if(!core.enableCore(enabCoreCB)) {
|
||||
this.setEnabled(false);
|
||||
return;
|
||||
}
|
||||
@@ -627,7 +763,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
mapManager = core.getMapManager();
|
||||
/* Initialized the currently loaded worlds */
|
||||
for (World world : getServer().getWorlds()) {
|
||||
BukkitWorld w = new BukkitWorld(world);
|
||||
BukkitWorld w = getWorld(world);
|
||||
if(core.processWorldLoad(w)) /* Have core process load first - fire event listeners if good load after */
|
||||
core.listenerManager.processWorldEvent(EventType.WORLD_LOAD, w);
|
||||
}
|
||||
@@ -748,7 +884,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
int x0 = l0.getBlockX(), y0 = l0.getBlockY(), z0 = l0.getBlockZ();
|
||||
int x1 = l1.getBlockX(), y1 = l1.getBlockY(), z1 = l1.getBlockZ();
|
||||
|
||||
return core.triggerRenderOfVolume(BukkitWorld.normalizeWorldName(l0.getWorld().getName()), Math.min(x0, x1), Math.min(y0, y1),
|
||||
return core.triggerRenderOfVolume(getWorld(l0.getWorld()).getName(), Math.min(x0, x1), Math.min(y0, y1),
|
||||
Math.min(z0, z1), Math.max(x0, x1), Math.max(y0, y1), Math.max(z0, z1));
|
||||
}
|
||||
|
||||
@@ -811,7 +947,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
if(bt == 9) bt = 8;
|
||||
if(btt.typeid == 9) btt.typeid = 8;
|
||||
if((bt != btt.typeid) || (btt.data != w.getBlockAt(loc).getData())) {
|
||||
String wn = BukkitWorld.normalizeWorldName(w.getName());
|
||||
String wn = getWorld(w).getName();
|
||||
sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
||||
mapManager.touch(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), btt.trigger);
|
||||
}
|
||||
@@ -881,7 +1017,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
if(event.isCancelled())
|
||||
return;
|
||||
Location loc = event.getBlock().getLocation();
|
||||
String wn = BukkitWorld.normalizeWorldName(loc.getWorld().getName());
|
||||
String wn = getWorld(loc.getWorld()).getName();
|
||||
sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
||||
mapManager.touch(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), "blockplace");
|
||||
}
|
||||
@@ -898,7 +1034,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
Block b = event.getBlock();
|
||||
if(b == null) return; /* Stupid mod workaround */
|
||||
Location loc = b.getLocation();
|
||||
String wn = BukkitWorld.normalizeWorldName(loc.getWorld().getName());
|
||||
String wn = getWorld(loc.getWorld()).getName();
|
||||
sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
||||
mapManager.touch(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), "blockbreak");
|
||||
}
|
||||
@@ -913,7 +1049,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
if(event.isCancelled())
|
||||
return;
|
||||
Location loc = event.getBlock().getLocation();
|
||||
String wn = BukkitWorld.normalizeWorldName(loc.getWorld().getName());
|
||||
String wn = getWorld(loc.getWorld()).getName();
|
||||
sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
||||
if(onleaves) {
|
||||
mapManager.touch(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), "leavesdecay");
|
||||
@@ -930,7 +1066,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
if(event.isCancelled())
|
||||
return;
|
||||
Location loc = event.getBlock().getLocation();
|
||||
String wn = BukkitWorld.normalizeWorldName(loc.getWorld().getName());
|
||||
String wn = getWorld(loc.getWorld()).getName();
|
||||
sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
||||
if(onburn) {
|
||||
mapManager.touch(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), "blockburn");
|
||||
@@ -999,7 +1135,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
} catch (ClassCastException ccx) {
|
||||
dir = BlockFace.NORTH;
|
||||
}
|
||||
String wn = BukkitWorld.normalizeWorldName(loc.getWorld().getName());
|
||||
String wn = getWorld(loc.getWorld()).getName();
|
||||
int x = loc.getBlockX(), y = loc.getBlockY(), z = loc.getBlockZ();
|
||||
sscache.invalidateSnapshot(wn, x, y, z);
|
||||
if(onpiston)
|
||||
@@ -1025,7 +1161,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
} catch (ClassCastException ccx) {
|
||||
dir = BlockFace.NORTH;
|
||||
}
|
||||
String wn = BukkitWorld.normalizeWorldName(loc.getWorld().getName());
|
||||
String wn = getWorld(loc.getWorld()).getName();
|
||||
int x = loc.getBlockX(), y = loc.getBlockY(), z = loc.getBlockZ();
|
||||
sscache.invalidateSnapshot(wn, x, y, z);
|
||||
if(onpiston)
|
||||
@@ -1049,7 +1185,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
if(event.isCancelled())
|
||||
return;
|
||||
Location loc = event.getBlock().getLocation();
|
||||
String wn = BukkitWorld.normalizeWorldName(loc.getWorld().getName());
|
||||
String wn = getWorld(loc.getWorld()).getName();
|
||||
sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
||||
mapManager.touch(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), "blockspread");
|
||||
}
|
||||
@@ -1064,7 +1200,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
if(event.isCancelled())
|
||||
return;
|
||||
Location loc = event.getBlock().getLocation();
|
||||
String wn = BukkitWorld.normalizeWorldName(loc.getWorld().getName());
|
||||
String wn = getWorld(loc.getWorld()).getName();
|
||||
sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
||||
mapManager.touch(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), "blockform");
|
||||
}
|
||||
@@ -1079,7 +1215,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
if(event.isCancelled())
|
||||
return;
|
||||
Location loc = event.getBlock().getLocation();
|
||||
String wn = BukkitWorld.normalizeWorldName(loc.getWorld().getName());
|
||||
String wn = getWorld(loc.getWorld()).getName();
|
||||
sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
||||
mapManager.touch(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), "blockfade");
|
||||
}
|
||||
@@ -1098,7 +1234,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
if(event.isCancelled())
|
||||
return;
|
||||
Location loc = event.getBlock().getLocation();
|
||||
String wn = BukkitWorld.normalizeWorldName(loc.getWorld().getName());
|
||||
String wn = getWorld(loc.getWorld()).getName();
|
||||
sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
||||
mapManager.touch(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), "blockgrow");
|
||||
}
|
||||
@@ -1114,7 +1250,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
@EventHandler(priority=EventPriority.MONITOR)
|
||||
public void onBlockRedstone(BlockRedstoneEvent event) {
|
||||
Location loc = event.getBlock().getLocation();
|
||||
String wn = BukkitWorld.normalizeWorldName(loc.getWorld().getName());
|
||||
String wn = getWorld(loc.getWorld()).getName();
|
||||
sscache.invalidateSnapshot(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
||||
mapManager.touch(wn, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), "blockredstone");
|
||||
}
|
||||
@@ -1128,7 +1264,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
if(onplayerjoin) {
|
||||
Location loc = event.getPlayer().getLocation();
|
||||
mapManager.touch(BukkitWorld.normalizeWorldName(loc.getWorld().getName()), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), "playerjoin");
|
||||
mapManager.touch(getWorld(loc.getWorld()).getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), "playerjoin");
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1142,7 +1278,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
@EventHandler(priority=EventPriority.MONITOR)
|
||||
public void onPlayerMove(PlayerMoveEvent event) {
|
||||
Location loc = event.getPlayer().getLocation();
|
||||
mapManager.touch(BukkitWorld.normalizeWorldName(loc.getWorld().getName()), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), "playermove");
|
||||
mapManager.touch(getWorld(loc.getWorld()).getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), "playermove");
|
||||
}
|
||||
};
|
||||
pm.registerEvents(playermove, this);
|
||||
@@ -1153,7 +1289,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
@EventHandler(priority=EventPriority.MONITOR)
|
||||
public void onEntityExplode(EntityExplodeEvent event) {
|
||||
Location loc = event.getLocation();
|
||||
String wname = BukkitWorld.normalizeWorldName(loc.getWorld().getName());
|
||||
String wname = getWorld(loc.getWorld()).getName();
|
||||
int minx, maxx, miny, maxy, minz, maxz;
|
||||
minx = maxx = loc.getBlockX();
|
||||
miny = maxy = loc.getBlockY();
|
||||
@@ -1185,22 +1321,23 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
Listener worldTrigger = new Listener() {
|
||||
@EventHandler(priority=EventPriority.MONITOR)
|
||||
public void onWorldLoad(WorldLoadEvent event) {
|
||||
core.updateConfigHashcode();
|
||||
BukkitWorld w = new BukkitWorld(event.getWorld());
|
||||
BukkitWorld w = getWorld(event.getWorld());
|
||||
if(core.processWorldLoad(w)) /* Have core process load first - fire event listeners if good load after */
|
||||
core.listenerManager.processWorldEvent(EventType.WORLD_LOAD, w);
|
||||
}
|
||||
@EventHandler(priority=EventPriority.MONITOR)
|
||||
public void onWorldUnload(WorldUnloadEvent event) {
|
||||
core.updateConfigHashcode();
|
||||
DynmapWorld w = core.getWorld(BukkitWorld.normalizeWorldName(event.getWorld().getName()));
|
||||
if(w != null)
|
||||
BukkitWorld w = getWorld(event.getWorld());
|
||||
if(w != null) {
|
||||
core.listenerManager.processWorldEvent(EventType.WORLD_UNLOAD, w);
|
||||
w.setWorldUnloaded();
|
||||
core.processWorldUnload(w);
|
||||
}
|
||||
}
|
||||
@EventHandler(priority=EventPriority.MONITOR)
|
||||
public void onStructureGrow(StructureGrowEvent event) {
|
||||
Location loc = event.getLocation();
|
||||
String wname = BukkitWorld.normalizeWorldName(loc.getWorld().getName());
|
||||
String wname = getWorld(loc.getWorld()).getName();
|
||||
int minx, maxx, miny, maxy, minz, maxz;
|
||||
minx = maxx = loc.getBlockX();
|
||||
miny = maxy = loc.getBlockY();
|
||||
@@ -1237,7 +1374,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
|
||||
/* Touch extreme corners */
|
||||
int x = c.getX() << 4;
|
||||
int z = c.getZ() << 4;
|
||||
mapManager.touchVolume(BukkitWorld.normalizeWorldName(event.getWorld().getName()), x, 0, z, x+15, 128, z+16, "chunkpopulate");
|
||||
mapManager.touchVolume(getWorld(event.getWorld()).getName(), x, 0, z, x+15, 128, z+16, "chunkpopulate");
|
||||
}
|
||||
};
|
||||
pm.registerEvents(chunkTrigger, this);
|
||||
|
||||
@@ -258,7 +258,7 @@ public class Metrics {
|
||||
// Each post thereafter will be a ping
|
||||
firstPost = false;
|
||||
} catch (IOException e) {
|
||||
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage());
|
||||
//Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}, 0, PING_INTERVAL * 1200);
|
||||
|
||||
@@ -1,27 +1,23 @@
|
||||
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;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import net.minecraft.server.ChunkProviderServer;
|
||||
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.CraftWorld;
|
||||
import org.bukkit.craftbukkit.util.LongHashset;
|
||||
import org.bukkit.ChunkSnapshot;
|
||||
import org.dynmap.DynmapChunk;
|
||||
import org.dynmap.DynmapCore;
|
||||
import org.dynmap.DynmapWorld;
|
||||
import org.dynmap.Log;
|
||||
import org.dynmap.bukkit.SnapshotCache.SnapshotRec;
|
||||
import org.dynmap.common.BiomeMap;
|
||||
import org.dynmap.hdmap.HDBlockModels;
|
||||
import org.dynmap.renderer.RenderPatchFactory;
|
||||
import org.dynmap.utils.DynIntHashMap;
|
||||
import org.dynmap.utils.MapChunkCache;
|
||||
import org.dynmap.utils.MapIterator;
|
||||
import org.dynmap.utils.BlockStep;
|
||||
@@ -32,9 +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 boolean use_spout = false;
|
||||
|
||||
private World w;
|
||||
private DynmapWorld dw;
|
||||
@@ -51,6 +45,7 @@ public class NewMapChunkCache implements MapChunkCache {
|
||||
private boolean do_save = false;
|
||||
private boolean isempty = true;
|
||||
private ChunkSnapshot[] snaparray; /* Index = (x-x_min) + ((z-z_min)*x_dim) */
|
||||
private DynIntHashMap[] snaptile;
|
||||
private byte[][] sameneighborbiomecnt;
|
||||
private BiomeMap[][] biomemap;
|
||||
private boolean[][] isSectionNotEmpty; /* Indexed by snapshot index, then by section index */
|
||||
@@ -61,11 +56,17 @@ 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 };
|
||||
|
||||
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)
|
||||
*/
|
||||
@@ -145,15 +146,31 @@ public class NewMapChunkCache implements MapChunkCache {
|
||||
sameneighborbiomecnt[i] = new byte[z_size];
|
||||
biomemap[i] = new BiomeMap[z_size];
|
||||
}
|
||||
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++) {
|
||||
Biome bb = snap.getBiome(bx, bz);
|
||||
BiomeMap bm;
|
||||
if(bb == null)
|
||||
bm = BiomeMap.NULL;
|
||||
else
|
||||
bm = biome_to_bmap[bb.ordinal()];
|
||||
|
||||
if(snap != biome_css) {
|
||||
biomebase = null;
|
||||
biome_css = snap;
|
||||
if (biome_css instanceof SpoutChunkSnapshot) {
|
||||
biome_css = ((SpoutChunkSnapshot)biome_css).chunk;
|
||||
}
|
||||
biomebase = helper.getBiomeBaseFromSnapshot(biome_css);
|
||||
}
|
||||
if(biomebase != null) {
|
||||
bm = BiomeMap.byBiomeID(helper.getBiomeBaseID(biomebase[bz << 4 | bx]));
|
||||
}
|
||||
else {
|
||||
Biome bb = snap.getBiome(bx, bz);
|
||||
if(bb == null)
|
||||
bm = BiomeMap.NULL;
|
||||
else
|
||||
bm = biome_to_bmap[bb.ordinal()];
|
||||
}
|
||||
biomemap[i][j] = bm;
|
||||
int cnt = 0;
|
||||
if(i > 0) {
|
||||
@@ -517,6 +534,53 @@ public class NewMapChunkCache implements MapChunkCache {
|
||||
return !isSectionNotEmpty[chunkindex][y >> 4];
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public RenderPatchFactory getPatchFactory() {
|
||||
return HDBlockModels.getPatchDefinitionFactory();
|
||||
}
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
@Override
|
||||
public int getBlockTypeIDAt(int xoff, int yoff, int zoff) {
|
||||
int xx = this.x + xoff;
|
||||
int yy = this.y + yoff;
|
||||
int zz = this.z + zoff;
|
||||
int idx = ((xx >> 4) - x_min) + (((zz >> 4) - z_min) * x_dim);
|
||||
try {
|
||||
return snaparray[idx].getBlockTypeId(xx & 0xF, yy, zz & 0xF);
|
||||
} catch (Exception x) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public int getBlockDataAt(int xoff, int yoff, int zoff) {
|
||||
int xx = this.x + xoff;
|
||||
int yy = this.y + yoff;
|
||||
int zz = this.z + zoff;
|
||||
int idx = ((xx >> 4) - x_min) + (((zz >> 4) - z_min) * x_dim);
|
||||
try {
|
||||
return snaparray[idx].getBlockData(xx & 0xF, yy, zz & 0xF);
|
||||
} catch (Exception x) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public Object getBlockTileEntityFieldAt(String fieldId, int xoff,
|
||||
int yoff, int zoff) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private class OurEndMapIterator extends OurMapIterator {
|
||||
@@ -666,27 +730,15 @@ 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;
|
||||
}
|
||||
init = true;
|
||||
}
|
||||
}
|
||||
public void setChunks(BukkitWorld dw, List<DynmapChunk> chunks) {
|
||||
this.dw = dw;
|
||||
this.w = dw.getWorld();
|
||||
if(this.w == null) {
|
||||
this.chunks = new ArrayList<DynmapChunk>();
|
||||
}
|
||||
nsect = dw.worldheight >> 4;
|
||||
this.chunks = chunks;
|
||||
/* Compute range */
|
||||
@@ -713,8 +765,10 @@ public class NewMapChunkCache implements MapChunkCache {
|
||||
x_dim = x_max - x_min + 1;
|
||||
}
|
||||
|
||||
snaparray = new ChunkSnapshot[x_dim * (z_max-z_min+1)];
|
||||
isSectionNotEmpty = new boolean[x_dim * (z_max-z_min+1)][];
|
||||
int snapcnt = 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) {
|
||||
@@ -729,16 +783,11 @@ public class NewMapChunkCache implements MapChunkCache {
|
||||
}
|
||||
|
||||
public int loadChunks(int max_to_load) {
|
||||
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();
|
||||
@@ -767,8 +816,11 @@ public class NewMapChunkCache implements MapChunkCache {
|
||||
}
|
||||
}
|
||||
/* Check if cached chunk snapshot found */
|
||||
ChunkSnapshot ss = DynmapPlugin.plugin.sscache.getSnapshot(dw.getName(), chunk.x, chunk.z, blockdata, biome, biomeraw, highesty);
|
||||
if(ss != null) {
|
||||
ChunkSnapshot 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(hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN)
|
||||
ss = STONE;
|
||||
@@ -777,7 +829,10 @@ public class NewMapChunkCache implements MapChunkCache {
|
||||
else
|
||||
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;
|
||||
}
|
||||
chunks_attempted++;
|
||||
@@ -785,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;
|
||||
@@ -814,6 +864,8 @@ public class NewMapChunkCache implements MapChunkCache {
|
||||
didgenerate = didload = w.loadChunk(chunk.x, chunk.z, true);
|
||||
/* If it did load, make cache of it */
|
||||
if(didload) {
|
||||
tileData = new DynIntHashMap();
|
||||
|
||||
Chunk c = w.getChunkAt(chunk.x, chunk.z); /* Get the chunk */
|
||||
/* Test if chunk isn't populated */
|
||||
boolean populated = true;
|
||||
@@ -842,22 +894,55 @@ public class NewMapChunkCache implements MapChunkCache {
|
||||
if(use_spout) {
|
||||
ss = checkSpoutData(c, ss);
|
||||
}
|
||||
/* Get tile entity data */
|
||||
List<Object> vals = new ArrayList<Object>();
|
||||
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) {
|
||||
Object nbtcompound = helper.readTileEntityNBT(t);
|
||||
|
||||
vals.clear();
|
||||
for(String id: te_fields) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
ss = w.getEmptyChunkSnapshot(chunk.x, chunk.z, biome, biomeraw);
|
||||
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;
|
||||
snaptile[(chunk.x-x_min) + (chunk.z - z_min)*x_dim] = tileData;
|
||||
|
||||
/* If wasn't loaded before, we need to do unload */
|
||||
if (!wasLoaded) {
|
||||
chunks_read++;
|
||||
/* 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
|
||||
@@ -893,6 +978,11 @@ public class NewMapChunkCache implements MapChunkCache {
|
||||
* Test if done loading
|
||||
*/
|
||||
public boolean isDoneLoading() {
|
||||
if(dw.isLoaded() == false) {
|
||||
isempty = true;
|
||||
unloadChunks();
|
||||
return true;
|
||||
}
|
||||
if(iterator != null)
|
||||
return !iterator.hasNext();
|
||||
return false;
|
||||
@@ -914,45 +1004,6 @@ public class NewMapChunkCache implements MapChunkCache {
|
||||
snaparray = null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get block ID at coordinates
|
||||
*/
|
||||
public int getBlockTypeID(int x, int y, int z) {
|
||||
ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
|
||||
return ss.getBlockTypeId(x & 0xF, y, z & 0xF);
|
||||
}
|
||||
/**
|
||||
* Get block data at coordiates
|
||||
*/
|
||||
public byte getBlockData(int x, int y, int z) {
|
||||
ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
|
||||
return (byte)ss.getBlockData(x & 0xF, y, z & 0xF);
|
||||
}
|
||||
/* Get sky light level
|
||||
*/
|
||||
public int getBlockSkyLight(int x, int y, int z) {
|
||||
ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
|
||||
return ss.getBlockSkyLight(x & 0xF, y, z & 0xF);
|
||||
}
|
||||
/* Get emitted light level
|
||||
*/
|
||||
public int getBlockEmittedLight(int x, int y, int z) {
|
||||
ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
|
||||
return ss.getBlockEmittedLight(x & 0xF, y, z & 0xF);
|
||||
}
|
||||
public BiomeMap getBiome(int x, int z) {
|
||||
ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
|
||||
Biome b = ss.getBiome(x & 0xF, z & 0xF);
|
||||
return (b != null)?biome_to_bmap[b.ordinal()]:null;
|
||||
}
|
||||
public double getRawBiomeTemperature(int x, int z) {
|
||||
ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
|
||||
return ss.getRawBiomeTemperature(x & 0xF, z & 0xF);
|
||||
}
|
||||
public double getRawBiomeRainfall(int x, int z) {
|
||||
ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
|
||||
return ss.getRawBiomeRainfall(x & 0xF, z & 0xF);
|
||||
}
|
||||
private void initSectionData(int idx) {
|
||||
isSectionNotEmpty[idx] = new boolean[nsect + 1];
|
||||
if(snaparray[idx] != EMPTY) {
|
||||
|
||||
@@ -8,15 +8,21 @@ import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.ChunkSnapshot;
|
||||
import org.dynmap.utils.DynIntHashMap;
|
||||
|
||||
public class SnapshotCache {
|
||||
public static class SnapshotRec {
|
||||
public ChunkSnapshot ss;
|
||||
public DynIntHashMap tileData;
|
||||
};
|
||||
|
||||
private CacheHashMap snapcache;
|
||||
private ReferenceQueue<ChunkSnapshot> refqueue;
|
||||
private ReferenceQueue<SnapshotRec> refqueue;
|
||||
private long cache_attempts;
|
||||
private long cache_success;
|
||||
|
||||
private static class CacheRec {
|
||||
WeakReference<ChunkSnapshot> ref;
|
||||
WeakReference<SnapshotRec> ref;
|
||||
boolean hasbiome;
|
||||
boolean hasrawbiome;
|
||||
boolean hasblockdata;
|
||||
@@ -26,12 +32,12 @@ public class SnapshotCache {
|
||||
@SuppressWarnings("serial")
|
||||
public class CacheHashMap extends LinkedHashMap<String, CacheRec> {
|
||||
private int limit;
|
||||
private IdentityHashMap<WeakReference<ChunkSnapshot>, String> reverselookup;
|
||||
private IdentityHashMap<WeakReference<SnapshotRec>, String> reverselookup;
|
||||
|
||||
public CacheHashMap(int lim) {
|
||||
super(16, (float)0.75, true);
|
||||
limit = lim;
|
||||
reverselookup = new IdentityHashMap<WeakReference<ChunkSnapshot>, String>();
|
||||
reverselookup = new IdentityHashMap<WeakReference<SnapshotRec>, String>();
|
||||
}
|
||||
protected boolean removeEldestEntry(Map.Entry<String, CacheRec> last) {
|
||||
boolean remove = (size() >= limit);
|
||||
@@ -47,7 +53,7 @@ public class SnapshotCache {
|
||||
*/
|
||||
public SnapshotCache(int max_size) {
|
||||
snapcache = new CacheHashMap(max_size);
|
||||
refqueue = new ReferenceQueue<ChunkSnapshot>();
|
||||
refqueue = new ReferenceQueue<SnapshotRec>();
|
||||
}
|
||||
private String getKey(String w, int cx, int cz) {
|
||||
return w + ":" + cx + ":" + cz;
|
||||
@@ -83,11 +89,11 @@ public class SnapshotCache {
|
||||
/**
|
||||
* 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) {
|
||||
String key = getKey(w, chunkx, chunkz);
|
||||
processRefQueue();
|
||||
ChunkSnapshot ss = null;
|
||||
SnapshotRec ss = null;
|
||||
CacheRec rec = snapcache.get(key);
|
||||
if(rec != null) {
|
||||
ss = rec.ref.get();
|
||||
@@ -112,7 +118,7 @@ public class SnapshotCache {
|
||||
/**
|
||||
* 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) {
|
||||
String key = getKey(w, chunkx, chunkz);
|
||||
processRefQueue();
|
||||
@@ -121,7 +127,7 @@ public class SnapshotCache {
|
||||
rec.hasbiome = biome;
|
||||
rec.hasrawbiome = biomeraw;
|
||||
rec.hashighesty = highesty;
|
||||
rec.ref = new WeakReference<ChunkSnapshot>(ss, refqueue);
|
||||
rec.ref = new WeakReference<SnapshotRec>(ss, refqueue);
|
||||
CacheRec prevrec = snapcache.put(key, rec);
|
||||
if(prevrec != null) {
|
||||
snapcache.reverselookup.remove(prevrec.ref);
|
||||
@@ -132,7 +138,7 @@ public class SnapshotCache {
|
||||
* Process reference queue
|
||||
*/
|
||||
private void processRefQueue() {
|
||||
Reference<? extends ChunkSnapshot> ref;
|
||||
Reference<? extends SnapshotRec> ref;
|
||||
while((ref = refqueue.poll()) != null) {
|
||||
String k = snapcache.reverselookup.remove(ref);
|
||||
if(k != null) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import java.lang.reflect.Field;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
@@ -33,7 +34,29 @@ import org.getspout.spoutapi.material.MaterialData;
|
||||
public class SpoutPluginBlocks {
|
||||
private Field textXPosField; /* float[][] textXPos */
|
||||
private Field textYPosField; /* float[][] textYPos */
|
||||
|
||||
private HashSet<String> plugins_pending = new HashSet<String>();
|
||||
|
||||
public SpoutPluginBlocks(Plugin plugin) {
|
||||
/* First, see if any spout plugins that need to be enabled */
|
||||
for(Plugin p : plugin.getServer().getPluginManager().getPlugins()) {
|
||||
List<String> dep = p.getDescription().getDepend();
|
||||
if((dep != null) && (dep.contains("Spout"))) {
|
||||
Log.info("Found Spout plugin: " + p.getName());
|
||||
if(p.isEnabled() == false) {
|
||||
plugins_pending.add(p.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isReady() {
|
||||
return plugins_pending.isEmpty();
|
||||
}
|
||||
|
||||
public void markPluginEnabled(Plugin p) {
|
||||
plugins_pending.remove(p.getName());
|
||||
}
|
||||
|
||||
private boolean initSpoutAccess() {
|
||||
boolean success = false;
|
||||
try {
|
||||
@@ -73,17 +96,6 @@ public class SpoutPluginBlocks {
|
||||
|
||||
/* Process spout blocks - return true if something changed */
|
||||
public boolean processSpoutBlocks(DynmapPlugin plugin, DynmapCore core) {
|
||||
/* First, see if any spout plugins that need to be enabled */
|
||||
for(Plugin p : plugin.getServer().getPluginManager().getPlugins()) {
|
||||
List<String> dep = p.getDescription().getDepend();
|
||||
if((dep != null) && (dep.contains("Spout"))) {
|
||||
Log.info("Found Spout plugin: " + p.getName());
|
||||
if(p.isEnabled() == false) {
|
||||
plugin.getPluginLoader().enablePlugin(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File datadir = core.getDataFolder();
|
||||
if(textYPosField == null) {
|
||||
if(initSpoutAccess() == false)
|
||||
|
||||
@@ -201,8 +201,10 @@ image-format: png
|
||||
|
||||
# use-generated-textures: if true, use generated textures (same as client); false is static water/lava textures
|
||||
# correct-water-lighting: if true, use corrected water lighting (same as client); false is legacy water (darker)
|
||||
# transparent-leaves: if true, leaves are transparent (lighting-wise): false is needed for some Spout versions that break lighting on leaf blocks
|
||||
use-generated-textures: true
|
||||
correct-water-lighting: true
|
||||
transparent-leaves: true
|
||||
|
||||
# Control loading of player faces (if set to false, skins are never fetched)
|
||||
#fetchskins: false
|
||||
@@ -218,43 +220,6 @@ skin-url: "http://s3.amazonaws.com/MinecraftSkins/%player%.png"
|
||||
# 'newnorth' is used to rotate maps and rose (requires fullrender of any HDMap map - same as 'newrose' for FlatMap or KzedMap)
|
||||
compass-mode: newnorth
|
||||
|
||||
### Mod block support ###
|
||||
# Enable Industrial Craft 2 block rendering support (core, Advanced Machines, Charging Bench, Power Converters, Compact Solars, Nuclear Control)
|
||||
#ic2-support: true
|
||||
#ic2-advancesmachines-support: true
|
||||
#ic2-chargingbench-support: true
|
||||
#ic2-powerconverters-support: true
|
||||
#ic2-compactsolars-support: true
|
||||
#ic2-nuclearcontrol-support: true
|
||||
# Enable BuildCraft block rendering support
|
||||
#buildcraft-support: true
|
||||
# Enable RedPower2 block rendering support
|
||||
#redpower2-support: true
|
||||
# Enable NetherOres block rendering support
|
||||
#netherores-support: true
|
||||
# Enable RailCraft block rendering support
|
||||
#railcraft-support: true
|
||||
# Enable Kaevator's Superslopes block rendering support
|
||||
#superslopes-support: true
|
||||
# Enabled ComputerCraft block rendering support
|
||||
#computercraft-support: true
|
||||
# Enabled LC Trees++ block rendering support
|
||||
#lctrees-support: true
|
||||
# Enable Forestry block rending support
|
||||
#forestry-support: true
|
||||
# Enable IronCheck block rendering support
|
||||
#ironchest-support: true
|
||||
# Enable TubeCraft block rendering support
|
||||
#tubecraft-support: true
|
||||
# Enable Ender Storage block rendering support
|
||||
#enderstorage-support: true
|
||||
# Enable ExtraBiomesXL block rendering support
|
||||
#extrabiomesxl-support: true
|
||||
# Enable ExtraBiomesXL Bunyan block rendering support
|
||||
#extrabiomesxl-bunyan-support: true
|
||||
# Equivalent Exchange 2 block rendering support
|
||||
#ee2-support: true
|
||||
|
||||
render-triggers:
|
||||
#- playermove
|
||||
#- playerjoin
|
||||
@@ -359,6 +324,9 @@ defaultmap: flat
|
||||
# If true, make persistent record of IP addresses used by player logins, to support web IP to player matching
|
||||
persist-ids-by-ip: true
|
||||
|
||||
# If true, map text to cyrillic
|
||||
cyrillic-support: false
|
||||
|
||||
# Messages to customize
|
||||
msg:
|
||||
maptypes: "Map Types"
|
||||
|
||||
Reference in New Issue
Block a user