More cleanup and refactoring - get ready to split out core

This commit is contained in:
Mike Primm 2012-01-15 23:19:01 -06:00
parent 1f6eb62cc1
commit eb35dbe1a6
35 changed files with 352 additions and 216 deletions

View file

@ -0,0 +1,80 @@
package org.dynmap.bukkit;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.bukkit.block.Block;
import org.dynmap.Log;
/**
* Wrapper for accessing raw light levels for given block
*/
public class BlockLightLevel {
private Method gethandle;
private Method getrawlight;
private Object enum_sky;
private Object enum_block;
private boolean ready;
@SuppressWarnings({ "unchecked", "rawtypes" })
public BlockLightLevel() {
/* Get CraftChunk.getChunkSnapshot(boolean,boolean,boolean) and CraftChunk.getHandle() */
try {
Class c = Class.forName("org.bukkit.craftbukkit.CraftChunk");
gethandle = c.getDeclaredMethod("getHandle", new Class[0]);
Class enumskyblock = Class.forName("net.minecraft.server.EnumSkyBlock");
Object[] enumvals = enumskyblock.getEnumConstants();
for(int i = 0; i < enumvals.length; i++) {
String ev = enumvals[i].toString();
if(ev.equals("Sky")) {
enum_sky = enumvals[i];
}
else if(ev.equals("Block")) {
enum_block = enumvals[i];
}
}
Class cc = Class.forName("net.minecraft.server.Chunk");
getrawlight = cc.getDeclaredMethod("a", new Class[] { enumskyblock, int.class, int.class, int.class });
} catch (ClassNotFoundException cnfx) {
} catch (NoSuchMethodException nsmx) {
}
if((gethandle != null) && (enum_sky != null) && (enum_block != null) && (getrawlight != null)) {
ready = true;
}
else {
Log.warning("Block raw light level API not available");
}
}
public boolean isReady() {
return ready;
}
public int getSkyLightLevel(Block b) {
try {
Object hand = gethandle.invoke(b.getChunk());
if(hand != null) {
Integer v = (Integer)getrawlight.invoke(hand, enum_sky, b.getX() & 0xF, b.getY() & 0x7F, b.getZ() & 0xF);
return v;
}
} catch (InvocationTargetException itx) {
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
}
return -1;
}
public int getBlockLightLevel(Block b) {
try {
Object hand = gethandle.invoke(b.getChunk());
if(hand != null) {
Integer v = (Integer)getrawlight.invoke(hand, enum_block, b.getX() & 0xF, b.getY() & 0x7F, b.getZ() & 0xF);
return v;
}
} catch (InvocationTargetException itx) {
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
}
return -1;
}
}

View file

