Get 1.13 support building and running a little....

This commit is contained in:
Mike Primm 2018-08-08 01:39:51 -05:00
parent c12e2a6ef9
commit 4e590f0373
42 changed files with 1763 additions and 249 deletions

36
helper/.classpath Normal file
View file

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

1
helper/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target/

23
helper/.project Normal file
View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>helper</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

View file

@ -0,0 +1,6 @@
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/main/resources=UTF-8
encoding//src/test/java=UTF-8
encoding//src/test/resources=UTF-8
encoding/<project>=UTF-8

View file

@ -0,0 +1,5 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
org.eclipse.jdt.core.compiler.compliance=1.5
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.5

View file

@ -0,0 +1,4 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

47
helper/pom.xml Normal file
View file

@ -0,0 +1,47 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>us.dynmap</groupId>
<artifactId>dynmap-bukkit</artifactId>
<version>3.0-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<artifactId>dynmap-helper</artifactId>
<groupId>us.dynmap</groupId>
<version>3.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.7.10-R0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>us.dynmap</groupId>
<artifactId>dynmap-api</artifactId>
<version>3.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>us.dynmap</groupId>
<artifactId>DynmapCore</artifactId>
<version>3.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.2</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>dynmap-repo</id>
<url>http://repo.mikeprimm.com/</url>
</repository>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
</repositories>
<name>dynmap-helper</name>
</project>

View file

