diff --git a/war/src/main/java/bukkit/tommytony/war/War.java b/war/src/main/java/bukkit/tommytony/war/War.java index 62ac0bb..ba5868e 100644 --- a/war/src/main/java/bukkit/tommytony/war/War.java +++ b/war/src/main/java/bukkit/tommytony/war/War.java @@ -63,6 +63,7 @@ public class War extends JavaPlugin { private boolean pvpInZonesOnly = false; private boolean disablePvpMessage = false; private boolean buildInZonesOnly = false; + private boolean tntInZonesOnly = false; private final List deadlyAdjectives = new ArrayList(); private final List killerVerbs = new ArrayList(); @@ -458,6 +459,11 @@ public class War extends JavaPlugin { this.setBuildInZonesOnly(onOff.equals("on") || onOff.equals("true")); returnMessage.append(" buildinzonesonly set to " + String.valueOf(war.isBuildInZonesOnly()) + "."); } + if (namedParams.containsKey("tntinzonesonly")) { + String onOff = namedParams.get("tntinzonesonly"); + this.setTntInZonesOnly(onOff.equals("on") || onOff.equals("true")); + returnMessage.append(" tntinzonesonly set to " + String.valueOf(war.isTntInZonesOnly()) + "."); + } if (namedParams.containsKey("lifepool")) { this.setDefaultLifepool(Integer.parseInt(namedParams.get("lifepool"))); @@ -643,6 +649,7 @@ public class War extends JavaPlugin { + " pvpinzonesonly:" + String.valueOf(this.isPvpInZonesOnly()) + " disablepvpmessage:" + String.valueOf(this.isDisablePvpMessage()) + " buildinzonesonly:" + String.valueOf(this.isBuildInZonesOnly()) + + " tntinzonesonly:" + String.valueOf(this.isTntInZonesOnly()) + " - Warzone defaults -" + " lifepool:" + this.getDefaultLifepool() + " teamsize:" + this.getDefaultTeamCap() @@ -1174,4 +1181,12 @@ public class War extends JavaPlugin { public List getKillerVerbs() { return killerVerbs; } + + public boolean isTntInZonesOnly() { + return tntInZonesOnly; + } + + public void setTntInZonesOnly(boolean tntInZonesOnly) { + this.tntInZonesOnly = tntInZonesOnly; + } } diff --git a/war/src/main/java/bukkit/tommytony/war/WarEntityListener.java b/war/src/main/java/bukkit/tommytony/war/WarEntityListener.java index a1c9c76..d2ab725 100644 --- a/war/src/main/java/bukkit/tommytony/war/WarEntityListener.java +++ b/war/src/main/java/bukkit/tommytony/war/WarEntityListener.java @@ -1,5 +1,6 @@ package bukkit.tommytony.war; +import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.logging.Level; @@ -8,12 +9,17 @@ import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; +import org.bukkit.block.ContainerBlock; +import org.bukkit.block.NoteBlock; +import org.bukkit.block.Sign; +import org.bukkit.craftbukkit.entity.CraftCreeper; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.craftbukkit.entity.CraftTNTPrimed; import org.bukkit.entity.Arrow; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; +import org.bukkit.entity.TNTPrimed; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.EntityCombustEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent; @@ -22,9 +28,12 @@ import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.entity.EntityListener; import org.bukkit.event.entity.EntityRegainHealthEvent; import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason; +import org.bukkit.inventory.ItemStack; import com.tommytony.war.Team; import com.tommytony.war.Warzone; +import com.tommytony.war.jobs.DeferredBlockResetsJob; +import com.tommytony.war.utils.DeferredBlockReset; /** * Handles Entity-Events @@ -34,7 +43,7 @@ import com.tommytony.war.Warzone; */ public class WarEntityListener extends EntityListener { - private Random killSeed = new Random(); + private final Random killSeed = new Random(); /** * Handles PVP-Damage @@ -157,11 +166,8 @@ public class WarEntityListener extends EntityListener { if (d != null && defenderWarzone != null && event.getDamage() >= d.getHealth()) { String deathMessage = ""; String defenderString = Team.getTeamByPlayerName(d.getName()).getKind().getColor() + d.getDisplayName(); - /* if (event.getDamager() instanceof Projectile && ((Projectile)event.getDamager()).getShooter() instanceof Player){ - Player shooter = ((Player)((Projectile)event.getDamager()).getShooter()); - Team shooterTeam = Team.getTeamByPlayerName(shooter.getName()); - deathMessage = shooterTeam.getKind().getColor() + shooter.getDisplayName() + ChatColor.WHITE + "'s deadly aim killed " + defenderString; - } else */ if (event.getDamager() instanceof CraftTNTPrimed) { + + if (event.getDamager() instanceof CraftTNTPrimed) { deathMessage = defenderString + ChatColor.WHITE + " exploded"; } else { deathMessage = defenderString + ChatColor.WHITE + " died"; @@ -187,25 +193,101 @@ public class WarEntityListener extends EntityListener { } // protect zones elements, lobbies and warhub from creepers List explodedBlocks = event.blockList(); + List dontExplode = new ArrayList(); + + boolean explosionInAWarzone = Warzone.getZoneByLocation(event.getEntity().getLocation()) != null; + + if (!explosionInAWarzone && War.war.isTntInZonesOnly() && event.getEntity() instanceof TNTPrimed) { + // if tntinzonesonly:true, no tnt blows up outside zones + event.setCancelled(true); + return; + } + for (Block block : explodedBlocks) { if (War.war.getWarHub() != null && War.war.getWarHub().getVolume().contains(block)) { - event.setCancelled(true); - War.war.log("Explosion prevented at warhub.", Level.INFO); - return; - } - - for (Warzone zone : War.war.getWarzones()) { - if (zone.isImportantBlock(block)) { - event.setCancelled(true); - War.war.log("Explosion prevented in zone " + zone.getName() + ".", Level.INFO); - return; - } else if (zone.getLobby() != null && zone.getLobby().getVolume().contains(block)) { - event.setCancelled(true); - War.war.log("Explosion prevented at zone " + zone.getName() + " lobby.", Level.INFO); - return; + dontExplode.add(block); + } else { + boolean inOneZone = false; + for (Warzone zone : War.war.getWarzones()) { + if (zone.isImportantBlock(block)) { + dontExplode.add(block); + inOneZone = true; + break; + } else if (zone.getLobby() != null && zone.getLobby().getVolume().contains(block)) { + dontExplode.add(block); + inOneZone = true; + break; + } else if (zone.getVolume().contains(block)) { + inOneZone = true; + } + } + + if (!inOneZone && explosionInAWarzone) { + // if the explosion originated in warzone, always rollback + dontExplode.add(block); } } } + + int dontExplodeSize = dontExplode.size(); + if (dontExplode.size() > 0) { + // Reset the exploded blocks that shouldn't have exploded (some of these are zone artifacts, if rollbackexplosion some may be outside-of-zone blocks + DeferredBlockResetsJob job = new DeferredBlockResetsJob(dontExplode.get(0).getWorld()); + List doors = new ArrayList(); + for (Block dont : dontExplode) { + DeferredBlockReset deferred = null; + if (dont.getState() instanceof Sign) { + String[] lines = ((Sign)dont.getState()).getLines(); + deferred = new DeferredBlockReset(dont.getX(), dont.getY(), dont.getZ(), dont.getTypeId(), dont.getData(), lines); + } else if (dont.getState() instanceof ContainerBlock) { + ItemStack[] contents = ((ContainerBlock)dont.getState()).getInventory().getContents(); + Block worldBlock = dont.getWorld().getBlockAt(dont.getLocation()); + if (worldBlock.getState() instanceof ContainerBlock) { + ((ContainerBlock)worldBlock.getState()).getInventory().clear(); + } + deferred = new DeferredBlockReset(dont.getX(), dont.getY(), dont.getZ(), dont.getTypeId(), dont.getData(), copyItems(contents)); + } else if (dont.getTypeId() == Material.NOTE_BLOCK.getId()) { + Block worldBlock = dont.getWorld().getBlockAt(dont.getLocation()); + if (worldBlock.getState() instanceof NoteBlock) { + NoteBlock noteBlock = ((NoteBlock)worldBlock.getState()); + if (noteBlock != null) { + deferred = new DeferredBlockReset(dont.getX(), dont.getY(), dont.getZ(), dont.getTypeId(), dont.getData(), noteBlock.getRawNote()); + } + } + } else if (dont.getTypeId() != Material.TNT.getId()) { + deferred = new DeferredBlockReset(dont.getX(), dont.getY(), dont.getZ(), dont.getTypeId(), dont.getData()); + if (dont.getTypeId() == Material.WOODEN_DOOR.getId() || dont.getTypeId() == Material.IRON_DOOR_BLOCK.getId()) { + doors.add(dont); + } + } + if (deferred != null) { + job.add(deferred); + } + } + War.war.getServer().getScheduler().scheduleSyncDelayedTask(War.war, job); + + // Changed explosion yeild following proportion of explosion prevention (makes drops less buggy too) + int explodedSize = explodedBlocks.size(); + float middleYeild = (float)(explodedSize - dontExplodeSize) / (float)explodedSize; + float newYeild = middleYeild * event.getYield(); + + float old = event.getYield(); + event.setYield(newYeild); + } + } + + private List copyItems(ItemStack[] contents) { + List list = new ArrayList(); + for (ItemStack stack : contents) { + if (stack != null) { + if (stack.getData() != null) { + list.add(new ItemStack(stack.getType(), stack.getAmount(), stack.getDurability(), stack.getData().getData())); + } else { + list.add(new ItemStack(stack.getType(), stack.getAmount(), stack.getDurability())); + } + } + } + return list; } /** diff --git a/war/src/main/java/bukkit/tommytony/war/command/ResetZoneCommand.java b/war/src/main/java/bukkit/tommytony/war/command/ResetZoneCommand.java index f8e505d..7f2a167 100644 --- a/war/src/main/java/bukkit/tommytony/war/command/ResetZoneCommand.java +++ b/war/src/main/java/bukkit/tommytony/war/command/ResetZoneCommand.java @@ -45,7 +45,7 @@ public class ResetZoneCommand extends AbstractZoneMakerCommand { for (Player p : team.getPlayers()) { zone.restorePlayerState(p); p.teleport(zone.getTeleport()); - War.war.msg(p, "You have left the warzone. Your inventory has been restored."); + War.war.msg(p, "You have left the warzone. Your inventory is being restored."); } team.resetPoints(); team.getPlayers().clear(); diff --git a/war/src/main/java/com/tommytony/war/Warzone.java b/war/src/main/java/com/tommytony/war/Warzone.java index 8febc88..59fab80 100644 --- a/war/src/main/java/com/tommytony/war/Warzone.java +++ b/war/src/main/java/com/tommytony/war/Warzone.java @@ -903,7 +903,7 @@ public class Warzone { player.setFireTicks(0); player.setRemainingAir(300); - War.war.msg(player, "Left the zone. Your inventory has been restored."); + War.war.msg(player, "Left the zone. Your inventory is being restored."); if (War.war.getWarHub() != null) { War.war.getWarHub().resetZoneSign(this); } diff --git a/war/src/main/java/com/tommytony/war/jobs/DeferredBlockResetsJob.java b/war/src/main/java/com/tommytony/war/jobs/DeferredBlockResetsJob.java index f90f207..b0c0e51 100644 --- a/war/src/main/java/com/tommytony/war/jobs/DeferredBlockResetsJob.java +++ b/war/src/main/java/com/tommytony/war/jobs/DeferredBlockResetsJob.java @@ -2,14 +2,30 @@ package com.tommytony.war.jobs; import java.util.ArrayList; import java.util.List; +import java.util.logging.Level; +import org.bukkit.Chunk; +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.block.BlockState; +import org.bukkit.block.Chest; +import org.bukkit.block.ContainerBlock; +import org.bukkit.block.Dispenser; +import org.bukkit.block.Furnace; +import org.bukkit.block.NoteBlock; import org.bukkit.block.Sign; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Item; +import org.bukkit.inventory.ItemStack; +import bukkit.tommytony.war.War; + +import com.tommytony.war.mappers.ZoneVolumeMapper; import com.tommytony.war.utils.DeferredBlockReset; +import com.tommytony.war.volumes.Volume; public class DeferredBlockResetsJob implements Runnable { @@ -30,37 +46,130 @@ public class DeferredBlockResetsJob implements Runnable { } public void run() { + ArrayList doors = new ArrayList(); + for (DeferredBlockReset reset : this.deferred) { - Block worldBlock = this.world.getBlockAt(reset.getX(), reset.getY(), reset.getZ()); - worldBlock.setType(Material.getMaterial(reset.getBlockType())); - - if (reset.getBlockType() == Material.SIGN_POST.getId()) { - BlockState state = worldBlock.getState(); - state.setData(new org.bukkit.material.Sign(reset.getBlockType(), reset.getBlockData())); - if (state instanceof Sign) { - Sign sign = (Sign) state; - // String[] lines = this.getSignLines().get("sign-" + i + "-" + j + "-" + k); - if (reset.getLines() != null && sign.getLines() != null) { - if (reset.getLines().length > 0) { - sign.setLine(0, reset.getLines()[0]); + if (this.world != null && reset != null) { + Block worldBlock = this.world.getBlockAt(reset.getX(), reset.getY(), reset.getZ()); + worldBlock.setType(Material.getMaterial(reset.getBlockType())); + + if (reset.getBlockType() == Material.WALL_SIGN.getId() || reset.getBlockType() == Material.SIGN_POST.getId()) { + BlockState state = worldBlock.getState(); + state.setData(new org.bukkit.material.Sign(reset.getBlockType(), reset.getBlockData())); + if (state instanceof Sign) { + Sign sign = (Sign) state; + if (reset.getLines() != null && sign.getLines() != null) { + if (reset.getLines().length > 0) { + sign.setLine(0, reset.getLines()[0]); + } + if (reset.getLines().length > 1) { + sign.setLine(1, reset.getLines()[1]); + } + if (reset.getLines().length > 2) { + sign.setLine(2, reset.getLines()[2]); + } + if (reset.getLines().length > 3) { + sign.setLine(3, reset.getLines()[3]); + } + sign.update(true); } - if (reset.getLines().length > 1) { - sign.setLine(1, reset.getLines()[1]); + } + } else if (reset.getBlockType() == Material.CHEST.getId() + || reset.getBlockType() == Material.DISPENSER.getId() + || reset.getBlockType() == Material.FURNACE.getId() + || reset.getBlockType() == Material.BURNING_FURNACE.getId()) { + List items = reset.getItems(); + + worldBlock.setType(Material.getMaterial(reset.getBlockType())); + worldBlock.setData(reset.getBlockData()); + BlockState state = worldBlock.getState(); + if (state instanceof ContainerBlock) { + ContainerBlock container = (ContainerBlock) state; + if (items != null) { + int ii = 0; + container.getInventory().clear(); + for (ItemStack item : items) { + if (item != null) { + container.getInventory().setItem(ii, item); + ii++; + } + } + state.update(true); + items.clear(); } - if (reset.getLines().length > 2) { - sign.setLine(2, reset.getLines()[2]); - } - if (reset.getLines().length > 3) { - sign.setLine(3, reset.getLines()[3]); - } - sign.update(true); + } else { + // normal reset + worldBlock.setData(reset.getBlockData()); + } + } else if (reset.getBlockType() == Material.NOTE_BLOCK.getId()) { + worldBlock.setType(Material.getMaterial(reset.getBlockType())); + worldBlock.setData(reset.getBlockData()); + BlockState state = worldBlock.getState(); + if (state instanceof NoteBlock && reset.getRawNote() != null) { + NoteBlock noteBlock = (NoteBlock) state; + noteBlock.setRawNote(reset.getRawNote()); + noteBlock.update(true); + } else { + // normal reset + worldBlock.setData(reset.getBlockData()); + } + } else if (reset.getBlockType() == Material.WOODEN_DOOR.getId() || reset.getBlockType() == Material.IRON_DOOR_BLOCK.getId()) { + // Door blocks + doors.add(reset); + } else { + // normal data reset + worldBlock.setData(reset.getBlockData()); + } + } + } + + // Take care of doors last + for (DeferredBlockReset doorBlock : doors) { + Block worldBlock = world.getBlockAt(doorBlock.getX(), doorBlock.getY(), doorBlock.getZ()); + if (worldBlock.getTypeId() != doorBlock.getBlockType() || worldBlock.getData() != doorBlock.getBlockData()) { + // find its friend + for (DeferredBlockReset other : doors) { + if (other.getX() == doorBlock.getX() + && other.getY() == doorBlock.getY() - 1 + && other.getZ() == doorBlock.getZ()) { + // doorBlock is above + Block above = worldBlock; + Block below = world.getBlockAt(other.getX(), other.getY(), other.getZ()); + above.setTypeId(doorBlock.getBlockType()); + above.setData(doorBlock.getBlockData()); + below.setTypeId(other.getBlockType()); + below.setData(other.getBlockData()); + scrubDroppedDoors(below); + break; + } else if (other.getX() == doorBlock.getX() + && other.getY() == doorBlock.getY() + 1 + && other.getZ() == doorBlock.getZ()) { + // doorBlock is below + Block above = world.getBlockAt(other.getX(), other.getY(), other.getZ()); + Block below = worldBlock; + above.setTypeId(doorBlock.getBlockType()); + above.setData(doorBlock.getBlockData()); + below.setTypeId(other.getBlockType()); + below.setData(other.getBlockData()); + scrubDroppedDoors(below); + break; } } - } else { - // normal data reset - worldBlock.setData(reset.getBlockData()); } + } + } + private void scrubDroppedDoors(Block block) { + Chunk chunk = block.getWorld().getChunkAt(block); + Volume scrubVolume = new Volume("scrub", block.getWorld()); + scrubVolume.setCornerOne(block.getRelative(BlockFace.DOWN).getRelative(BlockFace.EAST).getRelative(BlockFace.NORTH)); + scrubVolume.setCornerTwo(block.getRelative(BlockFace.UP).getRelative(BlockFace.WEST).getRelative(BlockFace.SOUTH)); + for (Entity entity : chunk.getEntities()) { + if ((entity instanceof Item && (((Item)entity).getItemStack().getTypeId() == Material.IRON_DOOR.getId() + || ((Item)entity).getItemStack().getTypeId() == Material.WOOD_DOOR.getId())) + && scrubVolume.contains(entity.getLocation())) { + entity.remove(); + } } } diff --git a/war/src/main/java/com/tommytony/war/mappers/WarMapper.java b/war/src/main/java/com/tommytony/war/mappers/WarMapper.java index 8cb2f25..e094f50 100644 --- a/war/src/main/java/com/tommytony/war/mappers/WarMapper.java +++ b/war/src/main/java/com/tommytony/war/mappers/WarMapper.java @@ -164,6 +164,11 @@ public class WarMapper { if (warConfig.keyExists("disablePvpMessage")) { War.war.setDisablePvpMessage(warConfig.getBoolean("disablePvpMessage")); } + + // tntInZonesOnly + if (warConfig.keyExists("tntInZonesOnly")) { + War.war.setTntInZonesOnly(warConfig.getBoolean("tntInZonesOnly")); + } // defaultSpawnStyle String spawnStyle = warConfig.getString("defaultspawnStyle"); @@ -338,6 +343,9 @@ public class WarMapper { // disablePVPMessage warConfig.setBoolean("disablePvpMessage", War.war.isDisablePvpMessage()); + // tntInZonesOnly + warConfig.setBoolean("tntInZonesOnly", War.war.isTntInZonesOnly()); + // spawnStyle warConfig.setString("spawnStyle", War.war.getDefaultSpawnStyle().toString()); diff --git a/war/src/main/java/com/tommytony/war/mappers/ZoneVolumeMapper.java b/war/src/main/java/com/tommytony/war/mappers/ZoneVolumeMapper.java index f0e1731..5039c87 100644 --- a/war/src/main/java/com/tommytony/war/mappers/ZoneVolumeMapper.java +++ b/war/src/main/java/com/tommytony/war/mappers/ZoneVolumeMapper.java @@ -128,7 +128,7 @@ public class ZoneVolumeMapper { String[] lines = linesStr.split(";;"); // Signs set - if (diskBlockType == Material.SIGN_POST.getId() && ((diskBlockData & 0x04) == 0x04) && i + 1 != volume.getSizeX()) { + if (diskBlockType == Material.WALL_SIGN.getId() && ((diskBlockData & 0x04) == 0x04) && i + 1 != volume.getSizeX()) { // A sign post hanging on a wall south of here needs that block to be set first deferred.add(new DeferredBlockReset(x, y, z, diskBlockType, diskBlockData, lines)); } else { diff --git a/war/src/main/java/com/tommytony/war/utils/DeferredBlockReset.java b/war/src/main/java/com/tommytony/war/utils/DeferredBlockReset.java index 8abb9ef..398a78c 100644 --- a/war/src/main/java/com/tommytony/war/utils/DeferredBlockReset.java +++ b/war/src/main/java/com/tommytony/war/utils/DeferredBlockReset.java @@ -1,5 +1,9 @@ package com.tommytony.war.utils; +import java.util.List; + +import org.bukkit.inventory.ItemStack; + public class DeferredBlockReset { private final int x; @@ -8,6 +12,8 @@ public class DeferredBlockReset { private final int blockType; private final byte blockData; private String[] lines; + private List items; + private Byte rawNote; public DeferredBlockReset(int x, int y, int z, int blockType, byte blockData) { this.x = x; @@ -26,6 +32,26 @@ public class DeferredBlockReset { this.blockData = blockData; this.lines = signLines; } + + // Container block + public DeferredBlockReset(int x, int y, int z, int blockType, byte blockData, List contents) { + this.x = x; + this.y = y; + this.z = z; + this.blockType = blockType; + this.blockData = blockData; + this.items = contents; + } + + // Noteblock + public DeferredBlockReset(int x, int y, int z, int blockType, byte blockData, byte rawNote) { + this.x = x; + this.y = y; + this.z = z; + this.blockType = blockType; + this.blockData = blockData; + this.rawNote = rawNote; + } public int getX() { return this.x; @@ -50,4 +76,12 @@ public class DeferredBlockReset { public String[] getLines() { return this.lines; } + + public List getItems() { + return items; + } + + public Byte getRawNote() { + return rawNote; + } }