@ -9,7 +9,6 @@ import org.bukkit.World;
import org.dynmap.DynmapChunk;
import org.dynmap.DynmapLocation;
import org.dynmap.DynmapWorld;
import org.dynmap.utils.BlockLightLevel;
import org.dynmap.utils.MapChunkCache;
public class BukkitWorld extends DynmapWorld {
@ -88,7 +87,11 @@ public class BukkitWorld extends DynmapWorld {
@Override
public MapChunkCache getChunkCache(List<DynmapChunk> chunks) {
MapChunkCache c = new NewMapChunkCache();
c.setChunks(world, chunks);
c.setChunks(this, chunks);
return c;
}
public World getWorld() {
return world;
}
}

View file

@ -57,15 +57,16 @@ import org.dynmap.DynmapWebChatEvent;
import org.dynmap.DynmapWorld;
import org.dynmap.Log;
import org.dynmap.MapManager;
import org.dynmap.bukkit.permissions.BukkitPermissions;
import org.dynmap.bukkit.permissions.NijikokunPermissions;
import org.dynmap.bukkit.permissions.OpPermissions;
import org.dynmap.bukkit.permissions.PermissionProvider;
import org.dynmap.common.BiomeMap;
import org.dynmap.common.DynmapCommandSender;
import org.dynmap.common.DynmapPlayer;
import org.dynmap.common.DynmapServerInterface;
import org.dynmap.common.DynmapListenerManager.EventType;
import org.dynmap.markers.MarkerAPI;
import org.dynmap.permissions.BukkitPermissions;
import org.dynmap.permissions.NijikokunPermissions;
import org.dynmap.permissions.OpPermissions;
import org.dynmap.permissions.PermissionProvider;
public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
private DynmapCore core;
@ -217,6 +218,15 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
public void broadcastMessage(String msg) {
getServer().broadcastMessage(msg);
}
@Override
public String[] getBiomeIDs() {
BiomeMap[] b = BiomeMap.values();
String[] bname = new String[b.length];
for(int i = 0; i < bname.length; i++)
bname[i] = b[i].toString();
return bname;
}
}
/**
* Player access abstraction class

View file

@ -18,10 +18,9 @@ import org.dynmap.DynmapCore;
import org.dynmap.DynmapWorld;
import org.dynmap.Log;
import org.dynmap.MapManager;
import org.dynmap.common.BiomeMap;
import org.dynmap.utils.MapChunkCache;
import org.dynmap.utils.MapIterator;
import org.dynmap.utils.MapChunkCache.HiddenChunkStyle;
import org.dynmap.utils.MapChunkCache.VisibilityLimit;
import org.dynmap.utils.MapIterator.BlockStep;
/**
@ -41,6 +40,7 @@ public class NewMapChunkCache implements MapChunkCache {
private static final int MAX_TICKLIST = 20000;
private World w;
private DynmapWorld dw;
private Object craftworld;
private List<DynmapChunk> chunks;
private ListIterator<DynmapChunk> iterator;
@ -54,7 +54,7 @@ public class NewMapChunkCache implements MapChunkCache {
private boolean do_save = false;
private boolean isempty = true;
private ChunkSnapshot[] snaparray; /* Index = (x-x_min) + ((z-z_min)*x_dim) */
private Biome[][] snapbiomes; /* Biome cache - getBiome() is expensive */
private BiomeMap[][] snapbiomes; /* Biome cache - getBiome() is expensive */
private TreeSet<?> ourticklist;
private int chunks_read; /* Number of chunks actually loaded */
@ -66,6 +66,8 @@ public class NewMapChunkCache implements MapChunkCache {
private static final BlockStep unstep[] = { BlockStep.X_MINUS, BlockStep.Y_MINUS, BlockStep.Z_MINUS,
BlockStep.X_PLUS, BlockStep.Y_PLUS, BlockStep.Z_PLUS };
private static BiomeMap[] biome_to_bmap;
/**
* Iterator for traversing map chunk cache (base is for non-snapshot)
*/
@ -114,15 +116,17 @@ public class NewMapChunkCache implements MapChunkCache {
public final int getBlockEmittedLight() {
return snap.getBlockEmittedLight(bx, y, bz);
}
public final Biome getBiome() {
Biome[] b = snapbiomes[chunkindex];
public final BiomeMap getBiome() {
BiomeMap[] b = snapbiomes[chunkindex];
if(b == null) {
b = snapbiomes[chunkindex] = new Biome[256];
b = snapbiomes[chunkindex] = new BiomeMap[256];
}
int off = bx + (bz << 4);
Biome bio = b[off];
BiomeMap bio = b[off];
if(bio == null) {
bio = b[off] = snap.getBiome(bx, bz);
Biome bb = snap.getBiome(bx, bz);
if(bb != null)
bio = b[off] = biome_to_bmap[bb.ordinal()];
}
return bio;
}
@ -403,8 +407,9 @@ public class NewMapChunkCache implements MapChunkCache {
}
}
@SuppressWarnings({ "rawtypes" })
public void setChunks(World w, List<DynmapChunk> chunks) {
this.w = w;
public void setChunks(DynmapWorld dw, List<DynmapChunk> chunks) {
this.dw = dw;
this.w = ((BukkitWorld)dw).getWorld();
if((getworldhandle != null) && (craftworld == null)) {
try {
craftworld = getworldhandle.invoke(w); /* World.getHandle() */
@ -439,7 +444,7 @@ public class NewMapChunkCache implements MapChunkCache {
}
snaparray = new ChunkSnapshot[x_dim * (z_max-z_min+1)];
snapbiomes = new Biome[x_dim * (z_max-z_min+1)][];
snapbiomes = new BiomeMap[x_dim * (z_max-z_min+1)][];
}
public int loadChunks(int max_to_load) {
@ -634,9 +639,10 @@ public class NewMapChunkCache implements MapChunkCache {
ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
return ss.getBlockEmittedLight(x & 0xF, y, z & 0xF);
}
public Biome getBiome(int x, int z) {
public BiomeMap getBiome(int x, int z) {
ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
return ss.getBiome(x & 0xF, z & 0xF);
Biome b = ss.getBiome(x & 0xF, z & 0xF);
return (b != null)?biome_to_bmap[b.ordinal()]:null;
}
public double getRawBiomeTemperature(int x, int z) {
ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
@ -727,8 +733,8 @@ public class NewMapChunkCache implements MapChunkCache {
return true;
}
@Override
public World getWorld() {
return w;
public DynmapWorld getWorld() {
return dw;
}
@Override
public int getChunksLoaded() {
@ -767,4 +773,31 @@ public class NewMapChunkCache implements MapChunkCache {
}
return isok;
}
static {
Biome[] b = Biome.values();
biome_to_bmap = new BiomeMap[b.length];
biome_to_bmap[Biome.RAINFOREST.ordinal()] = BiomeMap.RAINFOREST;
biome_to_bmap[Biome.SWAMPLAND.ordinal()] = BiomeMap.SWAMPLAND;
biome_to_bmap[Biome.SEASONAL_FOREST.ordinal()] = BiomeMap.SEASONAL_FOREST;
biome_to_bmap[Biome.FOREST.ordinal()] = BiomeMap.FOREST;
biome_to_bmap[Biome.SAVANNA.ordinal()] = BiomeMap.SAVANNA;
biome_to_bmap[Biome.SHRUBLAND.ordinal()] = BiomeMap.SHRUBLAND;
biome_to_bmap[Biome.TAIGA.ordinal()] = BiomeMap.TAIGA;
biome_to_bmap[Biome.DESERT.ordinal()] = BiomeMap.DESERT;
biome_to_bmap[Biome.PLAINS.ordinal()] = BiomeMap.PLAINS;
biome_to_bmap[Biome.ICE_DESERT.ordinal()] = BiomeMap.ICE_DESERT;
biome_to_bmap[Biome.TUNDRA.ordinal()] = BiomeMap.TUNDRA;
biome_to_bmap[Biome.HELL.ordinal()] = BiomeMap.HELL;
biome_to_bmap[Biome.SKY.ordinal()] = BiomeMap.SKY;
biome_to_bmap[Biome.OCEAN.ordinal()] = BiomeMap.OCEAN;
biome_to_bmap[Biome.RIVER.ordinal()] = BiomeMap.RIVER;
biome_to_bmap[Biome.EXTREME_HILLS.ordinal()] = BiomeMap.EXTREME_HILLS;
biome_to_bmap[Biome.FROZEN_OCEAN.ordinal()] = BiomeMap.FROZEN_OCEAN;
biome_to_bmap[Biome.FROZEN_RIVER.ordinal()] = BiomeMap.FROZEN_RIVER;
biome_to_bmap[Biome.ICE_PLAINS.ordinal()] = BiomeMap.ICE_PLAINS;
biome_to_bmap[Biome.ICE_MOUNTAINS.ordinal()] = BiomeMap.ICE_MOUNTAINS;
biome_to_bmap[Biome.MUSHROOM_ISLAND.ordinal()] = BiomeMap.MUSHROOM_ISLAND;
biome_to_bmap[Biome.MUSHROOM_SHORE.ordinal()] = BiomeMap.MUSHROOM_SHORE;
}
}

View file

@ -0,0 +1,169 @@
package org.dynmap.bukkit;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.bukkit.ChunkSnapshot;
public class SnapshotCache {
private CacheHashMap snapcache;
private ReferenceQueue<ChunkSnapshot> refqueue;
private long cache_attempts;
private long cache_success;
private static class CacheRec {
WeakReference<ChunkSnapshot> ref;
boolean hasbiome;
boolean hasrawbiome;
boolean hasblockdata;
boolean hashighesty;
}
public class CacheHashMap extends LinkedHashMap<String, CacheRec> {
private int limit;
private IdentityHashMap<WeakReference<ChunkSnapshot>, String> reverselookup;
public CacheHashMap(int lim) {
super(16, (float)0.75, true);
limit = lim;
reverselookup = new IdentityHashMap<WeakReference<ChunkSnapshot>, 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) {
snapcache = new CacheHashMap(max_size);
refqueue = new ReferenceQueue<ChunkSnapshot>();
}
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 ChunkSnapshot getSnapshot(String w, int chunkx, int chunkz,
boolean blockdata, boolean biome, boolean biomeraw, boolean highesty) {
String key = getKey(w, chunkx, chunkz);
processRefQueue();
ChunkSnapshot ss = null;
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, ChunkSnapshot 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;
rec.ref = new WeakReference<ChunkSnapshot>(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 ChunkSnapshot> 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;
}
}
}

View file

@ -0,0 +1,31 @@
package org.dynmap.bukkit.permissions;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.dynmap.Log;
public class BukkitPermissions implements PermissionProvider {
String name;
public static BukkitPermissions create(String name) {
try {
Class.forName("org.bukkit.permissions.PermissibleBase"); /* See if class exists */
} catch (ClassNotFoundException cnfx) {
return null;
}
Log.info("Using Bukkit Permissions (superperms) for access control");
return new BukkitPermissions(name);
}
public BukkitPermissions(String name) {
this.name = name;
}
@Override
public boolean has(CommandSender sender, String permission) {
Player player = sender instanceof Player ? (Player) sender : null;
return player != null
? player.hasPermission(name + "." + permission) || player.hasPermission(name + ".*")
: true;
}
}

View file

@ -0,0 +1,41 @@
package org.dynmap.bukkit.permissions;
import org.bukkit.Server;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.dynmap.Log;
import com.nijiko.permissions.PermissionHandler;
import com.nijikokun.bukkit.Permissions.Permissions;
public class NijikokunPermissions implements PermissionProvider {
String name;
PermissionHandler permissions;
Plugin plugin;
public static NijikokunPermissions create(Server server, String name) {
Plugin permissionsPlugin = server.getPluginManager().getPlugin("Permissions");
if (permissionsPlugin == null)
return null;
server.getPluginManager().enablePlugin(permissionsPlugin);
Log.info("Using Permissions " + permissionsPlugin.getDescription().getVersion() + " for access control");
return new NijikokunPermissions(permissionsPlugin, name);
}
public NijikokunPermissions(Plugin permissionsPlugin, String name) {
this.name = name;
plugin = permissionsPlugin;
}
@Override
public boolean has(CommandSender sender, String permission) {
if(permissions == null)
permissions = ((Permissions)plugin).getHandler();
Player player = sender instanceof Player ? (Player) sender : null;
return player != null
? permissions.has(player, name + "." + permission) || permissions.has(player, name + ".*")
: true;
}
}

View file

@ -0,0 +1,27 @@
package org.dynmap.bukkit.permissions;
import java.util.HashSet;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.dynmap.Log;
public class OpPermissions implements PermissionProvider {
public HashSet<String> opCommands = new HashSet<String>();
public OpPermissions(String[] opCommands) {
for (String opCommand : opCommands) {
this.opCommands.add(opCommand);
}
Log.info("Using ops.txt for access control");
}
@Override
public boolean has(CommandSender sender, String permission) {
return (sender instanceof Player)
? opCommands.contains(permission)
? ((Player) sender).isOp()
: true
: true;
}
}

View file

@ -0,0 +1,7 @@
package org.dynmap.bukkit.permissions;
import org.bukkit.command.CommandSender;
public interface PermissionProvider {
boolean has(CommandSender sender, String permission);
}