@ -0,0 +1,172 @@
package org.dynmap.bukkit.helper;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.bukkit.Chunk;
import org.bukkit.ChunkSnapshot;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.dynmap.DynmapChunk;
import org.dynmap.Log;
import org.dynmap.renderer.DynmapBlockState;
import org.dynmap.utils.MapChunkCache;
import org.dynmap.utils.Polygon;
/**
* Helper for isolation of bukkit version specific issues
*/
public abstract class BukkitVersionHelper {
public static BukkitVersionHelper helper = null;
public static DynmapBlockState[] stateByID;
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 unload queue for given NMS world
*/
public abstract Object getUnloadQueue(World world);
/**
* 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);
/**
* Get inhabited ticks count from chunk
*/
public abstract long getInhabitedTicks(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 name list
*/
public abstract String[] getBlockNames();
/**
* Get biome name list
*/
public abstract String[] getBiomeNames();
/**
* Get block material index list
*/
public abstract int[] getBlockMaterialMap();
/**
* Get list of online players
*/
public abstract Player[] getOnlinePlayers();
/**
* Get player health
*/
public abstract double getHealth(Player p);
/**
* Get world border
*/
public Polygon getWorldBorder(World world) { return null; }
/**
* Test if broken unloadChunk
*/
public boolean isUnloadChunkBroken() { return false; }
/**
* Get skin URL for player
* @param player
*/
public String getSkinURL(Player player) { return null; }
/**
* Initialize block states (org.dynmap.blockstate.DynmapBlockState)
*/
public void initializeBlockStates() {
String[] blkname = getBlockNames();
// Keep it simple for now - just assume 16 meta states for each
stateByID = new DynmapBlockState[16*blkname.length];
Arrays.fill(stateByID, DynmapBlockState.AIR);
for (int i = 0; i < blkname.length; i++) {
if (blkname[i] == null) continue;
String bn = blkname[i];
if (bn.indexOf(':') < 0) {
bn = "minecraft:" + bn;
}
// Only do defined names, and not "air"
if (!bn.equals(DynmapBlockState.AIR_BLOCK)) {
DynmapBlockState basebs = new DynmapBlockState(null, 0, bn, "meta=0");
stateByID[i << 4] = basebs;
for (int m = 1; m < 16; m++) {
DynmapBlockState bs = new DynmapBlockState(basebs, m, bn, "meta=" + m);
stateByID[(i << 4) + m] = bs;
}
}
}
for (int gidx = 0; gidx < DynmapBlockState.getGlobalIndexMax(); gidx++) {
DynmapBlockState bs = DynmapBlockState.getStateByGlobalIndex(gidx);
Log.info(gidx + ":" + bs.toString() + ", gidx=" + bs.globalStateIndex + ", sidx=" + bs.stateIndex);
}
}
/**
* Create chunk cache for given chunks of given world
* @param dw - world
* @param chunks - chunk list
* @return cache
*/
public MapChunkCache getChunkCache(BukkitWorld dw, List<DynmapChunk> chunks) {
NewMapChunkCache c = new NewMapChunkCache();
c.setChunks(dw, chunks);
return c;
}
public Object[] getBlockIDFieldFromSnapshot(ChunkSnapshot css) {
return null;
}
}

View file

@ -0,0 +1,362 @@
package org.dynmap.bukkit.helper;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Map;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Server;
import org.bukkit.World;
import org.dynmap.Log;
import org.dynmap.hdmap.HDBlockModels;
import org.dynmap.utils.Polygon;
/**
* 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 material;
private Method blockbyidfunc; // 1.7+ method for getting block by id
private Method getworldborder; // 1.8+ method for getting world border
private Class<?> nmsworldborder;
private Method worldborderminx;
private Method worldbordermaxx;
private Method worldborderminz;
private Method worldbordermaxz;
private Method getbiomebyid;
private Method getidbybiome;
private boolean isBadUnload = false;
public BukkitVersionHelperCB() {
String bukkitver = Bukkit.getServer().getVersion();
String mcver = "1.0.0";
int idx = bukkitver.indexOf("(MC: ");
if(idx > 0) {
mcver = bukkitver.substring(idx+5);
idx = mcver.indexOf(")");
if(idx > 0) mcver = mcver.substring(0, idx);
}
isBadUnload = HDBlockModels.checkVersionRange(mcver, "1.9-");
Log.verboseinfo("MCVER=" + mcver + ", isBadUnload=" + isBadUnload);
}
@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 = getFieldNoFail(nmsblock, new String[] { "byId" }, nmsblockarray);
if (blockbyid == null) {
blockbyidfunc = getMethod(nmsblock, new String[] { "getById", "e" }, new Class[] { int.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 = getPrivateFieldNoFail(biomebase, new String[] { "biomes" }, biomebasearray);
if (biomebaselist == null) {
getbiomebyid = getMethod(biomebase, new String[] { "a" }, new Class[] { int.class} );
}
biomebasetemp = getPrivateFieldNoFail(biomebase, new String[] { "B" }, float.class);
if (biomebasetemp != null) {
biomebasehumi = getPrivateField(biomebase, new String[] { "C" }, float.class);
}
else {
biomebasetemp = getPrivateField(biomebase, new String[] { "temperature", "F", "C", "aO" }, float.class);
biomebasehumi = getPrivateField(biomebase, new String[] { "humidity", "G", "D", "aP" }, float.class);
}
biomebaseidstring = getPrivateField(biomebase, new String[] { "y", "af", "ah", "z", "aS" }, String.class);
biomebaseid = getFieldNoFail(biomebase, new String[] { "id" }, int.class);
if (biomebaseid == null) {
getidbybiome = getMethod(biomebase, new String[] { "a" }, new Class[] { biomebase } );
}
/* n.m.s.World */
nmsworld = getNMSClass("net.minecraft.server.WorldServer");
chunkprovserver = getNMSClass("net.minecraft.server.ChunkProviderServer");
nmsw_chunkproviderserver = getPrivateFieldNoFail(nmsworld, new String[] { "chunkProviderServer" }, chunkprovserver);
if (nmsw_chunkproviderserver == null) {
Class<?> nmsworldbase = getNMSClass("net.minecraft.server.World");
Class<?> nmsichunkprovider = getNMSClass("net.minecraft.server.IChunkProvider");
nmsw_chunkproviderserver = getPrivateField(nmsworldbase, new String[] { "chunkProvider" }, nmsichunkprovider);
}
getworldborder = getMethodNoFail(nmsworld, new String[] { "af" }, nulltypes);
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 = getOBCClassNoFail("org.bukkit.craftbukkit.util.LongHashset");
if (longhashset != null) {
lhs_containskey = getMethod(longhashset, new String[] { "containsKey" }, new Class[] { int.class, int.class });
}
else {
longhashset = getOBCClassNoFail("org.bukkit.craftbukkit.libs.it.unimi.dsi.fastutil.longs.LongSet");
if (longhashset != null) {
lhs_containskey = getMethod(longhashset, new String[] { "contains" }, new Class[] { long.class });
cps_unloadqueue_isSet = true;
}
}
}
cps_unloadqueue_isSet = false;
if (longhashset != null) {
cps_unloadqueue = getFieldNoFail(chunkprovserver, new String[] { "unloadQueue" }, longhashset);
}
if(cps_unloadqueue == null) {
cps_unloadqueue = getFieldNoFail(chunkprovserver, new String[] { "unloadQueue" }, Set.class);
cps_unloadqueue_isSet = true;
}
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_tileentities = getField(nmschunk, new String[] { "tileEntities" }, Map.class);
nmsc_inhabitedticks = getPrivateFieldNoFail(nmschunk, new String[] { "s", "q", "u", "v", "w", "A" }, long.class);
if (nmsc_inhabitedticks == null) {
Log.info("inhabitedTicks field not found - inhabited shader not functional");
}
/** n.m.s.WorldBorder */
nmsworldborder = getNMSClassNoFail("net.minecraft.server.WorldBorder");
if (nmsworldborder != null) {
worldborderminx = getMethod(nmsworldborder, new String[] { "b" }, nulltypes);
worldborderminz = getMethod(nmsworldborder, new String[] { "c" }, nulltypes);
worldbordermaxx = getMethod(nmsworldborder, new String[] { "d" }, nulltypes);
worldbordermaxz = getMethod(nmsworldborder, new String[] { "e" }, nulltypes);
}
/** 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 = 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");
nmst_readnbt = getMethod(nms_tileentity, new String[] { "b", "save" }, new Class[] { nbttagcompound });
nmst_getposition = getMethodNoFail(nms_tileentity, new String[] { "getPosition" }, new Class[0]); // Try 1.8 method
if (nmst_getposition == null) {
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);
}
else { /* BlockPosition */
nms_blockposition = getNMSClass("net.minecraft.server.BlockPosition");
nmsbp_getx = getMethod(nms_blockposition, new String[] { "getX" }, new Class[0]);
nmsbp_gety = getMethod(nms_blockposition, new String[] { "getY" }, new Class[0]);
nmsbp_getz = getMethod(nms_blockposition, new String[] { "getZ" }, new Class[0]);
}
}
@Override
public void unloadChunkNoSave(World w, Chunk c, int cx, int cz) {
w.unloadChunk(cx, cz, false, false);
}
private String stripBlockString(String bname) {
int idx = bname.indexOf('{');
if (idx >= 0) bname = bname.substring(idx+1);
idx = bname.indexOf('}');
if (idx >= 0) bname = bname.substring(0, idx);
return bname;
}
/**
* Get block short name list
*/
@Override
public String[] getBlockNames() {
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] = stripBlockString(byid[i].toString());
}
}
}
else {
for (int i = 0; i < names.length; i++) {
Object blk = blockbyidfunc.invoke(nmsblock, i);
if (blk != null) {
names[i] = stripBlockString(blk.toString());
}
}
}
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];
}
@Override
public Polygon getWorldBorder(World world) {
Polygon p = null;
if ((getworldborder == null) || (world == null)) {
return null;
}
Object cw = getNMSWorld(world);
if (cw == null) return null;
Object wb = callMethod(cw, getworldborder, nullargs, null);
if (wb != null) {
double minx = (Double) callMethod(wb, worldborderminx, nullargs, Double.MIN_VALUE);
double minz = (Double) callMethod(wb, worldborderminz, nullargs, Double.MIN_VALUE);
double maxx = (Double) callMethod(wb, worldbordermaxx, nullargs, Double.MAX_VALUE);
double maxz = (Double) callMethod(wb, worldbordermaxz, nullargs, Double.MAX_VALUE);
if (maxx < 1E7) {
p = new Polygon();
p.addVertex(minx, minz);
p.addVertex(minx, maxz);
p.addVertex(maxx, maxz);
p.addVertex(maxx, minz);
}
}
return p;
}
private Object[] biomelist = null;
/**
* Get list of defined biomebase objects
*/
public Object[] getBiomeBaseList() {
if (getbiomebyid != null) {
if (biomelist == null) {
biomelist = new Object[1024];
for (int i = 0; i < 1024; i++) {
try {
biomelist[i] = getbiomebyid.invoke(biomebase, i);
} catch (IllegalAccessException x) {
} catch (IllegalArgumentException x) {
} catch (InvocationTargetException x) {
}
}
}
return biomelist;
}
return super.getBiomeBaseList();
}
/** Get ID from biomebase */
public int getBiomeBaseID(Object bb) {
if (getidbybiome != null) {
try {
return (Integer) getidbybiome.invoke(biomebase, bb);
} catch (IllegalAccessException e) {
} catch (IllegalArgumentException e) {
} catch (InvocationTargetException e) {
}
}
return super.getBiomeBaseID(bb);
}
/**
* Test if broken unloadChunk
*/
@Override
public boolean isUnloadChunkBroken() { return isBadUnload; }
}

