diff --git a/src/main/java/org/dynmap/ClientUpdateComponent.java b/src/main/java/org/dynmap/ClientUpdateComponent.java index b96d0e9c..6cb702f9 100644 --- a/src/main/java/org/dynmap/ClientUpdateComponent.java +++ b/src/main/java/org/dynmap/ClientUpdateComponent.java @@ -11,10 +11,13 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Player; +import org.dynmap.utils.BlockLightLevel; import org.json.simple.JSONArray; import org.json.simple.JSONObject; public class ClientUpdateComponent extends Component { + private BlockLightLevel bll = new BlockLightLevel(); + public ClientUpdateComponent(final DynmapPlugin plugin, ConfigurationNode configuration) { super(plugin, configuration); plugin.events.addListener("buildclientupdate", new Event.Listener() { @@ -53,9 +56,14 @@ public class ClientUpdateComponent extends Component { hide = true; } if(hideifunder < 15) { - /*TODO: when pull accepted for getSkyLightLevel(), switch to that */ - if(pl.getWorld().getHighestBlockYAt(pl) > pl.getBlockY()) - hide = true; + if(bll.isReady()) { /* If we can get real sky level */ + if(bll.getSkyLightLevel(pl.getBlock()) <= hideifunder) + hide = true; + } + else { + if(pl.getWorld().getHighestBlockYAt(pl) > pl.getBlockY()) + hide = true; + } } /* Don't leak player location for world not visible on maps, or if sendposition disbaled */ diff --git a/src/main/java/org/dynmap/utils/BlockLightLevel.java b/src/main/java/org/dynmap/utils/BlockLightLevel.java new file mode 100644 index 00000000..4054147f --- /dev/null +++ b/src/main/java/org/dynmap/utils/BlockLightLevel.java @@ -0,0 +1,80 @@ +package org.dynmap.utils; + +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; + } +}