diff --git a/MobArena.jar b/MobArena.jar index f2dc2fb..94fd344 100644 Binary files a/MobArena.jar and b/MobArena.jar differ diff --git a/src/com/garbagemule/MobArena/Arena.java b/src/com/garbagemule/MobArena/Arena.java index 4338e58..ba29169 100644 --- a/src/com/garbagemule/MobArena/Arena.java +++ b/src/com/garbagemule/MobArena/Arena.java @@ -7,6 +7,7 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; @@ -25,6 +26,8 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.block.ContainerBlock; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.entity.Creature; @@ -40,6 +43,9 @@ import org.bukkit.inventory.PlayerInventory; import org.bukkit.util.config.Configuration; import com.garbagemule.MobArena.MAMessages.Msg; +import com.garbagemule.MobArena.repairable.Repairable; +import com.garbagemule.MobArena.repairable.RepairableComparator; +import com.garbagemule.MobArena.repairable.RepairableContainer; import com.garbagemule.MobArena.util.WaveUtils; import com.garbagemule.MobArena.waves.BossWave; import com.garbagemule.MobArena.waves.Wave; @@ -74,8 +80,6 @@ public class Arena // Player sets protected Set arenaPlayers, lobbyPlayers, readyPlayers, specPlayers; // Wave stuff - //protected TreeSet singleWaves; - //protected TreeSet recurrentWaves; protected TreeSet singleWaves, singleWavesInstance; protected TreeSet recurrentWaves; protected BossWave bossWave; @@ -84,12 +88,13 @@ public class Arena // NEW IMPLEMENTATION // Arena sets/maps - protected Set hasPaid, rewardedPlayers, notifyPlayers, randoms; - protected Set monsters, explodingSheep, plaguedPigs, madCows; - protected Set blocks; - protected Set pets; - protected Map petMap; - protected List repairList; + protected Set hasPaid, rewardedPlayers, notifyPlayers, randoms; + protected Set monsters, explodingSheep, plaguedPigs, madCows; + protected Set blocks; + protected Set pets; + protected Map petMap; + //protected List repairList; + protected LinkedList repairables; // Spawn overriding protected int spawnMonsters; @@ -134,7 +139,8 @@ public class Arena petMap = new HashMap(); classMap = new HashMap(); randoms = new HashSet(); - repairList = new LinkedList(); + //repairList = new LinkedList(); + repairables = new LinkedList(); running = false; edit = false; @@ -153,6 +159,8 @@ public class Arena return false; if (!softRestore && forceRestore && !serializeRegion()) return false; + + saveContainerContents(); // Populate arenaPlayers and clear the lobby. arenaPlayers.addAll(lobbyPlayers); @@ -223,9 +231,13 @@ public class Arena cleanup(); // Restore region. + /* if (softRestore) for (int[] buffer : repairList) world.getBlockAt(buffer[0], buffer[1], buffer[2]).setTypeIdAndData(buffer[3], (byte) buffer[4], false); + */ + if (softRestore) + restoreRegion(); else if (forceRestore) deserializeRegion(); @@ -502,6 +514,29 @@ public class Arena healthMap.put(p, p.getHealth()); } + public void saveContainerContents() + { + Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, + new Runnable() + { + public void run() + { + long start = System.nanoTime(); + LinkedList list = new LinkedList(); + for (int x = p1.getBlockX(); x <= p2.getBlockX(); x++) + for (int y = p1.getBlockY(); y <= p2.getBlockY(); y++) + for (int z = p1.getBlockZ(); z <= p2.getBlockZ(); z++) + { + BlockState bs = world.getBlockAt(x,y,z).getState(); + if (bs instanceof ContainerBlock) + list.add(new RepairableContainer(bs)); + } + list.clear(); + System.out.println("Iteration took: " + (System.nanoTime() - start) + " ns"); + } + }); + } + public void movePlayerToLobby(Player p) { updateChunk(lobbyLoc); @@ -776,6 +811,14 @@ public class Arena lobbySetup = MAUtils.verifyLobby(this); } + public void restoreRegion() + { + Collections.sort(repairables, new RepairableComparator()); + + for (Repairable r : repairables) + r.repair(); + } + public void serializeConfig() { String coords = "arenas." + configName() + ".coords."; diff --git a/src/com/garbagemule/MobArena/Arenaz.java b/src/com/garbagemule/MobArena/Arenaz.java index 31ef9f6..ac63e9f 100644 --- a/src/com/garbagemule/MobArena/Arenaz.java +++ b/src/com/garbagemule/MobArena/Arenaz.java @@ -1,6 +1,5 @@ package com.garbagemule.MobArena; -import org.bukkit.Location; import org.bukkit.entity.Player; public interface Arenaz diff --git a/src/com/garbagemule/MobArena/MAListener.java b/src/com/garbagemule/MobArena/MAListener.java index 0dca14f..c2a44d2 100644 --- a/src/com/garbagemule/MobArena/MAListener.java +++ b/src/com/garbagemule/MobArena/MAListener.java @@ -1,12 +1,15 @@ package com.garbagemule.MobArena; -import java.util.HashMap; -import java.util.Map; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.block.ContainerBlock; import org.bukkit.block.Sign; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; @@ -19,7 +22,6 @@ import org.bukkit.event.block.BlockIgniteEvent; import org.bukkit.event.block.BlockIgniteEvent.IgniteCause; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.entity.CreatureSpawnEvent; -import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.event.entity.EntityCombustEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent; @@ -39,8 +41,14 @@ import org.bukkit.event.player.PlayerKickEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.inventory.ItemStack; +import org.bukkit.material.Attachable; import com.garbagemule.MobArena.MAMessages.Msg; +import com.garbagemule.MobArena.repairable.Repairable; +import com.garbagemule.MobArena.repairable.RepairableBlock; +import com.garbagemule.MobArena.repairable.RepairableComparator; +import com.garbagemule.MobArena.repairable.RepairableContainer; +import com.garbagemule.MobArena.repairable.RepairableSign; public class MAListener implements ArenaListener { @@ -58,26 +66,38 @@ public class MAListener implements ArenaListener if (!arena.inRegion(event.getBlock().getLocation()) || arena.edit || (!arena.protect && arena.running)) return; + BlockState statez = event.getBlock().getState(); + + if (statez.getData() instanceof Attachable) + { + System.out.println(statez.getData()); + event.setCancelled(true); + } + Block b = event.getBlock(); if (arena.blocks.remove(b) || b.getType() == Material.TNT) return; if (arena.softRestore && arena.running) { - int[] buffer = new int[5]; - buffer[0] = b.getX(); - buffer[1] = b.getY(); - buffer[2] = b.getZ(); - buffer[3] = b.getTypeId(); - buffer[4] = (int) b.getData(); - arena.repairList.add(buffer); - if (!arena.softRestoreDrops) event.getBlock().setTypeId(0); + BlockState state = b.getState(); + + if (state instanceof ContainerBlock) + arena.repairables.add(new RepairableContainer(state)); + else if (state instanceof Sign) + arena.repairables.add(new RepairableSign(state)); + else + arena.repairables.add(new RepairableBlock(state)); + + if (!arena.softRestoreDrops) + b.setTypeId(0); + return; } event.setCancelled(true); } - + public void onBlockPlace(BlockPlaceEvent event) { if (!arena.inRegion(event.getBlock().getLocation()) || arena.edit) @@ -109,13 +129,13 @@ public class MAListener implements ArenaListener public void onCreatureSpawn(CreatureSpawnEvent event) { - if (!arena.inRegion(event.getLocation()) || event.getSpawnReason() == SpawnReason.CUSTOM) + if (!arena.inRegion(event.getLocation())) // || event.getSpawnReason() == SpawnReason.CUSTOM) return; // If running == true, setCancelled(false), and vice versa. event.setCancelled(!arena.running); } - + public void onEntityExplode(EntityExplodeEvent event) { if (!arena.monsters.contains(event.getEntity()) && !arena.inRegionRadius(event.getLocation(), 10)) @@ -124,6 +144,71 @@ public class MAListener implements ArenaListener event.setYield(0); arena.monsters.remove(event.getEntity()); + // Cancel if the arena isn't running or if the repair delay is 0 + if (!arena.running || arena.repairDelay == 0) + { + event.setCancelled(true); + return; + } + + // Uncancel, just in case. + event.setCancelled(false); + + // Initialize the repair list. + final List toRepair = new LinkedList(); + + // Handle all the blocks in the block list. + for (Block b : event.blockList()) + { + BlockState state = b.getState(); + + // Create a Repairable from the block. + Repairable r = null; + if (state instanceof ContainerBlock) + r = new RepairableContainer(state); + else if (state instanceof Sign) + r = new RepairableSign(state); + else + r = new RepairableBlock(state); + + Material mat = state.getType(); + if (mat == Material.WOODEN_DOOR || mat == Material.IRON_DOOR_BLOCK || mat == Material.FIRE || mat == Material.CAKE_BLOCK || mat == Material.WATER || mat == Material.LAVA) + arena.blocks.remove(b); + else if (arena.blocks.remove(b)) + arena.world.dropItemNaturally(b.getLocation(), new ItemStack(state.getTypeId(), 1)); + else if (arena.softRestore) + arena.repairables.add(r); + else + toRepair.add(r); + } + + // If the arena isn't protected, or soft-restore is on, return. + if (!arena.protect || arena.softRestore) + return; + + // Otherwise, schedule repairs! + Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, + new Runnable() + { + public void run() + { + Collections.sort(toRepair, new RepairableComparator()); + + for (Repairable r : toRepair) + r.repair(); + } + }, arena.repairDelay); + } + + /* + public void onEntityExplodez(EntityExplodeEvent event) + { + if (!arena.monsters.contains(event.getEntity()) && !arena.inRegionRadius(event.getLocation(), 10)) + return; + + event.setYield(0); + arena.monsters.remove(event.getEntity()); + // If the arena isn't running if (!arena.running || arena.repairDelay == 0) { @@ -143,7 +228,7 @@ public class MAListener implements ArenaListener // Uncancel, just in case. event.setCancelled(false); - + int[] buffer; final HashMap blockMap = new HashMap(); for (Block b : event.blockList()) @@ -186,6 +271,7 @@ public class MAListener implements ArenaListener { public void run() { + long start = System.nanoTime(); for (Map.Entry entry : blockMap.entrySet()) { Block b = entry.getKey(); @@ -196,9 +282,11 @@ public class MAListener implements ArenaListener if (type > 1000) b.getLocation().getBlock().setData((byte) (type / 1000)); } + System.out.println("Repair took: " + (System.nanoTime() - start) + " ns"); } }, arena.repairDelay); } + */ public void onEntityDeath(EntityDeathEvent event) { @@ -394,20 +482,38 @@ public class MAListener implements ArenaListener public void onPlayerDropItem(PlayerDropItemEvent event) { - if (arena.running && arena.shareInArena) return; - Player p = event.getPlayer(); - if (p.getLocation().equals(arena.spectatorLoc)) + + // Player is in the lobby + if (arena.lobbyPlayers.contains(p)) { - event.getItemDrop().setItemStack(new ItemStack(1, 0)); + MAUtils.tellPlayer(p, Msg.LOBBY_DROP_ITEM); event.setCancelled(true); } - if (!arena.arenaPlayers.contains(p) && !arena.lobbyPlayers.contains(p)) - return; + // Player is in the arena + else if (arena.arenaPlayers.contains(p)) + { + if (!arena.shareInArena) + { + MAUtils.tellPlayer(p, Msg.LOBBY_DROP_ITEM); + event.setCancelled(true); + } + } - MAUtils.tellPlayer(p, Msg.LOBBY_DROP_ITEM); - event.setCancelled(true); + // Player died/left + else if (p.getLocation().equals(arena.spectatorLoc) || p.getLocation().equals(arena.locations.get(p))) + { + MobArena.warning("Player '" + p.getName() + "' tried to steal item " + event.getItemDrop().getItemStack().getType()); + event.getItemDrop().remove(); + } + + // Player is in the spectator area + else if (arena.specPlayers.contains(p)) + { + MAUtils.tellPlayer(p, Msg.LOBBY_DROP_ITEM); + event.setCancelled(true); + } } public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) diff --git a/src/com/garbagemule/MobArena/MAUtils.java b/src/com/garbagemule/MobArena/MAUtils.java index 02fc528..1927013 100644 --- a/src/com/garbagemule/MobArena/MAUtils.java +++ b/src/com/garbagemule/MobArena/MAUtils.java @@ -476,7 +476,8 @@ public class MAUtils // If these are rewards, don't tamper with them. if (rewards) { - inv.addItem(stack); + //inv.addItem(stack); + giveItem(inv, stack); continue; } @@ -491,19 +492,36 @@ public class MAUtils if (WEAPONS_TYPE.contains(stack.getType())) stack.setDurability((short) -32768); - inv.addItem(stack); + giveItem(inv, stack); + //inv.addItem(stack); } } - public static void giveRewards(Player p, List stacks, MobArena plugin) - { - giveItems(p, stacks, false, true, plugin); - } public static void giveItems(Player p, List stacks, boolean autoEquip, MobArena plugin) { giveItems(p, stacks, autoEquip, false, plugin); } + public static void giveItem(PlayerInventory inv, ItemStack stack) + { + int id = stack.getTypeId(); + int amount = stack.getAmount(); + + int times = amount / 64; + int remainder = amount % 64; + + for (int i = 0; i < times; i++) + inv.addItem(new ItemStack(id, 64)); + + if (remainder > 0) + inv.addItem(new ItemStack(id, remainder)); + } + + public static void giveRewards(Player p, List stacks, MobArena plugin) + { + giveItems(p, stacks, false, true, plugin); + } + public static int getPetAmount(Player p) { int result = 0; diff --git a/src/com/garbagemule/MobArena/MobArena.java b/src/com/garbagemule/MobArena/MobArena.java index 7eaa922..f68b7b1 100644 --- a/src/com/garbagemule/MobArena/MobArena.java +++ b/src/com/garbagemule/MobArena/MobArena.java @@ -1,6 +1,7 @@ package com.garbagemule.MobArena; import java.io.File; +import java.util.List; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -40,6 +41,7 @@ public class MobArena extends JavaPlugin // Global variables public static PluginDescriptionFile desc; public static File dir, arenaDir; + public static List permissionOps; public static final double MIN_PLAYER_DISTANCE = 256.0; public static final int ECONOMY_MONEY_ID = -29; @@ -60,7 +62,6 @@ public class MobArena extends JavaPlugin FileUtils.fetchLibs(config); // Set up permissions and economy - //setupSuperPerms(); setupPermissions(); setupRegister(); @@ -85,7 +86,6 @@ public class MobArena extends JavaPlugin am.arenaMap.clear(); // Permissions & Economy - //permissionHandler = null; if (Methods != null && Methods.hasMethod()) { Methods = null; @@ -136,14 +136,13 @@ public class MobArena extends JavaPlugin pm.registerEvent(Event.Type.ENTITY_COMBUST, entityListener, Priority.Normal, this); pm.registerEvent(Event.Type.ENTITY_TARGET, entityListener, Priority.Normal, this); pm.registerEvent(Event.Type.CREATURE_SPAWN, entityListener, Priority.Highest, this); - pm.registerEvent(Event.Type.PLAYER_COMMAND_PREPROCESS, playerListener, Priority.Monitor, this); + pm.registerEvent(Event.Type.PLAYER_COMMAND_PREPROCESS, playerListener, Priority.Monitor, this); // I know Monitor is bad, but other plugins suck! :( } // Permissions stuff public boolean has(Player p, String s) { - //return (permissionHandler == null || permissionHandler.has(p, s)); - return hasSuperPerms(p, s) || hasNijikoPerms(p, s); + return hasSuperPerms(p, s) || hasNijikoPerms(p, s) || hasOpPerms(p, s); } public boolean hasSuperPerms(Player p, String s) @@ -156,19 +155,16 @@ public class MobArena extends JavaPlugin return permissionHandler != null && permissionHandler.has(p, s); } + public boolean hasOpPerms (Player p, String node) + { + return permissionOps == null || permissionOps.contains(node) == false || p.isOp(); + } + // Console printing public static void info(String msg) { Bukkit.getServer().getLogger().info("[MobArena] " + msg); } public static void warning(String msg) { Bukkit.getServer().getLogger().warning("[MobArena] " + msg); } public static void error(String msg) { Bukkit.getServer().getLogger().severe("[MobArena] " + msg); } - /* - private void setupSuperPerms() - { - getServer().getPluginManager().addPermission(new Permission("mobarena.classes")); - getServer().getPluginManager().addPermission(new Permission("mobarena.arenas")); - } - */ - private void setupPermissions() { if (permissionHandler != null) diff --git a/src/com/garbagemule/MobArena/repairable/Repairable.java b/src/com/garbagemule/MobArena/repairable/Repairable.java new file mode 100644 index 0000000..3af3be1 --- /dev/null +++ b/src/com/garbagemule/MobArena/repairable/Repairable.java @@ -0,0 +1,21 @@ +package com.garbagemule.MobArena.repairable; + +//import java.io.Serializable; + +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.BlockState; + +public interface Repairable// extends Serializable +{ + public void repair(); + + public BlockState getState(); + public World getWorld(); + public Material getType(); + public int getId(); + public byte getData(); + public int getX(); + public int getY(); + public int getZ(); +} diff --git a/src/com/garbagemule/MobArena/repairable/RepairableBlock.java b/src/com/garbagemule/MobArena/repairable/RepairableBlock.java new file mode 100644 index 0000000..c7ef73b --- /dev/null +++ b/src/com/garbagemule/MobArena/repairable/RepairableBlock.java @@ -0,0 +1,112 @@ +package com.garbagemule.MobArena.repairable; + +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.BlockState; + +public class RepairableBlock implements Repairable +{ + private BlockState state; + private World world; + private int id, x, y, z; + private Material type; + private byte data; + + public RepairableBlock(BlockState state) + { + this.state = state; + + world = state.getWorld(); + + x = state.getX(); + y = state.getY(); + z = state.getZ(); + + id = state.getTypeId(); + type = state.getType(); + data = state.getRawData(); + } + + /** + * Repairs the block by setting the type and data + */ + public void repair() + { + getWorld().getBlockAt(x,y,z).setTypeIdAndData(id, data, false); + } + + public BlockState getState() + { + return state; + } + + public World getWorld() + { + return world; + } + + public void setWorld(World world) + { + this.world = world; + } + + public Material getType() + { + return type; + } + + public void setType(Material type) + { + this.type = type; + } + + public int getId() + { + return id; + } + + public void setId(int id) + { + this.id = id; + } + + public byte getData() + { + return data; + } + + public void setData(byte data) + { + this.data = data; + } + + public int getX() + { + return x; + } + + public void setX(int x) + { + this.x = x; + } + + public int getY() + { + return y; + } + + public void setY(int y) + { + this.y = y; + } + + public int getZ() + { + return z; + } + + public void setZ(int z) + { + this.z = z; + } +} diff --git a/src/com/garbagemule/MobArena/repairable/RepairableComparator.java b/src/com/garbagemule/MobArena/repairable/RepairableComparator.java new file mode 100644 index 0000000..0a1ed94 --- /dev/null +++ b/src/com/garbagemule/MobArena/repairable/RepairableComparator.java @@ -0,0 +1,31 @@ +package com.garbagemule.MobArena.repairable; + +import java.util.Comparator; + +import org.bukkit.material.Attachable; +import org.bukkit.material.Door; +import org.bukkit.material.MaterialData; +import org.bukkit.material.Redstone; + +public class RepairableComparator implements Comparator +{ + public int compare(Repairable r1, Repairable r2) + { + if (restoreLast(r1)) + { + if (restoreLast(r2)) + return 0; + return 1; + } + else if (restoreLast(r2)) + return -1; + + return 0; + } + + private boolean restoreLast(Repairable r) + { + MaterialData m = r.getState().getData(); + return (m instanceof Attachable || m instanceof Redstone || m instanceof Door); + } +} diff --git a/src/com/garbagemule/MobArena/repairable/RepairableContainer.java b/src/com/garbagemule/MobArena/repairable/RepairableContainer.java new file mode 100644 index 0000000..74b0c8a --- /dev/null +++ b/src/com/garbagemule/MobArena/repairable/RepairableContainer.java @@ -0,0 +1,31 @@ +package com.garbagemule.MobArena.repairable; + +import org.bukkit.block.BlockState; +import org.bukkit.block.ContainerBlock; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +public class RepairableContainer extends RepairableBlock +{ + private ItemStack[] contents; + + public RepairableContainer(BlockState state) + { + super(state); + + Inventory inv = ((ContainerBlock) state).getInventory(); + contents = inv.getContents(); + inv.clear(); + } + + /** + * Repairs the container block by adding all the contents back in. + */ + public void repair() + { + super.repair(); + + ContainerBlock cb = (ContainerBlock) getWorld().getBlockAt(getX(),getY(),getZ()).getState(); + cb.getInventory().setContents(contents); + } +} diff --git a/src/com/garbagemule/MobArena/repairable/RepairableSign.java b/src/com/garbagemule/MobArena/repairable/RepairableSign.java new file mode 100644 index 0000000..7081500 --- /dev/null +++ b/src/com/garbagemule/MobArena/repairable/RepairableSign.java @@ -0,0 +1,32 @@ +package com.garbagemule.MobArena.repairable; + +import org.bukkit.block.BlockState; +import org.bukkit.block.Sign; + +public class RepairableSign extends RepairableBlock +{ + private String[] lines = new String[4]; + + public RepairableSign(BlockState state) + { + super(state); + + Sign s = (Sign) state; + lines = s.getLines(); + } + + /** + * Repairs the sign block by restoring all the lines + */ + public void repair() + { + super.repair(); + + Sign s = (Sign) getWorld().getBlockAt(getX(),getY(),getZ()).getState(); + s.setLine(0, lines[0]); + s.setLine(1, lines[1]); + s.setLine(2, lines[2]); + s.setLine(3, lines[3]); + } + +} diff --git a/src/com/garbagemule/MobArena/waves/Wave.java b/src/com/garbagemule/MobArena/waves/Wave.java index 22d54d6..d009570 100644 --- a/src/com/garbagemule/MobArena/waves/Wave.java +++ b/src/com/garbagemule/MobArena/waves/Wave.java @@ -123,7 +123,7 @@ public interface Wave { public void run(final Arena arena, LivingEntity boss) { - System.out.println("Intimidate target"); + System.out.println("Root target"); final LivingEntity target = getTarget(boss); if (target == null) return;