View file

@ -0,0 +1,561 @@
package org.dynmap.bukkit.helper;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.ChunkSnapshot;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.dynmap.Log;
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
import com.google.common.base.Charsets;
import com.google.common.collect.ForwardingMultimap;
import com.google.common.collect.Iterables;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParseException;
/**
* 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;
protected static final Object[] nullargs = new Object[0];
protected static final Class<?>[] nulltypes = new Class[0];
private static final Map<?, ?> nullmap = Collections.emptyMap();
/** CraftChunkSnapshot */
protected 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 boolean cps_unloadqueue_isSet;
protected Method lhs_containskey;
/** n.m.s.Chunk */
protected Class<?> nmschunk;
protected Field nmsc_tileentities;
protected Field nmsc_inhabitedticks;
/** 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;
protected Method nmst_getposition;
/** BlockPosition */
protected Class<?> nms_blockposition;
protected Method nmsbp_getx;
protected Method nmsbp_gety;
protected Method nmsbp_getz;
/** Server */
protected Method server_getonlineplayers;
/** Player */
protected Method player_gethealth;
// CraftPlayer
private Class<?> obc_craftplayer;
private Method obcplayer_getprofile;
// GameProfile
private Class<?> cma_gameprofile;
private Method cmaprofile_getproperties;
// Property
private Class<?> cma_property;
private Method cmaproperty_getvalue;
protected BukkitVersionHelperGeneric() {
failed = false;
/* 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");
biomebasearray = getNMSClass("[Lnet.minecraft.server.BiomeBase;");
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]);
/** Server */
server_getonlineplayers = getMethod(Server.class, new String[] { "getOnlinePlayers" }, new Class[0]);
/** Player */
player_gethealth = getMethod(Player.class, new String[] { "getHealth" }, new Class[0]);
// CraftPlayer
obc_craftplayer = getOBCClass("org.bukkit.craftbukkit.entity.CraftPlayer");
obcplayer_getprofile = getMethod(obc_craftplayer, new String[] { "getProfile" }, new Class[0]);
// GameProfile
cma_gameprofile = getOBCClass("com.mojang.authlib.GameProfile");
cmaprofile_getproperties = getMethod(cma_gameprofile, new String[] { "getProperties" }, new Class[0]);
// Property
cma_property = getOBCClass("com.mojang.authlib.properties.Property");
cmaproperty_getvalue = getMethod(cma_property, new String[] { "getValue" }, 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<?> getNMSClassNoFail(String classname) {
return getClassByName(classname, "net.minecraft.server", nms_package, true);
}
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 getPrivateFieldNoFail(Class<?> cls, String[] ids, Class<?> type) {
return getPrivateField(cls, ids, type, true);
}
/**
* Get private field
*/
protected Field getPrivateField(Class<?> cls, String[] ids, Class<?> type) {
return getPrivateField(cls, ids, type, false);
}
/**
* Get private field
*/
protected Field getPrivateField(Class<?> cls, String[] ids, Class<?> type, boolean nofail) {
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) {
}
}
if (!nofail) {
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) {
System.out.println(String.format("IllegalArgExc(%s,%s)", obj.toString(), field.toString()));
} catch (IllegalAccessException e) {
System.out.println(String.format("IllegalAccessExc(%s,%s)", obj.toString(), field.toString()));
}
}
else {
System.out.println(String.format("NullArg(%s,%s)", (obj != null)?obj.toString():"null", (field != null)?field.toString():"null"));
}
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;
}
protected Method getMethodNoFail(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) {
}
}
return null;
}
protected 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 */
protected Object getNMSWorld(World w) {
return callMethod(w, cw_gethandle, nullargs, null);
}
/* Get unload queue for given NMS world */
public Object getUnloadQueue(World world) {
Object cps = getFieldValue(getNMSWorld(world), nmsw_chunkproviderserver, null); // Get chunkproviderserver
if ((cps != null) && (cps_unloadqueue != 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) {
if (cps_unloadqueue_isSet)
return ((Set) unloadqueue).contains(Long.valueOf((long)x & 0xFFFFFFFF | ((long)z & 0xFFFFFFFF) << 32));
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;
// }
/**
* Get inhabited ticks count from chunk
*/
private static final Long zero = new Long(0);
public long getInhabitedTicks(Chunk c) {
if (nmsc_inhabitedticks == null) {
return 0;
}
Object omsc = callMethod(c, cc_gethandle, nullargs, null);
if(omsc != null) {
return (Long)getFieldValue(omsc, nmsc_inhabitedticks, zero);
}
return 0;
}
/** 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) {
if (nmst_getposition == null) {
return (Integer)getFieldValue(te, nmst_x, 0);
}
else {
Object pos = callMethod(te, nmst_getposition, nullargs, null);
return (Integer) callMethod(pos, nmsbp_getx, nullargs, null);
}
}
/**
* Get Y coordinate of tile entity
*/
public int getTileEntityY(Object te) {
if (nmst_getposition == null) {
return (Integer)getFieldValue(te, nmst_y, 0);
}
else {
Object pos = callMethod(te, nmst_getposition, nullargs, null);
return (Integer) callMethod(pos, nmsbp_gety, nullargs, null);
}
}
/**
* Get Z coordinate of tile entity
*/
public int getTileEntityZ(Object te) {
if (nmst_getposition == null) {
return (Integer)getFieldValue(te, nmst_z, 0);
}
else {
Object pos = callMethod(te, nmst_getposition, nullargs, null);
return (Integer) callMethod(pos, nmsbp_getz, nullargs, null);
}
}
/**
* 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;
}
/**
* Get list of online players
*/
public Player[] getOnlinePlayers() {
Object players = callMethod(Bukkit.getServer(), server_getonlineplayers, nullargs, null);
if (players instanceof Player[]) { /* Pre 1.7.10 */
return (Player[]) players;
}
else {
@SuppressWarnings("unchecked")
Collection<? extends Player> p = (Collection<? extends Player>) players;
return p.toArray(new Player[0]);
}
}
/**
* Get player health
*/
@Override
public double getHealth(Player p) {
Object health = callMethod(p, player_gethealth, nullargs, null);
if (health instanceof Integer) {
return (Integer) health;
}
else {
return ((Double) health).intValue();
}
}
private static final Gson gson = new GsonBuilder().create();
public class TexturesPayload {
public long timestamp;
public String profileId;
public String profileName;
public boolean isPublic;
public Map<String, ProfileTexture> textures;
}
public class ProfileTexture {
public String url;
}
/**
* Get skin URL for player
* @param player
*/
public String getSkinURL(Player player) {
String url = null;
Object profile = callMethod(player, obcplayer_getprofile, nullargs, null);
if (profile != null) {
Object propmap = callMethod(profile, cmaprofile_getproperties, nullargs, null);
if ((propmap != null) && (propmap instanceof ForwardingMultimap)) {
ForwardingMultimap<String, Object> fmm = (ForwardingMultimap<String, Object>) propmap;
Collection<Object> txt = fmm.get("textures");
Object textureProperty = Iterables.getFirst(fmm.get("textures"), null);
if (textureProperty != null) {
String val = (String) callMethod(textureProperty, cmaproperty_getvalue, nullargs, null);
if (val != null) {
TexturesPayload result = null;
try {
String json = new String(Base64Coder.decode(val), Charsets.UTF_8);
result = gson.fromJson(json, TexturesPayload.class);
} catch (JsonParseException e) {
}
if ((result != null) && (result.textures != null) && (result.textures.containsKey("SKIN"))) {
url = result.textures.get("SKIN").url;
}
}
}
}
}
return url;
}
}

View file

@ -0,0 +1,445 @@
package org.dynmap.bukkit.helper;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
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.bukkit.entity.Player;
public class BukkitVersionHelperGlowstone extends BukkitVersionHelper {
private Method rawbiome;
private Method server_getonlineplayers;
public BukkitVersionHelperGlowstone() {
try {
Class<?> c = Class.forName("net.glowstone.chunk.GlowChunkSnapshot");
rawbiome = c.getMethod("getRawBiomes", new Class[0]);
/** Server */
server_getonlineplayers = Server.class.getMethod("getOnlinePlayers", new Class[0]);
} catch (SecurityException e) {
} catch (NoSuchMethodException e) {
} catch (ClassNotFoundException e) {
}
if ((rawbiome == null) && (server_getonlineplayers == null)) {
throw new IllegalArgumentException("Error initializing dynmap - Glowstone version incompatible!");
}
}
@Override
public Object[] getBiomeBaseList() {
return new Object[0];
}
@Override
public float getBiomeBaseTemperature(Object bb) {
return 0;
}
@Override
public float getBiomeBaseHumidity(Object bb) {
return 0;
}
@Override
public String getBiomeBaseIDString(Object bb) {
return "";
}
@Override
public int getBiomeBaseID(Object bb) {
if (bb != null)
return (Integer) bb;
else
return 0;
}
@Override
public Object getUnloadQueue(World world) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isInUnloadQueue(Object unloadqueue, int x, int z) {
// TODO Auto-generated method stub
return false;
}
@Override
public Object[] getBiomeBaseFromSnapshot(ChunkSnapshot css) {
Integer b[] = new Integer[256];
byte[] rb = null;
try {
rb = (byte[]) rawbiome.invoke(css, new Object[0]);
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
if (rb != null) {
for (int i = 0; i < 256; i++) {
b[i] = Integer.valueOf(255 & (int)rb[i]);
}
}
return b;
}
@Override
public long getInhabitedTicks(Chunk c) {
// TODO Auto-generated method stub
return 0;
}
@Override
public Map<?, ?> getTileEntitiesForChunk(Chunk c) {
// TODO Auto-generated method stub
return Collections.emptyMap();
}
@Override
public int getTileEntityX(Object te) {
// TODO Auto-generated method stub
return 0;
}
@Override
public int getTileEntityY(Object te) {
// TODO Auto-generated method stub
return 0;
}
@Override
public int getTileEntityZ(Object te) {
// TODO Auto-generated method stub
return 0;
}
@Override
public Object readTileEntityNBT(Object te) {
// TODO Auto-generated method stub
return null;
}
@Override
public Object getFieldValue(Object nbt, String field) {
// TODO Auto-generated method stub
return null;
}
@Override
public void unloadChunkNoSave(World w, Chunk c, int cx, int cz) {
// TODO Auto-generated method stub
}
@Override
public String[] getBlockNames() {
// TODO Auto-generated method stub
return null;
}
private static final String[] bnames = {
"Ocean",
"Plains",
"Desert",
"Extreme Hills",
"Forest",
"Taiga",
"Swampland",
"River",
"Hell",
"Sky",
"FrozenOcean",
"FrozenRiver",
"Ice Plains",
"Ice Mountains",
"MushroomIsland",
"MushroomIslandShore",
"Beach",
"DesertHills",
"ForestHills",
"TaigaHills",
"Extreme Hills Edge",
"Jungle",
"JungleHills",
"JungleEdge",
"Deep Ocean",
"Stone Beach",
"Cold Beach",
"Birch Forest",
"Birch Forest Hills",
"Roofed Forest",
"Cold Taiga",
"Cold Taiga Hills",
"Mega Taiga",
"Mega Taiga Hills",
"Extreme Hills+",
"Savanna",
"Savanna Plateau",
"Mesa",
"Mesa Plateau F",
"Mesa Plateau",
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
"Sunflower Plains",
"Desert M",
"Extreme Hills M",
"Flower Forest",
"Taiga M",
"Swampland M",
null,
null,
null,
null,
null,
"Ice Plains Spikes",
null,
null,
null,
null,
null,
null,
null,
null,
"Jungle M",
null,
"JungleEdge M",
null,
null,
null,
"Birch Forest M",
"Birch Forest Hills M",
"Roofed Forest M",
"Cold Taiga M",
null,
"Mega Spruce Taiga",
"Mega Spruce Taiga",
"Extreme Hills+ M",
"Savanna M",
"Savanna Plateau M",
"Mesa (Bryce)",
"Mesa Plateau F M",
"Mesa Plateau M",
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null
};
@Override
public String[] getBiomeNames() {
return bnames;
}
@Override
public int[] getBlockMaterialMap() {
// TODO Auto-generated method stub
return null;
}
/**
* Get list of online players
*/
public Player[] getOnlinePlayers() {
Object players;
try {
players = server_getonlineplayers.invoke(Bukkit.getServer(), new Object[0]);
if (players instanceof Player[]) { /* Pre 1.7.10 */
return (Player[]) players;
}
else {
@SuppressWarnings("unchecked")
Collection<? extends Player> p = (Collection<? extends Player>) players;
return p.toArray(new Player[0]);
}
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
return new Player[0];
}
@Override
public double getHealth(Player p) {
return p.getHealth();
}
}

View file

@ -0,0 +1,247 @@
package org.dynmap.bukkit.helper;
/**
* 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;
import org.bukkit.permissions.PermissionDefault;
import org.dynmap.DynmapChunk;
import org.dynmap.DynmapLocation;
import org.dynmap.DynmapWorld;
import org.dynmap.utils.MapChunkCache;
import org.dynmap.utils.Polygon;
import org.dynmap.utils.TileFlags;
public class BukkitWorld extends DynmapWorld {
private World world;
private World.Environment env;
private boolean skylight;
private DynmapLocation spawnloc = new DynmapLocation();
public BukkitWorld(World w) {
this(w.getName(), w.getMaxHeight(), w.getSeaLevel(), w.getEnvironment());
setWorldLoaded(w);
new Permission("dynmap.world." + getName(), "Dynmap access for world " + getName(), PermissionDefault.OP);
}
public BukkitWorld(String name, int height, int sealevel, World.Environment env) {
super(name, height, sealevel);
world = null;
this.env = env;
skylight = (env == World.Environment.NORMAL);
new Permission("dynmap.world." + getName(), "Dynmap access for world " + getName(), PermissionDefault.OP);
// Generate non-default environment lighting table
switch (env) {
case NETHER:
{
float f = 0.1F;
for (int i = 0; i <= 15; ++i) {
float f1 = 1.0F - (float)i / 15.0F;
this.setBrightnessTableEntry(i, (1.0F - f1) / (f1 * 3.0F + 1.0F) * (1.0F - f) + f);
}
}
break;
default:
break;
}
}
/**
* Set world online
* @param w - loaded world
*/
public void setWorldLoaded(World w) {
world = w;
env = world.getEnvironment();
skylight = (env == World.Environment.NORMAL);
}
/**
* Set world unloaded
*/
@Override
public void setWorldUnloaded() {
getSpawnLocation(); /* Remember spawn location before unload */
world = null;
}
/* Test if world is nether */
@Override
public boolean isNether() {
return env == World.Environment.NETHER;
}
/* Get world spawn location */
@Override
public DynmapLocation getSpawnLocation() {
if(world != null) {
Location sloc = world.getSpawnLocation();
spawnloc.x = sloc.getBlockX();
spawnloc.y = sloc.getBlockY();
spawnloc.z = sloc.getBlockZ();
spawnloc.world = normalizeWorldName(sloc.getWorld().getName());
}
return spawnloc;
}
/* Get world time */
@Override
public long getTime() {
if(world != null) {
return world.getTime();
}
else {
return -1;
}
}
/* World is storming */
@Override
public boolean hasStorm() {
if(world != null) {
return world.hasStorm();
}
else {
return false;
}
}
/* World is thundering */
@Override
public boolean isThundering() {
if(world != null) {
return world.isThundering();
}
else {
return false;
}
}
/* World is loaded */
@Override
public boolean isLoaded() {
return (world != null);
}
/* Get light level of block */
@Override
public int getLightLevel(int x, int y, int z) {
if(world != null) {
if ((y >= 0) && (y < this.worldheight)) {
return world.getBlockAt(x, y, z).getLightLevel();
}
return 0;
}
else {
return -1;
}
}
/* Get highest Y coord of given location */
@Override
public int getHighestBlockYAt(int x, int z) {
if(world != null) {
return world.getHighestBlockYAt(x, z);
}
else {
return -1;
}
}
/* Test if sky light level is requestable */
@Override
public boolean canGetSkyLightLevel() {
return skylight && (world != null);
}
/* Return sky light level */
@Override
public int getSkyLightLevel(int x, int y, int z) {
if(world != null) {
if ((y >= 0) && (y < this.worldheight)) {
return world.getBlockAt(x, y, z).getLightFromSky();
}
else {
return 15;
}
}
else {
return -1;
}
}
/**
* Get world environment ID (lower case - normal, the_end, nether)
*/
@Override
public String getEnvironment() {
return env.name().toLowerCase();
}
/**
* Get map chunk cache for world
*/
@Override
public MapChunkCache getChunkCache(List<DynmapChunk> chunks) {
if(isLoaded()) {
return BukkitVersionHelper.helper.getChunkCache(this, chunks);
}
else {
return null;
}
}
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;
}
@Override
public Polygon getWorldBorder() {
return BukkitVersionHelper.helper.getWorldBorder(world);
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,186 @@
package org.dynmap.bukkit.helper;
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;
import org.bukkit.ChunkSnapshot;
import org.dynmap.utils.DynIntHashMap;
public class SnapshotCache {
public static SnapshotCache sscache;
public static class SnapshotRec {
public ChunkSnapshot ss;
public long inhabitedTicks;
public DynIntHashMap tileData;
};
private CacheHashMap snapcache;
private ReferenceQueue<SnapshotRec> refqueue;
private long cache_attempts;
private long cache_success;
private boolean softref;
private static class CacheRec {
Reference<SnapshotRec> ref;
boolean hasbiome;
boolean hasrawbiome;
boolean hasblockdata;
boolean hashighesty;
}
@SuppressWarnings("serial")
public class CacheHashMap extends LinkedHashMap<String, CacheRec> {
private int limit;
private IdentityHashMap<Reference<SnapshotRec>, String> reverselookup;
public CacheHashMap(int lim) {
super(16, (float)0.75, true);
limit = lim;
reverselookup = new IdentityHashMap<Reference<SnapshotRec>, String>();
}
protected boolean removeEldestEntry(Map.Entry<String, CacheRec> last) {
boolean remove = (size() >= limit);
if(remove) {
reverselookup.remove(last.getValue().ref);
}
return remove;
}
}
/**
* Create snapshot cache
*/
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;
}
/**
* Invalidate cached snapshot, if in cache
*/
public void invalidateSnapshot(String w, int x, int y, int z) {
String key = getKey(w, x>>4, z>>4);
CacheRec rec = snapcache.remove(key);
if(rec != null) {
snapcache.reverselookup.remove(rec.ref);
rec.ref.clear();
}
//processRefQueue();
}
/**
* Invalidate cached snapshot, if in cache
*/
public void invalidateSnapshot(String w, int x0, int y0, int z0, int x1, int y1, int z1) {
for(int xx = (x0>>4); xx <= (x1>>4); xx++) {
for(int zz = (z0>>4); zz <= (z1>>4); zz++) {
String key = getKey(w, xx, zz);
CacheRec rec = snapcache.remove(key);
if(rec != null) {
snapcache.reverselookup.remove(rec.ref);
rec.ref.clear();
}
}
}
//processRefQueue();
}
/**
* Look for chunk snapshot in cache
*/
public SnapshotRec getSnapshot(String w, int chunkx, int chunkz,
boolean blockdata, boolean biome, boolean biomeraw, boolean highesty) {
String key = getKey(w, chunkx, chunkz);
processRefQueue();
SnapshotRec ss = null;
CacheRec rec = snapcache.get(key);
if(rec != null) {
ss = rec.ref.get();
if(ss == null) {
snapcache.reverselookup.remove(rec.ref);
snapcache.remove(key);
}
}
if(ss != null) {
if((blockdata && (!rec.hasblockdata)) ||
(biome && (!rec.hasbiome)) ||
(biomeraw && (!rec.hasrawbiome)) ||
(highesty && (!rec.hashighesty))) {
ss = null;
}
}
cache_attempts++;
if(ss != null) cache_success++;
return ss;
}
/**
* Add chunk snapshot to cache
*/
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();
CacheRec rec = new CacheRec();
rec.hasblockdata = blockdata;
rec.hasbiome = biome;
rec.hasrawbiome = biomeraw;
rec.hashighesty = highesty;
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);
}
snapcache.reverselookup.put(rec.ref, key);
}
/**
* Process reference queue
*/
private void processRefQueue() {
Reference<? extends SnapshotRec> ref;
while((ref = refqueue.poll()) != null) {
String k = snapcache.reverselookup.remove(ref);
if(k != null) {
snapcache.remove(k);
}
}
}
/**
* Get hit rate (percent)
*/
public double getHitRate() {
if(cache_attempts > 0) {
return (100.0*cache_success)/(double)cache_attempts;
}
return 0.0;
}
/**
* Reset cache stats
*/
public void resetStats() {
cache_attempts = cache_success = 0;
}
/**
* Cleanup
*/
public void cleanup() {
if(snapcache != null) {
snapcache.clear();
snapcache.reverselookup.clear();
snapcache.reverselookup = null;
snapcache = null;
}
}
}