Compare commits

...

62 Commits

Author SHA1 Message Date
Mike Primm d4aaa1d1fd Revert chunk load change - but still make sure they don't unload under us 2013-05-10 17:36:27 -05:00
Mike Primm fe83a7d1cc Revert "Additional check on loaded chunks : avoid getChunkAt rare exception"
This reverts commit 3efe3c3d3d.
2013-05-10 17:00:52 -05:00
Mike Primm d4e24e9d26 Add GroupManager specific permissions support 2013-05-10 01:31:30 -05:00
Mike Primm 734937884a Repackage to single JAR, no ZIP - make other files self-extracting 2013-05-09 00:55:07 -05:00
Mike Primm 3efe3c3d3d Additional check on loaded chunks : avoid getChunkAt rare exception 2013-05-08 19:35:45 -05:00
Mike Primm 46ab344197 Switch to smooth lighting by default 2013-05-02 23:12:25 -05:00
Mike Primm 9270ce853d Update author contact info 2013-05-01 23:23:49 -05:00
Mike Primm 04a2019e9d Add comments for boost-enabled templates 2013-05-01 00:26:28 -05:00
Mike Primm 8daf95891d Add comment for disabling join/quit message 2013-04-29 15:07:54 -05:00
Mike Primm 5396d0b823 Add full support for CTM material connection method 2013-04-28 10:12:01 -05:00
Mike Primm a2ab8c4f2f Tune performance on map iterator 2013-04-26 21:44:29 -05:00
Mike Primm e7efbe193a Add Custom Colors support for texture packs 2013-04-22 23:03:07 -05:00
Mike Primm 99ea38d02a Avoid shutdown exception due to bukkit 'improvements' 2013-04-21 21:05:12 -05:00
Mike Primm 7c6e660cf0 Add supporting code to help with CTM support (block names, biome names) 2013-04-18 01:20:59 -05:00
Mike Primm bcd0acec33 Bump to 1.7 2013-04-07 21:34:37 -05:00
Mike Primm 7e07bff71f Remove MCPC-Plus support from Bukkit version - add notice to use Forge 2013-03-29 21:46:06 -05:00
Mike Primm 2d95548d25 Add default setting for initial zoomout validate option 2013-03-26 23:50:54 -05:00
Mike Primm 3ac67ce2c5 Update for new API listener 2013-03-20 23:59:50 -05:00
Mike Primm 0d25fd2edc Make sure chunk unload queue is processed quickly enough on MCPC 2013-03-18 20:30:13 -05:00
Mike Primm bee16ef331 Switch MCPC+ to using unloadChunkRequest - unloadChunk() seems to not clean up properly 2013-03-17 23:43:11 -05:00
Mike Primm bf16d18371 Bump to 1.6 2013-03-02 16:00:58 -06:00
Mike Primm e57634ebb3 Add BukkitForge handler - doesn't work right due to BukkitForge API bugs 2013-03-01 23:51:45 -06:00
Mike Primm 55a5aacfce Drop autogenerate option 2013-02-24 20:24:05 -06:00
mikeprimm e6fe29f0c5 Merge pull request #1148 from dejavecu/master
Added support of round visibility limits
2013-02-24 16:15:16 -08:00
Mike Primm 34712e27f0 Put in some protextion logic for apparently broken SpoutPlugin 2013-02-24 18:04:20 -06:00
dejavecu 6a5eebcc00 Added support of round visibility limits 2013-02-16 03:59:07 +04:00
Mike Primm c8b1f71949 Add settings for image update command exits 2013-02-03 17:11:35 -06:00
Mike Primm dc11ef3507 Bump to 1.5 2013-01-29 13:52:25 -06:00
Mike Primm d0bbb78e98 Add upgrade version check 2013-01-29 11:49:22 -06:00
Mike Primm 9144bff25b Add support for MCPC-Plus 2013-01-21 23:54:13 -06:00
Mike Primm 18325c2b33 Switch version check to core version 2013-01-15 11:33:51 -06:00
Mike Primm f1a686eaf8 Hack to work around broken jenkins 2013-01-15 08:45:49 -06:00
Mike Primm b3c32456ca Revert "Test to try to fix jenkins f-up"
This reverts commit 3483b19cef.
2013-01-15 08:23:31 -06:00
Mike Primm be16ac089f Revert "Revert - no help"
This reverts commit 9ad5a7e4f7.
2013-01-15 08:23:11 -06:00
Mike Primm 44a8bfa38d Revert "Try to workaround Jenkins/Maven packaging issue"
This reverts commit 443d64f7da.
2013-01-15 08:22:55 -06:00
Mike Primm 443d64f7da Try to workaround Jenkins/Maven packaging issue 2013-01-15 08:17:31 -06:00
Mike Primm 9ad5a7e4f7 Revert - no help 2013-01-15 03:31:33 -06:00
Mike Primm 3483b19cef Test to try to fix jenkins f-up 2013-01-15 03:26:03 -06:00
Mike Primm 44c5d51c4e Fix v1.2.5 support, broken by API change in metrics 2013-01-15 00:30:08 -06:00
Mike Primm 56d1bcf3eb Show details on execution exceptions - better info on cause 2013-01-11 15:59:55 -06:00
Mike Primm f43027f02f Add tileupdatedelay setting, compute more accurate bounding box for new chunks 2013-01-08 00:10:53 -06:00
Mike Primm bd12420edd Add option to hide players on map that have invisibility potion effects 2013-01-03 21:58:58 -06:00
Mike Primm 3c01aff411 Drop obsolete file 2013-01-02 21:25:17 -06:00
Mike Primm 4d664de250 Bump to 1.4 2012-12-31 15:58:32 -06:00
Mike Primm 278fa36f94 Add call needed for sign block checks 2012-12-31 12:29:28 -06:00
Mike Primm 1a2f63bcfb Switch weather display to be on by default 2012-12-30 11:23:21 -06:00
Mike Primm 344d9bf1c9 Add support for configuing which proxy addresses to trust X-Forwarded-For from 2012-12-30 11:03:28 -06:00
Mike Primm 70b27b8034 Remove debug message 2012-12-30 10:14:05 -06:00
Mike Primm abe7fc8405 Update metrics agent 2012-12-30 09:17:35 -06:00
Mike Primm 4fa62993f4 Scrub system dependencies - shifted to repository 2012-12-24 15:10:24 -06:00
Mike Primm 08a920694b Switch to new repo 2012-12-24 14:52:00 -06:00
Mike Primm 4bdb331eb0 Switch mod use to features graph - doesn't look like we get a 3rd one.. 2012-12-17 21:55:23 -06:00
Mike Primm cb7c9061e8 Update stats to collect mod usage data 2012-12-17 21:08:39 -06:00
Mike Primm 29cb155534 Revert "Fix to bukkit API 1.2.5 - avoid accidental breaks of backward compat"
This reverts commit ada85ed960.
2012-12-16 17:12:09 -06:00
Mike Primm ada85ed960 Fix to bukkit API 1.2.5 - avoid accidental breaks of backward compat 2012-12-16 15:02:19 -06:00
Mike Primm bfb12aa0f3 Bump to 1.3 2012-12-10 22:52:02 -06:00
Mike Primm 3342977a92 Add cyrillic setting back in to configuration.txt 2012-12-10 00:21:58 -06:00
Mike Primm 07cbd84d44 Combine support for pre 1.4.5 versions and new 1.4.x packaging crud 2012-12-09 22:28:21 -06:00
Mike Primm da5e2cf24a Add transparent-leaves setting : workaround for borked lighting in some SpoutPlugin versions 2012-12-09 13:04:44 -06:00
Mike Primm c6d345d8f1 Add tile entity data collection 2012-11-22 00:50:55 -06:00
Mike Primm 3a57261120 First pass of custom renderer support 2012-11-19 15:56:55 -06:00
Mike Primm a39f99cab8 Back to 1.2 2012-11-16 18:46:34 -06:00
18 changed files with 1242 additions and 448 deletions
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
-6
View File
@@ -1,6 +0,0 @@
dynmap.render # Render current chunk
dynmap.fullrender # Issue a full render
dynmap.hide.self # Hide self from map
dynmap.hide.others # Hide others from map
dynmap.show.self # Reveal self on map
dynmap.show.others # Reveal others on map
+16 -66
View File
@@ -5,7 +5,7 @@
<name>dynmap</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<BUILD_NUMBER>dev</BUILD_NUMBER>
<BUILD_NUMBER>Dev</BUILD_NUMBER>
</properties>
<url>http://github.com/webbukkit/dynmap/</url>
<issueManagement>
@@ -41,31 +41,6 @@
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>unpack</id>
<phase>package</phase>
<goals><goal>unpack</goal></goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.dynmap</groupId>
<artifactId>DynmapCore</artifactId>
<version>${project.version}</version>
<classifier>bin</classifier>
<type>zip</type>
<outputDirectory>${project.build.directory}/core</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -88,29 +63,6 @@
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>src/main/assembly/package.xml</descriptor>
</descriptors>
<!-- Hack for bug in maven-assembly: http://jira.codehaus.org/browse/MASSEMBLY-449 -->
<archiverConfig>
<fileMode>420</fileMode> <!-- 420(dec) = 644(oct) -->
<directoryMode>493</directoryMode> <!-- 493(dec) = 755(oct) -->
<defaultDirectoryMode>493</defaultDirectoryMode>
</archiverConfig>
</configuration>
<executions>
<execution>
<id>build</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
@@ -119,8 +71,16 @@
</releases>
<snapshots>
</snapshots>
<id>spout-repo</id>
<url>http://repo.spout.org</url>
<id>bukkit-repo</id>
<url>http://repo.bukkit.org/content/repositories/releases/</url>
</repository>
<repository>
<releases>
</releases>
<snapshots>
</snapshots>
<id>dynmap-repo</id>
<url>http://repo.mikeprimm.com/</url>
</repository>
</repositories>
<dependencies>
@@ -128,15 +88,11 @@
<groupId>com.nijikokun.bukkit</groupId>
<artifactId>Permissions</artifactId>
<version>3.1.6</version>
<scope>system</scope>
<systemPath>${project.basedir}/Permissions.jar</systemPath>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>[1.2.5-R4.0,1.7)</version>
<type>jar</type>
<scope>compile</scope>
<version>1.3.2-R3.0</version>
</dependency>
<dependency>
<groupId>org.dynmap</groupId>
@@ -163,28 +119,22 @@
<groupId>ru.tehkode</groupId>
<artifactId>PermissionsEx</artifactId>
<version>1.19.1</version>
<scope>system</scope>
<systemPath>${project.basedir}/PermissionsEx.jar</systemPath>
</dependency>
<dependency>
<groupId>de.bananaco</groupId>
<artifactId>bPermissions</artifactId>
<version>2.9.1</version>
<scope>system</scope>
<systemPath>${project.basedir}/bpermissions.jar</systemPath>
</dependency>
<dependency>
<groupId>com.platymuus.bukkit.permissions</groupId>
<artifactId>PermissionsBukkit</artifactId>
<version>1.6</version>
<scope>system</scope>
<systemPath>${project.basedir}/PermissionsBukkit.jar</systemPath>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<version>1.2.5-R5.1-SNAPSHOT</version>
<groupId>org.anjocaido</groupId>
<artifactId>EssentialsGroupManager</artifactId>
<version>2.10.1</version>
</dependency>
</dependencies>
<version>1.1</version>
<version>1.7</version>
</project>
+1 -9
View File
@@ -7,15 +7,7 @@
<fileSets>
<fileSet>
<directory>${project.build.directory}/core</directory>
<outputDirectory>/dynmap</outputDirectory>
<excludes>
<exclude>web/version.js</exclude></excludes></fileSet>
<fileSet>
<directory>${project.build.directory}/core/web</directory>
<outputDirectory>/dynmap/web</outputDirectory>
<includes>
<include>version.js</include></includes>
<filtered>true</filtered></fileSet>
<outputDirectory>/dynmap</outputDirectory></fileSet>
<fileSet>
<directory>${project.basedir}</directory>
<outputDirectory>/dynmap</outputDirectory>
@@ -0,0 +1,131 @@
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 abstract class BukkitVersionHelper {
private static BukkitVersionHelper helper = null;
public static final BukkitVersionHelper getHelper() {
if(helper == null) {
if(Bukkit.getServer().getVersion().contains("MCPC")) {
Log.severe("*********************************************************************************");
Log.severe("* MCPC-Plus is no longer supported via the Bukkit version of Dynmap. *");
Log.severe("* Install the appropriate Forge version of Dynmap. *");
Log.severe("* Add the DynmapCBBridge plugin to enable support for Dynmap-compatible plugins *");
Log.severe("*********************************************************************************");
}
else if(Bukkit.getServer().getVersion().contains("BukkitForge")) {
Log.severe("*********************************************************************************");
Log.severe("* BukkitForge is not supported via the Bukkit version of Dynmap. *");
Log.severe("* Install the appropriate Forge version of Dynmap. *");
Log.severe("* Add the DynmapCBBridge plugin to enable support for Dynmap-compatible plugins *");
Log.severe("*********************************************************************************");
}
else {
helper = new BukkitVersionHelperCB();
}
}
return helper;
}
protected BukkitVersionHelper() {
}
/**
* Get list of defined biomebase objects
*/
public abstract Object[] getBiomeBaseList();
/**
* Get temperature from biomebase
*/
public abstract float getBiomeBaseTemperature(Object bb);
/**
* Get humidity from biomebase
*/
public abstract float getBiomeBaseHumidity(Object bb);
/**
* Get ID string from biomebase
*/
public abstract String getBiomeBaseIDString(Object bb);
/**
* Get ID from biomebase
*/
public abstract int getBiomeBaseID(Object bb);
/**
* Get net.minecraft.server.world for given world
*/
public abstract Object getNMSWorld(World w);
/**
* Get unload queue for given NMS world
*/
public abstract Object getUnloadQueue(Object nmsworld);
/**
* For testing unload queue for presence of givne chunk
*/
public abstract boolean isInUnloadQueue(Object unloadqueue, int x, int z);
/**
* Read raw biome ID from snapshot
*/
public abstract Object[] getBiomeBaseFromSnapshot(ChunkSnapshot css);
/**
* Test if normal chunk snapshot
*/
public abstract boolean isCraftChunkSnapshot(ChunkSnapshot css);
/**
* Remove entities from given chunk
*/
public abstract void removeEntitiesFromChunk(Chunk c);
/**
* Get tile entities map from chunk
*/
public abstract Map getTileEntitiesForChunk(Chunk c);
/**
* Get X coordinate of tile entity
*/
public abstract int getTileEntityX(Object te);
/**
* Get Y coordinate of tile entity
*/
public abstract int getTileEntityY(Object te);
/**
* Get Z coordinate of tile entity
*/
public abstract int getTileEntityZ(Object te);
/**
* Read tile entity NBT
*/
public abstract Object readTileEntityNBT(Object te);
/**
* Get field value from NBT compound
*/
public abstract Object getFieldValue(Object nbt, String field);
/**
* Unload chunk no save needed
*/
public abstract void unloadChunkNoSave(World w, Chunk c, int cx, int cz);
/**
* Get block short name list
*/
public abstract String[] getBlockShortNames();
/**
* Get biome name list
*/
public abstract String[] getBiomeNames();
/**
* Get block material index list
*/
public abstract int[] getBlockMaterialMap();
}
@@ -0,0 +1,180 @@
package org.dynmap.bukkit;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Map;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Server;
import org.bukkit.World;
import org.dynmap.Log;
import org.dynmap.common.BiomeMap;
/**
* Helper for isolation of bukkit version specific issues
*/
public class BukkitVersionHelperCB extends BukkitVersionHelperGeneric {
private Class<?> nmsblock;
private Class<?> nmsblockarray;
private Class<?> nmsmaterial;
private Field blockbyid;
private Field blockname;
private Field material;
BukkitVersionHelperCB() {
}
@Override
protected String getNMSPackage() {
Server srv = Bukkit.getServer();
/* Get getHandle() method */
try {
Method m = srv.getClass().getMethod("getHandle");
Object scm = m.invoke(srv); /* And use it to get SCM (nms object) */
return scm.getClass().getPackage().getName();
} catch (Exception x) {
Log.severe("Error finding net.minecraft.server packages");
return null;
}
}
@Override
protected void loadNMS() {
// Get block fields
nmsblock = getNMSClass("net.minecraft.server.Block");
nmsblockarray = getNMSClass("[Lnet.minecraft.server.Block;");
nmsmaterial = getNMSClass("net.minecraft.server.Material");
blockbyid = getField(nmsblock, new String[] { "byId" }, nmsblockarray);
blockname = getPrivateField(nmsblock, new String[] { "name" }, String.class);
material = getField(nmsblock, new String[] { "material" }, nmsmaterial);
/* 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);
/* n.m.s.World */
nmsworld = getNMSClass("net.minecraft.server.WorldServer");
chunkprovserver = getNMSClass("net.minecraft.server.ChunkProviderServer");
nmsw_chunkproviderserver = getField(nmsworld, new String[] { "chunkProviderServer" }, chunkprovserver);
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 });
}
cps_unloadqueue = getFieldNoFail(chunkprovserver, new String[] { "unloadQueue" }, longhashset);
if(cps_unloadqueue == null) {
Log.info("Unload queue not found - default to unload all chunks");
}
/** 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);
}
@Override
public void unloadChunkNoSave(World w, Chunk c, int cx, int cz) {
this.removeEntitiesFromChunk(c);
w.unloadChunk(cx, cz, false, false);
}
/**
* Get block short name list
*/
@Override
public String[] getBlockShortNames() {
try {
Object[] byid = (Object[])blockbyid.get(nmsblock);
String[] names = new String[byid.length];
for (int i = 0; i < names.length; i++) {
if (byid[i] != null) {
names[i] = (String)blockname.get(byid[i]);
}
}
return names;
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
}
return new String[0];
}
/**
* Get biome name list
*/
@Override
public String[] getBiomeNames() {
String[] names;
/* Find array of biomes in biomebase */
Object[] biomelist = getBiomeBaseList();
names = new String[biomelist.length];
/* Loop through list, starting afer well known biomes */
for(int i = 0; i < biomelist.length; i++) {
Object bb = biomelist[i];
if(bb != null) {
names[i] = getBiomeBaseIDString(bb);
}
}
return names;
}
/**
* Get block material index list
*/
public int[] getBlockMaterialMap() {
try {
Object[] byid = (Object[])blockbyid.get(nmsblock);
int[] map = new int[byid.length];
ArrayList<Object> mats = new ArrayList<Object>();
for (int i = 0; i < map.length; i++) {
if (byid[i] != null) {
Object mat = (Object)material.get(byid[i]);
if (mat != null) {
map[i] = mats.indexOf(mat);
if (map[i] < 0) {
map[i] = mats.size();
mats.add(mat);
}
}
else {
map[i] = -1;
}
}
}
return map;
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
}
return new int[0];
}
}
@@ -0,0 +1,372 @@
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 abstract class BukkitVersionHelperGeneric extends BukkitVersionHelper {
private String obc_package; // Package used for org.bukkit.craftbukkit
protected String nms_package; // Package used for net.minecraft.server
private boolean failed;
private static final Object[] nullargs = new Object[0];
private static final Map nullmap = Collections.emptyMap();
/** CraftChunkSnapshot */
private Class<?> craftchunksnapshot;
private Field ccss_biome;
/** CraftChunk */
private Class<?> craftchunk;
private Method cc_gethandle;
/** CraftWorld */
private Class<?> craftworld;
private Method cw_gethandle;
/** BiomeBase related helpers */
protected Class<?> biomebase;
protected Class<?> biomebasearray;
protected Field biomebaselist;
protected Field biomebasetemp;
protected Field biomebasehumi;
protected Field biomebaseidstring;
protected Field biomebaseid;
/** n.m.s.World */
protected Class<?> nmsworld;
protected Class<?> chunkprovserver;
protected Class<?> longhashset;
protected Field nmsw_chunkproviderserver;
protected Field cps_unloadqueue;
protected Method lhs_containskey;
/** n.m.s.Chunk */
protected Class<?> nmschunk;
protected Method nmsc_removeentities;
protected Field nmsc_tileentities;
/** nbt classes */
protected Class<?> nbttagcompound;
protected Class<?> nbttagbyte;
protected Class<?> nbttagshort;
protected Class<?> nbttagint;
protected Class<?> nbttaglong;
protected Class<?> nbttagfloat;
protected Class<?> nbttagdouble;
protected Class<?> nbttagbytearray;
protected Class<?> nbttagstring;
protected Class<?> nbttagintarray;
protected Method compound_get;
protected Field nbttagbyte_val;
protected Field nbttagshort_val;
protected Field nbttagint_val;
protected Field nbttaglong_val;
protected Field nbttagfloat_val;
protected Field nbttagdouble_val;
protected Field nbttagbytearray_val;
protected Field nbttagstring_val;
protected Field nbttagintarray_val;
/** Tile entity */
protected Class<?> nms_tileentity;
protected Method nmst_readnbt;
protected Field nmst_x;
protected Field nmst_y;
protected Field nmst_z;
BukkitVersionHelperGeneric() {
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 NMS package */
nms_package = getNMSPackage();
if(nms_package == null) {
failed = true;
}
/* Craftworld fields */
craftworld = getOBCClass("org.bukkit.craftbukkit.CraftWorld");
cw_gethandle = getMethod(craftworld, new String[] { "getHandle" }, new Class[0]);
/* 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]);
/* Get NMS classes and fields */
if(!failed)
loadNMS();
if(failed)
throw new IllegalArgumentException("Error initializing dynmap - bukkit version incompatible!");
}
protected abstract void loadNMS();
protected abstract String getNMSPackage();
protected Class<?> getOBCClass(String classname) {
return getClassByName(classname, "org.bukkit.craftbukkit", obc_package, false);
}
protected Class<?> getOBCClassNoFail(String classname) {
return getClassByName(classname, "org.bukkit.craftbukkit", obc_package, true);
}
protected Class<?> getNMSClass(String classname) {
return getClassByName(classname, "net.minecraft.server", nms_package, false);
}
protected 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
*/
protected Field getField(Class<?> cls, String[] ids, Class<?> type) {
return getField(cls, ids, type, false);
}
protected 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
*/
protected 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;
}
protected 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
*/
protected 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.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
@@ -14,12 +13,12 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import net.minecraft.server.BiomeBase;
import org.bukkit.ChatColor;
import org.bukkit.Chunk;
import org.bukkit.ChunkSnapshot;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
@@ -60,16 +59,16 @@ 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;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.potion.PotionEffectType;
import org.dynmap.DynmapAPI;
import org.dynmap.DynmapChunk;
import org.dynmap.DynmapCommonAPIListener;
import org.dynmap.DynmapCore;
import org.dynmap.DynmapLocation;
import org.dynmap.DynmapWebChatEvent;
@@ -83,6 +82,7 @@ import org.dynmap.bukkit.permissions.NijikokunPermissions;
import org.dynmap.bukkit.permissions.OpPermissions;
import org.dynmap.bukkit.permissions.PEXPermissions;
import org.dynmap.bukkit.permissions.PermBukkitPermissions;
import org.dynmap.bukkit.permissions.GroupManagerPermissions;
import org.dynmap.bukkit.permissions.PermissionProvider;
import org.dynmap.bukkit.permissions.bPermPermissions;
import org.dynmap.common.BiomeMap;
@@ -93,6 +93,7 @@ import org.dynmap.common.DynmapListenerManager.EventType;
import org.dynmap.hdmap.HDMap;
import org.dynmap.markers.MarkerAPI;
import org.dynmap.utils.MapChunkCache;
import org.dynmap.utils.VisibilityLimit;
public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
private DynmapCore core;
@@ -109,10 +110,13 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
private BukkitEnableCoreCallback enabCoreCB = new BukkitEnableCoreCallback();
private Method ismodloaded;
private HashMap<String, BukkitWorld> world_by_name = new HashMap<String, BukkitWorld>();
private HashSet<String> modsused = new HashSet<String>();
/* Lookup cache */
private World last_world;
private BukkitWorld last_bworld;
private BukkitVersionHelper helper;
private final BukkitWorld getWorldByName(String name) {
if((last_world != null) && (last_world.getName().equals(name))) {
return last_bworld;
@@ -155,6 +159,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
if(spb == null) {
spb = new SpoutPluginBlocks(DynmapPlugin.this);
}
modsused.add("SpoutPlugin");
}
else {
Log.info("Detected Spout - Support Disabled");
@@ -197,6 +202,15 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
private int chunks_in_cur_tick = 0;
private long cur_tick;
@Override
public int getBlockIDAt(String wname, int x, int y, int z) {
World w = getServer().getWorld(wname);
if((w != null) && w.isChunkLoaded(x >> 4, z >> 4)) {
return w.getBlockTypeIdAt(x, y, z);
}
return -1;
}
@Override
public void scheduleServerTask(Runnable run, long delay) {
getServer().getScheduler().scheduleSyncDelayedTask(DynmapPlugin.this, run, delay);
@@ -229,7 +243,10 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
}
@Override
public <T> Future<T> callSyncMethod(Callable<T> task) {
return getServer().getScheduler().callSyncMethod(DynmapPlugin.this, task);
if(DynmapPlugin.this.isEnabled())
return getServer().getScheduler().callSyncMethod(DynmapPlugin.this, task);
else
return null;
}
@Override
public String getServerName() {
@@ -403,7 +420,8 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
OfflinePlayer p = getServer().getOfflinePlayer(player);
if(p.isBanned())
return false;
return permissions.hasOfflinePermission(player, perm);
boolean rslt = permissions.hasOfflinePermission(player, perm);
return rslt;
}
/**
* Render processor helper - used by code running on render threads to request chunk snapshot cache from server/sync thread
@@ -416,14 +434,13 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
return null;
}
if(w.visibility_limits != null) {
for(MapChunkCache.VisibilityLimit limit: w.visibility_limits) {
for(VisibilityLimit limit: w.visibility_limits) {
c.setVisibleRange(limit);
}
c.setHiddenFillStyle(w.hiddenchunkstyle);
c.setAutoGenerateVisbileRanges(w.do_autogenerate);
}
if(w.hidden_limits != null) {
for(MapChunkCache.VisibilityLimit limit: w.hidden_limits) {
for(VisibilityLimit limit: w.hidden_limits) {
c.setHiddenRange(limit);
}
c.setHiddenFillStyle(w.hiddenchunkstyle);
@@ -459,11 +476,17 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
return exhausted;
}
});
if (f == null) {
return null;
}
Boolean delay;
try {
delay = f.get();
} catch (CancellationException cx) {
return null;
} catch (ExecutionException ex) {
Log.severe("Exception while fetching chunks: ", ex.getCause());
return null;
} catch (Exception ix) {
Log.severe(ix);
return null;
@@ -492,6 +515,7 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
Object rslt =ismodloaded.invoke(null, name);
if(rslt instanceof Boolean) {
if(((Boolean)rslt).booleanValue()) {
modsused.add(name);
return true;
}
}
@@ -598,6 +622,13 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
public long getFirstLoginTime() {
return offplayer.getFirstPlayed();
}
@Override
public boolean isInvisible() {
if(player != null) {
return player.hasPotionEffect(PotionEffectType.INVISIBILITY);
}
return false;
}
}
/* Handler for generic console command sender */
public class BukkitCommandSender implements DynmapCommandSender {
@@ -636,63 +667,45 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
}
public void loadExtraBiomes() {
Field tmpfld;
Field humfld;
int cnt = 0;
try {
tmpfld = BiomeBase.class.getField("temperature");
} catch (NoSuchFieldException nsfx) {
try {
tmpfld = BiomeBase.class.getField("F");
} catch (NoSuchFieldException nsfx2) {
Log.warning("BiomeBase.temperature field not found");
tmpfld = null;
}
}
if((tmpfld != null) && (tmpfld.getType().getClass().isAssignableFrom(float.class) == false)) {
tmpfld = null;
}
try {
humfld = BiomeBase.class.getField("humidity");
} catch (NoSuchFieldException nsfx) {
try {
humfld = BiomeBase.class.getField("G");
} catch (NoSuchFieldException nsfx2) {
Log.warning("BiomeBase.humidity field not found");
humfld = null;
}
}
if((humfld != null) && (humfld.getType().getClass().isAssignableFrom(float.class) == false)) {
humfld = null;
}
for(int i = BiomeMap.LAST_WELL_KNOWN+1; i < BiomeBase.biomes.length; i++) {
BiomeBase bb = BiomeBase.biomes[i];
/* Find array of biomes in biomebase */
Object[] biomelist = helper.getBiomeBaseList();
/* Loop through list, starting afer well known biomes */
for(int i = BiomeMap.LAST_WELL_KNOWN+1; i < biomelist.length; i++) {
Object bb = biomelist[i];
if(bb != null) {
String id = "BIOME_" + i;
float tmp = 0.5F, hum = 0.5F;
try {
id = bb.y;
} catch (Exception x) {}
try {
if(tmpfld != null)
tmp = tmpfld.getFloat(bb);
if(humfld != null)
hum = humfld.getFloat(bb);
} catch (Exception x) {
String id = helper.getBiomeBaseIDString(bb);
if(id == null) {
id = "BIOME_" + i;
}
float tmp = helper.getBiomeBaseTemperature(bb);
float hum = helper.getBiomeBaseHumidity(bb);
BiomeMap m = new BiomeMap(i, id, tmp, hum);
Log.verboseinfo("Add custom biome [" + m.toString() + "] (" + i + ")");
cnt++;
}
}
Log.info("Added " + cnt + " custom biome mappings");
if(cnt > 0) {
Log.info("Added " + cnt + " custom biome mappings");
}
}
@Override
public void onLoad() {
Log.setLogger(this.getLogger(), "");
helper = BukkitVersionHelper.getHelper();
pm = this.getServer().getPluginManager();
}
@Override
public void onEnable() {
pm = this.getServer().getPluginManager();
if (helper == null) {
Log.info("Dynmap is disabled (unsupported platform)");
return;
}
PluginDescriptionFile pdfFile = this.getDescription();
version = pdfFile.getVersion();
@@ -712,6 +725,8 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
permissions = PEXPermissions.create(getServer(), "dynmap");
if (permissions == null)
permissions = bPermPermissions.create(getServer(), "dynmap", perdefs);
if (permissions == null)
permissions = GroupManagerPermissions.create(getServer(), "dynmap");
if (permissions == null)
permissions = PermBukkitPermissions.create(getServer(), "dynmap", perdefs);
if (permissions == null)
@@ -739,10 +754,14 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
if(core == null)
core = new DynmapCore();
/* Inject dependencies */
core.setPluginVersion(version);
core.setPluginJarFile(this.getFile());
core.setPluginVersion(version, "CraftBukkit");
core.setMinecraftVersion(mcver);
core.setDataFolder(dataDirectory);
core.setServer(new BukkitServer());
core.setBlockNames(helper.getBlockShortNames());
core.setBlockMaterialMap(helper.getBlockMaterialMap());
core.setBiomeNames(helper.getBiomeNames());
/* Load configuration */
if(!core.initConfiguration(enabCoreCB)) {
@@ -797,19 +816,24 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
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);
}
}
/* Register our update trigger events */
registerEvents();
/* Submit metrics to mcstats.org */
initMetrics();
/* Core is ready - notify API availability */
DynmapCommonAPIListener.apiInitialized(this);
Log.info("Enabled");
}
@Override
public void onDisable() {
/* Core is being disabled - notify API disable */
DynmapCommonAPIListener.apiTerminated();
if (metrics != null) {
metrics = null;
}
@@ -1402,10 +1426,17 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
@EventHandler(priority=EventPriority.MONITOR)
public void onChunkPopulate(ChunkPopulateEvent event) {
Chunk c = event.getChunk();
ChunkSnapshot cs = c.getChunkSnapshot();
int ymax = 0;
for(int i = 0; i < c.getWorld().getMaxHeight() / 16; i++) {
if(!cs.isSectionEmpty(i)) {
ymax = (i+1)*16;
}
}
/* Touch extreme corners */
int x = c.getX() << 4;
int z = c.getZ() << 4;
mapManager.touchVolume(getWorld(event.getWorld()).getName(), x, 0, z, x+15, 128, z+16, "chunkpopulate");
mapManager.touchVolume(getWorld(event.getWorld()).getName(), x, 0, z, x+15, ymax, z+16, "chunkpopulate");
}
};
pm.registerEvents(chunkTrigger, this);
@@ -1536,6 +1567,15 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
return cnt;
}
});
for (String mod : modsused) {
features.addPlotter(new Metrics.Plotter(mod + " Blocks") {
@Override
public int getValue() {
return 1;
}
});
}
metrics.start();
} catch (IOException e) {
// Failed to submit the stats :-(
+103 -79
View File
@@ -25,7 +25,6 @@
* authors and contributors and should not be interpreted as representing official policies,
* either expressed or implied, of anybody else.
*/
package org.dynmap.bukkit;
import org.bukkit.Bukkit;
@@ -33,6 +32,7 @@ import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.scheduler.BukkitTask;
import java.io.BufferedReader;
import java.io.File;
@@ -53,15 +53,11 @@ import java.util.UUID;
import java.util.logging.Level;
/**
* <p>
* The metrics class obtains data about a plugin and submits statistics about it to the metrics backend.
* </p>
* <p>
* Public methods provided by this class:
* </p>
* <p> The metrics class obtains data about a plugin and submits statistics about it to the metrics backend. </p> <p>
* Public methods provided by this class: </p>
* <code>
* Graph createGraph(String name); <br/>
* void addCustomData(Metrics.Plotter plotter); <br/>
* void addCustomData(BukkitMetrics.Plotter plotter); <br/>
* void start(); <br/>
* </code>
*/
@@ -70,68 +66,60 @@ public class Metrics {
/**
* The current revision number
*/
private final static int REVISION = 5;
private final static int REVISION = 6;
/**
* The base url of the metrics domain
*/
private static final String BASE_URL = "http://mcstats.org";
/**
* The url used to report a server's status
*/
private static final String REPORT_URL = "/report/%s";
/**
* The separator to use for custom data. This MUST NOT change unless you are hosting your own
* version of metrics and want to change it.
* The separator to use for custom data. This MUST NOT change unless you are hosting your own version of metrics and
* want to change it.
*/
private static final String CUSTOM_DATA_SEPARATOR = "~~";
/**
* Interval of time to ping (in minutes)
*/
private static final int PING_INTERVAL = 10;
/**
* The plugin this metrics submits for
*/
private final Plugin plugin;
/**
* All of the custom graphs to submit to metrics
*/
private final Set<Graph> graphs = Collections.synchronizedSet(new HashSet<Graph>());
/**
* The default graph, used for addCustomData when you don't want a specific graph
*/
private final Graph defaultGraph = new Graph("Default");
/**
* The plugin configuration file
*/
private final YamlConfiguration configuration;
/**
* The plugin configuration file
*/
private final File configurationFile;
/**
* Unique server id
*/
private final String guid;
/**
* Debug mode
*/
private final boolean debug;
/**
* Lock for synchronization
*/
private final Object optOutLock = new Object();
/**
* Id of the scheduled task
* The scheduled task
*/
private volatile int taskId = -1;
private volatile BukkitTask task = null;
public Metrics(final Plugin plugin) throws IOException {
if (plugin == null) {
@@ -147,6 +135,7 @@ public class Metrics {
// add some defaults
configuration.addDefault("opt-out", false);
configuration.addDefault("guid", UUID.randomUUID().toString());
configuration.addDefault("debug", false);
// Do we need to create the file?
if (configuration.get("guid", null) == null) {
@@ -156,11 +145,12 @@ public class Metrics {
// Load the guid then
guid = configuration.getString("guid");
debug = configuration.getBoolean("debug", false);
}
/**
* Construct and create a Graph that can be used to separate specific plotters to their own graphs
* on the metrics website. Plotters can be added to the graph object returned.
* Construct and create a Graph that can be used to separate specific plotters to their own graphs on the metrics
* website. Plotters can be added to the graph object returned.
*
* @param name The name of the graph
* @return Graph object created. Will never return NULL under normal circumstances unless bad parameters are given
@@ -181,7 +171,7 @@ public class Metrics {
}
/**
* Add a Graph object to Metrics that represents data for the plugin that should be sent to the backend
* Add a Graph object to BukkitMetrics that represents data for the plugin that should be sent to the backend
*
* @param graph The name of the graph
*/
@@ -211,9 +201,9 @@ public class Metrics {
}
/**
* Start measuring statistics. This will immediately create an async repeating task as the plugin and send
* the initial data to the metrics backend, and then after that it will post in increments of
* PING_INTERVAL * 1200 ticks.
* Start measuring statistics. This will immediately create an async repeating task as the plugin and send the
* initial data to the metrics backend, and then after that it will post in increments of PING_INTERVAL * 1200
* ticks.
*
* @return True if statistics measuring is running, otherwise false.
*/
@@ -225,12 +215,13 @@ public class Metrics {
}
// Is metrics already running?
if (taskId >= 0) {
if (task != null) {
return true;
}
// Begin hitting the server with glorious data
taskId = plugin.getServer().getScheduler().scheduleAsyncRepeatingTask(plugin, new Runnable() {
try {
task = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, new Runnable() {
private boolean firstPost = true;
@@ -239,11 +230,11 @@ public class Metrics {
// This has to be synchronized or it can collide with the disable method.
synchronized (optOutLock) {
// Disable Task, if it is running and the server owner decided to opt-out
if (isOptOut() && taskId > 0) {
plugin.getServer().getScheduler().cancelTask(taskId);
taskId = -1;
if (isOptOut() && task != null) {
task.cancel();
task = null;
// Tell all plotters to stop gathering information.
for (Graph graph : graphs){
for (Graph graph : graphs) {
graph.onOptOut();
}
}
@@ -258,10 +249,16 @@ public class Metrics {
// Each post thereafter will be a ping
firstPost = false;
} catch (IOException e) {
//Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage());
if (debug) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage());
}
}
}
}, 0, PING_INTERVAL * 1200);
}, 0, PING_INTERVAL * 1200);
} catch (NoSuchMethodError nsme) {
// Handle deprecated scheduler API stupidity
return false;
}
return true;
}
@@ -273,15 +270,19 @@ public class Metrics {
* @return true if metrics should be opted out of it
*/
public boolean isOptOut() {
synchronized(optOutLock) {
synchronized (optOutLock) {
try {
// Reload the metrics file
configuration.load(getConfigFile());
} catch (IOException ex) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
if (debug) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
}
return true;
} catch (InvalidConfigurationException ex) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
if (debug) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
}
return true;
}
return configuration.getBoolean("opt-out", false);
@@ -289,30 +290,30 @@ public class Metrics {
}
/**
* Enables metrics for the server by setting "opt-out" to false in the config file and starting the metrics task.
*
* @throws IOException
*/
* Enables metrics for the server by setting "opt-out" to false in the config file and starting the metrics task.
*
* @throws java.io.IOException
*/
public void enable() throws IOException {
// This has to be synchronized or it can collide with the check in the task.
synchronized (optOutLock) {
// Check if the server owner has already set opt-out, if not, set it.
if (isOptOut()) {
configuration.set("opt-out", false);
configuration.save(configurationFile);
}
// Check if the server owner has already set opt-out, if not, set it.
if (isOptOut()) {
configuration.set("opt-out", false);
configuration.save(configurationFile);
}
// Enable Task, if it is not running
if (taskId < 0) {
start();
}
// Enable Task, if it is not running
if (task == null) {
start();
}
}
}
/**
* Disables metrics for the server by setting "opt-out" to true in the config file and canceling the metrics task.
*
* @throws IOException
* @throws java.io.IOException
*/
public void disable() throws IOException {
// This has to be synchronized or it can collide with the check in the task.
@@ -324,9 +325,9 @@ public class Metrics {
}
// Disable Task, if it is running
if (taskId > 0) {
this.plugin.getServer().getScheduler().cancelTask(taskId);
taskId = -1;
if (task != null) {
task.cancel();
task = null;
}
}
}
@@ -352,17 +353,45 @@ public class Metrics {
* Generic method that posts a plugin to the metrics website
*/
private void postPlugin(final boolean isPing) throws IOException {
// The plugin's description file containg all of the plugin data such as name, version, author, etc
final PluginDescriptionFile description = plugin.getDescription();
// Server software specific section
PluginDescriptionFile description = plugin.getDescription();
String pluginName = description.getName();
boolean onlineMode = Bukkit.getServer().getOnlineMode(); // TRUE if online mode is enabled
String pluginVersion = description.getVersion();
String serverVersion = Bukkit.getVersion();
int playersOnline = Bukkit.getServer().getOnlinePlayers().length;
// END server software specific section -- all code below does not use any code outside of this class / Java
// Construct the post data
final StringBuilder data = new StringBuilder();
// The plugin's description file containg all of the plugin data such as name, version, author, etc
data.append(encode("guid")).append('=').append(encode(guid));
encodeDataPair(data, "version", description.getVersion());
encodeDataPair(data, "server", Bukkit.getVersion());
encodeDataPair(data, "players", Integer.toString(Bukkit.getServer().getOnlinePlayers().length));
encodeDataPair(data, "version", pluginVersion);
encodeDataPair(data, "server", serverVersion);
encodeDataPair(data, "players", Integer.toString(playersOnline));
encodeDataPair(data, "revision", String.valueOf(REVISION));
// New data as of R6
String osname = System.getProperty("os.name");
String osarch = System.getProperty("os.arch");
String osversion = System.getProperty("os.version");
String java_version = System.getProperty("java.version");
int coreCount = Runtime.getRuntime().availableProcessors();
// normalize os arch .. amd64 -> x86_64
if (osarch.equals("amd64")) {
osarch = "x86_64";
}
encodeDataPair(data, "osname", osname);
encodeDataPair(data, "osarch", osarch);
encodeDataPair(data, "osversion", osversion);
encodeDataPair(data, "cores", Integer.toString(coreCount));
encodeDataPair(data, "online-mode", Boolean.toString(onlineMode));
encodeDataPair(data, "java_version", java_version);
// If we're pinging, append it
if (isPing) {
encodeDataPair(data, "ping", "true");
@@ -393,7 +422,7 @@ public class Metrics {
}
// Create the url
URL url = new URL(BASE_URL + String.format(REPORT_URL, encode(plugin.getDescription().getName())));
URL url = new URL(BASE_URL + String.format(REPORT_URL, encode(pluginName)));
// Connect to the website
URLConnection connection;
@@ -456,8 +485,8 @@ public class Metrics {
}
/**
* <p>Encode a key/value data pair to be used in a HTTP post request. This INCLUDES a & so the first
* key/value pair MUST be included manually, e.g:</p>
* <p>Encode a key/value data pair to be used in a HTTP post request. This INCLUDES a & so the first key/value pair
* MUST be included manually, e.g:</p>
* <code>
* StringBuffer data = new StringBuffer();
* data.append(encode("guid")).append('=').append(encode(guid));
@@ -488,11 +517,10 @@ public class Metrics {
public static class Graph {
/**
* The graph's name, alphanumeric and spaces only :)
* If it does not comply to the above when submitted, it is rejected
* The graph's name, alphanumeric and spaces only :) If it does not comply to the above when submitted, it is
* rejected
*/
private final String name;
/**
* The set of plotters that are contained within this graph
*/
@@ -532,7 +560,7 @@ public class Metrics {
/**
* Gets an <b>unmodifiable</b> set of the plotter objects in the graph
*
* @return an unmodifiable {@link Set} of the plotter objects
* @return an unmodifiable {@link java.util.Set} of the plotter objects
*/
public Set<Plotter> getPlotters() {
return Collections.unmodifiableSet(plotters);
@@ -554,11 +582,10 @@ public class Metrics {
}
/**
* Called when the server owner decides to opt-out of Metrics while the server is running.
* Called when the server owner decides to opt-out of BukkitMetrics while the server is running.
*/
protected void onOptOut() {
}
}
/**
@@ -588,10 +615,9 @@ public class Metrics {
}
/**
* Get the current value for the plotted point. Since this function defers to an external function
* it may or may not return immediately thus cannot be guaranteed to be thread friendly or safe.
* This function can be called from any thread so care should be taken when accessing resources
* that need to be synchronized.
* Get the current value for the plotted point. Since this function defers to an external function it may or may
* not return immediately thus cannot be guaranteed to be thread friendly or safe. This function can be called
* from any thread so care should be taken when accessing resources that need to be synchronized.
*
* @return the current value for the point to be plotted.
*/
@@ -626,7 +652,5 @@ public class Metrics {
final Plotter plotter = (Plotter) object;
return plotter.name.equals(name) && plotter.getValue() == getValue();
}
}
}
File diff suppressed because it is too large Load Diff
@@ -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) {
@@ -115,7 +115,12 @@ public class SpoutPluginBlocks {
/* Loop through blocks - try to freshen files, if needed */
for(CustomBlock b : cb) {
BlockDesign bd = b.getBlockDesign();
String blkid = bd.getTexturePlugin() + "." + fixIDString(b.getName());
if(bd == null) continue;
String txtplug = bd.getTexturePlugin();
if(txtplug == null) continue;
String blkname = b.getName();
if(blkname == null) continue;
String blkid = txtplug + "." + fixIDString(blkname);
/* If not GenericCubiodBlockDesign, we don't handle it */
if((bd instanceof GenericCuboidBlockDesign) == false) {
Log.info("Block " + blkid + " not suppored - only cubiod blocks");
@@ -0,0 +1,64 @@
package org.dynmap.bukkit.permissions;
import java.util.HashSet;
import java.util.Set;
import org.bukkit.Server;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.dynmap.Log;
import org.anjocaido.groupmanager.GroupManager;
import org.anjocaido.groupmanager.dataholder.worlds.WorldsHolder;
import org.anjocaido.groupmanager.permissions.AnjoPermissionsHandler;
public class GroupManagerPermissions implements PermissionProvider {
String name;
GroupManager gm;
WorldsHolder wh;
public static GroupManagerPermissions create(Server server, String name) {
Plugin permissionsPlugin = server.getPluginManager().getPlugin("GroupManager");
if (permissionsPlugin == null)
return null;
server.getPluginManager().enablePlugin(permissionsPlugin);
if(permissionsPlugin.isEnabled() == false)
return null;
Log.info("Using GroupManager " + permissionsPlugin.getDescription().getVersion() + " for access control");
return new GroupManagerPermissions(name, permissionsPlugin);
}
public GroupManagerPermissions(String name, Plugin permissionsPlugin) {
this.name = name;
gm = (GroupManager)permissionsPlugin;
wh = gm.getWorldsHolder();
}
@Override
public boolean has(CommandSender sender, String permission) {
Player player = sender instanceof Player ? (Player) sender : null;
return (player != null) ? wh.getWorldPermissions(player).has(player, name + "." + permission) : true;
}
@Override
public Set<String> hasOfflinePermissions(String player, Set<String> perms) {
HashSet<String> hasperms = new HashSet<String>();
AnjoPermissionsHandler apm = wh.getWorldPermissionsByPlayerName(player);
if (apm != null) {
for (String pp : perms) {
if (apm.permission(player, name + "." + pp)) {
hasperms.add(pp);
}
}
}
return hasperms;
}
@Override
public boolean hasOfflinePermission(String player, String perm) {
AnjoPermissionsHandler apm = wh.getWorldPermissionsByPlayerName(player);
if(apm != null) {
return apm.permission(player, name + "." + perm);
}
return false;
}
}
+51 -11
View File
@@ -1,14 +1,18 @@
# All paths in this configuration file are relative to Dynmap's data-folder: minecraft_server/plugins/dynmap/
# All map templates are defined in the templates directory
# The 'classic' FlatMap and KzedMap templates are used, which can be found in normal.txt, nether.txt, and skylands.txt
# To use these, do not set deftemplatesuffix (make sure deftemplatesuffix is commented, below)
# To use the HDMap very-low-res map templates as world defaults (normal-vlowres, nether-vlowres and skylands-vlowres), set value to vlowres
# The definitions of these templates are in normal-vlowres.txt, nether-vlowres.txt, and skylands-vlowres.txt
# To use the HDMap low-res map templates as world defaults (normal-lowres, nether-lowres and skylands-lowres), set value to lowres
# The definitions of these templates are in normal-lowres.txt, nether-lowres.txt, and skylands-lowres.txt
# To use the HDMap hi-res map templates (these can take a VERY long time for initial fullrender), set value to hires
# The definitions of these templates are in normal-hires.txt, nether-hires.txt, and skylands-hires.txt
# To use the HDMap very-low-res (2 ppb) map templates as world defaults, set value to vlowres
# The definitions of these templates are in normal-vlowres.txt, nether-vlowres.txt, and the_end-vlowres.txt
# To use the HDMap low-res (4 ppb) map templates as world defaults, set value to lowres
# The definitions of these templates are in normal-lowres.txt, nether-lowres.txt, and the_end-lowres.txt
# To use the HDMap hi-res (16 ppb) map templates (these can take a VERY long time for initial fullrender), set value to hires
# The definitions of these templates are in normal-hires.txt, nether-hires.txt, and the_end-hires.txt
# To use the HDMap low-res (4 ppb) map templates, with support for boosting resolution selectively to hi-res (16 ppb), set value to low_boost_hi
# The definitions of these templates are in normal-low_boost_hi.txt, nether-low_boost_hi.txt, and the_end-low_boost_hi.txt
# To use the HDMap hi-res (16 ppb) map templates, with support for boosting resolution selectively to vhi-res (32 ppb), set value to hi_boost_vhi
# The definitions of these templates are in normal-hi_boost_vhi.txt, nether-hi_boost_vhi.txt, and the_end-hi_boost_vhi.txt
# To use the HDMap hi-res (16 ppb) map templates, with support for boosting resolution selectively to xhi-res (64 ppb), set value to hi_boost_xhi
# The definitions of these templates are in normal-hi_boost_xhi.txt, nether-hi_boost_xhi.txt, and the_end-hi_boost_xhi.txt
deftemplatesuffix: vlowres
components:
@@ -42,11 +46,13 @@ components:
hideifsneaking: false
# If true, player positions/status is protected (login with ID with dynmap.playermarkers.seeall permission required for info other than self)
protected-player-info: false
# If true, hide players with invisibility potion effects active
hide-if-invisiblity-potion: true
#- class: org.dynmap.JsonFileClientUpdateComponent
# writeinterval: 1
# sendhealth: true
# sendposition: true
# allowwebchat: false
# allowwebchat: true
# webchat-interval: 5
# hidewebchatip: false
# includehiddenplayers: false
@@ -62,6 +68,7 @@ components:
# webchat-permissions: false
# # Limit length of single chat messages
# chatlengthlimit: 256
# hide-if-invisiblity-potion: true
- class: org.dynmap.SimpleWebChatComponent
allowchat: true
@@ -131,7 +138,7 @@ components:
- class: org.dynmap.ClientComponent
type: timeofdayclock
showdigitalclock: true
#showweather: true
showweather: true
# Mouse pointer world coordinate display
- class: org.dynmap.ClientComponent
type: coord
@@ -183,6 +190,14 @@ saverestorepending: true
# Zoom-out tile update period - how often to scan for and process tile updates into zoom-out tiles (in seconds)
zoomoutperiod: 30
# Control whether zoom out tiles are validated on startup (can be needed if zoomout processing is interrupted, but can be expensive on large maps)
initial-zoomout-validate: true
# Default delay on processing of updated tiles, in seconds. This can reduce potentially expensive re-rendering
# of frequently updated tiles (such as due to machines, pistons, quarries or other automation). Values can
# also be set on individual worlds and individual maps.
tileupdatedelay: 30
# Tile hashing is used to minimize tile file updates when no changes have occurred - set to false to disable
enabletilehash: true
@@ -193,7 +208,7 @@ enabletilehash: true
#better-grass: true
# Optional - enable smooth lighting by default on all maps supporting it (can be set per map as lighting option)
smooth-lighting: false
smooth-lighting: true
# Default image format for HDMaps (png, jpg, jpg-q75, jpg-q80, jpg-q85, jpg-q90, jpg-q95, jpg-q100)
# Has no effect on maps with explicit format settings
@@ -201,8 +216,15 @@ 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
# ctm-support: if true, Connected Texture Mod (CTM) in texture packs is enabled (default)
ctm-support: true
# custom-colors-support: if true, Custom Colors in texture packs is enabled (default)
custom-colors-support: true
# Control loading of player faces (if set to false, skins are never fetched)
#fetchskins: false
@@ -299,8 +321,15 @@ grayplayerswhenhidden: true
# Access-Control-Allow-Origin: "my-domain.com"
# X-Custom-Header-Of-Mine: "MyHeaderValue"
# Trusted proxies for web server - which proxy addresses are trusted to supply valid X-Forwarded-For fields
trusted-proxies:
- "127.0.0.1"
- "0:0:0:0:0:0:0:1"
# Join/quit message format for web chat: set to "" to disable notice on web UI
joinmessage: "%playername% joined"
quitmessage: "%playername% quit"
spammessage: "You may only chat once every %interval% seconds."
# format for messages from web: %playername% substitutes sender ID (typically IP), %message% includes text
webmsgformat: "&color;2[WEB] %playername%: &color;f%message%"
@@ -322,6 +351,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"
@@ -355,6 +387,14 @@ spout:
# to clean cached textures and force reload on next startup)
use-existing-textures: true
# Customization commands - allows scripts to be run before/after certain events
custom-commands:
image-updates:
# Command run just before any image file is written or updated: run with single parameter with fully qualified file name
preupdatecommand: ""
# Command run just after any image file is written or updated: run with single parameter with fully qualified file name
postupdatecommand: ""
# Set to true to enable verbose startup messages - can help with debugging map configuration problems
# Set to false for a much quieter startup log
verbose: false
+2 -1
View File
@@ -1,7 +1,8 @@
name: dynmap
main: org.dynmap.bukkit.DynmapPlugin
version: "${project.version}-${BUILD_NUMBER}"
authors: [FrozenCow, mikeprimm]
authors: [mikeprimm]
website: "http://www.minecraftforum.net/topic/1543523-dynmap-dynamic-web-based-maps-for-minecraft/"
softdepend: [ Permissions, PermissionEx, bPermissions, PermissionsBukkit ]
commands:
dynmap: