Update for Spigot and mavenize.

This commit is contained in:
garbagemule
2015-07-17 03:38:41 +02:00
parent 91d426a74b
commit aafeb93d38
175 changed files with 97 additions and 152 deletions
@@ -0,0 +1,334 @@
package com.garbagemule.MobArena;
import java.util.*;
import java.util.Map.Entry;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.permissions.PermissionAttachment;
public class ArenaClass
{
private String configName, lowercaseName;
private ItemStack helmet, chestplate, leggings, boots;
private List<ItemStack> items, armor;
private Map<String,Boolean> perms;
private Map<String,Boolean> lobbyperms;
private boolean unbreakableWeapons, unbreakableArmor;
private double price;
private Location classchest;
/**
* Create a new, empty arena class with the given name.
* @param name the class name as it appears in the config-file
*/
public ArenaClass(String name, double price, boolean unbreakableWeapons, boolean unbreakableArmor) {
this.configName = name;
this.lowercaseName = name.toLowerCase();
this.items = new ArrayList<ItemStack>();
this.armor = new ArrayList<ItemStack>(4);
this.perms = new HashMap<String,Boolean>();
this.lobbyperms = new HashMap<String,Boolean>();
this.unbreakableWeapons = unbreakableWeapons;
this.unbreakableArmor = unbreakableArmor;
this.price = price;
}
/**
* Get the name of the arena class as it appears in the config-file.
* @return the class name as it appears in the config-file
*/
public String getConfigName() {
return configName;
}
/**
* Get the lowercase class name.
* @return the lowercase class name
*/
public String getLowercaseName() {
return lowercaseName;
}
/**
* Get the Material type of the first item in the items list.
* If the items list is empty, the method returns Material.STONE
* @return the type of the first item, or STONE if the list is empty
*/
public Material getLogo() {
if (items.isEmpty()) {
return Material.STONE;
}
return items.get(0).getType();
}
/**
* Set the helmet slot for the class.
* @param helmet an item
*/
public void setHelmet(ItemStack helmet) {
this.helmet = helmet;
}
/**
* Set the chestplate slot for the class.
* @param chestplate an item
*/
public void setChestplate(ItemStack chestplate) {
this.chestplate = chestplate;
}
/**
* Set the leggings slot for the class.
* @param leggings an item
*/
public void setLeggings(ItemStack leggings) {
this.leggings = leggings;
}
/**
* Set the boots slot for the class.
* @param boots an item
*/
public void setBoots(ItemStack boots) {
this.boots = boots;
}
/**
* Add an item to the items list.
* @param stack an item
*/
public void addItem(ItemStack stack) {
if (stack == null) return;
if (stack.getAmount() > 64) {
while (stack.getAmount() > 64) {
items.add(new ItemStack(stack.getType(), 64));
stack.setAmount(stack.getAmount() - 64);
}
}
items.add(stack);
}
/**
* Replace the current items list with a new list of all the items in the given list.
* This method uses the addItem() method for each item to ensure consistency.
* @param stacks a list of items
*/
public void setItems(List<ItemStack> stacks) {
this.items = new ArrayList<ItemStack>(stacks.size());
for (ItemStack stack : stacks) {
addItem(stack);
}
}
/**
* Replace the current armor list with the given list.
* @param armor a list of items
*/
public void setArmor(List<ItemStack> armor) {
this.armor = armor;
}
/**
* Grants all of the class items and armor to the given player.
* The normal items will be added to the inventory normally, while the
* armor items will be verified as armor items and placed in their
* appropriate slots. If any specific armor slots are specified, they
* will overwrite any items in the armor list.
* @param p a player
*/
public void grantItems(Player p) {
PlayerInventory inv = p.getInventory();
// Fork over the items.
for (ItemStack stack : items) {
inv.addItem(stack);
}
// Check for legacy armor-node items
if (!armor.isEmpty()) {
for (ItemStack piece : armor) {
ArmorType type = ArmorType.getType(piece);
if (type == null) continue;
switch (type) {
case HELMET:
inv.setHelmet(piece);
break;
case CHESTPLATE:
inv.setChestplate(piece);
break;
case LEGGINGS:
inv.setLeggings(piece);
break;
case BOOTS:
inv.setBoots(piece);
break;
default:
break;
}
}
}
// Check type specifics.
if (helmet != null) inv.setHelmet(helmet);
if (chestplate != null) inv.setChestplate(chestplate);
if (leggings != null) inv.setLeggings(leggings);
if (boots != null) inv.setBoots(boots);
}
/**
* Add a permission value to the class.
* @param perm the permission
* @param value the value
*/
public void addPermission(String perm, boolean value) {
perms.put(perm, value);
}
/**
* Get an unmodifiable map of permissions and values for the class.
* @return a map of permissions and values
*/
public Map<String,Boolean> getPermissions() {
return Collections.unmodifiableMap(perms);
}
public void addLobbyPermission(String perm, boolean value) {
lobbyperms.put(perm, value);
}
public Map<String,Boolean> getLobbyPermissions() {
return Collections.unmodifiableMap(lobbyperms);
}
/**
* Grant the given player all the permissions of the class.
* All permissions will be attached to a PermissionAttachment object, which
* will be returned to the caller.
* @param plugin a MobArena instance
* @param p a player
* @return the PermissionAttachment with all the permissions
*/
public PermissionAttachment grantPermissions(MobArena plugin, Player p) {
if (perms.isEmpty()) return null;
PermissionAttachment pa = p.addAttachment(plugin);
grantPerms(pa, perms, p);
return pa;
}
public PermissionAttachment grantLobbyPermissions(MobArena plugin, Player p) {
if (lobbyperms.isEmpty()) return null;
PermissionAttachment pa = p.addAttachment(plugin);
grantPerms(pa, lobbyperms, p);
return pa;
}
private void grantPerms(PermissionAttachment pa, Map<String,Boolean> map, Player p) {
for (Entry<String,Boolean> entry : map.entrySet()) {
try {
pa.setPermission(entry.getKey(), entry.getValue());
}
catch (Exception e) {
String perm = entry.getKey() + ":" + entry.getValue();
String player = p.getName();
Messenger.warning("[PERM00] Failed to attach permission '" + perm + "' to player '" + player + " with class " + this.configName
+ "'.\nPlease verify that your class permissions are well-formed.");
}
}
}
public Location getClassChest() {
return classchest;
}
public void setClassChest(Location loc) {
classchest = loc;
}
public boolean hasUnbreakableWeapons() {
return unbreakableWeapons;
}
public boolean hasUnbreakableArmor() {
return unbreakableArmor;
}
public double getPrice() {
return price;
}
/**
* Used by isWeapon() to determine if an ItemStack is a weapon type.
*/
private static int[] weaponTypes = {256,257,258,259,261,267,268,269,270,271,272,273,274,275,276,277,278,279,283,284,285,286,290,291,292,293,294,346,398};
/**
* Returns true, if the ItemStack appears to be a weapon, in which case
* the addItem() method will set the weapon durability to the absolute
* maximum, as to give them "infinite" durability.
* @param stack an ItemStack
* @return true, if the item is a weapon
*/
public static boolean isWeapon(ItemStack stack) {
if (stack == null) return false;
return Arrays.binarySearch(weaponTypes, stack.getTypeId()) > -1;
}
/**
* Used by the grantItems() method to determine the armor type of a given
* ItemStack. Armor pieces are auto-equipped.
* Note: This enum is only necessary for backward-compatibility with the
* 'armor'-node.
*/
public enum ArmorType {
HELMET (298,302,306,310,314),
CHESTPLATE (299,303,307,311,315),
LEGGINGS (300,304,308,312,316),
BOOTS (301,305,309,313,317);
private int[] types;
private ArmorType(int... types) {
this.types = types;
}
public static ArmorType getType(ItemStack stack) {
int id = stack.getTypeId();
for (ArmorType armorType : ArmorType.values()) {
for (int type : armorType.types) {
if (id == type) {
return armorType;
}
}
}
return null;
}
}
@Override
public boolean equals(Object o) {
if (o == null) return false;
if (this == o) return true;
if (!this.getClass().equals(o.getClass())) return false;
ArenaClass other = (ArenaClass) o;
return other.lowercaseName.equals(this.lowercaseName);
}
@Override
public int hashCode() {
return lowercaseName.hashCode();
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,661 @@
package com.garbagemule.MobArena;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.ArrayList;
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.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionDefault;
import org.bukkit.plugin.PluginManager;
import static com.garbagemule.MobArena.util.config.ConfigUtils.makeSection;
import static com.garbagemule.MobArena.util.config.ConfigUtils.parseLocation;
import com.garbagemule.MobArena.ArenaClass.ArmorType;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
import com.garbagemule.MobArena.util.ItemParser;
import com.garbagemule.MobArena.util.TextUtils;
import com.garbagemule.MobArena.util.config.ConfigUtils;
public class ArenaMasterImpl implements ArenaMaster
{
private MobArena plugin;
private FileConfiguration config;
private List<Arena> arenas;
private Map<Player, Arena> arenaMap;
private Arena selectedArena;
private Map<String, ArenaClass> classes;
private Set<String> allowedCommands;
private boolean enabled;
/**
* Default constructor.
*/
public ArenaMasterImpl(MobArena plugin) {
this.plugin = plugin;
this.config = plugin.getConfig();
this.arenas = new ArrayList<Arena>();
this.arenaMap = new HashMap<Player, Arena>();
this.classes = new HashMap<String, ArenaClass>();
this.allowedCommands = new HashSet<String>();
this.enabled = config.getBoolean("global-settings.enabled", true);
}
/*
* /////////////////////////////////////////////////////////////////////////
* // // NEW METHODS IN REFACTORING //
* /////////////////////////////////////////////////////////////////////////
*/
public MobArena getPlugin() {
return plugin;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean value) {
enabled = value;
config.set("global-settings.enabled", enabled);
}
public boolean notifyOnUpdates() {
return config.getBoolean("global-settings.update-notification", false);
}
public List<Arena> getArenas() {
return arenas;
}
public Map<String, ArenaClass> getClasses() {
return classes;
}
public void addPlayer(Player p, Arena arena) {
arenaMap.put(p, arena);
}
public Arena removePlayer(Player p) {
return arenaMap.remove(p);
}
public void resetArenaMap() {
arenaMap.clear();
}
public boolean isAllowed(String command) {
return allowedCommands.contains(command);
}
/*
* /////////////////////////////////////////////////////////////////////////
* // // Arena getters //
* /////////////////////////////////////////////////////////////////////////
*/
public List<Arena> getEnabledArenas() {
return getEnabledArenas(arenas);
}
public List<Arena> getEnabledArenas(List<Arena> arenas) {
List<Arena> result = new ArrayList<Arena>(arenas.size());
for (Arena arena : arenas)
if (arena.isEnabled())
result.add(arena);
return result;
}
public List<Arena> getPermittedArenas(Player p) {
List<Arena> result = new ArrayList<Arena>(arenas.size());
for (Arena arena : arenas)
if (plugin.has(p, "mobarena.arenas." + arena.configName()))
result.add(arena);
return result;
}
public List<Arena> getEnabledAndPermittedArenas(Player p) {
List<Arena> result = new ArrayList<Arena>(arenas.size());
for (Arena arena : arenas)
if (arena.isEnabled() && plugin.has(p, "mobarena.arenas." + arena.configName()))
result.add(arena);
return result;
}
public Arena getArenaAtLocation(Location loc) {
for (Arena arena : arenas)
if (arena.getRegion().contains(loc))
return arena;
return null;
}
public List<Arena> getArenasInWorld(World world) {
List<Arena> result = new ArrayList<Arena>(arenas.size());
for (Arena arena : arenas)
if (arena.getWorld().equals(world))
result.add(arena);
return result;
}
public List<Player> getAllPlayers() {
List<Player> result = new ArrayList<Player>(arenas.size());
for (Arena arena : arenas)
result.addAll(arena.getAllPlayers());
return result;
}
public List<Player> getAllPlayersInArena(String arenaName) {
Arena arena = getArenaWithName(arenaName);
return (arena != null) ? new ArrayList<Player>(arena.getPlayersInArena()) : new ArrayList<Player>();
}
public List<Player> getAllLivingPlayers() {
List<Player> result = new ArrayList<Player>();
for (Arena arena : arenas)
result.addAll(arena.getPlayersInArena());
return result;
}
public List<Player> getLivingPlayersInArena(String arenaName) {
Arena arena = getArenaWithName(arenaName);
return (arena != null) ? new ArrayList<Player>(arena.getPlayersInArena()) : new ArrayList<Player>();
}
public Arena getArenaWithPlayer(Player p) {
return arenaMap.get(p);
}
public Arena getArenaWithPlayer(String playerName) {
return arenaMap.get(plugin.getServer().getPlayer(playerName));
}
public Arena getArenaWithSpectator(Player p) {
for (Arena arena : arenas) {
if (arena.getSpectators().contains(p))
return arena;
}
return null;
}
public Arena getArenaWithMonster(Entity e) {
for (Arena arena : arenas)
if (arena.getMonsterManager().getMonsters().contains(e))
return arena;
return null;
}
public Arena getArenaWithPet(Entity e) {
for (Arena arena : arenas)
if (arena.hasPet(e))
return arena;
return null;
}
public Arena getArenaWithName(String configName) {
return getArenaWithName(this.arenas, configName);
}
public Arena getArenaWithName(Collection<Arena> arenas, String configName) {
for (Arena arena : arenas)
if (arena.configName().equals(configName))
return arena;
return null;
}
/*
* /////////////////////////////////////////////////////////////////////////
* // // Initialization //
* /////////////////////////////////////////////////////////////////////////
*/
public void initialize() {
loadSettings();
loadClasses();
loadArenas();
}
/**
* Load the global settings.
*/
public void loadSettings() {
ConfigurationSection section = plugin.getConfig().getConfigurationSection("global-settings");
ConfigUtils.addMissingRemoveObsolete(plugin, "global-settings.yml", section);
// Grab the commands string
String cmds = section.getString("allowed-commands", "");
// Split by commas
String[] parts = cmds.split(",");
// Add in the /ma command.
allowedCommands.add("/ma");
// Add in each command
for (String part : parts) {
allowedCommands.add(part.trim().toLowerCase());
}
}
/**
* Load all class-related stuff.
*/
public void loadClasses() {
ConfigurationSection section = makeSection(plugin.getConfig(), "classes");
ConfigUtils.addIfEmpty(plugin, "classes.yml", section);
// Establish the map.
classes = new HashMap<String, ArenaClass>();
Set<String> classNames = section.getKeys(false);
// Load each individual class.
for (String className : classNames) {
loadClass(className);
}
}
/**
* Helper method for loading a single class.
*/
private ArenaClass loadClass(String classname) {
ConfigurationSection section = config.getConfigurationSection("classes." + classname);
String lowercase = classname.toLowerCase();
// If the section doesn't exist, the class doesn't either.
if (section == null) {
Messenger.severe("Failed to load class '" + classname + "'.");
return null;
}
// Check if weapons and armor for this class should be unbreakable
boolean weps = section.getBoolean("unbreakable-weapons", true);
boolean arms = section.getBoolean("unbreakable-armor", true);
// Grab the class price, if any
double price = -1D;
String priceString = section.getString("price", null);
if (priceString != null) {
ItemStack priceItem = ItemParser.parseItem(priceString);
if (priceItem != null && priceItem.getTypeId() == MobArena.ECONOMY_MONEY_ID) {
price = (priceItem.getAmount() + (priceItem.getDurability() / 100D));
} else {
Messenger.warning("The price for class '" + classname + "' could not be parsed!");
Messenger.warning("- expected e.g. '$10', found '" + priceString + "'");
}
}
// Create an ArenaClass with the config-file name.
ArenaClass arenaClass = new ArenaClass(classname, price, weps, arms);
// Parse the items-node
List<String> items = section.getStringList("items");
if (items == null || items.isEmpty()) {
String str = section.getString("items", "");
List<ItemStack> stacks = ItemParser.parseItems(str);
arenaClass.setItems(stacks);
} else {
List<ItemStack> stacks = new ArrayList<ItemStack>();
for (String item : items) {
ItemStack stack = ItemParser.parseItem(item);
if (stack != null) {
stacks.add(stack);
}
}
arenaClass.setItems(stacks);
}
// And the legacy armor-node
String armor = section.getString("armor", "");
if (!armor.equals("")) {
List<ItemStack> stacks = ItemParser.parseItems(armor);
arenaClass.setArmor(stacks);
}
// Get armor strings
String head = section.getString("helmet", null);
String chest = section.getString("chestplate", null);
String legs = section.getString("leggings", null);
String feet = section.getString("boots", null);
// Parse to ItemStacks
ItemStack helmet = ItemParser.parseItem(head);
ItemStack chestplate = ItemParser.parseItem(chest);
ItemStack leggings = ItemParser.parseItem(legs);
ItemStack boots = ItemParser.parseItem(feet);
// Set in ArenaClass
arenaClass.setHelmet(helmet);
arenaClass.setChestplate(chestplate);
arenaClass.setLeggings(leggings);
arenaClass.setBoots(boots);
// Per-class permissions
loadClassPermissions(arenaClass, section);
loadClassLobbyPermissions(arenaClass, section);
// Register the permission.
registerPermission("mobarena.classes." + lowercase, PermissionDefault.TRUE).addParent("mobarena.classes", true);
// Check for class chests
Location cc = parseLocation(section, "classchest", null);
arenaClass.setClassChest(cc);
// Finally add the class to the classes map.
classes.put(lowercase, arenaClass);
return arenaClass;
}
private void loadClassPermissions(ArenaClass arenaClass, ConfigurationSection section) {
List<String> perms = section.getStringList("permissions");
if (perms.isEmpty()) return;
for (String perm : perms) {
// If the permission starts with - or ^, it must be revoked.
boolean value = true;
if (perm.startsWith("-") || perm.startsWith("^")) {
perm = perm.substring(1).trim();
value = false;
}
arenaClass.addPermission(perm, value);
}
}
private void loadClassLobbyPermissions(ArenaClass arenaClass, ConfigurationSection section) {
List<String> perms = section.getStringList("lobby-permissions");
if (perms.isEmpty()) return;
for (String perm : perms) {
// If the permission starts with - or ^, it must be revoked.
boolean value = true;
if (perm.startsWith("-") || perm.startsWith("^")) {
perm = perm.substring(1).trim();
value = false;
}
arenaClass.addLobbyPermission(perm, value);
}
}
public ArenaClass createClassNode(String classname, PlayerInventory inv, boolean safe) {
String path = "classes." + classname;
if (safe && config.getConfigurationSection(path) != null) {
return null;
}
// Create the node.
config.set(path, "");
// Grab the section, create if missing
ConfigurationSection section = config.getConfigurationSection(path);
if (section == null) section = config.createSection(path);
// Take the current items and armor.
section.set("items", ItemParser.parseString(inv.getContents()));
section.set("armor", ItemParser.parseString(inv.getArmorContents()));
// If the helmet isn't a real helmet, set it explicitly.
ItemStack helmet = inv.getHelmet();
if (helmet != null && ArmorType.getType(helmet) != ArmorType.HELMET) {
section.set("helmet", ItemParser.parseString(helmet));
}
// Save changes.
plugin.saveConfig();
// Load the class
return loadClass(classname);
}
public void removeClassNode(String classname) {
String lowercase = classname.toLowerCase();
if (!classes.containsKey(lowercase))
throw new IllegalArgumentException("Class does not exist!");
// Remove the class from the config-file and save it.
config.set("classes." + classname, null);
plugin.saveConfig();
// Remove the class from the map.
classes.remove(lowercase);
unregisterPermission("mobarena.arenas." + lowercase);
}
public boolean addClassPermission(String classname, String perm) {
return addRemoveClassPermission(classname, perm, true);
}
public boolean removeClassPermission(String classname, String perm) {
return addRemoveClassPermission(classname, perm, false);
}
private boolean addRemoveClassPermission(String classname, String perm, boolean add) {
classname = TextUtils.camelCase(classname);
String path = "classes." + classname;
if (config.getConfigurationSection(path) == null)
return false;
// Grab the class section
ConfigurationSection section = config.getConfigurationSection(path);
// Get any previous nodes
List<String> nodes = section.getStringList("permissions");
if (nodes.contains(perm) && add) {
return false;
}
else if (nodes.contains(perm) && !add) {
nodes.remove(perm);
}
else if (!nodes.contains(perm) && add) {
removeContradictions(nodes, perm);
nodes.add(perm);
}
else if (!nodes.contains(perm) && !add) {
return false;
}
// Replace the set.
section.set("permissions", nodes);
plugin.saveConfig();
// Reload the class.
loadClass(classname);
return true;
}
/**
* Removes any nodes that would contradict the permission, e.g. if the node
* 'mobarena.use' is in the set, and the perm node is '-mobarena.use', the
* '-mobarena.use' node is removed as to not contradict the new
* 'mobarena.use' node.
*/
private void removeContradictions(List<String> nodes, String perm) {
if (perm.startsWith("^") || perm.startsWith("-")) {
nodes.remove(perm.substring(1).trim());
}
else {
nodes.remove("^" + perm);
nodes.remove("-" + perm);
}
}
/**
* Load all arena-related stuff.
*/
public void loadArenas() {
ConfigurationSection section = makeSection(config, "arenas");
Set<String> arenanames = section.getKeys(false);
// If no arenas were found, create a default node.
if (arenanames == null || arenanames.isEmpty()) {
createArenaNode(section, "default", plugin.getServer().getWorlds().get(0), false);
}
arenas = new ArrayList<Arena>();
for (World w : Bukkit.getServer().getWorlds()) {
loadArenasInWorld(w.getName());
}
}
public void loadArenasInWorld(String worldName) {
Set<String> arenaNames = config.getConfigurationSection("arenas").getKeys(false);
if (arenaNames == null || arenaNames.isEmpty()) {
return;
}
for (String arenaName : arenaNames) {
Arena arena = getArenaWithName(arenaName);
if (arena != null) continue;
String arenaWorld = config.getString("arenas." + arenaName + ".settings.world", "");
if (!arenaWorld.equals(worldName)) continue;
loadArena(arenaName);
}
}
public void unloadArenasInWorld(String worldName) {
Set<String> arenaNames = config.getConfigurationSection("arenas").getKeys(false);
if (arenaNames == null || arenaNames.isEmpty()) {
return;
}
for (String arenaName : arenaNames) {
Arena arena = getArenaWithName(arenaName);
if (arena == null) continue;
String arenaWorld = arena.getWorld().getName();
if (!arenaWorld.equals(worldName)) continue;
arena.forceEnd();
arenas.remove(arena);
}
}
// Load an already existing arena node
private Arena loadArena(String arenaname) {
ConfigurationSection section = makeSection(config, "arenas." + arenaname);
ConfigurationSection settings = makeSection(section, "settings");
String worldName = settings.getString("world", "");
World world;
if (!worldName.equals("")) {
world = plugin.getServer().getWorld(worldName);
if (world == null) {
Messenger.warning("World '" + worldName + "' for arena '" + arenaname + "' was not found...");
return null;
}
} else {
world = plugin.getServer().getWorlds().get(0);
Messenger.warning("Could not find the world for arena '" + arenaname + "'. Using default world ('" + world.getName() + "')! Check the config-file!");
}
ConfigUtils.addMissingRemoveObsolete(plugin, "settings.yml", settings);
ConfigUtils.addIfEmpty(plugin, "waves.yml", makeSection(section, "waves"));
Arena arena = new ArenaImpl(plugin, section, arenaname, world);
registerPermission("mobarena.arenas." + arenaname.toLowerCase(), PermissionDefault.TRUE);
arenas.add(arena);
plugin.getLogger().info("Loaded arena '" + arenaname + "'");
return arena;
}
@Override
public boolean reloadArena(String name) {
Arena arena = getArenaWithName(name);
if (arena == null) return false;
arena.forceEnd();
arenas.remove(arena);
plugin.reloadConfig();
config = plugin.getConfig();
loadArena(name);
return true;
}
// Create and load a new arena node
@Override
public Arena createArenaNode(String arenaName, World world) {
ConfigurationSection section = makeSection(config, "arenas");
return createArenaNode(section, arenaName, world, true);
}
// Create a new arena node, and (optionally) load it
private Arena createArenaNode(ConfigurationSection arenas, String arenaName, World world, boolean load) {
if (arenas.contains(arenaName)) {
throw new IllegalArgumentException("Arena already exists!");
}
ConfigurationSection section = makeSection(arenas, arenaName);
// Add missing settings and remove obsolete ones
ConfigUtils.addMissingRemoveObsolete(plugin, "settings.yml", makeSection(section, "settings"));
section.set("settings.world", world.getName());
ConfigUtils.addIfEmpty(plugin, "waves.yml", makeSection(section, "waves"));
ConfigUtils.addIfEmpty(plugin, "rewards.yml", makeSection(section, "rewards"));
plugin.saveConfig();
// Load the arena
return (load ? loadArena(arenaName) : null);
}
public void removeArenaNode(Arena arena) {
arenas.remove(arena);
unregisterPermission("mobarena.arenas." + arena.configName());
config.set("arenas." + arena.configName(), null);
plugin.saveConfig();
}
public void reloadConfig() {
boolean wasEnabled = isEnabled();
if (wasEnabled) setEnabled(false);
for (Arena a : arenas) {
a.forceEnd();
}
plugin.reloadConfig();
config = plugin.getConfig();
initialize();
if (wasEnabled) setEnabled(true);
}
public void saveConfig() {
plugin.saveConfig();
}
private Permission registerPermission(String permString, PermissionDefault value) {
PluginManager pm = plugin.getServer().getPluginManager();
Permission perm = pm.getPermission(permString);
if (perm == null) {
perm = new Permission(permString);
perm.setDefault(value);
pm.addPermission(perm);
}
return perm;
}
private void unregisterPermission(String s) {
plugin.getServer().getPluginManager().removePermission(s);
}
}
@@ -0,0 +1,63 @@
package com.garbagemule.MobArena;
import org.bukkit.entity.Player;
import com.garbagemule.MobArena.ArenaPlayerStatistics;
import com.garbagemule.MobArena.MobArena;
import com.garbagemule.MobArena.framework.Arena;
public class ArenaPlayer
{
private Player player;
private ArenaClass arenaClass;
private ArenaPlayerStatistics stats;
private boolean isDead;
//private List<ItemStack> rewards;
//private List<Block> blocks;
public ArenaPlayer(Player player, Arena arena, MobArena plugin) {
this.player = player;
}
public Player getPlayer() {
return player;
}
public ArenaClass getArenaClass() {
return arenaClass;
}
public void setArenaClass(ArenaClass arenaClass) {
this.arenaClass = arenaClass;
}
/**
* Check if the player is "dead", i.e. died or not.
* @return true, if the player is either a spectator or played and died, false otherwise
*/
public boolean isDead() {
return isDead;
}
/**
* Set the player's death status.
* @param value true, if the player is dead, false otherwise
*/
public void setDead(boolean value) {
isDead = value;
}
public void resetStats() {
if (stats != null) {
stats.reset();
return;
}
stats = new ArenaPlayerStatistics(this);
}
public ArenaPlayerStatistics getStats() {
return stats;
}
}
@@ -0,0 +1,130 @@
package com.garbagemule.MobArena;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.entity.Player;
import com.garbagemule.MobArena.ArenaPlayer;
import com.garbagemule.MobArena.ArenaPlayerStatistics;
import com.garbagemule.MobArena.MobArena;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.util.MutableInt;
public class ArenaPlayerStatistics
{
private ArenaPlayer player;
private String playerName, className;
private Map<String, MutableInt> ints;
public ArenaPlayerStatistics(ArenaPlayer player) {
this.player = player;
this.playerName = player.getPlayer().getName();
this.className = player.getArenaClass().getLowercaseName();
reset();
}
public void reset() {
if (ints == null) {
ints = new HashMap<String, MutableInt>();
}
ints.clear();
ints.put("kills", new MutableInt());
ints.put("dmgDone", new MutableInt());
ints.put("dmgTaken", new MutableInt());
ints.put("swings", new MutableInt());
ints.put("hits", new MutableInt());
ints.put("lastWave", new MutableInt());
}
public ArenaPlayerStatistics(Player p, Arena arena, MobArena plugin) {
this(new ArenaPlayer(p, arena, plugin));
}
public ArenaPlayer getArenaPlayer() {
return player;
}
public String getPlayerName() {
return playerName;
}
public String getClassName() {
return className;
}
public int getInt(String s) {
return ints.get(s).value();
}
public void inc(String s) {
ints.get(s).inc();
}
public void add(String s, double amount) {
ints.get(s).add(amount);
}
public static Comparator<ArenaPlayerStatistics> killComparator() {
return new Comparator<ArenaPlayerStatistics>() {
public int compare(ArenaPlayerStatistics s1, ArenaPlayerStatistics s2) {
int s1kills = s1.getInt("kills");
int s2kills = s2.getInt("kills");
if (s1kills == s2kills)
return 0;
return (s1kills > s2kills ? -1 : 1);
}
};
}
public static Comparator<ArenaPlayerStatistics> waveComparator() {
return new Comparator<ArenaPlayerStatistics>() {
public int compare(ArenaPlayerStatistics s1, ArenaPlayerStatistics s2) {
int result = compareWaves(s1, s2);
if (result != 0)
return result;
return compareKills(s1, s2);
}
};
}
public static Comparator<ArenaPlayerStatistics> dmgDoneComparator() {
return new Comparator<ArenaPlayerStatistics>() {
public int compare(ArenaPlayerStatistics s1, ArenaPlayerStatistics s2) {
int s1dmgDone = s1.getInt("dmgDone");
int s2dmgDone = s2.getInt("dmgDone");
if (s1dmgDone == s2dmgDone)
return 0;
return (s1dmgDone > s2dmgDone ? -1 : 1);
}
};
}
private static int compareKills(ArenaPlayerStatistics s1, ArenaPlayerStatistics s2) {
int s1kills = s1.getInt("kills");
int s2kills = s2.getInt("kills");
if (s1kills == s2kills)
return 0;
return (s1kills > s2kills ? -1 : 1);
}
private static int compareWaves(ArenaPlayerStatistics s1, ArenaPlayerStatistics s2) {
int s1wave = s1.getInt("lastWave");
int s2wave = s2.getInt("lastWave");
if (s1wave == s2wave)
return 0;
return (s1wave > s2wave ? -1 : 1);
}
}
@@ -0,0 +1,105 @@
package com.garbagemule.MobArena;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.util.MutableInt;
import org.bukkit.plugin.Plugin;
public class ClassLimitManager
{
private HashMap<ArenaClass,MutableInt> classLimits;
private HashMap<ArenaClass, HashSet<String>> classesInUse;
private ConfigurationSection limits;
private Map<String,ArenaClass> classes;
public ClassLimitManager(Arena arena, Map<String,ArenaClass> classes, ConfigurationSection limits) {
this.limits = limits;
this.classes = classes;
this.classLimits = new HashMap<ArenaClass,MutableInt>();
this.classesInUse = new HashMap<ArenaClass, HashSet<String>>();
loadLimitMap(arena.getPlugin());
initInUseMap();
}
private void loadLimitMap(Plugin plugin) {
// If the config-section is empty, create and populate it.
if (limits.getKeys(false).isEmpty()) {
for (ArenaClass ac : classes.values()) {
limits.set(ac.getConfigName(), -1);
}
plugin.saveConfig();
}
// Populate the limits map using the values in the config-file.
for (ArenaClass ac : classes.values()) {
classLimits.put(ac, new MutableInt(limits.getInt(ac.getConfigName(), -1)));
}
}
private void initInUseMap() {
// Initialize the in-use map with zeros.
for (ArenaClass ac : classes.values()) {
classesInUse.put(ac, new HashSet<String>());
}
}
/**
* This is the class a player is changing to
* @param ac the new ArenaClass
*/
public void playerPickedClass(ArenaClass ac, Player p) {
classesInUse.get(ac).add(p.getName());
}
/**
* This is the class a player left
* @param ac the current/old ArenaClass
*/
public void playerLeftClass(ArenaClass ac, Player p) {
if (ac != null) {
classesInUse.get(ac).remove(p.getName());
}
}
/**
* Checks to see if a player can pick a specific class
* @param ac the ArenaClass to check
* @return true/false
*/
public boolean canPlayerJoinClass(ArenaClass ac) {
if (classLimits.get(ac) == null) {
limits.set(ac.getConfigName(), -1);
classLimits.put(ac, new MutableInt(-1));
classesInUse.put(ac, new HashSet<String>());
}
if (classLimits.get(ac).value() <= -1)
return true;
return classesInUse.get(ac).size() < classLimits.get(ac).value();
}
/**
* returns a set of Player Names who have picked an ArenaClass
* @param ac the ArenaClass in question
* @return the Player Names who have picked the provided ArenaClass
*/
public HashSet<String> getPlayersWithClass(ArenaClass ac) {
return classesInUse.get(ac);
}
/**
* Clear the classes in use map and reinitialize it for the next match
*/
public void clearClassesInUse() {
classesInUse.clear();
initInUseMap();
}
}
@@ -0,0 +1,349 @@
package com.garbagemule.MobArena;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.garbagemule.MobArena.events.ArenaCompleteEvent;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Entity;
import org.bukkit.inventory.ItemStack;
import com.garbagemule.MobArena.events.NewWaveEvent;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.region.ArenaRegion;
import com.garbagemule.MobArena.waves.*;
import com.garbagemule.MobArena.waves.enums.WaveType;
import com.garbagemule.MobArena.waves.types.BossWave;
import com.garbagemule.MobArena.waves.types.SupplyWave;
import com.garbagemule.MobArena.waves.types.UpgradeWave;
public class MASpawnThread implements Runnable
{
private MobArena plugin;
private Arena arena;
private ArenaRegion region;
private RewardManager rewardManager;
private WaveManager waveManager;
private MonsterManager monsterManager;
private int playerCount, monsterLimit;
private boolean waveClear, bossClear, preBossClear, wavesAsLevel;
/**
* Create a new monster spawner for the input arena.
* Note that the arena's WaveManager is reset
* @param plugin a MobArena instance
* @param arena an arena
*/
public MASpawnThread(MobArena plugin, Arena arena) {
this.plugin = plugin;
this.arena = arena;
this.region = arena.getRegion();
this.rewardManager = arena.getRewardManager();
this.waveManager = arena.getWaveManager();
this.monsterManager = arena.getMonsterManager();
reset();
}
/**
* Reset the spawner, so all systems and settings are
* ready for a new session.
*/
public void reset() {
waveManager.reset();
playerCount = arena.getPlayersInArena().size();
monsterLimit = arena.getSettings().getInt("monster-limit", 100);
waveClear = arena.getSettings().getBoolean("clear-wave-before-next", false);
bossClear = arena.getSettings().getBoolean("clear-boss-before-next", false);
preBossClear = arena.getSettings().getBoolean("clear-wave-before-boss", false);
wavesAsLevel = arena.getSettings().getBoolean("display-waves-as-level", false);
}
public void run() {
// If the arena isn't running or if there are no players in it.
if (!arena.isRunning() || arena.getPlayersInArena().isEmpty()) {
return;
}
// Clear out all dead monsters in the monster set.
removeDeadMonsters();
removeCheatingPlayers();
// In case some players were removed, check again.
if (!arena.isRunning()) {
return;
}
// Grab the wave number.
int nextWave = waveManager.getWaveNumber() + 1;
// Check if wave needs to be cleared first. If so, return!
if (!isWaveClear()) {
arena.scheduleTask(this, 60);
return;
}
// Fire off the event. If cancelled, try again in 3 seconds.
NewWaveEvent event = new NewWaveEvent(arena, waveManager.getNext(), nextWave);
plugin.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
arena.scheduleTask(this, 60);
return;
}
// Grant rewards (if any) for the wave about to spawn
grantRewards(nextWave);
// Check if this is the final wave, in which case, end instead of spawn
if (nextWave > 1 && (nextWave - 1) == waveManager.getFinalWave()) {
// Fire the complete event
ArenaCompleteEvent complete = new ArenaCompleteEvent(arena);
plugin.getServer().getPluginManager().callEvent(complete);
// Then force leave everyone
List<Player> players = new ArrayList<Player>(arena.getPlayersInArena());
for (Player p : players) {
arena.playerLeave(p);
}
return;
}
// Spawn the next wave.
spawnWave(nextWave);
// Update stats
updateStats(nextWave);
// Reschedule the spawner for the next wave.
arena.scheduleTask(this, arena.getSettings().getInt("wave-interval", 3) * 20);
}
private void spawnWave(int wave) {
Wave w = waveManager.next();
w.announce(arena, wave);
arena.getScoreboard().updateWave(wave);
// Set the players' level to the wave number
if (wavesAsLevel) {
for (Player p : arena.getPlayersInArena()) {
p.setLevel(wave);
p.setExp(0.0f);
}
}
if (w.getType() == WaveType.UPGRADE) {
handleUpgradeWave(w);
return;
}
Map<MACreature, Integer> monsters = w.getMonstersToSpawn(wave, playerCount, arena);
List<Location> spawnpoints = w.getSpawnpoints(arena);
World world = arena.getWorld();
int totalSpawnpoints = spawnpoints.size();
int index = 0;
double mul = w.getHealthMultiplier();
for (Map.Entry<MACreature, Integer> entry : monsters.entrySet()) {
for (int i = 0; i < entry.getValue(); i++, index++) {
// Check if monster limit has been reached.
if (monsterManager.getMonsters().size() >= monsterLimit) {
return;
}
// Grab a spawnpoint
Location spawnpoint = spawnpoints.get(index % totalSpawnpoints);
// Spawn the monster
LivingEntity e = entry.getKey().spawn(arena, world, spawnpoint);
// Add it to the arena.
monsterManager.addMonster(e);
// Set the health.
e.resetMaxHealth(); // Avoid conflicts/enormous multiplications from other plugins handling Mob health
int health = (int) Math.max(1D, e.getMaxHealth() * mul);
try {
e.setMaxHealth(health);
e.setHealth(health);
} catch (IllegalArgumentException ex) {
// Spigot... *facepalm*
Messenger.severe("Can't set health to " + health + ", using default health. If you are running Spigot, set 'maxHealth' higher in your Spigot settings.");
Messenger.severe(ex.getLocalizedMessage());
if (w.getType() == WaveType.BOSS) {
((BossWave) w).setBossName("SPIGOT ERROR");
} else {
e.setCustomName("SPIGOT ERROR");
}
}
// Switch on the type.
switch (w.getType()){
case BOSS:
BossWave bw = (BossWave) w;
double maxHealth = bw.getMaxHealth(playerCount);
MABoss boss = monsterManager.addBoss(e, maxHealth);
boss.setReward(bw.getReward());
boss.setDrops(bw.getDrops());
bw.addMABoss(boss);
bw.activateAbilities(arena);
e.addPotionEffects(bw.getPotions());
if (bw.getBossName() != null) {
e.setCustomName(bw.getBossName());
e.setCustomNameVisible(true);
}
break;
case SWARM:
health = (int) (mul < 1D ? e.getMaxHealth() * mul : 1);
health = Math.max(1, health);
e.setHealth(Math.min(health, e.getMaxHealth()));
break;
case SUPPLY:
SupplyWave sw = (SupplyWave) w;
monsterManager.addSupplier(e, sw.getDropList());
break;
default:
break;
}
}
}
}
private void handleUpgradeWave(Wave w) {
UpgradeWave uw = (UpgradeWave) w;
for (Player p : arena.getPlayersInArena()) {
String className = arena.getArenaPlayer(p).getArenaClass().getLowercaseName();
uw.grantItems(arena, p, className);
uw.grantItems(arena, p, "all");
}
}
/**
* Check if the wave is clear for new spawns.
* If clear-boss-before-next: true, bosses must be dead.
* If clear-wave-before-next: true, all monsters must be dead.
* @return true, if the wave is "clear" for new spawns.
*/
private boolean isWaveClear() {
// Check for monster limit
if (monsterManager.getMonsters().size() >= monsterLimit) {
return false;
}
// Check for boss clear
if (bossClear && !monsterManager.getBossMonsters().isEmpty()) {
return false;
}
// Check for wave and pre boss clear
if (waveClear && !monsterManager.getMonsters().isEmpty()) {
return false;
}
// Check for pre boss clear
if (preBossClear && waveManager.getNext().getType() == WaveType.BOSS && !monsterManager.getMonsters().isEmpty()) {
return false;
}
// Check for final wave
if (!monsterManager.getMonsters().isEmpty() && waveManager.getWaveNumber() == waveManager.getFinalWave()) {
return false;
}
return true;
}
private void removeDeadMonsters() {
List<Entity> tmp = new ArrayList<Entity>(monsterManager.getMonsters());
for (Entity e : tmp) {
if (e == null) {
continue;
}
if (e.isDead() || !region.contains(e.getLocation())) {
monsterManager.remove(e);
e.remove();
}
}
}
private void removeCheatingPlayers() {
List<Player> players = new ArrayList<Player>(arena.getPlayersInArena());
for (Player p : players) {
if (region.contains(p.getLocation())) {
continue;
}
Messenger.tell(p, "Leaving so soon?");
p.getInventory().clear();
arena.playerLeave(p);
}
}
private void grantRewards(int wave) {
for (Map.Entry<Integer, List<ItemStack>> entry : arena.getEveryWaveEntrySet()) {
if (wave % entry.getKey() == 0) {
addReward(entry.getValue());
}
}
List<ItemStack> after = arena.getAfterWaveReward(wave);
if (after != null) {
addReward(after);
}
}
private void updateStats(int wave) {
for (ArenaPlayer ap : arena.getArenaPlayerSet()) {
if (arena.getPlayersInArena().contains(ap.getPlayer())) {
ap.getStats().inc("lastWave");
}
}
}
/*
* ////////////////////////////////////////////////////////////////////
* //
* // Getters/setters
* //
* ////////////////////////////////////////////////////////////////////
*/
public int getPlayerCount() {
return playerCount;
}
/**
* Rewards all players with an item from the input String.
*/
private void addReward(List<ItemStack> rewards) {
for (Player p : arena.getPlayersInArena()) {
ItemStack reward = MAUtils.getRandomReward(rewards);
rewardManager.addReward(p, reward);
if (reward == null) {
Messenger.tell(p, "ERROR! Problem with rewards. Notify server host!");
Messenger.warning("Could not add null reward. Please check the config-file!");
}
else if (reward.getTypeId() == MobArena.ECONOMY_MONEY_ID) {
if (plugin.giveMoney(p, reward)) { // Money already awarded here, not needed at end of match as well
Messenger.tell(p, Msg.WAVE_REWARD, plugin.economyFormat(reward));
}
else {
Messenger.warning("Tried to add money, but no economy plugin detected!");
}
}
else {
Messenger.tell(p, Msg.WAVE_REWARD, MAUtils.toCamelCase(reward.getType().toString()) + ":" + reward.getAmount());
}
}
}
}
@@ -0,0 +1,487 @@
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.ArrayList;
import java.util.Collection;
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.Set;
import org.bukkit.block.Sign;
import org.bukkit.World;
import org.bukkit.Material;
import org.bukkit.Location;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Wolf;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.java.JavaPlugin;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
import com.garbagemule.MobArena.region.ArenaRegion;
import com.garbagemule.MobArena.util.EntityPosition;
import com.garbagemule.MobArena.util.ItemParser;
import com.garbagemule.MobArena.util.TextUtils;
public class MAUtils
{
public static final String sep = File.separator;
/* ///////////////////////////////////////////////////////////////////// //
INITIALIZATION METHODS
// ///////////////////////////////////////////////////////////////////// */
/**
* 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<Integer,List<ItemStack>> getArenaRewardMap(MobArena plugin, ConfigurationSection config, String arena, String type)
{
//String arenaPath = "arenas." + arena + ".rewards.waves.";
Map<Integer,List<ItemStack>> result = new HashMap<Integer,List<ItemStack>>();
String typePath = "rewards.waves." + type;
if (!config.contains(typePath)) return result;
//Set<String> waves = config.getKeys(arenaPath + type);
Set<String> waves = config.getConfigurationSection(typePath).getKeys(false);
if (waves == null) return result;
for (String n : waves)
{
if (!n.matches("[0-9]+"))
continue;
int wave = Integer.parseInt(n);
String path = typePath + "." + wave;
String rewards = config.getString(path);
result.put(wave, ItemParser.parseItems(rewards));
}
return result;
}
/* ///////////////////////////////////////////////////////////////////// //
INVENTORY AND REWARD METHODS
// ///////////////////////////////////////////////////////////////////// */
/* Helper method for grabbing a random reward */
public static ItemStack getRandomReward(List<ItemStack> rewards)
{
if (rewards.isEmpty())
return null;
Random ran = new Random();
return rewards.get(ran.nextInt(rewards.size()));
}
/* ///////////////////////////////////////////////////////////////////// //
PET CLASS METHODS
// ///////////////////////////////////////////////////////////////////// */
/**
* Makes all nearby wolves sit if their owner is the given player.
*/
public static void sitPets(Player p)
{
if (p == null)
return;
List<Entity> entities = p.getNearbyEntities(80, 40, 80);
for (Entity e : entities)
{
if (!(e instanceof Wolf))
continue;
Wolf w = (Wolf) e;
if (w.isTamed() && w.getOwner() != null && w.getOwner().equals(p))
w.setSitting(true);
}
}
/* ///////////////////////////////////////////////////////////////////// //
MISC METHODS
// ///////////////////////////////////////////////////////////////////// */
public static Player getClosestPlayer(MobArena plugin, 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. */
List<Player> players = new ArrayList<Player>(arena.getPlayersInArena());
for (Player p : players) {
if (!arena.getWorld().equals(p.getWorld())) {
Messenger.info("Player '" + p.getName() + "' is not in the right world. Kicking...");
p.kickPlayer("[MobArena] Cheater! (Warped out of the arena world.)");
Messenger.tell(p, "You warped out of the arena world.");
continue;
}
double dist = distanceSquared(plugin, p, e.getLocation());
if (dist < current && dist < 256D) {
current = dist;
result = p;
}
}
return result;
}
public static double distanceSquared(MobArena plugin, Player p, Location l) {
try {
return p.getLocation().distanceSquared(l);
}
catch (Exception e) {
p.kickPlayer("Banned for life! No, but stop trying to cheat in MobArena!");
if (plugin != null) {
Messenger.warning(p.getName() + " tried to cheat in MobArena and has been kicked.");
}
return Double.MAX_VALUE;
}
}
/**
* 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 <E> String listToString(Collection<E> list, boolean none, MobArena plugin)
{
if (list == null || list.isEmpty()) {
return (none ? Msg.MISC_NONE.toString() : "");
}
StringBuffer buffy = new StringBuffer();
int trimLength = 0;
E type = list.iterator().next();
if (type instanceof Player) {
for (E e : list) {
buffy.append(((Player) e).getName());
buffy.append(" ");
}
}
else if (type instanceof ItemStack) {
trimLength = 2;
ItemStack stack;
for (E e : list) {
stack = (ItemStack) e;
if (stack.getTypeId() == MobArena.ECONOMY_MONEY_ID) {
String formatted = plugin.economyFormat(stack);
if (formatted != null) {
buffy.append(formatted);
buffy.append(", ");
}
else {
Messenger.warning("Tried to do some money stuff, but no economy plugin was detected!");
return buffy.toString();
}
continue;
}
buffy.append(stack.getType().toString().toLowerCase());
buffy.append(":");
buffy.append(stack.getAmount());
buffy.append(", ");
}
}
else {
for (E e : list) {
buffy.append(e.toString());
buffy.append(" ");
}
}
return buffy.toString().substring(0, buffy.length() - trimLength);
}
public static <E> String listToString(Collection<E> list, JavaPlugin plugin) { return listToString(list, true, (MobArena) plugin); }
/**
* Returns a String-list version of a comma-separated list.
*/
public static List<String> stringToList(String list)
{
List<String> result = new LinkedList<String>();
if (list == null) return result;
String[] parts = list.trim().split(",");
for (String part : parts)
result.add(part.trim());
return result;
}
/**
* Stand back, I'm going to try science!
*/
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.getArenaMaster();
// Create the arena node in the config-file.
World world = loc.getWorld();
Arena arena = am.createArenaNode(name, world);
// Get the hippie bounds.
int x1 = (int)loc.getX() - radius;
int x2 = (int)loc.getX() + radius;
int y1 = (int)loc.getY() - 9;
int y2 = (int)loc.getY() - 1;
int z1 = (int)loc.getZ() - radius;
int z2 = (int)loc.getZ() + radius;
int lx1 = x1;
int lx2 = x1 + am.getClasses().size() + 3;
int ly1 = y1-6;
int ly2 = y1-2;
int lz1 = z1;
int lz2 = z1 + 6;
// Save the precious patch
HashMap<EntityPosition,Integer> preciousPatch = new HashMap<EntityPosition,Integer>();
Location lo;
int id;
for (int i = x1; i <= x2; i++)
{
for (int j = ly1; j <= y2; j++)
{
for (int k = z1; k <= z2; k++)
{
lo = world.getBlockAt(i,j,k).getLocation();
id = world.getBlockAt(i,j,k).getTypeId();
preciousPatch.put(new EntityPosition(lo),id);
}
}
}
try
{
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)
{
e.printStackTrace();
Messenger.warning("Couldn't create backup file. Aborting auto-generate...");
return false;
}
// Build some monster walls.
for (int i = x1; i <= x2; i++)
{
for (int j = y1; j <= y2; j++)
{
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++)
{
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++)
{
world.getBlockAt(i,y1+2,z1).setTypeId(89);
world.getBlockAt(i,y1+2,z2).setTypeId(89);
}
for (int k = z1; k <= z2; k++)
{
world.getBlockAt(x1,y1+2,k).setTypeId(89);
world.getBlockAt(x2,y1+2,k).setTypeId(89);
}
// Build a monster floor, and some Obsidian foundation.
for (int i = x1; i <= x2; i++)
{
for (int k = z1; k <= z2; k++)
{
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++)
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++)
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++)
{
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++)
{
world.getBlockAt(lx1,j,k).setTypeId(24);
world.getBlockAt(lx2,j,k).setTypeId(24);
}
}
for (int k = lz1; k <= lz2; k++) // Lights
{
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++)
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++)
world.getBlockAt(i,j,k).setTypeId(0);
// Place the hippie signs
//Iterator<String> iterator = am.getClasses().iterator();
Iterator<String> iterator = am.getClasses().keySet().iterator();
for (int i = lx1+2; i <= lx2-2; i++) // Signs
{
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, TextUtils.camelCase((String)iterator.next()));
sign.update();
}
world.getBlockAt(lx2-2,ly1+1,lz1+2).setType(Material.IRON_BLOCK);
// Set up the monster points.
ArenaRegion region = arena.getRegion();
region.set("p1", new Location(world, x1, ly1, z1));
region.set("p2", new Location(world, x2, y2+1, z2));
region.set("arena", new Location(world, loc.getX(), y1+1, loc.getZ()));
region.set("lobby", new Location(world, x1+2, ly1+1, z1+2));
region.set("spectator", new Location(world, loc.getX(), y2+1, loc.getZ()));
region.addSpawn("s1", new Location(world, x1+3, y1+2, z1+3));
region.addSpawn("s2", new Location(world, x1+3, y1+2, z2-3));
region.addSpawn("s3", new Location(world, x2-3, y1+2, z1+3));
region.addSpawn("s4", new Location(world, x2-3, y1+2, z2-3));
region.save();
am.reloadConfig();
return true;
}
/**
* This fixes everything!
*/
@SuppressWarnings("unchecked")
public static boolean undoItHippieMonster(String name, MobArena plugin, boolean error)
{
File file = new File("plugins" + sep + "MobArena" + sep + "agbackup" + sep + name + ".tmp");
HashMap<EntityPosition,Integer> preciousPatch;
try
{
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
preciousPatch = (HashMap<EntityPosition,Integer>) ois.readObject();
ois.close();
}
catch (Exception e)
{
if (error) Messenger.warning("Couldn't find backup file for arena '" + name + "'");
return false;
}
World world = plugin.getServer().getWorld(preciousPatch.keySet().iterator().next().getWorld());
for (Map.Entry<EntityPosition,Integer> entry : preciousPatch.entrySet())
{
world.getBlockAt(entry.getKey().getLocation(world)).setTypeId(entry.getValue());
}
plugin.getConfig().set("arenas." + name, null);
plugin.saveConfig();
file.delete();
plugin.getArenaMaster().reloadConfig();
return true;
}
}
@@ -0,0 +1,69 @@
package com.garbagemule.MobArena;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.garbagemule.MobArena.framework.Arena;
public class Messenger
{
private static final Logger log = Logger.getLogger("Minecraft");
private static final String prefix = "[MobArena] ";
private Messenger() {}
public static boolean tell(CommandSender p, String msg) {
// If the input sender is null or the string is empty, return.
if (p == null || msg.equals("")) {
return false;
}
// Otherwise, send the message with the [MobArena] tag.
p.sendMessage(ChatColor.GREEN + "[MobArena] " + ChatColor.RESET + msg);
return true;
}
public static boolean tell(CommandSender p, Msg msg, String s) {
return tell(p, msg.format(s));
}
public static boolean tell(CommandSender p, Msg msg) {
return tell(p, msg.toString());
}
public static void announce(Arena arena, String msg) {
List<Player> players = new ArrayList<Player>();
players.addAll(arena.getPlayersInArena());
players.addAll(arena.getPlayersInLobby());
players.addAll(arena.getSpectators());
for (Player p : players) {
tell(p, msg);
}
}
public static void announce(Arena arena, Msg msg, String s) {
announce(arena, msg.format(s));
}
public static void announce(Arena arena, Msg msg) {
announce(arena, msg.toString());
}
public static void info(String msg) {
log.info(prefix + msg);
}
public static void warning(String msg) {
log.warning(prefix + msg);
}
public static void severe(String msg) {
log.severe(prefix + msg);
}
}
@@ -0,0 +1,353 @@
package com.garbagemule.MobArena;
import java.io.*;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import net.milkbowl.vault.economy.Economy;
import net.milkbowl.vault.economy.EconomyResponse;
import net.milkbowl.vault.economy.EconomyResponse.ResponseType;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.ServicesManager;
import org.bukkit.plugin.java.JavaPlugin;
import com.garbagemule.MobArena.commands.CommandHandler;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
import com.garbagemule.MobArena.listeners.MAGlobalListener;
import com.garbagemule.MobArena.listeners.MagicSpellsListener;
import com.garbagemule.MobArena.metrics.Metrics;
import com.garbagemule.MobArena.util.VersionChecker;
import com.garbagemule.MobArena.util.config.ConfigUtils;
import com.garbagemule.MobArena.util.inventory.InventoryManager;
import com.garbagemule.MobArena.waves.ability.AbilityManager;
/**
* MobArena
* @author garbagemule
*/
public class MobArena extends JavaPlugin
{
private ArenaMaster arenaMaster;
private CommandHandler commandHandler;
// Inventories from disconnects
private Set<String> inventoriesToRestore;
// Vault
private Economy economy;
private File configFile;
private FileConfiguration config;
public static final double MIN_PLAYER_DISTANCE_SQUARED = 225D;
public static final int ECONOMY_MONEY_ID = -29;
public static Random random = new Random();
public void onEnable() {
// Initialize config-file
configFile = new File(getDataFolder(), "config.yml");
config = new YamlConfiguration();
reloadConfig();
// Set the header and save
getConfig().options().header(getHeader());
saveConfig();
// Initialize announcements-file
loadAnnouncementsFile();
// Load boss abilities
loadAbilities();
// Set up soft dependencies
setupVault();
setupMagicSpells();
// Set up the ArenaMaster
arenaMaster = new ArenaMasterImpl(this);
arenaMaster.initialize();
// Register any inventories to restore.
registerInventories();
// Register event listeners
registerListeners();
// Go go Metrics
startMetrics();
// Announce enable!
Messenger.info("v" + this.getDescription().getVersion() + " enabled.");
// Check for updates
if (getConfig().getBoolean("global-settings.update-notification", false)) {
VersionChecker.checkForUpdates(this, null);
}
}
public void onDisable() {
// Force all arenas to end.
if (arenaMaster == null) return;
for (Arena arena : arenaMaster.getArenas()) {
arena.forceEnd();
}
arenaMaster.resetArenaMap();
VersionChecker.shutdown();
Messenger.info("disabled.");
}
public File getPluginFile() {
return getFile();
}
@Override
public FileConfiguration getConfig() {
return config;
}
@Override
public void reloadConfig() {
// Check if the config-file exists
if (!configFile.exists()) {
Messenger.info("No config-file found, creating default...");
saveDefaultConfig();
}
// Check for tab characters in config-file
BufferedReader in = null;
try {
in = new BufferedReader(new FileReader(new File(getDataFolder(), "config.yml")));
int row = 0;
String line;
while ((line = in.readLine()) != null) {
row++;
if (line.indexOf('\t') != -1) {
StringBuilder buffy = new StringBuilder();
buffy.append("Found tab in config-file on line ").append(row).append(".");
buffy.append('\n').append("NEVER use tabs! ALWAYS use spaces!");
buffy.append('\n').append(line);
buffy.append('\n');
for (int i = 0; i < line.indexOf('\t'); i++) {
buffy.append(' ');
}
buffy.append('^');
throw new IllegalArgumentException(buffy.toString());
}
}
// Actually reload the config-file
config.load(configFile);
} catch (InvalidConfigurationException e) {
throw new RuntimeException("\n\n>>>\n>>> There is an error in your config-file! Handle it!\n>>> Here is what snakeyaml says:\n>>>\n\n" + e.getMessage());
} catch (FileNotFoundException e) {
throw new IllegalStateException("Config-file could not be created for some reason! <o>");
} catch (IOException e) {
// Error reading the file, just re-throw
Messenger.severe("There was an error reading the config-file:\n" + e.getMessage());
} finally {
// Java 6 <3
if (in != null) {
try {
in.close();
} catch (IOException e) {
// Swallow
}
}
}
}
@Override
public void saveConfig() {
try {
config.save(configFile);
} catch (IOException e) {
e.printStackTrace();
}
}
private void loadAnnouncementsFile() {
// Create if missing
File file = new File(getDataFolder(), "announcements.yml");
try {
if (file.createNewFile()) {
Messenger.info("announcements.yml created.");
YamlConfiguration yaml = Msg.toYaml();
yaml.save(file);
return;
}
} catch (Exception e) {
e.printStackTrace();
}
// Otherwise, load the announcements from the file
try {
YamlConfiguration yaml = new YamlConfiguration();
yaml.load(file);
ConfigUtils.addMissingRemoveObsolete(file, Msg.toYaml(), yaml);
Msg.load(yaml);
} catch (Exception e) {
e.printStackTrace();
}
}
private void registerListeners() {
// Bind the /ma, /mobarena commands to MACommands.
commandHandler = new CommandHandler(this);
getCommand("ma").setExecutor(commandHandler);
getCommand("mobarena").setExecutor(commandHandler);
PluginManager pm = this.getServer().getPluginManager();
pm.registerEvents(new MAGlobalListener(this, arenaMaster), this);
}
// Permissions stuff
public boolean has(Player p, String s) {
return p.hasPermission(s);
}
public boolean has(CommandSender sender, String s) {
if (sender instanceof ConsoleCommandSender) {
return true;
}
return has((Player) sender, s);
}
private void setupVault() {
Plugin vaultPlugin = this.getServer().getPluginManager().getPlugin("Vault");
if (vaultPlugin == null) {
Messenger.warning("Vault was not found. Economy rewards will not work!");
return;
}
ServicesManager manager = this.getServer().getServicesManager();
RegisteredServiceProvider<Economy> e = manager.getRegistration(net.milkbowl.vault.economy.Economy.class);
if (e != null) {
economy = e.getProvider();
Messenger.info("Vault found; economy rewards enabled.");
} else {
Messenger.warning("Vault found, but no economy plugin detected. Economy rewards will not work!");
}
}
private void setupMagicSpells() {
Plugin spells = this.getServer().getPluginManager().getPlugin("MagicSpells");
if (spells == null) return;
Messenger.info("MagicSpells found, loading config-file.");
this.getServer().getPluginManager().registerEvents(new MagicSpellsListener(this), this);
}
private void loadAbilities() {
File dir = new File(this.getDataFolder(), "abilities");
if (!dir.exists()) dir.mkdir();
AbilityManager.loadCoreAbilities();
AbilityManager.loadCustomAbilities(dir);
}
private void startMetrics() {
try {
Metrics m = new Metrics(this);
m.start();
} catch (Exception e) {
Messenger.warning("y u disable stats :(");
}
}
public ArenaMaster getArenaMaster() {
return arenaMaster;
}
public CommandHandler getCommandHandler() {
return commandHandler;
}
private String getHeader() {
String sep = System.getProperty("line.separator");
return "MobArena v" + this.getDescription().getVersion() + " - Config-file" + sep +
"Read the Wiki for details on how to set up this file: http://goo.gl/F5TTc" + sep +
"Note: You -must- use spaces instead of tabs!";
}
private void registerInventories() {
this.inventoriesToRestore = new HashSet<String>();
File dir = new File(getDataFolder(), "inventories");
if (!dir.exists()) {
dir.mkdir();
return;
}
for (File f : dir.listFiles()) {
if (f.getName().endsWith(".inv")) {
inventoriesToRestore.add(f.getName().substring(0, f.getName().indexOf(".")));
}
}
}
public void restoreInventory(Player p) {
if (!inventoriesToRestore.contains(p.getName())) {
return;
}
if (InventoryManager.restoreFromFile(this, p)) {
inventoriesToRestore.remove(p.getName());
}
}
public boolean giveMoney(Player p, ItemStack item) {
if (economy != null) {
EconomyResponse result = economy.depositPlayer(p.getName(), getAmount(item));
return (result.type == ResponseType.SUCCESS);
}
return false;
}
public boolean takeMoney(Player p, ItemStack item) {
return takeMoney(p, getAmount(item));
}
public boolean takeMoney(Player p, double amount) {
if (economy != null) {
EconomyResponse result = economy.withdrawPlayer(p.getName(), amount);
return (result.type == ResponseType.SUCCESS);
}
return false;
}
public boolean hasEnough(Player p, ItemStack item) {
return hasEnough(p, getAmount(item));
}
public boolean hasEnough(Player p, double amount) {
return economy == null || (economy.getBalance(p.getName()) >= amount);
}
public String economyFormat(ItemStack item) {
return economyFormat(getAmount(item));
}
public String economyFormat(double amount) {
return economy == null ? null : economy.format(amount);
}
private double getAmount(ItemStack item) {
double major = item.getAmount();
double minor = item.getDurability() / 100D;
return major + minor;
}
}
@@ -0,0 +1,228 @@
package com.garbagemule.MobArena;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import com.garbagemule.MobArena.MobArena;
import com.garbagemule.MobArena.framework.Arena;
public class MobArenaHandler
{
private MobArena plugin;
/**
* Primary constructor.
* The field 'plugin' is initalized, if the server is running MobArena.
*/
public MobArenaHandler() {
plugin = (MobArena) Bukkit.getServer().getPluginManager().getPlugin("MobArena");
}
/*//////////////////////////////////////////////////////////////////
REGION/LOCATION METHODS
//////////////////////////////////////////////////////////////////*/
/**
* Check if a Location is inside of any arena region.
* @param loc A location.
* @return true, if the Location is inside of any arena region.
*/
public boolean inRegion(Location loc) {
for (Arena arena : plugin.getArenaMaster().getArenas()) {
if (arena.getRegion().contains(loc)) {
return true;
}
}
return false;
}
/**
* Check if a Location is inside of a specific arena region (by arena object).
* @param arena An Arena object
* @param loc A location
* @return true, if the Location is inside of the arena region.
*/
public boolean inRegion(Arena arena, Location loc) {
return (arena != null && arena.getRegion().contains(loc));
}
/**
* Check if a Location is inside of a specific arena region (by arena name).
* @param arenaName The name of an arena
* @param loc A location
* @return true, if the Location is inside of the arena region.
*/
public boolean inRegion(String arenaName, Location loc) {
Arena arena = plugin.getArenaMaster().getArenaWithName(arenaName);
if (arena == null)
throw new NullPointerException("There is no arena with that name");
return arena.getRegion().contains(loc);
}
/**
* Check if a Location is inside of the region of an arena that is currently running.
* @param loc A location.
* @return true, if the Location is inside of the region of an arena that is currently running.
*/
public boolean inRunningRegion(Location loc) {
return inRegion(loc, false, true);
}
/**
* Check if a Location is inside of the region of an arena that is currently enabled.
* @param loc A location.
* @return true, if the Location is inside of the region of an arena that is currently enabled.
*/
public boolean inEnabledRegion(Location loc) {
return inRegion(loc, true, false);
}
/**
* Private helper method for inRunningRegion and inEnabledRegion
* @param loc A location
* @param enabled if true, the method will check if the arena is enabled
* @param running if true, the method will check if the arena is running, overrides enabled
* @return true, if the location is inside of the region of an arena that is currently enabled/running, depending on the parameters.
*/
private boolean inRegion(Location loc, boolean enabled, boolean running) {
// If the plugin doesn't exist, always return false.
if (plugin.getArenaMaster() == null) return false;
// Return true if location is within just one arena's region.
for (Arena arena : plugin.getArenaMaster().getArenas()) {
if (arena.getRegion().contains(loc)) {
if ((running && arena.isRunning()) || (enabled && arena.isEnabled())) {
return true;
}
}
}
return false;
}
/*//////////////////////////////////////////////////////////////////
PLAYER/MONSTER/PET METHODS
//////////////////////////////////////////////////////////////////*/
/**
* Check if a player is in a MobArena arena (by Player).
* @param player The player
* @return true, if the player is in an arena
*/
public boolean isPlayerInArena(Player player) {
return (plugin.getArenaMaster().getArenaWithPlayer(player) != null);
}
/**
* Check if a player is in a MobArena arena (by name).
* @param playerName The name of the player
* @return true, if the player is in an arena
*/
public boolean isPlayerInArena(String playerName) {
return (plugin.getArenaMaster().getArenaWithPlayer(playerName) != null);
}
/**
* Get the MobArena class of a given player.
* @param player The player
* @return The class name of the player if the player is in the arena, null otherwise
*/
public String getPlayerClass(Player player) {
Arena arena = plugin.getArenaMaster().getArenaWithPlayer(player);
if (arena == null) return null;
return getPlayerClass(arena, player);
}
/**
* Get the MobArena class of a given player in a given arena.
* This method is faster than the above method, granted the Arena object is known.
* @param arena The MobArena arena to check in
* @param player The player to look up
* @return The class name of the player, if the player is in the arena, null otherwise
*/
public String getPlayerClass(Arena arena, Player player) {
ArenaPlayer ap = arena.getArenaPlayer(player);
if (ap == null) return null;
ArenaClass ac = ap.getArenaClass();
if (ac == null) return null;
return ac.getLowercaseName();
}
/**
* Check if a monster is in a MobArena arena.
* @param entity The monster entity
* @return true, if the monster is in an arena
*/
public boolean isMonsterInArena(LivingEntity entity) {
return plugin.getArenaMaster().getArenaWithMonster(entity) != null;
}
/**
* Check if a pet is in a MobArena arena.
* @param wolf The pet wolf
* @return true, if the pet is in an arena
*/
public boolean isPetInArena(LivingEntity wolf) {
return plugin.getArenaMaster().getArenaWithPet(wolf) != null;
}
/*//////////////////////////////////////////////////////////////////
ARENA GETTERS
//////////////////////////////////////////////////////////////////*/
/**
* Get an Arena object at the given location.
* @param loc A location
* @return an Arena object, or null
*/
public Arena getArenaAtLocation(Location loc) {
return plugin.getArenaMaster().getArenaAtLocation(loc);
}
/**
* Get the Arena object that the given player is currently in.
* @param p A player
* @return an Arena object, or null
*/
public Arena getArenaWithPlayer(Player p) {
return plugin.getArenaMaster().getArenaWithPlayer(p);
}
/**
* Get the Arena object that the given pet is currently in.
* @param wolf A pet wolf
* @return an Arena object, or null
*/
public Arena getArenaWithPet(Entity wolf) {
return plugin.getArenaMaster().getArenaWithPet(wolf);
}
/**
* Get the Arena object that the given monster is currently in.
* @param monster A monster
* @return an Arena object, or null
*/
public Arena getArenaWithMonster(Entity monster) {
return plugin.getArenaMaster().getArenaWithMonster(monster);
}
}
@@ -0,0 +1,180 @@
package com.garbagemule.MobArena;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Wolf;
import org.bukkit.inventory.ItemStack;
import com.garbagemule.MobArena.waves.MABoss;
public class MonsterManager
{
private Set<LivingEntity> monsters, sheep, golems;
private Set<Wolf> pets;
private Map<LivingEntity,MABoss> bosses;
private Map<LivingEntity,List<ItemStack>> suppliers;
private Set<LivingEntity> mounts;
public MonsterManager() {
this.monsters = new HashSet<LivingEntity>();
this.sheep = new HashSet<LivingEntity>();
this.golems = new HashSet<LivingEntity>();
this.pets = new HashSet<Wolf>();
this.bosses = new HashMap<LivingEntity,MABoss>();
this.suppliers = new HashMap<LivingEntity,List<ItemStack>>();
this.mounts = new HashSet<LivingEntity>();
}
public void reset() {
monsters.clear();
sheep.clear();
golems.clear();
pets.clear();
bosses.clear();
suppliers.clear();
mounts.clear();
}
public void clear() {
removeAll(monsters);
removeAll(sheep);
removeAll(golems);
removeAll(pets);
removeAll(bosses.keySet());
removeAll(suppliers.keySet());
removeAll(mounts);
reset();
}
private void removeAll(Collection<? extends LivingEntity> collection) {
for (LivingEntity e : collection) {
if (e != null) {
e.remove();
}
}
}
public void remove(Entity e) {
if (monsters.remove(e)) {
sheep.remove(e);
golems.remove(e);
pets.remove(e);
suppliers.remove(e);
MABoss boss = bosses.remove(e);
if (boss != null) {
boss.setDead(true);
}
}
}
public Set<LivingEntity> getMonsters() {
return monsters;
}
public void addMonster(LivingEntity e) {
monsters.add(e);
}
public boolean removeMonster(Entity e) {
return monsters.remove(e);
}
public Set<LivingEntity> getExplodingSheep() {
return sheep;
}
public void addExplodingSheep(LivingEntity e) {
sheep.add(e);
}
public boolean removeExplodingSheep(LivingEntity e) {
return sheep.remove(e);
}
public Set<LivingEntity> getGolems() {
return golems;
}
public void addGolem(LivingEntity e) {
golems.add(e);
}
public boolean removeGolem(LivingEntity e) {
return golems.remove(e);
}
public Set<Wolf> getPets() {
return pets;
}
public void addPet(Wolf w) {
pets.add(w);
}
public boolean hasPet(Entity e) {
return pets.contains(e);
}
public void removePets(Player p) {
for (Wolf w : pets) {
if (w == null || !(w.getOwner() instanceof Player) || !((Player) w.getOwner()).getName().equals(p.getName()))
continue;
w.setOwner(null);
w.remove();
}
}
public void addMount(LivingEntity e) {
mounts.add(e);
}
public boolean hasMount(Entity e) {
return mounts.contains(e);
}
public boolean removeMount(Entity e) {
return mounts.remove(e);
}
public void removeMounts() {
for (LivingEntity e : mounts) {
e.remove();
}
}
public void addSupplier(LivingEntity e, List<ItemStack> drops) {
suppliers.put(e, drops);
}
public List<ItemStack> getLoot(Entity e) {
return suppliers.get(e);
}
public MABoss addBoss(LivingEntity e, double maxHealth) {
MABoss b = new MABoss(e, maxHealth);
bosses.put(e, b);
return b;
}
public MABoss removeBoss(LivingEntity e) {
return bosses.remove(e);
}
public MABoss getBoss(LivingEntity e) {
return bosses.get(e);
}
public Set<LivingEntity> getBossMonsters() {
return bosses.keySet();
}
}
@@ -0,0 +1,121 @@
package com.garbagemule.MobArena;
import org.bukkit.ChatColor;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
public enum Msg {
ARENA_START("Let the slaughter begin!"),
ARENA_END("Arena finished."),
ARENA_DOES_NOT_EXIST("That arena does not exist. Type &e/ma arenas&r for a list."),
ARENA_END_GLOBAL("Arena &e%&r finished! Type &e/ma j %&r to join a new game!"),
ARENA_JOIN_GLOBAL("Arena &e%&r is about to start! Type &e/ma j %&r to join!"),
ARENA_LBOARD_NOT_FOUND("That arena does not have a leaderboard set up."),
ARENA_AUTO_START("Arena will auto-start in &c%&r seconds."),
ARENA_START_DELAY("Arena can start in &e%&r seconds."),
JOIN_NOT_ENABLED("MobArena is not enabled."),
JOIN_IN_OTHER_ARENA("You are already in an arena! Leave that one first."),
JOIN_ARENA_NOT_ENABLED("This arena is not enabled."),
JOIN_ARENA_NOT_SETUP("This arena has not been set up yet."),
JOIN_ARENA_EDIT_MODE("This arena is in edit mode."),
JOIN_ARENA_PERMISSION("You don't have permission to join this arena."),
JOIN_FEE_REQUIRED("Insufficient funds. Price: &c%&r"),
JOIN_FEE_PAID("Price to join was: &c%&r"),
JOIN_ARENA_IS_RUNNING("This arena is already in progress."),
JOIN_ALREADY_PLAYING("You are already playing!"),
JOIN_ARG_NEEDED("You must specify an arena."),
JOIN_NO_PERMISSION("You don't have permission to join any arenas."),
JOIN_TOO_FAR("You are too far away from the arena to join/spectate."),
JOIN_EMPTY_INV("You must empty your inventory to join the arena."),
JOIN_PLAYER_LIMIT_REACHED("The player limit of this arena has been reached."),
JOIN_STORE_INV_FAIL("Failed to store inventory. Try again."),
JOIN_EXISTING_INV_RESTORED("Your old inventory items have been restored."),
JOIN_PLAYER_JOINED("You joined the arena. Have fun!"),
LEAVE_NOT_PLAYING("You are not in the arena."),
LEAVE_NOT_READY("You did not ready up in time! Next time, ready up by clicking an iron block."),
LEAVE_PLAYER_LEFT("You left the arena. Thanks for playing!"),
PLAYER_DIED("&c%&r died!"),
GOLEM_DIED("A friendly Golem has died!"),
SPEC_PLAYER_SPECTATE("Enjoy the show!"),
SPEC_FROM_ARENA("Enjoy the rest of the show!"),
SPEC_NOT_RUNNING("This arena isn't running."),
SPEC_EMPTY_INV("Empty your inventory first!"),
SPEC_ALREADY_PLAYING("Can't spectate when in the arena!"),
NOT_READY_PLAYERS("Not ready: &c%&r"),
FORCE_START_RUNNING("Arena has already started."),
FORCE_START_NOT_READY("Can't force start, no players are ready."),
FORCE_START_STARTED("Forced arena start."),
FORCE_END_EMPTY("No one is in the arena."),
FORCE_END_ENDED("Forced arena end."),
FORCE_END_IDLE("You weren't quick enough!"),
REWARDS_GIVE("Here are all of your rewards!"),
LOBBY_DROP_ITEM("No sharing allowed at this time!"),
LOBBY_PLAYER_READY("You have been flagged as ready!"),
LOBBY_PICK_CLASS("You must first pick a class!"),
LOBBY_CLASS_FULL("This class can no longer be selected, class limit reached!"),
LOBBY_NOT_ENOUGH_PLAYERS("Not enough players to start. Need at least &c%&r players."),
LOBBY_RIGHT_CLICK("Punch the sign. Don't right-click."),
LOBBY_CLASS_PICKED("You have chosen &e%&r as your class!"),
LOBBY_CLASS_RANDOM("You will get a random class on arena start."),
LOBBY_CLASS_PERMISSION("You don't have permission to use this class!"),
LOBBY_CLASS_PRICE("This class costs &c%&r (paid on arena start)."),
LOBBY_CLASS_TOO_EXPENSIVE("You can't afford that class (&c%&r)"),
LOBBY_NO_SUCH_CLASS("There is no class named &c%&r."),
WARP_TO_ARENA("Warping to the arena not allowed!"),
WARP_FROM_ARENA("Warping from the arena not allowed!"),
WAVE_DEFAULT("Wave &b#%&r!"),
WAVE_SPECIAL("Wave &b#%&r! [SPECIAL]"),
WAVE_SWARM("Wave &b#%&r! [SWARM]"),
WAVE_SUPPLY("Wave &b#%&r! [SUPPLY]"),
WAVE_UPGRADE("Wave &b#%&r! [UPGRADE]"),
WAVE_BOSS("Wave &b#%&r! [BOSS]"),
WAVE_BOSS_ABILITY("Boss used ability: &c%&r!"),
WAVE_BOSS_LOW_HEALTH("Boss is almost dead!"),
WAVE_REWARD("You just earned a reward: &e%&r"),
MISC_LIST_PLAYERS("Live players: &a%&r"),
MISC_LIST_ARENAS("Available arenas: %"),
MISC_COMMAND_NOT_ALLOWED("You can't use that command in the arena!"),
MISC_NO_ACCESS("You don't have access to this command."),
MISC_NOT_FROM_CONSOLE("You can't use this command from the console."),
MISC_HELP("For a list of commands, type &e/ma help&r"),
MISC_MULTIPLE_MATCHES("Did you mean one of these commands?"),
MISC_NO_MATCHES("Command not found. Type &e/ma help&r"),
MISC_MA_LEAVE_REMINDER("Remember to use &e/ma leave&r when you are done."),
MISC_NONE("&6<none>&r");
private String value;
private Msg(String value) {
set(value);
}
void set(String value) {
this.value = value;
}
public String toString() {
return ChatColor.translateAlternateColorCodes('&', value);
}
public String format(String s) {
return (s == null) ? "" : toString().replace("%", s);
}
static void load(ConfigurationSection config) {
for (Msg msg : values()) {
// ARENA_END_GLOBAL => arena-end-global
String key = msg.name().toLowerCase().replace("_","-");
msg.set(config.getString(key, ""));
}
}
static YamlConfiguration toYaml() {
YamlConfiguration yaml = new YamlConfiguration();
for (Msg msg : values()) {
// ARENA_END_GLOBAL => arena-end-global
String key = msg.name().replace("_","-").toLowerCase();
yaml.set(key, msg.value);
}
return yaml;
}
}
@@ -0,0 +1,109 @@
package com.garbagemule.MobArena;
import java.util.Collection;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect;
public class PlayerData
{
private Player player;
private double health;
private int food, level;
private float exp;
private GameMode mode = null;
private Location entry = null;
private Collection<PotionEffect> potions;
public PlayerData(Player player, Location loc) {
this.player = player;
this.mode = player.getGameMode();
this.potions = player.getActivePotionEffects();
this.entry = loc;
update();
}
/**
* Updates the information that is restored, when a player
* dies in the arena, that is, health, food level, and
* experience. Used when a player re-joins an arena while
* already being a spectator.
*/
public void update() {
this.health = player.getHealth();
this.food = player.getFoodLevel();
this.level = player.getLevel();
this.exp = player.getExp();
}
/**
* Restores health, food level, and experience as per the
* currently stored values of this object. Used when a
* player leaves the arena.
*/
public void restoreData() {
player.setFoodLevel(food);
player.setLevel(level);
player.setExp(exp);
}
public Player getPlayer() {
return player;
}
public double health() {
return health;
}
public void setHealth(int health) {
this.health = health;
}
public int food() {
return food;
}
public void setFood(int food) {
this.food = food;
}
public int level() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public float exp() {
return exp;
}
public void setExp(int exp) {
this.exp = exp;
}
public GameMode getMode() {
return mode;
}
public Collection<PotionEffect> getPotionEffects() {
return potions;
}
public void setMode(GameMode mode) {
this.mode = mode;
}
public Location entry() {
return entry;
}
public void setEntry(Location entry) {
this.entry = entry;
}
}
@@ -0,0 +1,69 @@
package com.garbagemule.MobArena;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import com.garbagemule.MobArena.framework.Arena;
public class RewardManager
{
@SuppressWarnings("unused")
private MobArena plugin;
@SuppressWarnings("unused")
private Arena arena;
private Map<Player,List<ItemStack>> players;
private Set<Player> rewarded;
public RewardManager(Arena arena) {
this.plugin = arena.getPlugin();
this.arena = arena;
this.players = new HashMap<Player,List<ItemStack>>();
this.rewarded = new HashSet<Player>();
}
public void reset() {
players.clear();
rewarded.clear();
}
public void addReward(Player p, ItemStack stack) {
if (!players.containsKey(p)) {
players.put(p, new ArrayList<ItemStack>());
}
players.get(p).add(stack);
}
public List<ItemStack> getRewards(Player p) {
List<ItemStack> rewards = players.get(p);
return (rewards == null ? new ArrayList<ItemStack>(1) : Collections.unmodifiableList(rewards));
}
public void grantRewards(Player p) {
if (rewarded.contains(p)) return;
List<ItemStack> rewards = players.get(p);
if (rewards == null) return;
for (ItemStack stack : rewards) {
if (stack == null) {
continue;
}
if (stack.getTypeId() == MobArena.ECONOMY_MONEY_ID) {
// plugin.giveMoney(p, stack.getAmount()); - removed to fix double money rewards
continue;
}
p.getInventory().addItem(stack);
}
rewarded.add(p);
}
}
@@ -0,0 +1,139 @@
package com.garbagemule.MobArena;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.scoreboard.DisplaySlot;
import org.bukkit.scoreboard.Objective;
import org.bukkit.scoreboard.Score;
import org.bukkit.scoreboard.Scoreboard;
import com.garbagemule.MobArena.framework.Arena;
public class ScoreboardManager {
private static final String DISPLAY_NAME = ChatColor.GREEN + "Kills " + ChatColor.AQUA + "Wave ";
private Arena arena;
private Scoreboard scoreboard;
private Objective kills;
/**
* Create a new scoreboard for the given arena.
* @param arena an arena
*/
ScoreboardManager(Arena arena) {
this.arena = arena;
scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
}
/**
* Add a player to the scoreboard by setting the player's scoreboard
* and giving him an initial to-be-reset non-zero score.
* @param player a player
*/
void addPlayer(Player player) {
/* Set the player's scoreboard and give them an initial non-zero
* score. This is necessary due to either Minecraft or Bukkit
* not wanting to show non-zero scores initially. */
player.setScoreboard(scoreboard);
kills.getScore(player).setScore(8);
}
/**
* Remove a player from the scoreboard by setting the player's scoreboard
* to the main server scoreboard.
* @param player a player
*/
void removePlayer(Player player) {
player.setScoreboard(Bukkit.getScoreboardManager().getMainScoreboard());
}
/**
* Add a kill to the player's score. Called when a player kills a mob.
* @param player a player
*/
void addKill(Player player) {
Score score = kills.getScore(player);
score.setScore(score.getScore() + 1);
}
/**
* Signal a player death.
* @param player a player
*/
void death(Player player) {
String name = ChatColor.GRAY + player.getName();
if (name.length() > 16) {
name = name.substring(0, 15);
}
int value = kills.getScore(player).getScore();
scoreboard.resetScores(player);
/* In case the player has no kills, they will not show up on the
* scoreboard unless they are first given a different score.
* If zero kills, the score is set to 8 (which looks a bit like
* 0), and then in the next tick, it's set to 0. Otherwise, the
* score is just set to its current value.
*/
final Score fake = kills.getScore(Bukkit.getOfflinePlayer(name));
if (value == 0) {
fake.setScore(8);
arena.scheduleTask(new Runnable() {
public void run() {
fake.setScore(0);
}
}, 1);
} else {
fake.setScore(value);
}
}
/**
* Update the scoreboard to display the given wave number.
* @param wave a wave number
*/
void updateWave(int wave) {
kills.setDisplayName(DISPLAY_NAME + wave);
}
/**
* Initialize the scoreboard by resetting the kills objective and
* setting all player scores to 0.
*/
void initialize() {
/* Initialization involves first unregistering the kill counter if
* it was already registered, and then setting it back up.
* It is necessary to delay the reset of the player scores, and the
* reset is necessary because of non-zero crappiness. */
resetKills();
arena.scheduleTask(new Runnable() {
public void run() {
for (Player p : arena.getPlayersInArena()) {
kills.getScore(p).setScore(0);
}
}
}, 1);
}
private void resetKills() {
if (kills != null) {
kills.unregister();
}
kills = scoreboard.registerNewObjective("kills", "ma-kills");
kills.setDisplaySlot(DisplaySlot.SIDEBAR);
updateWave(0);
}
static class NullScoreboardManager extends ScoreboardManager {
NullScoreboardManager(Arena arena) {
super(arena);
}
void addPlayer(Player player) {}
void removePlayer(Player player) {}
void addKill(Player player) {}
void death(Player player) {}
void updateWave(int wave) {}
void initialize() {}
}
}
@@ -0,0 +1,29 @@
package com.garbagemule.MobArena.commands;
import org.bukkit.command.CommandSender;
import com.garbagemule.MobArena.framework.ArenaMaster;
public interface Command
{
/**
* Execute the command using the given arguments.
* <p>
* If the method returns false, the command handler will print the usage
* message (usage + description) for the command, and as such, if the
* execution was successful in any way, the method should return true.
* Note that "successful in any way" means if the execution managed to
* complete in the sense that it itself prints a message to the sender,
* or otherwise executed properly, not if the intent of the command
* wasn't fulfilled. Typically, this means that false is only returned
* if the command was executed with a set of arguments that did not
* match the usage message.
*
* @param am an ArenaMaster instance
* @param sender the sender
* @param args array of arguments
* @return true, if the command succeeded in any way, false if the
* command handler should print the usage message to the sender
*/
public boolean execute(ArenaMaster am, CommandSender sender, String... args);
}
@@ -0,0 +1,242 @@
package com.garbagemule.MobArena.commands;
import java.util.*;
import java.util.Map.Entry;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.user.*;
import com.garbagemule.MobArena.commands.admin.*;
import com.garbagemule.MobArena.commands.setup.*;
import com.garbagemule.MobArena.framework.ArenaMaster;
import org.bukkit.conversations.Conversable;
import org.bukkit.entity.Player;
public class CommandHandler implements CommandExecutor
{
private MobArena plugin;
private ArenaMaster am;
private Map<String,Command> commands;
public CommandHandler(MobArena plugin) {
this.plugin = plugin;
this.am = plugin.getArenaMaster();
registerCommands();
}
@Override
public boolean onCommand(CommandSender sender, org.bukkit.command.Command bcmd, String label, String[] args) {
// Grab the base and arguments.
String base = (args.length > 0 ? args[0] : "");
String last = (args.length > 0 ? args[args.length - 1] : "");
// If the player is in a convo (Setup Mode), bail
if (sender instanceof Conversable && ((Conversable) sender).isConversing()) {
return true;
}
// If there's no base argument, show a helpful message.
if (base.equals("")) {
Messenger.tell(sender, Msg.MISC_HELP);
return true;
}
// The help command is a little special
if (base.equals("?") || base.equals("help")) {
showHelp(sender);
return true;
}
// Get all commands that match the base.
List<Command> matches = getMatchingCommands(base);
// If there's more than one match, display them.
if (matches.size() > 1) {
Messenger.tell(sender, Msg.MISC_MULTIPLE_MATCHES);
for (Command cmd : matches) {
showUsage(cmd, sender, false);
}
return true;
}
// If there are no matches at all, notify.
if (matches.size() == 0) {
Messenger.tell(sender, Msg.MISC_NO_MATCHES);
return true;
}
// Grab the only match.
Command command = matches.get(0);
CommandInfo info = command.getClass().getAnnotation(CommandInfo.class);
// First check if the sender has permission.
if (!plugin.has(sender, info.permission())) {
Messenger.tell(sender, Msg.MISC_NO_ACCESS);
return true;
}
// Check if the last argument is a ?, in which case, display usage and description
if (last.equals("?") || last.equals("help")) {
showUsage(command, sender, true);
return true;
}
// Otherwise, execute the command!
String[] params = trimFirstArg(args);
if (!command.execute(am, sender, params)) {
showUsage(command, sender, true);
}
return true;
}
/**
* Get all commands that match a given string.
* @param arg the given string
* @return a list of commands whose patterns match the given string
*/
private List<Command> getMatchingCommands(String arg) {
List<Command> result = new ArrayList<Command>();
// Grab the commands that match the argument.
for (Entry<String,Command> entry : commands.entrySet()) {
if (arg.matches(entry.getKey())) {
result.add(entry.getValue());
}
}
return result;
}
/**
* Show the usage and description messages of a command to a player.
* The usage will only be shown, if the player has permission for the command.
* @param cmd a Command
* @param sender a CommandSender
*/
private void showUsage(Command cmd, CommandSender sender, boolean prefix) {
CommandInfo info = cmd.getClass().getAnnotation(CommandInfo.class);
if (!plugin.has(sender, info.permission())) return;
sender.sendMessage((prefix ? "Usage: " : "") + info.usage() + " " + ChatColor.YELLOW + info.desc());
}
/**
* Remove the first argument of a string. This is because the very first
* element of the arguments array will be the command itself.
* @param args an array of length n
* @return the same array minus the first element, and thus of length n-1
*/
private String[] trimFirstArg(String[] args) {
return Arrays.copyOfRange(args, 1, args.length);
}
/**
* List all the available MobArena commands for the CommandSender.
* @param sender a player or the console
*/
private void showHelp(CommandSender sender) {
StringBuilder user = new StringBuilder();
StringBuilder admin = new StringBuilder();
StringBuilder setup = new StringBuilder();
for (Command cmd : commands.values()) {
CommandInfo info = cmd.getClass().getAnnotation(CommandInfo.class);
if (!plugin.has(sender, info.permission())) continue;
StringBuilder buffy;
if (info.permission().startsWith("mobarena.admin")) {
buffy = admin;
} else if (info.permission().startsWith("mobarena.setup")) {
buffy = setup;
} else {
buffy = user;
}
buffy.append("\n")
.append(ChatColor.RESET).append(info.usage()).append(" ")
.append(ChatColor.YELLOW).append(info.desc());
}
if (admin.length() == 0 && setup.length() == 0) {
Messenger.tell(sender, "Available commands: " + user.toString());
} else {
Messenger.tell(sender, "User commands: " + user.toString());
if (admin.length() > 0) Messenger.tell(sender, "Admin commands: " + admin.toString());
if (setup.length() > 0) Messenger.tell(sender, "Setup commands: " + setup.toString());
}
}
/**
* Register all the commands directly.
* This could also be done with a somewhat dirty classloader/resource reader
* method, but this is neater, albeit more manual work.
*/
private void registerCommands() {
commands = new LinkedHashMap<String,Command>();
// mobarena.use
register(JoinCommand.class);
register(LeaveCommand.class);
register(SpecCommand.class);
register(ArenaListCommand.class);
register(PlayerListCommand.class);
register(NotReadyCommand.class);
register(PickClassCommand.class);
// mobarena.admin
register(EnableCommand.class);
register(DisableCommand.class);
register(ForceCommand.class);
register(KickCommand.class);
register(RestoreCommand.class);
// mobarena.setup
register(ConfigCommand.class);
register(SetupCommand.class);
register(SettingCommand.class);
register(AddArenaCommand.class);
register(RemoveArenaCommand.class);
register(EditArenaCommand.class);
register(CheckDataCommand.class);
register(RemoveSpawnpointCommand.class);
register(CheckSpawnsCommand.class);
register(RemoveContainerCommand.class);
register(ListClassesCommand.class);
register(SetClassCommand.class);
register(SetClassPriceCommand.class);
register(RemoveClassCommand.class);
register(ClassChestCommand.class);
register(ListClassPermsCommand.class);
register(AddClassPermCommand.class);
register(RemoveClassPermCommand.class);
register(RemoveLeaderboardCommand.class);
register(AutoGenerateCommand.class);
register(AutoDegenerateCommand.class);
}
/**
* Register a command.
* The Command's CommandInfo annotation is queried to find its pattern
* string, which is used to map the commands.
* @param c a Command
*/
public void register(Class<? extends Command> c) {
CommandInfo info = c.getAnnotation(CommandInfo.class);
if (info == null) return;
try {
commands.put(info.pattern(), c.newInstance());
}
catch (Exception e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,33 @@
package com.garbagemule.MobArena.commands;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface CommandInfo
{
/**
* The actual name of the command. Not really used anywhere.
*/
public String name();
/**
* A regex pattern that allows minor oddities and alternatives to the command name.
*/
public String pattern();
/**
* The usage message, i.e. how the command should be used.
*/
public String usage();
/**
* A description of what the command does.
*/
public String desc();
/**
* The permission required to execute this command.
*/
public String permission();
}
@@ -0,0 +1,79 @@
package com.garbagemule.MobArena.commands;
import java.util.List;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.garbagemule.MobArena.Messenger;
import com.garbagemule.MobArena.Msg;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
import com.garbagemule.MobArena.util.TextUtils;
public class Commands
{
public static boolean isPlayer(CommandSender sender) {
return (sender instanceof Player);
}
public static Arena getArenaToJoinOrSpec(ArenaMaster am, Player p, String arg1) {
// Check if MobArena is enabled first.
if (!am.isEnabled()) {
Messenger.tell(p, Msg.JOIN_NOT_ENABLED);
return null;
}
// Then check if we have permission at all.
List<Arena> arenas = am.getPermittedArenas(p);
if (arenas.isEmpty()) {
Messenger.tell(p, Msg.JOIN_NO_PERMISSION);
return null;
}
// Then check if we have any enabled arenas.
arenas = am.getEnabledArenas(arenas);
if (arenas.isEmpty()) {
Messenger.tell(p, Msg.JOIN_NOT_ENABLED);
return null;
}
// The arena to join.
Arena arena = null;
// Branch on whether there's an argument or not.
if (arg1 != null) {
arena = am.getArenaWithName(arg1);
if (arena == null) {
Messenger.tell(p, Msg.ARENA_DOES_NOT_EXIST);
return null;
}
if (!arenas.contains(arena)) {
Messenger.tell(p, Msg.JOIN_ARENA_NOT_ENABLED);
return null;
}
}
else {
if (arenas.size() > 1) {
Messenger.tell(p, Msg.JOIN_ARG_NEEDED);
Messenger.tell(p, Msg.MISC_LIST_ARENAS.format(TextUtils.listToString(arenas)));
return null;
}
arena = arenas.get(0);
}
// If player is in a boat/minecart, eject!
if (p.isInsideVehicle()) {
p.leaveVehicle();
}
// If player is in a bed, unbed!
if (p.isSleeping()) {
p.kickPlayer("Banned for life... Nah, just don't join from a bed ;)");
return null;
}
return arena;
}
}
@@ -0,0 +1,53 @@
package com.garbagemule.MobArena.commands.admin;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
@CommandInfo(
name = "disable",
pattern = "disable|off",
usage = "/ma disable (<arena>|all)",
desc = "disable MobArena or individual arenas",
permission = "mobarena.admin.enable"
)
public class DisableCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
// Grab the argument, if any.
String arg1 = (args.length > 0 ? args[0] : "");
if (arg1.equals("all")) {
for (Arena arena : am.getArenas()) {
disable(arena, sender);
}
return true;
}
if (!arg1.equals("")) {
Arena arena = am.getArenaWithName(arg1);
if (arena == null) {
Messenger.tell(sender, Msg.ARENA_DOES_NOT_EXIST);
return true;
}
disable(arena, sender);
return true;
}
am.setEnabled(false);
am.saveConfig();
Messenger.tell(sender, "MobArena " + ChatColor.RED + "disabled");
return true;
}
private void disable(Arena arena, CommandSender sender) {
arena.setEnabled(false);
arena.getPlugin().saveConfig();
Messenger.tell(sender, "Arena '" + arena.configName() + "' " + ChatColor.RED + "disabled");
}
}
@@ -0,0 +1,53 @@
package com.garbagemule.MobArena.commands.admin;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
@CommandInfo(
name = "enable",
pattern = "enable|on",
usage = "/ma enable",
desc = "enable MobArena or individual arenas",
permission = "mobarena.admin.enable"
)
public class EnableCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
// Grab the argument, if any.
String arg1 = (args.length > 0 ? args[0] : "");
if (arg1.equals("all")) {
for (Arena arena : am.getArenas()) {
enable(arena, sender);
}
return true;
}
if (!arg1.equals("")) {
Arena arena = am.getArenaWithName(arg1);
if (arena == null) {
Messenger.tell(sender, Msg.ARENA_DOES_NOT_EXIST);
return true;
}
enable(arena, sender);
return true;
}
am.setEnabled(true);
am.saveConfig();
Messenger.tell(sender, "MobArena " + ChatColor.GREEN + "enabled");
return true;
}
private void enable(Arena arena, CommandSender sender) {
arena.setEnabled(true);
arena.getPlugin().saveConfig();
Messenger.tell(sender, "Arena '" + arena.configName() + "' " + ChatColor.GREEN + "enabled");
}
}
@@ -0,0 +1,85 @@
package com.garbagemule.MobArena.commands.admin;
import org.bukkit.command.CommandSender;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
@CommandInfo(
name = "force",
pattern = "force",
usage = "/ma force start|end (<arena>)",
desc = "force start or end an arena",
permission = "mobarena.admin.force"
)
public class ForceCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
// Require at least one argument
if (args.length < 1) return false;
// Grab the argument, if any.
String arg1 = (args.length > 0 ? args[0] : "");
String arg2 = (args.length > 1 ? args[1] : "");
if (arg1.equals("end")) {
// With no arguments, end all.
if (arg2.equals("")) {
for (Arena arena : am.getArenas()) {
arena.forceEnd();
}
Messenger.tell(sender, Msg.FORCE_END_ENDED);
am.resetArenaMap();
return true;
}
// Otherwise, grab the arena in question.
Arena arena = am.getArenaWithName(arg2);
if (arena == null) {
Messenger.tell(sender, Msg.ARENA_DOES_NOT_EXIST);
return true;
}
if (arena.getAllPlayers().isEmpty()) {
Messenger.tell(sender, Msg.FORCE_END_EMPTY);
return true;
}
// And end it!
arena.forceEnd();
Messenger.tell(sender, Msg.FORCE_END_ENDED);
return true;
}
if (arg1.equals("start")) {
// Require argument.
if (arg2.equals("")) return false;
// Grab the arena.
Arena arena = am.getArenaWithName(arg2);
if (arena == null) {
Messenger.tell(sender, Msg.ARENA_DOES_NOT_EXIST);
return true;
}
if (arena.isRunning()) {
Messenger.tell(sender, Msg.FORCE_START_RUNNING);
return true;
}
if (arena.getReadyPlayersInLobby().isEmpty()) {
Messenger.tell(sender, Msg.FORCE_START_NOT_READY);
return true;
}
// And start it!
arena.forceStart();
Messenger.tell(sender, Msg.FORCE_START_STARTED);
return true;
}
return false;
}
}
@@ -0,0 +1,40 @@
package com.garbagemule.MobArena.commands.admin;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
@CommandInfo(
name = "kick",
pattern = "kick|kcik",
usage = "/ma kick <player>",
desc = "kick a player from an arena",
permission = "mobarena.admin.kick"
)
public class KickCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
// Require a player name
if (args.length != 1) return false;
Arena arena = am.getArenaWithPlayer(args[0]);
if (arena == null) {
Messenger.tell(sender, "That player is not in an arena.");
return true;
}
// Grab the Player object.
Player bp = am.getPlugin().getServer().getPlayer(args[0]);
// Force leave.
arena.playerLeave(bp);
Messenger.tell(sender, "Player '" + args[0] + "' was kicked from arena '" + arena.configName() + "'.");
Messenger.tell(bp, "You were kicked by " + sender.getName() + ".");
return true;
}
}
@@ -0,0 +1,36 @@
package com.garbagemule.MobArena.commands.admin;
import org.bukkit.command.CommandSender;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.ArenaMaster;
import com.garbagemule.MobArena.util.inventory.InventoryManager;
@CommandInfo(
name = "restore",
pattern = "restore",
usage = "/ma restore <player>",
desc = "restore a player's inventory",
permission = "mobarena.admin.restore"
)
public class RestoreCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
// Require a player name
if (args.length != 1) return false;
if (am.getArenaWithPlayer(args[0]) != null) {
Messenger.tell(sender, "Player is currently in an arena.");
return true;
}
if (InventoryManager.restoreFromFile(am.getPlugin(), am.getPlugin().getServer().getPlayer(args[0]))) {
Messenger.tell(sender, "Restored " + args[0] + "'s inventory!");
} else {
Messenger.tell(sender, "Failed to restore " + args[0] + "'s inventory.");
}
return true;
}
}
@@ -0,0 +1,42 @@
package com.garbagemule.MobArena.commands.setup;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
@CommandInfo(
name = "addarena",
pattern = "(add|new)arena",
usage = "/ma addarena <arena>",
desc = "add a new arena",
permission = "mobarena.setup.addarena"
)
public class AddArenaCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
if (!Commands.isPlayer(sender)) {
Messenger.tell(sender, Msg.MISC_NOT_FROM_CONSOLE);
return true;
}
// Require an arena name
if (args.length != 1) return false;
// Cast the sender.
Player p = (Player) sender;
Arena arena = am.getArenaWithName(args[0]);
if (arena != null) {
Messenger.tell(sender, "An arena with that name already exists.");
return true;
}
am.createArenaNode(args[0], p.getWorld());
Messenger.tell(sender, "New arena with name '" + args[0] + "' created!");
return true;
}
}
@@ -0,0 +1,41 @@
package com.garbagemule.MobArena.commands.setup;
import org.bukkit.command.CommandSender;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.ArenaMaster;
import com.garbagemule.MobArena.util.TextUtils;
@CommandInfo(
name = "addclassperm",
pattern = "add(class)?perm(.*)",
usage = "/ma addclassperm <classname> <permission>",
desc = "add a per-class permission",
permission = "mobarena.setup.classes"
)
public class AddClassPermCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
// Require classname and permission
if (args.length != 2) return false;
// Grab the arena class
ArenaClass arenaClass = am.getClasses().get(args[0]);
if (arenaClass == null) {
Messenger.tell(sender, "The class '" + TextUtils.camelCase(args[0]) + "' does not exist.");
return true;
}
// Try to add the permission.
if (am.addClassPermission(args[0], args[1])) {
Messenger.tell(sender, "Added permission '" + args[1] + "' to class '" + TextUtils.camelCase(args[0]) + "'.");
return true;
}
// If it wasn't added, notify.
Messenger.tell(sender, "Permission '" + args[1] + "' was NOT added to class '" + TextUtils.camelCase(args[0]) + "'.");
return true;
}
}
@@ -0,0 +1,45 @@
package com.garbagemule.MobArena.commands.setup;
import org.bukkit.command.CommandSender;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
@CommandInfo(
name = "autodegenerate",
pattern = "auto(\\-)?degenerate",
usage = "/ma autodegenerate <arena>",
desc = "autodegenerate an existing arena",
permission = "mobarena.setup.autodegenerate"
)
public class AutoDegenerateCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
// Require an arena name
if (args.length != 1) return false;
// We have to make sure at least one arena exists before degenerating
if (am.getArenas().size() < 2) {
Messenger.tell(sender, "At least one arena must exist!");
return true;
}
// Check if arena exists.
Arena arena = am.getArenaWithName(args[0]);
if (arena == null) {
Messenger.tell(sender, Msg.ARENA_DOES_NOT_EXIST);
return true;
}
if (!MAUtils.undoItHippieMonster(args[0], am.getPlugin(), true)) {
Messenger.tell(sender, "Could not degenerate arena.");
return true;
}
Messenger.tell(sender, "Arena with name '" + args[0] + "' degenerated.");
return true;
}
}
@@ -0,0 +1,48 @@
package com.garbagemule.MobArena.commands.setup;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
@CommandInfo(
name = "autogenerate",
pattern = "auto(\\-)?generate",
usage = "/ma autogenerate <arena>",
desc = "autogenerate a new arena",
permission = "mobarena.setup.autogenerate"
)
public class AutoGenerateCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
if (!Commands.isPlayer(sender)) {
Messenger.tell(sender, Msg.MISC_NOT_FROM_CONSOLE);
return true;
}
// Require an arena name
if (args.length != 1) return false;
// Cast the sender.
Player p = (Player) sender;
// Check if arena already exists.
Arena arena = am.getArenaWithName(args[0]);
if (arena != null) {
Messenger.tell(sender, "An arena with that name already exists.");
return true;
}
if (!MAUtils.doooooItHippieMonster(p.getLocation(), 13, args[0], am.getPlugin())) {
Messenger.tell(sender, "Could not auto-generate arena.");
return true;
}
Messenger.tell(sender, "Arena with name '" + args[0] + "' generated.");
return true;
}
}
@@ -0,0 +1,39 @@
package com.garbagemule.MobArena.commands.setup;
import org.bukkit.command.CommandSender;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
@CommandInfo(
name = "checkdata",
pattern = "checkdata",
usage = "/ma checkdata <arena>",
desc = "check if all required points are set up",
permission = "mobarena.setup.checkdata"
)
public class CheckDataCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
Arena arena;
if (args.length == 0) {
if (am.getArenas().size() > 1) {
Messenger.tell(sender, "There are multiple arenas.");
return true;
} else {
arena = am.getArenas().get(0);
}
} else {
arena = am.getArenaWithName(args[0]);
if (arena == null) {
Messenger.tell(sender, "There is no arena named " + args[0]);
return true;
}
}
arena.getRegion().checkData(am.getPlugin(), sender, true, true, true, true);
return true;
}
}
@@ -0,0 +1,53 @@
package com.garbagemule.MobArena.commands.setup;
import com.garbagemule.MobArena.Messenger;
import com.garbagemule.MobArena.Msg;
import com.garbagemule.MobArena.commands.Command;
import com.garbagemule.MobArena.commands.CommandInfo;
import com.garbagemule.MobArena.commands.Commands;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@CommandInfo(
name = "checkspawns",
pattern = "checkspawn(point)?s",
usage = "/ma checkspawns <arena>",
desc = "show spawnpoints that cover your location",
permission = "mobarena.setup.checkspawns"
)
public class CheckSpawnsCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
if (!Commands.isPlayer(sender)) {
Messenger.tell(sender, Msg.MISC_NOT_FROM_CONSOLE);
return true;
}
Arena arena;
if (args.length == 0) {
if (am.getArenas().size() > 1) {
Messenger.tell(sender, "There are multiple arenas.");
return true;
} else {
arena = am.getArenas().get(0);
}
} else {
arena = am.getArenaWithName(args[0]);
if (arena == null) {
Messenger.tell(sender, "There is no arena named " + args[0]);
return true;
}
}
if (arena.getRegion().getSpawnpoints().isEmpty()) {
Messenger.tell(sender, "There are no spawnpoints in the selected arena.");
return true;
}
Player p = (Player) sender;
arena.getRegion().checkSpawns(p);
return true;
}
}
@@ -0,0 +1,63 @@
package com.garbagemule.MobArena.commands.setup;
import com.garbagemule.MobArena.ArenaClass;
import com.garbagemule.MobArena.Messenger;
import com.garbagemule.MobArena.Msg;
import com.garbagemule.MobArena.commands.Command;
import com.garbagemule.MobArena.commands.CommandInfo;
import com.garbagemule.MobArena.commands.Commands;
import com.garbagemule.MobArena.framework.ArenaMaster;
import com.garbagemule.MobArena.util.config.ConfigUtils;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.HashSet;
import static com.garbagemule.MobArena.util.config.ConfigUtils.setLocation;
@CommandInfo(
name = "classchest",
pattern = "classchest",
usage = "/ma classchest <class>",
desc = "link a chest to a class",
permission = "mobarena.setup.classchest"
)
public class ClassChestCommand implements Command {
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
if (!Commands.isPlayer(sender)) {
Messenger.tell(sender, Msg.MISC_NOT_FROM_CONSOLE);
return true;
}
// Require a class name
if (args.length != 1) return false;
ArenaClass ac = am.getClasses().get(args[0].toLowerCase());
if (ac == null) {
Messenger.tell(sender, "Class not found.");
return true;
}
Player p = (Player) sender;
Block b = p.getTargetBlock(new HashSet<Material>(), 10);
switch (b.getType()) {
case CHEST:
case ENDER_CHEST:
case TRAPPED_CHEST:
break;
default:
Messenger.tell(sender, "You must look at a chest.");
return true;
}
setLocation(am.getPlugin().getConfig(), "classes." + ac.getConfigName() + ".classchest", b.getLocation());
am.saveConfig();
Messenger.tell(sender, "Class chest updated for class " + ac.getConfigName());
am.loadClasses();
return true;
}
}
@@ -0,0 +1,41 @@
package com.garbagemule.MobArena.commands.setup;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.ArenaMaster;
@CommandInfo(
name = "config",
pattern = "config|cfg",
usage = "/ma config reload|save",
desc = "reload or save the config-file",
permission = "mobarena.setup.config"
)
public class ConfigCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
// Require reload/save
if (args.length != 1) return false;
if (args[0].equals("reload")) {
try {
am.reloadConfig();
Messenger.tell(sender, "Config reloaded.");
} catch (Exception e) {
Messenger.tell(sender, ChatColor.RED + "ERROR:" + ChatColor.RESET + "\n" + e.getMessage());
Messenger.tell(sender, "MobArena has been " + ChatColor.RED + "disabled" + ChatColor.RESET + ".");
Messenger.tell(sender, "Fix the config-file, then reload it again, and then type " + ChatColor.YELLOW + "/ma enable" + ChatColor.RESET + " to re-enable MobArena.");
}
} else if (args[0].equals("save")) {
am.saveConfig();
Messenger.tell(sender, "Config saved.");
} else {
return false;
}
return true;
}
}
@@ -0,0 +1,56 @@
package com.garbagemule.MobArena.commands.setup;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
@CommandInfo(
name = "editarena",
pattern = "edit(arena)?",
usage = "/ma editarena <arena> (true|false)",
desc = "set edit mode of an arena",
permission = "mobarena.setup.editarena"
)
public class EditArenaCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
boolean value;
Arena arena;
if (args.length == 0) {
if (am.getArenas().size() > 1) {
Messenger.tell(sender, "There are multiple arenas.");
return true;
}
arena = am.getArenas().get(0);
value = !arena.inEditMode();
} else if (args.length == 1) {
if (args[0].matches("on|off|true|false")) {
if (am.getArenas().size() > 1) {
Messenger.tell(sender, "There are multiple arenas.");
return true;
}
arena = am.getArenas().get(0);
value = args[0].matches("on|true");
} else {
arena = am.getArenaWithName(args[0]);
if (arena == null) {
Messenger.tell(sender, "There is no arena named " + args[0]);
return true;
}
value = !arena.inEditMode();
}
} else {
arena = am.getArenaWithName(args[0]);
value = args[1].matches("on|true");
}
arena.setEditMode(value);
Messenger.tell(sender, "Edit mode for arena '" + arena.configName() + "': " + ((arena.inEditMode()) ? ChatColor.GREEN + "true" : ChatColor.RED + "false"));
if (arena.inEditMode()) Messenger.tell(sender, "Remember to turn it back off after editing!");
return true;
}
}
@@ -0,0 +1,51 @@
package com.garbagemule.MobArena.commands.setup;
import java.util.Map;
import java.util.Map.Entry;
import org.bukkit.command.CommandSender;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.ArenaMaster;
import com.garbagemule.MobArena.util.TextUtils;
@CommandInfo(
name = "listclassperms",
pattern = "(list)?classperm(.*)s",
usage = "/ma listclassperms <classname>",
desc = "list per-class permissions",
permission = "mobarena.setup.classes"
)
public class ListClassPermsCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
// Require a class name
if (args.length != 1) return false;
ArenaClass arenaClass = am.getClasses().get(args[0]);
String className = TextUtils.camelCase(args[0]);
if (arenaClass == null) {
Messenger.tell(sender, "The class '" + className + "' does not exist.");
return true;
}
Messenger.tell(sender, "Permissions for '" + className + "':");
Map<String,Boolean> perms = arenaClass.getPermissions();
if (perms.isEmpty()) {
Messenger.tell(sender, "<none>");
return true;
}
for (Entry<String,Boolean> entry : arenaClass.getPermissions().entrySet()) {
String perm = entry.getKey();
if (!entry.getValue()) {
perm = "^" + perm;
}
Messenger.tell(sender, "- " + perm);
}
return true;
}
}
@@ -0,0 +1,34 @@
package com.garbagemule.MobArena.commands.setup;
import java.util.Set;
import org.bukkit.command.CommandSender;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.ArenaMaster;
@CommandInfo(
name = "listclasses",
pattern = "(list)?classes(.)*",
usage = "/ma listclasses",
desc = "list all current classes",
permission = "mobarena.setup.classes"
)
public class ListClassesCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
Messenger.tell(sender, "Current classes:");
Set<String> classes = am.getClasses().keySet();
if (classes == null || classes.isEmpty()) {
Messenger.tell(sender, "<none>");
return true;
}
for (String c : classes) {
Messenger.tell(sender, "- " + c);
}
return true;
}
}
@@ -0,0 +1,38 @@
package com.garbagemule.MobArena.commands.setup;
import org.bukkit.command.CommandSender;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
@CommandInfo(
name = "removearena",
pattern = "(del(.)*|r(e)?m(ove)?)arena",
usage = "/ma removearena <arena>",
desc = "remove an arena",
permission = "mobarena.setup.removearena"
)
public class RemoveArenaCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
// Require an arena name
if (args.length != 1) return false;
if (am.getArenas().size() == 1) {
Messenger.tell(sender, "At least one arena must exist.");
return true;
}
Arena arena = am.getArenaWithName(args[0]);
if (arena == null) {
Messenger.tell(sender, "There is no arena with that name.");
return true;
}
am.removeArenaNode(arena);
Messenger.tell(sender, "Arena '" + arena.configName() + "' deleted.");
return true;
}
}
@@ -0,0 +1,36 @@
package com.garbagemule.MobArena.commands.setup;
import org.bukkit.command.CommandSender;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.ArenaMaster;
import com.garbagemule.MobArena.util.TextUtils;
@CommandInfo(
name = "removeclass",
pattern = "(del(.)*|r(e)?m(ove)?)class",
usage = "/ma removeclass <classname>",
desc = "remove the given class",
permission = "mobarena.setup.classes"
)
public class RemoveClassCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
// Require a class name
if (args.length != 1) return false;
// Find the class
ArenaClass arenaClass = am.getClasses().get(args[0]);
String className = TextUtils.camelCase(args[0]);
if (arenaClass == null) {
Messenger.tell(sender, "The class '" + className + "' does not exist.");
return true;
}
am.removeClassNode(className);
Messenger.tell(sender, "Removed class '" + className + "'.");
return true;
}
}
@@ -0,0 +1,41 @@
package com.garbagemule.MobArena.commands.setup;
import org.bukkit.command.CommandSender;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.ArenaMaster;
import com.garbagemule.MobArena.util.TextUtils;
@CommandInfo(
name = "removeclassperm",
pattern = "(del(.)*|r(e)?m(ove)?)(class)?perm(.*)",
usage = "/ma removeclassperm <classname> <permission>",
desc = "remove a per-class permission",
permission = "mobarena.setup.classes"
)
public class RemoveClassPermCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
// Require class name and permission
if (args.length != 2) return false;
// Grab the arena class
ArenaClass arenaClass = am.getClasses().get(args[0]);
if (arenaClass == null) {
Messenger.tell(sender, "The class '" + TextUtils.camelCase(args[0]) + "' does not exist.");
return true;
}
// Remove the permission.
if (am.removeClassPermission(args[0], args[1])) {
Messenger.tell(sender, "Removed permission '" + args[1] + "' from class '" + TextUtils.camelCase(args[0]) + "'.");
return true;
}
// If it wasn't removed, notify.
Messenger.tell(sender, "Permission '" + args[1] + "' was NOT removed from class '" + TextUtils.camelCase(args[0]) + "'.");
return true;
}
}
@@ -0,0 +1,48 @@
package com.garbagemule.MobArena.commands.setup;
import com.garbagemule.MobArena.framework.Arena;
import org.bukkit.command.CommandSender;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.ArenaMaster;
@CommandInfo(
name = "removecontainer",
pattern = "(del(.)*|r(e)?m(ove)?)(container|chest)",
usage = "/ma removecontainer <arena> <chest>",
desc = "remove a container from the selected arena",
permission = "mobarena.setup.containers"
)
public class RemoveContainerCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
if (args.length < 1) return false;
Arena arena;
String chest;
if (args.length == 1) {
if (am.getArenas().size() > 1) {
Messenger.tell(sender, "There are multiple arenas.");
return true;
}
arena = am.getArenas().get(0);
chest = args[0];
} else {
arena = am.getArenaWithName(args[0]);
if (arena == null) {
Messenger.tell(sender, "There is no arena named " + args[0]);
return true;
}
chest = args[1];
}
if (arena.getRegion().removeChest(chest)) {
Messenger.tell(sender, "Container " + chest + " removed for arena '" + arena.configName() + "'");
} else {
Messenger.tell(sender, "Could not find the container " + chest + " for the arena '" + arena.configName() + "'");
}
return true;
}
}
@@ -0,0 +1,46 @@
package com.garbagemule.MobArena.commands.setup;
import com.garbagemule.MobArena.framework.Arena;
import org.bukkit.command.CommandSender;
import com.garbagemule.MobArena.Messenger;
import com.garbagemule.MobArena.Msg;
import com.garbagemule.MobArena.commands.Command;
import com.garbagemule.MobArena.commands.CommandInfo;
import com.garbagemule.MobArena.framework.ArenaMaster;
@CommandInfo(
name = "removeleaderboard",
pattern = "(del(.)*|r(e)?m(ove)?)leaderboard",
usage = "/ma removeleaderboard <arena>",
desc = "remove the selected arena's leaderboard",
permission = "mobarena.setup.leaderboards"
)
public class RemoveLeaderboardCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
Arena arena;
if (args.length == 0) {
if (am.getArenas().size() > 1) {
Messenger.tell(sender, "There are multiple arenas.");
return true;
}
arena = am.getArenas().get(0);
} else {
arena = am.getArenaWithName(args[0]);
if (arena == null) {
Messenger.tell(sender, "There is no arena named " + args[0]);
return true;
}
}
if (arena.getRegion().getLeaderboard() != null) {
arena.getRegion().set("leaderboard", null);
Messenger.tell(sender, "Leaderboard for " + arena.configName() + " successfully removed!");
} else {
Messenger.tell(sender, Msg.ARENA_LBOARD_NOT_FOUND);
}
return true;
}
}
@@ -0,0 +1,48 @@
package com.garbagemule.MobArena.commands.setup;
import com.garbagemule.MobArena.framework.Arena;
import org.bukkit.command.CommandSender;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.ArenaMaster;
@CommandInfo(
name = "delspawn",
pattern = "(del(.)*|r(e)?m(ove)?)spawn(point)?",
usage = "/ma delspawn <arena> <point>",
desc = "delete a spawnpoint",
permission = "mobarena.setup.spawnpoints"
)
public class RemoveSpawnpointCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
if (args.length < 1) return false;
Arena arena;
String point;
if (args.length == 1) {
if (am.getArenas().size() > 1) {
Messenger.tell(sender, "There are multiple arenas.");
return true;
}
arena = am.getArenas().get(0);
point = args[0];
} else {
arena = am.getArenaWithName(args[0]);
if (arena == null) {
Messenger.tell(sender, "There is no arena named " + args[0]);
return true;
}
point = args[1];
}
if (arena.getRegion().removeSpawn(point)) {
Messenger.tell(sender, "Spawnpoint " + point + " removed for arena '" + arena.configName() + "'");
} else {
Messenger.tell(sender, "Could not find the spawnpoint " + point + " for the arena '" + arena.configName() + "'");
}
return true;
}
}
@@ -0,0 +1,58 @@
package com.garbagemule.MobArena.commands.setup;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.ArenaMaster;
import com.garbagemule.MobArena.util.TextUtils;
@CommandInfo(
name = "setclass",
pattern = "setclass|saveclass",
usage = "/ma setclass (safe) <classname>",
desc = "save your inventory as a class",
permission = "mobarena.setup.classes"
)
public class SetClassCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
if (!Commands.isPlayer(sender)) {
Messenger.tell(sender, Msg.MISC_NOT_FROM_CONSOLE);
return true;
}
// Require at least a class name
if (args.length < 1) return false;
// Grab the argument, if any.
String arg1 = (args.length > 0 ? args[0] : "");
String arg2 = (args.length > 1 ? args[1] : "");
// Cast the sender.
Player p = (Player) sender;
// Check if we're overwriting.
boolean safe = arg1.equals("safe");
if (safe && arg2.equals("")) return false;
// If so, use arg2, otherwise, use arg1
String className = TextUtils.camelCase(safe ? arg2 : arg1);
// Create the class.
ArenaClass arenaClass = am.createClassNode(className, p.getInventory(), safe);
// If the class is null, it was not created.
if (arenaClass == null) {
Messenger.tell(p, "That class already exists!");
Messenger.tell(p, "To overwrite, omit the 'safe' parameter.");
return true;
}
// Otherwise, yay!
Messenger.tell(p, "Class '" + className + "' set with your current inventory.");
return true;
}
}
@@ -0,0 +1,70 @@
package com.garbagemule.MobArena.commands.setup;
import com.garbagemule.MobArena.ArenaClass;
import com.garbagemule.MobArena.Messenger;
import com.garbagemule.MobArena.Msg;
import com.garbagemule.MobArena.commands.Command;
import com.garbagemule.MobArena.commands.CommandInfo;
import com.garbagemule.MobArena.commands.Commands;
import com.garbagemule.MobArena.framework.ArenaMaster;
import com.garbagemule.MobArena.util.TextUtils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@CommandInfo(
name = "setclassprice",
pattern = "set(class)?price|fee",
usage = "/ma setclassprice <classname> $<price>",
desc = "set the price of a class",
permission = "mobarena.setup.classes"
)
public class SetClassPriceCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
// Require at least a class name
if (args.length < 1) return false;
// Grab the argument, if any.
String arg1 = args[0];
String arg2 = (args.length > 1 ? args[1] : "");
// Grab the class.
ArenaClass ac = am.getClasses().get(arg1);
if (ac == null) {
Messenger.tell(sender, "No class named '" + arg1 + "'.");
return true;
}
// Config-file value to set, and message to print
String value;
String msg;
if (!arg2.equals("")) {
// Strip the dollar sign, if it's there
if (arg2.startsWith("$")) {
arg2 = arg2.substring(1);
}
// Not a valid number? Bail!
if (!arg2.matches("([1-9]\\d*)|(\\d*.\\d\\d?)")) {
Messenger.tell(sender, "Could not parse price '" + arg2 + "'. Expected e.g. $10 or $2.50 or $.25");
return true;
}
double price = Double.parseDouble(arg2);
value = "$" + arg2;
msg = "Price for class '" + ac.getConfigName() + "' was set to " + am.getPlugin().economyFormat(price);
} else {
value = null;
msg = "Price for class '" + ac.getConfigName() + "' was removed. The class is now free!";
}
// Set the value, save and reload config
am.getPlugin().getConfig().set("classes." + ac.getConfigName() + ".price", value);
am.getPlugin().saveConfig();
am.loadClasses();
Messenger.tell(sender, msg);
return true;
}
}
@@ -0,0 +1,99 @@
package com.garbagemule.MobArena.commands.setup;
import com.garbagemule.MobArena.Messenger;
import com.garbagemule.MobArena.commands.Command;
import com.garbagemule.MobArena.commands.CommandInfo;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import java.util.Map;
@CommandInfo(
name = "setting",
pattern = "sett(ing)?",
usage = "/ma setting <arena> (<setting> (<value>))",
desc = "show or change arena settings",
permission = "mobarena.setup.setting"
)
public class SettingCommand implements Command {
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
// Require at least an arena
if (args.length < 1) return false;
// Find the arena first
Arena arena = am.getArenaWithName(args[0]);
if (arena == null) {
Messenger.tell(sender, "There's no arena with the name '" + args[0] + "'.");
return true;
}
// If we have no more args, just show all settings
if (args.length == 1) {
StringBuilder buffy = new StringBuilder();
buffy.append("Settings for ").append(ChatColor.GREEN).append(args[0]).append(ChatColor.RESET).append(":");
for (Map.Entry<String,Object> entry : arena.getSettings().getValues(false).entrySet()) {
buffy.append("\n").append(ChatColor.RESET);
buffy.append(ChatColor.AQUA).append(entry.getKey()).append(ChatColor.RESET).append(": ");
buffy.append(ChatColor.YELLOW).append(entry.getValue());
}
Messenger.tell(sender, buffy.toString());
return true;
}
// Otherwise, find the setting
Object val = arena.getSettings().get(args[1], null);
if (val == null) {
StringBuilder buffy = new StringBuilder();
buffy.append(ChatColor.RED).append(" is not a valid setting.");
buffy.append("Type ").append(ChatColor.YELLOW).append("/ma setting ").append(args[0]);
buffy.append(ChatColor.RESET).append(" to see all settings.");
Messenger.tell(sender, buffy.toString());
return true;
}
// If there are no more args, show the value
if (args.length == 2) {
StringBuilder buffy = new StringBuilder();
buffy.append(ChatColor.AQUA).append(args[1]).append(ChatColor.RESET).append(": ");
buffy.append(ChatColor.YELLOW).append(val);
Messenger.tell(sender, buffy.toString());
return true;
}
// Otherwise, determine the value of the setting
if (val instanceof Boolean) {
if (!args[2].matches("on|off|yes|no|true|false")) {
Messenger.tell(sender, "Expected a boolean value for that setting");
return true;
}
boolean value = args[2].matches("on|yes|true");
args[2] = String.valueOf(value);
arena.getSettings().set(args[1], value);
} else if (val instanceof Number) {
try {
arena.getSettings().set(args[1], Integer.parseInt(args[2]));
} catch (NumberFormatException e) {
Messenger.tell(sender, "Expected a numeric value for that setting.");
return true;
}
} else {
arena.getSettings().set(args[1], args[2]);
}
// Save config-file and reload arena
am.saveConfig();
am.reloadArena(args[0]);
// Notify the sender
StringBuilder buffy = new StringBuilder();
buffy.append("Setting ").append(ChatColor.AQUA).append(args[1]).append(ChatColor.RESET);
buffy.append(" for arena ").append(ChatColor.GREEN).append(args[0]).append(ChatColor.RESET);
buffy.append(" set to ").append(ChatColor.YELLOW).append(args[2]).append(ChatColor.RESET);
buffy.append("!");
Messenger.tell(sender, buffy.toString());
return true;
}
}
@@ -0,0 +1,771 @@
package com.garbagemule.MobArena.commands.setup;
import static com.garbagemule.MobArena.Messenger.*;
import com.garbagemule.MobArena.Msg;
import com.garbagemule.MobArena.commands.Command;
import com.garbagemule.MobArena.commands.CommandInfo;
import com.garbagemule.MobArena.commands.Commands;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
import com.garbagemule.MobArena.region.ArenaRegion;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.command.CommandSender;
import org.bukkit.conversations.*;
import org.bukkit.entity.Player;
import org.bukkit.event.*;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@CommandInfo(
name = "setup",
pattern = "setup",
usage = "/ma setup <arena>",
desc = "enter setup mode for an arena",
permission = "mobarena.setup.setup"
)
public class SetupCommand implements Command, Listener {
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
if (!Commands.isPlayer(sender)) {
tell(sender, Msg.MISC_NOT_FROM_CONSOLE);
return true;
}
// Get the arena
Arena arena;
if (args.length == 0) {
List<Arena> arenas = am.getArenas();
if (arenas.size() > 1) {
return false;
}
arena = arenas.get(0);
} else {
arena = am.getArenaWithName(args[0]);
if (arena == null) {
tell(sender, "There is no arena with the name " + ChatColor.RED + args[0] + ChatColor.RESET + ".");
tell(sender, "Type " + ChatColor.YELLOW + "/ma addarena " + args[0] + ChatColor.RESET + " to create it!");
return true;
}
}
Player player = (Player) sender;
// Create the setup object
Setup setup = new Setup(player, arena);
// Register it as an event listener
am.getPlugin().getServer().getPluginManager().registerEvents(setup, am.getPlugin());
// Set up the conversation
Conversation convo = new Conversation(am.getPlugin(), player, setup);
setup.convo = convo;
convo.addConversationAbandonedListener(setup);
convo.setLocalEchoEnabled(false);
convo.begin();
return true;
}
/**
* The internal Setup class has three roles; it is the prompt and the
* abandon listener for the Conversation initiated by the setup command,
* but it is also an event listener for the interact event, to handle
* the Toolbox events.
*/
private class Setup implements Prompt, ConversationAbandonedListener, Listener {
private Player player;
private Arena arena;
private Conversation convo;
private boolean enabled;
private boolean allowFlight;
private boolean flying;
private ItemStack[] armor;
private ItemStack[] items;
private List<String> missing;
private String next;
public Setup(Player player, Arena arena) {
this.player = player;
this.arena = arena;
// Store player and arena state
this.enabled = arena.isEnabled();
this.allowFlight = player.getAllowFlight();
this.flying = player.isFlying();
this.armor = player.getInventory().getArmorContents();
this.items = player.getInventory().getContents();
// Change state
arena.setEnabled(false);
player.setAllowFlight(true);
player.setFlying(true);
player.getInventory().clear();
player.getInventory().setContents(getToolbox());
player.getInventory().setHeldItemSlot(0);
this.missing = new ArrayList<String>();
this.next = color(String.format(
"Setup Mode for arena &a%s&r. Type &e?&r for help.",
"&a" + arena.configName() + "&r"
));
ArenaRegion region = arena.getRegion();
if (!region.isSetup()){
// Region points
if (!region.isDefined()) {
missing.add("p1");
missing.add("p2");
}
// Arena, lobby, and spectator warps
if (region.getArenaWarp() == null) missing.add("arena");
if (region.getLobbyWarp() == null) missing.add("lobby");
if (region.getSpecWarp() == null) missing.add("spectator");
// Spawnpoints
if (region.getSpawnpoints().isEmpty()) {
missing.add("spawnpoints");
}
}
}
// ====================================================================
// Toolbox handler
// ====================================================================
private ItemStack[] getToolbox() {
// Arena region tool
ItemStack areg = makeTool(
Material.GOLD_AXE, AREG_NAME,
color("Set &ep1"),
color("Set &ep2")
);
// Warps tool
ItemStack warps = makeTool(
Material.GOLD_HOE, WARPS_NAME,
color("&eSet &rselected warp"),
color("&eCycle &rbetween warps")
);
// Spawns tool
ItemStack spawns = makeTool(
Material.GOLD_SWORD, SPAWNS_NAME,
color("&eAdd &rspawnpoint on block"),
color("&eRemove &rspawnpoint on block")
);
// Chests tool
ItemStack chests = makeTool(
Material.GOLD_SPADE, CHESTS_NAME,
color("&eAdd &rcontainer"),
color("&eRemove &rcontainer")
);
// Lobby region tool
ItemStack lreg = makeTool(
Material.GOLD_AXE, LREG_NAME,
color("Set &el1"),
color("Set &el2")
);
// Round 'em up.
return new ItemStack[] {
null, areg, warps, spawns, chests, null, lreg
};
}
private ItemStack makeTool(Material mat, String name, String left, String right) {
ItemStack tool = new ItemStack(mat);
ItemMeta meta = tool.getItemMeta();
meta.setDisplayName(name);
meta.setLore(Arrays.asList(
color("&9Left&r: &r" + left),
color("&cRight&r: &r" + right)
));
tool.setItemMeta(meta);
return tool;
}
private boolean isTool(ItemStack item) {
if (item == null || item.getTypeId() == 0) return false;
String name = item.getItemMeta().getDisplayName();
if (name == null) return false;
// Just check the names of each tool
return name.equals(AREG_NAME)
|| name.equals(LREG_NAME)
|| name.equals(WARPS_NAME)
|| name.equals(SPAWNS_NAME)
|| name.equals(CHESTS_NAME)
|| name.equals(MANUAL_NAME);
}
@EventHandler
public void onDisable(PluginDisableEvent event) {
if (event.getPlugin().getName().equals(arena.getPlugin().getName()) && player.isConversing()) {
player.abandonConversation(convo);
}
}
@EventHandler
public void onQuit(PlayerQuitEvent event) {
if (event.getPlayer().equals(player) && player.isConversing()) {
player.abandonConversation(convo);
}
}
@EventHandler
public void onBreak(BlockBreakEvent event) {
Player p = event.getPlayer();
if (!p.equals(player)) return;
ItemStack tool = p.getItemInHand();
if (!isTool(tool)) return;
event.setCancelled(true);
tool.setDurability((short) 0);
}
@EventHandler
public void onDrop(PlayerDropItemEvent event) {
Player p = event.getPlayer();
if (!p.equals(player)) return;
event.setCancelled(true);
tell(p, "You can't drop the toolbox items.");
}
@EventHandler(priority = EventPriority.LOWEST)
public void onInteract(PlayerInteractEvent event) {
Player p = event.getPlayer();
if (!p.equals(player)) return;
ItemStack tool = p.getItemInHand();
if (!isTool(tool)) return;
String name = tool.getItemMeta().getDisplayName();
if (name.equals(AREG_NAME)) {
if (!arena(event)) return;
} else if (name.equals(LREG_NAME)) {
if (!lobby(event)) return;
} else if (name.equals(WARPS_NAME)) {
if (!warps(event)) return;
} else if (name.equals(SPAWNS_NAME)) {
if (!spawns(event)) return;
} else if (name.equals(CHESTS_NAME)) {
if (!chests(event)) return;
}
event.setUseItemInHand(Event.Result.DENY);
event.setCancelled(true);
player.sendRawMessage(getPromptText(null));
}
private boolean arena(PlayerInteractEvent event) {
if (!event.hasBlock()) {
return false;
}
Location loc = event.getClickedBlock().getLocation();
region(event.getAction(), "p1", "p2", loc);
return true;
}
private boolean lobby(PlayerInteractEvent event) {
if (!event.hasBlock()) {
return false;
}
Location loc = event.getClickedBlock().getLocation();
region(event.getAction(), "l1", "l2", loc);
return true;
}
private boolean region(Action action, String lower, String upper, Location loc) {
switch (action) {
case LEFT_CLICK_BLOCK: regions(lower, loc); return true;
case RIGHT_CLICK_BLOCK: regions(upper, loc); return true;
}
return false;
}
private boolean warps(PlayerInteractEvent event) {
switch (event.getAction()) {
case LEFT_CLICK_BLOCK:
Location loc = event.getClickedBlock().getLocation();
loc.setYaw(player.getLocation().getYaw());
loc.setPitch(0);
fix(loc);
String warp = warpArray[warpIndex];
warps(warp, loc);
return true;
case RIGHT_CLICK_BLOCK:
case RIGHT_CLICK_AIR:
warpIndex++;
if (warpIndex == warpArray.length) {
warpIndex = 0;
}
next = formatYellow("Current warp: %s", warpArray[warpIndex]);
return true;
}
return false;
}
private boolean spawns(PlayerInteractEvent event) {
if (!event.hasBlock()) {
return false;
}
Location l = event.getClickedBlock().getLocation();
fix(l);
switch (event.getAction()) {
case LEFT_CLICK_BLOCK: spawns(l, true); return true;
case RIGHT_CLICK_BLOCK: spawns(l, false); return true;
}
return false;
}
private boolean chests(PlayerInteractEvent event) {
if (!event.hasBlock()) {
return false;
}
Block b = event.getClickedBlock();
switch (event.getAction()) {
case LEFT_CLICK_BLOCK: chests(b, true); return true;
case RIGHT_CLICK_BLOCK: chests(b, false); return true;
}
return false;
}
private void fix(Location loc) {
loc.setX(loc.getBlockX() + 0.5D);
loc.setY(loc.getBlockY() + 1);
loc.setZ(loc.getBlockZ() + 0.5D);
}
private int warpIndex = 0;
private String[] warpArray = new String[] {"arena", "lobby", "spectator", "exit"};
private static final String AREG_NAME = "Arena Region";
private static final String LREG_NAME = "Lobby Region";
private static final String WARPS_NAME = "Warps";
private static final String SPAWNS_NAME = "Spawnpoints";
private static final String CHESTS_NAME = "Containers";
private static final String MANUAL_NAME = "Manual";
// ====================================================================
// Conversation end handler (items, state, etc.)
// ====================================================================
@Override
public void conversationAbandoned(ConversationAbandonedEvent event) {
// Unregister listener
HandlerList.unregisterAll(this);
// Restore player and arena state
arena.setEnabled(enabled);
arena.getRegion().save();
arena.getRegion().reloadAll();
player.getInventory().setContents(items);
player.getInventory().setArmorContents(armor);
// setAllowFlight(false) also handles setFlying(false)
player.setAllowFlight(allowFlight);
if (allowFlight) {
player.setFlying(flying);
}
}
// ====================================================================
// Prompt methods
// ====================================================================
@Override
public String getPromptText(ConversationContext context) {
return ChatColor.GREEN + "[MobArena] " + ChatColor.RESET + next;
}
@Override
public boolean blocksForInput(ConversationContext context) {
return true;
}
@Override
public Prompt acceptInput(ConversationContext context, String s) {
// Check regexes at the bottom of the file
return s.matches(HELP) ? help()
: s.matches(MISSING) ? missing()
: s.matches(EXPAND) ? expand(s)
: s.matches(EXPHELP) ? expandOptions()
: s.matches(SHOW) ? show(context, s)
: s.matches(SHOWHELP) ? showOptions()
: s.matches(DONE) ? done()
: invalidInput();
}
// ====================================================================
// Input handlers
// ====================================================================
/**
* Help
*/
private Prompt help() {
StringBuilder buffy = new StringBuilder();
buffy.append("\nAvailable input:");
buffy.append("\n&r&e exp &7expand a region");
buffy.append("\n&r&e show &7show a region, warp, or point");
buffy.append("\n&r&e miss &7show missing warps and points");
buffy.append("\n&r&e done &7exit out of Setup Mode");
buffy.append("\n&r&7Read &bitem tooltips&r&7 for info about each tool.");
next = color(buffy.toString());
return this;
}
/**
* Regions
*/
private Prompt regions(String s, Location loc) {
// Change worlds if needed
if (!inArenaWorld()) {
String msg = String.format(
"Changed world of arena %s from %s to %s.",
ChatColor.GREEN + arena.configName() + ChatColor.RESET,
ChatColor.YELLOW + arena.getWorld().getName() + ChatColor.RESET,
ChatColor.YELLOW + loc.getWorld().getName() + ChatColor.RESET
);
arena.setWorld(loc.getWorld());
tell(player, msg);
}
arena.getRegion().set(s, loc);
next = formatYellow("Region point %s was set.", s);
missing.remove(s);
return this;
}
/**
* Expand
*/
private Prompt expand(String s) {
String[] parts = s.split(" ");
boolean lobby = parts[1].equalsIgnoreCase("lr");
int amount = Integer.parseInt(parts[2]);
if (parts[3].equalsIgnoreCase("up")) {
if (lobby) {
arena.getRegion().expandLobbyUp(amount);
} else {
arena.getRegion().expandUp(amount);
}
} else if (parts[3].equalsIgnoreCase("down")) {
if (lobby) {
arena.getRegion().expandLobbyDown(amount);
} else {
arena.getRegion().expandDown(amount);
}
} else {
if (lobby) {
arena.getRegion().expandLobbyOut(amount);
} else {
arena.getRegion().expandOut(amount);
}
}
next = color(String.format("Expanded &e%s&r region &e%s&r by &e%s&r blocks.", (lobby ? "lobby" : "arena"), parts[3], parts[2]));
return this;
}
/**
* Warps
*/
private Prompt warps(String s, Location loc) {
if (s.equals("spec")) s = "spectator";
// World change stuff for the arena warp
if (s.equals("arena") && !arena.getRegion().contains(loc)) {
if (!arena.getWorld().getName().equals(loc.getWorld().getName())) {
World tmp = arena.getWorld();
arena.setWorld(loc.getWorld());
if (arena.getRegion().contains(loc)) {
String msg = String.format(
"Changed world of arena %s from %s to %s.",
ChatColor.GREEN + arena.configName() + ChatColor.RESET,
ChatColor.YELLOW + tmp.getName() + ChatColor.RESET,
ChatColor.YELLOW + loc.getWorld().getName() + ChatColor.RESET
);
tell(player, msg);
} else {
arena.setWorld(tmp);
next = "You must be inside the arena region.";
return this;
}
} else {
next = "You must be inside the arena region.";
return this;
}
}
missing.remove(s);
arena.getRegion().set(s, loc);
next = formatYellow("Warp point %s was set.", s);
return this;
}
/**
* Spawns
*/
private Prompt spawns(Location l, boolean add) {
String point = getName(l);
if (add) {
if (!arena.getRegion().contains(l)) {
next = "You must be inside the arena region.";
} else {
arena.getRegion().addSpawn(point, l);
next = formatYellow("Spawnpoint %s added.", point);
missing.remove("spawnpoints");
}
} else {
if (arena.getRegion().removeSpawn(point)) {
next = formatYellow("Spawnpoint %s removed.", point);
if (arena.getRegion().getSpawnpoints().size() == 0) {
missing.add("spawnpoints");
}
} else {
next = formatYellow("No spawnpoint named %s.", point);
}
}
return this;
}
/**
* Chests
*/
private Prompt chests(Block b, boolean add) {
if (b != null) {
if (!(b.getState() instanceof InventoryHolder)) {
next = "You must be looking at a container.";
} else if (!arena.getRegion().contains(b.getLocation())) {
next = "You must be inside the arena region.";
} else {
String point = getName(b.getLocation());
if (add) {
arena.getRegion().addChest(point, b.getLocation());
next = formatYellow("Container %s added.", point);
} else if (arena.getRegion().removeChest(point)) {
next = formatYellow("Container %s removed.", point);
} else {
next = formatYellow("No container named %s.", point);
}
}
}
return this;
}
/**
* Show things.
*/
private Prompt show(ConversationContext context, String s) {
ArenaRegion region = arena.getRegion();
String toShow = s.split(" ")[1].trim();
// Regions
if (toShow.equalsIgnoreCase("r") || toShow.equalsIgnoreCase("regions")) {
if (region.isDefined()) {
region.showRegion(player);
if (region.isLobbyDefined()) {
region.showLobbyRegion(player);
next = formatYellow("Showing both %s.", "regions");
} else {
next = formatYellow("Showing %s (lobby region not defined).", "arena region");
}
} else if (region.isLobbyDefined()) {
region.showLobbyRegion(player);
next = formatYellow("Showing %s (arena region not defined).", "lobby region");
} else {
next = "No regions have been defined yet.";
}
return this;
} else if (toShow.equalsIgnoreCase("ar")) {
if (region.isDefined()) {
next = formatYellow("Showing %s.", "arena region");
region.showRegion(player);
} else {
next = "The region has not been defined yet.";
}
return this;
} else if (toShow.equalsIgnoreCase("lr")) {
if (region.isLobbyDefined()) {
next = formatYellow("Showing %s.", "lobby region");
region.showLobbyRegion(player);
} else {
next = "The lobby region has not been defined yet.";
}
return this;
}
// Warps
if (toShow.matches("arena|lobby|spec(tator)?|exit")) {
next = formatYellow("Showing %s warp.", toShow);
Location loc;
loc = toShow.equals("arena") ? region.getArenaWarp() :
toShow.equals("lobby") ? region.getLobbyWarp() :
toShow.equals("spec") ? region.getSpecWarp() :
toShow.equals("spectator") ? region.getSpecWarp() :
toShow.equals("exit") ? region.getExitWarp() : null;
region.showBlock(player, loc, 35, (byte) 14);
return this;
}
// Spawnpoints
if (toShow.matches("sp(awn(point)?s?)?")) {
next = formatYellow("Showing %s.", "spawnpoints");
region.showSpawns(player);
return this;
}
// Chests
if (toShow.matches("c((hest(s)?)?|on(tainer(s)?)?)")) {
next = formatYellow("Showing %s.", "containers");
region.showChests(player);
return this;
}
// Show the "show help", if invalid thing
return acceptInput(context, "show ?");
}
/**
* Missing points and warps
*/
private Prompt missing() {
if (missing.isEmpty()) {
next = "All required points and warps have been set!";
} else {
next = "Missing points and warps: " + getMissing();
}
return this;
}
/**
* Expand options
*/
private Prompt expandOptions() {
StringBuilder buffy = new StringBuilder();
buffy.append("\nUsage: &eexp <region> <amount> <direction>");
buffy.append("\n\n&r&7Variable details:");
buffy.append("\n&r&7 region: &rar&7 (arena region) or &rlr&7 (lobby region)");
buffy.append("\n&r&7 amount: number of blocks to expand by");
buffy.append("\n&r&7 direction: &rup&7, &rdown&7, or &routs&7");
buffy.append("\n\n&r&7Examples:");
buffy.append("\n&r exp ar 5 up &7expand arena region up by 5");
buffy.append("\n&r exp lr 10 out &7expand lobby region out by 10");
next = color(buffy.toString());
return this;
}
/**
* Show options
*/
private Prompt showOptions() {
StringBuilder buffy = new StringBuilder();
buffy.append("\nUsage: &eshow <thing>");
buffy.append("\n\n&r&7Possible things to show:");
buffy.append("\n&r&7 regions: &rar&7 (arena region) or &rlr&7 (lobby region) or &rr&7 (both)");
buffy.append("\n&r&7 warps: &rarena&7, &rlobby&7, &rspec&7, or &rexit");
buffy.append("\n&r&7 points: &rspawns&7 or &rchests&7");
buffy.append("\n\n&r&7Examples:");
buffy.append("\n&r show spawns &7show spawnpoints");
buffy.append("\n&r show ar &7show arena region");
next = color(buffy.toString());
return this;
}
/**
* Done!
*/
private Prompt done() {
if (missing.isEmpty()) {
tell(player, "Setup complete! Arena is ready to be used!");
} else {
tell(player, "Setup incomplete. Missing points and warps: " + getMissing());
}
return Prompt.END_OF_CONVERSATION;
}
/**
* Invalid input
*/
private Prompt invalidInput() {
next = formatYellow("Invalid input. Type %s for help", "?");
return this;
}
// ====================================================================
// Auxiliary methods
// ====================================================================
private String getMissing() {
StringBuilder buffy = new StringBuilder();
for (String m : missing) {
buffy.append("\n").append(m);
}
return buffy.toString();
}
private String color(String s) {
return ChatColor.translateAlternateColorCodes('&', s);
}
private boolean inArenaWorld() {
return player.getWorld().getName().equals(arena.getWorld().getName());
}
private void tell(Conversable whom, String msg) {
whom.sendRawMessage(ChatColor.GREEN + "[MobArena] " + ChatColor.RESET + msg);
}
private String formatYellow(String msg, String arg) {
return String.format(msg, ChatColor.YELLOW + arg + ChatColor.RESET);
}
private String getName(Location l) {
return l.getBlockX() + "," + l.getBlockY() + "," + l.getBlockZ();
}
// ====================================================================
// Regular expressions for the input
// ====================================================================
private static final String HELP = "[?]|h(elp)?";
private static final String MISSING = "miss(ing)?";
private static final String EXPAND = "exp(and)? (a|l)r [1-9][0-9]* (up|down|out)";
private static final String EXPHELP = "exp(and)?";
private static final String SHOW = "show (r|ar|lr|arena|lobby|spec(tator)?|exit|sp(awn(point)?s?)?|c((hest(s)?)?|on(tainer(s)?)?))";
private static final String SHOWHELP = "show";
private static final String DONE = "done|quit|stop|end";
}
}
@@ -0,0 +1,37 @@
package com.garbagemule.MobArena.commands.user;
import java.util.List;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
@CommandInfo(
name = "arenalist",
pattern = "arenas|arenal.*|lista.*",
usage = "/ma arenas",
desc = "lists all available arenas",
permission = "mobarena.use.arenalist"
)
public class ArenaListCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
List<Arena> arenas;
if (Commands.isPlayer(sender)) {
Player p = (Player) sender;
arenas = am.getPermittedArenas(p);
} else {
arenas = am.getArenas();
}
String list = MAUtils.listToString(arenas, am.getPlugin());
Messenger.tell(sender, Msg.MISC_LIST_ARENAS.format(list));
return true;
}
}
@@ -0,0 +1,55 @@
package com.garbagemule.MobArena.commands.user;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
@CommandInfo(
name = "join",
pattern = "j|jo.*|j.*n",
usage = "/ma join (<arena>)",
desc = "join an arena",
permission = "mobarena.use.join"
)
public class JoinCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
if (!Commands.isPlayer(sender)) {
Messenger.tell(sender, Msg.MISC_NOT_FROM_CONSOLE);
return true;
}
// Cast the sender, grab the argument, if any.
Player p = (Player) sender;
String arg1 = (args.length > 0 ? args[0] : null);
// Run some rough sanity checks, and grab the arena to join.
Arena toArena = Commands.getArenaToJoinOrSpec(am, p, arg1);
if (toArena == null) {
return true;
}
// Deny joining from other arenas
Arena fromArena = am.getArenaWithPlayer(p);
if (fromArena != null && (fromArena.inArena(p) || fromArena.inLobby(p))) {
Messenger.tell(p, Msg.JOIN_ALREADY_PLAYING);
return true;
}
// Per-arena sanity checks
if (!toArena.canJoin(p)) {
return true;
}
// Force leave previous arena
if (fromArena != null) fromArena.playerLeave(p);
// Join the arena!
return toArena.playerJoin(p, p.getLocation());
}
}
@@ -0,0 +1,44 @@
package com.garbagemule.MobArena.commands.user;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
@CommandInfo(
name = "leave",
pattern = "l|le((.*))?",
usage = "/ma leave",
desc = "leave the arena",
permission = "mobarena.use.leave"
)
public class LeaveCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
if (!Commands.isPlayer(sender)) {
Messenger.tell(sender, Msg.MISC_NOT_FROM_CONSOLE);
return true;
}
// Cast the sender.
Player p = (Player) sender;
Arena arena = am.getArenaWithPlayer(p);
if (arena == null) {
arena = am.getArenaWithSpectator(p);
if (arena == null) {
Messenger.tell(p, Msg.LEAVE_NOT_PLAYING);
return true;
}
}
if (arena.playerLeave(p)) {
Messenger.tell(p, Msg.LEAVE_PLAYER_LEFT);
}
return true;
}
}
@@ -0,0 +1,50 @@
package com.garbagemule.MobArena.commands.user;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
@CommandInfo(
name = "notready",
pattern = "notr.*|ready",
usage = "/ma notready (<arena>)",
desc = "see which players aren't ready",
permission = "mobarena.use.notready"
)
public class NotReadyCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
// Grab the argument, if any
String arg1 = (args.length > 0 ? args[0] : "");
// The arena to query.
Arena arena = null;
if (!arg1.equals("")) {
arena = am.getArenaWithName(arg1);
if (arena == null) {
Messenger.tell(sender, Msg.ARENA_DOES_NOT_EXIST);
return false;
}
} else if (Commands.isPlayer(sender)) {
Player p = (Player) sender;
arena = am.getArenaWithPlayer(p);
if (arena == null) {
Messenger.tell(sender, Msg.LEAVE_NOT_PLAYING);
return true;
}
} else {
return false;
}
String list = MAUtils.listToString(arena.getNonreadyPlayers(), am.getPlugin());
Messenger.tell(sender, Msg.MISC_LIST_PLAYERS.format(list));
return true;
}
}
@@ -0,0 +1,124 @@
package com.garbagemule.MobArena.commands.user;
import com.garbagemule.MobArena.ArenaClass;
import com.garbagemule.MobArena.ClassLimitManager;
import com.garbagemule.MobArena.Messenger;
import com.garbagemule.MobArena.Msg;
import com.garbagemule.MobArena.commands.Command;
import com.garbagemule.MobArena.commands.CommandInfo;
import com.garbagemule.MobArena.commands.Commands;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
import com.garbagemule.MobArena.util.TextUtils;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
@CommandInfo(
name = "class",
pattern = "(pick)?class",
usage = "/ma class <class>",
desc = "pick a class",
permission = "mobarena.use.class"
)
public class PickClassCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
if (!Commands.isPlayer(sender)) {
Messenger.tell(sender, Msg.MISC_NOT_FROM_CONSOLE);
return true;
}
// Require a class name
if (args.length != 1) return false;
// Cast the sender
Player p = (Player) sender;
// Make sure the player is in an arena
Arena arena = am.getArenaWithPlayer(p);
if (arena == null) return true;
// Make sure the player is in the lobby
if (!arena.inLobby(p)) {
Messenger.tell(p, Msg.MISC_NO_ACCESS);
return true;
}
// Grab the ArenaClass, if it exists
String lowercase = args[0].toLowerCase();
ArenaClass ac = am.getClasses().get(lowercase);
if (ac == null) {
Messenger.tell(p, Msg.LOBBY_NO_SUCH_CLASS, lowercase);
return true;
}
// Check for permission.
if (!am.getPlugin().has(p, "mobarena.classes." + lowercase) && !lowercase.equals("random")) {
Messenger.tell(p, Msg.LOBBY_CLASS_PERMISSION);
return true;
}
// Grab the old ArenaClass, if any, same => ignore
ArenaClass oldAC = arena.getArenaPlayer(p).getArenaClass();
if (ac.equals(oldAC)) return true;
// If the new class is full, inform the player.
ClassLimitManager clm = arena.getClassLimitManager();
if (!clm.canPlayerJoinClass(ac)) {
Messenger.tell(p, Msg.LOBBY_CLASS_FULL);
return true;
}
// Check price, balance, and inform
double price = ac.getPrice();
if (price > 0D) {
if (!am.getPlugin().hasEnough(p, price)) {
Messenger.tell(p, Msg.LOBBY_CLASS_TOO_EXPENSIVE, am.getPlugin().economyFormat(price));
return true;
}
}
// Otherwise, leave the old class, and pick the new!
clm.playerLeftClass(oldAC, p);
clm.playerPickedClass(ac, p);
if (!lowercase.equalsIgnoreCase("random")) {
if (arena.getSettings().getBoolean("use-class-chests", false)) {
Location loc = ac.getClassChest();
if (loc != null) {
Block blockChest = loc.getBlock();
InventoryHolder holder = (InventoryHolder) blockChest.getState();
ItemStack[] contents = holder.getInventory().getContents();
// Guard against double-chests for now
if (contents.length > 36) {
ItemStack[] newContents = new ItemStack[36];
System.arraycopy(contents, 0, newContents, 0, 36);
contents = newContents;
}
arena.assignClassGiveInv(p, lowercase, contents);
p.getInventory().setContents(contents);
Messenger.tell(p, Msg.LOBBY_CLASS_PICKED, TextUtils.camelCase(lowercase));
if (price > 0D) {
Messenger.tell(p, Msg.LOBBY_CLASS_PRICE, am.getPlugin().economyFormat(price));
}
return true;
}
// No linked chest? Fall through to config-file
}
arena.assignClass(p, lowercase);
Messenger.tell(p, Msg.LOBBY_CLASS_PICKED, TextUtils.camelCase(lowercase));
if (price > 0D) {
Messenger.tell(p, Msg.LOBBY_CLASS_PRICE, am.getPlugin().economyFormat(price));
}
} else {
arena.addRandomPlayer(p);
Messenger.tell(p, Msg.LOBBY_CLASS_RANDOM);
}
return true;
}
}
@@ -0,0 +1,53 @@
package com.garbagemule.MobArena.commands.user;
import java.util.LinkedList;
import java.util.List;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
@CommandInfo(
name = "playerlist",
pattern = "player.*|listp.*",
usage = "/ma players (<arena>)",
desc = "lists players in an arena",
permission = "mobarena.use.playerlist"
)
public class PlayerListCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
// Grab the argument, if any.
String arg1 = (args.length > 0 ? args[0] : "");
String list = null;
if (!arg1.equals("")) {
Arena arena = am.getArenaWithName(arg1);
if (arena == null) {
Messenger.tell(sender, Msg.ARENA_DOES_NOT_EXIST);
return false;
}
list = MAUtils.listToString(arena.getPlayersInArena(), am.getPlugin());
} else {
StringBuilder buffy = new StringBuilder();
List<Player> players = new LinkedList<Player>();
for (Arena arena : am.getArenas()) {
players.addAll(arena.getPlayersInArena());
}
buffy.append(MAUtils.listToString(players, am.getPlugin()));
list = buffy.toString();
}
Messenger.tell(sender, Msg.MISC_LIST_PLAYERS.format(list));
return true;
}
}
@@ -0,0 +1,56 @@
package com.garbagemule.MobArena.commands.user;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.garbagemule.MobArena.*;
import com.garbagemule.MobArena.commands.*;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
@CommandInfo(
name = "spec",
pattern = "s|spec.*",
usage = "/ma spec (<arena>)",
desc = "spec an arena",
permission = "mobarena.use.spec"
)
public class SpecCommand implements Command
{
@Override
public boolean execute(ArenaMaster am, CommandSender sender, String... args) {
if (!Commands.isPlayer(sender)) {
Messenger.tell(sender, Msg.MISC_NOT_FROM_CONSOLE);
return false;
}
// Cast the sender, grab the argument, if any.
Player p = (Player) sender;
String arg1 = (args.length > 0 ? args[0] : null);
// Run some rough sanity checks, and grab the arena to spec.
Arena toArena = Commands.getArenaToJoinOrSpec(am, p, arg1);
if (toArena == null) {
return true;
}
// Deny spectating from other arenas
Arena fromArena = am.getArenaWithPlayer(p);
if (fromArena != null && (fromArena.inArena(p) || fromArena.inLobby(p))) {
Messenger.tell(p, Msg.SPEC_ALREADY_PLAYING);
return true;
}
// Per-arena sanity checks
if (!toArena.canSpec(p)) {
return true;
}
// Force leave previous arena
if (fromArena != null) fromArena.playerLeave(p);
// Spec the arena!
toArena.playerSpec(p, p.getLocation());
return true;
}
}
@@ -0,0 +1,48 @@
package com.garbagemule.MobArena.events;
import com.garbagemule.MobArena.framework.Arena;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import java.util.HashSet;
import java.util.Set;
public class ArenaCompleteEvent extends Event {
private static final HandlerList handlers = new HandlerList();
private Arena arena;
private Set<Player> survivors;
public ArenaCompleteEvent(Arena arena) {
this.arena = arena;
this.survivors = new HashSet<Player>();
this.survivors.addAll(arena.getPlayersInArena());
}
/**
* Get the arena the event happened in.
*
* @return an arena
*/
public Arena getArena() {
return arena;
}
/**
* Get a set of players who survived until the final wave.
*
* @return a set of winners
*/
public Set<Player> getSurvivors() {
return survivors;
}
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}
@@ -0,0 +1,41 @@
package com.garbagemule.MobArena.events;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import com.garbagemule.MobArena.framework.Arena;
public class ArenaEndEvent extends Event implements Cancellable
{
private static final HandlerList handlers = new HandlerList();
private Arena arena;
private boolean cancelled;
public ArenaEndEvent(Arena arena) {
this.arena = arena;
this.cancelled = false;
}
public Arena getArena() {
return arena;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}
@@ -0,0 +1,60 @@
package com.garbagemule.MobArena.events;
import com.garbagemule.MobArena.framework.Arena;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
/**
* Called when an arena player kills a mob or another player.
*/
public class ArenaKillEvent extends Event {
private static final HandlerList handlers = new HandlerList();
private Arena arena;
private Player killer;
private Entity victim;
public ArenaKillEvent(Arena arena, Player killer, Entity victim) {
this.arena = arena;
this.killer = killer;
this.victim = victim;
}
/**
* Get the arena the event happened in.
*
* @return an arena
*/
public Arena getArena() {
return arena;
}
/**
* Get the killer.
*
* @return the killer
*/
public Player getPlayer() {
return killer;
}
/**
* Get the victim.
*
* @return the victim
*/
public Entity getVictim() {
return victim;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}
@@ -0,0 +1,41 @@
package com.garbagemule.MobArena.events;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import com.garbagemule.MobArena.framework.Arena;
public class ArenaPlayerDeathEvent extends Event
{
private static final HandlerList handlers = new HandlerList();
private Player player;
private Arena arena;
private boolean last;
public ArenaPlayerDeathEvent(Player player, Arena arena, boolean last) {
this.player = player;
this.arena = arena;
this.last = last;
}
public Player getPlayer() {
return player;
}
public Arena getArena() {
return arena;
}
public boolean wasLastPlayerStanding() {
return last;
}
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}
@@ -0,0 +1,48 @@
package com.garbagemule.MobArena.events;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import com.garbagemule.MobArena.framework.Arena;
public class ArenaPlayerJoinEvent extends Event implements Cancellable
{
private static final HandlerList handlers = new HandlerList();
private Player player;
private Arena arena;
private boolean cancelled;
public ArenaPlayerJoinEvent(Player player, Arena arena) {
this.player = player;
this.arena = arena;
this.cancelled = false;
}
public Player getPlayer() {
return player;
}
public Arena getArena() {
return arena;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}
@@ -0,0 +1,48 @@
package com.garbagemule.MobArena.events;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import com.garbagemule.MobArena.framework.Arena;
public class ArenaPlayerLeaveEvent extends Event implements Cancellable
{
private static final HandlerList handlers = new HandlerList();
private Player player;
private Arena arena;
private boolean cancelled;
public ArenaPlayerLeaveEvent(Player player, Arena arena) {
this.player = player;
this.arena = arena;
this.cancelled = false;
}
public Player getPlayer() {
return player;
}
public Arena getArena() {
return arena;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}
@@ -0,0 +1,48 @@
package com.garbagemule.MobArena.events;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import com.garbagemule.MobArena.framework.Arena;
public class ArenaPlayerReadyEvent extends Event implements Cancellable
{
private static final HandlerList handlers = new HandlerList();
private Player player;
private Arena arena;
private boolean cancelled;
public ArenaPlayerReadyEvent(Player player, Arena arena) {
this.player = player;
this.arena = arena;
this.cancelled = false;
}
public Player getPlayer() {
return player;
}
public Arena getArena() {
return arena;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}
@@ -0,0 +1,41 @@
package com.garbagemule.MobArena.events;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import com.garbagemule.MobArena.framework.Arena;
public class ArenaStartEvent extends Event implements Cancellable
{
private static final HandlerList handlers = new HandlerList();
private Arena arena;
private boolean cancelled;
public ArenaStartEvent(Arena arena) {
this.arena = arena;
this.cancelled = false;
}
public Arena getArena() {
return arena;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}
@@ -0,0 +1,54 @@
package com.garbagemule.MobArena.events;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.waves.Wave;
public class NewWaveEvent extends Event implements Cancellable
{
private static final HandlerList handlers = new HandlerList();
private Arena arena;
private boolean cancelled;
private Wave wave;
private int waveNo;
public NewWaveEvent(Arena arena, Wave wave, int waveNo) {
this.arena = arena;
this.wave = wave;
this.waveNo = waveNo;
}
public Wave getWave() {
return wave;
}
public int getWaveNumber() {
return waveNo;
}
public Arena getArena() {
return arena;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}
@@ -0,0 +1,248 @@
package com.garbagemule.MobArena.framework;
import java.util.*;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import com.garbagemule.MobArena.ArenaClass;
import com.garbagemule.MobArena.ArenaListener;
import com.garbagemule.MobArena.ArenaPlayer;
import com.garbagemule.MobArena.ClassLimitManager;
import com.garbagemule.MobArena.MASpawnThread;
import com.garbagemule.MobArena.MobArena;
import com.garbagemule.MobArena.MonsterManager;
import com.garbagemule.MobArena.RewardManager;
import com.garbagemule.MobArena.ScoreboardManager;
import com.garbagemule.MobArena.leaderboards.Leaderboard;
import com.garbagemule.MobArena.region.ArenaRegion;
import com.garbagemule.MobArena.repairable.Repairable;
import com.garbagemule.MobArena.util.inventory.InventoryManager;
import com.garbagemule.MobArena.util.timer.AutoStartTimer;
import com.garbagemule.MobArena.waves.WaveManager;
public interface Arena
{
/*/////////////////////////////////////////////////////////////////////////
//
// NEW METHODS IN REFACTORING
//
/////////////////////////////////////////////////////////////////////////*/
public ConfigurationSection getSettings();
public World getWorld();
public void setWorld(World world);
public boolean isEnabled();
public void setEnabled(boolean value);
public boolean isProtected();
public void setProtected(boolean value);
public boolean isRunning();
public boolean inEditMode();
public void setEditMode(boolean value);
public int getMinPlayers();
public int getMaxPlayers();
public List<ItemStack> getEntryFee();
public Set<Map.Entry<Integer,List<ItemStack>>> getEveryWaveEntrySet();
public List<ItemStack> getAfterWaveReward(int wave);
public Set<Player> getPlayersInArena();
public Set<Player> getPlayersInLobby();
public Set<Player> getReadyPlayersInLobby();
public Set<Player> getSpectators();
public MASpawnThread getSpawnThread();
public WaveManager getWaveManager();
public Location getPlayerEntry(Player p);
public ArenaListener getEventListener();
public void setLeaderboard(Leaderboard leaderboard);
public ArenaPlayer getArenaPlayer(Player p);
public Set<Block> getBlocks();
public void addBlock(Block b);
public boolean removeBlock(Block b);
public boolean hasPet(Entity e);
public void addRepairable(Repairable r);
public ArenaRegion getRegion();
public InventoryManager getInventoryManager();
public RewardManager getRewardManager();
public MonsterManager getMonsterManager();
public ClassLimitManager getClassLimitManager();
public void revivePlayer(Player p);
public ScoreboardManager getScoreboard();
public void scheduleTask(Runnable r, int delay);
public boolean startArena();
public boolean endArena();
public void forceStart();
public void forceEnd();
public boolean playerJoin(Player p, Location loc);
public void playerReady(Player p);
public boolean playerLeave(Player p);
public void playerDeath(Player p);
public void playerRespawn(Player p);
public Location getRespawnLocation(Player p);
public void playerSpec(Player p, Location loc);
public void storePlayerData(Player p, Location loc);
public void storeContainerContents();
public void restoreContainerContents();
public void movePlayerToLobby(Player p);
public void movePlayerToSpec(Player p);
public void movePlayerToEntry(Player p);
public void discardPlayer(Player p);
public void repairBlocks();
public void queueRepairable(Repairable r);
/*////////////////////////////////////////////////////////////////////
//
// Items & Cleanup
//
////////////////////////////////////////////////////////////////////*/
public void assignClass(Player p, String className);
public void assignClassGiveInv(Player p, String className, ItemStack[] contents);
public void addRandomPlayer(Player p);
public void assignRandomClass(Player p);
public void assignClassPermissions(Player p);
public void removeClassPermissions(Player p);
public void addPermission(Player p, String perm, boolean value);
/*////////////////////////////////////////////////////////////////////
//
// Initialization & Checks
//
////////////////////////////////////////////////////////////////////*/
public void restoreRegion();
/*////////////////////////////////////////////////////////////////////
//
// Getters & Misc
//
////////////////////////////////////////////////////////////////////*/
public boolean inArena(Player p);
public boolean inLobby(Player p);
public boolean inSpec(Player p);
public boolean isDead(Player p);
public String configName();
public String arenaName();
public MobArena getPlugin();
public Map<String,ArenaClass> getClasses();
public int getPlayerCount();
public List<Player> getAllPlayers();
public Collection<ArenaPlayer> getArenaPlayerSet();
public List<Player> getNonreadyPlayers();
public boolean canAfford(Player p);
public boolean takeFee(Player p);
public boolean refund(Player p);
public boolean canJoin(Player p);
public boolean canSpec(Player p);
public boolean hasIsolatedChat();
public Player getLastPlayerStanding();
public AutoStartTimer getAutoStartTimer();
}
@@ -0,0 +1,143 @@
package com.garbagemule.MobArena.framework;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.PlayerInventory;
import com.garbagemule.MobArena.ArenaClass;
import com.garbagemule.MobArena.MobArena;
import com.garbagemule.MobArena.framework.Arena;
public interface ArenaMaster
{
/*/////////////////////////////////////////////////////////////////////////
//
// NEW METHODS IN REFACTORING
//
/////////////////////////////////////////////////////////////////////////*/
public MobArena getPlugin();
public boolean isEnabled();
public void setEnabled(boolean value);
public boolean notifyOnUpdates();
public List<Arena> getArenas();
public Map<String,ArenaClass> getClasses();
public void addPlayer(Player p, Arena arena);
public Arena removePlayer(Player p);
public void resetArenaMap();
/*/////////////////////////////////////////////////////////////////////////
//
// Getters
//
/////////////////////////////////////////////////////////////////////////*/
public List<Arena> getEnabledArenas();
public List<Arena> getEnabledArenas(List<Arena> arenas);
public List<Arena> getPermittedArenas(Player p);
public List<Arena> getEnabledAndPermittedArenas(Player p);
public Arena getArenaAtLocation(Location loc);
public List<Arena> getArenasInWorld(World world);
public List<Player> getAllPlayers();
public List<Player> getAllPlayersInArena(String arenaName);
public List<Player> getAllLivingPlayers();
public List<Player> getLivingPlayersInArena(String arenaName);
public Arena getArenaWithPlayer(Player p);
public Arena getArenaWithPlayer(String playerName);
public Arena getArenaWithSpectator(Player p);
public Arena getArenaWithMonster(Entity e);
public Arena getArenaWithPet(Entity e);
public Arena getArenaWithName(String configName);
public Arena getArenaWithName(Collection<Arena> arenas, String configName);
public boolean isAllowed(String command);
/*/////////////////////////////////////////////////////////////////////////
//
// Initialization
//
/////////////////////////////////////////////////////////////////////////*/
public void initialize();
/**
* Load the global settings.
*/
public void loadSettings();
/**
* Load all class-related stuff.
*/
public void loadClasses();
public ArenaClass createClassNode(String className, PlayerInventory inv, boolean safe);
public void removeClassNode(String className);
public boolean addClassPermission(String className, String perm);
public boolean removeClassPermission(String className, String perm);
/**
* Load all arena-related stuff.
*/
public void loadArenas();
public void loadArenasInWorld(String worldName);
public void unloadArenasInWorld(String worldName);
public boolean reloadArena(String name);
public Arena createArenaNode(String configName, World world);
public void removeArenaNode(Arena arena);
/*/////////////////////////////////////////////////////////////////////////
//
// Update and serialization methods
//
/////////////////////////////////////////////////////////////////////////*/
public void reloadConfig();
public void saveConfig();
}
@@ -0,0 +1,57 @@
package com.garbagemule.MobArena.leaderboards;
import java.util.List;
import org.bukkit.block.Sign;
import com.garbagemule.MobArena.ArenaPlayerStatistics;
public abstract class AbstractLeaderboardColumn implements LeaderboardColumn
{
protected String statname;
private Sign header;
private List<Sign> signs;
public AbstractLeaderboardColumn(String statname, Sign header, List<Sign> signs) {
this.statname = statname;
this.header = header;
this.signs = signs;
}
public void update(List<ArenaPlayerStatistics> stats) {
// Make sure the stats will fit on the signs.
int range = Math.min(stats.size(), signs.size()*4);
for (int i = 0; i < range; i++) {
// Grab the right sign.
Sign s = signs.get(i/4);
// Call the template method.
String value = getLine(stats.get(i));
// And set the line
s.setLine(i % 4, value);
s.update();
}
}
public abstract String getLine(ArenaPlayerStatistics stats);
public void clear() {
for (Sign s : signs) {
s.setLine(0, "");
s.setLine(1, "");
s.setLine(2, "");
s.setLine(3, "");
s.update();
}
}
public Sign getHeader() {
return header;
}
public List<Sign> getSigns() {
return signs;
}
}
@@ -0,0 +1,19 @@
package com.garbagemule.MobArena.leaderboards;
import java.util.List;
import org.bukkit.block.Sign;
import com.garbagemule.MobArena.ArenaPlayerStatistics;
public class ClassLeaderboardColumn extends AbstractLeaderboardColumn
{
public ClassLeaderboardColumn(String statname, Sign header, List<Sign> signs) {
super(statname, header, signs);
}
@Override
public String getLine(ArenaPlayerStatistics stats) {
return stats.getClassName();
}
}
@@ -0,0 +1,19 @@
package com.garbagemule.MobArena.leaderboards;
import java.util.List;
import org.bukkit.block.Sign;
import com.garbagemule.MobArena.ArenaPlayerStatistics;
public class IntLeaderboardColumn extends AbstractLeaderboardColumn
{
public IntLeaderboardColumn(String statname, Sign header, List<Sign> signs) {
super(statname, header, signs);
}
@Override
public String getLine(ArenaPlayerStatistics stats) {
return "" + stats.getInt(statname);
}
}
@@ -0,0 +1,259 @@
package com.garbagemule.MobArena.leaderboards;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.Sign;
import com.garbagemule.MobArena.ArenaPlayer;
import com.garbagemule.MobArena.ArenaPlayerStatistics;
import com.garbagemule.MobArena.Messenger;
import com.garbagemule.MobArena.MobArena;
import com.garbagemule.MobArena.framework.Arena;
public class Leaderboard
{
private MobArena plugin;
private Arena arena;
private Location topLeft;
private Sign topLeftSign;
private BlockFace direction;
private int rows, cols, trackingId;
private List<LeaderboardColumn> boards;
private List<ArenaPlayerStatistics> stats;
private boolean isValid;
/**
* Private constructor.
* Creates a new leaderboard with no signs or locations or anything.
* @param plugin MobArena instance.
* @param arena The arena to which this leaderboard belongs.
*/
private Leaderboard(MobArena plugin, Arena arena)
{
this.plugin = plugin;
this.arena = arena;
this.boards = new ArrayList<LeaderboardColumn>();
this.stats = new ArrayList<ArenaPlayerStatistics>();
}
/**
* Location constructor.
* Used to create a leaderboard on-the-fly from the location from the SignChangeEvent.
* @param plugin MobArena instance.
* @param arena The arena to which this leaderboard belongs.
* @param topLeft The location at which the main leaderboard sign exists.
*/
public Leaderboard(MobArena plugin, Arena arena, Location topLeft)
{
this(plugin, arena);
if (topLeft == null) {
return;
}
if (!(topLeft.getBlock().getState() instanceof Sign)) {
Messenger.warning("The leaderboard-node for arena '" + arena.configName() + "' does not point to a sign!");
return;
}
this.topLeft = topLeft;
}
/**
* Grab all adjacent signs and register the individual columns.
*/
public void initialize()
{
if (!isGridWellFormed()) {
return;
}
initializeBoards();
initializeStats();
clear();
}
public void clear()
{
for (LeaderboardColumn column : boards)
column.clear();
}
public void update()
{
Collections.sort(stats, ArenaPlayerStatistics.waveComparator());
for (LeaderboardColumn column : boards)
column.update(stats);
}
public void startTracking()
{
trackingId = plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin,
new Runnable()
{
public void run()
{
update();
}
}, 100, 100);
}
public void stopTracking()
{
plugin.getServer().getScheduler().cancelTask(trackingId);
}
/**
* Check if the leaderboards grid is well-formed.
* @return true, if the grid is well-formed, false otherwise.
*/
private boolean isGridWellFormed()
{
if (topLeft == null) {
return false;
}
BlockState state = topLeft.getBlock().getState();
if (!(state instanceof Sign))
{
Messenger.severe("Leaderboards for '" + arena.configName() + "' could not be established!");
return false;
}
// Grab the top left sign and set up a copy for parsing.
this.topLeftSign = (Sign) state;
Sign current = this.topLeftSign;
// Calculate matrix dimensions.
this.direction = getRightDirection(current);
this.rows = getSignCount(current, BlockFace.DOWN);
this.cols = getSignCount(current, direction);
// Require at least 2x2 to be valid
if (rows <= 1 || cols <= 1) {
return false;
}
// Get the left-most sign in the current row.
Sign first = getAdjacentSign(current, BlockFace.DOWN);
for (int i = 1; i < rows; i++)
{
// Back to the first sign of the row.
current = first;
for (int j = 1; j < cols; j++)
{
// Grab the sign to the right, if not a sign, grid is ill-formed.
current = getAdjacentSign(current, direction);
if (current == null) return false;
}
// Hop down to the next row.
first = getAdjacentSign(first, BlockFace.DOWN);
}
return true;
}
/**
* Build the leaderboards.
* Requires: The grid MUST be valid!
*/
private void initializeBoards()
{
boards.clear();
Sign header = this.topLeftSign;
Sign current;
do
{
// Strip the sign of any colors.
String name = ChatColor.stripColor(header.getLine(2));
// Grab the stat to track.
Stats stat = Stats.getByFullName(name);
if (stat == null) continue;
// Create the list of signs
List<Sign> signs = new ArrayList<Sign>();
current = header;
for (int i = 1; i < rows; i++)
{
current = getAdjacentSign(current, BlockFace.DOWN);
signs.add(current);
}
// Create the column.
LeaderboardColumn column = null;
// Switch on the type of stat
switch (stat) {
case PLAYER_NAME:
column = new PlayerLeaderboardColumn(stat.getShortName(), header, signs);
break;
case CLASS_NAME:
column = new ClassLeaderboardColumn(stat.getShortName(), header, signs);
break;
default:
column = new IntLeaderboardColumn(stat.getShortName(), header, signs);
break;
}
this.boards.add(column);
}
while ((header = getAdjacentSign(header, direction)) != null);
}
private void initializeStats()
{
stats.clear();
for (ArenaPlayer ap : arena.getArenaPlayerSet())
stats.add(ap.getStats());
}
private int getSignCount(Sign s, BlockFace direction)
{
int i = 1;
BlockState state = s.getBlock().getState();
while ((state = state.getBlock().getRelative(direction).getState()) instanceof Sign)
i++;
return i;
}
private Sign getAdjacentSign(Sign s, BlockFace direction)
{
BlockState state = s.getBlock().getRelative(direction).getState();
if (state instanceof Sign)
return (Sign) state;
return null;
}
private BlockFace getRightDirection(Sign s)
{
byte data = s.getRawData();
if (data == 2) return BlockFace.WEST;//BlockFace.NORTH;
if (data == 3) return BlockFace.EAST;//BlockFace.SOUTH;
if (data == 4) return BlockFace.SOUTH;//BlockFace.WEST;
if (data == 5) return BlockFace.NORTH;//BlockFace.EAST;
return null;
}
public boolean isValid()
{
return isValid;
}
}
@@ -0,0 +1,43 @@
package com.garbagemule.MobArena.leaderboards;
import java.util.List;
import org.bukkit.block.Sign;
import com.garbagemule.MobArena.ArenaPlayerStatistics;
public interface LeaderboardColumn
{
/**
* Update all the signs in this column to the current values
* of the player stat associated with this column.
*/
public void update(List<ArenaPlayerStatistics> stats);
/**
* Get the String representation of the stat in question.
* The line is calculated by simply calling the appropriate
* getter on the ArenaPlayerStatistics object.
* @param stats an ArenaPlayerStatistics object
* @return the String representation of the stat in question
*/
public String getLine(ArenaPlayerStatistics stats);
/**
* Clear the text on all the signs in the column.
*/
public void clear();
/**
* Get the top sign of the column.
* The top sign displays the stat name.
* @return the top sign of the column
*/
public Sign getHeader();
/**
* Get all signs in the column (minus the header).
* @return all signs in the column (minus the header)
*/
public List<Sign> getSigns();
}
@@ -0,0 +1,19 @@
package com.garbagemule.MobArena.leaderboards;
import java.util.List;
import org.bukkit.block.Sign;
import com.garbagemule.MobArena.ArenaPlayerStatistics;
public class PlayerLeaderboardColumn extends AbstractLeaderboardColumn
{
public PlayerLeaderboardColumn(String statname, Sign header, List<Sign> signs) {
super(statname, header, signs);
}
@Override
public String getLine(ArenaPlayerStatistics stats) {
return stats.getPlayerName();
}
}
@@ -0,0 +1,44 @@
package com.garbagemule.MobArena.leaderboards;
public enum Stats
{
PLAYER_NAME("Players", "playerName"),
CLASS_NAME("Class", "class"),
KILLS("Kills", "kills"),
DAMAGE_DONE("Damage Done", "dmgDone"),
DAMAGE_TAKEN("Damage Taken", "dmgTaken"),
SWINGS("Swings", "swings"),
HITS("Hits", "hits"),
LAST_WAVE("Last Wave", "lastWave");
private String name, shortName;
private Stats(String name, String shortName) {
this.name = name;
this.shortName = shortName;
}
public String getShortName() {
return shortName;
}
public String getFullName() {
return name;
}
public static Stats getByFullName(String name) {
for (Stats s : Stats.values())
if (s.name.equals(name))
return s;
return null;
}
public static Stats getByShortName(String name) {
for (Stats s : Stats.values()) {
if (s.shortName.equalsIgnoreCase(name)) {
return s;
}
}
return null;
}
}
@@ -0,0 +1,346 @@
package com.garbagemule.MobArena.listeners;
import org.bukkit.ChatColor;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.*;
import org.bukkit.event.entity.*;
import org.bukkit.event.hanging.HangingBreakEvent;
import org.bukkit.event.player.*;
import org.bukkit.event.vehicle.VehicleExitEvent;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.event.world.WorldUnloadEvent;
import com.garbagemule.MobArena.Messenger;
import com.garbagemule.MobArena.MobArena;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.framework.ArenaMaster;
import com.garbagemule.MobArena.leaderboards.Stats;
import com.garbagemule.MobArena.util.VersionChecker;
import com.garbagemule.MobArena.util.inventory.InventoryManager;
/**
* The point of this class is to simply redirect all events to each arena's
* own listener(s).
* This means only one actual listener need be registered in Bukkit, and thus
* less overhead. Of course, this requires a little bit of "hackery" here
* and there.
*/
public class MAGlobalListener implements Listener
{
private MobArena plugin;
private ArenaMaster am;
public MAGlobalListener(MobArena plugin, ArenaMaster am) {
this.plugin = plugin;
this.am = am;
}
///////////////////////////////////////////////////////////////////////////
// //
// BLOCK EVENTS //
// //
///////////////////////////////////////////////////////////////////////////
//TODO watch block physics, piston extend, and piston retract events
@EventHandler(priority = EventPriority.HIGHEST)
public void blockBreak(BlockBreakEvent event) {
for (Arena arena : am.getArenas())
arena.getEventListener().onBlockBreak(event);
}
@EventHandler
public void hangingBreak(HangingBreakEvent event) {
for (Arena arena : am.getArenas())
arena.getEventListener().onHangingBreak(event);
}
@EventHandler(priority = EventPriority.HIGHEST)
public void blockBurn(BlockBurnEvent event) {
for (Arena arena : am.getArenas())
arena.getEventListener().onBlockBurn(event);
}
@EventHandler(priority = EventPriority.NORMAL)
public void blockForm(BlockFormEvent event) {
for (Arena arena : am.getArenas())
arena.getEventListener().onBlockForm(event);
}
// // TODO: See ArenaListener.onBlockFromTo()
// @EventHandler(priority = EventPriority.NORMAL)
// public void blockFromTo(BlockFromToEvent event) {
// for (Arena arena : am.getArenas())
// arena.getEventListener().onBlockFromTo(event);
// }
@EventHandler(priority = EventPriority.HIGH)
public void blockIgnite(BlockIgniteEvent event) {
for (Arena arena : am.getArenas())
arena.getEventListener().onBlockIgnite(event);
}
@EventHandler(priority = EventPriority.HIGHEST)
public void blockPlace(BlockPlaceEvent event) {
for (Arena arena : am.getArenas())
arena.getEventListener().onBlockPlace(event);
}
@EventHandler(priority = EventPriority.NORMAL)
public void signChange(SignChangeEvent event) {
if (!event.getPlayer().hasPermission("mobarena.setup.leaderboards")) {
return;
}
if (!event.getLine(0).startsWith("[MA]")) {
return;
}
String text = event.getLine(0).substring((4));
Arena arena;
Stats stat;
if ((arena = am.getArenaWithName(text)) != null) {
arena.getEventListener().onSignChange(event);
setSignLines(event, ChatColor.GREEN + "MobArena", ChatColor.YELLOW + arena.arenaName(), ChatColor.AQUA + "Players", "---------------");
}
else if ((stat = Stats.getByShortName(text)) != null) {
setSignLines(event, ChatColor.GREEN + "", "", ChatColor.AQUA + stat.getFullName(), "---------------");
Messenger.tell(event.getPlayer(), "Stat sign created.");
}
}
private void setSignLines(SignChangeEvent event, String s1, String s2, String s3, String s4) {
event.setLine(0, s1);
event.setLine(1, s2);
event.setLine(2, s3);
event.setLine(3, s4);
}
///////////////////////////////////////////////////////////////////////////
// //
// ENTITY EVENTS //
// //
///////////////////////////////////////////////////////////////////////////
@EventHandler(priority = EventPriority.HIGHEST)
public void creatureSpawn(CreatureSpawnEvent event) {
for (Arena arena : am.getArenas())
arena.getEventListener().onCreatureSpawn(event);
}
@EventHandler(priority = EventPriority.NORMAL)
public void onEntityChangeBlock(EntityChangeBlockEvent event) {
for (Arena arena : am.getArenas())
arena.getEventListener().onEntityChangeBlock(event);
}
@EventHandler(priority = EventPriority.NORMAL)
public void entityCombust(EntityCombustEvent event) {
for (Arena arena : am.getArenas())
arena.getEventListener().onEntityCombust(event);
}
@EventHandler(priority = EventPriority.LOW)
public void entityDamage(EntityDamageEvent event) {
for (Arena arena : am.getArenas())
arena.getEventListener().onEntityDamage(event);
}
@EventHandler(priority = EventPriority.LOWEST)
public void entityDeath(EntityDeathEvent event) {
for (Arena arena : am.getArenas())
arena.getEventListener().onEntityDeath(event);
}
@EventHandler(priority = EventPriority.HIGHEST)
public void entityExplode(EntityExplodeEvent event) {
for (Arena arena : am.getArenas())
arena.getEventListener().onEntityExplode(event);
}
@EventHandler(priority = EventPriority.NORMAL)
public void entityRegainHealth(EntityRegainHealthEvent event) {
for (Arena arena : am.getArenas())
arena.getEventListener().onEntityRegainHealth(event);
}
@EventHandler(priority = EventPriority.NORMAL)
public void entityFoodLevelChange(FoodLevelChangeEvent event) {
for (Arena arena : am.getArenas())
arena.getEventListener().onFoodLevelChange(event);
}
@EventHandler(priority = EventPriority.NORMAL)
public void entityTarget(EntityTargetEvent event) {
for (Arena arena : am.getArenas())
arena.getEventListener().onEntityTarget(event);
}
@EventHandler(priority = EventPriority.HIGH)
public void entityTeleport(EntityTeleportEvent event) {
for (Arena arena : am.getArenas()) {
arena.getEventListener().onEntityTeleport(event);
}
}
@EventHandler(priority = EventPriority.NORMAL)
public void potionSplash(PotionSplashEvent event) {
for (Arena arena : am.getArenas()) {
arena.getEventListener().onPotionSplash(event);
}
}
///////////////////////////////////////////////////////////////////////////
// //
// PLAYER EVENTS //
// //
///////////////////////////////////////////////////////////////////////////
@EventHandler(priority = EventPriority.NORMAL)
public void playerAnimation(PlayerAnimationEvent event) {
if (!am.isEnabled()) return;
for (Arena arena : am.getArenas())
arena.getEventListener().onPlayerAnimation(event);
}
@EventHandler(priority = EventPriority.NORMAL)
public void playerBucketEmpty(PlayerBucketEmptyEvent event) {
if (!am.isEnabled()) return;
for (Arena arena : am.getArenas())
arena.getEventListener().onPlayerBucketEmpty(event);
}
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void playerChat(AsyncPlayerChatEvent event) {
if (!am.isEnabled()) return;
Arena arena = am.getArenaWithPlayer(event.getPlayer());
if (arena == null || !arena.hasIsolatedChat()) return;
event.getRecipients().retainAll(arena.getAllPlayers());
}
@EventHandler(priority = EventPriority.LOWEST)
public void playerCommandPreprocess(PlayerCommandPreprocessEvent event) {
if (!am.isEnabled()) return;
for (Arena arena : am.getArenas())
arena.getEventListener().onPlayerCommandPreprocess(event);
}
@EventHandler(priority = EventPriority.NORMAL)
public void playerDropItem(PlayerDropItemEvent event) {
if (!am.isEnabled()) return;
for (Arena arena : am.getArenas())
arena.getEventListener().onPlayerDropItem(event);
}
// HIGHEST => after SignShop
@EventHandler(priority = EventPriority.HIGHEST)
public void playerInteract(PlayerInteractEvent event) {
if (!am.isEnabled()) return;
for (Arena arena : am.getArenas())
arena.getEventListener().onPlayerInteract(event);
}
@EventHandler(priority = EventPriority.NORMAL)
public void playerJoin(PlayerJoinEvent event) {
InventoryManager.restoreFromFile(plugin, event.getPlayer());
if (!am.notifyOnUpdates() || !event.getPlayer().isOp()) return;
VersionChecker.checkForUpdates(plugin, event.getPlayer());
}
@EventHandler(priority = EventPriority.NORMAL)
public void playerKick(PlayerKickEvent event) {
for (Arena arena : am.getArenas())
arena.getEventListener().onPlayerKick(event);
}
@EventHandler(priority = EventPriority.NORMAL)
public void playerQuit(PlayerQuitEvent event) {
for (Arena arena : am.getArenas())
arena.getEventListener().onPlayerQuit(event);
}
@EventHandler(priority = EventPriority.NORMAL)
public void playerRespawn(PlayerRespawnEvent event) {
for (Arena arena : am.getArenas()) {
if (arena.getEventListener().onPlayerRespawn(event)) {
return;
}
}
plugin.restoreInventory(event.getPlayer());
}
public enum TeleportResponse {
ALLOW, REJECT, IDGAF
}
@EventHandler(priority = EventPriority.NORMAL)
public void playerTeleport(PlayerTeleportEvent event) {
if (!am.isEnabled()) return;
boolean allow = true;
for (Arena arena : am.getArenas()) {
TeleportResponse r = arena.getEventListener().onPlayerTeleport(event);
// If just one arena allows, uncancel and stop.
switch (r) {
case ALLOW:
event.setCancelled(false);
return;
case REJECT:
allow = false;
break;
default: break;
}
}
// Only cancel if at least one arena has rejected the teleport.
if (!allow) {
event.setCancelled(true);
}
}
@EventHandler(priority = EventPriority.NORMAL)
public void playerPreLogin(PlayerLoginEvent event) {
for (Arena arena : am.getArenas()) {
arena.getEventListener().onPlayerPreLogin(event);
}
}
@EventHandler(priority = EventPriority.NORMAL)
public void vehicleExit(VehicleExitEvent event) {
for (Arena arena : am.getArenas()) {
arena.getEventListener().onVehicleExit(event);
}
}
///////////////////////////////////////////////////////////////////////////
// //
// WORLD EVENTS //
// //
///////////////////////////////////////////////////////////////////////////
@EventHandler(priority = EventPriority.NORMAL)
public void worldLoadEvent(WorldLoadEvent event) {
am.loadArenasInWorld(event.getWorld().getName());
}
@EventHandler(priority = EventPriority.NORMAL)
public void worldUnloadEvent(WorldUnloadEvent event) {
am.unloadArenasInWorld(event.getWorld().getName());
}
}
@@ -0,0 +1,66 @@
package com.garbagemule.MobArena.listeners;
import java.io.File;
import java.util.List;
import com.garbagemule.MobArena.Messenger;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.waves.enums.*;
import com.garbagemule.MobArena.MobArena;
import com.nisovin.magicspells.events.SpellCastEvent;
public class MagicSpellsListener implements Listener
{
private MobArena plugin;
private List<String> disabled, disabledOnBoss, disabledOnSwarm;
public MagicSpellsListener(MobArena plugin)
{
this.plugin = plugin;
// Set up the MagicSpells config-file.
File file = new File(plugin.getDataFolder(), "magicspells.yml");
if (!file.exists()) {
plugin.saveResource("magicspells.yml", false);
Messenger.info("magicspells.yml created.");
}
try {
FileConfiguration config = new YamlConfiguration();
config.load(file);
setupSpells(config);
} catch (Exception e) {
e.printStackTrace();
}
}
@EventHandler(priority = EventPriority.NORMAL)
public void onSpellCast(SpellCastEvent event)
{
Arena arena = plugin.getArenaMaster().getArenaWithPlayer(event.getCaster());
if (arena == null || !arena.isRunning()) return;
String spell = event.getSpell().getName();
WaveType type = (arena.getWaveManager().getCurrent() != null) ? arena.getWaveManager().getCurrent().getType() : null;
if (disabled.contains(spell) ||
(type == WaveType.BOSS && disabledOnBoss.contains(spell)) ||
(type == WaveType.SWARM && disabledOnSwarm.contains(spell))) {
event.setCancelled(true);
}
}
private void setupSpells(ConfigurationSection config)
{
this.disabled = config.getStringList("disabled-spells");
this.disabledOnBoss = config.getStringList("disabled-on-bosses");
this.disabledOnSwarm = config.getStringList("disabled-on-swarms");
}
}
@@ -0,0 +1,651 @@
/*
* Copyright 2011-2013 Tyler Blair. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and contributors and should not be interpreted as representing official policies,
* either expressed or implied, of anybody else.
*/
package com.garbagemule.MobArena.metrics;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.scheduler.BukkitTask;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
/**
* <p> The metrics class obtains data about a plugin and submits statistics about it to the metrics backend. </p> <p>
* Public methods provided by this class: </p>
* <code>
* Graph createGraph(String name); <br/>
* void addCustomData(BukkitMetrics.Plotter plotter); <br/>
* void start(); <br/>
* </code>
*/
public class Metrics {
/**
* The current revision number
*/
private final static int REVISION = 6;
/**
* The base url of the metrics domain
*/
private static final String BASE_URL = "http://mcstats.org";
/**
* The url used to report a server's status
*/
private static final String REPORT_URL = "/report/%s";
/**
* The separator to use for custom data. This MUST NOT change unless you are hosting your own version of metrics and
* want to change it.
*/
private static final String CUSTOM_DATA_SEPARATOR = "~~";
/**
* Interval of time to ping (in minutes)
*/
private static final int PING_INTERVAL = 10;
/**
* The plugin this metrics submits for
*/
private final Plugin plugin;
/**
* All of the custom graphs to submit to metrics
*/
private final Set<Graph> graphs = Collections.synchronizedSet(new HashSet<Graph>());
/**
* The default graph, used for addCustomData when you don't want a specific graph
*/
private final Graph defaultGraph = new Graph("Default");
/**
* The plugin configuration file
*/
private final YamlConfiguration configuration;
/**
* The plugin configuration file
*/
private final File configurationFile;
/**
* Unique server id
*/
private final String guid;
/**
* Debug mode
*/
private final boolean debug;
/**
* Lock for synchronization
*/
private final Object optOutLock = new Object();
/**
* The scheduled task
*/
private volatile BukkitTask task = null;
public Metrics(final Plugin plugin) throws IOException {
if (plugin == null) {
throw new IllegalArgumentException("Plugin cannot be null");
}
this.plugin = plugin;
// load the config
configurationFile = getConfigFile();
configuration = YamlConfiguration.loadConfiguration(configurationFile);
// add some defaults
configuration.addDefault("opt-out", false);
configuration.addDefault("guid", UUID.randomUUID().toString());
configuration.addDefault("debug", false);
// Do we need to create the file?
if (configuration.get("guid", null) == null) {
configuration.options().header("http://mcstats.org").copyDefaults(true);
configuration.save(configurationFile);
}
// Load the guid then
guid = configuration.getString("guid");
debug = configuration.getBoolean("debug", false);
}
/**
* Construct and create a Graph that can be used to separate specific plotters to their own graphs on the metrics
* website. Plotters can be added to the graph object returned.
*
* @param name The name of the graph
* @return Graph object created. Will never return NULL under normal circumstances unless bad parameters are given
*/
public Graph createGraph(final String name) {
if (name == null) {
throw new IllegalArgumentException("Graph name cannot be null");
}
// Construct the graph object
final Graph graph = new Graph(name);
// Now we can add our graph
graphs.add(graph);
// and return back
return graph;
}
/**
* Add a Graph object to BukkitMetrics that represents data for the plugin that should be sent to the backend
*
* @param graph The name of the graph
*/
public void addGraph(final Graph graph) {
if (graph == null) {
throw new IllegalArgumentException("Graph cannot be null");
}
graphs.add(graph);
}
/**
* Adds a custom data plotter to the default graph
*
* @param plotter The plotter to use to plot custom data
*/
public void addCustomData(final Plotter plotter) {
if (plotter == null) {
throw new IllegalArgumentException("Plotter cannot be null");
}
// Add the plotter to the graph o/
defaultGraph.addPlotter(plotter);
// Ensure the default graph is included in the submitted graphs
graphs.add(defaultGraph);
}
/**
* Start measuring statistics. This will immediately create an async repeating task as the plugin and send the
* initial data to the metrics backend, and then after that it will post in increments of PING_INTERVAL * 1200
* ticks.
*
* @return True if statistics measuring is running, otherwise false.
*/
public boolean start() {
synchronized (optOutLock) {
// Did we opt out?
if (isOptOut()) {
return false;
}
// Is metrics already running?
if (task != null) {
return true;
}
// Begin hitting the server with glorious data
task = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, new Runnable() {
private boolean firstPost = true;
public void run() {
try {
// This has to be synchronized or it can collide with the disable method.
synchronized (optOutLock) {
// Disable Task, if it is running and the server owner decided to opt-out
if (isOptOut() && task != null) {
task.cancel();
task = null;
// Tell all plotters to stop gathering information.
for (Graph graph : graphs) {
graph.onOptOut();
}
}
}
// We use the inverse of firstPost because if it is the first time we are posting,
// it is not a interval ping, so it evaluates to FALSE
// Each time thereafter it will evaluate to TRUE, i.e PING!
postPlugin(!firstPost);
// After the first post we set firstPost to false
// Each post thereafter will be a ping
firstPost = false;
} catch (IOException e) {
if (debug) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage());
}
}
}
}, 0, PING_INTERVAL * 1200);
return true;
}
}
/**
* Has the server owner denied plugin metrics?
*
* @return true if metrics should be opted out of it
*/
public boolean isOptOut() {
synchronized (optOutLock) {
try {
// Reload the metrics file
configuration.load(getConfigFile());
} catch (IOException ex) {
if (debug) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
}
return true;
} catch (InvalidConfigurationException ex) {
if (debug) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
}
return true;
}
return configuration.getBoolean("opt-out", false);
}
}
/**
* Enables metrics for the server by setting "opt-out" to false in the config file and starting the metrics task.
*
* @throws java.io.IOException
*/
public void enable() throws IOException {
// This has to be synchronized or it can collide with the check in the task.
synchronized (optOutLock) {
// Check if the server owner has already set opt-out, if not, set it.
if (isOptOut()) {
configuration.set("opt-out", false);
configuration.save(configurationFile);
}
// Enable Task, if it is not running
if (task == null) {
start();
}
}
}
/**
* Disables metrics for the server by setting "opt-out" to true in the config file and canceling the metrics task.
*
* @throws java.io.IOException
*/
public void disable() throws IOException {
// This has to be synchronized or it can collide with the check in the task.
synchronized (optOutLock) {
// Check if the server owner has already set opt-out, if not, set it.
if (!isOptOut()) {
configuration.set("opt-out", true);
configuration.save(configurationFile);
}
// Disable Task, if it is running
if (task != null) {
task.cancel();
task = null;
}
}
}
/**
* Gets the File object of the config file that should be used to store data such as the GUID and opt-out status
*
* @return the File object for the config file
*/
public File getConfigFile() {
// I believe the easiest way to get the base folder (e.g craftbukkit set via -P) for plugins to use
// is to abuse the plugin object we already have
// plugin.getDataFolder() => base/plugins/PluginA/
// pluginsFolder => base/plugins/
// The base is not necessarily relative to the startup directory.
File pluginsFolder = plugin.getDataFolder().getParentFile();
// return => base/plugins/PluginMetrics/config.yml
return new File(new File(pluginsFolder, "PluginMetrics"), "config.yml");
}
/**
* Generic method that posts a plugin to the metrics website
*/
private void postPlugin(final boolean isPing) throws IOException {
// Server software specific section
PluginDescriptionFile description = plugin.getDescription();
String pluginName = description.getName();
boolean onlineMode = Bukkit.getServer().getOnlineMode(); // TRUE if online mode is enabled
String pluginVersion = description.getVersion();
String serverVersion = Bukkit.getVersion();
int playersOnline = Bukkit.getServer().getOnlinePlayers().size();
// END server software specific section -- all code below does not use any code outside of this class / Java
// Construct the post data
final StringBuilder data = new StringBuilder();
// The plugin's description file containg all of the plugin data such as name, version, author, etc
data.append(encode("guid")).append('=').append(encode(guid));
encodeDataPair(data, "version", pluginVersion);
encodeDataPair(data, "server", serverVersion);
encodeDataPair(data, "players", Integer.toString(playersOnline));
encodeDataPair(data, "revision", String.valueOf(REVISION));
// New data as of R6
String osname = System.getProperty("os.name");
String osarch = System.getProperty("os.arch");
String osversion = System.getProperty("os.version");
String java_version = System.getProperty("java.version");
int coreCount = Runtime.getRuntime().availableProcessors();
// normalize os arch .. amd64 -> x86_64
if (osarch.equals("amd64")) {
osarch = "x86_64";
}
encodeDataPair(data, "osname", osname);
encodeDataPair(data, "osarch", osarch);
encodeDataPair(data, "osversion", osversion);
encodeDataPair(data, "cores", Integer.toString(coreCount));
encodeDataPair(data, "online-mode", Boolean.toString(onlineMode));
encodeDataPair(data, "java_version", java_version);
// If we're pinging, append it
if (isPing) {
encodeDataPair(data, "ping", "true");
}
// Acquire a lock on the graphs, which lets us make the assumption we also lock everything
// inside of the graph (e.g plotters)
synchronized (graphs) {
final Iterator<Graph> iter = graphs.iterator();
while (iter.hasNext()) {
final Graph graph = iter.next();
for (Plotter plotter : graph.getPlotters()) {
// The key name to send to the metrics server
// The format is C-GRAPHNAME-PLOTTERNAME where separator - is defined at the top
// Legacy (R4) submitters use the format Custom%s, or CustomPLOTTERNAME
final String key = String.format("C%s%s%s%s", CUSTOM_DATA_SEPARATOR, graph.getName(), CUSTOM_DATA_SEPARATOR, plotter.getColumnName());
// The value to send, which for the foreseeable future is just the string
// value of plotter.getValue()
final String value = Integer.toString(plotter.getValue());
// Add it to the http post data :)
encodeDataPair(data, key, value);
}
}
}
// Create the url
URL url = new URL(BASE_URL + String.format(REPORT_URL, encode(pluginName)));
// Connect to the website
URLConnection connection;
// Mineshafter creates a socks proxy, so we can safely bypass it
// It does not reroute POST requests so we need to go around it
if (isMineshafterPresent()) {
connection = url.openConnection(Proxy.NO_PROXY);
} else {
connection = url.openConnection();
}
connection.setDoOutput(true);
// Write the data
final OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
writer.write(data.toString());
writer.flush();
// Now read the response
final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
final String response = reader.readLine();
// close resources
writer.close();
reader.close();
if (response == null || response.startsWith("ERR")) {
throw new IOException(response); //Throw the exception
} else {
// Is this the first update this hour?
if (response.contains("OK This is your first update this hour")) {
synchronized (graphs) {
final Iterator<Graph> iter = graphs.iterator();
while (iter.hasNext()) {
final Graph graph = iter.next();
for (Plotter plotter : graph.getPlotters()) {
plotter.reset();
}
}
}
}
}
}
/**
* Check if mineshafter is present. If it is, we need to bypass it to send POST requests
*
* @return true if mineshafter is installed on the server
*/
private boolean isMineshafterPresent() {
try {
Class.forName("mineshafter.MineServer");
return true;
} catch (Exception e) {
return false;
}
}
/**
* <p>Encode a key/value data pair to be used in a HTTP post request. This INCLUDES a & so the first key/value pair
* MUST be included manually, e.g:</p>
* <code>
* StringBuffer data = new StringBuffer();
* data.append(encode("guid")).append('=').append(encode(guid));
* encodeDataPair(data, "version", description.getVersion());
* </code>
*
* @param buffer the stringbuilder to append the data pair onto
* @param key the key value
* @param value the value
*/
private static void encodeDataPair(final StringBuilder buffer, final String key, final String value) throws UnsupportedEncodingException {
buffer.append('&').append(encode(key)).append('=').append(encode(value));
}
/**
* Encode text as UTF-8
*
* @param text the text to encode
* @return the encoded text, as UTF-8
*/
private static String encode(final String text) throws UnsupportedEncodingException {
return URLEncoder.encode(text, "UTF-8");
}
/**
* Represents a custom graph on the website
*/
public static class Graph {
/**
* The graph's name, alphanumeric and spaces only :) If it does not comply to the above when submitted, it is
* rejected
*/
private final String name;
/**
* The set of plotters that are contained within this graph
*/
private final Set<Plotter> plotters = new LinkedHashSet<Plotter>();
private Graph(final String name) {
this.name = name;
}
/**
* Gets the graph's name
*
* @return the Graph's name
*/
public String getName() {
return name;
}
/**
* Add a plotter to the graph, which will be used to plot entries
*
* @param plotter the plotter to add to the graph
*/
public void addPlotter(final Plotter plotter) {
plotters.add(plotter);
}
/**
* Remove a plotter from the graph
*
* @param plotter the plotter to remove from the graph
*/
public void removePlotter(final Plotter plotter) {
plotters.remove(plotter);
}
/**
* Gets an <b>unmodifiable</b> set of the plotter objects in the graph
*
* @return an unmodifiable {@link java.util.Set} of the plotter objects
*/
public Set<Plotter> getPlotters() {
return Collections.unmodifiableSet(plotters);
}
@Override
public int hashCode() {
return name.hashCode();
}
@Override
public boolean equals(final Object object) {
if (!(object instanceof Graph)) {
return false;
}
final Graph graph = (Graph) object;
return graph.name.equals(name);
}
/**
* Called when the server owner decides to opt-out of BukkitMetrics while the server is running.
*/
protected void onOptOut() {
}
}
/**
* Interface used to collect custom data for a plugin
*/
public static abstract class Plotter {
/**
* The plot's name
*/
private final String name;
/**
* Construct a plotter with the default plot name
*/
public Plotter() {
this("Default");
}
/**
* Construct a plotter with a specific plot name
*
* @param name the name of the plotter to use, which will show up on the website
*/
public Plotter(final String name) {
this.name = name;
}
/**
* Get the current value for the plotted point. Since this function defers to an external function it may or may
* not return immediately thus cannot be guaranteed to be thread friendly or safe. This function can be called
* from any thread so care should be taken when accessing resources that need to be synchronized.
*
* @return the current value for the point to be plotted.
*/
public abstract int getValue();
/**
* Get the column name for the plotted point
*
* @return the plotted point's column name
*/
public String getColumnName() {
return name;
}
/**
* Called after the website graphs have been updated
*/
public void reset() {
}
@Override
public int hashCode() {
return getColumnName().hashCode();
}
@Override
public boolean equals(final Object object) {
if (!(object instanceof Plotter)) {
return false;
}
final Plotter plotter = (Plotter) object;
return plotter.name.equals(name) && plotter.getValue() == getValue();
}
}
}
@@ -0,0 +1,725 @@
package com.garbagemule.MobArena.region;
import com.garbagemule.MobArena.MAUtils;
import com.garbagemule.MobArena.Messenger;
import com.garbagemule.MobArena.MobArena;
import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.util.Enums;
import org.bukkit.ChatColor;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import java.util.*;
import static com.garbagemule.MobArena.util.config.ConfigUtils.*;
public class ArenaRegion
{
private Arena arena;
private World world;
private Location lastP1, lastP2, lastL1, lastL2;
private Location p1, p2, l1, l2, arenaWarp, lobbyWarp, specWarp, exitWarp, leaderboard;
private Map<String,Location> spawnpoints, containers;
private boolean setup, lobbySetup;
private ConfigurationSection coords;
private ConfigurationSection spawns;
private ConfigurationSection chests;
public ArenaRegion(ConfigurationSection section, Arena arena) {
this.arena = arena;
refreshWorld();
this.coords = makeSection(section, "coords");
this.spawns = makeSection(coords, "spawnpoints");
this.chests = makeSection(coords, "containers");
reloadAll();
}
public void refreshWorld() {
this.world = arena.getWorld();
}
public void reloadAll() {
reloadRegion();
reloadWarps();
reloadLeaderboards();
reloadSpawnpoints();
reloadChests();
verifyData();
}
public void reloadRegion() {
p1 = parseLocation(coords, "p1", world);
p2 = parseLocation(coords, "p2", world);
//fixRegion();
l1 = parseLocation(coords, "l1", world);
l2 = parseLocation(coords, "l2", world);
//fixLobbyRegion();
}
public void reloadWarps() {
arenaWarp = parseLocation(coords, "arena", world);
lobbyWarp = parseLocation(coords, "lobby", world);
specWarp = parseLocation(coords, "spectator", world);
exitWarp = parseLocation(coords, "exit", null);
}
public void reloadLeaderboards() {
// try-catch for backwards compatibility
try {
leaderboard = parseLocation(coords, "leaderboard", null);
} catch (IllegalArgumentException e) {
leaderboard = parseLocation(coords, "leaderboard", world);
}
if (leaderboard != null && leaderboard.getWorld() == null) {
leaderboard.setWorld(world);
}
}
public void reloadSpawnpoints() {
spawnpoints = new HashMap<String,Location>();
Set<String> keys = spawns.getKeys(false);
if (keys != null) {
for (String spwn : keys) {
spawnpoints.put(spwn, parseLocation(spawns, spwn, world));
}
}
}
public void reloadChests() {
containers = new HashMap<String,Location>();
Set<String> keys = chests.getKeys(false);
if (keys != null) {
for (String chst : keys) {
containers.put(chst, parseLocation(chests, chst, world));
}
}
}
public void verifyData() {
setup = (p1 != null &&
p2 != null &&
arenaWarp != null &&
lobbyWarp != null &&
specWarp != null &&
!spawnpoints.isEmpty());
lobbySetup = (l1 != null &&
l2 != null);
}
public void checkData(MobArena plugin, CommandSender s, boolean ready, boolean region, boolean warps, boolean spawns) {
// Verify data first
verifyData();
// Prepare the list
List<String> list = new ArrayList<String>();
// Region points
if (region) {
if (p1 == null) list.add("p1");
if (p2 == null) list.add("p2");
if (!list.isEmpty()) {
Messenger.tell(s, "Missing region points: " + MAUtils.listToString(list, plugin));
list.clear();
}
}
// Warps
if (warps) {
if (arenaWarp == null) list.add("arena");
if (lobbyWarp == null) list.add("lobby");
if (specWarp == null) list.add("spectator");
if (!list.isEmpty()) {
Messenger.tell(s, "Missing warps: " + MAUtils.listToString(list, plugin));
list.clear();
}
}
// Spawnpoints
if (spawns) {
if (spawnpoints.isEmpty()) {
Messenger.tell(s, "Missing spawnpoints");
}
}
// Ready?
if (ready && setup) {
Messenger.tell(s, "Arena is ready to be used!");
}
}
public boolean isDefined() {
return (p1 != null && p2 != null);
}
public boolean isLobbyDefined() {
return (l1 != null && l2 != null);
}
public boolean isSetup() {
return setup;
}
public boolean isLobbySetup() {
return lobbySetup;
}
public boolean isWarp(Location l) {
return (l.equals(arenaWarp) ||
l.equals(lobbyWarp) ||
l.equals(specWarp) ||
l.equals(exitWarp));
}
public boolean contains(Location l) {
if (!l.getWorld().getName().equals(world.getName()) || !isDefined()) {
return false;
}
int x = l.getBlockX();
int y = l.getBlockY();
int z = l.getBlockZ();
// Check the lobby first.
if (lobbySetup) {
if ((x >= l1.getBlockX() && x <= l2.getBlockX()) &&
(z >= l1.getBlockZ() && z <= l2.getBlockZ()) &&
(y >= l1.getBlockY() && y <= l2.getBlockY()))
return true;
}
// Returns false if the location is outside of the region.
return ((x >= p1.getBlockX() && x <= p2.getBlockX()) &&
(z >= p1.getBlockZ() && z <= p2.getBlockZ()) &&
(y >= p1.getBlockY() && y <= p2.getBlockY()));
}
public boolean contains(Location l, int radius) {
if (!l.getWorld().getName().equals(world.getName()) || !isDefined()) {
return false;
}
int x = l.getBlockX();
int y = l.getBlockY();
int z = l.getBlockZ();
if (lobbySetup) {
if ((x + radius >= l1.getBlockX() && x - radius <= l2.getBlockX()) &&
(z + radius >= l1.getBlockZ() && z - radius <= l2.getBlockZ()) &&
(y + radius >= l1.getBlockY() && y - radius <= l2.getBlockY()))
return true;
}
return ((x + radius >= p1.getBlockX() && x - radius <= p2.getBlockX()) &&
(z + radius >= p1.getBlockZ() && z - radius <= p2.getBlockZ()) &&
(y + radius >= p1.getBlockY() && y - radius <= p2.getBlockY()));
}
// Region expand
public void expandUp(int amount) {
int x = p2.getBlockX();
int y = Math.min(p2.getWorld().getMaxHeight(), p2.getBlockY() + amount);
int z = p2.getBlockZ();
setSaveReload(coords, "p2", p2.getWorld(), x ,y ,z);
}
public void expandDown(int amount) {
int x = p1.getBlockX();
int y = Math.max(0, p1.getBlockY() - amount);
int z = p1.getBlockZ();
setSaveReload(coords, "p1", p1.getWorld(), x ,y ,z);
}
public void expandP1(int dx, int dz) {
int x = p1.getBlockX() - dx;
int y = p1.getBlockY();
int z = p1.getBlockZ() - dz;
setSaveReload(coords, "p1", p1.getWorld(), x ,y ,z);
}
public void expandP2(int dx, int dz) {
int x = p2.getBlockX() + dx;
int y = p2.getBlockY();
int z = p2.getBlockZ() + dz;
setSaveReload(coords, "p2", p2.getWorld(), x ,y ,z);
}
public void expandOut(int amount) {
expandP1(amount, amount);
expandP2(amount, amount);
}
// Lobby expand
public void expandLobbyUp(int amount) {
int x = l2.getBlockX();
int y = Math.min(l2.getWorld().getMaxHeight(), l2.getBlockY() + amount);
int z = l2.getBlockZ();
setSaveReload(coords, "l2", l2.getWorld(), x ,y ,z);
}
public void expandLobbyDown(int amount) {
int x = l1.getBlockX();
int y = Math.max(0, l1.getBlockY() - amount);
int z = l1.getBlockZ();
setSaveReload(coords, "l1", l1.getWorld(), x ,y ,z);
}
public void expandL1(int dx, int dz) {
int x = l1.getBlockX() - dx;
int y = l1.getBlockY();
int z = l1.getBlockZ() - dz;
setSaveReload(coords, "l1", l1.getWorld(), x ,y ,z);
}
public void expandL2(int dx, int dz) {
int x = l2.getBlockX() + dx;
int y = l2.getBlockY();
int z = l2.getBlockZ() + dz;
setSaveReload(coords, "l2", l2.getWorld(), x ,y ,z);
}
public void expandLobbyOut(int amount) {
expandL1(amount, amount);
expandL2(amount, amount);
}
private void setSaveReload(ConfigurationSection section, String key, World w, double x, double y, double z) {
Location loc = new Location(w, x, y, z);
setLocation(section, key, loc);
save();
reloadRegion();
}
public void fixRegion() {
fix("p1", "p2");
}
public void fixLobbyRegion() {
fix("l1", "l2");
}
private void fix(String location1, String location2) {
Location loc1 = parseLocation(coords, location1, world);
Location loc2 = parseLocation(coords, location2, world);
if (loc1 == null || loc2 == null) {
return;
}
boolean modified = false;
if (loc1.getX() > loc2.getX()) {
double tmp = loc1.getX();
loc1.setX(loc2.getX());
loc2.setX(tmp);
modified = true;
}
if (loc1.getZ() > loc2.getZ()) {
double tmp = loc1.getZ();
loc1.setZ(loc2.getZ());
loc2.setZ(tmp);
modified = true;
}
if (loc1.getY() > loc2.getY()) {
double tmp = loc1.getY();
loc1.setY(loc2.getY());
loc2.setY(tmp);
modified = true;
}
if (!arena.getWorld().getName().equals(world.getName())) {
arena.setWorld(world);
modified = true;
}
if (!modified) {
return;
}
setLocation(coords, location1, loc1);
setLocation(coords, location2, loc2);
save();
}
public List<Chunk> getChunks() {
List<Chunk> result = new ArrayList<Chunk>();
if (p1 == null || p2 == null) {
return result;
}
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++) {
result.add(world.getChunkAt(i,j));
}
}
return result;
}
public Location getArenaWarp() {
return arenaWarp;
}
public Location getLobbyWarp() {
return lobbyWarp;
}
public Location getSpecWarp() {
return specWarp;
}
public Location getExitWarp() {
return exitWarp;
}
public Location getSpawnpoint(String name) {
return spawnpoints.get(name);
}
public Collection<Location> getSpawnpoints() {
return spawnpoints.values();
}
public List<Location> getSpawnpointList() {
return new ArrayList<Location>(spawnpoints.values());
}
public Collection<Location> getContainers() {
return containers.values();
}
public Location getLeaderboard() {
return leaderboard;
}
public void set(RegionPoint point, Location loc) {
// Act based on the point
switch (point) {
case P1:
case P2:
case L1:
case L2: setPoint(point, loc); return;
case ARENA:
case LOBBY:
case EXIT:
case SPECTATOR: setWarp(point, loc); return;
case LEADERBOARD: setLeaderboard(loc); return;
}
throw new IllegalArgumentException("Invalid region point!");
}
private void setPoint(RegionPoint point, Location l) {
// Lower and upper locations
RegionPoint r1, r2;
Location lower, upper;
/* Initialize the bounds.
*
* To allow users to set a region point without paying attention to
* the 'fixed' points, we continuously store the previously stored
* location for the given point. These location references are only
* ever overwritten when using the set commands, and remain fully
* decoupled from the 'fixed' points.
*
* Effectively, the config-file and region store 'fixed' locations
* that allow fast membership tests, but the region also stores the
* 'unfixed' locations for a more intuitive setup process.
*/
switch (point) {
case P1:
lastP1 = l.clone();
lower = lastP1.clone();
upper = (lastP2 != null ? lastP2.clone() : p2);
r1 = RegionPoint.P1; r2 = RegionPoint.P2;
break;
case P2:
lastP2 = l.clone();
lower = (lastP1 != null ? lastP1.clone() : p1);
upper = lastP2.clone();
r1 = RegionPoint.P1; r2 = RegionPoint.P2;
break;
case L1:
lastL1 = l.clone();
lower = lastL1.clone();
upper = (lastL2 != null ? lastL2.clone() : l2);
r1 = RegionPoint.L1; r2 = RegionPoint.L2;
break;
case L2:
lastL2 = l.clone();
lower = (lastL1 != null ? lastL1.clone() : l1);
upper = lastL2.clone();
r1 = RegionPoint.L1; r2 = RegionPoint.L2;
break;
default:
lower = upper = null;
r1 = r2 = null;
}
// Min-max if both locations are non-null
if (lower != null && upper != null) {
double tmp;
if (lower.getX() > upper.getX()) {
tmp = lower.getX();
lower.setX(upper.getX());
upper.setX(tmp);
}
if (lower.getY() > upper.getY()) {
tmp = lower.getY();
lower.setY(upper.getY());
upper.setY(tmp);
}
if (lower.getZ() > upper.getZ()) {
tmp = lower.getZ();
lower.setZ(upper.getZ());
upper.setZ(tmp);
}
}
// Set the coords and save
if (lower != null) setLocation(coords, r1.name().toLowerCase(), lower);
if (upper != null) setLocation(coords, r2.name().toLowerCase(), upper);
save();
// Reload regions and verify data
reloadRegion();
verifyData();
}
public void set(String point, Location loc) {
// Get the region point enum
RegionPoint rp = Enums.getEnumFromString(RegionPoint.class, point);
if (rp == null) throw new IllegalArgumentException("Invalid region point '" + point + "'");
// Then delegate
set(rp, loc);
}
public void setWarp(RegionPoint point, Location l) {
// Set the point and save
setLocation(coords, point.toString(), l);
save();
// Then reload warps
reloadWarps();
}
public void setLeaderboard(Location l) {
// Set the point and save
setLocation(coords, "leaderboard", l);
save();
// Then reload the leaderboards
reloadLeaderboards();
}
public void addSpawn(String name, Location loc) {
// Add the spawn and save
setLocation(spawns, name, loc);
save();
// Reload spawnpoints and verify data
reloadSpawnpoints();
verifyData();
}
public boolean removeSpawn(String name) {
// Check if the spawnpoint exists
if (spawns.getString(name) == null) {
return false;
}
// Null the spawnpoint and save
setLocation(spawns, name, null);
save();
// Reload spawnpoints and verify data
reloadSpawnpoints();
verifyData();
return true;
}
public void addChest(String name, Location loc) {
// Add the chest location and save
setLocation(chests, name, loc);
save();
// Reload the chests
reloadChests();
}
public boolean removeChest(String name) {
// Check if the chest exists
if (chests.getString(name) == null) {
return false;
}
// Null the chest and save
setLocation(chests, name, null);
save();
// Reload the chests
reloadChests();
return true;
}
public void save() {
arena.getPlugin().saveConfig();
}
public void showRegion(Player p) {
if (!isDefined()) {
return;
}
showBlocks(p, getFramePoints(p1, p2));
}
public void showLobbyRegion(Player p) {
if (!isLobbyDefined()) {
return;
}
showBlocks(p, getFramePoints(l1, l2));
}
public void showSpawns(Player p) {
if (spawnpoints.isEmpty()) {
return;
}
showBlocks(p, spawnpoints.values());
}
public void showChests(Player p) {
if (containers.isEmpty()) {
return;
}
showBlocks(p, containers.values());
}
public void checkSpawns(Player p) {
if (spawnpoints.isEmpty()) {
return;
}
// Find all the spawnpoints that cover the location
Map<String,Location> map = new HashMap<String,Location>();
for (Map.Entry<String,Location> entry : spawnpoints.entrySet()) {
if (p.getLocation().distanceSquared(entry.getValue()) < MobArena.MIN_PLAYER_DISTANCE_SQUARED) {
map.put(entry.getKey(), entry.getValue());
}
}
if (map.isEmpty()) {
Messenger.tell(p, "No spawnpoints cover your location!");
return;
}
// Notify the player
Messenger.tell(p, "The following points cover your location:");
for (Map.Entry<String,Location> entry : map.entrySet()) {
Location l = entry.getValue();
String coords = l.getBlockX() + "," + l.getBlockY() + "," + l.getBlockZ();
p.sendMessage(ChatColor.AQUA + entry.getKey() + ChatColor.WHITE + " : " + coords);
}
// And show the blocks
showBlocks(p, map.values());
}
public void showBlock(final Player p, final Location loc, final int id, final byte data) {
arena.scheduleTask(new Runnable() {
@Override
public void run() {
p.sendBlockChange(loc, id, data);
arena.scheduleTask(new Runnable() {
@Override
public void run() {
if (!p.isOnline()) return;
Block b = loc.getBlock();
p.sendBlockChange(loc, b.getTypeId(), b.getData());
}
}, 100);
}
}, 0);
}
private void showBlocks(final Player p, final Collection<Location> points) {
arena.scheduleTask(new Runnable() {
@Override
public void run() {
// Grab all the blocks, and send block change events.
final Map<Location,BlockState> blocks = new HashMap<Location,BlockState>();
for (Location l : points) {
Block b = l.getBlock();
blocks.put(l, b.getState());
p.sendBlockChange(l, 35, (byte) 14);
}
arena.scheduleTask(new Runnable() {
public void run() {
// If the player isn't online, just forget it.
if (!p.isOnline()) {
return;
}
// Send block "restore" events.
for (Map.Entry<Location,BlockState> entry : blocks.entrySet()) {
Location l = entry.getKey();
BlockState b = entry.getValue();
int id = b.getTypeId();
byte data = b.getRawData();
p.sendBlockChange(l, id, data);
}
}
}, 100);
}
}, 0);
}
private List<Location> getFramePoints(Location loc1, Location loc2) {
List<Location> result = new ArrayList<Location>();
int x1 = loc1.getBlockX(); int y1 = loc1.getBlockY(); int z1 = loc1.getBlockZ();
int x2 = loc2.getBlockX(); int y2 = loc2.getBlockY(); int z2 = loc2.getBlockZ();
for (int i = x1; i <= x2; i++) {
result.add(world.getBlockAt(i, y1, z1).getLocation());
result.add(world.getBlockAt(i, y1, z2).getLocation());
result.add(world.getBlockAt(i, y2, z1).getLocation());
result.add(world.getBlockAt(i, y2, z2).getLocation());
}
for (int j = y1; j <= y2; j++) {
result.add(world.getBlockAt(x1, j, z1).getLocation());
result.add(world.getBlockAt(x1, j, z2).getLocation());
result.add(world.getBlockAt(x2, j, z1).getLocation());
result.add(world.getBlockAt(x2, j, z2).getLocation());
}
for (int k = z1; k <= z2; k++) {
result.add(world.getBlockAt(x1, y1, k).getLocation());
result.add(world.getBlockAt(x1, y2, k).getLocation());
result.add(world.getBlockAt(x2, y1, k).getLocation());
result.add(world.getBlockAt(x2, y2, k).getLocation());
}
return result;
}
}
@@ -0,0 +1,18 @@
package com.garbagemule.MobArena.region;
public enum RegionPoint {
P1,
P2,
L1,
L2,
ARENA,
LOBBY,
SPECTATOR,
EXIT,
LEADERBOARD;
@Override
public String toString() {
return name().toLowerCase();
}
}
@@ -0,0 +1,143 @@
package com.garbagemule.MobArena.region;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import com.garbagemule.MobArena.framework.Arena;
public class RegionSerializer
{
//private UUID worldUID;
private int x1, y1, z1, x2, y2, z2;
private long width, height, length;
private int[][][] blocks;
private byte[][][] data;
//private transient World world;
public RegionSerializer(World world, Location p1, Location p2) {
//this.worldUID = world.getUID();
this.x1 = p1.getBlockX();
this.y1 = p1.getBlockY();
this.z1 = p1.getBlockZ();
this.x2 = p2.getBlockX();
this.y2 = p2.getBlockY();
this.z2 = p2.getBlockZ();
this.width = (x2 - x1) + 1;
this.height = (y2 - y1) + 1;
this.length = (z2 - z1) + 1;
int w = (int) width;
int h = (int) height;
int l = (int) length;
this.blocks = new int[w][h][l];
this.data = new byte[w][h][l];
}
public void serialize(Arena arena) {
Serializer s = new Serializer(arena);
s.start();
}
public void deserialize(Arena arena) {
Deserializer d = new Deserializer(arena);
d.start();
}
private class Serializer implements Runnable
{
private Arena arena;
private long total;
public Serializer(Arena arena) {
this.arena = arena;
}
public void start() {
// Disable the arena while serializing.
arena.setEnabled(false);
// Start serializing!
total = 0;
arena.scheduleTask(this, 1);
}
@Override
public void run() {
int y = (int) (total / (width*length));
int z = (int) ((total % (width*length)) / width);
int x = (int) ((total % (width*length)) % width);
long max = width*height*length;
int amount = (int) Math.min(20, (max - total));
for (int i = 0; i < amount; i++) {
Block b = arena.getWorld().getBlockAt(x,y,z);
blocks[x][y][z] = b.getTypeId();
data[x][y][z] = b.getData();
x = (int) ((x+1) % width);
y = (int) ((y+1) % height);
z = (int) ((z+1) % length);
}
total += amount;
if (total == max) {
arena.setEnabled(true);
return;
}
arena.scheduleTask(this, 1);
}
}
private class Deserializer implements Runnable
{
private Arena arena;
private long total;
public Deserializer(Arena arena) {
this.arena = arena;
}
public void start() {
// Disable the arena while serializing.
arena.setEnabled(false);
// Start serializing!
total = 0;
arena.scheduleTask(this, 1);
}
@Override
public void run() {
int y = (int) (total / (width*length));
int z = (int) ((total % (width*length)) / width);
int x = (int) ((total % (width*length)) % width);
long max = width*height*length;
int amount = (int) Math.min(20, (max - total));
for (int i = 0; i < 20; i++) {
Block b = arena.getWorld().getBlockAt(x,y,z);
b.setTypeIdAndData(blocks[x][y][z], data[x][y][z], false);
}
total += amount;
if (total == max) {
arena.setEnabled(true);
return;
}
arena.scheduleTask(this, 1);
}
}
}
@@ -0,0 +1,21 @@
package com.garbagemule.MobArena.repairable;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.BlockState;
public interface Repairable
{
public void repair();
public BlockState getState();
public Material getType();
public int getId();
public byte getData();
public World getWorld();
public int getX();
public int getY();
public int getZ();
}
@@ -0,0 +1,37 @@
package com.garbagemule.MobArena.repairable;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.material.Attachable;
public class RepairableAttachable extends RepairableBlock
{
private int x, y, z;
public RepairableAttachable(BlockState state)
{
super(state);
BlockState attached;
if (state.getData() instanceof Attachable)
attached = state.getBlock().getRelative(((Attachable) state.getData()).getAttachedFace()).getState();
else
attached = state.getBlock().getRelative(BlockFace.DOWN).getState();
x = attached.getX();
y = attached.getY();
z = attached.getZ();
state.getBlock().setTypeId(1);
}
public void repair()
{
Block b = getWorld().getBlockAt(x,y,z);
if (b.getTypeId() == 0)
b.setTypeId(1);
super.repair();
}
}
@@ -0,0 +1,24 @@
package com.garbagemule.MobArena.repairable;
import org.bukkit.block.BlockState;
import org.bukkit.material.Bed;
public class RepairableBed extends RepairableBlock
{
private BlockState other;
public RepairableBed(BlockState state)
{
super(state);
other = state.getBlock().getRelative(((Bed) state.getData()).getFacing()).getState();
}
public void repair()
{
if (getWorld().getBlockAt(getX(), getY(), getZ()).getState().getData() instanceof Bed)
return;
super.repair();
other.getBlock().setTypeIdAndData(getId(), (byte) (getData() + 8), false);
}
}
@@ -0,0 +1,77 @@
package com.garbagemule.MobArena.repairable;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.BlockState;
public class RepairableBlock implements Repairable
{
private BlockState state;
private World world;
private int id, x, y, z;
private Material type;
private byte data;
public RepairableBlock(BlockState state)
{
this.state = state;
world = state.getWorld();
x = state.getX();
y = state.getY();
z = state.getZ();
id = state.getTypeId();
type = state.getType();
data = state.getRawData();
}
/**
* Repairs the block by setting the type and data
*/
public void repair()
{
world.getBlockAt(x,y,z).setTypeIdAndData(id, data, false);
}
public BlockState getState()
{
return state;
}
public World getWorld()
{
return world;
}
public Material getType()
{
return type;
}
public int getId()
{
return id;
}
public byte getData()
{
return data;
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public int getZ()
{
return z;
}
}
@@ -0,0 +1,35 @@
package com.garbagemule.MobArena.repairable;
import java.util.Comparator;
import org.bukkit.Material;
import org.bukkit.material.Attachable;
import org.bukkit.material.Bed;
import org.bukkit.material.Door;
import org.bukkit.material.MaterialData;
import org.bukkit.material.Redstone;
public class RepairableComparator implements Comparator<Repairable>
{
public int compare(Repairable r1, Repairable r2)
{
if (restoreLast(r1))
{
if (restoreLast(r2))
return 0;
return 1;
}
else if (restoreLast(r2))
return -1;
return 0;
}
private boolean restoreLast(Repairable r)
{
Material t = r.getType();
MaterialData m = r.getState().getData();
return (m instanceof Attachable || m instanceof Redstone || m instanceof Door || m instanceof Bed || t == Material.STATIONARY_LAVA || t == Material.STATIONARY_WATER || t == Material.FIRE);
}
}
@@ -0,0 +1,46 @@
package com.garbagemule.MobArena.repairable;
import org.bukkit.block.BlockState;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
public class RepairableContainer extends RepairableBlock
{
private ItemStack[] contents;
public RepairableContainer(BlockState state, boolean clear) {
super(state);
// Grab the inventory of the block
Inventory inv = ((InventoryHolder) state).getInventory();
ItemStack[] stacks = inv.getContents();
// Manual copy is necessary due to "reduce to 0" bug in Bukkit
contents = new ItemStack[stacks.length];
for (int i = 0; i < contents.length; i++) {
contents[i] = (stacks[i] != null) ? stacks[i].clone() : null;
}
// Clear the inventory if prompted
if (clear) inv.clear();
}
public RepairableContainer(BlockState state) {
this(state, true);
}
/**
* Repairs the container block by adding all the contents back in.
*/
public void repair() {
super.repair();
// Grab the inventory
InventoryHolder cb = (InventoryHolder) getWorld().getBlockAt(getX(),getY(),getZ()).getState();
Inventory chestInv = cb.getInventory();
chestInv.setContents(contents);
}
}
@@ -0,0 +1,36 @@
package com.garbagemule.MobArena.repairable;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.material.Door;
public class RepairableDoor extends RepairableAttachable//RepairableBlock
{
private BlockState other;
private int x, y, z;
public RepairableDoor(BlockState state)
{
super(state);
other = state.getBlock().getRelative(BlockFace.UP).getState();
BlockState attached = state.getBlock().getRelative(BlockFace.DOWN).getState();
x = attached.getX();
y = attached.getY();
z = attached.getZ();
}
public void repair()
{
if (getWorld().getBlockAt(getX(), getY(), getZ()).getState().getData() instanceof Door)
return;
Block b = getWorld().getBlockAt(x,y,z);
if (b.getTypeId() == 0)
b.setTypeId(1);
super.repair();
other.getBlock().setTypeIdAndData(getId(), (byte) (getData() + 8), false);
}
}
@@ -0,0 +1,32 @@
package com.garbagemule.MobArena.repairable;
import org.bukkit.block.BlockState;
import org.bukkit.block.Sign;
public class RepairableSign extends RepairableAttachable
{
private String[] lines = new String[4];
public RepairableSign(BlockState state)
{
super(state);
Sign s = (Sign) state;
lines = s.getLines();
}
/**
* Repairs the sign block by restoring all the lines
*/
public void repair()
{
super.repair();
Sign s = (Sign) getWorld().getBlockAt(getX(),getY(),getZ()).getState();
s.setLine(0, lines[0]);
s.setLine(1, lines[1]);
s.setLine(2, lines[2]);
s.setLine(3, lines[3]);
}
}
@@ -0,0 +1,27 @@
package com.garbagemule.MobArena.time;
public enum Time
{
DAWN(23000),
SUNRISE(23500),
MORNING(23900),
MIDDAY(6000),
NOON(6000),
DAY(8000),
AFTERNOON(11000),
EVENING(12000),
SUNSET(12600),
DUSK(13300),
NIGHT(14000),
MIDNIGHT(18000);
private int time;
private Time(int time) {
this.time = time;
}
public int getTime() {
return time;
}
}
@@ -0,0 +1,24 @@
package com.garbagemule.MobArena.time;
import org.bukkit.entity.Player;
public interface TimeStrategy
{
/**
* Set the time enum used by setPlayerTime()
* @param time a Time enum
*/
public void setTime(Time time);
/**
* Set the local client time for the player.
* @param p a player
*/
public void setPlayerTime(Player p);
/**
* Reset the local client time for the player to the server time
* @param p a player
*/
public void resetPlayerTime(Player p);
}
@@ -0,0 +1,27 @@
package com.garbagemule.MobArena.time;
import org.bukkit.entity.Player;
public class TimeStrategyLocked implements TimeStrategy
{
private Time time;
public TimeStrategyLocked(Time time) {
setTime(time);
}
@Override
public void setTime(Time time) {
this.time = time;
}
@Override
public void setPlayerTime(Player p) {
p.setPlayerTime(time.getTime(), false);
}
@Override
public void resetPlayerTime(Player p) {
p.resetPlayerTime();
}
}
@@ -0,0 +1,15 @@
package com.garbagemule.MobArena.time;
import org.bukkit.entity.Player;
public class TimeStrategyNull implements TimeStrategy
{
@Override
public void setTime(Time time) {}
@Override
public void setPlayerTime(Player p) {}
@Override
public void resetPlayerTime(Player p) {}
}
@@ -0,0 +1,31 @@
package com.garbagemule.MobArena.util;
import org.bukkit.entity.Player;
import com.garbagemule.MobArena.MobArena;
import com.garbagemule.MobArena.framework.Arena;
public class Delays
{
public static void douse(MobArena plugin, final Player p, long delay) {
if (!plugin.isEnabled()) return;
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
public void run() {
if (p.isOnline()) {
p.setFireTicks(0);
}
}
}, delay);
}
public static void revivePlayer(MobArena plugin, final Arena arena, final Player p) {
if (!plugin.isEnabled()) return;
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
public void run() {
if (p.isOnline()) {
arena.revivePlayer(p);
}
}
});
}
}
@@ -0,0 +1,89 @@
package com.garbagemule.MobArena.util;
import java.io.Serializable;
import org.bukkit.Location;
import org.bukkit.World;
/**
* NOTE: I (garbagemule) DID NOT WRITE THIS CLASS (notice the author below)
* @author creadri
*/
@SuppressWarnings("serial")
public class EntityPosition implements Serializable{
private double x;
private double y;
private double z;
private String world;
private float yaw;
private float pitch;
public EntityPosition(double x, double y, double z, String world, float yaw, float pitch) {
this.x = x;
this.y = y;
this.z = z;
this.world = world;
this.yaw = yaw;
this.pitch = pitch;
}
public EntityPosition(Location location) {
this.x = location.getX();
this.y = location.getY();
this.z = location.getZ();
this.world = location.getWorld().getName();
this.yaw = location.getYaw();
this.pitch = location.getPitch();
}
public Location getLocation(World world) {
return new Location(world, x, y, z, yaw, pitch);
}
public float getPitch() {
return pitch;
}
public void setPitch(float pitch) {
this.pitch = pitch;
}
public String getWorld() {
return world;
}
public void setWorld(String world) {
this.world = world;
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
public float getYaw() {
return yaw;
}
public void setYaw(float yaw) {
this.yaw = yaw;
}
public double getZ() {
return z;
}
public void setZ(double z) {
this.z = z;
}
}
@@ -0,0 +1,30 @@
package com.garbagemule.MobArena.util;
public class Enums
{
/**
* Get the enum value of a string, null if it doesn't exist.
*/
public static <T extends Enum<T>> T getEnumFromString(Class<T> c, String string) {
if (c != null && string != null) {
try {
return Enum.valueOf(c, string.trim().toUpperCase());
}
catch(IllegalArgumentException ex) {}
}
return null;
}
/**
* Get the enum value of a string, null if it doesn't exist.
*/
public static <T extends Enum<T>> T getEnumFromStringCaseSensitive(Class<T> c, String string) {
if (c != null && string != null) {
try {
return Enum.valueOf(c, string);
}
catch(IllegalArgumentException ex) {}
}
return null;
}
}
@@ -0,0 +1,243 @@
package com.garbagemule.MobArena.util;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.garbagemule.MobArena.Messenger;
import org.bukkit.DyeColor;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
import org.bukkit.material.MaterialData;
import com.garbagemule.MobArena.MobArena;
public class ItemParser
{
private static final int WOOL_ID = Material.WOOL.getId();
private static final int DYE_ID = Material.INK_SACK.getId();
public static String parseString(ItemStack... stacks) {
String result = "";
// Parse each stack
for (ItemStack stack : stacks) {
if (stack == null || stack.getTypeId() == 0) continue;
result += ", " + parseString(stack);
}
// Trim off the leading ', ' if it is there
if (!result.equals("")) {
result = result.substring(2);
}
return result;
}
public static String parseString(ItemStack stack) {
if (stack.getTypeId() == 0) return null;
// <item> part
String type = stack.getType().toString().toLowerCase();
// <data> part
MaterialData md = stack.getData();
short data = (md != null ? md.getData() : 0);
// Take wool into account
if (stack.getType() == Material.WOOL) {
data = (byte) (15 - data);
}
// Take potions into account
else if (stack.getType() == Material.POTION) {
data = stack.getDurability();
}
// <amount> part
int amount = stack.getAmount();
// Enchantments
Map<Enchantment,Integer> enchants = null;
if (stack.getType() == Material.ENCHANTED_BOOK) {
EnchantmentStorageMeta esm = (EnchantmentStorageMeta) stack.getItemMeta();
enchants = esm.getStoredEnchants();
} else {
enchants = stack.getEnchantments();
}
String enchantments = "";
for (Entry<Enchantment,Integer> entry : enchants.entrySet()) {
int id = entry.getKey().getId();
int lvl = entry.getValue();
// <eid>:<level>;
enchantments += ";" + id + ":" + lvl;
}
// Trim off the leading ';' if it is there
if (!enchantments.equals("")) {
enchantments = enchantments.substring(1);
}
// <item>
String result = type;
// <item>(:<data>)
if (data != 0) {
result += ":" + data;
}
// <item>((:<data>):<amount>) - force if there is data
if (amount > 1 || data != 0) {
result += ":" + amount;
}
// <item>((:<data>):<amount>) (<eid>:<level>(;<eid>:<level>(; ... )))
if (!enchantments.equals("")) {
result += " " + enchantments;
}
return result;
}
public static List<ItemStack> parseItems(String s) {
if (s == null) {
return new ArrayList<ItemStack>(1);
}
String[] items = s.split(",");
List<ItemStack> result = new ArrayList<ItemStack>(items.length);
for (String item : items) {
ItemStack stack = parseItem(item.trim());
if (stack != null) {
result.add(stack);
}
}
return result;
}
public static ItemStack parseItem(String item) {
if (item == null || item.equals(""))
return null;
// Check if the item has enchantments.
String[] space = item.split(" ");
String[] parts = (space.length == 2 ? space[0].split(":") : item.split(":"));
ItemStack result = null;
switch (parts.length) {
case 1:
result = singleItem(parts[0]);
break;
case 2:
result = withAmount(parts[0], parts[1]);
break;
case 3:
result = withDataAndAmount(parts[0], parts[1], parts[2]);
break;
}
if (result == null || result.getTypeId() == 0) {
Messenger.warning("Failed to parse item: " + item);
return null;
}
if (space.length == 2) {
addEnchantments(result, space[1]);
}
return result;
}
private static ItemStack singleItem(String item) {
if (item.matches("\\$(([1-9]\\d*)|(\\d*.\\d\\d?))")) {
double amount = Double.parseDouble(item.substring(1));
int major = (int) amount;
int minor = ((int) (amount * 100D)) % 100;
return new ItemStack(MobArena.ECONOMY_MONEY_ID, major, (short) minor);
}
int id = getTypeId(item);
return new ItemStack(id);
}
private static ItemStack withAmount(String item, String amount) {
int id = getTypeId(item);
int a = getAmount(amount);
return new ItemStack(id,a);
}
private static ItemStack withDataAndAmount(String item, String data, String amount) {
int id = getTypeId(item);
short d = getData(data, id);
int a = getAmount(amount);
return new ItemStack(id,a,d);
}
private static int getTypeId(String item) {
if (item.matches("(-)?[0-9]*")) {
return Integer.parseInt(item);
}
Material m = Enums.getEnumFromString(Material.class, item);
return (m != null ? m.getId() : 0);
}
private static short getData(String data, int id) {
// Wool and ink are special
if (id == WOOL_ID) {
DyeColor dye = Enums.getEnumFromString(DyeColor.class, data);
if (dye == null) dye = DyeColor.getByWoolData(Byte.parseByte(data));
return dye.getWoolData();
} else if (id == DYE_ID) {
DyeColor dye = Enums.getEnumFromString(DyeColor.class, data);
if (dye == null) dye = DyeColor.getByDyeData(Byte.parseByte(data));
return dye.getDyeData();
}
return (data.matches("(-)?[0-9]+") ? Short.parseShort(data) : 0);
}
private static int getAmount(String amount) {
if (amount.matches("(-)?[1-9][0-9]*")) {
return Integer.parseInt(amount);
}
return 1;
}
private static void addEnchantments(ItemStack stack, String list) {
String[] parts = list.split(";");
for (String ench : parts) {
addEnchantment(stack, ench.trim());
}
}
private static void addEnchantment(ItemStack stack, String ench) {
String[] parts = ench.split(":");
if (parts.length != 2 || !(parts[0].matches("[0-9]*") && parts[1].matches("[0-9]*"))) {
return;
}
int id = Integer.parseInt(parts[0]);
int lvl = Integer.parseInt(parts[1]);
Enchantment e = Enchantment.getById(id);
if (e == null) {// || !e.canEnchantItem(stack) || lvl > e.getMaxLevel() || lvl < e.getStartLevel()) {
return;
}
if (stack.getType() == Material.ENCHANTED_BOOK) {
EnchantmentStorageMeta esm = (EnchantmentStorageMeta) stack.getItemMeta();
esm.addStoredEnchant(e, lvl, true);
stack.setItemMeta(esm);
} else {
stack.addUnsafeEnchantment(e, lvl);
}
}
}
@@ -0,0 +1,68 @@
package com.garbagemule.MobArena.util;
public class MutableInt
{
private int value;
/**
* Create a new MutableInt with the given value.
* @param value the initial value of the MutableInt
*/
public MutableInt(int value) {
this.value = value;
}
/**
* Create a new MutableInt with value 0.
*/
public MutableInt() {
this(0);
}
/**
* Add the given amount to the internal int value.
* @param amount the amount to add
*/
public void add(double amount) {
this.value += amount;
}
/**
* Subtract the given amount from the internal int value.
* @param amount the amount to subtract
*/
public void sub(int amount) {
this.value -= amount;
}
/**
* Increment the value and return it.
* This is essentially the same as calling add(1), followed by value().
* @return the value after incrementing by one
*/
public int inc() {
return ++this.value;
}
/**
* Decrement the value and return it.
* This is essentially the same as calling sub(1), followed by value().
* @return the value after decrementing by one
*/
public int dec() {
return --this.value;
}
/**
* The value of the MutableInt.
* @return the current value
*/
public int value() {
return value;
}
@Override
public String toString() {
return "" + value;
}
}
@@ -0,0 +1,123 @@
package com.garbagemule.MobArena.util;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import com.garbagemule.MobArena.Messenger;
public class PotionEffectParser
{
private static final int TICKS_PER_SECOND = 20;
private static final int DEFAULT_POTION_AMPLIFIER = 0;
private static final int DEFAULT_POTION_DURATION = Integer.MAX_VALUE;
public static List<PotionEffect> parsePotionEffects(String s) {
if (s == null || s.isEmpty())
return null;
List<PotionEffect> potions = new ArrayList<PotionEffect>();
for (String potion : s.split(",")) {
PotionEffect eff = parsePotionEffect(potion.trim());
if (eff != null) {
potions.add(eff);
}
}
return potions;
}
public static PotionEffect parsePotionEffect(String p) {
if (p == null || p.isEmpty())
return null;
String[] parts = p.split(":");
PotionEffect result = null;
switch (parts.length) {
case 1:
result = parseSingle(parts[0]);
break;
case 2:
result = withAmplifier(parts[0], parts[1]);
break;
case 3:
result = withAmplifierAndDuration(parts[0], parts[1], parts[2]);
break;
}
if (result == null) {
Messenger.warning("Failed to parse potion effect: " + p);
return null;
}
return result;
}
private static PotionEffect parseSingle(String type) {
PotionEffectType effect = getType(type);
if (effect == null) {
return null;
} else {
return new PotionEffect(effect, DEFAULT_POTION_DURATION, DEFAULT_POTION_AMPLIFIER);
}
}
private static PotionEffect withAmplifier(String type, String amplifier) {
PotionEffectType effect = getType(type);
int amp = getAmplification(amplifier);
if (effect == null || amp == -1) {
return null;
} else {
return new PotionEffect(effect, DEFAULT_POTION_DURATION, amp);
}
}
private static PotionEffect withAmplifierAndDuration(String type, String amplifier, String duration) {
PotionEffectType effect = getType(type);
int amp = getAmplification(amplifier);
int dur = getDuration(duration);
if (effect == null || dur == -1 || amp == -1) {
return null;
} else {
return new PotionEffect(effect, dur * TICKS_PER_SECOND, amp);
}
}
private static PotionEffectType getType(String type) {
PotionEffectType effect = null;
if (type.matches("[0-9]+")) {
effect = PotionEffectType.getById(Integer.parseInt(type));
} else {
effect = PotionEffectType.getByName(type.toUpperCase());
}
return effect;
}
private static int getDuration(String duration) {
int dur = -1;
if (duration.matches("[0-9]+")) {
dur = Integer.parseInt(duration);
}
return dur;
}
private static int getAmplification(String amplifier) {
int amp = -1;
if (amplifier.matches("[0-9]+")) {
amp = Integer.parseInt(amplifier);
}
return amp;
}
}
@@ -0,0 +1,94 @@
package com.garbagemule.MobArena.util;
import java.util.Collection;
import org.bukkit.entity.Player;
import com.garbagemule.MobArena.Msg;
public class TextUtils
{
/**
* Add character padding on the right side of a String.
* @param s String to add padding to
* @param length Total amount of characters in the returned String
* @param pad The padding character
* @return A padded String with the input length
*/
public static String padRight(String s, int length, char pad)
{
StringBuffer buffy = new StringBuffer();
buffy.append(s);
for (int i = s.length(); i < length; i++)
buffy.append(pad);
return buffy.toString();
}
public static String padRight(String s, int length) { return padRight(s, length, ' '); }
public static String padRight(int s, int length) { return padRight(Integer.toString(s), length, ' '); }
public static String padRight(double s, int length) { return padRight(Double.toString(s), length, ' '); }
/**
* Add character padding on the left side of a String.
* @param s String to add padding to
* @param length Total amount of characters in the returned String
* @param pad The padding character
* @return A padded String with the input length
*/
public static String padLeft(String s, int length, char pad)
{
StringBuffer buffy = new StringBuffer();
for (int i = 0; i < length - s.length(); i++)
buffy.append(pad);
buffy.append(s);
return buffy.toString();
}
public static String padLeft(String s, int length) { return padLeft(s, length, ' '); }
public static String padLeft(int s, int length) { return padLeft(Integer.toString(s), length, ' '); }
public static String padLeft(double s, int length) { return padLeft(Double.toString(s), length, ' '); }
/**
* Truncate the input string to be at most the input length
* @param s The string to truncate
* @param length The maximum length
* @return A truncated string with length 15, or the input string
*/
public static String truncate(String s, int length)
{
if (s.length() <= length)
return s;
return s.substring(0, length);
}
public static String truncate(String s) { return truncate(s, 15); }
public static String camelCase(String s) {
if (s == null || s.length() < 2)
return null;
String firstLetter = s.substring(0,1).toUpperCase();
return firstLetter + s.substring(1).toLowerCase();
}
public static String playerListToString(Collection<? extends Player> list) {
if (list.isEmpty()) {
return Msg.MISC_NONE.toString();
}
StringBuffer buffy = new StringBuffer();
for (Player p : list) {
buffy.append(", " + p.getName());
}
return buffy.substring(2);
}
public static String listToString(Collection<? extends Object> list) {
if (list.isEmpty()) {
return Msg.MISC_NONE.toString();
}
StringBuffer buffy = new StringBuffer();
for (Object o : list) {
buffy.append(", " + o.toString());
}
return buffy.substring(2);
}
}
@@ -0,0 +1,94 @@
package com.garbagemule.MobArena.util;
import java.util.Date;
public class TimeUtils
{
/**
* Turn the input long into a string on the form (D:)HH:MM:SS, where the
* day-part is only added if the number of days is greater than or equal
* to 1, i.e. a long value of 86,399,999.
* @param ms time in milliseconds
* @return string-representation of the input long
*/
public static String toTime(long ms) {
long total = ms / 1000;
long secs = total % 60;
long mins = total % 3600 / 60;
long hours = total / 3600 % 24;
long days = total / 3600 / 24;
String time = (days > 0 ? days + ":" : "") +
(hours < 10 ? "0" + hours : hours) + ":" +
(mins < 10 ? "0" + mins : mins) + ":" +
(secs < 10 ? "0" + secs : secs);
return time;
}
/**
* Makes a new java.util.Date with the input long and toString()s it.
* @param ms time in milliseconds
* @return java.util.Date toString() of the input long
*/
public static String toDateTime(long ms) {
return new Date(ms).toString();
}
/**
* Adds two string-representations of time and returns the resulting time.
* @param t1 a time-string
* @param t2 another time-string
* @return the sum of the time-strings
*/
public static String addTimes(String t1, String t2) {
String[] parts1 = t1.split(":");
String[] parts2 = t2.split(":");
long secs1 = extractSeconds(parts1);
long secs2 = extractSeconds(parts2);
long mins1 = extractMinutes(parts1);
long mins2 = extractMinutes(parts2);
long hours1 = extractHours(parts1);
long hours2 = extractHours(parts2);
long days1 = extractDays(parts1);
long days2 = extractDays(parts2);
long time = (secs1 + secs2 + mins1 + mins2 + hours1 + hours2 + days1 + days2) * 1000;
return toTime(time);
}
private static long extractSeconds(String[] parts) {
int length = parts.length;
if (length < 1) {
return 0L;
}
return Long.parseLong(parts[length - 1]);
}
private static long extractMinutes(String[] parts) {
int length = parts.length;
if (length < 2) {
return 0L;
}
return Long.parseLong(parts[length - 2]) * 60;
}
private static long extractHours(String[] parts) {
int length = parts.length;
if (length < 3) {
return 0L;
}
return Long.parseLong(parts[length - 3]) * 3600;
}
private static long extractDays(String[] parts) {
int length = parts.length;
if (length < 4) {
return 0L;
}
return Long.parseLong(parts[length - 4]) * 24 * 3600;
}
}
@@ -0,0 +1,513 @@
/*
* Updater for Bukkit.
*
* This class provides the means to safely and easily update a plugin, or check to see if it is updated using dev.bukkit.org
*/
package com.garbagemule.MobArena.util;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
/**
* Check dev.bukkit.org to find updates for a given plugin, and download the updates if needed.
* <p/>
* <b>VERY, VERY IMPORTANT</b>: Because there are no standards for adding auto-update toggles in your plugin's config, this system provides NO CHECK WITH YOUR CONFIG to make sure the user has allowed auto-updating.
* <br>
* It is a <b>BUKKIT POLICY</b> that you include a boolean value in your config that prevents the auto-updater from running <b>AT ALL</b>.
* <br>
* If you fail to include this option in your config, your plugin will be <b>REJECTED</b> when you attempt to submit it to dev.bukkit.org.
* <p/>
* An example of a good configuration option would be something similar to 'auto-update: true' - if this value is set to false you may NOT run the auto-updater.
* <br>
* If you are unsure about these rules, please read the plugin submission guidelines: http://goo.gl/8iU5l
*
* @author Gravity
* @version 2.0
*/
public class Updater {
private Plugin plugin;
private UpdateType type;
private String versionName;
private String versionLink;
private String versionType;
private String versionGameVersion;
private boolean announce; // Whether to announce file downloads
private URL url; // Connecting to RSS
private File file; // The plugin's file
private Thread thread; // Updater thread
private int id = -1; // Project's Curse ID
private String apiKey = null; // BukkitDev ServerMods API key
private static final String TITLE_VALUE = "name"; // Gets remote file's title
private static final String LINK_VALUE = "downloadUrl"; // Gets remote file's download link
private static final String TYPE_VALUE = "releaseType"; // Gets remote file's release type
private static final String VERSION_VALUE = "gameVersion"; // Gets remote file's build version
private static final String QUERY = "/servermods/files?projectIds="; // Path to GET
private static final String HOST = "https://api.curseforge.com"; // Slugs will be appended to this to get to the project's RSS feed
private static final String[] NO_UPDATE_TAG = { "-DEV", "-PRE", "-SNAPSHOT" }; // If the version number contains one of these, don't update.
private static final int BYTE_SIZE = 1024; // Used for downloading files
private YamlConfiguration config; // Config file
private String updateFolder;// The folder that downloads will be placed in
private Updater.UpdateResult result = Updater.UpdateResult.SUCCESS; // Used for determining the outcome of the update process
/**
* Gives the dev the result of the update process. Can be obtained by called getResult().
*/
public enum UpdateResult {
/**
* The updater found an update, and has readied it to be loaded the next time the server restarts/reloads.
*/
SUCCESS,
/**
* The updater did not find an update, and nothing was downloaded.
*/
NO_UPDATE,
/**
* The server administrator has disabled the updating system
*/
DISABLED,
/**
* The updater found an update, but was unable to download it.
*/
FAIL_DOWNLOAD,
/**
* For some reason, the updater was unable to contact dev.bukkit.org to download the file.
*/
FAIL_DBO,
/**
* When running the version check, the file on DBO did not contain the a version in the format 'vVersion' such as 'v1.0'.
*/
FAIL_NOVERSION,
/**
* The id provided by the plugin running the updater was invalid and doesn't exist on DBO.
*/
FAIL_BADID,
/**
* The server administrator has improperly configured their API key in the configuration
*/
FAIL_APIKEY,
/**
* The updater found an update, but because of the UpdateType being set to NO_DOWNLOAD, it wasn't downloaded.
*/
UPDATE_AVAILABLE
}
/**
* Allows the dev to specify the type of update that will be run.
*/
public enum UpdateType {
/**
* Run a version check, and then if the file is out of date, download the newest version.
*/
DEFAULT,
/**
* Don't run a version check, just find the latest update and download it.
*/
NO_VERSION_CHECK,
/**
* Get information about the version and the download size, but don't actually download anything.
*/
NO_DOWNLOAD
}
/**
* Initialize the updater
*
* @param plugin The plugin that is checking for an update.
* @param id The dev.bukkit.org id of the project
* @param file The file that the plugin is running from, get this by doing this.getFile() from within your main class.
* @param type Specify the type of update this will be. See {@link UpdateType}
* @param announce True if the program should announce the progress of new updates in console
*/
public Updater(Plugin plugin, int id, File file, UpdateType type, boolean announce) {
this.plugin = plugin;
this.type = type;
this.announce = announce;
this.file = file;
this.id = id;
this.updateFolder = plugin.getServer().getUpdateFolder();
final File pluginFile = plugin.getDataFolder().getParentFile();
final File updaterFile = new File(pluginFile, "Updater");
final File updaterConfigFile = new File(updaterFile, "config.yml");
if (!updaterFile.exists()) {
updaterFile.mkdir();
}
if (!updaterConfigFile.exists()) {
try {
updaterConfigFile.createNewFile();
} catch (final IOException e) {
plugin.getLogger().severe("The updater could not create a configuration in " + updaterFile.getAbsolutePath());
e.printStackTrace();
}
}
this.config = YamlConfiguration.loadConfiguration(updaterConfigFile);
this.config.options().header("This configuration file affects all plugins using the Updater system (version 2+ - http://forums.bukkit.org/threads/96681/ )" + '\n'
+ "If you wish to use your API key, read http://wiki.bukkit.org/ServerMods_API and place it below." + '\n'
+ "Some updating systems will not adhere to the disabled value, but these may be turned off in their plugin's configuration.");
this.config.addDefault("api-key", "PUT_API_KEY_HERE");
this.config.addDefault("disable", false);
if (this.config.get("api-key", null) == null) {
this.config.options().copyDefaults(true);
try {
this.config.save(updaterConfigFile);
} catch (final IOException e) {
plugin.getLogger().severe("The updater could not save the configuration in " + updaterFile.getAbsolutePath());
e.printStackTrace();
}
}
if (this.config.getBoolean("disable")) {
this.result = UpdateResult.DISABLED;
return;
}
String key = this.config.getString("api-key");
if (key.equalsIgnoreCase("PUT_API_KEY_HERE") || key.equals("")) {
key = null;
}
this.apiKey = key;
try {
this.url = new URL(Updater.HOST + Updater.QUERY + id);
} catch (final MalformedURLException e) {
plugin.getLogger().severe("The project ID provided for updating, " + id + " is invalid.");
this.result = UpdateResult.FAIL_BADID;
e.printStackTrace();
}
this.thread = new Thread(new UpdateRunnable());
this.thread.start();
}
/**
* Get the result of the update process.
*/
public Updater.UpdateResult getResult() {
this.waitForThread();
return this.result;
}
/**
* Get the latest version's release type (release, beta, or alpha).
*/
public String getLatestType() {
this.waitForThread();
return this.versionType;
}
/**
* Get the latest version's game version.
*/
public String getLatestGameVersion() {
this.waitForThread();
return this.versionGameVersion;
}
/**
* Get the latest version's name.
*/
public String getLatestName() {
this.waitForThread();
return this.versionName;
}
/**
* Get the latest version's file link.
*/
public String getLatestFileLink() {
this.waitForThread();
return this.versionLink;
}
/**
* As the result of Updater output depends on the thread's completion, it is necessary to wait for the thread to finish
* before allowing anyone to check the result.
*/
private void waitForThread() {
if ((this.thread != null) && this.thread.isAlive()) {
try {
this.thread.join();
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* Save an update from dev.bukkit.org into the server's update folder.
*/
private void saveFile(File folder, String file, String u) {
if (!folder.exists()) {
folder.mkdir();
}
BufferedInputStream in = null;
FileOutputStream fout = null;
try {
// Download the file
final URL url = new URL(u);
final int fileLength = url.openConnection().getContentLength();
in = new BufferedInputStream(url.openStream());
fout = new FileOutputStream(folder.getAbsolutePath() + "/" + file);
final byte[] data = new byte[Updater.BYTE_SIZE];
int count;
if (this.announce) {
this.plugin.getLogger().info("About to download a new update: " + this.versionName);
}
long downloaded = 0;
while ((count = in.read(data, 0, Updater.BYTE_SIZE)) != -1) {
downloaded += count;
fout.write(data, 0, count);
final int percent = (int) ((downloaded * 100) / fileLength);
if (this.announce && ((percent % 10) == 0)) {
this.plugin.getLogger().info("Downloading update: " + percent + "% of " + fileLength + " bytes.");
}
}
//Just a quick check to make sure we didn't leave any files from last time...
for (final File xFile : new File(this.plugin.getDataFolder().getParent(), this.updateFolder).listFiles()) {
if (xFile.getName().endsWith(".zip")) {
xFile.delete();
}
}
// Check to see if it's a zip file, if it is, unzip it.
final File dFile = new File(folder.getAbsolutePath() + "/" + file);
if (dFile.getName().endsWith(".zip")) {
// Unzip
this.unzip(dFile.getCanonicalPath());
}
if (this.announce) {
this.plugin.getLogger().info("Finished updating.");
}
} catch (final Exception ex) {
this.plugin.getLogger().warning("The auto-updater tried to download a new update, but was unsuccessful.");
this.result = Updater.UpdateResult.FAIL_DOWNLOAD;
} finally {
try {
if (in != null) {
in.close();
}
if (fout != null) {
fout.close();
}
} catch (final Exception ex) {
}
}
}
/**
* Part of Zip-File-Extractor, modified by Gravity for use with Bukkit
*/
private void unzip(String file) {
try {
final File fSourceZip = new File(file);
final String zipPath = file.substring(0, file.length() - 4);
ZipFile zipFile = new ZipFile(fSourceZip);
Enumeration<? extends ZipEntry> e = zipFile.entries();
while (e.hasMoreElements()) {
ZipEntry entry = e.nextElement();
File destinationFilePath = new File(zipPath, entry.getName());
destinationFilePath.getParentFile().mkdirs();
if (entry.isDirectory()) {
continue;
} else {
final BufferedInputStream bis = new BufferedInputStream(zipFile.getInputStream(entry));
int b;
final byte buffer[] = new byte[Updater.BYTE_SIZE];
final FileOutputStream fos = new FileOutputStream(destinationFilePath);
final BufferedOutputStream bos = new BufferedOutputStream(fos, Updater.BYTE_SIZE);
while ((b = bis.read(buffer, 0, Updater.BYTE_SIZE)) != -1) {
bos.write(buffer, 0, b);
}
bos.flush();
bos.close();
bis.close();
final String name = destinationFilePath.getName();
if (name.endsWith(".jar") && this.pluginFile(name)) {
destinationFilePath.renameTo(new File(this.plugin.getDataFolder().getParent(), this.updateFolder + "/" + name));
}
}
entry = null;
destinationFilePath = null;
}
e = null;
zipFile.close();
zipFile = null;
// Move any plugin data folders that were included to the right place, Bukkit won't do this for us.
for (final File dFile : new File(zipPath).listFiles()) {
if (dFile.isDirectory()) {
if (this.pluginFile(dFile.getName())) {
final File oFile = new File(this.plugin.getDataFolder().getParent(), dFile.getName()); // Get current dir
final File[] contents = oFile.listFiles(); // List of existing files in the current dir
for (final File cFile : dFile.listFiles()) // Loop through all the files in the new dir
{
boolean found = false;
for (final File xFile : contents) // Loop through contents to see if it exists
{
if (xFile.getName().equals(cFile.getName())) {
found = true;
break;
}
}
if (!found) {
// Move the new file into the current dir
cFile.renameTo(new File(oFile.getCanonicalFile() + "/" + cFile.getName()));
} else {
// This file already exists, so we don't need it anymore.
cFile.delete();
}
}
}
}
dFile.delete();
}
new File(zipPath).delete();
fSourceZip.delete();
} catch (final IOException ex) {
this.plugin.getLogger().warning("The auto-updater tried to unzip a new update file, but was unsuccessful.");
this.result = Updater.UpdateResult.FAIL_DOWNLOAD;
ex.printStackTrace();
}
new File(file).delete();
}
/**
* Check if the name of a jar is one of the plugins currently installed, used for extracting the correct files out of a zip.
*/
private boolean pluginFile(String name) {
for (final File file : new File("plugins").listFiles()) {
if (file.getName().equals(name)) {
return true;
}
}
return false;
}
/**
* Check to see if the program should continue by evaluation whether the plugin is already updated, or shouldn't be updated
*/
private boolean versionCheck(String title) {
if (this.type != UpdateType.NO_VERSION_CHECK) {
final String version = this.plugin.getDescription().getVersion();
if (title.split(" v").length == 2) {
final String remoteVersion = title.split(" v")[1].split(" ")[0]; // Get the newest file's version number
if (this.hasTag(version) || version.equalsIgnoreCase(remoteVersion)) {
// We already have the latest version, or this build is tagged for no-update
this.result = Updater.UpdateResult.NO_UPDATE;
return false;
}
} else {
// The file's name did not contain the string 'vVersion'
final String authorInfo = this.plugin.getDescription().getAuthors().size() == 0 ? "" : " (" + this.plugin.getDescription().getAuthors().get(0) + ")";
this.plugin.getLogger().warning("The author of this plugin" + authorInfo + " has misconfigured their Auto Update system");
this.plugin.getLogger().warning("File versions should follow the format 'PluginName vVERSION'");
this.plugin.getLogger().warning("Please notify the author of this error.");
this.result = Updater.UpdateResult.FAIL_NOVERSION;
return false;
}
}
return true;
}
/**
* Evaluate whether the version number is marked showing that it should not be updated by this program
*/
private boolean hasTag(String version) {
for (final String string : Updater.NO_UPDATE_TAG) {
if (version.contains(string)) {
return true;
}
}
return false;
}
private boolean read() {
try {
final URLConnection conn = this.url.openConnection();
conn.setConnectTimeout(5000);
if (this.apiKey != null) {
conn.addRequestProperty("X-API-Key", this.apiKey);
}
conn.addRequestProperty("User-Agent", "Updater (by Gravity)");
conn.setDoOutput(true);
final BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
final String response = reader.readLine();
final JSONArray array = (JSONArray) JSONValue.parse(response);
if (array.size() == 0) {
this.plugin.getLogger().warning("The updater could not find any files for the project id " + this.id);
this.result = UpdateResult.FAIL_BADID;
return false;
}
this.versionName = (String) ((JSONObject) array.get(array.size() - 1)).get(Updater.TITLE_VALUE);
this.versionLink = (String) ((JSONObject) array.get(array.size() - 1)).get(Updater.LINK_VALUE);
this.versionType = (String) ((JSONObject) array.get(array.size() - 1)).get(Updater.TYPE_VALUE);
this.versionGameVersion = (String) ((JSONObject) array.get(array.size() - 1)).get(Updater.VERSION_VALUE);
return true;
} catch (final IOException e) {
if (e.getMessage().contains("HTTP response code: 403")) {
this.plugin.getLogger().warning("dev.bukkit.org rejected the API key provided in plugins/Updater/config.yml");
this.plugin.getLogger().warning("Please double-check your configuration to ensure it is correct.");
this.result = UpdateResult.FAIL_APIKEY;
} else {
this.plugin.getLogger().warning("The updater could not contact dev.bukkit.org for updating.");
this.plugin.getLogger().warning("If you have not recently modified your configuration and this is the first time you are seeing this message, the site may be experiencing temporary downtime.");
this.result = UpdateResult.FAIL_DBO;
}
e.printStackTrace();
return false;
}
}
private class UpdateRunnable implements Runnable {
@Override
public void run() {
if (Updater.this.url != null) {
// Obtain the results of the project's file feed
if (Updater.this.read()) {
if (Updater.this.versionCheck(Updater.this.versionName)) {
if ((Updater.this.versionLink != null) && (Updater.this.type != UpdateType.NO_DOWNLOAD)) {
String name = Updater.this.file.getName();
// If it's a zip file, it shouldn't be downloaded as the plugin's name
if (Updater.this.versionLink.endsWith(".zip")) {
final String[] split = Updater.this.versionLink.split("/");
name = split[split.length - 1];
}
Updater.this.saveFile(new File(Updater.this.plugin.getDataFolder().getParent(), Updater.this.updateFolder), name, Updater.this.versionLink);
} else {
Updater.this.result = UpdateResult.UPDATE_AVAILABLE;
}
}
}
}
}
}
}
@@ -0,0 +1,104 @@
package com.garbagemule.MobArena.util;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import com.garbagemule.MobArena.Messenger;
import com.garbagemule.MobArena.MobArena;
import com.garbagemule.MobArena.util.Updater.UpdateResult;
import com.garbagemule.MobArena.util.Updater.UpdateType;
public class VersionChecker
{
static Updater updater;
public static void checkForUpdates(final MobArena plugin, final Player player) {
if (updater == null) {
updater = new Updater(plugin, 31265, plugin.getPluginFile(), UpdateType.NO_DOWNLOAD, false);
}
// Async for anti-lag
final Updater cache = updater;
Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() {
public void run() {
if (cache.getResult() == UpdateResult.UPDATE_AVAILABLE) {
final String latest = getLatestVersionString();
final String current = plugin.getDescription().getVersion();
if (latest == null || current == null) {
String msg = "Update checker failed. Please check manually!";
message(plugin, player, msg);
}
else if (isUpdateAvailable(latest, current)) {
String msg1 = "MobArena v" + latest + " is now available!";
String msg2 = "Your version: v" + current;
message(plugin, player, msg1, msg2);
}
}
}
});
}
private static String getLatestVersionString() {
String latestName = updater.getLatestName();
if (!latestName.matches("MobArena v.*")) {
return null;
}
return latestName.substring("MobArena v".length());
}
private static boolean isUpdateAvailable(String latestVersion, String currentVersion) {
// Split into major.minor(.patch(.build))
String[] latestParts = latestVersion.split("\\.");
String[] currentParts = currentVersion.split("\\.");
// Figure out how many numbers to compare
int parts = Math.max(latestParts.length, currentParts.length);
// Check each part
for (int i = 0; i < parts; i++) {
int latest = getPart(latestParts, i);
int current = getPart(currentParts, i);
// Return early if current is more recent
if (current > latest) {
return false;
}
// And also if latest is more recent
if (latest > current) {
return true;
}
}
// Otherwise, we're completely up-to-date!
return false;
}
private static int getPart(String[] parts, int i) {
// Out of bounds or not an int? Bail with 0.
if (i >= parts.length || !parts[i].matches("[0-9]+")) {
return 0;
}
return Integer.parseInt(parts[i]);
}
private static void message(MobArena plugin, final Player player, final String... messages) {
Bukkit.getScheduler().runTaskLater(plugin, new Runnable() {
public void run() {
for (String message : messages) {
if (player == null) {
Messenger.info(message);
} else if (player.isOnline()) {
Messenger.tell(player, message);
}
}
}
}, (player == null) ? 0 : 60); // Message player after login spam
}
public static void shutdown() {
updater = null;
}
}

Some files were not shown because too many files have changed in this diff Show More