diff --git a/MobArena.jar b/MobArena.jar index 6a73e4b..7254bd6 100644 Binary files a/MobArena.jar and b/MobArena.jar differ diff --git a/bin/plugin.yml b/bin/plugin.yml index 0996566..8d7f2c1 100644 --- a/bin/plugin.yml +++ b/bin/plugin.yml @@ -1,6 +1,6 @@ name: MobArena main: com.garbagemule.MobArena.MobArena -version: 0.91.2 +version: 0.92 softdepend: [MultiVerse] commands: ma: @@ -8,22 +8,19 @@ commands: usage: | /ma join - Join the arena. /ma leave - Leave the arena. - /ma list - List of players in the arena. /ma notready - List of players who aren't ready. - /ma spectator - Warp to the spectator area. + /ma spectate - Warp to the spectator area. marena: description: Base command for MobArena usage: | /marena join - Join the arena. /marena leave - Leave the arena. - /marena list - List of players in the arena. /marena notready - List of players who aren't ready. - /marena spectator - Warp to the spectator area. + /marena spectate - Warp to the spectator area. mobarena: description: Base command for MobArena usage: | /mobarena join - Join the arena. /mobarena leave - Leave the arena. - /mobarena list - List of players in the arena. /mobarena notready - List of players who aren't ready. - /mobarena spectator - Warp to the spectator area. \ No newline at end of file + /mobarena spectate - Warp to the spectator area. \ No newline at end of file diff --git a/src/com/garbagemule/MobArena/Arena.java b/src/com/garbagemule/MobArena/Arena.java new file mode 100644 index 0000000..e604e62 --- /dev/null +++ b/src/com/garbagemule/MobArena/Arena.java @@ -0,0 +1,1193 @@ +package com.garbagemule.MobArena; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +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.Sign; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.entity.CreatureType; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Item; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Slime; +import org.bukkit.entity.Wolf; +import org.bukkit.event.Event.Result; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.entity.EntityCombustEvent; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.event.entity.EntityRegainHealthEvent; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason; +import org.bukkit.event.entity.EntityTargetEvent; +import org.bukkit.event.entity.EntityTargetEvent.TargetReason; +import org.bukkit.event.player.PlayerBucketEmptyEvent; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.player.PlayerDropItemEvent; +import org.bukkit.event.player.PlayerInteractEvent; +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.util.config.Configuration; + +import com.garbagemule.MobArena.MAMessages.Msg; + +public class Arena +{ + private MobArena plugin; + + // Setup fields + protected String name; + protected World world; + protected boolean enabled, running, setup, protect, autoEquip, forceRestore, softRestore, softRestoreDrops, emptyInvJoin, emptyInvSpec, pvp, monsterInfight, allowWarp; + protected boolean edit, waveClear, detCreepers, detDamage, lightning, hellhounds; + protected Location p1, p2, arenaLoc, lobbyLoc, spectatorLoc; + protected Map spawnpoints; + + // Wave/reward fields + protected int spawnTaskId, waveDelay, waveInterval, specialModulo, spawnMonstersInt, maxIdleTime; + protected MASpawnThread spawnThread; + protected Map> everyWaveMap, afterWaveMap; + protected Map distDefault, distSpecial; + protected Map classMap; + protected Map> classItems, classArmor; + protected Map> rewardMap; + + // Arena sets/maps + protected Set livePlayers, deadPlayers, readyPlayers, specPlayers; + protected Set monsters; + protected Set blocks; + protected Set pets; + protected Map petMap; + protected Map kills; + protected List repairList; + + // Spawn overriding + protected int spawnMonsters; + protected boolean allowMonsters, allowAnimals; + + // Global settings + protected int repairDelay; + protected List classes = new LinkedList(); + protected Map locations = new HashMap(); + + /** + * Primary constructor. Requires a name and a world. + */ + public Arena(String name, World world) + { + this.name = name; + this.world = world; + plugin = (MobArena) Bukkit.getServer().getPluginManager().getPlugin("MobArena"); + + livePlayers = new HashSet(); + deadPlayers = new HashSet(); + readyPlayers = new HashSet(); + specPlayers = new HashSet(); + monsters = new HashSet(); + blocks = new HashSet(); + pets = new HashSet(); + petMap = new HashMap(); + classMap = new HashMap(); + rewardMap = new HashMap>(); + kills = new HashMap(); + repairList = new LinkedList(); + + running = false; + edit = false; + + allowMonsters = world.getAllowMonsters(); + allowAnimals = world.getAllowAnimals(); + spawnMonsters = ((net.minecraft.server.World) ((CraftWorld) world).getHandle()).spawnMonsters; + } + + public Arena(String name, World world, ArenaMaster am) + { + this(name, world); + //classItems = am.classItems; + //classArmor = am.classArmor; + } + + public void startArena() + { + if (running) + return; + + if (!softRestore && forceRestore && !serializeRegion()) + return; + + // Set the spawn flags to enable monster spawning. + //MAUtils.setSpawnFlags(plugin, world, 1, true, true); + MAUtils.setSpawnFlags(plugin, world, 1, allowMonsters, allowAnimals); + + // Teleport players. + for (Player p : livePlayers) + { + p.teleport(arenaLoc); + p.setHealth(20); + rewardMap.put(p, new LinkedList()); + } + + running = true; + + // Spawn pets. + for (Map.Entry entry : petMap.entrySet()) + { + Player p = entry.getKey(); + for (int i = 0; i < entry.getValue(); i++) + { + Wolf wolf = (Wolf) world.spawnCreature(p.getLocation(), CreatureType.WOLF); + wolf.setTamed(true); + wolf.setOwner(p); + wolf.setHealth(20); + if (hellhounds) + wolf.setFireTicks(32768); + pets.add(wolf); + } + } + + // Start the spawnThread. + spawnThread = new MASpawnThread(plugin, this); + spawnTaskId = Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, spawnThread, waveDelay, waveInterval); + + readyPlayers.clear(); + MAUtils.tellAll(this, MAMessages.get(Msg.ARENA_START)); + + // Notify listeners. + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onArenaStart(); + } + + /** + * End this arena's session. + */ + public void endArena() + { + running = false; + + // If the arena was actually ever started, cancel the spawnthread. + if (spawnThread != null) + { + Bukkit.getServer().getScheduler().cancelTask(spawnThread.taskId); + Bukkit.getServer().getScheduler().cancelTask(spawnTaskId); + } + + if (!emptyInvJoin) + for (Player p : deadPlayers) + MAUtils.restoreInventory(p); + + // Clean up the arena floor and give rewards + cleanup(); + giveRewards(); + + // Clear all the sets and maps. + livePlayers.clear(); + deadPlayers.clear(); + pets.clear(); + classMap.clear(); + rewardMap.clear(); + + if (softRestore) + for (int[] buffer : repairList) + world.getBlockAt(buffer[0], buffer[1], buffer[2]).setTypeIdAndData(buffer[3], (byte) buffer[4], false); + else if (forceRestore) + deserializeRegion(); + + // Set the spawn flags to restore monster spawning. + MAUtils.setSpawnFlags(plugin, world, spawnMonsters, allowMonsters, allowAnimals); + MAUtils.tellAll(this, MAMessages.get(Msg.ARENA_END)); + + // Notify listeners. + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onArenaEnd(); + } + + /** + * Force an arena start by forcing all not-ready players to leave. + * @precondition - The arena musn't be running, and readyPlayers must not be empty. + */ + public void forceStart() + { + // Set operations. + Set tmp = new HashSet(); + tmp.addAll(livePlayers); + tmp.removeAll(readyPlayers); + + // Force leave. + for (Player p : tmp) + playerLeave(p); + } + + /** + * Force an arena end by forcing all players to leave. + * @precondition - livePlayers must not be empty. + */ + public void forceEnd() + { + // Force leave. + for (Player p : getAllPlayers()) + playerLeave(p); + } + + /** + * Warp the player to the arena lobby and add to the set of live players. + */ + public void playerJoin(Player p, Location loc) + { + if (!locations.containsKey(p)) + locations.put(p,loc); + + MAUtils.sitPets(p); + livePlayers.add(p); + p.teleport(lobbyLoc); + + // Notify listeners. + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onPlayerJoin(p); + } + + /** + * Add the player to the set of ready players. + * If every is ready, the arena starts. + */ + public void playerReady(Player p) + { + readyPlayers.add(p); + + if (readyPlayers.equals(livePlayers)) + startArena(); + } + + /** + * Remove the player from all the player sets, and clear his inventory if necessary. + * If the set of live players becomes empty, end the arena. + * If the set of ready players becomes equal to the set of live players, start the arena. + */ + public void playerLeave(Player p) + { + boolean clear = false; + + p.teleport(locations.get(p)); + locations.remove(p); // get, then remove, because of Teleport Event + + // Only clear the inventory if the player has class items. + if (readyPlayers.remove(p)) clear = true; + if (livePlayers.remove(p)) clear = true; + if (deadPlayers.remove(p)) clear = false; + if (specPlayers.remove(p)) clear = false; + removePets(p); + + if (clear) MAUtils.clearInventory(p); + if (!emptyInvJoin) MAUtils.restoreInventory(p); + + if (running && livePlayers.isEmpty()) + endArena(); + else if (!readyPlayers.isEmpty() && readyPlayers.equals(livePlayers)) + startArena(); + + // Notify listeners. + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onPlayerLeave(p); + } + + public void playerQuit(Player p) + { + p.teleport(locations.get(p)); + readyPlayers.remove(p); + livePlayers.remove(p); + deadPlayers.remove(p); + specPlayers.remove(p); + removePets(p); + + if (running && livePlayers.isEmpty()) + endArena(); + else if (!readyPlayers.isEmpty() && readyPlayers.equals(livePlayers)) + startArena(); + } + + public void playerDeath(final Player p) + { + p.teleport(spectatorLoc); + p.setFireTicks(0); + p.setHealth(20); + + // Add to the list of dead players. + livePlayers.remove(p); + deadPlayers.add(p); + removePets(p); + + // Has to be delayed for TombStone not to fuck shit up. + if (running && livePlayers.isEmpty()) + Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, + new Runnable() + { + public void run() + { + MAUtils.restoreInventory(p); + endArena(); + } + }, 10); + + // Notify listeners. + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onPlayerDeath(p); + } + + public void playerSpec(Player p, Location loc) + { + if (!locations.containsKey(p)) + locations.put(p,loc); + + MAUtils.sitPets(p); + specPlayers.add(p); + p.teleport(spectatorLoc); + } + + public void playerKill(Player p, LivingEntity e) + { + kills.put(p, kills.get(p) + 1); + } + + + + /*//////////////////////////////////////////////////////////////////// + // + // Items & Cleanup + // + ////////////////////////////////////////////////////////////////////*/ + + public void assignClass(Player p, String className) + { + petMap.remove(p); + classMap.put(p, className); + MAUtils.clearInventory(p); + MAUtils.giveItems(p, classItems.get(className), autoEquip); + MAUtils.giveItems(p, classArmor.get(className), autoEquip); + + int pets = MAUtils.getPetAmount(p); + if (pets > 0) petMap.put(p, pets); + } + + private void giveRewards() + { + for (Map.Entry> entry : rewardMap.entrySet()) + { + MAUtils.tellPlayer(entry.getKey(), MAMessages.get(Msg.REWARDS_GIVE)); + MAUtils.giveRewards(entry.getKey(), entry.getValue()); + } + } + + private void cleanup() + { + removeMonsters(); + removeBlocks(); + removePets(); + removeEntities(); + monsters.clear(); + blocks.clear(); + pets.clear(); + } + + private void removeMonsters() + { + for (LivingEntity e : monsters) + e.remove(); + } + + private void removeBlocks() + { + for (Block b : blocks) + b.setTypeId(0); + } + + private void removePets() + { + for (Wolf w : pets) + w.remove(); + } + + private void removePets(Player p) + { + for (Wolf w : pets) + if (w.getOwner().equals(p)) + w.remove(); + } + + private void removeEntities() + { + Chunk c1 = world.getChunkAt(p1); + Chunk c2 = world.getChunkAt(p2); + + for (int i = c1.getX(); i <= c2.getX(); i++) + for (int j = c1.getZ(); j <= c2.getZ(); j++) + for (Entity e : world.getChunkAt(i,j).getEntities()) + if ((e instanceof Item || e instanceof Slime) && inRegion(e.getLocation())) + e.remove(); + } + + + + /*//////////////////////////////////////////////////////////////////// + // + // Initialization & Checks + // + ////////////////////////////////////////////////////////////////////*/ + + public void load(Configuration config) + { + config.load(); + + String arenaPath = "arenas." + MAUtils.nameArenaToConfig(name) + ".settings."; + String configName = MAUtils.nameArenaToConfig(name); + + enabled = config.getBoolean(arenaPath + "enabled", true); + protect = config.getBoolean(arenaPath + "protect", true); + autoEquip = config.getBoolean(arenaPath + "auto-equip-armor", true); + waveClear = config.getBoolean(arenaPath + "clear-wave-before-next", false); + detCreepers = config.getBoolean(arenaPath + "detonate-creepers", false); + detDamage = config.getBoolean(arenaPath + "detonate-damage", false); + lightning = config.getBoolean(arenaPath + "lightning", true); + forceRestore = config.getBoolean(arenaPath + "force-restore", false); + softRestore = config.getBoolean(arenaPath + "soft-restore", false); + softRestoreDrops = config.getBoolean(arenaPath + "soft-restore-drops", false); + emptyInvJoin = config.getBoolean(arenaPath + "require-empty-inv-join", false); + emptyInvSpec = config.getBoolean(arenaPath + "require-empty-inv-spec", false); + hellhounds = config.getBoolean(arenaPath + "hellhounds", false); + pvp = config.getBoolean(arenaPath + "pvp-enabled", false); + monsterInfight = config.getBoolean(arenaPath + "monster-infight", false); + allowWarp = config.getBoolean(arenaPath + "allow-teleporting", false); + repairDelay = config.getInt(arenaPath + "repair-delay", 5); + waveDelay = config.getInt(arenaPath + "first-wave-delay", 5) * 20; + waveInterval = config.getInt(arenaPath + "wave-interval", 20) * 20; + specialModulo = config.getInt(arenaPath + "special-modulo", 4); + maxIdleTime = config.getInt(arenaPath + "max-idle-time", 0) * 20; + + distDefault = MAUtils.getArenaDistributions(config, configName, "default"); + distSpecial = MAUtils.getArenaDistributions(config, configName, "special"); + everyWaveMap = MAUtils.getArenaRewardMap(config, configName, "every"); + afterWaveMap = MAUtils.getArenaRewardMap(config, configName, "after"); + + p1 = MAUtils.getArenaCoord(config, world, configName, "p1"); + p2 = MAUtils.getArenaCoord(config, world, configName, "p2"); + arenaLoc = MAUtils.getArenaCoord(config, world, configName, "arena"); + lobbyLoc = MAUtils.getArenaCoord(config, world, configName, "lobby"); + spectatorLoc = MAUtils.getArenaCoord(config, world, configName, "spectator"); + spawnpoints = MAUtils.getArenaSpawnpoints(config, world, configName); + + classes = plugin.getAM().classes; + classItems = plugin.getAM().classItems; + classArmor = plugin.getAM().classArmor; + + // Determine if the arena is properly set up. Then add the to arena list. + setup = MAUtils.verifyData(this); + } + + public void serializeConfig() + { + String coords = "arenas." + configName() + ".coords."; + Configuration config = plugin.getConfig(); + + config.setProperty("arenas." + configName() + ".settings.enabled", enabled); + config.setProperty("arenas." + configName() + ".settings.protect", protect); + if (p1 != null) config.setProperty(coords + "p1", MAUtils.makeCoord(p1)); + if (p2 != null) config.setProperty(coords + "p2", MAUtils.makeCoord(p2)); + if (arenaLoc != null) config.setProperty(coords + "arena", MAUtils.makeCoord(arenaLoc)); + if (lobbyLoc != null) config.setProperty(coords + "lobby", MAUtils.makeCoord(lobbyLoc)); + if (spectatorLoc != null) config.setProperty(coords + "spectator", MAUtils.makeCoord(spectatorLoc)); + for (Map.Entry entry : spawnpoints.entrySet()) + config.setProperty(coords + "spawnpoints." + entry.getKey(), MAUtils.makeCoord(entry.getValue())); + + config.save(); + } + + public void deserializeConfig() + { + Configuration config = plugin.getConfig(); + config.load(); + load(config); + } + + public boolean serializeRegion() + { + int x1 = (int) p1.getX(); + int y1 = (int) p1.getY(); + int z1 = (int) p1.getZ(); + int x2 = (int) p2.getX(); + int y2 = (int) p2.getY(); + int z2 = (int) p2.getZ(); + + HashSet set = new HashSet(); + int[] buffer; + for (int i = x1; i <= x2; i++) + { + for (int j = y1; j <= y2; j++) + { + for (int k = z1; k <= z2; k++) + { + buffer = new int[4]; + buffer[0] = i; + buffer[1] = j; + buffer[2] = k; + buffer[3] = world.getBlockAt(i,j,k).getTypeId(); + set.add(buffer); + } + } + } + + try + { + new File(plugin.getDataFolder() + File.separator + "regions").mkdir(); + File regionFile = new File(plugin.getDataFolder() + File.separator + "regions" + File.separator + configName() + ".tmp"); + if (regionFile.exists()) + regionFile.createNewFile(); + + FileOutputStream fos = new FileOutputStream(regionFile); + ObjectOutputStream oos = new ObjectOutputStream(fos); + oos.writeObject(set); + oos.close(); + } + catch (Exception e) + { + System.out.println("[MobArena] ERROR! Could not create region file. The arena will not be started!"); + e.printStackTrace(); + return false; + } + return true; + } + + @SuppressWarnings("unchecked") + public boolean deserializeRegion() + { + HashSet set = new HashSet(); + try + { + File regionFile = new File(plugin.getDataFolder() + File.separator + "regions" + File.separator + configName() + ".tmp"); + if (!regionFile.exists()) + return false; + + FileInputStream fis = new FileInputStream(regionFile); + ObjectInputStream ois = new ObjectInputStream(fis); + set = (HashSet) ois.readObject(); + ois.close(); + } + catch (Exception e) + { + System.out.println("[MobArena] ERROR! Could not find region file. The arena cannot be restored!"); + e.printStackTrace(); + return false; + } + + for (int[] buffer : set) + world.getBlockAt(buffer[0], buffer[1], buffer[2]).setTypeId(buffer[3]); + + return true; + } + + /** + * Check if a location is inside of the cuboid region + * that p1 and p2 span. + */ + public boolean inRegion(Location loc) + { + if (!loc.getWorld().getName().equals(world.getName())) + return false; + + if (!setup) + return false; + + // Returns false if the location is outside of the region. + return ((loc.getX() >= p1.getX() && loc.getX() <= p2.getX()) && + (loc.getZ() >= p1.getZ() && loc.getZ() <= p2.getZ()) && + (loc.getY() >= p1.getY() && loc.getY() <= p2.getY())); + } + + /** + * Check if a location is inside of the arena region, expanded + * by 'radius' blocks. Used with explosions. + */ + public boolean inRegionRadius(Location loc, int radius) + { + if (!loc.getWorld().getName().equals(world.getName()) || !setup) + return false; + + return ((loc.getX() + radius >= p1.getX() && loc.getX() - radius <= p2.getX()) && + (loc.getZ() + radius >= p1.getZ() && loc.getZ() - radius <= p2.getZ()) && + (loc.getY() + radius >= p1.getY() && loc.getY() - radius <= p2.getY())); + } + + + + /*//////////////////////////////////////////////////////////////////// + // + // EventListener methods + // + ////////////////////////////////////////////////////////////////////*/ + + // Block Listener + public void onBlockBreak(BlockBreakEvent event) + { + if (edit || !inRegion(event.getBlock().getLocation())) + return; + + Block b = event.getBlock(); + if (blocks.remove(b) || b.getType() == Material.TNT) + return; + + if (softRestore) + { + 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(); + repairList.add(buffer); + if (!softRestoreDrops) event.getBlock().setTypeId(0); + return; + } + + event.setCancelled(true); + } + + public void onBlockPlace(BlockPlaceEvent event) + { + // If in edit mode or the event didn't happen in this region, return. + if (edit || !inRegion(event.getBlock().getLocation())) + return; + + Block b = event.getBlock(); + if (running && livePlayers.contains(event.getPlayer())) + { + blocks.add(b); + Material mat = b.getType(); + + if (mat == Material.WOODEN_DOOR || mat == Material.IRON_DOOR_BLOCK) + blocks.add(b.getRelative(0,1,0)); + return; + } + + // If the arena isn't running, or if the player isn't in the arena, cancel. + event.setCancelled(true); + } + + // Monster Listener + public void onCreatureSpawn(CreatureSpawnEvent event) + { + if (!inRegion(event.getLocation())) + return; + + // If running == true, setCancelled(false), and vice versa. + event.setCancelled(!running); + } + + public void onEntityExplode(EntityExplodeEvent event) + { + if (!monsters.contains(event.getEntity()) && !inRegionRadius(event.getLocation(), 10)) + return; + + // If the arena isn't running + if (!running || repairDelay == 0) + { + event.setCancelled(true); + return; + } + + // Uncancel, just in case. + event.setCancelled(false); + event.setYield(0); + monsters.remove(event.getEntity()); + + int[] buffer; + final HashMap blockMap = new HashMap(); + for (Block b : event.blockList()) + { + Material mat = b.getType(); + + if (mat == Material.WOODEN_DOOR || mat == Material.IRON_DOOR_BLOCK || mat == Material.FIRE || mat == Material.CAKE_BLOCK || mat == Material.WATER || mat == Material.LAVA) + { + blocks.remove(b); + } + else if (blocks.remove(b)) + { + world.dropItemNaturally(b.getLocation(), new ItemStack(b.getTypeId(), 1)); + } + else if (softRestore) + { + 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(); + repairList.add(buffer); + blockMap.put(b, b.getTypeId() + (b.getData() * 1000)); + } + else + { + blockMap.put(b, b.getTypeId() + (b.getData() * 1000)); + } + } + + if (!protect || softRestore) + return; + + Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, + new Runnable() + { + public void run() + { + for (Map.Entry entry : blockMap.entrySet()) + { + Block b = entry.getKey(); + int type = entry.getValue(); + + b.getLocation().getBlock().setTypeId(type % 1000); + + if (type > 1000) + b.getLocation().getBlock().setData((byte) (type / 1000)); + } + } + }, repairDelay); + } + + public void onEntityCombust(EntityCombustEvent event) + { + if (monsters.contains(event.getEntity())) + event.setCancelled(true); + } + + public void onEntityTarget(EntityTargetEvent event) + { + if (!running) return; + + if (pets.contains(event.getEntity())) + { + if (event.getReason() != TargetReason.TARGET_ATTACKED_OWNER && event.getReason() != TargetReason.OWNER_ATTACKED_TARGET) + return; + + if (!(event.getTarget() instanceof Player)) + return; + + // If the target is a player, cancel. + event.setCancelled(true); + return; + } + + if (monsters.contains(event.getEntity())) + { + if (event.getReason() == TargetReason.FORGOT_TARGET) + { + event.setTarget(MAUtils.getClosestPlayer(event.getEntity(), this)); + return; + } + + if (event.getReason() == TargetReason.TARGET_DIED) + { + event.setTarget(MAUtils.getClosestPlayer(event.getEntity(), this)); + return; + } + + if (event.getReason() == TargetReason.CLOSEST_PLAYER) + if (!livePlayers.contains(event.getTarget())) + event.setCancelled(true); + return; + } + } + + // Death Listener + public void onEntityRegainHealth(EntityRegainHealthEvent event) + { + if (!running) return; + + if (!(event.getEntity() instanceof Player) || !livePlayers.contains((Player)event.getEntity())) + return; + + if (event.getRegainReason() == RegainReason.REGEN) + event.setCancelled(true); + } + + public void onEntityDeath(EntityDeathEvent event) + { + if (!running) return; + + if (event.getEntity() instanceof Player) + { + Player p = (Player) event.getEntity(); + + if (!livePlayers.contains(p)) + return; + + event.getDrops().clear(); + playerDeath(p); + p.getInventory().clear(); // For TombStone + return; + } + + if (monsters.remove(event.getEntity())) + { + event.getDrops().clear(); + resetIdleTimer(); + return; + } + } + + public void onEntityDamage(EntityDamageEvent event) + { + if (!running) return; + + EntityDamageByEntityEvent e = (event instanceof EntityDamageByEntityEvent) ? (EntityDamageByEntityEvent) event : null; + Entity damager = (e != null) ? e.getDamager() : null; + Entity damagee = event.getEntity(); + + // Damagee - Pet Wolf - cancel all damage. + if (damagee instanceof Wolf && pets.contains(damagee)) + { + if (event.getCause() == DamageCause.FIRE_TICK) + { + damagee.setFireTicks(32768); // For mcMMO + event.setCancelled(true); + } + + event.setDamage(0); + return; + } + + // Damager - Pet Wolf - lower damage + if (e != null && damager instanceof Wolf && pets.contains(damager)) + { + event.setDamage(1); + return; + } + + // Damagee & Damager - Player - cancel if pvp disabled + if (damagee instanceof Player && damager instanceof Player) + { + if (livePlayers.contains(damagee) && !pvp) + event.setCancelled(true); + + return; + } + + // Damagee & Damager - Monsters - cancel if no monsterInfight + if (e != null && monsters.contains(damagee) && monsters.contains(damager)) + { + if (!monsterInfight) + event.setCancelled(true); + + return; + } + + // Creeper detonations + if (inRegion(damagee.getLocation())) + { + if (!detDamage || !(damagee instanceof Player) || !livePlayers.contains((Player) damagee)) + return; + + if (event.getCause() == DamageCause.BLOCK_EXPLOSION) + event.setCancelled(true); + + return; + } + } + + // Lobby Listener + public void onPlayerDropItem(PlayerDropItemEvent event) + { + if (running) return; + + Player p = event.getPlayer(); + if (!inRegion(p.getLocation()) || !livePlayers.contains(p)) + return; + + MAUtils.tellPlayer(p, MAMessages.get(Msg.LOBBY_DROP_ITEM)); + event.setCancelled(true); + } + + public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) + { + if (!readyPlayers.contains(event.getPlayer()) && !livePlayers.contains(event.getPlayer())) + return; + + if (!running) + { + event.getBlockClicked().getFace(event.getBlockFace()).setTypeId(0); + event.setCancelled(true); + return; + } + + Block liquid = event.getBlockClicked().getFace(event.getBlockFace()); + blocks.add(liquid); + } + + public void onPlayerInteract(PlayerInteractEvent event) + { + if (running || !livePlayers.contains(event.getPlayer())) + return; + + Player p = event.getPlayer(); + Action a = event.getAction(); + if ((a == Action.RIGHT_CLICK_AIR) || (a == Action.RIGHT_CLICK_BLOCK)) + { + event.setUseItemInHand(Result.DENY); + event.setCancelled(true); + } + + // Iron block + if (event.hasBlock() && event.getClickedBlock().getTypeId() == 42) + { + if (classMap.containsKey(p)) + { + MAUtils.tellPlayer(p, MAMessages.get(Msg.LOBBY_PLAYER_READY)); + playerReady(p); + } + else + { + MAUtils.tellPlayer(p, MAMessages.get(Msg.LOBBY_PICK_CLASS)); + } + return; + } + + // Sign + if (event.hasBlock() && event.getClickedBlock().getState() instanceof Sign) + { + if (a == Action.RIGHT_CLICK_BLOCK) + { + MAUtils.tellPlayer(p, MAMessages.get(Msg.LOBBY_RIGHT_CLICK)); + return; + } + + // Cast the block to a sign to get the text on it. + Sign sign = (Sign) event.getClickedBlock().getState(); + + // Check if the first line of the sign is a class name. + String className = sign.getLine(0); + if (!classes.contains(className)) + return; + + if (!MobArena.hasDefTrue(p, "mobarena.classes." + className)) + { + MAUtils.tellPlayer(p, MAMessages.get(Msg.LOBBY_CLASS_PERMISSION)); + return; + } + + // Set the player's class. + assignClass(p, className); + MAUtils.tellPlayer(p, MAMessages.get(Msg.LOBBY_CLASS_PICKED, className)); + return; + } + } + + // Disconnect Listener + public void onPlayerQuit(PlayerQuitEvent event) + { + Player p = event.getPlayer(); + if (!enabled || !getAllPlayers().contains(p)) + return; + + MAUtils.clearInventory(p); + playerQuit(p); + } + + public void onPlayerKick(PlayerKickEvent event) + { + Player p = event.getPlayer(); + if (!enabled || !getAllPlayers().contains(p)) + return; + + MAUtils.clearInventory(p); + playerQuit(p); + } + + // Teleport Listener + public void onPlayerTeleport(PlayerTeleportEvent event) + { + if (edit || !enabled || !setup || allowWarp) + return; + + if (!inRegion(event.getTo()) && !inRegion(event.getFrom())) + return; + + Player p = event.getPlayer(); + Location old = locations.get(p); + Location to = event.getTo(); + Location from = event.getFrom(); + + if (livePlayers.contains(p)) + { + if (inRegion(from)) + { + if (to.equals(arenaLoc) || to.equals(lobbyLoc) || to.equals(spectatorLoc) || to.equals(old)) + return; + + MAUtils.tellPlayer(p, MAMessages.get(Msg.WARP_FROM_ARENA)); + event.setCancelled(true); + return; + } + + if (inRegion(to)) + { + if (to.equals(arenaLoc) || to.equals(lobbyLoc) || to.equals(spectatorLoc) || to.equals(old)) + return; + + MAUtils.tellPlayer(p, MAMessages.get(Msg.WARP_TO_ARENA)); + event.setCancelled(true); + return; + } + + return; + } + + if (running && inRegion(to)) + { + MAUtils.tellPlayer(p, MAMessages.get(Msg.WARP_TO_ARENA)); + event.setCancelled(true); + return; + } + } + + // Command Listener + public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) + { + Player p = event.getPlayer(); + + if (!livePlayers.contains(p)) + return; + + String[] args = event.getMessage().split(" "); + + if ((args.length > 1 && MACommands.COMMANDS.contains(args[1].trim())) || + MACommands.ALLOWED_COMMANDS.contains(event.getMessage().substring(1).trim()) || + MACommands.ALLOWED_COMMANDS.contains(args[0])) + return; + + event.setCancelled(true); + MAUtils.tellPlayer(p, MAMessages.get(Msg.MISC_COMMAND_NOT_ALLOWED)); + } + + + /*//////////////////////////////////////////////////////////////////// + // + // Getters & Misc + // + ////////////////////////////////////////////////////////////////////*/ + + public String configName() + { + return MAUtils.nameArenaToConfig(name); + } + + public String arenaName() + { + return name; + } + + public List getAllPlayers() + { + List result = new LinkedList(); + result.addAll(livePlayers); + result.addAll(deadPlayers); + result.addAll(specPlayers); + return result; + } + + public List getLivingPlayers() + { + List result = new LinkedList(); + result.addAll(livePlayers); + return result; + } + + public List getNonreadyPlayers() + { + List result = new LinkedList(); + result.addAll(livePlayers); + result.removeAll(readyPlayers); + return result; + } + + public List getDeadPlayers() + { + List result = new LinkedList(); + result.addAll(deadPlayers); + return result; + } + + public void resetIdleTimer() + { + if (maxIdleTime <= 0) + return; + + // Reset the previousSize, cancel the previous timer, and start the new timer. + spawnThread.previousSize = monsters.size(); + Bukkit.getServer().getScheduler().cancelTask(spawnThread.taskId); + spawnThread.taskId = Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, + new Runnable() + { + public void run() + { + // Make sure to remove any dead/removed entities first. + List tmp = new LinkedList(monsters); + for (Entity e : tmp) + if (e.isDead()) + monsters.remove(e); + + // Compare the current size with the previous size. + if (monsters.size() < spawnThread.previousSize || spawnThread.previousSize == 0) + return; + + // Clear all player inventories, and "kill" all players. + for (Player p : livePlayers) + { + MAUtils.clearInventory(p); + playerDeath(p); + MAUtils.tellPlayer(p, MAMessages.get(Msg.FORCE_END_IDLE)); + } + } + }, maxIdleTime*20); + } + + /** + * The "perfect equals method" cf. "Object-Oriented Design and Patterns" + * by Cay S. Horstmann. + */ + public boolean equals(Object other) + { + if (this == other) return true; + if (other == null) return false; + if (getClass() != other.getClass()) return false; + + // Arenas must have different names. + if (other instanceof Arena && ((Arena)other).name.equals(name)) + return true; + + return false; + } + + public String toString() + { + return ((enabled && setup) ? ChatColor.GREEN : ChatColor.GRAY) + configName(); + } +} diff --git a/src/com/garbagemule/MobArena/ArenaMaster.java b/src/com/garbagemule/MobArena/ArenaMaster.java new file mode 100644 index 0000000..cbfbd07 --- /dev/null +++ b/src/com/garbagemule/MobArena/ArenaMaster.java @@ -0,0 +1,366 @@ +package com.garbagemule.MobArena; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.config.Configuration; + +public class ArenaMaster +{ + private MobArena plugin; + private Configuration config; + protected Arena selectedArena; + protected Lobby masterLobby; + + // Settings + protected boolean enabled, updateNotify, autoEquip, emptyInvs, hellhounds; + + // Classes + protected List classes; + protected Map> classItems, classArmor; + protected Map arenaMap; + + // Location map + protected Map locations = new HashMap(); + + // Arena list + protected List arenas; + + // Listeners + protected Set listeners = new HashSet(); + + + + /** + * Default constructor. + */ + public ArenaMaster(MobArena instance) + { + plugin = instance; + config = plugin.getConfig(); + } + + + + /*///////////////////////////////////////////////////////////////////////// + // + // Arena getters + // + /////////////////////////////////////////////////////////////////////////*/ + + public Arena getArenaInLocation(Location loc) + { + for (Arena arena : arenas) + if (arena.inRegion(loc)) + return arena; + return null; + } + + public List getArenasInWorld(World world) + { + List result = new LinkedList(); + for (Arena arena : arenas) + if (arena.world.equals(world)) + result.add(arena); + return result; + } + + public List getAllPlayers() + { + List result = new LinkedList(); + for (Arena arena : arenas) + result.addAll(arena.getAllPlayers()); + return result; + } + + public List getAllPlayersInArena(String arenaName) + { + Arena arena = getArenaWithName(arenaName); + return (arena != null) ? arena.getLivingPlayers() : new LinkedList(); + } + + public List getAllLivingPlayers() + { + List result = new LinkedList(); + for (Arena arena : arenas) + result.addAll(arena.getLivingPlayers()); + return result; + } + + public List getLivingPlayersInArena(String arenaName) + { + Arena arena = getArenaWithName(arenaName); + return (arena != null) ? arena.getLivingPlayers() : new LinkedList(); + } + + public Arena getArenaWithPlayer(Player p) + { + return arenaMap.get(p); + } + + public Arena getArenaWithPlayer(String playerName) + { + return arenaMap.get(Bukkit.getServer().getPlayer(playerName)); + } + + public Arena getArenaWithSpectator(Player p) + { + for (Arena arena : arenas) + { + if (arena.specPlayers.contains(p)) + return arena; + } + return null; + } + + public Arena getArenaWithMonster(Entity e) + { + for (Arena arena : arenas) + if (arena.monsters.contains(e)) + return arena; + return null; + } + + public Arena getArenaWithPet(Entity e) + { + for (Arena arena : arenas) + if (arena.pets.contains(e)) + return arena; + return null; + } + + public Arena getArenaWithName(String configName) + { + for (Arena arena : arenas) + if (arena.configName().equals(configName)) + return arena; + return null; + } + + + + /*///////////////////////////////////////////////////////////////////////// + // + // Initialization + // + /////////////////////////////////////////////////////////////////////////*/ + + public void initialize() + { + config.load(); + loadSettings(); + loadClasses(); + loadArenas(); + config.save(); + } + + /** + * Load the global settings. + */ + public void loadSettings() + { + if (config.getKeys("global-settings") == null) + { + config.setProperty("global-settings.enabled", true); + config.setProperty("global-settings.update-notification", true); + } + + enabled = config.getBoolean("global-settings.enabled", true); + updateNotify = config.getBoolean("global-settings.update-notification", true); + } + + /** + * Load all class-related stuff. + */ + public void loadClasses() + { + if (config.getKeys("classes") == null) + { + config.setProperty("classes.Archer.items", "wood_sword, bow, arrow:128, grilled_pork"); + config.setProperty("classes.Archer.armor", "298,299,300,301"); + config.setProperty("classes.Knight.items", "diamond_sword, grilled_pork:2"); + config.setProperty("classes.Knight.armor", "306,307,308,309"); + config.setProperty("classes.Tank.items", "iron_sword, grilled_pork:3, apple"); + config.setProperty("classes.Tank.armor", "310,311,312,313"); + config.setProperty("classes.Oddjob.items", "stone_sword, flint_and_steel, netherrack:2, wood_pickaxe, tnt:4, fishing_rod, apple, grilled_pork:3"); + config.setProperty("classes.Oddjob.armor", "298,299,300,301"); + config.setProperty("classes.Chef.items", "stone_sword, bread:6, grilled_pork:4, mushroom_soup, cake:3, cookie:12"); + config.setProperty("classes.Chef.armor", "314,315,316,317"); + } + classes = config.getKeys("classes"); + classItems = MAUtils.getClassItems(config, "items"); + classArmor = MAUtils.getClassItems(config, "armor"); + } + + /** + * Load all arena-related stuff. + */ + public void loadArenas() + { + arenas = new LinkedList(); + + if (config.getKeys("arenas") == null) + createArenaNode("default", Bukkit.getServer().getWorlds().get(0)); + + for (String configName : config.getKeys("arenas")) + { + String arenaPath = "arenas." + configName + "."; + String worldName = config.getString(arenaPath + "settings.world"); + World world; + if (worldName == null) + { + System.out.println("[MobArena] ERROR! Could not find the world for arena '" + configName + "'. Using default world! Check the config-file!"); + world = Bukkit.getServer().getWorlds().get(0); + } + else + { + world = Bukkit.getServer().getWorld(worldName); + } + + Arena arena = new Arena(MAUtils.nameConfigToArena(configName), world, this); + arena.load(config); + arenas.add(arena); + } + + arenaMap = new HashMap(); + selectedArena = arenas.get(0); + } + + public Arena createArenaNode(String configName, World world) + { + config.setProperty("arenas." + configName + ".settings.world", world.getName()); + config.save(); + config.load(); + config.setProperty("arenas." + configName + ".settings.enabled", true); + config.save(); + config.load(); + config.setProperty("arenas." + configName + ".settings.protect", true); + config.save(); + config.load(); + config.setProperty("arenas." + configName + ".settings.clear-wave-before-next", false); + config.setProperty("arenas." + configName + ".settings.detonate-creepers", false); + config.setProperty("arenas." + configName + ".settings.detonate-damage", false); + config.setProperty("arenas." + configName + ".settings.lightning", true); + config.setProperty("arenas." + configName + ".settings.auto-equip-armor", true); + config.setProperty("arenas." + configName + ".settings.force-restore", false); + config.setProperty("arenas." + configName + ".settings.soft-restore", false); + config.setProperty("arenas." + configName + ".settings.soft-restore-drops", false); + config.setProperty("arenas." + configName + ".settings.require-empty-inv-join", false); + config.setProperty("arenas." + configName + ".settings.require-empty-inv-spec", false); + config.setProperty("arenas." + configName + ".settings.hellhounds", false); + config.setProperty("arenas." + configName + ".settings.pvp-enabled", false); + config.setProperty("arenas." + configName + ".settings.monster-infight", false); + config.setProperty("arenas." + configName + ".settings.allow-teleporting", false); + config.save(); + config.load(); + config.setProperty("arenas." + configName + ".settings.repair-delay", 5); + config.setProperty("arenas." + configName + ".settings.first-wave-delay", 5); + config.setProperty("arenas." + configName + ".settings.wave-interval", 20); + config.setProperty("arenas." + configName + ".settings.special-modulo", 4); + config.setProperty("arenas." + configName + ".settings.max-idle-time", 0); + config.save(); + config.load(); + + Arena arena = new Arena(MAUtils.nameConfigToArena(configName), world, this); + arena.load(config); + return arena; + } + + public void removeArenaNode(String configName) + { + config.removeProperty("arenas." + configName); + config.save(); + } + + + + /*///////////////////////////////////////////////////////////////////////// + // + // Update and serialization methods + // + /////////////////////////////////////////////////////////////////////////*/ + + /** + * Update one, two or all three of global settings, classes + * and arenas (arenas with deserialization). + */ + public void update(boolean settings, boolean classes, boolean arenalist) + { + boolean tmp = enabled; + enabled = false; + + for (Arena arena : arenas) + arena.forceEnd(); + + config.load(); + if (settings) loadSettings(); + if (classes) loadClasses(); + if (arenalist) deserializeArenas(); + config.save(); + + enabled = tmp; + } + + /** + * Serialize the global settings. + */ + public void serializeSettings() + { + String settings = "global-settings."; + config.setProperty(settings + "enabled", enabled); + config.save(); + } + + /** + * Serialize all arena configs. + */ + public void serializeArenas() + { + for (Arena arena : arenas) + arena.serializeConfig(); + } + + /** + * Deserialize all arena configs. Updates the arena list to + * include only the current arenas (not ones added in the + * actual file) that are also in the config-file. + */ + public void deserializeArenas() + { + // Get only the arenas in the config. + List strings = config.getKeys("arenas"); + if (strings == null) + return; + + // Get their Arena objects. + List configArenas = new LinkedList(); + for (String s : strings) + if (getArenaWithName(s) != null) + configArenas.add(getArenaWithName(s)); + + // Remove all Arenas no longer in the config. + arenas.retainAll(configArenas); + + for (Arena arena : arenas) + arena.deserializeConfig(); + + // Make sure to update the selected arena to a valid one. + if (!arenas.contains(selectedArena) && arenas.size() >= 1) + selectedArena = arenas.get(0); + } + + public void updateSettings() { update(true, false, false); } + public void updateClasses() { update(false, true, false); } + public void updateArenas() { update(false, false, true); } + public void updateAll() { update(true, true, true); } +} diff --git a/src/com/garbagemule/MobArena/Lobby.java b/src/com/garbagemule/MobArena/Lobby.java new file mode 100644 index 0000000..6740175 --- /dev/null +++ b/src/com/garbagemule/MobArena/Lobby.java @@ -0,0 +1,26 @@ +package com.garbagemule.MobArena; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +public class Lobby +{ + protected Arena arena; + protected ArenaMaster am; + protected Location warp, l1, l2; + + public Lobby(Arena arena) + { + this.arena = arena; + } + public Lobby() + { + this(null); + } + + public void playerJoin(Player p) + { + p.teleport(warp); + } +} diff --git a/src/com/garbagemule/MobArena/MABlockListener.java b/src/com/garbagemule/MobArena/MABlockListener.java index 1f80376..fef7a65 100644 --- a/src/com/garbagemule/MobArena/MABlockListener.java +++ b/src/com/garbagemule/MobArena/MABlockListener.java @@ -1,69 +1,27 @@ package com.garbagemule.MobArena; -import org.bukkit.Material; -import org.bukkit.block.Block; import org.bukkit.event.block.BlockListener; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; -//import org.bukkit.event.block.BlockDamageEvent; -/** - * This listener serves as a protection class. Blocks within - * the arena region cannot be destroyed, and blocks can only - * be placed by a participant in the current arena session. - * Any placed blocks will be removed by the cleanup method in - * ArenaManager when the session ends. - */ public class MABlockListener extends BlockListener -{ - public MABlockListener(MobArena instance) +{ + private ArenaMaster am; + + public MABlockListener(ArenaMaster am) { + this.am = am; } - /** - * Prevents blocks from breaking if block protection is on. - */ public void onBlockBreak(BlockBreakEvent event) { - if (!ArenaManager.isSetup || !ArenaManager.isProtected) - return; - - Block b = event.getBlock(); - - if (ArenaManager.blockSet.remove(b) || b.getType() == Material.TNT) - return; - - if (MAUtils.inRegion(b.getLocation())) - event.setCancelled(true); + for (Arena arena : am.arenas) + arena.onBlockBreak(event); } - - /** - * Adds player-placed blocks to a set for removal and item - * drop purposes. If the block is placed within the arena - * region, cancel the event if protection is on. - */ + public void onBlockPlace(BlockPlaceEvent event) { - if (!ArenaManager.isSetup || !ArenaManager.isProtected) - return; - - Block b = event.getBlock(); - - if (!MAUtils.inRegion(b.getLocation())) - return; - - if (ArenaManager.isRunning && ArenaManager.playerSet.contains(event.getPlayer())) - { - ArenaManager.blockSet.add(b); - Material type = b.getType(); - - // Make sure to add the top parts of doors. - if (type == Material.WOODEN_DOOR || type == Material.IRON_DOOR_BLOCK) - ArenaManager.blockSet.add(b.getRelative(0,1,0)); - - return; - } - - event.setCancelled(true); + for (Arena arena : am.arenas) + arena.onBlockPlace(event); } } \ No newline at end of file diff --git a/src/com/garbagemule/MobArena/MACommands.java b/src/com/garbagemule/MobArena/MACommands.java index da7a001..6a6439a 100644 --- a/src/com/garbagemule/MobArena/MACommands.java +++ b/src/com/garbagemule/MobArena/MACommands.java @@ -1,320 +1,922 @@ package com.garbagemule.MobArena; -import java.util.Arrays; +import java.util.List; +import java.util.LinkedList; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Server; import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.CommandExecutor; +import org.bukkit.command.ConsoleCommandSender; + +import com.garbagemule.MobArena.MAMessages.Msg; public class MACommands implements CommandExecutor { + public static List ALLOWED_COMMANDS = new LinkedList(); + public static final List COMMANDS = new LinkedList(); + static + { + COMMANDS.add("j"); // Join + COMMANDS.add("join"); // Join + COMMANDS.add("l"); // Leave + COMMANDS.add("leave"); // Leave + COMMANDS.add("notready"); // List of players who aren't ready + COMMANDS.add("spec"); // Watch arena + COMMANDS.add("spectate"); // Watch arena + COMMANDS.add("arenas"); // List of arenas + COMMANDS.add("list"); // List of players + COMMANDS.add("players"); // List of players + COMMANDS.add("restore"); // Restore inventory + COMMANDS.add("enable"); // Enabling + COMMANDS.add("disable"); // Disabling + COMMANDS.add("protect"); // Protection on/off + COMMANDS.add("force"); // Force start/end + COMMANDS.add("config"); // Reload config + COMMANDS.add("arena"); // Current arena + COMMANDS.add("setarena"); // Set current arena + COMMANDS.add("addarena"); // Add a new arena + COMMANDS.add("delarena"); // Delete current aren + COMMANDS.add("editarena"); // Editing + COMMANDS.add("setregion"); // Set a region point + COMMANDS.add("setwarp"); // Set arena/lobby/spec + COMMANDS.add("spawnpoints"); // List spawnpoints + COMMANDS.add("addspawn"); // Add a spawnpoint + COMMANDS.add("delspawn"); // Delete a spawnpoint + COMMANDS.add("expandregion"); // Expand the region + COMMANDS.add("reset"); // Reset arena coordinates + COMMANDS.add("auto-generate"); // Auto-generate arena + COMMANDS.add("auto-degenerate"); // Restore cuboid + } + private boolean player, op, console, meanAdmins; + private Server server; + private MobArena plugin; + private ArenaMaster am; + + public MACommands(MobArena plugin, ArenaMaster am) + { + this.plugin = plugin; + this.am = am; + server = Bukkit.getServer(); + meanAdmins = (server.getPluginManager().getPlugin("Mean Admins") != null); + ALLOWED_COMMANDS = MAUtils.getAllowedCommands(plugin.getConfig()); + } + /** * Handles all command parsing. * Unrecognized commands return false, giving the sender a list of * valid commands (from plugin.yml). */ - public boolean onCommand(CommandSender sender, Command command, String commandLabel, String[] args) + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - // Check if the server is also running Mean Admins. - Plugin ma = ArenaManager.server.getPluginManager().getPlugin("Mean Admins"); - if (ma != null && !Arrays.asList(ArenaManager.plugin.COMMANDS).contains(args[0].toLowerCase())) + // Play nice with Mean Admins. + if (meanAdmins && !COMMANDS.contains(args[0].toLowerCase())) { - ma.onCommand(sender, command, commandLabel, args); - return true; - } - - // Only accept commands from players. - if ((sender == null) || !(sender instanceof Player)) - { - System.out.println("Only players can use these commands, silly."); + server.getPluginManager().getPlugin("Mean Admins").onCommand(sender, command, label, args); return true; } - // Cast the sender to a Player object. - Player p = (Player) sender; + // Determine if the sender is a player (and an op), or the console. + player = (sender instanceof Player); + op = player && ((Player) sender).isOp(); + console = (sender instanceof ConsoleCommandSender); - /* If more than one argument, must be an advanced command. - * Only allow operators to access these commands. */ - if (args.length > 1) - { - if (p.isOp()) - return advancedCommands(p, args); - - ArenaManager.tellPlayer(p, "Must be operator for advanced commands."); - return true; - } + // Cast the sender to Player if possible. + Player p = (player) ? (Player)sender : null; - // If not exactly one argument, must be an invalid command. - if (args.length != 1) + if (args.length == 0) return false; - // Exactly one argument, return whatever simpleCommands returns. - return basicCommands(p, args[0].toLowerCase()); - } - - /** - * Handles basic commands. - */ - private boolean basicCommands(Player p, String cmd) - { - if (cmd.equals("join") || cmd.equals("j")) - { - ArenaManager.playerJoin(p); - return true; - } - - if (cmd.equals("leave") || cmd.equals("l")) - { - ArenaManager.playerLeave(p); - return true; - } - - if (cmd.equals("list") || cmd.equals("who")) - { - ArenaManager.playerList(p); - return true; - } + // Grab the command base and any arguments. + String base = args[0].toLowerCase(); + String arg1 = (args.length > 1) ? args[1].toLowerCase() : ""; + String arg2 = (args.length > 2) ? args[2].toLowerCase() : ""; - if (cmd.equals("spectate") || cmd.equals("spec")) - { - ArenaManager.playerSpectate(p); - return true; - } - - if (cmd.equals("ready") || cmd.equals("notready")) - { - ArenaManager.notReadyList(p); - return true; - } - return false; - } - - /** - * Handles advanced commands, mainly for setting up the arena. - */ - private boolean advancedCommands(Player p, String[] args) - { - String cmd = args[0].toLowerCase(); - String arg = args[1].toLowerCase(); - // ma enabled [true|false] - if (cmd.equals("enabled")) - { - if (!arg.equals("true") && !arg.equals("false")) + /*//////////////////////////////////////////////////////////////// + // + // Basics + // + ////////////////////////////////////////////////////////////////*/ + + /* + * Player join + */ + if (base.equals("join") || base.equals("j")) + { + if (!player || !MobArena.has(p, "mobarena.use.join")) { - ArenaManager.tellPlayer(p, "/ma enabled [true|false]"); - return true; - } - - // Set the boolean - ArenaManager.isEnabled = Boolean.valueOf(arg); - ArenaManager.tellPlayer(p, "Enabled: " + arg); - return true; - } - - if (cmd.equals("check")) - { - if (!arg.equals("updates")) - { - ArenaManager.tellPlayer(p, "/ma check updates"); - return true; - } - - MAUtils.checkForUpdates(p, true); - return true; - } - - // ma force [start|end] - if (cmd.equals("force")) - { - // Start arena. - if (arg.equals("start")) - { - ArenaManager.forceStart(p); + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); return true; } - // End the arena. - if (arg.equals("end")) + boolean error; + + if (!arg1.isEmpty()) { - ArenaManager.forceEnd(p); + Arena arena = am.getArenaWithName(arg1); + + // Crap-load of sanity-checks. + if (!am.enabled) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_NOT_ENABLED)); + else if (arena == null) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.ARENA_DOES_NOT_EXIST)); + else if (am.arenaMap.containsKey(p) && am.arenaMap.get(p).livePlayers.contains(p)) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_IN_OTHER_ARENA)); + else if (!arena.enabled) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_ARENA_NOT_ENABLED)); + else if (!arena.setup) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_ARENA_NOT_SETUP)); + else if (arena.running) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_ARENA_IS_RUNNING)); + else if (arena.livePlayers.contains(p)) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_ALREADY_PLAYING)); + else if (arena.emptyInvJoin && !MAUtils.hasEmptyInventory(p)) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_EMPTY_INV)); + else if (!arena.emptyInvJoin && !MAUtils.storeInventory(p)) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_STORE_INV_FAIL)); + else error = false; + + // If there was an error, don't join. + if (error) + return true; + + am.arenaMap.put(p,arena); + arena.playerJoin(p, p.getLocation()); + + MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_PLAYER_JOINED)); + return true; + } + else + { + if (am.arenas.size() < 1) + { + MAUtils.tellPlayer(sender, "There are no arenas loaded. Check your config-file."); + return true; + } + + Arena arena = am.arenas.get(0); + + if (!am.enabled) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_NOT_ENABLED)); + else if (am.arenas.size() > 1) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_ARG_NEEDED)); + else if (arena == null) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.ARENA_DOES_NOT_EXIST)); + else if (am.arenaMap.containsKey(p) && am.arenaMap.get(p).livePlayers.contains(p)) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_IN_OTHER_ARENA)); + else if (!arena.enabled) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_ARENA_NOT_ENABLED)); + else if (!arena.setup) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_ARENA_NOT_SETUP)); + else if (arena.running) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_ARENA_IS_RUNNING)); + else if (arena.livePlayers.contains(p)) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_ALREADY_PLAYING)); + else if (arena.emptyInvJoin && !MAUtils.hasEmptyInventory(p)) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_EMPTY_INV)); + else if (!arena.emptyInvJoin && !MAUtils.storeInventory(p)) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_STORE_INV_FAIL)); + else error = false; + + // If there was an error, don't join. + if (error) + return true; + + am.arenaMap.put(p,arena); + arena.playerJoin(p, p.getLocation()); + + MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_PLAYER_JOINED)); + return true; + } + } + + /* + * Player leave + */ + if (base.equals("leave") || base.equals("l")) + { + if (!player || !MobArena.has(p, "mobarena.use.leave")) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); return true; } - ArenaManager.tellPlayer(p, "/ma force [start|end]"); + if (!am.arenaMap.containsKey(p)) + { + Arena arena = am.getArenaWithSpectator(p); + if (arena != null) + { + arena.playerLeave(p); + MAUtils.tellPlayer(p, MAMessages.get(Msg.LEAVE_PLAYER_LEFT)); + return true; + } + + MAUtils.tellPlayer(p, MAMessages.get(Msg.LEAVE_NOT_PLAYING)); + return true; + } + + Arena arena = am.arenaMap.remove(p); + arena.playerLeave(p); + MAUtils.tellPlayer(p, MAMessages.get(Msg.LEAVE_PLAYER_LEFT)); return true; } - // ma config reload - if (cmd.equals("config")) + /* + * Player spectate + */ + if (base.equals("spectate") || base.equals("spec")) { - if (!arg.equals("reload")) + if (!player || !MobArena.has(p, "mobarena.use.spectate")) { - ArenaManager.tellPlayer(p, "/ma config reload"); + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); return true; } - - // End the arena. - ArenaManager.init(ArenaManager.plugin); - ArenaManager.tellPlayer(p, "Config-file was reloaded."); - return true; - } - - // ma setwarp [arena|lobby|spectator] - if (cmd.equals("setwarp")) - { - if (!arg.equals("arena") && !arg.equals("lobby") && !arg.equals("spectator")) - { - ArenaManager.tellPlayer(p, "/ma setwarp [arena|lobby|spectator]"); - return true; - } - - // Write the coordinate data to the config-file. - MAUtils.setCoords(arg, p.getLocation().getBlock().getRelative(0,1,0).getLocation()); - ArenaManager.tellPlayer(p, "Warp point \"" + arg + "\" set."); - MAUtils.notifyIfSetup(p); + boolean error; + Arena arena = null; + + if (!arg1.isEmpty()) + { + arena = am.getArenaWithName(arg1); + + if (!am.enabled) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_NOT_ENABLED)); + else if (am.arenaMap.containsKey(p)) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.SPEC_ALREADY_PLAYING)); + else if (arena == null) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.ARENA_DOES_NOT_EXIST)); + else if (arena.emptyInvSpec && !MAUtils.hasEmptyInventory(p)) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.SPEC_EMPTY_INV)); + else error = false; + + if (error) + return true; + } + else + { + arena = am.arenas.get(0); + + if (!am.enabled) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_NOT_ENABLED)); + else if (am.arenaMap.containsKey(p)) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.SPEC_ALREADY_PLAYING)); + else if (am.arenas.size() > 1) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.JOIN_ARG_NEEDED)); + else if (arena == null) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.ARENA_DOES_NOT_EXIST)); + else if (arena.emptyInvSpec && !MAUtils.hasEmptyInventory(p)) + error = MAUtils.tellPlayer(p, MAMessages.get(Msg.SPEC_EMPTY_INV)); + else error = false; + + if (error) + return true; + } + + arena.playerSpec(p, p.getLocation()); + MAUtils.tellPlayer(p, MAMessages.get(Msg.SPEC_PLAYER_SPECTATE)); return true; } - // ma addspawn - if (cmd.equals("addspawn")) - { - // The name must start with a letter, followed by any letter(s) or number(s). - if (!arg.matches("[a-z]+([[0-9][a-z]])*")) - { - ArenaManager.tellPlayer(p, "Name must consist of only letters a-z and numbers 0-9"); - return true; - } - - // Write the coordinate data to the config-file. - MAUtils.setCoords("spawnpoints." + arg, p.getLocation().getBlock().getRelative(0,1,0).getLocation()); - - ArenaManager.tellPlayer(p, "Spawn point with name \"" + arg + "\" added."); - MAUtils.notifyIfSetup(p); + /* + * Prints a list of all arenas. + */ + if (base.equals("arenas")) + { + String list = MAUtils.listToString(am.arenas); + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_LIST_ARENAS, list)); return true; } - // ma delspawn - if (cmd.equals("delspawn")) + /* + * Prints a list of all live players in all arenas, or live players in a specific arena. + */ + if (base.equals("players") || base.equals("list")) { - // The name must start with a letter, followed by any letter(s) or number(s). - if (!arg.matches("[a-z]+([[0-9][a-z]])*")) + if (!arg1.isEmpty()) { - ArenaManager.tellPlayer(p, "Name must consist of only letters a-z and numbers 0-9"); - return true; + Arena arena = am.getArenaWithName(arg1); + if (arena == null) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.ARENA_DOES_NOT_EXIST)); + return true; + } + + String list = MAUtils.listToString(arena.getLivingPlayers()); + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_LIST_PLAYERS, list)); } - - // If the spawnpoint does not exist, notify the player. - if (MAUtils.getCoords("spawnpoints." + arg) == null) + else { - ArenaManager.tellPlayer(p, "Couldn't find spawnpoint \"" + arg + "\"."); - ArenaManager.tellPlayer(p, "Spawnpoints: " + MAUtils.spawnList()); - return true; + StringBuffer buffy = new StringBuffer(); + for (Arena arena : am.arenas) + buffy.append(MAUtils.listToString(arena.getLivingPlayers(), false)); + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_LIST_PLAYERS, buffy.toString())); } - - MAUtils.delCoords("coords.spawnpoints." + arg); - - ArenaManager.tellPlayer(p, "Spawn point with name \"" + arg + "\" removed."); - MAUtils.notifyIfSetup(p); return true; } - // ma setregion [p1|p2] - if (cmd.equals("setregion")) + /* + * Prints a list of all non-ready players in current arena, or non-ready players in a specific arena. + */ + if (base.equals("notready")) { - if (!arg.equals("p1") && !arg.equals("p2")) + Arena arena; + if (!arg1.isEmpty()) { - ArenaManager.tellPlayer(p, "/ma setregion [p1|p2]"); + arena = am.getArenaWithName(arg1); + if (arena == null) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.ARENA_DOES_NOT_EXIST)); + return true; + } + } + else if (player) + { + arena = am.getArenaWithPlayer(p); + if (arena == null) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.LEAVE_NOT_PLAYING)); + return true; + } + } + else + { + MAUtils.tellPlayer(sender, "Usage: /ma notready "); return true; } - MAUtils.setCoords(arg, p.getLocation()); - MAUtils.fixCoords(); - - ArenaManager.tellPlayer(p, "Region point \"" + arg + "\" set."); - MAUtils.notifyIfSetup(p); + String list = MAUtils.listToString(arena.getNonreadyPlayers()); + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_LIST_PLAYERS, list)); return true; } - - // ma expandregion [up|down|out] - if (cmd.equals("expandregion")) - { - if (ArenaManager.p1 == null || ArenaManager.p2 == null) - { - ArenaManager.tellPlayer(p, "Set up region points first: /ma setregion [p1|p2]"); - return true; - } - if (!arg.equals("up") && !arg.equals("down") && !arg.equals("out")) - { - ArenaManager.tellPlayer(p, "/ma expandregion [up|down|out] "); - return true; - } - - if (args.length != 3 || !args[2].matches("[0-9]+")) - return false; - - int i = Integer.parseInt(args[2]); - MAUtils.expandRegion(arg, i); - - ArenaManager.tellPlayer(p, "Region expanded " + arg + " by " + i + " blocks."); - return true; - } - - // ma reset coords - if (cmd.equals("reset")) - { - if (!arg.equals("coords")) - return false; - - MAUtils.delCoords("coords"); - ArenaManager.tellPlayer(p, "All arena coords have been reset."); - return true; - } - - // ma protect [true|false] - if (cmd.equals("protect")) - { - if (!arg.equals("true") && !arg.equals("false")) - return false; - - // Set the boolean - ArenaManager.isProtected = Boolean.valueOf(arg); - - ArenaManager.tellPlayer(p, "Region protection: " + arg); - return true; - } - - // ma dooooo it hippie monster - if (cmd.equals("dooooo")) - { - if (args.length != 4) - return false; - - if (args[1].equals("it") && args[2].equals("hippie") && args[3].equals("monster")) - { - MAUtils.DoooooItHippieMonster(p.getLocation(), 13); - ArenaManager.tellPlayer(p, "Auto-generated a working MobArena!"); - return true; - } - } - // ma undo it hippie monster - if (cmd.equals("undo")) + + + /*//////////////////////////////////////////////////////////////// + // + // Setup & Reload + // + ////////////////////////////////////////////////////////////////*/ + + /* + * Enable or disable arena(s) + */ + if ((base.equals("enable") || base.equals("disable"))) { - if (args.length != 4) - return false; - - if (args[1].equals("it") && args[2].equals("hippie") && args[3].equals("monster")) + if (!console && !(player && MobArena.has(p, "mobarena.admin.enable")) && !op) { - MAUtils.UnDoooooItHippieMonster(); - ArenaManager.tellPlayer(p, "Restored your precious little patch >_>"); + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + + if (!arg1.isEmpty()) + { + Arena arena = am.getArenaWithName(arg1); + if (arena != null) + { + arena.enabled = base.equals("enable"); + arena.serializeConfig(); + MAUtils.tellPlayer(sender, "Arena '" + arena.configName() + "' " + ((arena.enabled) ? ChatColor.GREEN : ChatColor.RED) + base + "d"); + } + else + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.ARENA_DOES_NOT_EXIST)); + } + } + else + { + am.enabled = base.equals("enable"); + am.serializeSettings(); + MAUtils.tellPlayer(sender, "All arenas " + ((am.enabled) ? ChatColor.GREEN : ChatColor.RED) + base + "d"); + } + return true; + } + + /* + * Enable or disable protection + */ + if (base.equals("protect")) + { + if (!console && !(player && MobArena.has(p, "mobarena.admin.protect")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + if (arg1.isEmpty() || !arg1.matches("^[a-zA-Z][a-zA-Z0-9_]*$") || !(arg2.equals("true") || arg2.equals("false"))) + { + MAUtils.tellPlayer(sender, "Usage: /ma protect [true|false]"); + return true; + } + + Arena arena = am.getArenaWithName(arg1); + if (arena == null) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.ARENA_DOES_NOT_EXIST)); + return true; + } + + arena.protect = arg2.equals("true"); + arena.serializeConfig(); + arena.load(plugin.getConfig()); + MAUtils.tellPlayer(sender, "Protection for arena '" + arg1 + "' set to " + arg2); + return true; + } + + /* + * Restore a player's inventory. + */ + if (base.equals("restore")) + { + if (!console && !(player && MobArena.has(p, "mobarena.admin.restore")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + + if (!arg1.isEmpty()) + { + if (am.getArenaWithPlayer(arg1) != null) + { + MAUtils.tellPlayer(sender, "Player is currently in an arena."); + return true; + } + + if (MAUtils.restoreInventory(Bukkit.getServer().getPlayer(arg1))); + MAUtils.tellPlayer(sender, "Restored " + arg1 + "'s inventory!"); return true; } } - return false; + /* + * Force start/end arenas. + */ + if (base.equals("force") && arg1.equals("end")) + { + if (arg1.equals("end")) + { + if (!console && !(player && MobArena.has(p, "mobarena.admin.force.end")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + + if (arg2.isEmpty()) + { + for (Arena arena : am.arenas) + arena.forceEnd(); + + am.arenaMap.clear(); + return true; + } + + Arena arena = am.getArenaWithName(arg2); + if (arena == null) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.ARENA_DOES_NOT_EXIST)); + return true; + } + + if (arena.livePlayers.isEmpty()) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.FORCE_END_EMPTY)); + return true; + } + + arena.forceEnd(); + MAUtils.tellPlayer(sender, MAMessages.get(Msg.FORCE_END_ENDED)); + return true; + } + else if (arg1.equals("start")) + { + if (!console && !(player && MobArena.has(p, "mobarena.admin.force.start")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + + if (arg2.isEmpty()) + { + MAUtils.tellPlayer(sender, "Usage: /ma force start "); + return true; + } + + Arena arena = am.getArenaWithName(arg2); + if (arena == null) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.ARENA_DOES_NOT_EXIST)); + return true; + } + + if (arena.running) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.FORCE_START_RUNNING)); + return true; + } + if (arena.readyPlayers.isEmpty()) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.FORCE_START_NOT_READY)); + return true; + } + + arena.forceStart(); + MAUtils.tellPlayer(sender, MAMessages.get(Msg.FORCE_START_STARTED)); + return true; + } + else + { + MAUtils.tellPlayer(sender, "Usage: /ma force [start|end] ()"); + return true; + } + } + + /* + * Reload the config-file. + */ + if (base.equals("config")) + { + if (!console && !(player && MobArena.has(p, "mobarena.admin.config.reload")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + + if (!arg1.equals("reload")) + { + MAUtils.tellPlayer(sender, "Usage: /ma config reload"); + return true; + } + + am.updateAll(); + MAUtils.tellPlayer(sender, "Config reloaded."); + return true; + } + + /* + * Get the current arena, and list all other arenas. + */ + if (base.equals("arena")) + { + if (!console && !(player && MobArena.has(p, "mobarena.setup.arena")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + + MAUtils.tellPlayer(sender, "Currently selected arena: " + ChatColor.GREEN + am.selectedArena.configName()); + + StringBuffer buffy = new StringBuffer(); + if (am.arenas.size() > 1) + { + for (Arena arena : am.arenas) + if (!arena.equals(am.selectedArena)) + buffy.append(arena.configName() + " "); + } + else buffy.append(MAMessages.get(Msg.MISC_NONE)); + + MAUtils.tellPlayer(sender, "Other arenas: " + buffy.toString()); + return true; + } + + /* + * Set the current arena + */ + if (base.equals("setarena")) + { + if (!console && !(player && MobArena.has(p, "mobarena.setup.setarena")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + if (arg1.isEmpty()) + { + MAUtils.tellPlayer(sender, "Usage: /ma setarena "); + return true; + } + + Arena arena = am.getArenaWithName(arg1); + if (arena != null) + { + am.selectedArena = arena; + MAUtils.tellPlayer(sender, "Currently selected arena: " + arena.configName()); + } + else + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.ARENA_DOES_NOT_EXIST)); + } + return true; + } + + /* + * Create a new arena, and set the current arena to this new arena. + */ + if (base.equals("addarena")) + { + if (!(player && MobArena.has(p, "mobarena.setup.addarena")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + if (arg1.isEmpty()) + { + MAUtils.tellPlayer(sender, "Usage: /ma addarena "); + return true; + } + + Arena arena = am.getArenaWithName(arg1); + if (arena != null) + { + MAUtils.tellPlayer(sender, "An arena with that name already exists."); + return true; + } + + arena = am.createArenaNode(arg1, p.getWorld()); + am.arenas.add(arena); + am.selectedArena = arena; + + MAUtils.tellPlayer(sender, "New arena with name '" + arg1 + "' created!"); + return true; + } + + if (base.equals("delarena")) + { + if (!console && !(player && MobArena.has(p, "mobarena.setup.delarena")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + if (arg1.isEmpty()) + { + MAUtils.tellPlayer(sender, "Usage: /ma delarena "); + return true; + } + if (am.arenas.size() < 2) + { + MAUtils.tellPlayer(sender, "At least one arena must exist."); + return true; + } + + Arena arena = am.getArenaWithName(arg1); + if (arena == null) + { + MAUtils.tellPlayer(sender, "There is no arena with that name."); + return true; + } + + am.removeArenaNode(arg1); + am.arenas.remove(arena); + am.selectedArena = (am.selectedArena.equals(arena)) ? am.arenas.get(0) : am.selectedArena; + + MAUtils.tellPlayer(sender, "Arena '" + arena.configName() + "' deleted."); + return true; + } + + if (base.equals("editarena")) + { + if (!console && !(player && MobArena.has(p, "mobarena.setup.editarena")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + if (arg1.isEmpty() || !(arg2.equals("true") || arg2.equals("false"))) + { + MAUtils.tellPlayer(sender, "Usage: /ma editarena [true|false]"); + return true; + } + + Arena arena = am.getArenaWithName(arg1); + if (arena == null) + { + MAUtils.tellPlayer(sender, "There is no arena with that name."); + return true; + } + + arena.edit = arg2.equals("true"); + MAUtils.tellPlayer(sender, "Edit mode for arena '" + arg1 + "': " + ((arena.edit) ? ChatColor.GREEN + "true" : ChatColor.RED + "false")); + if (arena.edit) MAUtils.tellPlayer(sender, "Remember to turn it back off after editing!"); + return true; + } + + /* + * Set region points [p1|p2] for the current arena. + */ + if (base.equals("setregion")) + { + if (!(player && MobArena.has(p, "mobarena.setup.setregion")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + + if (!(arg1.equals("p1") || arg1.equals("p2"))) + { + MAUtils.tellPlayer(sender, "Usage: /ma setregion [p1|p2]"); + return true; + } + + MAUtils.setArenaCoord(plugin.getConfig(), am.selectedArena, arg1, p.getLocation()); + MAUtils.tellPlayer(sender, "Set region point " + arg1 + " for arena '" + am.selectedArena.configName() + "'"); + return true; + } + + /* + * Expand the region (arg1) [up|down|out] + */ + if (base.equals("expandregion")) + { + if (!console && !(player && MobArena.has(p, "mobarena.setup.expandregion")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + if (args.length != 3 || !arg1.matches("[0-9]+")) + { + MAUtils.tellPlayer(sender, "Usage: /ma expandregion [up|down|out]"); + return true; + } + + if (arg2.equals("up")) + { + am.selectedArena.p2.setY(Math.min(127, am.selectedArena.p2.getY() + Integer.parseInt(arg1))); + } + else if (arg2.equals("down")) + { + am.selectedArena.p1.setY(Math.max(0, am.selectedArena.p1.getY() - Integer.parseInt(arg1))); + } + else if (arg2.equals("out")) + { + am.selectedArena.p1.setX(am.selectedArena.p1.getX() - Integer.parseInt(arg1)); + am.selectedArena.p1.setZ(am.selectedArena.p1.getZ() - Integer.parseInt(arg1)); + am.selectedArena.p2.setX(am.selectedArena.p2.getX() + Integer.parseInt(arg1)); + am.selectedArena.p2.setZ(am.selectedArena.p2.getZ() + Integer.parseInt(arg1)); + } + else + { + MAUtils.tellPlayer(sender, "Usage: /ma expandregion [up|down|out]"); + return true; + } + + MAUtils.tellPlayer(sender, "Region for '" + am.selectedArena.configName() + "' expanded " + arg2 + " by " + arg1 + " blocks."); + am.selectedArena.serializeConfig(); + am.selectedArena.load(plugin.getConfig()); + return true; + } + + /* + * Set warp points [arena|lobby|spectator] for the current arena. + */ + if (base.equals("setwarp")) + { + if (!(player && MobArena.has(p, "mobarena.setup.setwarp")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + if (!(arg1.equals("arena") || arg1.equals("lobby") || arg1.equals("spectator"))) + { + MAUtils.tellPlayer(sender, "Usage: /ma setwarp [arena|lobby|spectator]"); + return true; + } + + MAUtils.setArenaCoord(plugin.getConfig(), am.selectedArena, arg1, p.getLocation().getBlock().getRelative(0,1,0).getLocation()); + MAUtils.tellPlayer(sender, "Set warp point " + arg1 + " for arena '" + am.selectedArena.configName() + "'"); + return true; + } + + /* + * List all the current spawnpoints for the current arena. + */ + if (base.equals("spawnpoints")) + { + if (!console && !(player && MobArena.has(p, "mobarena.setup.spawnpoints")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + + StringBuffer buffy = new StringBuffer(); + List spawnpoints = plugin.getConfig().getKeys("arenas." + am.selectedArena.configName() + ".coords.spawnpoints"); + + if (spawnpoints != null) + { + for (String s : spawnpoints) + { + buffy.append(s); + buffy.append(" "); + } + } + else + { + buffy.append(MAMessages.get(Msg.MISC_NONE)); + } + + MAUtils.tellPlayer(sender, "Spawnpoints for arena '" + am.selectedArena.configName() + "': " + buffy.toString()); + return true; + } + + /* + * Add a spawnpoint for the current arena. + */ + if (base.equals("addspawn")) + { + if (!(player && MobArena.has(p, "mobarena.setup.addspawn")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + if (arg1 == null || !arg1.matches("^[a-zA-Z][a-zA-Z0-9]*$")) + { + MAUtils.tellPlayer(sender, "Usage: /ma addspawn "); + return true; + } + + MAUtils.setArenaCoord(plugin.getConfig(), am.selectedArena, "spawnpoints." + arg1, p.getLocation()); + MAUtils.tellPlayer(sender, "Added spawnpoint " + arg1 + " for arena \"" + am.selectedArena.configName() + "\""); + return true; + } + + /* + * Delete a spawnpoint for the current arena. + */ + if (base.equals("delspawn")) + { + if (!console && !(player && MobArena.has(p, "mobarena.setup.delspawn")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + if (arg1 == null || !arg1.matches("^[a-zA-Z][a-zA-Z0-9]*$")) + { + MAUtils.tellPlayer(sender, "Usage: /ma delspawn "); + return true; + } + + if (MAUtils.delArenaCoord(plugin.getConfig(), am.selectedArena, "spawnpoints." + arg1)) + MAUtils.tellPlayer(sender, "Deleted spawnpoint " + arg1 + " for arena '" + am.selectedArena.configName() + "'"); + else + MAUtils.tellPlayer(sender, "Could not find the spawnpoint " + arg1 + "for the arena '" + am.selectedArena.configName() + "'"); + return true; + } + + if (base.equals("auto-generate")) + { + if (!(player && MobArena.has(p, "mobarena.setup.autogenerate")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + if (arg1 == null || !arg1.matches("^[a-zA-Z][a-zA-Z0-9]*$")) + { + MAUtils.tellPlayer(sender, "Usage: /ma autogenerate "); + return true; + } + if (am.getArenaWithName(arg1) != null) + { + MAUtils.tellPlayer(sender, "An arena with that name already exists."); + return true; + } + + if (MAUtils.doooooItHippieMonster(p.getLocation(), 13, arg1, plugin)) + MAUtils.tellPlayer(sender, "Arena with name '" + arg1 + "' generated."); + else + MAUtils.tellPlayer(sender, "Could not auto-generate arena."); + return true; + } + + if (base.equals("auto-degenerate")) + { + if (!console && !(player && MobArena.has(p, "mobarena.setup.autodegenerate")) && !op) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.MISC_NO_ACCESS)); + return true; + } + if (arg1.isEmpty()) + { + MAUtils.tellPlayer(sender, "Usage: /ma auto-degenerate "); + return true; + } + if (am.arenas.size() < 2) + { + MAUtils.tellPlayer(sender, "At least one arena must exist!"); + return true; + } + if (am.getArenaWithName(arg1) == null) + { + MAUtils.tellPlayer(sender, MAMessages.get(Msg.ARENA_DOES_NOT_EXIST)); + return true; + } + + if (MAUtils.undoItHippieMonster(arg1, plugin, true)) + MAUtils.tellPlayer(sender, "Arena with name '" + arg1 + "' degenerated."); + else + MAUtils.tellPlayer(sender, "Could not degenerate arena."); + return true; + } + + MAUtils.tellPlayer(sender, "Command not found."); + return true; } } \ No newline at end of file diff --git a/src/com/garbagemule/MobArena/MAEntityListener.java b/src/com/garbagemule/MobArena/MAEntityListener.java new file mode 100644 index 0000000..d51e118 --- /dev/null +++ b/src/com/garbagemule/MobArena/MAEntityListener.java @@ -0,0 +1,65 @@ +package com.garbagemule.MobArena; + +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.entity.EntityCombustEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.event.entity.EntityListener; +import org.bukkit.event.entity.EntityRegainHealthEvent; +import org.bukkit.event.entity.EntityTargetEvent; + +import com.garbagemule.MobArena.Arena; +import com.garbagemule.MobArena.ArenaMaster; + +public class MAEntityListener extends EntityListener +{ + private ArenaMaster am; + + public MAEntityListener(ArenaMaster am) + { + this.am = am; + } + + public void onEntityRegainHealth(EntityRegainHealthEvent event) + { + for (Arena arena : am.arenas) + arena.onEntityRegainHealth(event); + } + + public void onEntityDeath(EntityDeathEvent event) + { + for (Arena arena : am.arenas) + arena.onEntityDeath(event); + } + + public void onEntityDamage(EntityDamageEvent event) + { + for (Arena arena : am.arenas) + arena.onEntityDamage(event); + } + + public void onCreatureSpawn(CreatureSpawnEvent event) + { + for (Arena arena : am.arenas) + arena.onCreatureSpawn(event); + } + + public void onEntityExplode(EntityExplodeEvent event) + { + for (Arena arena : am.arenas) + arena.onEntityExplode(event); + } + + public void onEntityCombust(EntityCombustEvent event) + { + for (Arena arena : am.arenas) + arena.onEntityCombust(event); + } + + public void onEntityTarget(EntityTargetEvent event) + { + for (Arena arena : am.arenas) + arena.onEntityTarget(event); + } +} \ No newline at end of file diff --git a/src/com/garbagemule/MobArena/MAInventoryItem.java b/src/com/garbagemule/MobArena/MAInventoryItem.java new file mode 100644 index 0000000..ad33c45 --- /dev/null +++ b/src/com/garbagemule/MobArena/MAInventoryItem.java @@ -0,0 +1,22 @@ +package com.garbagemule.MobArena; + +import java.io.Serializable; + +public class MAInventoryItem implements Serializable +{ + private static final long serialVersionUID = 739709220350581510L; + private int typeId; + private int amount; + private short durability; + + public MAInventoryItem(int typeId, int amount, short durability) + { + this.typeId = typeId; + this.amount = amount; + this.durability = durability; + } + + public int getTypeId() { return typeId; } + public int getAmount() { return amount; } + public short getDurability() { return durability; } +} diff --git a/src/com/garbagemule/MobArena/MAMessages.java b/src/com/garbagemule/MobArena/MAMessages.java new file mode 100644 index 0000000..0a735b2 --- /dev/null +++ b/src/com/garbagemule/MobArena/MAMessages.java @@ -0,0 +1,232 @@ +package com.garbagemule.MobArena; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.util.HashMap; +import java.util.Map; + +public class MAMessages +{ + protected static Map msgMap; + private static Map defaults = new HashMap(); + protected static enum Msg + { + ARENA_START, + ARENA_END, + ARENA_DOES_NOT_EXIST, + JOIN_PLAYER_JOINED, + JOIN_NOT_ENABLED, + JOIN_IN_OTHER_ARENA, + JOIN_ARENA_NOT_ENABLED, + JOIN_ARENA_NOT_SETUP, + JOIN_ARENA_IS_RUNNING, + JOIN_ALREADY_PLAYING, + JOIN_ARG_NEEDED, + JOIN_EMPTY_INV, + JOIN_STORE_INV_FAIL, + LEAVE_PLAYER_LEFT, + LEAVE_NOT_PLAYING, + PLAYER_DIED, + SPEC_PLAYER_SPECTATE, + SPEC_NOT_RUNNING, + SPEC_ARG_NEEDED, + SPEC_EMPTY_INV, + SPEC_ALREADY_PLAYING, + NOT_READY_PLAYERS, + FORCE_START_STARTED, + FORCE_START_RUNNING, + FORCE_START_NOT_READY, + FORCE_END_ENDED, + FORCE_END_EMPTY, + FORCE_END_IDLE, + REWARDS_GIVE, + LOBBY_CLASS_PICKED, + LOBBY_CLASS_PERMISSION, + LOBBY_PLAYER_READY, + LOBBY_DROP_ITEM, + LOBBY_PICK_CLASS, + LOBBY_RIGHT_CLICK, + WARP_TO_ARENA, + WARP_FROM_ARENA, + WAVE_DEFAULT, + WAVE_SPECIAL, + WAVE_REWARD, + // Misc + MISC_LIST_ARENAS, + MISC_LIST_PLAYERS, + MISC_COMMAND_NOT_ALLOWED, + MISC_NO_ACCESS, + MISC_NONE + } + + // Populate the defaults map. + static + { + defaults.put(Msg.ARENA_START, "Let the slaughter begin!"); + defaults.put(Msg.ARENA_END, "Arena finished."); + defaults.put(Msg.ARENA_DOES_NOT_EXIST, "That arena does not exist. Type /ma arenas for a list."); + defaults.put(Msg.JOIN_NOT_ENABLED, "MobArena is not enabled."); + defaults.put(Msg.JOIN_IN_OTHER_ARENA, "You are already in an arena! Leave that one first."); + defaults.put(Msg.JOIN_ARENA_NOT_ENABLED, "This arena is not enabled."); + defaults.put(Msg.JOIN_ARENA_NOT_SETUP, "This arena has not been set up yet."); + defaults.put(Msg.JOIN_ARENA_IS_RUNNING, "This arena is in already progress."); + defaults.put(Msg.JOIN_ALREADY_PLAYING, "You are already playing!"); + defaults.put(Msg.JOIN_ARG_NEEDED, "You must specify an arena. Type /ma arenas for a list."); + defaults.put(Msg.JOIN_EMPTY_INV, "You must empty your inventory to join the arena."); + defaults.put(Msg.JOIN_STORE_INV_FAIL, "Failed to store inventory. Try again."); + defaults.put(Msg.JOIN_PLAYER_JOINED, "You joined the arena. Have fun!"); + defaults.put(Msg.LEAVE_NOT_PLAYING, "You are not in the arena."); + defaults.put(Msg.LEAVE_PLAYER_LEFT, "You left the arena. Thanks for playing!"); + defaults.put(Msg.PLAYER_DIED, "% died!"); + defaults.put(Msg.SPEC_PLAYER_SPECTATE, "Enjoy the show!"); + defaults.put(Msg.SPEC_NOT_RUNNING, "This arena isn't running."); + defaults.put(Msg.SPEC_ARG_NEEDED, "You must specify an arena. Type /ma arenas for a list."); + defaults.put(Msg.SPEC_EMPTY_INV, "Empty your inventory first!"); + defaults.put(Msg.SPEC_ALREADY_PLAYING, "Can't spectate when in the arena!"); + defaults.put(Msg.NOT_READY_PLAYERS, "Not ready: %"); + defaults.put(Msg.FORCE_START_RUNNING, "Arena has already started."); + defaults.put(Msg.FORCE_START_NOT_READY, "Can't force start, no players are ready."); + defaults.put(Msg.FORCE_START_STARTED, "Forced arena start."); + defaults.put(Msg.FORCE_END_EMPTY, "No one is in the arena."); + defaults.put(Msg.FORCE_END_ENDED, "Forced arena end."); + defaults.put(Msg.FORCE_END_IDLE, "You weren't quick enough!"); + defaults.put(Msg.REWARDS_GIVE, "Here are all of your rewards!"); + defaults.put(Msg.LOBBY_DROP_ITEM, "No sharing before the arena starts!"); + defaults.put(Msg.LOBBY_PLAYER_READY, "You have been flagged as ready!"); + defaults.put(Msg.LOBBY_PICK_CLASS, "You must first pick a class!"); + defaults.put(Msg.LOBBY_RIGHT_CLICK, "Punch the sign. Don't right-click."); + defaults.put(Msg.LOBBY_CLASS_PICKED, "You have chosen % as your class!"); + defaults.put(Msg.LOBBY_CLASS_PERMISSION, "You don't have permission to use this class!"); + defaults.put(Msg.WARP_TO_ARENA, "Can't warp to the arena during battle!"); + defaults.put(Msg.WARP_FROM_ARENA, "Warping not allowed in the arena!"); + defaults.put(Msg.WAVE_DEFAULT, "Get ready for wave #%!"); + defaults.put(Msg.WAVE_SPECIAL, "Get ready for wave #%! [SPECIAL]"); + defaults.put(Msg.WAVE_REWARD, "You just earned a reward: %"); + defaults.put(Msg.MISC_LIST_PLAYERS, "Live players: %"); + defaults.put(Msg.MISC_LIST_ARENAS, "Available arenas: %"); + defaults.put(Msg.MISC_COMMAND_NOT_ALLOWED, "You can't use that command in the arena!"); + defaults.put(Msg.MISC_NO_ACCESS, "You don't have access to this comand."); + defaults.put(Msg.MISC_NONE, ""); + } + + /** + * Initializes the msgMap by reading from the announcements-file. + */ + public static void init(MobArena plugin, boolean update) + { + // Use defaults in case of any errors. + msgMap = defaults; + + // Grab the announcements-file. + File msgFile; + try + { + msgFile = new File(plugin.getDataFolder(), "announcements.properties"); + + // If it doesn't exist, create it. + if (!msgFile.exists()) + { + System.out.println("[MobArena] Announcements-file not found. Creating one..."); + msgFile.createNewFile(); + + FileWriter fw = new FileWriter(msgFile); + BufferedWriter bw = new BufferedWriter(fw); + + // Write default announcements to the file. + for (Msg m : Msg.values()) + { + bw.write(m.toString() + "=" + defaults.get(m)); + bw.newLine(); + } + bw.close(); + + return; + } + } + catch (Exception e) + { + System.out.println("[MobArena] ERROR: Couldn't initialize announcements-file. Using defaults."); + return; + } + + // If the file was found, populate the msgMap. + try + { + FileReader fr = new FileReader(msgFile); + BufferedReader br = new BufferedReader(fr); + + String s; + while ((s = br.readLine()) != null) + { + process(s); + } + br.close(); + } + catch (Exception e) + { + System.out.println("[MobArena] ERROR: Problem with announcements-file. Using defaults."); + return; + } + } + + public static void init(MobArena plugin) + { + init(plugin, false); + } + + /** + * Grabs the announcement from the msgMap, and in case of + * s not being null, replaces the % with s. + */ + public static String get(Msg msg, String s) + { + // If p is null, just return the announcement as is. + if (s == null) + return msgMap.get(msg); + + // Otherwise, replace the % with the input string. + return msgMap.get(msg).replace("%", s); + } + + /** + * Grabs the announcement from the msgMap. + */ + public static String get(Msg msg) + { + return get(msg, null); + } + + /** + * Helper-method for parsing the strings from the + * announcements-file. + */ + private static void process(String s) + { + // Split the string by the equals-sign. + String[] split = s.split("="); + if (split.length != 2) + { + System.out.println("[MobArena] ERROR: Couldn't parse \"" + s + "\". Check announcements-file."); + return; + } + + // For simplicity... + String key = split[0]; + String val = split[1]; + Msg msg; + + try + { + msg = Msg.valueOf(key); + msgMap.put(msg, val); + } + catch (Exception e) + { + System.out.println("[MobArena] ERROR: " + key + " is not a valid key. Check announcements-file."); + return; + } + } +} \ No newline at end of file diff --git a/src/com/garbagemule/MobArena/MAPlayerListener.java b/src/com/garbagemule/MobArena/MAPlayerListener.java new file mode 100644 index 0000000..9cb29dd --- /dev/null +++ b/src/com/garbagemule/MobArena/MAPlayerListener.java @@ -0,0 +1,87 @@ +package com.garbagemule.MobArena; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerBucketEmptyEvent; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.player.PlayerDropItemEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerKickEvent; +import org.bukkit.event.player.PlayerListener; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.player.PlayerTeleportEvent; + +public class MAPlayerListener extends PlayerListener +{ + private MobArena plugin; + private ArenaMaster am; + + public MAPlayerListener(MobArena plugin, ArenaMaster am) + { + this.plugin = plugin; + this.am = am; + } + + public void onPlayerInteract(PlayerInteractEvent event) + { + if (!am.enabled) return; + for (Arena arena : am.arenas) + arena.onPlayerInteract(event); + } + + public void onPlayerDropItem(PlayerDropItemEvent event) + { + if (!am.enabled) return; + for (Arena arena : am.arenas) + arena.onPlayerDropItem(event); + } + + public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) + { + if (!am.enabled) return; + for (Arena arena : am.arenas) + arena.onPlayerBucketEmpty(event); + } + + public void onPlayerTeleport(PlayerTeleportEvent event) + { + if (!am.enabled) return; + for (Arena arena : am.arenas) + arena.onPlayerTeleport(event); + } + + public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) + { + if (!am.enabled) return; + for (Arena arena : am.arenas) + arena.onPlayerCommandPreprocess(event); + } + + public void onPlayerQuit(PlayerQuitEvent event) + { + for (Arena arena : am.arenas) + arena.onPlayerQuit(event); + } + + public void onPlayerKick(PlayerKickEvent event) + { + for (Arena arena : am.arenas) + arena.onPlayerKick(event); + } + + public void onPlayerJoin(PlayerJoinEvent event) + { + if (!am.updateNotify || !event.getPlayer().isOp()) return; + + final Player p = event.getPlayer(); + Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, + new Runnable() + { + public void run() + { + MAUtils.checkForUpdates(plugin, p, false); + } + }, 100); + } +} diff --git a/src/com/garbagemule/MobArena/MASpawnThread.java b/src/com/garbagemule/MobArena/MASpawnThread.java index d0d25fb..23c6a64 100644 --- a/src/com/garbagemule/MobArena/MASpawnThread.java +++ b/src/com/garbagemule/MobArena/MASpawnThread.java @@ -1,6 +1,12 @@ package com.garbagemule.MobArena; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; import java.util.Random; +import java.util.Set; + import org.bukkit.Location; import org.bukkit.entity.Wolf; import org.bukkit.entity.Ghast; @@ -11,6 +17,9 @@ import org.bukkit.entity.Creature; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.CreatureType; +import org.bukkit.inventory.ItemStack; + +import com.garbagemule.MobArena.MAMessages.Msg; /** * Core class for handling wave spawning. @@ -20,92 +29,107 @@ import org.bukkit.entity.CreatureType; * host chooses. It is possible to create default waves that consist of * only one type of monster, or ones that have no creepers, for example. */ -// TO-DO: Allow custom special wave interval. -// TO-DO: Allow custom special wave monsters. -// TO-DO: Allow additional "default" waves. +// TODO: Allow custom special wave monsters. +// TODO: Allow additional "default" waves. public class MASpawnThread implements Runnable { - private int wave, ran, noOfSpawnPoints, noOfPlayers, modulo; + protected int wave, previousSize, taskId; + private int ran, noOfPlayers, modulo; private int dZombies, dSkeletons, dSpiders, dCreepers, dWolves; private int dPoweredCreepers, dPigZombies, dSlimes, dMonsters, dAngryWolves, dGiants, dGhasts; private Random random; - private String reward, currentRewards; + private MobArena plugin; + private Arena arena; + private final double MIN_DISTANCE = 256; - public MASpawnThread() + public MASpawnThread(MobArena plugin, Arena arena) { - modulo = ArenaManager.specialModulo; + this.plugin = plugin; + this.arena = arena; + modulo = arena.specialModulo; if (modulo <= 0) modulo = -32768; - noOfPlayers = ArenaManager.playerSet.size(); - noOfSpawnPoints = ArenaManager.spawnpoints.size(); + taskId = -32768; + + noOfPlayers = arena.livePlayers.size(); wave = 1; random = new Random(); // Set up the distribution variables for the random spawner. - dZombies = ArenaManager.dZombies; - dSkeletons = dZombies + ArenaManager.dSkeletons; - dSpiders = dSkeletons + ArenaManager.dSpiders; - dCreepers = dSpiders + ArenaManager.dCreepers; - dWolves = dCreepers + ArenaManager.dWolves; + dZombies = arena.distDefault.get("zombies"); + dSkeletons = dZombies + arena.distDefault.get("skeletons"); + dSpiders = dSkeletons + arena.distDefault.get("spiders"); + dCreepers = dSpiders + arena.distDefault.get("creepers"); + dWolves = dCreepers + arena.distDefault.get("wolves"); - dPoweredCreepers = ArenaManager.dPoweredCreepers; - dPigZombies = dPoweredCreepers + ArenaManager.dPigZombies; - dSlimes = dPigZombies + ArenaManager.dSlimes; - dMonsters = dSlimes + ArenaManager.dMonsters; - dAngryWolves = dMonsters + ArenaManager.dAngryWolves; - dGiants = dAngryWolves + ArenaManager.dGiants; - dGhasts = dGiants + ArenaManager.dGhasts; + dPoweredCreepers = arena.distSpecial.get("powered-creepers"); + dPigZombies = dPoweredCreepers + arena.distSpecial.get("zombie-pigmen"); + dSlimes = dPigZombies + arena.distSpecial.get("slimes"); + dMonsters = dSlimes + arena.distSpecial.get("humans"); + dAngryWolves = dMonsters + arena.distSpecial.get("angry-wolves"); + dGiants = dAngryWolves + arena.distSpecial.get("giants"); + dGhasts = dGiants + arena.distSpecial.get("ghasts"); } public void run() - { - // Check if we need to grant more rewards with the recurrent waves. - for (Integer i : ArenaManager.everyWaveMap.keySet()) + { + // Check if wave needs to be cleared first. If so, return! + if (arena.waveClear && wave > 1) { - if (wave % i != 0) - continue; - - for (Player p : ArenaManager.playerSet) - { - currentRewards = ArenaManager.rewardMap.get(p); - reward = MAUtils.getRandomReward(ArenaManager.everyWaveMap.get(i)); - currentRewards += reward + ","; - ArenaManager.rewardMap.put(p, currentRewards); - ArenaManager.tellPlayer(p, "You just earned a reward: " + reward); - } + if (!arena.monsters.isEmpty()) + return; } + // If maxIdleTime is defined, reset the timer. + //if (arena.maxIdleTime > 0) arena.resetIdleTimer(); + + // Check if we need to grant more rewards with the recurrent waves. + for (Map.Entry> entry : arena.everyWaveMap.entrySet()) + if (wave % entry.getKey() == 0) + addReward(entry.getValue()); + // Same deal, this time with the one-time waves. - if (ArenaManager.afterWaveMap.containsKey(wave)) - { - for (Player p : ArenaManager.playerSet) - { - currentRewards = ArenaManager.rewardMap.get(p); - reward = MAUtils.getRandomReward(ArenaManager.afterWaveMap.get(wave)); - currentRewards += reward + ","; - ArenaManager.rewardMap.put(p, currentRewards); - ArenaManager.tellPlayer(p, "You just earned a reward: " + reward); - } - } + if (arena.afterWaveMap.containsKey(wave)) + addReward(arena.afterWaveMap.get(wave)); // Check if this is a special wave. if (wave % modulo == 0) { - ArenaManager.tellAll("Get ready for wave #" + wave + "! [SPECIAL]"); - for (MobArenaListener m : ArenaManager.listeners) - m.onSpecialWave(wave, wave/modulo); + MAUtils.tellAll(arena, MAMessages.get(Msg.WAVE_SPECIAL, ""+wave)); + detonateCreepers(arena.detCreepers); specialWave(); + + // Notify listeners. + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onSpecialWave(wave, wave/modulo); } else { - ArenaManager.tellAll("Get ready for wave #" + wave + "!"); - for (MobArenaListener m : ArenaManager.listeners) - m.onDefaultWave(wave); + MAUtils.tellAll(arena, MAMessages.get(Msg.WAVE_DEFAULT, ""+wave)); + detonateCreepers(arena.detCreepers); defaultWave(); + + // Notify listeners. + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onDefaultWave(wave); } - ArenaManager.wave = wave; wave++; + if (arena.maxIdleTime > 0) arena.resetIdleTimer(); + } + + /** + * Rewards all players with an item from the input String. + */ + private void addReward(List rewards) + { + for (Player p : arena.livePlayers) + { + ItemStack reward = MAUtils.getRandomReward(rewards); + arena.rewardMap.get(p).add(reward); + + MAUtils.tellPlayer(p, MAMessages.get(Msg.WAVE_REWARD, MAUtils.toCamelCase(reward.getType().toString()) + ":" + reward.getAmount())); + } } /** @@ -114,12 +138,15 @@ public class MASpawnThread implements Runnable private void defaultWave() { Location loc; - - for (int i = 0; i < wave + noOfPlayers; i++) + List spawnpoints = getValidSpawnpoints(); + int noOfSpawnpoints = spawnpoints.size(); + int count = wave + noOfPlayers; + CreatureType mob; + + for (int i = 0; i < count; i++) { - loc = ArenaManager.spawnpoints.get(i % noOfSpawnPoints); + loc = spawnpoints.get(i % noOfSpawnpoints); ran = random.nextInt(dWolves); - CreatureType mob; /* Because of the nature of the if-elseif-else statement, * we're able to evaluate the random number in this way. @@ -133,8 +160,8 @@ public class MASpawnThread implements Runnable else if (ran < dWolves) mob = CreatureType.WOLF; else continue; - LivingEntity e = ArenaManager.world.spawnCreature(loc,mob); - ArenaManager.monsterSet.add(e); + LivingEntity e = arena.world.spawnCreature(loc,mob); + arena.monsters.add(e); // Grab a random target. Creature c = (Creature) e; @@ -148,6 +175,8 @@ public class MASpawnThread implements Runnable private void specialWave() { Location loc; + List spawnpoints = getValidSpawnpoints(); + int noOfSpawnpoints = spawnpoints.size(); CreatureType mob; ran = random.nextInt(dGhasts); @@ -202,13 +231,10 @@ public class MASpawnThread implements Runnable // Spawn the hippie monsters. for (int i = 0; i < count; i++) { - loc = ArenaManager.spawnpoints.get(i % noOfSpawnPoints); + loc = spawnpoints.get(i % noOfSpawnpoints); - LivingEntity e = ArenaManager.world.spawnCreature(loc,mob); - if (!ArenaManager.monsterSet.contains(e)) - ArenaManager.monsterSet.add(e); - else - System.out.println("MASpawnThread - monsterSet contains this entity"); + LivingEntity e = arena.world.spawnCreature(loc,mob); + arena.monsters.add(e); if (slime) ((Slime)e).setSize(2); if (wolf) ((Wolf)e).setAngry(true); @@ -224,38 +250,85 @@ public class MASpawnThread implements Runnable c.setTarget(getClosestPlayer(e)); } - if (!ArenaManager.lightning) + if (!arena.lightning) return; // Lightning, just for effect ;) - for (Location spawn : ArenaManager.spawnpoints) + for (Location spawn : arena.spawnpoints.values()) + arena.world.strikeLightningEffect(spawn); + } + + /** + * "Detonates" all the Creepers in the monsterSet. + */ + public void detonateCreepers(boolean really) + { + if (!really) + return; + + Set tmp = new HashSet(); + for (Entity e : arena.monsters) { - ArenaManager.world.strikeLightningEffect(spawn); + if (!(e instanceof Creeper) || e.isDead()) + continue; + + tmp.add(e); + } + + Location loc; + for (Entity e : tmp) + { + arena.monsters.remove(e); + loc = e.getLocation().getBlock().getRelative(0,2,0).getLocation(); + arena.world.createExplosion(loc, 2); + e.remove(); } } /** - * Gets the player closest to the input entity. ArrayList implementation - * means a complexity of O(n). + * Get all the spawnpoints that have players nearby. */ - // TO-DO: Move this into MAUtils - public static Player getClosestPlayer(Entity e) + public List getValidSpawnpoints() { - // Grab the coordinates. - double x = e.getLocation().getX(); - double y = e.getLocation().getY(); - double z = e.getLocation().getZ(); + List result = new ArrayList(); + for (Location s : arena.spawnpoints.values()) + { + for (Player p : arena.livePlayers) + { + if (s.distanceSquared(p.getLocation()) > MIN_DISTANCE) + continue; + + result.add(s); + break; + } + } + + // If no players are in range, just use all the spawnpoints. + if (result.isEmpty()) + result.addAll(arena.spawnpoints.values()); + + return result; + } + + /** + * Get the player closest to the input entity. + */ + // TODO: Move this into MAUtils + public Player getClosestPlayer(Entity e) + { // Set up the comparison variable and the result. + double dist = 0; double current = Double.POSITIVE_INFINITY; Player result = null; /* Iterate through the ArrayList, and update current and result every * time a squared distance smaller than current is found. */ - for (Player p : ArenaManager.playerSet) + for (Player p : arena.livePlayers) { - double dist = distance(p.getLocation(), x, y, z); - if (dist < current) + dist = p.getLocation().distance(e.getLocation()); + //double dist = MAUtils.distance(p.getLocation(), e.getLocation()); + if (dist < current && dist < 256) { current = dist; result = p; @@ -263,17 +336,4 @@ public class MASpawnThread implements Runnable } return result; } - - /** - * Calculates the squared distance between locations. - */ - // TO-DO: Move this into MAUtils - private static double distance(Location loc, double d1, double d2, double d3) - { - double d4 = loc.getX() - d1; - double d5 = loc.getY() - d2; - double d6 = loc.getZ() - d3; - - return d4*d4 + d5*d5 + d6*d6; - } } \ No newline at end of file diff --git a/src/com/garbagemule/MobArena/MAUtils.java b/src/com/garbagemule/MobArena/MAUtils.java index cfdedc3..04b3a41 100644 --- a/src/com/garbagemule/MobArena/MAUtils.java +++ b/src/com/garbagemule/MobArena/MAUtils.java @@ -7,36 +7,305 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.LinkedList; import java.util.Map; import java.util.HashMap; import java.util.Random; -import java.util.Iterator; +import java.util.Set; + +import net.minecraft.server.WorldServer; + import org.bukkit.block.Sign; +import org.bukkit.command.CommandSender; import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; import org.bukkit.World; import org.bukkit.Material; import org.bukkit.Location; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; +import org.bukkit.entity.Wolf; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.bukkit.util.config.Configuration; +import com.garbagemule.MobArena.MAMessages.Msg; + public class MAUtils -{ - public static final List SWORDS_ID = new LinkedList(); - public static final List SWORDS_TYPE = new LinkedList(); +{ + public static final String sep = File.separator; + // Weapons + public static final List WEAPONS_TYPE = new LinkedList(); + public static final List SWORDS_TYPE = new LinkedList(); + public static final List AXES_TYPE = new LinkedList(); + public static final List PICKAXES_TYPE = new LinkedList(); + public static final List SPADES_TYPE = new LinkedList(); + public static final List HOES_TYPE = new LinkedList(); + // Armor + public static final List ARMORS_TYPE = new LinkedList(); + public static final List HELMETS_TYPE = new LinkedList(); + public static final List CHESTPLATES_TYPE = new LinkedList(); + public static final List LEGGINGS_TYPE = new LinkedList(); + public static final List BOOTS_TYPE = new LinkedList(); static { + // Weapons SWORDS_TYPE.add(Material.WOOD_SWORD); SWORDS_TYPE.add(Material.STONE_SWORD); SWORDS_TYPE.add(Material.GOLD_SWORD); SWORDS_TYPE.add(Material.IRON_SWORD); SWORDS_TYPE.add(Material.DIAMOND_SWORD); + + AXES_TYPE.add(Material.WOOD_AXE); + AXES_TYPE.add(Material.STONE_AXE); + AXES_TYPE.add(Material.GOLD_AXE); + AXES_TYPE.add(Material.IRON_AXE); + AXES_TYPE.add(Material.DIAMOND_AXE); + + PICKAXES_TYPE.add(Material.WOOD_PICKAXE); + PICKAXES_TYPE.add(Material.STONE_PICKAXE); + PICKAXES_TYPE.add(Material.GOLD_PICKAXE); + PICKAXES_TYPE.add(Material.IRON_PICKAXE); + PICKAXES_TYPE.add(Material.DIAMOND_PICKAXE); + + SPADES_TYPE.add(Material.WOOD_SPADE); + SPADES_TYPE.add(Material.STONE_SPADE); + SPADES_TYPE.add(Material.GOLD_SPADE); + SPADES_TYPE.add(Material.IRON_SPADE); + SPADES_TYPE.add(Material.DIAMOND_SPADE); + + HOES_TYPE.add(Material.WOOD_HOE); + HOES_TYPE.add(Material.STONE_HOE); + HOES_TYPE.add(Material.GOLD_HOE); + HOES_TYPE.add(Material.IRON_HOE); + HOES_TYPE.add(Material.DIAMOND_HOE); + + WEAPONS_TYPE.addAll(SWORDS_TYPE); + WEAPONS_TYPE.addAll(AXES_TYPE); + WEAPONS_TYPE.addAll(PICKAXES_TYPE); + WEAPONS_TYPE.addAll(SPADES_TYPE); + WEAPONS_TYPE.addAll(HOES_TYPE); + + // Armor + HELMETS_TYPE.add(Material.LEATHER_HELMET); + HELMETS_TYPE.add(Material.GOLD_HELMET); + HELMETS_TYPE.add(Material.CHAINMAIL_HELMET); + HELMETS_TYPE.add(Material.IRON_HELMET); + HELMETS_TYPE.add(Material.DIAMOND_HELMET); + + CHESTPLATES_TYPE.add(Material.LEATHER_CHESTPLATE); + CHESTPLATES_TYPE.add(Material.GOLD_CHESTPLATE); + CHESTPLATES_TYPE.add(Material.CHAINMAIL_CHESTPLATE); + CHESTPLATES_TYPE.add(Material.IRON_CHESTPLATE); + CHESTPLATES_TYPE.add(Material.DIAMOND_CHESTPLATE); + + LEGGINGS_TYPE.add(Material.LEATHER_LEGGINGS); + LEGGINGS_TYPE.add(Material.GOLD_LEGGINGS); + LEGGINGS_TYPE.add(Material.CHAINMAIL_LEGGINGS); + LEGGINGS_TYPE.add(Material.IRON_LEGGINGS); + LEGGINGS_TYPE.add(Material.DIAMOND_LEGGINGS); + + BOOTS_TYPE.add(Material.LEATHER_BOOTS); + BOOTS_TYPE.add(Material.GOLD_BOOTS); + BOOTS_TYPE.add(Material.CHAINMAIL_BOOTS); + BOOTS_TYPE.add(Material.IRON_BOOTS); + BOOTS_TYPE.add(Material.DIAMOND_BOOTS); + + ARMORS_TYPE.addAll(HELMETS_TYPE); + ARMORS_TYPE.addAll(CHESTPLATES_TYPE); + ARMORS_TYPE.addAll(LEGGINGS_TYPE); + ARMORS_TYPE.addAll(BOOTS_TYPE); + } + + + + /* ///////////////////////////////////////////////////////////////////// // + + INITIALIZATION METHODS + + // ///////////////////////////////////////////////////////////////////// */ + + /** + * Grab all the spawnpoints for a specific arena. + */ + public static Map getArenaSpawnpoints(Configuration config, World world, String arena) + { + Map spawnpoints = new HashMap(); + String arenaPath = "arenas." + arena + ".coords.spawnpoints"; + + if (config.getKeys(arenaPath) == null) + return spawnpoints; + + for (String point : config.getKeys(arenaPath)) + spawnpoints.put(point, makeLocation(world, config.getString(arenaPath + "." + point))); + + return spawnpoints; + } + + /** + * Returns a map of classnames mapped to lists of ItemStacks. + */ + public static Map> getClassItems(Configuration config, String type) + { + Map> result = new HashMap>(); + + for (String className : config.getKeys("classes")) + result.put(className, makeItemStackList(config.getString("classes." + className + "." + type))); + + return result; + } + + /** + * Takes a comma-separated list of items in the : format and + * returns a list of ItemStacks created from that data. + */ + public static List makeItemStackList(String string) + { + List result = new LinkedList(); + if (string == null) return result; + + string = string.trim(); + if (string.endsWith(",")) + string = string.substring(0, string.length()-1); + String[] items = string.split(","); + + for (String item : items) + { + item = item.trim(); + String[] parts = item.split(":"); + + // Grab the amount. + int amount = (parts.length == 2 && parts[1].matches("[0-9]+")) ? + Integer.parseInt(parts[1]) : + 1; + + // Make the ItemStack. + ItemStack stack = (parts[0].matches("[0-9]+")) ? + makeItemStack(Integer.parseInt(parts[0]), amount) : + makeItemStack(parts[0], amount); + + result.add(stack); + } + return result; + } + + /** + * Generates a map of wave numbers and rewards based on the + * type of wave ("after" or "every") and the config-file. If + * no keys exist in the config-file, an empty map is returned. + */ + public static Map> getArenaRewardMap(Configuration config, String arena, String type) + { + String arenaPath = "arenas." + arena + ".rewards.waves."; + Map> result = new HashMap>(); + + if (config.getKeys(arenaPath + type) == null) + { + if (type.equals("every")) + { + config.setProperty(arenaPath + "every.3", "feather, bone, stick"); + config.setProperty(arenaPath + "every.5", "dirt:4, gravel:4, stone:4"); + config.setProperty(arenaPath + "every.10", "iron_ingot:10, gold_ingot:8"); + } + else if (type.equals("after")) + { + config.setProperty(arenaPath + "after.7", "minecart, storage_minecart, powered_minecart"); + config.setProperty(arenaPath + "after.13", "iron_sword, iron_pickaxe, iron_spade"); + config.setProperty(arenaPath + "after.16", "diamond_sword"); + } + } + + List waves = config.getKeys(arenaPath + type); + if (waves == null) return result; + + for (String n : waves) + { + if (!n.matches("[0-9]+")) + continue; + + int wave = Integer.parseInt(n); + String rewards = config.getString(arenaPath + type + "." + n); + + result.put(wave, makeItemStackList(rewards)); + } + return result; + } + + /** + * Grabs the distribution coefficients from the config-file. If + * no coefficients are found, defaults (10) are added. + */ + public static Map getArenaDistributions(Configuration config, String arena, String wave) + { + //config.load(); + String arenaPath = "arenas." + arena + ".waves." + wave; + Map result = new HashMap(); + List dists = config.getKeys(arenaPath); + + // If there are no distributions yet, add them. + if (dists == null) + { + if (wave.equals("default")) + { + config.setProperty(arenaPath + ".zombies", 10); + config.setProperty(arenaPath + ".skeletons", 10); + config.setProperty(arenaPath + ".spiders", 10); + config.setProperty(arenaPath + ".creepers", 10); + config.setProperty(arenaPath + ".wolves", 10); + } + else if (wave.equals("special")) + { + config.setProperty(arenaPath + ".powered-creepers", 10); + config.setProperty(arenaPath + ".zombie-pigmen", 10); + config.setProperty(arenaPath + ".slimes", 10); + config.setProperty(arenaPath + ".humans", 10); + config.setProperty(arenaPath + ".angry-wolves", 10); + config.setProperty(arenaPath + ".giants", 0); + config.setProperty(arenaPath + ".ghasts", 0); + } + //config.save(); + dists = config.getKeys(arenaPath); + } + + for (String monster : dists) + { + int value = config.getInt(arenaPath + "." + monster, -1); + + // If no distribution value was found, set one. + if (value == -1) + { + value = 10; + if (monster.equals("giant") || monster.equals("ghast")) + value = 0; + + config.setProperty(arenaPath + "." + monster, value); + //config.save(); + } + + result.put(monster, value); + } + return result; + } + + public static List getAllowedCommands(Configuration config) + { + String commands = config.getString("global-settings.allowed-commands"); + if (commands == null) + { + config.setProperty("global-settings.allowed-commands", "/list, /pl"); + config.save(); + commands = config.getString("global-settings.allowed-commands"); + } + + return stringToList(commands); } + /* ///////////////////////////////////////////////////////////////////// // INVENTORY AND REWARD METHODS @@ -55,11 +324,110 @@ public class MAUtils return inv; } - /* Checks if all inventory and armor slots are empty. */ - public static boolean hasEmptyInventory(Player player) + public static boolean storeInventory(Player p) { - ItemStack[] inventory = player.getInventory().getContents(); - ItemStack[] armor = player.getInventory().getArmorContents(); + // Grab the contents. + ItemStack[] armor = p.getInventory().getArmorContents(); + ItemStack[] items = p.getInventory().getContents(); + + String invPath = "plugins" + sep + "MobArena" + sep + "inventories"; + new File(invPath).mkdir(); + File backupFile = new File(invPath + sep + p.getName() + ".inv"); + + try + { + if (backupFile.exists()) + return false; + + backupFile.createNewFile(); + + MAInventoryItem[] inv = new MAInventoryItem[armor.length + items.length]; + for (int i = 0; i < armor.length; i++) + inv[i] = stackToItem(armor[i]); + for (int i = 0; i < items.length; i++) + inv[armor.length + i] = stackToItem(items[i]); + + FileOutputStream fos = new FileOutputStream(backupFile); + ObjectOutputStream oos = new ObjectOutputStream(fos); + oos.writeObject(inv); + oos.close(); + } + catch (Exception e) + { + e.printStackTrace(); + System.out.println("[MobArena] ERROR! Could not create backup file for " + p.getName() + "."); + return false; + } + + clearInventory(p); + return true; + } + + public static boolean restoreInventory(Player p) + { + String invPath = "plugins" + sep + "MobArena" + sep + "inventories"; + File backupFile = new File(invPath + sep + p.getName() + ".inv"); + + try + { + // If the backup-file couldn't be found, return. + if (!backupFile.exists()) + return false; + + // Grab the MAInventoryItem array from the backup-file. + FileInputStream fis = new FileInputStream(backupFile); + ObjectInputStream ois = new ObjectInputStream(fis); + MAInventoryItem[] fromFile = (MAInventoryItem[]) ois.readObject(); + ois.close(); + + // Split that shit. + ItemStack[] armor = new ItemStack[4]; + ItemStack[] items = new ItemStack[fromFile.length-4]; + + for (int i = 0; i < 4; i++) + armor[i] = itemToStack(fromFile[i]); + for (int i = 4; i < fromFile.length; i++) + items[i - 4] = itemToStack(fromFile[i]); + + // Restore the inventory. + PlayerInventory inv = p.getInventory(); + inv.setArmorContents(armor); + for (ItemStack stack : items) + if (stack != null) + inv.addItem(stack); + + // Remove the backup-file. + backupFile.delete(); + } + catch (Exception e) + { + e.printStackTrace(); + System.out.println("[MobArena] ERROR! Could not restore inventory for " + p.getName()); + return false; + } + + return true; + } + + private static MAInventoryItem stackToItem(ItemStack stack) + { + if (stack == null) + return new MAInventoryItem(-1, -1, (short)0); + return new MAInventoryItem(stack.getTypeId(), stack.getAmount(), stack.getDurability()); + } + + private static ItemStack itemToStack(MAInventoryItem item) + { + if (item.getTypeId() == -1) + return null; + return new ItemStack(item.getTypeId(), item.getAmount(), item.getDurability()); + } + + /* Checks if all inventory and armor slots are empty. */ + public static boolean hasEmptyInventory(Player p) + { + ItemStack[] inventory = p.getInventory().getContents(); + ItemStack[] armor = p.getInventory().getArmorContents(); // For inventory, check for null for (ItemStack stack : inventory) @@ -72,540 +440,286 @@ public class MAUtils return true; } - /* Gives all the items in the input string(s) to the player */ - public static void giveItems(boolean reward, Player p, String... strings) + /** + * Gives the player all of the items in the list of ItemStacks. + */ + public static void giveItems(Player p, List stacks, boolean autoEquip, boolean rewards) { - // Variables used. - ItemStack stack; - int id, amount; + PlayerInventory inv = p.getInventory(); - PlayerInventory inv; - - if (reward) - inv = p.getInventory(); - else - inv = clearInventory(p); - - for (String s : strings) + for (ItemStack stack : stacks) { - /* Trim the list, remove possible trailing commas, split by - * commas, and start the item loop. */ - s = s.trim(); - if (s.endsWith(",")) - s = s.substring(0, s.length()-1); - String[] items = s.split(","); - - // For every item in the list - for (String i : items) + // If these are rewards, don't tamper with them. + if (rewards) { - /* Take into account possible amount, and if there is - * one, set the amount variable to that amount, else 1. */ - i = i.trim(); - String[] item = i.split(":"); - if (item.length == 2 && item[1].matches("[0-9]+")) - amount = Integer.parseInt(item[1]); - else - amount = 1; - - // Create ItemStack with appropriate constructor. - if (item[0].matches("[0-9]+")) - { - id = Integer.parseInt(item[0]); - stack = new ItemStack(id, amount); - if (!reward && SWORDS_TYPE.contains(stack.getType())) - stack.setDurability((short)-3276); - } - else - { - stack = makeItemStack(item[0], amount); - if (stack == null) continue; - if (!reward && SWORDS_TYPE.contains(stack.getType())) - stack.setDurability((short)-3276); - } - inv.addItem(stack); + continue; } + + // If this is an armor piece, equip it and continue. + if (autoEquip && ARMORS_TYPE.contains(stack.getType())) + { + equipArmorPiece(stack, inv); + continue; + } + + // If this is a sword, set its durability to "unlimited". + //if (SWORDS_TYPE.contains(stack.getType())) + if (WEAPONS_TYPE.contains(stack.getType())) + stack.setDurability((short) -32768); + + inv.addItem(stack); } } - /* Used for giving items "normally". */ - public static void giveItems(Player p, String... strings) + public static void giveItems(Player p, List stacks, boolean autoEquip) { - giveItems(false, p, strings); + giveItems(p, stacks, autoEquip, false); } - /* Helper method for grabbing a random reward */ - public static String getRandomReward(String rewardlist) + public static void giveRewards(Player p, List stacks) { - Random ran = new Random(); + giveItems(p, stacks, false, true); + } + + public static int getPetAmount(Player p) + { + int result = 0; - String[] rewards = rewardlist.split(","); - String item = rewards[ran.nextInt(rewards.length)]; - return item.trim(); + for (ItemStack stack : p.getInventory().getContents()) + { + if (stack == null || stack.getTypeId() != 352) + continue; + + result += stack.getAmount(); + } + + return result; } - /* Helper method for making an ItemStack out of a string */ - private static ItemStack makeItemStack(String s, int amount) + /* Helper method for equipping armor pieces. */ + public static void equipArmorPiece(ItemStack stack, PlayerInventory inv) + { + Material type = stack.getType(); + + if (HELMETS_TYPE.contains(type)) + inv.setHelmet(stack); + else if (CHESTPLATES_TYPE.contains(type)) + inv.setChestplate(stack); + else if (LEGGINGS_TYPE.contains(type)) + inv.setLeggings(stack); + else if (BOOTS_TYPE.contains(type)) + inv.setBoots(stack); + } + + /* Helper methods for making ItemStacks out of strings and ints */ + private static ItemStack makeItemStack(String name, int amount) { - Material mat; try { - mat = Material.valueOf(s.toUpperCase()); - return new ItemStack(mat, amount); + Material material = Material.valueOf(name.toUpperCase()); + return new ItemStack(material, amount); } catch (Exception e) { - System.out.println("[MobArena] ERROR! Could not create item " + s + ". Check config.yml"); + System.out.println("[MobArena] ERROR! Could not create item \"" + name + "\". Check config.yml"); return null; } } - - - /* ///////////////////////////////////////////////////////////////////// // - - INITIALIZATION METHODS - - // ///////////////////////////////////////////////////////////////////// */ - - /** - * Creates a Configuration object from the config.yml file. - */ - public static Configuration getConfig() + private static ItemStack makeItemStack(int id, int amount) { - new File("plugins/MobArena").mkdir(); - File configFile = new File("plugins/MobArena/config.yml"); - try { - if(!configFile.exists()) - { - configFile.createNewFile(); - } + Material material = Material.getMaterial(id); + return new ItemStack(material, amount); } - catch(Exception e) + catch (Exception e) { - System.out.println("[MobArena] ERROR: Config file could not be created."); + System.out.println("[MobArena] ERROR! Could not create item with id " + id + ". Check config.yml"); return null; } - - return new Configuration(configFile); } - public static List getDisabledCommands() + /* Helper method for grabbing a random reward */ + public static ItemStack getRandomReward(List rewards) { - Configuration c = ArenaManager.config; - c.load(); - - String commands = c.getString("settings.disabledcommands", "/kill"); - c.setProperty("settings.disabledcommands", commands); - c.save(); - - List result = new LinkedList(); - for (String s : commands.split(",")) - result.add(s.trim()); - - return result; + Random ran = new Random(); + return rewards.get(ran.nextInt(rewards.size())); } - /** - * Grabs the world from the config-file, or the "default" world - * from the list of worlds in the server object. - */ - public static World getWorld() - { - Configuration c = ArenaManager.config; - c.load(); - - String world = c.getString("settings.world", ArenaManager.server.getWorlds().get(0).getName()); - c.setProperty("settings.world", world); - - c.save(); - return ArenaManager.server.getWorld(world); - } - - /** - * Handles all spawn-monster bypassing. - * If toggle is true, swap the allowMonsters field if possible. Otherwise, just - * return the current value. - */ - public static boolean spawnBypass(boolean toggle) - { - // Cast the world to an nmsWorld. - net.minecraft.server.World nmsWorld = ((CraftWorld) ArenaManager.world).getHandle(); - - // If not toggling, just return the current variable. - if (!toggle) - { - ArenaManager.spawnMonstersInt = nmsWorld.spawnMonsters; - return nmsWorld.allowMonsters; - } - - // If arena is running, allow monsters, otherwise don't. - if (ArenaManager.isRunning) - { - nmsWorld.allowMonsters = true; - if (ArenaManager.spawnMonstersInt == 0) - nmsWorld.spawnMonsters = 1; - } - else - { - // If the server wasn't allowing monsters, set it back to false. - if (!ArenaManager.spawnMonsters) - nmsWorld.allowMonsters = false; - nmsWorld.spawnMonsters = ArenaManager.spawnMonstersInt; - } - - return true; - } - - /** - * Grabs the list of classes from the config-file. If no list is - * found, generate a set of default classes. - */ - public static List getClasses() - { - Configuration c = ArenaManager.config; - c.load(); - - if (c.getKeys("classes") == null) - { - c.setProperty("classes.Archer.items", "wood_sword, bow, arrow:128, grilled_pork"); - c.setProperty("classes.Archer.armor", "298,299,300,301"); - c.setProperty("classes.Knight.items", "diamond_sword, grilled_pork:2"); - c.setProperty("classes.Knight.armor", "306,307,308,309"); - c.setProperty("classes.Tank.items", "iron_sword, grilled_pork:3, apple"); - c.setProperty("classes.Tank.armor", "310,311,312,313"); - c.setProperty("classes.Oddjob.items", "stone_sword, flint_and_steel, netherrack:2, wood_pickaxe, tnt:4, fishing_rod, apple, grilled_pork:3"); - c.setProperty("classes.Oddjob.armor", "298,299,300,301"); - c.setProperty("classes.Chef.items", "stone_sword, bread:6, grilled_pork:4, mushroom_soup, cake:3, cookie:12"); - c.setProperty("classes.Chef.armor", "314,315,316,317"); - - c.save(); - } - - return c.getKeys("classes"); - } - - /** - * Generates a map of class names and class items based on the - * type of items ("items" or "armor") and the config-file. - * Will explode if the classes aren't well-defined. - */ - public static Map getClassItems(String type) - { - Configuration c = ArenaManager.config; - c.load(); - - Map result = new HashMap(); - - // Assuming well-defined classes. - List classes = c.getKeys("classes"); - for (String s : classes) - { - result.put(s, c.getString("classes." + s + "." + type, null)); - } - - return result; - } - - /** - * Generates a map of wave numbers and rewards based on the - * type of wave ("after" or "every") and the config-file. If - * no keys exist in the config-file, an empty map is returned. - */ - public static Map getWaveMap(String type) - { - Configuration c = ArenaManager.config; - c.load(); - - // Set up variables and resulting map. - Map result = new HashMap(); - int wave; - String rewards; - - /* Check if the keys exist in the config-file, if not, set some. */ - if (c.getKeys("rewards.waves." + type) == null) - { - if (type.equals("every")) - { - c.setProperty("rewards.waves.every.3", "feather, bone, stick"); - c.setProperty("rewards.waves.every.5", "dirt:4, gravel:4, stone:4"); - c.setProperty("rewards.waves.every.10", "iron_ingot:10, gold_ingot:8"); - } - else if (type.equals("after")) - { - c.setProperty("rewards.waves.after.7", "minecart, storage_minecart, powered_minecart"); - c.setProperty("rewards.waves.after.13", "iron_sword, iron_pickaxe, iron_spade"); - c.setProperty("rewards.waves.after.16", "diamon_sword"); - } - - c.save(); - } - List waves = c.getKeys("rewards.waves." + type); - - // Put all the rewards in the map. - for (String n : waves) - { - if (!n.matches("[0-9]+")) - continue; - - wave = Integer.parseInt(n); - rewards = c.getString("rewards.waves." + type + "." + n); - - result.put(wave,rewards); - } - - // And return the resulting map. - return result; - } - - /** - * Grabs all the spawnpoints from the config-file. IF no points - * are found, an empty list is returned. - */ - public static List getSpawnPoints() - { - Configuration c = ArenaManager.config; - c.load(); - - List spawnpoints = c.getKeys("coords.spawnpoints"); - if (spawnpoints == null) - return new LinkedList(); - - List result = new LinkedList(); - for (String s : spawnpoints) - { - Location loc = getCoords("spawnpoints." + s); - - if (loc != null) - result.add(loc); - } - - return result; - } - - /** - * Grabs the distribution coefficients from the config-file. If - * no coefficients are found, defaults (10) are added. - */ - public static int getDistribution(String monster) - { - return getDistribution(monster, "default"); - } - - public static int getDistribution(String monster, String type) - { - Configuration c = ArenaManager.config; - c.load(); - - if (c.getInt("waves." + type + "." + monster, -1) == -1) - { - int dist = 10; - if (monster.equals("giants") || monster.equals("ghasts")) - dist = 0; - - c.setProperty("waves." + type + "." + monster, dist); - c.save(); - } - - return c.getInt("waves." + type + "." + monster, 0); - } - - /** - * Grabs an integer from the config-file. - */ - public static int getInt(String path, int def) - { - Configuration c = ArenaManager.config; - c.load(); - - int result = c.getInt(path, def); - c.setProperty(path, result); - - c.save(); - return result; - } - - /** - * Grabs a boolean from the config-file. - */ - public static boolean getBoolean(String path, boolean def) - { - Configuration c = ArenaManager.config; - c.load(); - - boolean result = c.getBoolean(path, def); - c.setProperty(path, result); - - c.save(); - return result; - } /* ///////////////////////////////////////////////////////////////////// // - REGION AND SETUP METHODS + PET CLASS METHODS // ///////////////////////////////////////////////////////////////////// */ /** - * Checks if the Location object is within the arena region. + * Makes all nearby wolves sit if their owner is the given player. */ - public static boolean inRegion(Location loc) + public static void sitPets(Player p) { - if (!loc.getWorld().getName().equals(ArenaManager.world.getName())) + List entities = p.getNearbyEntities(80, 40, 80); + for (Entity e : entities) + { + if (!(e instanceof Wolf)) + continue; + + Wolf w = (Wolf) e; + if (w.getOwner().equals(p)) + w.setSitting(true); + } + } + + /** + * Removes all the pets belonging to this player. + */ + public static void clearPets(Arena arena, Player p) + { + for (Wolf w : arena.pets) + { + if (w.getOwner().equals(p)) + w.remove(); + } + } + + + + /* ///////////////////////////////////////////////////////////////////// // + + REGION METHODS + + // ///////////////////////////////////////////////////////////////////// */ + + /** + * Create a Location object from the config-file. + */ + public static Location getArenaCoord(Configuration config, World world, String arena, String coord) + { + //config.load(); + String str = config.getString("arenas." + arena + ".coords." + coord); + if (str == null) + return null; + return makeLocation(world, str); + } + + /** + * Save an arena location to the Configuration. + */ + public static void setArenaCoord(Configuration config, Arena arena, String coord, Location loc) + { + config.setProperty("arenas." + arena.configName() + ".coords." + coord, makeCoord(loc)); + config.save(); + arena.load(config); + + if (coord.equals("p1") || coord.equals("p2")) + fixRegion(config, loc.getWorld(), arena); + } + + public static boolean delArenaCoord(Configuration config, Arena arena, String coord) + { + if (config.getString("arenas." + arena.configName() + ".coords." + coord) == null) return false; - if (!ArenaManager.isSetup) - return false; - - Location p1 = ArenaManager.p1; - Location p2 = ArenaManager.p2; - - // Return false if the location is outside of the region. - if ((loc.getX() < p1.getX()) || (loc.getX() > p2.getX())) - return false; - - if ((loc.getZ() < p1.getZ()) || (loc.getZ() > p2.getZ())) - return false; - - if ((loc.getY() < p1.getY()) || (loc.getY() > p2.getY())) - return false; - + config.removeProperty("arenas." + arena.configName() + ".coords." + coord); + config.save(); + arena.load(config); return true; } - /** - * Grabs coordinate information from the config-file. - */ - public static Location getCoords(String name) + private static void fixRegion(Configuration config, World world, Arena arena) { - Configuration c = ArenaManager.config; - c.load(); - - // Return null if coords aren't in the config file. - if (c.getKeys("coords." + name) == null) - return null; - - double x = c.getDouble("coords." + name + ".x", 0); - double y = c.getDouble("coords." + name + ".y", 0); - double z = c.getDouble("coords." + name + ".z", 0); - - return new Location(ArenaManager.world, x, y, z); - } - - /** - * Writes coordinate information to the config-file. - */ - public static void setCoords(String name, Location loc) - { - Configuration c = ArenaManager.config; - c.load(); - - c.setProperty("coords." + name + ".world", loc.getWorld().getName()); - c.setProperty("coords." + name + ".x", loc.getX()); - c.setProperty("coords." + name + ".y", loc.getY()); - c.setProperty("coords." + name + ".z", loc.getZ()); - c.setProperty("coords." + name + ".yaw", loc.getYaw()); - c.setProperty("coords." + name + ".pitch", loc.getPitch()); - - c.save(); - ArenaManager.updateVariables(); - } - - /** - * Removes coordinate information from the config-file. - */ - public static void delCoords(String name) - { - Configuration c = ArenaManager.config; - c.load(); - - c.removeProperty(name); - - c.save(); - ArenaManager.updateVariables(); - } - - /** - * Maintains the invariant that p1's coordinates are of lower - * values than their respective counter-parts of p2. Makes the - * inRegion()-method much faster/easier. - */ - public static void fixCoords() - { - Location p1 = getCoords("p1"); - Location p2 = getCoords("p2"); - double tmp; - - if (p1 == null || p2 == null) + if (arena.p1 == null || arena.p2 == null) return; - - if (p1.getX() > p2.getX()) + + if (arena.p1.getX() > arena.p2.getX()) { - tmp = p1.getX(); - p1.setX(p2.getX()); - p2.setX(tmp); + double tmp = arena.p1.getX(); + arena.p1.setX(arena.p2.getX()); + arena.p2.setX(tmp); } - if (p1.getY() > p2.getY()) + if (arena.p1.getZ() > arena.p2.getZ()) { - tmp = p1.getY(); - p1.setY(p2.getY()); - p2.setY(tmp); + double tmp = arena.p1.getZ(); + arena.p1.setZ(arena.p2.getZ()); + arena.p2.setZ(tmp); } - if (p1.getZ() > p2.getZ()) + if (arena.p1.getY() > arena.p2.getY()) { - tmp = p1.getZ(); - p1.setZ(p2.getZ()); - p2.setZ(tmp); + double tmp = arena.p1.getY(); + arena.p1.setY(arena.p2.getY()); + arena.p2.setY(tmp); } - - setCoords("p1", p1); - setCoords("p2", p2); + arena.serializeConfig(); + arena.load(config); } /** - * Expands the arena region either upwards, downwards, or - * outwards (meaning on both the X and Z axes). + * Create a Location from the input String in the input World. */ - public static void expandRegion(String direction, int i) + public static Location makeLocation(World world, String str, boolean extras) { - Location p1 = ArenaManager.p1; - Location p2 = ArenaManager.p2; + String[] parts = str.split(","); - if (direction.equals("up")) - p2.setY(p2.getY() + i); - else if (direction.equals("down")) - p1.setY(p1.getY() - i); - else if (direction.equals("out")) + double x = Double.parseDouble(parts[0]); + double y = Double.parseDouble(parts[1]); + double z = Double.parseDouble(parts[2]); + + if (extras && parts.length == 5) { - p1.setX(p1.getX() - i); - p1.setZ(p1.getZ() - i); - p2.setX(p2.getX() + i); - p2.setZ(p2.getZ() + i); + float yaw = Float.parseFloat(parts[3]); + float pitch = Float.parseFloat(parts[4]); + return new Location(world, x, y, z, yaw, pitch); } - - setCoords("p1", p1); - setCoords("p2", p2); - fixCoords(); + + return new Location(world, x, y, z); } - public static String spawnList() + public static Location makeLocation(World world, String str) { - Configuration c = ArenaManager.config; - c.load(); + return makeLocation(world, str, true); + } + + /** + * Create a location String from the input Location. + */ + public static String makeCoord(Location loc, boolean extras) + { + int x = loc.getBlockX(); + int y = loc.getBlockY(); + int z = loc.getBlockZ(); - String result = ""; - if (c.getKeys("coords.spawnpoints") == null) - return result; + if (extras) + { + float yaw = loc.getYaw(); + float pitch = loc.getPitch(); + return x + "," + y + "," + z + "," + yaw + "," + pitch; + } - for (String s : c.getKeys("coords.spawnpoints")) - result += s + " "; + return x + "," + y + "," + z; + } + + public static String makeCoord(Location loc) + { + return makeCoord(loc, true); + } + + /** + * Check if a location is within any arena region. + */ + public static boolean inRegions(Location loc, Arena... arenas) + { + for (Arena arena : arenas) + { + if (arena.inRegion(loc)) + return true; + } - return result; + return false; } @@ -617,52 +731,181 @@ public class MAUtils // ///////////////////////////////////////////////////////////////////// */ /** - * Verifies that all important variables are declared. Returns true - * if, and only if, the warppoints, region, distribution coefficients, - * classes and spawnpoints are all set up. + * Sends a message to a player. */ - public static boolean verifyData() + public static boolean tellPlayer(CommandSender p, String msg) { - return ((ArenaManager.arenaLoc != null) && - (ArenaManager.lobbyLoc != null) && - (ArenaManager.spectatorLoc != null) && - (ArenaManager.p1 != null) && - (ArenaManager.p2 != null) && - (ArenaManager.dZombies != -1) && - (ArenaManager.dSkeletons != -1) && - (ArenaManager.dSpiders != -1) && - (ArenaManager.dCreepers != -1) && - (ArenaManager.dWolves != -1) && - (ArenaManager.classes.size() > 0) && - (ArenaManager.spawnpoints.size() > 0)); - } - - /** - * Notifies the player if MobArena is set up and ready to be used. - */ - public static void notifyIfSetup(Player p) - { - if (verifyData()) - { - ArenaManager.tellPlayer(p, "MobArena is set up and ready to roll!"); - } + if (p == null) + return false; + + p.sendMessage(ChatColor.GREEN + "[MobArena] " + ChatColor.WHITE + msg); + return true; } + /** + * Sends a message to all players in and around the arena. + */ + public static void tellAll(Arena arena, String msg) + { + Set tmp = new HashSet(); + tmp.addAll(arena.livePlayers); + tmp.addAll(arena.deadPlayers); + tmp.addAll(arena.specPlayers); + tmp.addAll(arena.readyPlayers); + for (Player p : tmp) + tellPlayer(p, msg); + } + + public static Player getClosestPlayer(Entity e, Arena arena) + { + // Set up the comparison variable and the result. + double current = Double.POSITIVE_INFINITY; + Player result = null; + + /* Iterate through the ArrayList, and update current and result every + * time a squared distance smaller than current is found. */ + for (Player p : arena.livePlayers) + { + double dist = p.getLocation().distanceSquared(e.getLocation()); //distance(p.getLocation(), e.getLocation()); + if (dist < current && dist < 256) + { + current = dist; + result = p; + } + } + return result; + } + + public static double distance(Location loc1, Location loc2) + { + double x = loc1.getX() - loc2.getX(); + double y = loc1.getY() - loc2.getY(); + double z = loc1.getZ() - loc2.getZ(); + + return x*x + y*y + z*z; + } + + /** + * Convert a proper arena name to a config-file name. + * All spaces are replaced by underscores, and the whole String is + * lowercased. + */ + public static String nameArenaToConfig(String name) + { + String tmp = name.replace(" ", "_"); + return tmp.toLowerCase(); + } + + /** + * Convert a config-name to a proper spaced and capsed arena name. + * The input String is split around all underscores, and every part + * of the String array is properly capsed. + */ + public static String nameConfigToArena(String name) + { + String[] parts = name.split("_"); + if (parts.length == 1) + return toCamelCase(parts[0]); + + String separator = " "; + StringBuffer buffy = new StringBuffer(name.length()); + for (String part : parts) + { + buffy.append(toCamelCase(part)); + buffy.append(separator); + } + buffy.replace(buffy.length()-1, buffy.length(), ""); + + return buffy.toString(); + } + + /** + * Returns the input String with a capital first letter, and all the + * other letters become lower case. + */ + public static String toCamelCase(String name) + { + return name.substring(0, 1).toUpperCase() + name.substring(1).toLowerCase(); + } + + /** + * Turn a list into a space-separated string-representation of the list. + */ + public static String listToString(List list) + { + return listToString(list, true); + } + + public static String listToString(List list, boolean none) + { + if (none && list.isEmpty()) + return MAMessages.get(Msg.MISC_NONE); + + StringBuffer buffy = new StringBuffer(); + for (E e : list) + { + buffy.append(e.toString()); + buffy.append(" "); + } + return buffy.toString(); + } + + /** + * Returns a String-list version of a comma-separated list. + */ + public static List stringToList(String list) + { + List result = new LinkedList(); + if (list == null) return result; + + String[] parts = list.trim().split(","); + + for (String part : parts) + result.add(part.trim()); + + return result; + } + + /** + * Turns the current set of players into an array, and grabs a random + * element out of it. + */ + public static Player getRandomPlayer(Arena arena) + { + Random random = new Random(); + Player[] array = (Player[]) arena.livePlayers.toArray(); + return array[random.nextInt(array.length)]; + } + + /** + * Verifies that all important variables are declared. Returns true + * if, and only if, the warppoints, region, distribution coefficients, + * and spawnpoints are all set up. + */ + public static boolean verifyData(Arena arena) + { + return ((arena.arenaLoc != null) && + (arena.lobbyLoc != null) && + (arena.spectatorLoc != null) && + (arena.p1 != null) && + (arena.p2 != null) && + (arena.spawnpoints.size() > 0)); + } + /** * Checks if there is a new update of MobArena and notifies the * player if the boolean specified is true */ - public static void checkForUpdates(final Player p, boolean response) + public static void checkForUpdates(MobArena plugin, final Player p, boolean response) { String site = "http://forums.bukkit.org/threads/818.19144/"; try { - // Make a URL of the site address - //URL baseURL = new URL(site); - URI baseURL = new URI(site); + // Make a URI of the site address + URI baseURI = new URI(site); // Open the connection and don't redirect. - HttpURLConnection con = (HttpURLConnection) baseURL.toURL().openConnection(); + HttpURLConnection con = (HttpURLConnection) baseURI.toURL().openConnection(); con.setInstanceFollowRedirects(false); String header = con.getHeaderField("Location"); @@ -670,7 +913,7 @@ public class MAUtils // If something's wrong with the connection... if (header == null) { - ArenaManager.tellPlayer(p, "Couldn't connect to the MobArena thread."); + tellPlayer(p, "Couldn't connect to the MobArena thread."); return; } @@ -678,17 +921,17 @@ public class MAUtils String url = new URI(con.getHeaderField("Location")).toString(); // If the current version is the same as the thread version. - if (url.contains(ArenaManager.plugin.getDescription().getVersion().replace(".", "-"))) + if (url.contains(plugin.getDescription().getVersion().replace(".", "-"))) { if (!response) return; - ArenaManager.tellPlayer(p, "Your version of MobArena is up to date!"); + tellPlayer(p, "Your version of MobArena is up to date!"); return; } // Otherwise, notify the player that there is a new version. - ArenaManager.tellPlayer(p, "There is a new version of MobArena available!");; + tellPlayer(p, "There is a new version of MobArena available!");; } catch (Exception e) { @@ -696,22 +939,35 @@ public class MAUtils } } - /** - * Turns the current set of players into an array, and grabs a random - * element out of it. - */ - public static Player getRandomPlayer() + public static void setSpawnFlags(MobArena plugin, World world, int spawnMonsters, boolean allowMonsters, boolean allowAnimals) { - Random random = new Random(); - Object[] array = ArenaManager.playerSet.toArray(); - return (Player) array[random.nextInt(array.length)]; + for (Arena arena : plugin.getAM().getArenasInWorld(world)) + if (arena.running) + return; + + WorldServer ws = ((CraftWorld) world).getHandle(); + ws.spawnMonsters = spawnMonsters; + ws.allowMonsters = allowMonsters; + ws.allowAnimals = allowAnimals; } /** * Stand back, I'm going to try science! */ - public static void DoooooItHippieMonster(Location loc, int radius) + public static boolean doooooItHippieMonster(Location loc, int radius, String name, MobArena plugin) { + // Try to restore the old patch first. + undoItHippieMonster(name, plugin, false); + + // Grab the Configuration and ArenaMaster + ArenaMaster am = plugin.getAM(); + + // Create the arena node in the config-file. + World world = loc.getWorld(); + Arena arena = am.createArenaNode(name, world); + am.arenas.add(arena); + am.selectedArena = arena; + // Get the hippie bounds. int x1 = (int)loc.getX() - radius; int x2 = (int)loc.getX() + radius; @@ -721,9 +977,9 @@ public class MAUtils int z2 = (int)loc.getZ() + radius; int lx1 = x1; - int lx2 = x1 + ArenaManager.classes.size() + 3; - int ly1 = y1-5; - int ly2 = y1-1; + int lx2 = x1 + am.classes.size() + 3; + int ly1 = y1-6; + int ly2 = y1-2; int lz1 = z1; int lz2 = z1 + 6; @@ -737,24 +993,25 @@ public class MAUtils { for (int k = z1; k <= z2; k++) { - lo = ArenaManager.world.getBlockAt(i,j,k).getLocation(); - id = ArenaManager.world.getBlockAt(i,j,k).getTypeId(); + lo = world.getBlockAt(i,j,k).getLocation(); + id = world.getBlockAt(i,j,k).getTypeId(); preciousPatch.put(new EntityPosition(lo),id); } } } try { - FileOutputStream fos = new FileOutputStream("plugins/MobArena/precious.tmp"); + new File("plugins" + sep + "MobArena" + sep + "agbackup").mkdir(); + FileOutputStream fos = new FileOutputStream("plugins" + sep + "MobArena" + sep + "agbackup" + sep + name + ".tmp"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(preciousPatch); oos.close(); } catch (Exception e) { - System.out.println("Couldn't create backup file. Aborting..."); e.printStackTrace(); - return; + System.out.println("Couldn't create backup file. Aborting auto-generate..."); + return false; } // Build some monster walls. @@ -762,132 +1019,148 @@ public class MAUtils { for (int j = y1; j <= y2; j++) { - ArenaManager.world.getBlockAt(i,j,z1).setTypeId(24); - ArenaManager.world.getBlockAt(i,j,z2).setTypeId(24); + world.getBlockAt(i,j,z1).setTypeId(24); + world.getBlockAt(i,j,z2).setTypeId(24); } } for (int k = z1; k <= z2; k++) { for (int j = y1; j <= y2; j++) { - ArenaManager.world.getBlockAt(x1,j,k).setTypeId(24); - ArenaManager.world.getBlockAt(x2,j,k).setTypeId(24); + world.getBlockAt(x1,j,k).setTypeId(24); + world.getBlockAt(x2,j,k).setTypeId(24); } } // Add some hippie light. for (int i = x1; i <= x2; i++) { - ArenaManager.world.getBlockAt(i,y1+2,z1).setTypeId(89); - ArenaManager.world.getBlockAt(i,y1+2,z2).setTypeId(89); + world.getBlockAt(i,y1+2,z1).setTypeId(89); + world.getBlockAt(i,y1+2,z2).setTypeId(89); } for (int k = z1; k <= z2; k++) { - ArenaManager.world.getBlockAt(x1,y1+2,k).setTypeId(89); - ArenaManager.world.getBlockAt(x2,y1+2,k).setTypeId(89); + world.getBlockAt(x1,y1+2,k).setTypeId(89); + world.getBlockAt(x2,y1+2,k).setTypeId(89); } - // Build a monster floor. + // Build a monster floor, and some Obsidian foundation. for (int i = x1; i <= x2; i++) { for (int k = z1; k <= z2; k++) - ArenaManager.world.getBlockAt(i,y1,k).setTypeId(24); + { + world.getBlockAt(i,y1,k).setTypeId(24); + world.getBlockAt(i,y1-1,k).setTypeId(49); + } } // Make a hippie roof. for (int i = x1; i <= x2; i++) { for (int k = z1; k <= z2; k++) - ArenaManager.world.getBlockAt(i,y2,k).setTypeId(20); + world.getBlockAt(i,y2,k).setTypeId(20); } // Monster bulldoze for (int i = x1+1; i < x2; i++) for (int j = y1+1; j < y2; j++) for (int k = z1+1; k < z2; k++) - ArenaManager.world.getBlockAt(i,j,k).setTypeId(0); + world.getBlockAt(i,j,k).setTypeId(0); // Build a hippie lobby for (int i = lx1; i <= lx2; i++) // Walls { for (int j = ly1; j <= ly2; j++) { - ArenaManager.world.getBlockAt(i,j,lz1).setTypeId(24); - ArenaManager.world.getBlockAt(i,j,lz2).setTypeId(24); + world.getBlockAt(i,j,lz1).setTypeId(24); + world.getBlockAt(i,j,lz2).setTypeId(24); } } for (int k = lz1; k <= lz2; k++) // Walls { for (int j = ly1; j <= ly2; j++) { - ArenaManager.world.getBlockAt(lx1,j,k).setTypeId(24); - ArenaManager.world.getBlockAt(lx2,j,k).setTypeId(24); + world.getBlockAt(lx1,j,k).setTypeId(24); + world.getBlockAt(lx2,j,k).setTypeId(24); } } for (int k = lz1; k <= lz2; k++) // Lights { - ArenaManager.world.getBlockAt(lx1,ly1+2,k).setTypeId(89); - ArenaManager.world.getBlockAt(lx2,ly1+2,k).setTypeId(89); - ArenaManager.world.getBlockAt(lx1,ly1+3,k).setTypeId(89); - ArenaManager.world.getBlockAt(lx2,ly1+3,k).setTypeId(89); + world.getBlockAt(lx1,ly1+2,k).setTypeId(89); + world.getBlockAt(lx2,ly1+2,k).setTypeId(89); + world.getBlockAt(lx1,ly1+3,k).setTypeId(89); + world.getBlockAt(lx2,ly1+3,k).setTypeId(89); } for (int i = lx1; i <= lx2; i++) // Floor { for (int k = lz1; k <= lz2; k++) - ArenaManager.world.getBlockAt(i,ly1,k).setTypeId(24); + world.getBlockAt(i,ly1,k).setTypeId(24); } for (int i = x1+1; i < lx2; i++) // Bulldoze for (int j = ly1+1; j <= ly2; j++) for (int k = lz1+1; k < lz2; k++) - ArenaManager.world.getBlockAt(i,j,k).setTypeId(0); + world.getBlockAt(i,j,k).setTypeId(0); // Place the hippie signs - Iterator iterator = ArenaManager.classes.iterator(); + Iterator iterator = am.classes.iterator(); for (int i = lx1+2; i <= lx2-2; i++) // Signs { - ArenaManager.world.getBlockAt(i,ly1+1,lz2-1).setTypeIdAndData(63, (byte)0x8, false); - Sign sign = (Sign) ArenaManager.world.getBlockAt(i,ly1+1,lz2-1).getState(); + world.getBlockAt(i,ly1+1,lz2-1).setTypeIdAndData(63, (byte)0x8, false); + Sign sign = (Sign) world.getBlockAt(i,ly1+1,lz2-1).getState(); sign.setLine(0, (String)iterator.next()); } - ArenaManager.world.getBlockAt(lx2-2,ly1+1,lz1+2).setType(Material.IRON_BLOCK); + world.getBlockAt(lx2-2,ly1+1,lz1+2).setType(Material.IRON_BLOCK); - // Set up the monster points. - setCoords("arena", new Location(ArenaManager.world, loc.getX(), y1+1, loc.getZ())); - setCoords("lobby", new Location(ArenaManager.world, x1+2, y1-3, z1+2)); - setCoords("spectator", new Location(ArenaManager.world, loc.getX(), y2+1, loc.getZ())); - setCoords("p1", new Location(ArenaManager.world, x1, y1-4, z1)); - setCoords("p2", new Location(ArenaManager.world, x2, y2+1, z2)); - setCoords("spawnpoints.s1", new Location(ArenaManager.world, x1+3, y1+2, z1+3)); - setCoords("spawnpoints.s2", new Location(ArenaManager.world, x1+3, y1+2, z2-3)); - setCoords("spawnpoints.s3", new Location(ArenaManager.world, x2-3, y1+2, z1+3)); - setCoords("spawnpoints.s4", new Location(ArenaManager.world, x2-3, y1+2, z2-3)); + // Set up the monster points. + MAUtils.setArenaCoord(plugin.getConfig(), arena, "p1", new Location(world, x1, ly1, z1)); + MAUtils.setArenaCoord(plugin.getConfig(), arena, "p2", new Location(world, x2, y2+1, z2)); + MAUtils.setArenaCoord(plugin.getConfig(), arena, "arena", new Location(world, loc.getX(), y1+1, loc.getZ())); + MAUtils.setArenaCoord(plugin.getConfig(), arena, "lobby", new Location(world, x1+2, y1-3, z1+2)); + MAUtils.setArenaCoord(plugin.getConfig(), arena, "spectator", new Location(world, loc.getX(), y2+1, loc.getZ())); + MAUtils.setArenaCoord(plugin.getConfig(), arena, "spawnpoints.s1", new Location(world, x1+3, y1+2, z1+3)); + MAUtils.setArenaCoord(plugin.getConfig(), arena, "spawnpoints.s2", new Location(world, x1+3, y1+2, z2-3)); + MAUtils.setArenaCoord(plugin.getConfig(), arena, "spawnpoints.s3", new Location(world, x2-3, y1+2, z1+3)); + MAUtils.setArenaCoord(plugin.getConfig(), arena, "spawnpoints.s4", new Location(world, x2-3, y1+2, z2-3)); + + am.updateAll(); + return true; } /** * This fixes everything! */ @SuppressWarnings("unchecked") - public static void UnDoooooItHippieMonster() + public static boolean undoItHippieMonster(String name, MobArena plugin, boolean error) { + File file = new File("plugins" + sep + "MobArena" + sep + "agbackup" + sep + name + ".tmp"); HashMap preciousPatch; try { - FileInputStream fis = new FileInputStream("plugins/MobArena/precious.tmp"); + FileInputStream fis = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(fis); preciousPatch = (HashMap) ois.readObject(); ois.close(); } catch (Exception e) { - System.out.println("Couldn't find backup file..."); - return; + if (error) System.out.println("Couldn't find backup file for arena '" + name + "'"); + return false; } - for (EntityPosition ep : preciousPatch.keySet()) + World world = Bukkit.getServer().getWorld(preciousPatch.keySet().iterator().next().getWorld()); + + for (Map.Entry entry : preciousPatch.entrySet()) { - ArenaManager.world.getBlockAt(ep.getLocation(ArenaManager.world)).setTypeId(preciousPatch.get(ep)); + world.getBlockAt(entry.getKey().getLocation(world)).setTypeId(entry.getValue()); } - delCoords("coords"); + Configuration config = plugin.getConfig(); + config.removeProperty("arenas." + name); + config.save(); + + file.delete(); + + plugin.getAM().updateAll(); + return true; } } \ No newline at end of file diff --git a/src/com/garbagemule/MobArena/MobArena.java b/src/com/garbagemule/MobArena/MobArena.java index 768d859..1d705e7 100644 --- a/src/com/garbagemule/MobArena/MobArena.java +++ b/src/com/garbagemule/MobArena/MobArena.java @@ -1,30 +1,33 @@ package com.garbagemule.MobArena; -import java.util.List; +import java.io.File; +import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.Event.Priority; import org.bukkit.event.block.BlockListener; import org.bukkit.event.player.PlayerListener; import org.bukkit.event.entity.EntityListener; +import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.PluginManager; +import org.bukkit.util.config.Configuration; + +import com.nijiko.permissions.PermissionHandler; +import com.nijikokun.bukkit.Permissions.Permissions; /** * MobArena - * * @author garbagemule */ public class MobArena extends JavaPlugin { - /* Array of commands used to determine if a command belongs to MobArena - * or Mean Admins. */ - public final String[] COMMANDS = {"join", "j", "leave", "l", "list", "who", "spectate", "spec", - "ready", "notready", "enabled", "force", "config", "setwarp", - "addspawn", "delspawn", "setregion", "expandregion", "protect", - "undo", "dooooo", "reset"}; - public List DISABLED_COMMANDS; + private Configuration config; + private ArenaMaster am; + + // Permissions stuff + protected static PermissionHandler permissionHandler; public MobArena() { @@ -34,52 +37,217 @@ public class MobArena extends JavaPlugin { PluginDescriptionFile pdfFile = this.getDescription(); - // Initialize convenience variables in ArenaManager. - ArenaManager.init(this); - DISABLED_COMMANDS = MAUtils.getDisabledCommands(); + // Config, messages and ArenaMaster initialization + loadConfig(); + MAMessages.init(this); + am = new ArenaMaster(this); + am.initialize(); - // Bind the /ma and /marena commands to MACommands. - getCommand("ma").setExecutor(new MACommands()); - getCommand("marena").setExecutor(new MACommands()); - getCommand("mobarena").setExecutor(new MACommands()); - - + // Permissions + setupPermissions(); + // Bind the /ma, /marena, and /mobarena commands to MACommands. + MACommands commandExecutor = new MACommands(this, am); + getCommand("ma").setExecutor(commandExecutor); + getCommand("marena").setExecutor(commandExecutor); + getCommand("mobarena").setExecutor(commandExecutor); + // Create event listeners. PluginManager pm = getServer().getPluginManager(); - PlayerListener commandListener = new MADisabledCommands(this); - PlayerListener lobbyListener = new MALobbyListener(this); - PlayerListener teleportListener = new MATeleportListener(this); - PlayerListener discListener = new MADisconnectListener(this); - BlockListener blockListener = new MABlockListener(this); - EntityListener deathListener = new MADeathListener(this); - EntityListener monsterListener = new MAMonsterListener(this); - // TO-DO: PlayerListener to check for kills/deaths. + PlayerListener playerListener = new MAPlayerListener(this, am); + EntityListener entityListener = new MAEntityListener(am); + BlockListener blockListener = new MABlockListener(am); // Register events. - pm.registerEvent(Event.Type.PLAYER_COMMAND_PREPROCESS, commandListener, Priority.Monitor, this); - pm.registerEvent(Event.Type.PLAYER_INTERACT, lobbyListener, Priority.Normal, this); - pm.registerEvent(Event.Type.PLAYER_DROP_ITEM, lobbyListener, Priority.Normal, this); - pm.registerEvent(Event.Type.PLAYER_BUCKET_EMPTY, lobbyListener, Priority.Normal, this); - pm.registerEvent(Event.Type.PLAYER_TELEPORT, teleportListener, Priority.Normal, this); - pm.registerEvent(Event.Type.PLAYER_QUIT, discListener, Priority.Normal, this); - pm.registerEvent(Event.Type.PLAYER_KICK, discListener, Priority.Normal, this); - pm.registerEvent(Event.Type.PLAYER_JOIN, discListener, Priority.Normal, this); - pm.registerEvent(Event.Type.BLOCK_BREAK, blockListener, Priority.Normal, this); - pm.registerEvent(Event.Type.BLOCK_PLACE, blockListener, Priority.Normal, this); - pm.registerEvent(Event.Type.ENTITY_DEATH, deathListener, Priority.Lowest, this); // Lowest because of Tombstone - pm.registerEvent(Event.Type.ENTITY_EXPLODE, monsterListener, Priority.Normal, this); - pm.registerEvent(Event.Type.ENTITY_COMBUST, monsterListener, Priority.Normal, this); - pm.registerEvent(Event.Type.ENTITY_TARGET, monsterListener, Priority.Normal, this); - pm.registerEvent(Event.Type.CREATURE_SPAWN, monsterListener, Priority.Normal, this); + pm.registerEvent(Event.Type.PLAYER_INTERACT, playerListener, Priority.Normal, this); + pm.registerEvent(Event.Type.PLAYER_DROP_ITEM, playerListener, Priority.Normal, this); + pm.registerEvent(Event.Type.PLAYER_BUCKET_EMPTY, playerListener, Priority.Normal, this); + pm.registerEvent(Event.Type.PLAYER_TELEPORT, playerListener, Priority.Normal, this); + pm.registerEvent(Event.Type.PLAYER_QUIT, playerListener, Priority.Normal, this); + pm.registerEvent(Event.Type.PLAYER_KICK, playerListener, Priority.Normal, this); + pm.registerEvent(Event.Type.PLAYER_JOIN, playerListener, Priority.Normal, this); + pm.registerEvent(Event.Type.BLOCK_BREAK, blockListener, Priority.Highest, this); + pm.registerEvent(Event.Type.BLOCK_PLACE, blockListener, Priority.Highest, this); + pm.registerEvent(Event.Type.ENTITY_DAMAGE, entityListener, Priority.Highest, this); + pm.registerEvent(Event.Type.ENTITY_DEATH, entityListener, Priority.Lowest, this); // Lowest because of Tombstone + pm.registerEvent(Event.Type.ENTITY_REGAIN_HEALTH, entityListener, Priority.Normal, this); + pm.registerEvent(Event.Type.ENTITY_EXPLODE, entityListener, Priority.Highest, this); + 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); - System.out.println(pdfFile.getName() + " v" + pdfFile.getVersion() + " enabled." ); + System.out.println("[MobArena] v" + pdfFile.getVersion() + " enabled." ); } public void onDisable() - { - System.out.println("WAIT! WHAT ARE YOU DOING?!"); + { + for (Arena arena : am.arenas) + arena.forceEnd(); + am.arenaMap.clear(); - ArenaManager.forceEnd(null); + System.out.println("[MobArena] disabled."); + } + + /** + * Load the config-file and initialize the Configuration object. + */ + private void loadConfig() + { + File file = new File(this.getDataFolder(), "config.yml"); + if (!file.exists()) + { + try + { + this.getDataFolder().mkdir(); + file.createNewFile(); + } + catch (Exception e) + { + e.printStackTrace(); + return; + } + } + // TODO: Remove in v1.0 + else + { + Configuration tmp = new Configuration(file); + tmp.load(); + if (tmp.getKeys("global-settings") == null) + { + file.renameTo(new File(this.getDataFolder(), "config_OLD.yml")); + file = new File(this.getDataFolder(), "config.yml"); + try + { + this.getDataFolder().mkdir(); + file.createNewFile(); + } + catch (Exception e) + { + e.printStackTrace(); + return; + } + + config = new Configuration(file); + config.load(); + fixConfig(); + config.setHeader("# MobArena Configuration-file\r\n# Please go to https://github.com/garbagemule/MobArena/wiki/Installing-MobArena for more details."); + config.save(); + } + } + + config = new Configuration(file); + config.load(); + config.setHeader("# MobArena Configuration-file\r\n# Please go to https://github.com/garbagemule/MobArena/wiki/Installing-MobArena for more details."); + config.save(); + } + + // Permissions stuff + public static boolean has(Player p, String s) + { + //return (permissionHandler != null && permissionHandler.has(p, s)); + return (permissionHandler == null || permissionHandler.has(p, s)); + } + + public static boolean hasDefTrue(Player p, String s) + { + return (permissionHandler == null || permissionHandler.has(p, s)); + } + + private void setupPermissions() + { + if (permissionHandler != null) + return; + + Plugin permissionsPlugin = this.getServer().getPluginManager().getPlugin("Permissions"); + if (permissionsPlugin == null) return; + + permissionHandler = ((Permissions) permissionsPlugin).getHandler(); + } + + public Configuration getConfig() { return config; } + public ArenaMaster getAM() { return am; } // More convenient. + public ArenaMaster getArenaMaster() { return am; } + + // TODO: Remove in v1.0 + private void fixConfig() + { + // If global-settings is sorted, don't do anything. + if (config.getKeys("global-settings") != null) + return; + + File oldFile = new File(this.getDataFolder(), "config_OLD.yml"); + if (!oldFile.exists()) + return; + + System.out.println("[MobArena] Config-file appears to be old. Trying to fix it..."); + + Configuration oldConfig = new Configuration(oldFile); + oldConfig.load(); + + config.setProperty("global-settings.enabled", true); + config.save(); + config.load(); + config.setProperty("global-settings.update-notification", true); + config.save(); + config.load(); + + // Copy classes + for (String s : oldConfig.getKeys("classes")) + { + config.setProperty("classes." + s + ".items", oldConfig.getString("classes." + s + ".items")); + config.setProperty("classes." + s + ".armor", oldConfig.getString("classes." + s + ".armor")); + } + config.save(); + + // Make the default arena node. + config.setProperty("arenas.default.settings.enabled", true); + config.save(); + config.load(); + config.setProperty("arenas.default.settings.world", oldConfig.getString("settings.world")); + config.save(); + config.load(); + + // Copy the coords. + for (String s : oldConfig.getKeys("coords")) + { + if (s.equals("spawnpoints")) + continue; + + StringBuffer buffy = new StringBuffer(); + buffy.append(oldConfig.getString("coords." + s + ".x")); + buffy.append(","); + buffy.append(oldConfig.getString("coords." + s + ".y")); + buffy.append(","); + buffy.append(oldConfig.getString("coords." + s + ".z")); + buffy.append(","); + buffy.append(oldConfig.getString("coords." + s + ".yaw")); + buffy.append(","); + buffy.append(oldConfig.getString("coords." + s + ".pitch")); + + config.setProperty("arenas.default.coords." + s, buffy.toString()); + } + config.save(); + config.load(); + + for (String s : oldConfig.getKeys("coords.spawnpoints")) + { + StringBuffer buffy = new StringBuffer(); + buffy.append(oldConfig.getString("coords.spawnpoints." + s + ".x")); + buffy.append(","); + buffy.append(oldConfig.getString("coords.spawnpoints." + s + ".y")); + buffy.append(","); + buffy.append(oldConfig.getString("coords.spawnpoints." + s + ".z")); + buffy.append(","); + buffy.append(oldConfig.getString("coords.spawnpoints." + s + ".yaw")); + buffy.append(","); + buffy.append(oldConfig.getString("coords.spawnpoints." + s + ".pitch")); + + config.setProperty("arenas.default.coords.spawnpoints." + s, buffy.toString()); + } + config.save(); + config.load(); + + System.out.println("[MobArena] Updated the config-file!"); } } \ No newline at end of file diff --git a/src/com/garbagemule/MobArena/MobArenaHandler.java b/src/com/garbagemule/MobArena/MobArenaHandler.java index e204808..80f4b3b 100644 --- a/src/com/garbagemule/MobArena/MobArenaHandler.java +++ b/src/com/garbagemule/MobArena/MobArenaHandler.java @@ -1,34 +1,105 @@ package com.garbagemule.MobArena; import java.util.List; -import java.util.LinkedList; +import org.bukkit.Bukkit; import org.bukkit.Location; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; public class MobArenaHandler { + MobArena plugin; + public MobArenaHandler() { + plugin = (MobArena) Bukkit.getServer().getPluginManager().getPlugin("MobArena"); } // Check if there is an active arena session running. - public boolean isRunning() { return ArenaManager.isRunning; } + public boolean isRunning(String arenaName) + { + Arena arena = plugin.getAM().getArenaWithName(arenaName); + if (arena == null) + throw new NullPointerException("Arena with name '" + arenaName + "' does not exist!"); + + return arena.running; + } - // Check if the specified player is in the arena/lobby. - public boolean isPlaying(Player p) { return ArenaManager.playerSet.contains(p); } + // Check if the specified player is in an arena. + public boolean isPlaying(Player p) { return (plugin.getAM().getArenaWithPlayer(p) != null); } - // Get a list of all players currently in the arena. - public List getPlayers() { return new LinkedList(ArenaManager.playerSet); } + // Arena getters + public Arena getArenaWithName(String arenaName) { return plugin.getAM().getArenaWithName(arenaName); } + public Arena getArenaWithPlayer(Player p) { return plugin.getAM().getArenaWithPlayer(p); } + public Arena getArenaWithPet(Entity wolf) { return plugin.getAM().getArenaWithPet(wolf); } + public Arena getArenaWithMonster(Entity monster) { return plugin.getAM().getArenaWithMonster(monster); } + public Arena getArenaInLocation(Location l) { return plugin.getAM().getArenaInLocation(l); } - // Get the warp locations. - public Location getArenaLocation() { return ArenaManager.arenaLoc; } - public Location getLobbyLocation() { return ArenaManager.lobbyLoc; } - public Location getSpectatorLocation() { return ArenaManager.spectatorLoc; } + // Player lists + public List getAllPlayers() { return plugin.getAM().getAllPlayers(); } + public List getAllLivingPlayers() { return plugin.getAM().getAllLivingPlayers(); } + public List getAllPlayersInArena(String arenaName) { return plugin.getAM().getAllPlayersInArena(arenaName); } + public List getLivingPlayersInArena(String arenaName) { return plugin.getAM().getLivingPlayersInArena(arenaName); } + + // Warp locations. + public Location getArenaLocation(String arenaName) + { + Arena arena = plugin.getAM().getArenaWithName(arenaName); + if (arena == null) + throw new NullPointerException("Arena with name '" + arenaName + "' does not exist!"); + + return arena.arenaLoc; + } + public Location getLobbyLocation(String arenaName) + { + Arena arena = plugin.getAM().getArenaWithName(arenaName); + if (arena == null) + throw new NullPointerException("Arena with name '" + arenaName + "' does not exist!"); + + return arena.lobbyLoc; + } + public Location getSpectatorLocation(String arenaName) + { + Arena arena = plugin.getAM().getArenaWithName(arenaName); + if (arena == null) + throw new NullPointerException("Arena with name '" + arenaName + "' does not exist!"); + + return arena.spectatorLoc; + } // Get the current wave number. - public int getWave() { return ArenaManager.wave; } + public int getWave(Arena arena) { return arena.spawnThread.wave; } - // Check if a location is in the arena region - public boolean inRegion(Location l) { return MAUtils.inRegion(l); } + public int getWave(String arenaName) + { + Arena arena = plugin.getAM().getArenaWithName(arenaName); + if (arena == null) + throw new NullPointerException("Arena with name '" + arenaName + "' does not exist!"); + + if (arena.spawnThread == null) + throw new NullPointerException("Arena with name '" + arenaName + "' has not started!"); + + return arena.spawnThread.wave; + } + + // Check if a location is within any arena regions. + + public boolean inRegion(Location l, Arena arena) { return arena.inRegion(l); } + + public boolean inRegion(Location l, String arenaName) + { + Arena arena = plugin.getAM().getArenaWithName(arenaName); + if (arena == null) + throw new NullPointerException("Arena with name '" + arenaName + "' does not exist!"); + + return arena.inRegion(l); + } + public boolean inRegion(Location l) + { + for (Arena arena : plugin.getAM().arenas) + if (arena.inRegion(l)) + return true; + return false; + } } diff --git a/src/com/garbagemule/MobArena/MobArenaListener.java b/src/com/garbagemule/MobArena/MobArenaListener.java index a71e8bf..1613774 100644 --- a/src/com/garbagemule/MobArena/MobArenaListener.java +++ b/src/com/garbagemule/MobArena/MobArenaListener.java @@ -1,5 +1,6 @@ package com.garbagemule.MobArena; +import org.bukkit.Bukkit; import org.bukkit.entity.Player; public class MobArenaListener @@ -7,9 +8,9 @@ public class MobArenaListener protected MobArena plugin; public MobArenaListener() - { - plugin = ArenaManager.plugin; - ArenaManager.listeners.add(this); + { + plugin = (MobArena) Bukkit.getServer().getPluginManager().getPlugin("MobArena"); + plugin.getAM().listeners.add(this); } public void onArenaStart() {}