Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
281 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
56 changes: 56 additions & 0 deletions
56
src/main/java/net/aufdemrand/denizen/scripts/commands/world/LightCommand.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package net.aufdemrand.denizen.scripts.commands.world; | ||
|
||
import net.aufdemrand.denizen.objects.dLocation; | ||
import net.aufdemrand.denizen.utilities.blocks.BlockLight; | ||
import net.aufdemrand.denizen.utilities.debugging.dB; | ||
import net.aufdemrand.denizencore.exceptions.CommandExecutionException; | ||
import net.aufdemrand.denizencore.exceptions.InvalidArgumentsException; | ||
import net.aufdemrand.denizencore.objects.Element; | ||
import net.aufdemrand.denizencore.objects.aH; | ||
import net.aufdemrand.denizencore.scripts.ScriptEntry; | ||
import net.aufdemrand.denizencore.scripts.commands.AbstractCommand; | ||
|
||
public class LightCommand extends AbstractCommand { | ||
|
||
@Override | ||
public void parseArgs(ScriptEntry scriptEntry) throws InvalidArgumentsException { | ||
|
||
for (aH.Argument arg : aH.interpret(scriptEntry.getArguments())) { | ||
|
||
if (!scriptEntry.hasObject("location") | ||
&& arg.matchesArgumentType(dLocation.class)) | ||
scriptEntry.addObject("location", arg.asType(dLocation.class)); | ||
|
||
else if (!scriptEntry.hasObject("light") | ||
&& arg.matchesPrimitive(aH.PrimitiveType.Integer)) | ||
scriptEntry.addObject("light", arg.asElement()); | ||
|
||
else if (!scriptEntry.hasObject("reset") | ||
&& arg.matches("reset")) | ||
scriptEntry.addObject("reset", new Element(true)); | ||
|
||
} | ||
|
||
if (!scriptEntry.hasObject("location") || | ||
(!scriptEntry.hasObject("light") && !scriptEntry.hasObject("reset"))) { | ||
throw new InvalidArgumentsException("Must specify a valid location and light level."); | ||
} | ||
|
||
scriptEntry.defaultObject("reset", new Element(false)); | ||
} | ||
|
||
@Override | ||
public void execute(ScriptEntry scriptEntry) throws CommandExecutionException { | ||
|
||
dLocation location = scriptEntry.getdObject("location"); | ||
Element light = scriptEntry.getElement("light"); | ||
Element reset = scriptEntry.getElement("reset"); | ||
|
||
dB.report(scriptEntry, getName(), location.debug() + (light != null ? light.debug() : "") + reset.debug()); | ||
|
||
if (!reset.asBoolean()) | ||
BlockLight.createLight(location, light.asInt()); | ||
else | ||
BlockLight.removeLight(location); | ||
} | ||
} |
199 changes: 199 additions & 0 deletions
199
src/main/java/net/aufdemrand/denizen/utilities/blocks/BlockLight.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
package net.aufdemrand.denizen.utilities.blocks; | ||
|
||
import net.aufdemrand.denizen.utilities.debugging.dB; | ||
import net.minecraft.server.v1_8_R1.*; | ||
import org.bukkit.Bukkit; | ||
import org.bukkit.Location; | ||
import org.bukkit.Material; | ||
import org.bukkit.World; | ||
import org.bukkit.block.Block; | ||
import org.bukkit.block.BlockFace; | ||
import org.bukkit.craftbukkit.v1_8_R1.CraftChunk; | ||
import org.bukkit.craftbukkit.v1_8_R1.CraftWorld; | ||
|
||
import java.lang.reflect.Field; | ||
import java.lang.reflect.Method; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
public class BlockLight { | ||
|
||
private static final Method playerChunkMethod; | ||
private static final Field dirtyCountField; | ||
private static final Map<Location, BlockLight> lightsByLocation = new HashMap<Location, BlockLight>(); | ||
private static final BlockFace[] adjacentFaces = new BlockFace[] { | ||
BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST, BlockFace.UP, BlockFace.DOWN | ||
}; | ||
|
||
static { | ||
Method pcm = null; | ||
Field dcf = null; | ||
try { | ||
pcm = PlayerChunkMap.class.getDeclaredMethod("a", int.class, int.class, boolean.class); | ||
pcm.setAccessible(true); | ||
dcf = pcm.getReturnType().getDeclaredField("dirtyCount"); | ||
dcf.setAccessible(true); | ||
} catch (Exception e) { | ||
dB.echoError(e); | ||
} | ||
playerChunkMethod = pcm; | ||
dirtyCountField = dcf; | ||
for (World worlds : Bukkit.getServer().getWorlds()) { | ||
WorldServer nmsWorld = ((CraftWorld) worlds).getHandle(); | ||
IWorldAccess access = getIWorldAccess(worlds); | ||
|
||
nmsWorld.addIWorldAccess(access); | ||
} | ||
} | ||
|
||
private final CraftWorld craftWorld; | ||
private final WorldServer worldServer; | ||
private final CraftChunk craftChunk; | ||
private final Block block; | ||
private final BlockPosition position; | ||
private final int originalLight; | ||
private int currentLight; | ||
|
||
private BlockLight(Location location) { | ||
this.craftWorld = (CraftWorld) location.getWorld(); | ||
this.worldServer = craftWorld.getHandle(); | ||
this.craftChunk = (CraftChunk) location.getChunk(); | ||
this.block = location.getBlock(); | ||
this.position = new BlockPosition(block.getX(), block.getY(), block.getZ()); | ||
this.originalLight = block.getLightLevel(); | ||
this.currentLight = originalLight; | ||
lightsByLocation.put(location, this); | ||
} | ||
|
||
public static BlockLight createLight(Location location, int lightLevel) { | ||
location = location.getBlock().getLocation(); | ||
BlockLight blockLight; | ||
if (lightsByLocation.containsKey(location)) | ||
removeLight(location); | ||
blockLight = new BlockLight(location); | ||
blockLight.update(lightLevel); | ||
return blockLight; | ||
} | ||
|
||
public static void removeLight(Location location) { | ||
location = location.getBlock().getLocation(); | ||
if (lightsByLocation.containsKey(location)) { | ||
lightsByLocation.get(location).reset(); | ||
lightsByLocation.remove(location); | ||
} | ||
} | ||
|
||
private void reset() { | ||
this.update(originalLight); | ||
} | ||
|
||
private void update(int lightLevel) { | ||
if (this.currentLight == lightLevel) { | ||
return; | ||
} | ||
else if (this.originalLight == lightLevel) { | ||
worldServer.c(EnumSkyBlock.BLOCK, position); | ||
} | ||
else { | ||
worldServer.a(EnumSkyBlock.BLOCK, position, lightLevel); | ||
Block adjacentAir = null; | ||
for (BlockFace face : adjacentFaces) { | ||
if (position.getY() == 0 && face == BlockFace.DOWN) | ||
continue; | ||
if (position.getY() == (craftWorld.getMaxHeight() - 1) && face == BlockFace.UP) | ||
continue; | ||
Block possible = block.getRelative(face); | ||
if (possible.getType() == Material.AIR) { | ||
adjacentAir = possible; | ||
break; | ||
} | ||
} | ||
if (adjacentAir != null) { | ||
worldServer.x(new BlockPosition(adjacentAir.getX(), adjacentAir.getY(), adjacentAir.getZ())); | ||
} | ||
} | ||
int cX = craftChunk.getX(); | ||
int cZ = craftChunk.getZ(); | ||
for (int x = -1; x <= 1; x++) { | ||
for (int z = -1; z <= 1; z++) { | ||
BlockLight.setDirtyCount(getPlayerChunk(worldServer.getPlayerChunkMap(), cX + x, cZ + z)); | ||
} | ||
} | ||
this.currentLight = lightLevel; | ||
} | ||
|
||
private static Object getPlayerChunk(PlayerChunkMap map, int x, int z) { | ||
try { | ||
return playerChunkMethod.invoke(map, x, z, false); | ||
} catch (Exception e) { | ||
dB.echoError(e); | ||
} | ||
return null; | ||
} | ||
|
||
private static void setDirtyCount(Object playerChunk) { | ||
try { | ||
int dirtyCount = dirtyCountField.getInt(playerChunk); | ||
if (dirtyCount > 0 && dirtyCount < 64) { | ||
dirtyCountField.set(playerChunk, 64); | ||
} | ||
} catch (Exception e) { | ||
dB.echoError(e); | ||
} | ||
} | ||
|
||
private static IWorldAccess getIWorldAccess(World world) { | ||
final PlayerChunkMap map = ((CraftWorld) world).getHandle().getPlayerChunkMap(); | ||
return new IWorldAccess() { | ||
@Override | ||
public void a(BlockPosition position) { | ||
map.flagDirty(position); | ||
} | ||
|
||
@Override | ||
public void b(BlockPosition position) { | ||
map.flagDirty(position); | ||
} | ||
|
||
@Override | ||
public void b(int arg0, BlockPosition arg1, int arg2) { | ||
} | ||
|
||
@Override | ||
public void a(EntityHuman arg0, int arg1, BlockPosition arg2, int arg3) { | ||
} | ||
|
||
@Override | ||
public void a(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { | ||
} | ||
|
||
@Override | ||
public void a(int arg0, BlockPosition arg1, int arg2) { | ||
} | ||
|
||
@Override | ||
public void a(String arg0, double arg1, double arg2, double arg3, float arg4, float arg5) { | ||
} | ||
|
||
@Override | ||
public void a(EntityHuman arg0, String arg1, double arg2, double arg3, double arg4, float arg5, float arg6) { | ||
} | ||
|
||
@Override | ||
public void a(int arg0, boolean arg1, double arg2, double arg3, double arg4, double arg5, double arg6, double arg7, int... arg8) { | ||
} | ||
|
||
@Override | ||
public void a(String arg0, BlockPosition arg1) { | ||
} | ||
|
||
@Override | ||
public void a(Entity arg0) { | ||
} | ||
|
||
@Override | ||
public void b(Entity arg0) { | ||
} | ||
}; | ||
} | ||
} |