Compare commits

..

67 Commits

Author SHA1 Message Date
Mike Primm f7d2dac826 Add permissions and help for /dynmap quiet command 2013-12-30 01:46:29 -06:00
Mike Primm 3cb7ba342c Add setting for periodic save of pending jobs 2013-12-30 01:45:17 -06:00
Mike Primm d2ab466dc0 Update server interface for mod-supplied texture/model files 2013-12-28 23:56:22 -06:00
Mike Primm d03ed7a461 Bump to 1.9.2 2013-12-24 10:52:17 -06:00
Mike Primm c8469d7aba Strip version check 2013-12-05 00:11:40 -06:00
Mike Primm e7c92096b2 Turn off version check (dev.bukkit.org doesn't like it...) 2013-12-02 16:12:11 -06:00
Mike Primm 0c9d397144 Update to support CB 1.7.2-R0.1 2013-12-01 08:32:16 -06:00
Mike Primm b4a3b61c11 Start mod support API 2013-11-30 22:51:48 -06:00
Mike Primm 564c38b44a Back to 1.9.1 2013-11-16 23:27:35 -06:00
Mike Primm 664e7da659 Bump to 2.0 2013-10-21 19:33:37 -05:00
Mike Primm 9046212a47 Update for mod image loading support 2013-09-18 17:17:23 -05:00
Mike Primm b6ee68c9b0 Fix comment typo 2013-09-14 16:38:38 -05:00
Mike Primm 7854568d88 Fix typo in security flag for dynmap.webregister.other 2013-09-14 15:56:24 -05:00
Mike Primm f1c9417237 Add support for web server bindaddress to be set to match MC server-ip setting 2013-09-08 00:00:25 -05:00
Mike Primm 336f8302c4 Have spout code handle renderdata not being defined yet 2013-09-07 23:11:35 -05:00
Mike Primm d8ccc26109 Add mod version check code 2013-08-16 02:17:10 -05:00
Mike Primm d396046249 Add block-id-alias setting 2013-08-04 18:07:36 -05:00
Mike Primm 1793d910d4 Straighten out GroupManager offline permissions 2013-07-18 08:44:33 -05:00
Mike Primm f0f881d126 Bump to 1.9 2013-07-07 22:01:02 -05:00
Mike Primm 5482ddaa89 Add 2 tick delay to player join processing - allows nicknames to be set before we send message to web 2013-07-05 10:57:19 -05:00
Mike Primm 47455eb912 Add 'hidenames' option, and supporting messages 2013-07-05 09:31:32 -05:00
Mike Primm 32a1c20fd0 Bandaid for MrApple's CB 1.6.1 2013-07-01 19:31:59 -05:00
Mike Primm b85c38e3a7 Add softref option for chunk snapshot cache 2013-06-25 01:09:25 -05:00
Mike Primm 5bc4de6a8b Add zoomout-min-tps setting 2013-06-24 21:44:01 -05:00
Mike Primm 2d20fd11f7 Update dev version format 2013-06-24 20:24:05 -05:00
Mike Primm 6a4bb59d60 Add permission node for /dynmap purgeworld command 2013-06-23 15:11:32 -05:00
Mike Primm ab45edb82c Add settings for TPS limits and per-tick msec limits 2013-06-19 23:20:38 -05:00
Mike Primm 4f6bc05180 Add help for /dynmap purgequeue <world> 2013-06-15 18:10:50 -05:00
Mike Primm 076681e188 Add help and permission node for /dynmap purgemap 2013-06-15 18:07:45 -05:00
Mike Primm b7abfe7c06 Add settings for player-sort-permission-nodes support 2013-06-14 01:49:49 -05:00
Mike Primm 3a88ac66a6 Add use-name-colors setting to control option to use name color markup 2013-06-02 19:28:03 -05:00
Mike Primm d3b9367794 Add 'updateplayerlimit' setting default 2013-06-02 16:31:35 -05:00
Mike Primm 666840fc8b Add help and permissions for /dmarker importdesc, importlabel, getlabel 2013-05-27 09:09:49 -05:00
Mike Primm 62f4c12147 Bump bukkit dependency to 1.4.7 2013-05-27 08:33:49 -05:00
Mike Primm 4b3f2280b6 Add command help and permissions for /dmarker description commands 2013-05-26 14:03:46 -05:00
Mike Primm df55606023 Add method for discovering all chunks in world 2013-05-24 23:59:08 -05:00
Mike Primm 6fc5fddd44 Back to 1.8 2013-05-15 20:53:56 -05:00
Mike Primm dea285c160 Back to 1.7.1 for bug fix 2013-05-15 19:35:06 -05:00
Mike Primm 204641a4b0 Bump to 1.8 2013-05-14 22:06:00 -05:00
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
15 changed files with 772 additions and 442 deletions
+10 -51
View File
@@ -4,8 +4,10 @@
<artifactId>dynmap</artifactId>
<name>dynmap</name>
<properties>
<timestamp>${maven.build.timestamp}</timestamp>
<maven.build.timestamp.format>yyyyMMddHHmm</maven.build.timestamp.format>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<BUILD_NUMBER>Dev</BUILD_NUMBER>
<BUILD_NUMBER>Dev${timestamp}</BUILD_NUMBER>
</properties>
<url>http://github.com/webbukkit/dynmap/</url>
<issueManagement>
@@ -41,31 +43,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 +65,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>
@@ -140,7 +94,7 @@
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.3.2-R3.0</version>
<version>1.4.7-R1.0</version>
</dependency>
<dependency>
<groupId>org.dynmap</groupId>
@@ -178,6 +132,11 @@
<artifactId>PermissionsBukkit</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>org.anjocaido</groupId>
<artifactId>EssentialsGroupManager</artifactId>
<version>2.10.1</version>
</dependency>
</dependencies>
<version>1.4</version>
<version>1.9.2</version>
</project>
@@ -22,8 +22,18 @@ public abstract class BukkitVersionHelper {
public static final BukkitVersionHelper getHelper() {
if(helper == null) {
if(Bukkit.getServer().getVersion().contains("MCPC")) {
Log.info("Loader version helper for MCPC");
helper = new BukkitVersionHelperMCPC();
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();
@@ -102,4 +112,20 @@ public abstract class BukkitVersionHelper {
* 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();
}
@@ -3,20 +3,27 @@ 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.ArrayList;
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;
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;
private Method blockbyidfunc; // 1.7+ method for getting block by id
BukkitVersionHelperCB() {
}
@Override
@@ -34,18 +41,39 @@ public class BukkitVersionHelperCB extends BukkitVersionHelperGeneric {
}
@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 = getFieldNoFail(nmsblock, new String[] { "byId" }, nmsblockarray);
if (blockbyid == null) {
blockbyidfunc = getMethod(nmsblock, new String[] { "e" }, new Class[] { int.class });
}
blockname = getPrivateField(nmsblock, new String[] { "name", "b" }, String.class);
material = getPrivateField(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);
biomebaselist = getPrivateField(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);
biomebaseidstring = getField(biomebase, new String[] { "y", "af" }, 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");
@@ -66,15 +94,15 @@ public class BukkitVersionHelperCB extends BukkitVersionHelperGeneric {
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);
nbttagbyte_val = getPrivateField(nbttagbyte, new String[] { "data" }, byte.class);
nbttagshort_val = getPrivateField(nbttagshort, new String[] { "data" }, short.class);
nbttagint_val = getPrivateField(nbttagint, new String[] { "data" }, int.class);
nbttaglong_val = getPrivateField(nbttaglong, new String[] { "data" }, long.class);
nbttagfloat_val = getPrivateField(nbttagfloat, new String[] { "data" }, float.class);
nbttagdouble_val = getPrivateField(nbttagdouble, new String[] { "data" }, double.class);
nbttagbytearray_val = getPrivateField(nbttagbytearray, new String[] { "data" }, byte[].class);
nbttagstring_val = getPrivateField(nbttagstring, new String[] { "data" }, String.class);
nbttagintarray_val = getPrivateField(nbttagintarray, new String[] { "data" }, int[].class);
/** Tile entity */
nms_tileentity = getNMSClass("net.minecraft.server.TileEntity");
@@ -83,4 +111,108 @@ public class BukkitVersionHelperCB extends BukkitVersionHelperGeneric {
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 {
String[] names = new String[4096];
if (blockbyid != null) {
Object[] byid = (Object[])blockbyid.get(nmsblock);
for (int i = 0; i < names.length; i++) {
if (byid[i] != null) {
names[i] = (String)blockname.get(byid[i]);
}
}
}
else {
for (int i = 0; i < names.length; i++) {
Object blk = blockbyidfunc.invoke(nmsblock, i);
if (blk != null) {
names[i] = (String)blockname.get(blk);
}
}
}
return names;
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException 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 {
int[] map = new int[4096];
if (blockbyid != null) {
Object[] byid = (Object[])blockbyid.get(nmsblock);
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;
}
}
}
}
else {
ArrayList<Object> mats = new ArrayList<Object>();
for (int i = 0; i < map.length; i++) {
Object blk = blockbyidfunc.invoke(nmsblock, i);
if (blk != null) {
Object mat = (Object)material.get(blk);
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) {
} catch (InvocationTargetException e) {
}
return new int[0];
}
}
@@ -92,14 +92,6 @@ public abstract class BukkitVersionHelperGeneric extends BukkitVersionHelper {
/* Craftworld fields */
craftworld = getOBCClass("org.bukkit.craftbukkit.CraftWorld");
cw_gethandle = getMethod(craftworld, new String[] { "getHandle" }, new Class[0]);
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 });
}
/* CraftChunkSnapshot */
craftchunksnapshot = getOBCClass("org.bukkit.craftbukkit.CraftChunkSnapshot");
ccss_biome = getPrivateField(craftchunksnapshot, new String[] { "biome" }, biomebasearray);
@@ -182,7 +174,7 @@ public abstract class BukkitVersionHelperGeneric extends BukkitVersionHelper {
/**
* Get private field
*/
private Field getPrivateField(Class<?> cls, String[] ids, Class<?> type) {
protected Field getPrivateField(Class<?> cls, String[] ids, Class<?> type) {
if((cls == null) || (type == null)) return null;
for(String id : ids) {
try {
@@ -198,7 +190,7 @@ public abstract class BukkitVersionHelperGeneric extends BukkitVersionHelper {
failed = true;
return null;
}
private Object getFieldValue(Object obj, Field field, Object def) {
protected Object getFieldValue(Object obj, Field field, Object def) {
if((obj != null) && (field != null)) {
try {
return field.get(obj);
@@ -1,81 +0,0 @@
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 BukkitVersionHelperMCPC extends BukkitVersionHelperGeneric {
BukkitVersionHelperMCPC() {
}
@Override
protected String getNMSPackage() {
return "";
}
@Override
protected void loadNMS() {
/* biomebase */
biomebase = getNMSClass("yy");
biomebasearray = getNMSClass("[Lyy;");
/* world */
nmsworld = getNMSClass("in");
/* chunk */
chunkprovserver = getNMSClass("im");
nmschunk = getNMSClass("zz");
/* nbt */
nbttagcompound = getNMSClass("bq");
nbttagbyte = getNMSClass("bp");
nbttagshort = getNMSClass("cb");
nbttagint = getNMSClass("bx");
nbttaglong = getNMSClass("bz");
nbttagfloat = getNMSClass("bv");
nbttagdouble = getNMSClass("bt");
nbttagbytearray = getNMSClass("bo");
nbttagstring = getNMSClass("cc");
nbttagintarray = getNMSClass("bw");
/* tileentity */
nms_tileentity = getNMSClass("any");
/** Set up NMS fields **/
/* biomebase */
biomebaselist = getField(biomebase, new String[] { "a" }, biomebasearray);
biomebasetemp = getField(biomebase, new String[] { "F" }, float.class);
biomebasehumi = getField(biomebase, new String[] { "G" }, float.class);
biomebaseidstring = getField(biomebase, new String[] { "y" }, String.class);
biomebaseid = getField(biomebase, new String[] { "N" }, int.class);
/* chunk */
nmsw_chunkproviderserver = getField(nmsworld, new String[] { "b" }, chunkprovserver);
cps_unloadqueue = getFieldNoFail(chunkprovserver, new String[] { "b" }, longhashset);
if(cps_unloadqueue == null) {
Log.info("Unload queue not found - default to unload all chunks");
}
nmsc_removeentities = getMethod(nmschunk, new String[] { "d" }, new Class[0]);
nmsc_tileentities = getField(nmschunk, new String[] { "i" }, Map.class);
/* nbt */
compound_get = getMethod(nbttagcompound, new String[] { "a" }, new Class[] { String.class });
nbttagbyte_val = getField(nbttagbyte, new String[] { "a" }, byte.class);
nbttagshort_val = getField(nbttagshort, new String[] { "a" }, short.class);
nbttagint_val = getField(nbttagint, new String[] { "a" }, int.class);
nbttaglong_val = getField(nbttaglong, new String[] { "a" }, long.class);
nbttagfloat_val = getField(nbttagfloat, new String[] { "a" }, float.class);
nbttagdouble_val = getField(nbttagdouble, new String[] { "a" }, double.class);
nbttagbytearray_val = getField(nbttagbytearray, new String[] { "a" }, byte[].class);
nbttagstring_val = getField(nbttagstring, new String[] { "a" }, String.class);
nbttagintarray_val = getField(nbttagintarray, new String[] { "a" }, int[].class);
/* tileentity */
nmst_readnbt = getMethod(nms_tileentity, new String[] { "b" }, new Class[] { nbttagcompound });
nmst_x = getField(nms_tileentity, new String[] { "l" }, int.class);
nmst_y = getField(nms_tileentity, new String[] { "m" }, int.class);
nmst_z = getField(nms_tileentity, new String[] { "n" }, int.class);
}
}
@@ -2,8 +2,13 @@ package org.dynmap.bukkit;
/**
* Bukkit specific implementation of DynmapWorld
*/
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;
import java.util.List;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.permissions.Permission;
@@ -12,6 +17,7 @@ import org.dynmap.DynmapChunk;
import org.dynmap.DynmapLocation;
import org.dynmap.DynmapWorld;
import org.dynmap.utils.MapChunkCache;
import org.dynmap.utils.TileFlags;
public class BukkitWorld extends DynmapWorld {
private World world;
@@ -160,4 +166,58 @@ public class BukkitWorld extends DynmapWorld {
public World getWorld() {
return world;
}
// Return false if unimplemented
@Override
public int getChunkMap(TileFlags map) {
map.clear();
if (world == null) return -1;
int cnt = 0;
// Mark loaded chunks
for(Chunk c : world.getLoadedChunks()) {
map.setFlag(c.getX(), c.getZ(), true);
cnt++;
}
File f = world.getWorldFolder();
File regiondir = new File(f, "region");
File[] lst = regiondir.listFiles();
if(lst != null) {
byte[] hdr = new byte[4096];
for(File rf : lst) {
if(!rf.getName().endsWith(".mca")) {
continue;
}
String[] parts = rf.getName().split("\\.");
if((!parts[0].equals("r")) && (parts.length != 4)) continue;
RandomAccessFile rfile = null;
int x = 0, z = 0;
try {
x = Integer.parseInt(parts[1]);
z = Integer.parseInt(parts[2]);
rfile = new RandomAccessFile(rf, "r");
rfile.read(hdr, 0, hdr.length);
} catch (IOException iox) {
Arrays.fill(hdr, (byte)0);
} catch (NumberFormatException nfx) {
Arrays.fill(hdr, (byte)0);
} finally {
if(rfile != null) {
try { rfile.close(); } catch (IOException iox) {}
}
}
for (int i = 0; i < 1024; i++) {
int v = hdr[4*i] | hdr[4*i + 1] | hdr[4*i + 2] | hdr[4*i + 3];
if (v == 0) continue;
int xx = (x << 5) | (i & 0x1F);
int zz = (z << 5) | ((i >> 5) & 0x1F);
if (!map.setFlag(xx, zz, true)) {
cnt++;
}
}
}
}
return cnt;
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -3,6 +3,7 @@ package org.dynmap.bukkit;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.lang.ref.SoftReference;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -20,9 +21,10 @@ public class SnapshotCache {
private ReferenceQueue<SnapshotRec> refqueue;
private long cache_attempts;
private long cache_success;
private boolean softref;
private static class CacheRec {
WeakReference<SnapshotRec> ref;
Reference<SnapshotRec> ref;
boolean hasbiome;
boolean hasrawbiome;
boolean hasblockdata;
@@ -32,12 +34,12 @@ public class SnapshotCache {
@SuppressWarnings("serial")
public class CacheHashMap extends LinkedHashMap<String, CacheRec> {
private int limit;
private IdentityHashMap<WeakReference<SnapshotRec>, String> reverselookup;
private IdentityHashMap<Reference<SnapshotRec>, String> reverselookup;
public CacheHashMap(int lim) {
super(16, (float)0.75, true);
limit = lim;
reverselookup = new IdentityHashMap<WeakReference<SnapshotRec>, String>();
reverselookup = new IdentityHashMap<Reference<SnapshotRec>, String>();
}
protected boolean removeEldestEntry(Map.Entry<String, CacheRec> last) {
boolean remove = (size() >= limit);
@@ -51,9 +53,10 @@ public class SnapshotCache {
/**
* Create snapshot cache
*/
public SnapshotCache(int max_size) {
public SnapshotCache(int max_size, boolean softref) {
snapcache = new CacheHashMap(max_size);
refqueue = new ReferenceQueue<SnapshotRec>();
this.softref = softref;
}
private String getKey(String w, int cx, int cz) {
return w + ":" + cx + ":" + cz;
@@ -127,7 +130,10 @@ public class SnapshotCache {
rec.hasbiome = biome;
rec.hasrawbiome = biomeraw;
rec.hashighesty = highesty;
rec.ref = new WeakReference<SnapshotRec>(ss, refqueue);
if (softref)
rec.ref = new SoftReference<SnapshotRec>(ss, refqueue);
else
rec.ref = new WeakReference<SnapshotRec>(ss, refqueue);
CacheRec prevrec = snapcache.put(key, rec);
if(prevrec != null) {
snapcache.reverselookup.remove(prevrec.ref);
@@ -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");
@@ -223,7 +228,10 @@ public class SpoutPluginBlocks {
}
String rslt = sb.toString();
/* Now, generate spout texture file - see if changed */
File st = new File(datadir, "renderdata/spout-texture.txt");
File renderdata = new File(datadir, "renderdata");
if (renderdata.exists() == false)
renderdata.mkdirs();
File st = new File(renderdata, "spout-texture.txt");
if(st.exists()) {
FileReader fr = null;
StringBuilder sbold = new StringBuilder();
@@ -39,7 +39,7 @@ public class BukkitPermissions implements PermissionProvider {
}
@Override
public Set<String> hasOfflinePermissions(String player, Set<String> perms) {
Player p = Bukkit.getPlayerExact(name);
Player p = Bukkit.getPlayerExact(player);
HashSet<String> hasperms = null;
if (p != null) {
hasperms = new HashSet<String>();
@@ -0,0 +1,66 @@
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;
boolean rslt = (player != null) ? gm.getWorldsHolder().getDefaultWorld().getPermissionsHandler().permission(player, name + "." + permission) : true;
return rslt;
}
@Override
public Set<String> hasOfflinePermissions(String player, Set<String> perms) {
HashSet<String> hasperms = new HashSet<String>();
AnjoPermissionsHandler apm = gm.getWorldsHolder().getDefaultWorld().getPermissionsHandler();
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 = gm.getWorldsHolder().getDefaultWorld().getPermissionsHandler();
boolean rslt = false;
if(apm != null) {
rslt = apm.permission(player, name + "." + perm);
}
return rslt;
}
}
@@ -24,8 +24,9 @@ public class PEXPermissions implements PermissionProvider {
server.getPluginManager().enablePlugin(permissionsPlugin);
if(permissionsPlugin.isEnabled() == false)
return null;
if(PermissionsEx.isAvailable() == false)
return null;
//Broken in new dev builds, apparently
//if(PermissionsEx.isAvailable() == false)
// return null;
Log.info("Using PermissionsEx " + permissionsPlugin.getDescription().getVersion() + " for access control");
return new PEXPermissions(name);
}
+72 -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:
@@ -22,6 +26,8 @@ components:
hidewebchatip: false
trustclientname: false
includehiddenplayers: false
# (optional) if true, color codes in player display names are used
use-name-colors: false
# (optional) if true, player login IDs will be used for web chat when their IPs match
use-player-login-ip: true
# (optional) if use-player-login-ip is true, setting this to true will cause chat messages not matching a known player IP to be ignored
@@ -44,6 +50,8 @@ components:
protected-player-info: false
# If true, hide players with invisibility potion effects active
hide-if-invisiblity-potion: true
# If true, player names are not shown on map, chat, list
hidenames: false
#- class: org.dynmap.JsonFileClientUpdateComponent
# writeinterval: 1
# sendhealth: true
@@ -52,6 +60,7 @@ components:
# webchat-interval: 5
# hidewebchatip: false
# includehiddenplayers: false
# use-name-colors: false
# use-player-login-ip: false
# require-player-login-ip: false
# block-banned-player-chat: true
@@ -65,6 +74,7 @@ components:
# # Limit length of single chat messages
# chatlengthlimit: 256
# hide-if-invisiblity-potion: true
# hidenames: false
- class: org.dynmap.SimpleWebChatComponent
allowchat: true
@@ -183,9 +193,15 @@ usenormalthreadpriority: true
# Save and restore pending tile renders - prevents their loss on server shutdown or /reload
saverestorepending: true
# Save period for pending jobs (in seconds): periodic saving for crash recovery of jobs
save-pending-period: 900
# 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.
@@ -201,8 +217,15 @@ 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
# Optional - render specific block IDs using the texures and models of another block ID: can be used to hide/disguise specific
# blocks (e.g. make ores look like stone, hide chests) or to provide simple support for rendering unsupported custom blocks
block-id-alias:
# "14": 1
# "15": 1
# "16": 1
# 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
image-format: png
@@ -214,6 +237,11 @@ 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
@@ -257,7 +285,8 @@ tilespath: web/tiles
webpath: web
# The network-interface the webserver will bind to (0.0.0.0 for all interfaces, 127.0.0.1 for only local access).
webserver-bindaddress: 0.0.0.0
# If not set, uses same setting as server in server.properties (or 0.0.0.0 if not specified)
#webserver-bindaddress: 0.0.0.0
# The TCP-port the webserver will listen on.
webserver-port: 8123
@@ -293,14 +322,29 @@ progressloginterval: 100
# Interval the browser should poll for updates.
updaterate: 2000
# If nonzero, server will pause fullrender/radiusrender processing when 'fullrenderplayerlimit' or more user's are logged in
# If nonzero, server will pause fullrender/radiusrender processing when 'fullrenderplayerlimit' or more users are logged in
fullrenderplayerlimit: 0
# If nonzero, server will pause update render processing when 'updateplayerlimit' or more users are logged in
updateplayerlimit: 0
# Target limit on server thread use - msec per tick
per-tick-time-limit: 50
# If TPS of server is below this setting, update renders processing is paused
update-min-tps: 18.0
# If TPS of server is below this setting, full/radius renders processing is paused
fullrender-min-tps: 18.0
# If TPS of server is below this setting, zoom out processing is paused
zoomout-min-tps: 18.0
showplayerfacesinmenu: true
# Control whether players that are hidden or not on current map are grayed out (true=yes)
grayplayerswhenhidden: true
# Use player permissions to order player list: first to last, players are ordered by first permission listed that they have
# That is, anyone with first listed permission goes before anyone with second, etc, with users with none of the nodes going last
player-sort-permission-nodes:
- bukkit.command.op
# Set sidebaropened: 'true' to pin menu sidebar opened permanently, 'pinned' to default the sidebar to pinned, but allow it to unpin
#sidebaropened: true
@@ -314,8 +358,10 @@ 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%"
@@ -346,6 +392,8 @@ msg:
players: "Players"
chatrequireslogin: "Chat Requires Login"
chatnotallowed: "You are not permitted to send chat messages"
hiddennamejoin: "Player joined"
hiddennamequit: "Player quit"
# URL for client configuration (only need to be tailored for proxies or other non-standard configurations)
url:
@@ -373,6 +421,19 @@ 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: ""
# Snapshot cache size, in chunks
snapshotcachesize: 500
# Snapshot cache uses soft references (true), else weak references (false)
soft-ref-cache: true
# 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
+55 -3
View File
@@ -1,8 +1,9 @@
name: dynmap
main: org.dynmap.bukkit.DynmapPlugin
version: "${project.version}-${BUILD_NUMBER}"
authors: [FrozenCow, mikeprimm]
softdepend: [ Permissions, PermissionEx, bPermissions, PermissionsBukkit ]
authors: [mikeprimm]
website: "http://www.minecraftforum.net/topic/1543523-dynmap-dynamic-web-based-maps-for-minecraft/"
softdepend: [ Permissions, PermissionEx, bPermissions, PermissionsBukkit, GroupManager ]
commands:
dynmap:
description: Controls Dynmap.
@@ -29,8 +30,12 @@ commands:
/<command> resetstats - Reset render statistics.
/<command> sendtoweb msg - Send message to web users
/<command> purgequeue - Set tile update queue to empty
/<command> purgequeue worldname - Set tile update queue to empty for world 'worldname'
/<command> purgemap worldname mapname - Delete all the tiles for map 'mapname' of world 'worldname'
/<command> purgeworld worldname - Delete all the files for world 'worldname'
/<command> pause - Show render pause state
/<command> pause <all|none|full|update> - Set render pause state
/<command> quiet - Stop progress messages from active jobs
/<command> ids-for-ip <ipaddress> - Show player IDs that have logged in from given IP address
/<command> ips-for-id <playerid> - Show IP addresses that have been used for the given player ID
/<command> add-id-for-ip <playerid> <ipaddress> - Add player ID to given IP address
@@ -86,6 +91,17 @@ commands:
/<command> listcircles - list details of all circles
/<command> updatecircle <label> <arg>:<value> ... - update attributes of circle with given label
/<command> updatecircle id:<id> <arg>:<value> ... - update attributes of circle with given ID
/<command> getdesc id:<id> type:<icon|area|circle|line> - get description for marker with given ID
/<command> getdesc <label> type:<icon|area|circle|line> - get description for marker with given label
/<command> resetdesc id:<id> type:<icon|area|circle|line> - clear description for marker with given ID
/<command> resetdesc <label> type:<icon|area|circle|line> - clear description for marker with given label
/<command> appenddesc id:<id> type:<icon|area|circle|line> desc:"text" - append text line to description for marker with given ID
/<command> appenddesc <label> type:<icon|area|circle|line> desc:"text" - append text line to description for marker with given label
/<command> importdesc id:<id> type:<icon|area|circle|line> file:<filename> - import description from given file for marker with given ID
/<command> importdesc <label> type:<icon|area|circle|line> file:<filename> - import description from given file for marker with given label
/<command> importlabel id:<id> type:<icon|area|circle|line> file:<filename> - import label with markup from given file for marker with given ID
/<command> importlabel <label> type:<icon|area|circle|line> file:<filename> - import label with markup from given file for marker with given label
/<command> getlabel id:<id> type:<icon|area|circle|line> - get label for marker with given ID
dmap:
description: List and modify dynmap configuration
@@ -119,6 +135,9 @@ permissions:
dynmap.resetstats: true
dynmap.sendtoweb: true
dynmap.purgequeue: true
dynmap.purgemap: true
dynmap.purgeworld: true
dynmap.quiet: true
dynmap.ids-for-ip: true
dynmap.ips-for-id: true
dynmap.webregister: true
@@ -146,6 +165,12 @@ permissions:
dynmap.marker.updatecircle: true
dynmap.marker.listcircles: true
dynmap.marker.deletecircle: true
dynmap.marker.getdesc: true
dynmap.marker.resetdesc: true
dynmap.marker.appenddesc: true
dynmap.marker.importdesc: true
dynmap.marker.getlabel: true
dynmap.marker.importlabel: true
dynmap.dmap.worldlist: true
dynmap.dmap.worldset: true
dynmap.dmap.worldreset: true
@@ -198,9 +223,18 @@ permissions:
dynmap.purgequeue:
description: Allows /dynmap purgequeue
default: op
dynmap.purgemap:
description: Allows /dynmap purgemap
default: op
dynmap.purgeworld:
description: Allows /dynmap purgeworld
default: op
dynmap.pause:
description: Allows /dynmap pause
default: op
dynmap.quiet:
description: Allows /dynmap quiet
default: true
dynmap.ids-for-ip:
description: Allows /dynmap ids-for-ip
default: op
@@ -210,7 +244,7 @@ permissions:
dynmap.webregister:
description: Allows /dynmap webregister
default: true
dynmao,webregister.other:
dynmap.webregister.other:
description: Allows /dynmap webregister userid
default: op
dynmap.marker.add:
@@ -291,6 +325,24 @@ permissions:
dynmap.marker.deletecircle:
description: Allows /dmarker deletecircle
default: op
dynmap.marker.getdesc:
description: Allows /dmarker getdesc
default: op
dynmap.marker.resetdesc:
description: Allows /dmarker resetdesc
default: op
dynmap.marker.appenddesc:
description: Allows /dmarker appenddesc
default: op
dynmap.marker.importdesc:
description: Allows /dmarker importdesc
default: op
dynmap.marker.getlabel:
description: Allows /dmarker getlabel
default: op
dynmap.marker.importlabel:
description: Allows /dmarker importlabel
default: op
dynmap.dmap.worldlist:
description: Allows /dmap worldlist
default: op