diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000..5fcaa0c28f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,53 @@
+.DS_Store
+/BuildAll/nbproject/private/
+/EssentialsProtect/nbproject/private/
+/EssentialsChat/nbproject/private/
+/EssentialsGroupBridge/nbproject/private/
+/EssentialsGeoIP/nbproject/private/
+/EssentialsSpawn/nbproject/private/
+/EssentialsXMPP/nbproject/private/
+/EssentialsGroupManager/nbproject/private/
+/BuildAll/build/
+/EssentialsGroupBridge/dist/
+/EssentialsGroupBridge/build/
+/EssentialsGeoIP/dist/
+/EssentialsGeoIP/build/
+/EssentialsGroupManager/build/
+/EssentialsGroupManager/dist/
+/BuildAll/dist/
+/EssentialsChat/build/
+/EssentialsChat/dist/
+/EssentialsSpawn/build/
+/EssentialsSpawn/dist/
+/EssentialsXMPP/dist/
+/EssentialsXMPP/build/
+/EssentialsProtect/dist/
+/EssentialsProtect/build/
+/EssentialsPermissionsCommands/nbproject/private/
+/EssentialsPermissionsCommands/build/
+/EssentialsPermissionsCommands/dist/
+/Essentials/nbproject/private/
+/Essentials/dist/
+/Essentials/build/
+/YamlAnnotations/
+/EssentialsUpdate/nbproject/private/
+/EssentialsRelease/
+/EssentialsUpdate/dist/
+/EssentialsUpdate/build/
+/WebPush/apikey.php
+/WebPush/nbproject/private
+/EssentialsGroupManager/bin
+/EssentialsGroupManager/.externalToolBuilders
+/EssentialsAntiBuild/nbproject/private/
+/EssentialsAntiBuild/dist/
+/EssentialsAntiBuild/build/
+/jars
+/out
+.idea/
+*.iml
+target/
+dependency-reduced-pom.xml
+/Essentials/config.yml
+/Essentials/userdata/testplayer1.yml
+/Essentials/usermap.csv
+/Essentials/userdata
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000000..0f5c0764c7
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,18 @@
+language: java
+jdk:
+ - oraclejdk7
+ - openjdk7
+ - openjdk6
+script: mvn compile test
+install: true
+notifications:
+ irc:
+ channels:
+ - "irc.esper.net#lain"
+ on_success: change
+ on_failure: always
+ email:
+ recipients:
+ - "khobbits@ess3.net"
+ on_success: change
+ on_failure: always
\ No newline at end of file
diff --git a/Essentials/pom.xml b/Essentials/pom.xml
new file mode 100644
index 0000000000..34a420c188
--- /dev/null
+++ b/Essentials/pom.xml
@@ -0,0 +1,144 @@
+
+ 4.0.0
+
+
+ net.ess3
+ EssentialsParent
+ 2.x-SNAPSHOT
+
+
+ Essentials
+
+ http://ess3.net/
+
+
+ Essentials Team
+ http://ess3.net/
+
+
+
+
+ GPLv3
+ http://www.gnu.org/copyleft/gpl.html
+
+
+
+
+ scm:git:https://github.com/essentials/Essentials.git
+ scm:git:https://github.com/essentials/Essentials.git
+ https://github.com/essentials/Essentials
+
+
+
+ JIRA
+ http://essentials3.atlassian.net
+
+
+
+ TeamCity
+ http://ci.ess3.net/
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 2.3.2
+
+ true
+
+
+
+
+
+
+ org.bukkit
+ bukkit
+ 1.7.2-R0.3-SNAPSHOT
+ system
+ ${project.basedir}/../lib/bukkit.jar
+
+
+ BOSEconomy
+ BOSEconomy
+ v0.7.8.1
+ system
+ ${project.basedir}/../lib/BOSEconomy.jar
+
+
+ de.bananaco
+ bPermissions
+ v2.12-DEV
+
+
+ iConomy
+ iConomy5
+ 5
+ system
+ ${project.basedir}/../lib/iCo5.jar
+
+
+ iConomy
+ iConomy6
+ 6
+ system
+ ${project.basedir}/../lib/iCo6.jar
+
+
+ net.ess3
+ GroupManager
+ ${project.version}
+ system
+ ${project.basedir}/../EssentialsGroupManager/dist/EssentialsGroupManager.jar
+
+
+ MultiCurrency
+ MultiCurrency
+ 2.2
+ system
+ ${project.basedir}/../lib/MultiCurrency.jar
+
+
+ com.platymuus
+ bukkit-permissions
+ 2.0
+ system
+ ${project.basedir}/../lib/PermissionsBukkit.jar
+
+
+ ru.tehkode
+ PermissionsEx
+ 1.20.4
+ system
+ ${project.basedir}/../lib/PermissionsEx.jar
+
+
+ Privileges
+ Privileges
+ 1.8.1
+ system
+ ${project.basedir}/../lib/Privileges.jar
+
+
+ SimplyPerms
+ SimplyPerms
+ 1.7.6
+ system
+ ${project.basedir}/../lib/SimplyPerms.jar
+
+
+ net.milkbowl.vault
+ Vault
+ 1.2.32
+
+
+ zPermissions
+ zPermissions
+ 1.1
+ system
+ ${project.basedir}/../lib/zPermissions.jar
+
+
+
diff --git a/Essentials/src/book.txt b/Essentials/src/book.txt
new file mode 100644
index 0000000000..164910fb7e
--- /dev/null
+++ b/Essentials/src/book.txt
@@ -0,0 +1,18 @@
+This is the book file.
+
+This file format works similar to the info.txt, motd.txt and rules.txt
+
+Place content in here that you would like to be used by books ingame.
+
+You can use this content by using the book: meta option in kits or item spawning.
+
+#Colors
+Minecraft colors:
+&0 &&0 &1 &&1 &2 &&2 &3 &&3
+&4 &&4 &5 &&5 &6 &&6 &7 &&7
+&8 &&8 &9 &&9 &a &&a &b &&b
+&c &&c &d &&d &e &&e &f &&f
+&0
+&&k &kMagic&r &&l &lBold
+&&m &mStrike&r &&n &nUline
+&&o &oItalic&r &&r &rReset
\ No newline at end of file
diff --git a/Essentials/src/com/earth2me/essentials/AlternativeCommandsHandler.java b/Essentials/src/com/earth2me/essentials/AlternativeCommandsHandler.java
new file mode 100644
index 0000000000..3016ffe594
--- /dev/null
+++ b/Essentials/src/com/earth2me/essentials/AlternativeCommandsHandler.java
@@ -0,0 +1,139 @@
+package com.earth2me.essentials;
+
+import java.util.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import net.ess3.api.IEssentials;
+import org.bukkit.command.Command;
+import org.bukkit.command.PluginCommand;
+import org.bukkit.command.PluginCommandYamlParser;
+import org.bukkit.plugin.Plugin;
+
+
+public class AlternativeCommandsHandler
+{
+ private static final Logger LOGGER = Logger.getLogger("Essentials");
+ private final transient Map> altcommands = new HashMap>();
+ private final transient Map disabledList = new HashMap();
+ private final transient IEssentials ess;
+
+ public AlternativeCommandsHandler(final IEssentials ess)
+ {
+ this.ess = ess;
+ for (Plugin plugin : ess.getServer().getPluginManager().getPlugins())
+ {
+ if (plugin.isEnabled())
+ {
+ addPlugin(plugin);
+ }
+ }
+ }
+
+ public final void addPlugin(final Plugin plugin)
+ {
+ if (plugin.getDescription().getMain().contains("com.earth2me.essentials"))
+ {
+ return;
+ }
+ final List commands = PluginCommandYamlParser.parse(plugin);
+ final String pluginName = plugin.getDescription().getName().toLowerCase(Locale.ENGLISH);
+
+ for (Command command : commands)
+ {
+ final PluginCommand pc = (PluginCommand)command;
+ final List labels = new ArrayList(pc.getAliases());
+ labels.add(pc.getName());
+
+ PluginCommand reg = ess.getServer().getPluginCommand(pluginName + ":" + pc.getName().toLowerCase(Locale.ENGLISH));
+ if (reg == null)
+ {
+ reg = ess.getServer().getPluginCommand(pc.getName().toLowerCase(Locale.ENGLISH));
+ }
+ if (reg == null || !reg.getPlugin().equals(plugin))
+ {
+ continue;
+ }
+ for (String label : labels)
+ {
+ List plugincommands = altcommands.get(label.toLowerCase(Locale.ENGLISH));
+ if (plugincommands == null)
+ {
+ plugincommands = new ArrayList();
+ altcommands.put(label.toLowerCase(Locale.ENGLISH), plugincommands);
+ }
+ boolean found = false;
+ for (PluginCommand pc2 : plugincommands)
+ {
+ if (pc2.getPlugin().equals(plugin))
+ {
+ found = true;
+ }
+ }
+ if (!found)
+ {
+ plugincommands.add(reg);
+ }
+ }
+ }
+ }
+
+ public void removePlugin(final Plugin plugin)
+ {
+ final Iterator>> iterator = altcommands.entrySet().iterator();
+ while (iterator.hasNext())
+ {
+ final Map.Entry> entry = iterator.next();
+ final Iterator pcIterator = entry.getValue().iterator();
+ while (pcIterator.hasNext())
+ {
+ final PluginCommand pc = pcIterator.next();
+ if (pc.getPlugin() == null || pc.getPlugin().equals(plugin))
+ {
+ pcIterator.remove();
+ }
+ }
+ if (entry.getValue().isEmpty())
+ {
+ iterator.remove();
+ }
+ }
+ }
+
+ public PluginCommand getAlternative(final String label)
+ {
+ final List commands = altcommands.get(label);
+ if (commands == null || commands.isEmpty())
+ {
+ return null;
+ }
+ if (commands.size() == 1)
+ {
+ return commands.get(0);
+ }
+ // return the first command that is not an alias
+ for (PluginCommand command : commands)
+ {
+ if (command.getName().equalsIgnoreCase(label))
+ {
+ return command;
+ }
+ }
+ // return the first alias
+ return commands.get(0);
+ }
+
+ public void executed(final String label, final PluginCommand pc)
+ {
+ final String altString = pc.getPlugin().getName() + ":" + pc.getLabel();
+ if (ess.getSettings().isDebug())
+ {
+ LOGGER.log(Level.INFO, "Essentials: Alternative command " + label + " found, using " + altString);
+ }
+ disabledList.put(label, altString);
+ }
+
+ public Map disabledCommands()
+ {
+ return disabledList;
+ }
+}
diff --git a/Essentials/src/com/earth2me/essentials/Backup.java b/Essentials/src/com/earth2me/essentials/Backup.java
new file mode 100644
index 0000000000..889d2cbfe5
--- /dev/null
+++ b/Essentials/src/com/earth2me/essentials/Backup.java
@@ -0,0 +1,168 @@
+package com.earth2me.essentials;
+
+import static com.earth2me.essentials.I18n.tl;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import net.ess3.api.IEssentials;
+import org.bukkit.Server;
+import org.bukkit.command.CommandSender;
+
+
+public class Backup implements Runnable
+{
+ private static final Logger LOGGER = Logger.getLogger("Essentials");
+ private transient final Server server;
+ private transient final IEssentials ess;
+ private transient boolean running = false;
+ private transient int taskId = -1;
+ private transient boolean active = false;
+
+ public Backup(final IEssentials ess)
+ {
+ this.ess = ess;
+ server = ess.getServer();
+ if (!ess.getOnlinePlayers().isEmpty())
+ {
+ ess.runTaskAsynchronously(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ startTask();
+ }
+ });
+ }
+ }
+
+ public void onPlayerJoin()
+ {
+ startTask();
+ }
+
+ public synchronized void stopTask()
+ {
+ running = false;
+ if (taskId != -1)
+ {
+ server.getScheduler().cancelTask(taskId);
+ }
+ taskId = -1;
+ }
+
+ private synchronized void startTask()
+ {
+ if (!running)
+ {
+ final long interval = ess.getSettings().getBackupInterval() * 1200; // minutes -> ticks
+ if (interval < 1200)
+ {
+ return;
+ }
+ taskId = ess.scheduleSyncRepeatingTask(this, interval, interval);
+ running = true;
+ }
+ }
+
+ @Override
+ public void run()
+ {
+ if (active)
+ {
+ return;
+ }
+ active = true;
+ final String command = ess.getSettings().getBackupCommand();
+ if (command == null || "".equals(command))
+ {
+ return;
+ }
+ if ("save-all".equalsIgnoreCase(command))
+ {
+ final CommandSender cs = server.getConsoleSender();
+ server.dispatchCommand(cs, "save-all");
+ active = false;
+ return;
+ }
+ LOGGER.log(Level.INFO, tl("backupStarted"));
+ final CommandSender cs = server.getConsoleSender();
+ server.dispatchCommand(cs, "save-all");
+ server.dispatchCommand(cs, "save-off");
+
+ ess.runTaskAsynchronously(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ final ProcessBuilder childBuilder = new ProcessBuilder(command);
+ childBuilder.redirectErrorStream(true);
+ childBuilder.directory(ess.getDataFolder().getParentFile().getParentFile());
+ final Process child = childBuilder.start();
+ ess.runTaskAsynchronously(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ final BufferedReader reader = new BufferedReader(new InputStreamReader(child.getInputStream()));
+ try
+ {
+ String line;
+ do
+ {
+ line = reader.readLine();
+ if (line != null)
+ {
+ LOGGER.log(Level.INFO, line);
+ }
+ }
+ while (line != null);
+ }
+ finally
+ {
+ reader.close();
+ }
+ }
+ catch (IOException ex)
+ {
+ LOGGER.log(Level.SEVERE, null, ex);
+ }
+ }
+ });
+ child.waitFor();
+ }
+ catch (InterruptedException ex)
+ {
+ LOGGER.log(Level.SEVERE, null, ex);
+ }
+ catch (IOException ex)
+ {
+ LOGGER.log(Level.SEVERE, null, ex);
+ }
+ finally
+ {
+ class BackupEnableSaveTask implements Runnable
+ {
+ @Override
+ public void run()
+ {
+ server.dispatchCommand(cs, "save-on");
+ if (ess.getOnlinePlayers().isEmpty())
+ {
+ stopTask();
+ }
+ active = false;
+ LOGGER.log(Level.INFO, tl("backupFinished"));
+ }
+ }
+ ess.scheduleSyncDelayedTask(new BackupEnableSaveTask());
+ }
+ }
+ });
+ }
+}
diff --git a/Essentials/src/com/earth2me/essentials/ChargeException.java b/Essentials/src/com/earth2me/essentials/ChargeException.java
new file mode 100644
index 0000000000..2fa4c7289a
--- /dev/null
+++ b/Essentials/src/com/earth2me/essentials/ChargeException.java
@@ -0,0 +1,15 @@
+package com.earth2me.essentials;
+
+
+public class ChargeException extends Exception
+{
+ public ChargeException(final String message)
+ {
+ super(message);
+ }
+
+ public ChargeException(final String message, final Throwable throwable)
+ {
+ super(message, throwable);
+ }
+}
diff --git a/Essentials/src/com/earth2me/essentials/CommandSource.java b/Essentials/src/com/earth2me/essentials/CommandSource.java
new file mode 100644
index 0000000000..689431a371
--- /dev/null
+++ b/Essentials/src/com/earth2me/essentials/CommandSource.java
@@ -0,0 +1,61 @@
+package com.earth2me.essentials;
+
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+
+public class CommandSource implements IReplyTo
+{
+ private CommandSource replyTo = null;
+ protected CommandSender sender;
+
+ public CommandSource(final CommandSender base)
+ {
+ this.sender = base;
+ }
+
+ public final CommandSender getSender()
+ {
+ return sender;
+ }
+
+ public final Player getPlayer()
+ {
+ if (sender instanceof Player)
+ {
+ return (Player)sender;
+ }
+ return null;
+ }
+
+ public final boolean isPlayer()
+ {
+ return (sender instanceof Player);
+ }
+
+ public final CommandSender setSender(final CommandSender base)
+ {
+ return this.sender = base;
+ }
+
+
+ public void sendMessage(String message)
+ {
+ if (!message.isEmpty())
+ {
+ sender.sendMessage(message);
+ }
+ }
+
+ @Override
+ public void setReplyTo(final CommandSource user)
+ {
+ replyTo = user;
+ }
+
+ @Override
+ public CommandSource getReplyTo()
+ {
+ return replyTo;
+ }
+}
diff --git a/Essentials/src/com/earth2me/essentials/Console.java b/Essentials/src/com/earth2me/essentials/Console.java
new file mode 100644
index 0000000000..3954bbb0f0
--- /dev/null
+++ b/Essentials/src/com/earth2me/essentials/Console.java
@@ -0,0 +1,38 @@
+package com.earth2me.essentials;
+
+import org.bukkit.Server;
+import org.bukkit.command.CommandSender;
+
+
+public final class Console implements IReplyTo
+{
+ private static final Console instance = new Console();
+ private CommandSource replyTo;
+ public final static String NAME = "Console";
+
+ private Console()
+ {
+ }
+
+ public static CommandSender getCommandSender(Server server) throws Exception
+ {
+ return server.getConsoleSender();
+ }
+
+ @Override
+ public void setReplyTo(CommandSource user)
+ {
+ replyTo = user;
+ }
+
+ @Override
+ public CommandSource getReplyTo()
+ {
+ return replyTo;
+ }
+
+ public static Console getConsoleReplyTo()
+ {
+ return instance;
+ }
+}
diff --git a/Essentials/src/com/earth2me/essentials/Enchantments.java b/Essentials/src/com/earth2me/essentials/Enchantments.java
new file mode 100644
index 0000000000..de987ba0f4
--- /dev/null
+++ b/Essentials/src/com/earth2me/essentials/Enchantments.java
@@ -0,0 +1,180 @@
+package com.earth2me.essentials;
+
+import com.earth2me.essentials.utils.NumberUtil;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import org.bukkit.enchantments.Enchantment;
+
+
+public class Enchantments
+{
+ private static final Map ENCHANTMENTS = new HashMap();
+ private static final Map ALIASENCHANTMENTS = new HashMap();
+
+ static
+ {
+ ENCHANTMENTS.put("alldamage", Enchantment.DAMAGE_ALL);
+ ALIASENCHANTMENTS.put("alldmg", Enchantment.DAMAGE_ALL);
+ ENCHANTMENTS.put("sharpness", Enchantment.DAMAGE_ALL);
+ ALIASENCHANTMENTS.put("sharp", Enchantment.DAMAGE_ALL);
+ ALIASENCHANTMENTS.put("dal", Enchantment.DAMAGE_ALL);
+
+ ENCHANTMENTS.put("ardmg", Enchantment.DAMAGE_ARTHROPODS);
+ ENCHANTMENTS.put("baneofarthropods", Enchantment.DAMAGE_ARTHROPODS);
+ ALIASENCHANTMENTS.put("baneofarthropod", Enchantment.DAMAGE_ARTHROPODS);
+ ALIASENCHANTMENTS.put("arthropod", Enchantment.DAMAGE_ARTHROPODS);
+ ALIASENCHANTMENTS.put("dar", Enchantment.DAMAGE_ARTHROPODS);
+
+ ENCHANTMENTS.put("undeaddamage", Enchantment.DAMAGE_UNDEAD);
+ ENCHANTMENTS.put("smite", Enchantment.DAMAGE_UNDEAD);
+ ALIASENCHANTMENTS.put("du", Enchantment.DAMAGE_UNDEAD);
+
+ ENCHANTMENTS.put("digspeed", Enchantment.DIG_SPEED);
+ ENCHANTMENTS.put("efficiency", Enchantment.DIG_SPEED);
+ ALIASENCHANTMENTS.put("minespeed", Enchantment.DIG_SPEED);
+ ALIASENCHANTMENTS.put("cutspeed", Enchantment.DIG_SPEED);
+ ALIASENCHANTMENTS.put("ds", Enchantment.DIG_SPEED);
+ ALIASENCHANTMENTS.put("eff", Enchantment.DIG_SPEED);
+
+ ENCHANTMENTS.put("durability", Enchantment.DURABILITY);
+ ALIASENCHANTMENTS.put("dura", Enchantment.DURABILITY);
+ ENCHANTMENTS.put("unbreaking", Enchantment.DURABILITY);
+ ALIASENCHANTMENTS.put("d", Enchantment.DURABILITY);
+
+ ENCHANTMENTS.put("thorns", Enchantment.THORNS);
+ ENCHANTMENTS.put("highcrit", Enchantment.THORNS);
+ ALIASENCHANTMENTS.put("thorn", Enchantment.THORNS);
+ ALIASENCHANTMENTS.put("highercrit", Enchantment.THORNS);
+ ALIASENCHANTMENTS.put("t", Enchantment.THORNS);
+
+ ENCHANTMENTS.put("fireaspect", Enchantment.FIRE_ASPECT);
+ ENCHANTMENTS.put("fire", Enchantment.FIRE_ASPECT);
+ ALIASENCHANTMENTS.put("meleefire", Enchantment.FIRE_ASPECT);
+ ALIASENCHANTMENTS.put("meleeflame", Enchantment.FIRE_ASPECT);
+ ALIASENCHANTMENTS.put("fa", Enchantment.FIRE_ASPECT);
+
+ ENCHANTMENTS.put("knockback", Enchantment.KNOCKBACK);
+ ALIASENCHANTMENTS.put("kback", Enchantment.KNOCKBACK);
+ ALIASENCHANTMENTS.put("kb", Enchantment.KNOCKBACK);
+ ALIASENCHANTMENTS.put("k", Enchantment.KNOCKBACK);
+
+ ALIASENCHANTMENTS.put("blockslootbonus", Enchantment.LOOT_BONUS_BLOCKS);
+ ENCHANTMENTS.put("fortune", Enchantment.LOOT_BONUS_BLOCKS);
+ ALIASENCHANTMENTS.put("fort", Enchantment.LOOT_BONUS_BLOCKS);
+ ALIASENCHANTMENTS.put("lbb", Enchantment.LOOT_BONUS_BLOCKS);
+
+ ALIASENCHANTMENTS.put("mobslootbonus", Enchantment.LOOT_BONUS_MOBS);
+ ENCHANTMENTS.put("mobloot", Enchantment.LOOT_BONUS_MOBS);
+ ENCHANTMENTS.put("looting", Enchantment.LOOT_BONUS_MOBS);
+ ALIASENCHANTMENTS.put("lbm", Enchantment.LOOT_BONUS_MOBS);
+
+ ALIASENCHANTMENTS.put("oxygen", Enchantment.OXYGEN);
+ ENCHANTMENTS.put("respiration", Enchantment.OXYGEN);
+ ALIASENCHANTMENTS.put("breathing", Enchantment.OXYGEN);
+ ENCHANTMENTS.put("breath", Enchantment.OXYGEN);
+ ALIASENCHANTMENTS.put("o", Enchantment.OXYGEN);
+
+ ENCHANTMENTS.put("protection", Enchantment.PROTECTION_ENVIRONMENTAL);
+ ALIASENCHANTMENTS.put("prot", Enchantment.PROTECTION_ENVIRONMENTAL);
+ ENCHANTMENTS.put("protect", Enchantment.PROTECTION_ENVIRONMENTAL);
+ ALIASENCHANTMENTS.put("p", Enchantment.PROTECTION_ENVIRONMENTAL);
+
+ ALIASENCHANTMENTS.put("explosionsprotection", Enchantment.PROTECTION_EXPLOSIONS);
+ ALIASENCHANTMENTS.put("explosionprotection", Enchantment.PROTECTION_EXPLOSIONS);
+ ALIASENCHANTMENTS.put("expprot", Enchantment.PROTECTION_EXPLOSIONS);
+ ALIASENCHANTMENTS.put("blastprotection", Enchantment.PROTECTION_EXPLOSIONS);
+ ALIASENCHANTMENTS.put("bprotection", Enchantment.PROTECTION_EXPLOSIONS);
+ ALIASENCHANTMENTS.put("bprotect", Enchantment.PROTECTION_EXPLOSIONS);
+ ENCHANTMENTS.put("blastprotect", Enchantment.PROTECTION_EXPLOSIONS);
+ ALIASENCHANTMENTS.put("pe", Enchantment.PROTECTION_EXPLOSIONS);
+
+ ALIASENCHANTMENTS.put("fallprotection", Enchantment.PROTECTION_FALL);
+ ENCHANTMENTS.put("fallprot", Enchantment.PROTECTION_FALL);
+ ENCHANTMENTS.put("featherfall", Enchantment.PROTECTION_FALL);
+ ALIASENCHANTMENTS.put("featherfalling", Enchantment.PROTECTION_FALL);
+ ALIASENCHANTMENTS.put("pfa", Enchantment.PROTECTION_FALL);
+
+ ALIASENCHANTMENTS.put("fireprotection", Enchantment.PROTECTION_FIRE);
+ ALIASENCHANTMENTS.put("flameprotection", Enchantment.PROTECTION_FIRE);
+ ENCHANTMENTS.put("fireprotect", Enchantment.PROTECTION_FIRE);
+ ALIASENCHANTMENTS.put("flameprotect", Enchantment.PROTECTION_FIRE);
+ ENCHANTMENTS.put("fireprot", Enchantment.PROTECTION_FIRE);
+ ALIASENCHANTMENTS.put("flameprot", Enchantment.PROTECTION_FIRE);
+ ALIASENCHANTMENTS.put("pf", Enchantment.PROTECTION_FIRE);
+
+ ENCHANTMENTS.put("projectileprotection", Enchantment.PROTECTION_PROJECTILE);
+ ENCHANTMENTS.put("projprot", Enchantment.PROTECTION_PROJECTILE);
+ ALIASENCHANTMENTS.put("pp", Enchantment.PROTECTION_PROJECTILE);
+
+ ENCHANTMENTS.put("silktouch", Enchantment.SILK_TOUCH);
+ ALIASENCHANTMENTS.put("softtouch", Enchantment.SILK_TOUCH);
+ ALIASENCHANTMENTS.put("st", Enchantment.SILK_TOUCH);
+
+ ENCHANTMENTS.put("waterworker", Enchantment.WATER_WORKER);
+ ENCHANTMENTS.put("aquaaffinity", Enchantment.WATER_WORKER);
+ ALIASENCHANTMENTS.put("watermine", Enchantment.WATER_WORKER);
+ ALIASENCHANTMENTS.put("ww", Enchantment.WATER_WORKER);
+
+ ALIASENCHANTMENTS.put("firearrow", Enchantment.ARROW_FIRE);
+ ENCHANTMENTS.put("flame", Enchantment.ARROW_FIRE);
+ ENCHANTMENTS.put("flamearrow", Enchantment.ARROW_FIRE);
+ ALIASENCHANTMENTS.put("af", Enchantment.ARROW_FIRE);
+
+ ENCHANTMENTS.put("arrowdamage", Enchantment.ARROW_DAMAGE);
+ ENCHANTMENTS.put("power", Enchantment.ARROW_DAMAGE);
+ ALIASENCHANTMENTS.put("arrowpower", Enchantment.ARROW_DAMAGE);
+ ALIASENCHANTMENTS.put("ad", Enchantment.ARROW_DAMAGE);
+
+ ENCHANTMENTS.put("arrowknockback", Enchantment.ARROW_KNOCKBACK);
+ ALIASENCHANTMENTS.put("arrowkb", Enchantment.ARROW_KNOCKBACK);
+ ENCHANTMENTS.put("punch", Enchantment.ARROW_KNOCKBACK);
+ ALIASENCHANTMENTS.put("arrowpunch", Enchantment.ARROW_KNOCKBACK);
+ ALIASENCHANTMENTS.put("ak", Enchantment.ARROW_KNOCKBACK);
+
+ ALIASENCHANTMENTS.put("infinitearrows", Enchantment.ARROW_INFINITE);
+ ENCHANTMENTS.put("infarrows", Enchantment.ARROW_INFINITE);
+ ENCHANTMENTS.put("infinity", Enchantment.ARROW_INFINITE);
+ ALIASENCHANTMENTS.put("infinite", Enchantment.ARROW_INFINITE);
+ ALIASENCHANTMENTS.put("unlimited", Enchantment.ARROW_INFINITE);
+ ALIASENCHANTMENTS.put("unlimitedarrows", Enchantment.ARROW_INFINITE);
+ ALIASENCHANTMENTS.put("ai", Enchantment.ARROW_INFINITE);
+
+ ENCHANTMENTS.put("luck", Enchantment.LUCK);
+ ALIASENCHANTMENTS.put("luckofsea", Enchantment.LUCK);
+ ALIASENCHANTMENTS.put("luckofseas", Enchantment.LUCK);
+ ALIASENCHANTMENTS.put("rodluck", Enchantment.LUCK);
+
+ ENCHANTMENTS.put("lure", Enchantment.LURE);
+ ALIASENCHANTMENTS.put("rodlure", Enchantment.LURE);
+ }
+
+ public static Enchantment getByName(String name)
+ {
+ Enchantment enchantment;
+ if (NumberUtil.isInt(name))
+ {
+ enchantment = Enchantment.getById(Integer.parseInt(name));
+ }
+ else
+ {
+ enchantment = Enchantment.getByName(name.toUpperCase(Locale.ENGLISH));
+ }
+ if (enchantment == null)
+ {
+ enchantment = ENCHANTMENTS.get(name.toLowerCase(Locale.ENGLISH));
+ }
+ if (enchantment == null)
+ {
+ enchantment = ALIASENCHANTMENTS.get(name.toLowerCase(Locale.ENGLISH));
+ }
+ return enchantment;
+ }
+
+ public static Set> entrySet()
+ {
+ return ENCHANTMENTS.entrySet();
+ }
+}
diff --git a/Essentials/src/com/earth2me/essentials/Essentials.java b/Essentials/src/com/earth2me/essentials/Essentials.java
new file mode 100644
index 0000000000..e8d0a5d3a7
--- /dev/null
+++ b/Essentials/src/com/earth2me/essentials/Essentials.java
@@ -0,0 +1,990 @@
+/*
+ * Essentials - a bukkit plugin
+ * Copyright (C) 2011 Essentials Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.earth2me.essentials;
+
+import static com.earth2me.essentials.I18n.tl;
+import com.earth2me.essentials.commands.EssentialsCommand;
+import com.earth2me.essentials.commands.IEssentialsCommand;
+import com.earth2me.essentials.commands.NoChargeException;
+import com.earth2me.essentials.commands.NotEnoughArgumentsException;
+import com.earth2me.essentials.commands.QuietAbortException;
+import com.earth2me.essentials.metrics.Metrics;
+import com.earth2me.essentials.metrics.MetricsListener;
+import com.earth2me.essentials.metrics.MetricsStarter;
+import com.earth2me.essentials.perm.PermissionsHandler;
+import com.earth2me.essentials.register.payment.Methods;
+import com.earth2me.essentials.signs.SignBlockListener;
+import com.earth2me.essentials.signs.SignEntityListener;
+import com.earth2me.essentials.signs.SignPlayerListener;
+import com.earth2me.essentials.textreader.IText;
+import com.earth2me.essentials.textreader.KeywordReplacer;
+import com.earth2me.essentials.textreader.SimpleTextInput;
+import com.earth2me.essentials.utils.DateUtil;
+import com.google.common.base.Function;
+import com.google.common.base.Throwables;
+import com.google.common.collect.Iterables;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.UUID;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import net.ess3.api.Economy;
+import net.ess3.api.IEssentials;
+import net.ess3.api.IItemDb;
+import net.ess3.api.IJails;
+import net.ess3.api.ISettings;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Server;
+import org.bukkit.World;
+import org.bukkit.block.Block;
+import org.bukkit.command.BlockCommandSender;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.PluginCommand;
+import org.bukkit.command.TabCompleter;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.world.WorldLoadEvent;
+import org.bukkit.event.world.WorldUnloadEvent;
+import org.bukkit.plugin.InvalidDescriptionException;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.plugin.PluginDescriptionFile;
+import org.bukkit.plugin.PluginManager;
+import org.bukkit.plugin.java.JavaPlugin;
+import org.bukkit.plugin.java.JavaPluginLoader;
+import org.bukkit.scheduler.BukkitScheduler;
+import org.bukkit.scheduler.BukkitTask;
+import org.yaml.snakeyaml.error.YAMLException;
+
+
+public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials
+{
+ public static final int BUKKIT_VERSION = 3050;
+ private static final Logger LOGGER = Logger.getLogger("Essentials");
+ private transient ISettings settings;
+ private final transient TNTExplodeListener tntListener = new TNTExplodeListener(this);
+ private transient Jails jails;
+ private transient Warps warps;
+ private transient Worth worth;
+ private transient List confList;
+ private transient Backup backup;
+ private transient ItemDb itemDb;
+ private transient final Methods paymentMethod = new Methods();
+ private transient PermissionsHandler permissionsHandler;
+ private transient AlternativeCommandsHandler alternativeCommandsHandler;
+ private transient UserMap userMap;
+ private transient ExecuteTimer execTimer;
+ private transient I18n i18n;
+ private transient Metrics metrics;
+ private transient EssentialsTimer timer;
+ private final transient List vanishedPlayers = new ArrayList();
+ private transient Method oldGetOnlinePlayers;
+
+ public Essentials()
+ {
+ }
+
+ public Essentials(final Server server)
+ {
+ super(new JavaPluginLoader(server), new PluginDescriptionFile("Essentials", "", "com.earth2me.essentials.Essentials"), null, null);
+ }
+
+ @Override
+ public ISettings getSettings()
+ {
+ return settings;
+ }
+
+ public void setupForTesting(final Server server) throws IOException, InvalidDescriptionException
+ {
+ final File dataFolder = File.createTempFile("essentialstest", "");
+ if (!dataFolder.delete())
+ {
+ throw new IOException();
+ }
+ if (!dataFolder.mkdir())
+ {
+ throw new IOException();
+ }
+ i18n = new I18n(this);
+ i18n.onEnable();
+ i18n.updateLocale("en");
+ LOGGER.log(Level.INFO, tl("usingTempFolderForTesting"));
+ LOGGER.log(Level.INFO, dataFolder.toString());
+ this.initialize(null, server, new PluginDescriptionFile(new FileReader(new File("src" + File.separator + "plugin.yml"))), dataFolder, null, null);
+ settings = new Settings(this);
+ userMap = new UserMap(this);
+ permissionsHandler = new PermissionsHandler(this, false);
+ Economy.setEss(this);
+ confList = new ArrayList();
+ jails = new Jails(this);
+ registerListeners(server.getPluginManager());
+ }
+
+ @Override
+ public void onEnable()
+ {
+ try
+ {
+ LOGGER.setParent(this.getLogger());
+ execTimer = new ExecuteTimer();
+ execTimer.start();
+ i18n = new I18n(this);
+ i18n.onEnable();
+ execTimer.mark("I18n1");
+ final PluginManager pm = getServer().getPluginManager();
+ for (Plugin plugin : pm.getPlugins())
+ {
+ if (plugin.getDescription().getName().startsWith("Essentials")
+ && !plugin.getDescription().getVersion().equals(this.getDescription().getVersion())
+ && !plugin.getDescription().getName().equals("EssentialsAntiCheat"))
+ {
+ LOGGER.log(Level.WARNING, tl("versionMismatch", plugin.getDescription().getName()));
+ }
+ }
+ final Matcher versionMatch = Pattern.compile("git-Bukkit-(?:(?:[0-9]+)\\.)+[0-9]+-R[\\.0-9]+-(?:[0-9]+-g[0-9a-f]+-)?b([0-9]+)jnks.*").matcher(getServer().getVersion());
+ if (versionMatch.matches())
+ {
+ final int versionNumber = Integer.parseInt(versionMatch.group(1));
+ if (versionNumber < BUKKIT_VERSION && versionNumber > 100)
+ {
+ wrongVersion();
+ this.setEnabled(false);
+ return;
+ }
+ }
+ else
+ {
+ LOGGER.log(Level.INFO, tl("bukkitFormatChanged"));
+ LOGGER.log(Level.INFO, getServer().getVersion());
+ LOGGER.log(Level.INFO, getServer().getBukkitVersion());
+ }
+ execTimer.mark("BukkitCheck");
+
+ for (Method method : Server.class.getDeclaredMethods())
+ {
+ if (method.getName().endsWith("getOnlinePlayers") && method.getReturnType() == Player[].class)
+ {
+ oldGetOnlinePlayers = method;
+ break;
+ }
+ }
+
+ try
+ {
+ final EssentialsUpgrade upgrade = new EssentialsUpgrade(this);
+ upgrade.beforeSettings();
+ execTimer.mark("Upgrade");
+ confList = new ArrayList();
+ settings = new Settings(this);
+ confList.add(settings);
+ execTimer.mark("Settings");
+ userMap = new UserMap(this);
+ confList.add(userMap);
+ execTimer.mark("Init(Usermap)");
+ upgrade.afterSettings();
+ execTimer.mark("Upgrade2");
+ i18n.updateLocale(settings.getLocale());
+ warps = new Warps(getServer(), this.getDataFolder());
+ confList.add(warps);
+ execTimer.mark("Init(Spawn/Warp)");
+ worth = new Worth(this.getDataFolder());
+ confList.add(worth);
+ itemDb = new ItemDb(this);
+ confList.add(itemDb);
+ execTimer.mark("Init(Worth/ItemDB)");
+ jails = new Jails(this);
+ confList.add(jails);
+ reload();
+ }
+ catch (YAMLException exception)
+ {
+ if (pm.getPlugin("EssentialsUpdate") != null)
+ {
+ LOGGER.log(Level.SEVERE, tl("essentialsHelp2"));
+ }
+ else
+ {
+ LOGGER.log(Level.SEVERE, tl("essentialsHelp1"));
+ }
+ handleCrash(exception);
+ return;
+ }
+ backup = new Backup(this);
+ permissionsHandler = new PermissionsHandler(this, settings.useBukkitPermissions());
+ alternativeCommandsHandler = new AlternativeCommandsHandler(this);
+
+ timer = new EssentialsTimer(this);
+ scheduleSyncRepeatingTask(timer, 1000, 50);
+
+ Economy.setEss(this);
+ execTimer.mark("RegHandler");
+
+ final MetricsStarter metricsStarter = new MetricsStarter(this);
+ if (metricsStarter.getStart() != null && metricsStarter.getStart() == true)
+ {
+ runTaskLaterAsynchronously(metricsStarter, 1);
+ }
+ else if (metricsStarter.getStart() != null && metricsStarter.getStart() == false)
+ {
+ final MetricsListener metricsListener = new MetricsListener(this, metricsStarter);
+ pm.registerEvents(metricsListener, this);
+ }
+
+ final String timeroutput = execTimer.end();
+ if (getSettings().isDebug())
+ {
+ LOGGER.log(Level.INFO, "Essentials load {0}", timeroutput);
+ }
+ }
+ catch (NumberFormatException ex)
+ {
+ handleCrash(ex);
+ }
+ catch (Error ex)
+ {
+ handleCrash(ex);
+ throw ex;
+ }
+ }
+
+ @Override
+ public void saveConfig()
+ {
+ // We don't use any of the bukkit config writing, as this breaks our config file formatting.
+ }
+
+ private void registerListeners(PluginManager pm)
+ {
+ HandlerList.unregisterAll(this);
+
+ if (getSettings().isDebug())
+ {
+ LOGGER.log(Level.INFO, "Registering Listeners");
+ }
+
+ final EssentialsPluginListener serverListener = new EssentialsPluginListener(this);
+ pm.registerEvents(serverListener, this);
+ confList.add(serverListener);
+
+ final EssentialsPlayerListener playerListener = new EssentialsPlayerListener(this);
+ pm.registerEvents(playerListener, this);
+
+ final EssentialsBlockListener blockListener = new EssentialsBlockListener(this);
+ pm.registerEvents(blockListener, this);
+
+ final SignBlockListener signBlockListener = new SignBlockListener(this);
+ pm.registerEvents(signBlockListener, this);
+
+ final SignPlayerListener signPlayerListener = new SignPlayerListener(this);
+ pm.registerEvents(signPlayerListener, this);
+
+ final SignEntityListener signEntityListener = new SignEntityListener(this);
+ pm.registerEvents(signEntityListener, this);
+
+ final EssentialsEntityListener entityListener = new EssentialsEntityListener(this);
+ pm.registerEvents(entityListener, this);
+
+ final EssentialsWorldListener worldListener = new EssentialsWorldListener(this);
+ pm.registerEvents(worldListener, this);
+
+ pm.registerEvents(tntListener, this);
+
+ jails.resetListener();
+ }
+
+ @Override
+ public void onDisable()
+ {
+ for (User user : getOnlineUsers())
+ {
+ if (user.isVanished())
+ {
+ user.setVanished(false);
+ user.sendMessage(tl("unvanishedReload"));
+ }
+ user.stopTransaction();
+ }
+ cleanupOpenInventories();
+ if (i18n != null)
+ {
+ i18n.onDisable();
+ }
+ if (backup != null)
+ {
+ backup.stopTask();
+ }
+ Economy.setEss(null);
+ Trade.closeLog();
+ getUserMap().getUUIDMap().forceWriteUUIDMap();
+
+ HandlerList.unregisterAll(this);
+ }
+
+ @Override
+ public void reload()
+ {
+ Trade.closeLog();
+
+ for (IConf iConf : confList)
+ {
+ iConf.reloadConfig();
+ execTimer.mark("Reload(" + iConf.getClass().getSimpleName() + ")");
+ }
+
+ i18n.updateLocale(settings.getLocale());
+
+ final PluginManager pm = getServer().getPluginManager();
+ registerListeners(pm);
+ }
+
+ @Override
+ public List onTabComplete(CommandSender sender,
+ Command command,
+ String commandLabel,
+ String[] args)
+ {
+ // Allow plugins to override the command via onCommand
+ if (!getSettings().isCommandOverridden(command.getName()) && (!commandLabel.startsWith("e") || commandLabel.equalsIgnoreCase(command.getName())))
+ {
+ final PluginCommand pc = alternativeCommandsHandler.getAlternative(commandLabel);
+ if (pc != null)
+ {
+ try
+ {
+ TabCompleter completer = pc.getTabCompleter();
+ if (completer != null)
+ {
+ return completer.onTabComplete(sender, command, commandLabel, args);
+ }
+ }
+ catch (final Exception ex)
+ {
+ Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean onCommand(final CommandSender sender, final Command command, final String commandLabel, final String[] args)
+ {
+ return onCommandEssentials(sender, command, commandLabel, args, Essentials.class.getClassLoader(), "com.earth2me.essentials.commands.Command", "essentials.", null);
+ }
+
+ @Override
+ public boolean onCommandEssentials(final CommandSender cSender, final Command command, final String commandLabel, final String[] args, final ClassLoader classLoader, final String commandPath, final String permissionPrefix, final IEssentialsModule module)
+ {
+ // Allow plugins to override the command via onCommand
+ if (!getSettings().isCommandOverridden(command.getName()) && (!commandLabel.startsWith("e") || commandLabel.equalsIgnoreCase(command.getName())))
+ {
+ final PluginCommand pc = alternativeCommandsHandler.getAlternative(commandLabel);
+ if (pc != null)
+ {
+ alternativeCommandsHandler.executed(commandLabel, pc);
+ try
+ {
+ return pc.execute(cSender, commandLabel, args);
+ }
+ catch (final Exception ex)
+ {
+ Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
+ cSender.sendMessage(ChatColor.RED + "An internal error occurred while attempting to perform this command");
+ return true;
+ }
+ }
+ }
+
+ try
+ {
+
+ User user = null;
+ Block bSenderBlock = null;
+ if (cSender instanceof Player)
+ {
+ user = getUser((Player)cSender);
+ }
+ else if (cSender instanceof BlockCommandSender)
+ {
+ BlockCommandSender bsender = (BlockCommandSender)cSender;
+ bSenderBlock = bsender.getBlock();
+ }
+
+ if (bSenderBlock != null)
+ {
+ Bukkit.getLogger().log(Level.INFO, "CommandBlock at {0},{1},{2} issued server command: /{3} {4}", new Object[]
+ {
+ bSenderBlock.getX(), bSenderBlock.getY(), bSenderBlock.getZ(), commandLabel, EssentialsCommand.getFinalArg(args, 0)
+ });
+ }
+ else if (user == null)
+ {
+ Bukkit.getLogger().log(Level.INFO, "{0} issued server command: /{1} {2}", new Object[]
+ {
+ cSender.getName(), commandLabel, EssentialsCommand.getFinalArg(args, 0)
+ });
+ }
+
+ CommandSource sender = new CommandSource(cSender);
+
+ // New mail notification
+ if (user != null && !getSettings().isCommandDisabled("mail") && !command.getName().equals("mail") && user.isAuthorized("essentials.mail"))
+ {
+ final List mail = user.getMails();
+ if (mail != null && !mail.isEmpty())
+ {
+ user.sendMessage(tl("youHaveNewMail", mail.size()));
+ }
+ }
+
+ //Print version even if admin command is not available #easteregg
+ if (commandLabel.equalsIgnoreCase("essversion"))
+ {
+ sender.sendMessage("This server is running Essentials " + getDescription().getVersion());
+ return true;
+ }
+
+ // Check for disabled commands
+ if (getSettings().isCommandDisabled(commandLabel))
+ {
+ return true;
+ }
+
+ IEssentialsCommand cmd;
+ try
+ {
+ cmd = (IEssentialsCommand)classLoader.loadClass(commandPath + command.getName()).newInstance();
+ cmd.setEssentials(this);
+ cmd.setEssentialsModule(module);
+ }
+ catch (Exception ex)
+ {
+ sender.sendMessage(tl("commandNotLoaded", commandLabel));
+ LOGGER.log(Level.SEVERE, tl("commandNotLoaded", commandLabel), ex);
+ return true;
+ }
+
+ // Check authorization
+ if (user != null && !user.isAuthorized(cmd, permissionPrefix))
+ {
+ LOGGER.log(Level.INFO, tl("deniedAccessCommand", user.getName()));
+ user.sendMessage(tl("noAccessCommand"));
+ return true;
+ }
+
+ if (user != null && user.isJailed() && !user.isAuthorized(cmd, "essentials.jail.allow."))
+ {
+ if (user.getJailTimeout() > 0)
+ {
+ user.sendMessage(tl("playerJailedFor", user.getName(), DateUtil.formatDateDiff(user.getJailTimeout())));
+ }
+ else
+ {
+ user.sendMessage(tl("jailMessage"));
+ }
+ return true;
+ }
+
+ // Run the command
+ try
+ {
+ if (user == null)
+ {
+ cmd.run(getServer(), sender, commandLabel, command, args);
+ }
+ else
+ {
+ cmd.run(getServer(), user, commandLabel, command, args);
+ }
+ return true;
+ }
+ catch (NoChargeException ex)
+ {
+ return true;
+ }
+ catch (QuietAbortException ex)
+ {
+ return true;
+ }
+ catch (NotEnoughArgumentsException ex)
+ {
+ sender.sendMessage(command.getDescription());
+ sender.sendMessage(command.getUsage().replaceAll("", commandLabel));
+ if (!ex.getMessage().isEmpty())
+ {
+ sender.sendMessage(ex.getMessage());
+ }
+ return true;
+ }
+ catch (Exception ex)
+ {
+ showError(sender, ex, commandLabel);
+ return true;
+ }
+ }
+ catch (Throwable ex)
+ {
+ LOGGER.log(Level.SEVERE, tl("commandFailed", commandLabel), ex);
+ return true;
+ }
+ }
+
+ public void cleanupOpenInventories()
+ {
+ for (User user : getOnlineUsers())
+ {
+ if (user.isRecipeSee())
+ {
+ user.getBase().getOpenInventory().getTopInventory().clear();
+ user.getBase().getOpenInventory().close();
+ user.setRecipeSee(false);
+ }
+ if (user.isInvSee() || user.isEnderSee())
+ {
+ user.getBase().getOpenInventory().close();
+ user.setInvSee(false);
+ user.setEnderSee(false);
+ }
+ }
+ }
+
+ @Override
+ public void showError(final CommandSource sender, final Throwable exception, final String commandLabel)
+ {
+ sender.sendMessage(tl("errorWithMessage", exception.getMessage()));
+ if (getSettings().isDebug())
+ {
+ LOGGER.log(Level.INFO, tl("errorCallingCommand", commandLabel), exception);
+ }
+ }
+
+ public static void wrongVersion()
+ {
+ LOGGER.log(Level.SEVERE, " * ! * ! * ! * ! * ! * ! * ! * ! * ! * ! * ! * ! *");
+ LOGGER.log(Level.SEVERE, tl("notRecommendedBukkit"));
+ LOGGER.log(Level.SEVERE, tl("requiredBukkit", Integer.toString(BUKKIT_VERSION)));
+ LOGGER.log(Level.SEVERE, " * ! * ! * ! * ! * ! * ! * ! * ! * ! * ! * ! * ! *");
+ }
+
+ @Override
+ public BukkitScheduler getScheduler()
+ {
+ return this.getServer().getScheduler();
+ }
+
+ @Override
+ public IJails getJails()
+ {
+ return jails;
+ }
+
+ @Override
+ public Warps getWarps()
+ {
+ return warps;
+ }
+
+ @Override
+ public Worth getWorth()
+ {
+ return worth;
+ }
+
+ @Override
+ public Backup getBackup()
+ {
+ return backup;
+ }
+
+ @Override
+ public Metrics getMetrics()
+ {
+ return metrics;
+ }
+
+ @Override
+ public void setMetrics(Metrics metrics)
+ {
+ this.metrics = metrics;
+ }
+
+ @Deprecated
+ @Override
+ public User getUser(final Object base)
+ {
+ if (base instanceof Player)
+ {
+ return getUser((Player)base);
+ }
+ if (base instanceof org.bukkit.OfflinePlayer)
+ {
+ return getUser(((org.bukkit.OfflinePlayer)base).getUniqueId());
+ }
+ if (base instanceof UUID)
+ {
+ return getUser((UUID)base);
+ }
+ if (base instanceof String)
+ {
+ return getOfflineUser((String)base);
+ }
+ return null;
+ }
+
+ //This will return null if there is not a match.
+ @Override
+ public User getUser(final String base)
+ {
+ return getOfflineUser(base);
+ }
+
+ //This will return null if there is not a match.
+ @Override
+ public User getUser(final UUID base)
+ {
+ return userMap.getUser(base);
+ }
+
+ //This will return null if there is not a match.
+ @Override
+ public User getOfflineUser(final String name)
+ {
+ final User user = userMap.getUser(name);
+ if (user != null && user.getBase() instanceof OfflinePlayer)
+ {
+ //This code should attempt to use the last known name of a user, if Bukkit returns name as null.
+ final String lastName = user.getLastAccountName();
+ if (lastName != null)
+ {
+ ((OfflinePlayer)user.getBase()).setName(lastName);
+ }
+ else
+ {
+ ((OfflinePlayer)user.getBase()).setName(name);
+ }
+ }
+ return user;
+ }
+
+ //This will create a new user if there is not a match.
+ @Override
+ public User getUser(final Player base)
+ {
+ if (base == null)
+ {
+ return null;
+ }
+
+ if (userMap == null)
+ {
+ LOGGER.log(Level.WARNING, "Essentials userMap not initialized");
+ return null;
+ }
+
+ User user = userMap.getUser(base.getUniqueId());
+
+ if (user == null)
+ {
+ if (getSettings().isDebug())
+ {
+ LOGGER.log(Level.INFO, "Constructing new userfile from base player {0}", base.getName());
+ }
+ user = new User(base, this);
+ }
+ else
+ {
+ user.update(base);
+ }
+ return user;
+ }
+
+ private void handleCrash(Throwable exception)
+ {
+ final PluginManager pm = getServer().getPluginManager();
+ LOGGER.log(Level.SEVERE, exception.toString());
+ pm.registerEvents(new Listener()
+ {
+ @EventHandler(priority = EventPriority.LOW)
+ public void onPlayerJoin(final PlayerJoinEvent event)
+ {
+ event.getPlayer().sendMessage("Essentials failed to load, read the log file.");
+ }
+ }, this);
+ for (Player player : getOnlinePlayers())
+ {
+ player.sendMessage("Essentials failed to load, read the log file.");
+ }
+ this.setEnabled(false);
+ }
+
+ @Override
+ public World getWorld(final String name)
+ {
+ if (name.matches("[0-9]+"))
+ {
+ final int worldId = Integer.parseInt(name);
+ if (worldId < getServer().getWorlds().size())
+ {
+ return getServer().getWorlds().get(worldId);
+ }
+ }
+ return getServer().getWorld(name);
+ }
+
+ @Override
+ public void addReloadListener(final IConf listener)
+ {
+ confList.add(listener);
+ }
+
+ @Override
+ public Methods getPaymentMethod()
+ {
+ return paymentMethod;
+ }
+
+ @Override
+ public int broadcastMessage(final String message)
+ {
+ return broadcastMessage(null, null, message, true);
+ }
+
+ @Override
+ public int broadcastMessage(final IUser sender, final String message)
+ {
+ return broadcastMessage(sender, null, message, false);
+ }
+
+ @Override
+ public int broadcastMessage(final String permission, final String message)
+ {
+ return broadcastMessage(null, permission, message, false);
+ }
+
+ private int broadcastMessage(final IUser sender, final String permission, final String message, final boolean keywords)
+ {
+ if (sender != null && sender.isHidden())
+ {
+ return 0;
+ }
+
+ IText broadcast = new SimpleTextInput(message);
+
+ final Collection players = getOnlinePlayers();
+
+ for (Player player : players)
+ {
+ final User user = getUser(player);
+ if ((permission == null && (sender == null || !user.isIgnoredPlayer(sender)))
+ || (permission != null && user.isAuthorized(permission)))
+ {
+ if (keywords)
+ {
+ broadcast = new KeywordReplacer(broadcast, new CommandSource(player), this, false);
+ }
+ for (String messageText : broadcast.getLines())
+ {
+ user.sendMessage(messageText);
+ }
+ }
+ }
+
+ return players.size();
+ }
+
+ @Override
+ public BukkitTask runTaskAsynchronously(final Runnable run)
+ {
+ return this.getScheduler().runTaskAsynchronously(this, run);
+ }
+
+ @Override
+ public BukkitTask runTaskLaterAsynchronously(final Runnable run, final long delay)
+ {
+ return this.getScheduler().runTaskLaterAsynchronously(this, run, delay);
+ }
+
+ @Override
+ public BukkitTask runTaskTimerAsynchronously(final Runnable run, final long delay, final long period)
+ {
+ return this.getScheduler().runTaskTimerAsynchronously(this, run, delay, period);
+ }
+
+ @Override
+ public int scheduleSyncDelayedTask(final Runnable run)
+ {
+ return this.getScheduler().scheduleSyncDelayedTask(this, run);
+ }
+
+ @Override
+ public int scheduleSyncDelayedTask(final Runnable run, final long delay)
+ {
+ return this.getScheduler().scheduleSyncDelayedTask(this, run, delay);
+ }
+
+ @Override
+ public int scheduleSyncRepeatingTask(final Runnable run, final long delay, final long period)
+ {
+ return this.getScheduler().scheduleSyncRepeatingTask(this, run, delay, period);
+ }
+
+ @Override
+ public TNTExplodeListener getTNTListener()
+ {
+ return tntListener;
+ }
+
+ @Override
+ public PermissionsHandler getPermissionsHandler()
+ {
+ return permissionsHandler;
+ }
+
+ @Override
+ public AlternativeCommandsHandler getAlternativeCommandsHandler()
+ {
+ return alternativeCommandsHandler;
+ }
+
+ @Override
+ public IItemDb getItemDb()
+ {
+ return itemDb;
+ }
+
+ @Override
+ public UserMap getUserMap()
+ {
+ return userMap;
+ }
+
+ @Override
+ public I18n getI18n()
+ {
+ return i18n;
+ }
+
+ @Override
+ public EssentialsTimer getTimer()
+ {
+ return timer;
+ }
+
+ @Override
+ public List getVanishedPlayers()
+ {
+ return vanishedPlayers;
+ }
+
+ @Override
+ public Collection getOnlinePlayers()
+ {
+ try
+ {
+ return (Collection)getServer().getOnlinePlayers(); // Needed for sanity here, the Bukkit API is a bit broken in the sense it only allows subclasses of Player to this list
+ }
+ catch (NoSuchMethodError ex)
+ {
+ try
+ {
+ return Arrays.asList((Player[])oldGetOnlinePlayers.invoke(getServer()));
+ }
+ catch (InvocationTargetException ex1)
+ {
+ throw Throwables.propagate(ex.getCause());
+ }
+ catch (IllegalAccessException ex1)
+ {
+ throw new RuntimeException("Error invoking oldGetOnlinePlayers", ex1);
+ }
+ }
+ }
+
+ @Override
+ public Iterable getOnlineUsers()
+ {
+ return Iterables.transform(getOnlinePlayers(), new Function()
+ {
+
+ @Override
+ public User apply(Player player)
+ {
+ return getUser(player);
+ }
+ });
+ }
+
+ private static class EssentialsWorldListener implements Listener, Runnable
+ {
+ private transient final IEssentials ess;
+
+ public EssentialsWorldListener(final IEssentials ess)
+ {
+ this.ess = ess;
+ }
+
+ @EventHandler(priority = EventPriority.LOW)
+ public void onWorldLoad(final WorldLoadEvent event)
+ {
+ ess.getJails().onReload();
+ ess.getWarps().reloadConfig();
+ for (IConf iConf : ((Essentials)ess).confList)
+ {
+ if (iConf instanceof IEssentialsModule)
+ {
+ iConf.reloadConfig();
+ }
+ }
+ }
+
+ @EventHandler(priority = EventPriority.LOW)
+ public void onWorldUnload(final WorldUnloadEvent event)
+ {
+ ess.getJails().onReload();
+ ess.getWarps().reloadConfig();
+ for (IConf iConf : ((Essentials)ess).confList)
+ {
+ if (iConf instanceof IEssentialsModule)
+ {
+ iConf.reloadConfig();
+ }
+ }
+ }
+
+ @Override
+ public void run()
+ {
+ ess.reload();
+ }
+ }
+}
diff --git a/Essentials/src/com/earth2me/essentials/EssentialsBlockListener.java b/Essentials/src/com/earth2me/essentials/EssentialsBlockListener.java
new file mode 100644
index 0000000000..0a5908899a
--- /dev/null
+++ b/Essentials/src/com/earth2me/essentials/EssentialsBlockListener.java
@@ -0,0 +1,71 @@
+package com.earth2me.essentials;
+
+import com.earth2me.essentials.utils.LocationUtil;
+import java.util.Locale;
+import net.ess3.api.IEssentials;
+import org.bukkit.GameMode;
+import org.bukkit.Material;
+import org.bukkit.block.BlockState;
+import org.bukkit.block.CreatureSpawner;
+import org.bukkit.entity.EntityType;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.BlockPlaceEvent;
+import org.bukkit.inventory.ItemStack;
+
+
+public class EssentialsBlockListener implements Listener
+{
+ private final transient IEssentials ess;
+
+ public EssentialsBlockListener(final IEssentials ess)
+ {
+ this.ess = ess;
+ }
+
+ @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
+ public void onBlockPlace(final BlockPlaceEvent event)
+ {
+ // Do not rely on getItemInHand();
+ // http://leaky.bukkit.org/issues/663
+ final ItemStack is = LocationUtil.convertBlockToItem(event.getBlockPlaced());
+ if (is == null)
+ {
+ return;
+ }
+
+ if (is.getType() == Material.MOB_SPAWNER && event.getItemInHand() != null && event.getPlayer() != null
+ && event.getItemInHand().getType() == Material.MOB_SPAWNER)
+ {
+ final BlockState blockState = event.getBlockPlaced().getState();
+ if (blockState instanceof CreatureSpawner)
+ {
+ final CreatureSpawner spawner = (CreatureSpawner)blockState;
+ final EntityType type = EntityType.fromId(event.getItemInHand().getData().getData());
+ if (type != null && Mob.fromBukkitType(type) != null)
+ {
+ if (ess.getUser(event.getPlayer()).isAuthorized("essentials.spawnerconvert." + Mob.fromBukkitType(type).name().toLowerCase(Locale.ENGLISH)))
+ {
+ spawner.setSpawnedType(type);
+ }
+ }
+ }
+ }
+
+ final User user = ess.getUser(event.getPlayer());
+ if (user.hasUnlimited(is) && user.getBase().getGameMode() == GameMode.SURVIVAL)
+ {
+ class UnlimitedItemSpawnTask implements Runnable
+ {
+ @Override
+ public void run()
+ {
+ user.getBase().getInventory().addItem(is);
+ user.getBase().updateInventory();
+ }
+ }
+ ess.scheduleSyncDelayedTask(new UnlimitedItemSpawnTask());
+ }
+ }
+}
diff --git a/Essentials/src/com/earth2me/essentials/EssentialsConf.java b/Essentials/src/com/earth2me/essentials/EssentialsConf.java
new file mode 100644
index 0000000000..0352007e8e
--- /dev/null
+++ b/Essentials/src/com/earth2me/essentials/EssentialsConf.java
@@ -0,0 +1,859 @@
+package com.earth2me.essentials;
+
+import static com.earth2me.essentials.I18n.tl;
+import com.google.common.io.Files;
+import java.io.*;
+import java.math.BigDecimal;
+import java.math.MathContext;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.util.*;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import net.ess3.api.InvalidWorldException;
+import org.bukkit.*;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.InvalidConfigurationException;
+import org.bukkit.configuration.file.YamlConfiguration;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.util.Vector;
+
+
+public class EssentialsConf extends YamlConfiguration
+{
+ protected static final Logger LOGGER = Logger.getLogger("Essentials");
+ protected final File configFile;
+ protected String templateName = null;
+ protected static final Charset UTF8 = Charset.forName("UTF-8");
+ private Class> resourceClass = EssentialsConf.class;
+ private static final ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor();
+ private final AtomicInteger pendingDiskWrites = new AtomicInteger(0);
+ private final AtomicBoolean transaction = new AtomicBoolean(false);
+
+ public EssentialsConf(final File configFile)
+ {
+ super();
+ this.configFile = configFile.getAbsoluteFile();
+ }
+ private final byte[] bytebuffer = new byte[1024];
+
+ public synchronized void load()
+ {
+ if (pendingDiskWrites.get() != 0)
+ {
+ LOGGER.log(Level.INFO, "File {0} not read, because it''s not yet written to disk.", configFile);
+ return;
+ }
+ if (!configFile.getParentFile().exists())
+ {
+ if (!configFile.getParentFile().mkdirs())
+ {
+ LOGGER.log(Level.SEVERE, tl("failedToCreateConfig", configFile.toString()));
+ }
+ }
+ // This will delete files where the first character is 0. In most cases they are broken.
+ if (configFile.exists() && configFile.length() != 0)
+ {
+ try
+ {
+ final InputStream input = new FileInputStream(configFile);
+ try
+ {
+ if (input.read() == 0)
+ {
+ input.close();
+ configFile.delete();
+ }
+ }
+ catch (IOException ex)
+ {
+ LOGGER.log(Level.SEVERE, null, ex);
+ }
+ finally
+ {
+ try
+ {
+ input.close();
+ }
+ catch (IOException ex)
+ {
+ LOGGER.log(Level.SEVERE, null, ex);
+ }
+ }
+ }
+ catch (FileNotFoundException ex)
+ {
+ LOGGER.log(Level.SEVERE, null, ex);
+ }
+ }
+
+ if (!configFile.exists())
+ {
+ if (legacyFileExists())
+ {
+ convertLegacyFile();
+ }
+ else if (altFileExists())
+ {
+ convertAltFile();
+ }
+ else if (templateName != null)
+ {
+ LOGGER.log(Level.INFO, tl("creatingConfigFromTemplate", configFile.toString()));
+ createFromTemplate();
+ }
+ else
+ {
+ return;
+ }
+ }
+
+
+ try
+ {
+ final FileInputStream inputStream = new FileInputStream(configFile);
+ try
+ {
+ long startSize = configFile.length();
+ if (startSize > Integer.MAX_VALUE)
+ {
+ throw new InvalidConfigurationException("File too big");
+ }
+ ByteBuffer buffer = ByteBuffer.allocate((int)startSize);
+ int length;
+ while ((length = inputStream.read(bytebuffer)) != -1)
+ {
+ if (length > buffer.remaining())
+ {
+ ByteBuffer resize = ByteBuffer.allocate(buffer.capacity() + length - buffer.remaining());
+ int resizePosition = buffer.position();
+ buffer.rewind();
+ resize.put(buffer);
+ resize.position(resizePosition);
+ buffer = resize;
+ }
+ buffer.put(bytebuffer, 0, length);
+ }
+ buffer.rewind();
+ final CharBuffer data = CharBuffer.allocate(buffer.capacity());
+ CharsetDecoder decoder = UTF8.newDecoder();
+ CoderResult result = decoder.decode(buffer, data, true);
+ if (result.isError())
+ {
+ buffer.rewind();
+ data.clear();
+ LOGGER.log(Level.INFO, "File " + configFile.getAbsolutePath().toString() + " is not utf-8 encoded, trying " + Charset.defaultCharset().displayName());
+ decoder = Charset.defaultCharset().newDecoder();
+ result = decoder.decode(buffer, data, true);
+ if (result.isError())
+ {
+ throw new InvalidConfigurationException("Invalid Characters in file " + configFile.getAbsolutePath().toString());
+ }
+ else
+ {
+ decoder.flush(data);
+ }
+ }
+ else
+ {
+ decoder.flush(data);
+ }
+ final int end = data.position();
+ data.rewind();
+ super.loadFromString(data.subSequence(0, end).toString());
+ }
+ finally
+ {
+ inputStream.close();
+ }
+ }
+ catch (IOException ex)
+ {
+ LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
+ }
+ catch (InvalidConfigurationException ex)
+ {
+ File broken = new File(configFile.getAbsolutePath() + ".broken." + System.currentTimeMillis());
+ configFile.renameTo(broken);
+ LOGGER.log(Level.SEVERE, "The file " + configFile.toString() + " is broken, it has been renamed to " + broken.toString(), ex.getCause());
+ }
+ }
+
+ public boolean legacyFileExists()
+ {
+ return false;
+ }
+
+ public void convertLegacyFile()
+ {
+ LOGGER.log(Level.SEVERE, "Unable to import legacy config file.");
+ }
+
+ public boolean altFileExists()
+ {
+ return false;
+ }
+
+ public void convertAltFile()
+ {
+ LOGGER.log(Level.SEVERE, "Unable to import alt config file.");
+ }
+
+ private void createFromTemplate()
+ {
+ InputStream istr = null;
+ OutputStream ostr = null;
+ try
+ {
+ istr = resourceClass.getResourceAsStream(templateName);
+ if (istr == null)
+ {
+ LOGGER.log(Level.SEVERE, tl("couldNotFindTemplate", templateName));
+ return;
+ }
+ ostr = new FileOutputStream(configFile);
+ byte[] buffer = new byte[1024];
+ int length = 0;
+ length = istr.read(buffer);
+ while (length > 0)
+ {
+ ostr.write(buffer, 0, length);
+ length = istr.read(buffer);
+ }
+ }
+ catch (IOException ex)
+ {
+ LOGGER.log(Level.SEVERE, tl("failedToWriteConfig", configFile.toString()), ex);
+ }
+ finally
+ {
+ try
+ {
+ if (istr != null)
+ {
+ istr.close();
+ }
+ }
+ catch (IOException ex)
+ {
+ Logger.getLogger(EssentialsConf.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ try
+ {
+ if (ostr != null)
+ {
+ ostr.close();
+ }
+ }
+ catch (IOException ex)
+ {
+ LOGGER.log(Level.SEVERE, tl("failedToCloseConfig", configFile.toString()), ex);
+ }
+ }
+ }
+
+ public void setTemplateName(final String templateName)
+ {
+ this.templateName = templateName;
+ }
+
+ public File getFile()
+ {
+ return configFile;
+ }
+
+ public void setTemplateName(final String templateName, final Class> resClass)
+ {
+ this.templateName = templateName;
+ this.resourceClass = resClass;
+ }
+
+ public void startTransaction()
+ {
+ transaction.set(true);
+ }
+
+ public void stopTransaction()
+ {
+ transaction.set(false);
+ save();
+ }
+
+ public void save()
+ {
+ try
+ {
+ save(configFile);
+ }
+ catch (IOException ex)
+ {
+ LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
+ }
+ }
+
+ public void saveWithError() throws IOException
+ {
+ save(configFile);
+ }
+
+ @Override
+ public synchronized void save(final File file) throws IOException
+ {
+ if (!transaction.get())
+ {
+ delayedSave(file);
+ }
+ }
+
+ //This may be aborted if there are stagnant requests sitting in queue.
+ //This needs fixed to discard outstanding save requests.
+ public synchronized void forceSave()
+ {
+ try
+ {
+ Future> future = delayedSave(configFile);
+ if (future != null)
+ {
+ future.get();
+ }
+ }
+ catch (InterruptedException ex)
+ {
+ LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
+ }
+ catch (ExecutionException ex)
+ {
+ LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
+ }
+ }
+
+ public synchronized void cleanup()
+ {
+ forceSave();
+ }
+
+ private Future> delayedSave(final File file)
+ {
+ if (file == null)
+ {
+ throw new IllegalArgumentException("File cannot be null");
+ }
+
+ final String data = saveToString();
+
+ if (data.length() == 0)
+ {
+ return null;
+ }
+
+ Future> future = EXECUTOR_SERVICE.submit(new WriteRunner(configFile, data, pendingDiskWrites));
+
+ return future;
+ }
+
+
+ private static class WriteRunner implements Runnable
+ {
+ private final File configFile;
+ private final String data;
+ private final AtomicInteger pendingDiskWrites;
+
+ private WriteRunner(final File configFile, final String data, final AtomicInteger pendingDiskWrites)
+ {
+ this.configFile = configFile;
+ this.data = data;
+ this.pendingDiskWrites = pendingDiskWrites;
+ }
+
+ @Override
+ public void run()
+ {
+ //long startTime = System.nanoTime();
+ synchronized (configFile)
+ {
+ if (pendingDiskWrites.get() > 1)
+ {
+ // Writes can be skipped, because they are stored in a queue (in the executor).
+ // Only the last is actually written.
+ pendingDiskWrites.decrementAndGet();
+ //LOGGER.log(Level.INFO, configFile + " skipped writing in " + (System.nanoTime() - startTime) + " nsec.");
+ return;
+ }
+ try
+ {
+ Files.createParentDirs(configFile);
+
+ if (!configFile.exists())
+ {
+ try
+ {
+ LOGGER.log(Level.INFO, tl("creatingEmptyConfig", configFile.toString()));
+ if (!configFile.createNewFile())
+ {
+ LOGGER.log(Level.SEVERE, tl("failedToCreateConfig", configFile.toString()));
+ return;
+ }
+ }
+ catch (IOException ex)
+ {
+ LOGGER.log(Level.SEVERE, tl("failedToCreateConfig", configFile.toString()), ex);
+ return;
+ }
+ }
+
+ final FileOutputStream fos = new FileOutputStream(configFile);
+ try
+ {
+ final OutputStreamWriter writer = new OutputStreamWriter(fos, UTF8);
+
+ try
+ {
+ writer.write(data);
+ }
+ finally
+ {
+ writer.close();
+ }
+ }
+ finally
+ {
+ fos.close();
+ }
+ }
+ catch (IOException e)
+ {
+ LOGGER.log(Level.SEVERE, e.getMessage(), e);
+ }
+ finally
+ {
+ //LOGGER.log(Level.INFO, configFile + " written to disk in " + (System.nanoTime() - startTime) + " nsec.");
+ pendingDiskWrites.decrementAndGet();
+ }
+ }
+ }
+ }
+
+ public boolean hasProperty(final String path)
+ {
+ return isSet(path);
+ }
+
+ public Location getLocation(final String path, final Server server) throws InvalidWorldException
+ {
+ final String worldString = (path == null ? "" : path + ".") + "world";
+ final String worldName = getString(worldString);
+ if (worldName == null || worldName.isEmpty())
+ {
+ return null;
+ }
+ final World world = server.getWorld(worldName);
+ if (world == null)
+ {
+ throw new InvalidWorldException(worldName);
+ }
+ return new Location(world,
+ getDouble((path == null ? "" : path + ".") + "x", 0),
+ getDouble((path == null ? "" : path + ".") + "y", 0),
+ getDouble((path == null ? "" : path + ".") + "z", 0),
+ (float)getDouble((path == null ? "" : path + ".") + "yaw", 0),
+ (float)getDouble((path == null ? "" : path + ".") + "pitch", 0));
+ }
+
+ public void setProperty(final String path, final Location loc)
+ {
+ set((path == null ? "" : path + ".") + "world", loc.getWorld().getName());
+ set((path == null ? "" : path + ".") + "x", loc.getX());
+ set((path == null ? "" : path + ".") + "y", loc.getY());
+ set((path == null ? "" : path + ".") + "z", loc.getZ());
+ set((path == null ? "" : path + ".") + "yaw", loc.getYaw());
+ set((path == null ? "" : path + ".") + "pitch", loc.getPitch());
+ }
+
+ @Override
+ public ItemStack getItemStack(final String path)
+ {
+ final ItemStack stack = new ItemStack(
+ Material.valueOf(getString(path + ".type", "AIR")),
+ getInt(path + ".amount", 1),
+ (short)getInt(path + ".damage", 0));
+ final ConfigurationSection enchants = getConfigurationSection(path + ".enchant");
+ if (enchants != null)
+ {
+ for (String enchant : enchants.getKeys(false))
+ {
+ final Enchantment enchantment = Enchantment.getByName(enchant.toUpperCase(Locale.ENGLISH));
+ if (enchantment == null)
+ {
+ continue;
+ }
+ final int level = getInt(path + ".enchant." + enchant, enchantment.getStartLevel());
+ stack.addUnsafeEnchantment(enchantment, level);
+ }
+ }
+ return stack;
+ /*
+ * ,
+ * (byte)getInt(path + ".data", 0)
+ */
+ }
+
+ public void setProperty(final String path, final ItemStack stack)
+ {
+ final Map map = new HashMap();
+ map.put("type", stack.getType().toString());
+ map.put("amount", stack.getAmount());
+ map.put("damage", stack.getDurability());
+ Map enchantments = stack.getEnchantments();
+ if (!enchantments.isEmpty())
+ {
+ Map enchant = new HashMap();
+ for (Map.Entry entry : enchantments.entrySet())
+ {
+ enchant.put(entry.getKey().getName().toLowerCase(Locale.ENGLISH), entry.getValue());
+ }
+ map.put("enchant", enchant);
+ }
+ // getData().getData() is broken
+ //map.put("data", stack.getDurability());
+ set(path, map);
+ }
+
+ public void setProperty(String path, List object)
+ {
+ set(path, new ArrayList(object));
+ }
+
+ public void setProperty(String path, Map object)
+ {
+ set(path, new LinkedHashMap(object));
+ }
+
+ public Object getProperty(String path)
+ {
+ return get(path);
+ }
+
+ public void setProperty(final String path, final BigDecimal bigDecimal)
+ {
+ set(path, bigDecimal.toString());
+ }
+
+ public void setProperty(String path, Object object)
+ {
+ set(path, object);
+ }
+
+ public void removeProperty(String path)
+ {
+ set(path, null);
+ }
+
+ @Override
+ public synchronized Object get(String path)
+ {
+ return super.get(path);
+ }
+
+ @Override
+ public synchronized Object get(String path, Object def)
+ {
+ return super.get(path, def);
+ }
+
+ public synchronized BigDecimal getBigDecimal(final String path, final BigDecimal def)
+ {
+ final String input = super.getString(path);
+ return toBigDecimal(input, def);
+ }
+
+ public static BigDecimal toBigDecimal(final String input, final BigDecimal def)
+ {
+ if (input == null || input.isEmpty())
+ {
+ return def;
+ }
+ else
+ {
+ try
+ {
+ return new BigDecimal(input, MathContext.DECIMAL128);
+ }
+ catch (NumberFormatException e)
+ {
+ return def;
+ }
+ catch (ArithmeticException e)
+ {
+ return def;
+ }
+ }
+ }
+
+ @Override
+ public synchronized boolean getBoolean(String path)
+ {
+ return super.getBoolean(path);
+ }
+
+ @Override
+ public synchronized boolean getBoolean(String path, boolean def)
+ {
+ return super.getBoolean(path, def);
+ }
+
+ @Override
+ public synchronized List getBooleanList(String path)
+ {
+ return super.getBooleanList(path);
+ }
+
+ @Override
+ public synchronized List getByteList(String path)
+ {
+ return super.getByteList(path);
+ }
+
+ @Override
+ public synchronized List getCharacterList(String path)
+ {
+ return super.getCharacterList(path);
+ }
+
+ @Override
+ public synchronized ConfigurationSection getConfigurationSection(String path)
+ {
+ return super.getConfigurationSection(path);
+ }
+
+ @Override
+ public synchronized double getDouble(String path)
+ {
+ return super.getDouble(path);
+ }
+
+ @Override
+ public synchronized double getDouble(final String path, final double def)
+ {
+ return super.getDouble(path, def);
+ }
+
+ @Override
+ public synchronized List getDoubleList(String path)
+ {
+ return super.getDoubleList(path);
+ }
+
+ @Override
+ public synchronized List getFloatList(String path)
+ {
+ return super.getFloatList(path);
+ }
+
+ @Override
+ public synchronized int getInt(String path)
+ {
+ return super.getInt(path);
+ }
+
+ @Override
+ public synchronized int getInt(String path, int def)
+ {
+ return super.getInt(path, def);
+ }
+
+ @Override
+ public synchronized List getIntegerList(String path)
+ {
+ return super.getIntegerList(path);
+ }
+
+ @Override
+ public synchronized ItemStack getItemStack(String path, ItemStack def)
+ {
+ return super.getItemStack(path, def);
+ }
+
+ @Override
+ public synchronized Set getKeys(boolean deep)
+ {
+ return super.getKeys(deep);
+ }
+
+ @Override
+ public synchronized List> getList(String path)
+ {
+ return super.getList(path);
+ }
+
+ @Override
+ public synchronized List> getList(String path, List> def)
+ {
+ return super.getList(path, def);
+ }
+
+ @Override
+ public synchronized long getLong(String path)
+ {
+ return super.getLong(path);
+ }
+
+ @Override
+ public synchronized long getLong(final String path, final long def)
+ {
+ return super.getLong(path, def);
+ }
+
+ @Override
+ public synchronized List getLongList(String path)
+ {
+ return super.getLongList(path);
+ }
+
+ public synchronized Map getMap()
+ {
+ return map;
+ }
+
+ @Override
+ public synchronized List