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> getMapList(String path) + { + return super.getMapList(path); + } + + @Override + public synchronized OfflinePlayer getOfflinePlayer(String path) + { + return super.getOfflinePlayer(path); + } + + @Override + public synchronized OfflinePlayer getOfflinePlayer(String path, OfflinePlayer def) + { + return super.getOfflinePlayer(path, def); + } + + @Override + public synchronized List getShortList(String path) + { + return super.getShortList(path); + } + + @Override + public synchronized String getString(String path) + { + return super.getString(path); + } + + @Override + public synchronized String getString(String path, String def) + { + return super.getString(path, def); + } + + @Override + public synchronized List getStringList(String path) + { + return super.getStringList(path); + } + + @Override + public synchronized Map getValues(boolean deep) + { + return super.getValues(deep); + } + + @Override + public synchronized Vector getVector(String path) + { + return super.getVector(path); + } + + @Override + public synchronized Vector getVector(String path, Vector def) + { + return super.getVector(path, def); + } + + @Override + public synchronized boolean isBoolean(String path) + { + return super.isBoolean(path); + } + + @Override + public synchronized boolean isConfigurationSection(String path) + { + return super.isConfigurationSection(path); + } + + @Override + public synchronized boolean isDouble(String path) + { + return super.isDouble(path); + } + + @Override + public synchronized boolean isInt(String path) + { + return super.isInt(path); + } + + @Override + public synchronized boolean isItemStack(String path) + { + return super.isItemStack(path); + } + + @Override + public synchronized boolean isList(String path) + { + return super.isList(path); + } + + @Override + public synchronized boolean isLong(String path) + { + return super.isLong(path); + } + + @Override + public synchronized boolean isOfflinePlayer(String path) + { + return super.isOfflinePlayer(path); + } + + @Override + public synchronized boolean isSet(String path) + { + return super.isSet(path); + } + + @Override + public synchronized boolean isString(String path) + { + return super.isString(path); + } + + @Override + public synchronized boolean isVector(String path) + { + return super.isVector(path); + } + + @Override + public synchronized void set(String path, Object value) + { + super.set(path, value); + } +} diff --git a/Essentials/src/com/earth2me/essentials/EssentialsEntityListener.java b/Essentials/src/com/earth2me/essentials/EssentialsEntityListener.java new file mode 100644 index 0000000000..5e3bbb1d04 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/EssentialsEntityListener.java @@ -0,0 +1,226 @@ +package com.earth2me.essentials; + +import static com.earth2me.essentials.I18n.tl; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Pattern; +import net.ess3.api.IEssentials; +import org.bukkit.Material; +import org.bukkit.entity.*; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.*; +import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason; +import org.bukkit.inventory.ItemStack; + + +public class EssentialsEntityListener implements Listener +{ + private static final Logger LOGGER = Logger.getLogger("Essentials"); + private static final transient Pattern powertoolPlayer = Pattern.compile("\\{player\\}"); + private final IEssentials ess; + + public EssentialsEntityListener(IEssentials ess) + { + this.ess = ess; + } + + // This method does something undocumented reguarding certain bucket types #EasterEgg + @EventHandler(priority = EventPriority.LOW) + public void onEntityDamage(final EntityDamageByEntityEvent event) + { + final Entity eAttack = event.getDamager(); + final Entity eDefend = event.getEntity(); + if (eAttack instanceof Player) + { + final User attacker = ess.getUser((Player)eAttack); + if (eDefend instanceof Player) + { + onPlayerVsPlayerDamage(event, (Player)eDefend, attacker); + } + else if (eDefend instanceof Ageable) + { + final ItemStack hand = attacker.getBase().getItemInHand(); + if (hand != null && hand.getType() == Material.MILK_BUCKET) + { + ((Ageable)eDefend).setBaby(); + hand.setType(Material.BUCKET); + attacker.getBase().setItemInHand(hand); + attacker.getBase().updateInventory(); + event.setCancelled(true); + } + } + attacker.updateActivity(true); + } + else if (eAttack instanceof Projectile && eDefend instanceof Player) + { + final Projectile projectile = (Projectile)event.getDamager(); + //This should return a ProjectileSource on 1.7.3 beta + + final Object shooter = projectile.getShooter(); + if (shooter instanceof Player) + { + final User attacker = ess.getUser((Player)shooter); + onPlayerVsPlayerDamage(event, (Player)eDefend, attacker); + attacker.updateActivity(true); + } + } + } + + private void onPlayerVsPlayerDamage(final EntityDamageByEntityEvent event, final Player defender, final User attacker) + { + if (ess.getSettings().getLoginAttackDelay() > 0 + && (System.currentTimeMillis() < (attacker.getLastLogin() + ess.getSettings().getLoginAttackDelay())) + && !attacker.isAuthorized("essentials.pvpdelay.exempt")) + { + event.setCancelled(true); + } + + if (!defender.equals(attacker.getBase()) && (attacker.hasInvulnerabilityAfterTeleport() || ess.getUser(defender).hasInvulnerabilityAfterTeleport())) + { + event.setCancelled(true); + } + + if (attacker.isGodModeEnabled() && !attacker.isAuthorized("essentials.god.pvp")) + { + event.setCancelled(true); + } + + if (attacker.isHidden() && !attacker.isAuthorized("essentials.vanish.pvp")) + { + event.setCancelled(true); + } + + onPlayerVsPlayerPowertool(event, defender, attacker); + } + + private void onPlayerVsPlayerPowertool(final EntityDamageByEntityEvent event, final Player defender, final User attacker) + { + final List commandList = attacker.getPowertool(attacker.getBase().getItemInHand()); + if (commandList != null && !commandList.isEmpty()) + { + for (final String tempCommand : commandList) + { + final String command = powertoolPlayer.matcher(tempCommand).replaceAll(defender.getName()); + if (command != null && !command.isEmpty() && !command.equals(tempCommand)) + { + + class PowerToolInteractTask implements Runnable + { + @Override + public void run() + { + attacker.getServer().dispatchCommand(attacker.getBase(), command); + LOGGER.log(Level.INFO, String.format("[PT] %s issued server command: /%s", attacker.getName(), command)); + } + } + ess.scheduleSyncDelayedTask(new PowerToolInteractTask()); + + event.setCancelled(true); + return; + } + } + } + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onEntityDamage(final EntityDamageEvent event) + { + if (event.getEntity() instanceof Player && ess.getUser((Player)event.getEntity()).isGodModeEnabled()) + { + final Player player = (Player)event.getEntity(); + player.setFireTicks(0); + player.setRemainingAir(player.getMaximumAir()); + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onEntityCombust(final EntityCombustEvent event) + { + if (event.getEntity() instanceof Player && ess.getUser((Player)event.getEntity()).isGodModeEnabled()) + { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerDeathEvent(final PlayerDeathEvent event) + { + final User user = ess.getUser(event.getEntity()); + if (user.isAuthorized("essentials.back.ondeath") && !ess.getSettings().isCommandDisabled("back")) + { + user.setLastLocation(); + user.sendMessage(tl("backAfterDeath")); + } + if (!ess.getSettings().areDeathMessagesEnabled()) + { + event.setDeathMessage(""); + } + } + + @EventHandler(priority = EventPriority.LOW) + public void onPlayerDeathExpEvent(final PlayerDeathEvent event) + { + final User user = ess.getUser(event.getEntity()); + if (user.isAuthorized("essentials.keepxp")) + { + event.setKeepLevel(true); + event.setDroppedExp(0); + } + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onFoodLevelChange(final FoodLevelChangeEvent event) + { + if (event.getEntity() instanceof Player) + { + final User user = ess.getUser((Player)event.getEntity()); + if (user.isGodModeEnabled()) + { + if (user.isGodModeEnabledRaw()) + { + user.getBase().setFoodLevel(20); + user.getBase().setSaturation(10); + } + event.setCancelled(true); + } + } + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onEntityRegainHealth(final EntityRegainHealthEvent event) + { + if (event.getRegainReason() == RegainReason.SATIATED && event.getEntity() instanceof Player + && ess.getUser((Player)event.getEntity()).isAfk() && ess.getSettings().getFreezeAfkPlayers()) + { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onPotionSplashEvent(final PotionSplashEvent event) + { + for (LivingEntity entity : event.getAffectedEntities()) + { + if (entity instanceof Player && ess.getUser((Player)entity).isGodModeEnabled()) + { + event.setIntensity(entity, 0d); + } + } + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onEntityShootBow(EntityShootBowEvent event) + { + if (event.getEntity() instanceof Player) + { + final User user = ess.getUser((Player)event.getEntity()); + if (user.isAfk()) + { + user.updateActivity(true); + } + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/EssentialsPlayerListener.java b/Essentials/src/com/earth2me/essentials/EssentialsPlayerListener.java new file mode 100644 index 0000000000..4ca588e6ea --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/EssentialsPlayerListener.java @@ -0,0 +1,777 @@ +package com.earth2me.essentials; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.textreader.IText; +import com.earth2me.essentials.textreader.KeywordReplacer; +import com.earth2me.essentials.textreader.TextInput; +import com.earth2me.essentials.textreader.TextPager; +import com.earth2me.essentials.utils.LocationUtil; +import java.io.IOException; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.logging.Level; +import java.util.logging.Logger; +import net.ess3.api.IEssentials; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.event.player.*; +import org.bukkit.event.player.PlayerLoginEvent.Result; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; + + +public class EssentialsPlayerListener implements Listener +{ + private static final Logger LOGGER = Logger.getLogger("Essentials"); + private final transient IEssentials ess; + + public EssentialsPlayerListener(final IEssentials parent) + { + this.ess = parent; + } + + @EventHandler(priority = EventPriority.NORMAL) + public void onPlayerRespawn(final PlayerRespawnEvent event) + { + final User user = ess.getUser(event.getPlayer()); + updateCompass(user); + user.setDisplayNick(); + + if (ess.getSettings().isTeleportInvulnerability()) + { + user.enableInvulnerabilityAfterTeleport(); + } + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerChat(final AsyncPlayerChatEvent event) + { + final User user = ess.getUser(event.getPlayer()); + if (user.isMuted()) + { + event.setCancelled(true); + user.sendMessage(tl("voiceSilenced")); + LOGGER.info(tl("mutedUserSpeaks", user.getName())); + } + try + { + final Iterator it = event.getRecipients().iterator(); + while (it.hasNext()) + { + final User u = ess.getUser(it.next()); + if (u.isIgnoredPlayer(user)) + { + it.remove(); + } + } + } + catch (UnsupportedOperationException ex) + { + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "Ignore could not block chat due to custom chat plugin event.", ex); + } + else + { + ess.getLogger().info("Ignore could not block chat due to custom chat plugin event."); + } + } + + user.updateActivity(true); + user.setDisplayNick(); + } + + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void onPlayerMove(final PlayerMoveEvent event) + { + if (event.getFrom().getBlockX() == event.getTo().getBlockX() + && event.getFrom().getBlockZ() == event.getTo().getBlockZ() + && event.getFrom().getBlockY() == event.getTo().getBlockY()) + { + return; + } + + if (!ess.getSettings().cancelAfkOnMove() && !ess.getSettings().getFreezeAfkPlayers()) + { + event.getHandlers().unregister(this); + + if (ess.getSettings().isDebug()) + { + LOGGER.log(Level.INFO, "Unregistering move listener"); + } + + return; + } + + final User user = ess.getUser(event.getPlayer()); + if (user.isAfk() && ess.getSettings().getFreezeAfkPlayers()) + { + final Location from = event.getFrom(); + final Location origTo = event.getTo(); + final Location to = origTo.clone(); + if (ess.getSettings().cancelAfkOnMove() && origTo.getY() >= from.getBlockY() + 1) + { + user.updateActivity(true); + return; + } + to.setX(from.getX()); + to.setY(from.getY()); + to.setZ(from.getZ()); + try + { + event.setTo(LocationUtil.getSafeDestination(to)); + } + catch (Exception ex) + { + event.setTo(to); + } + return; + } + final Location afk = user.getAfkPosition(); + if (afk == null || !event.getTo().getWorld().equals(afk.getWorld()) || afk.distanceSquared(event.getTo()) > 9) + { + user.updateActivity(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onPlayerQuit(final PlayerQuitEvent event) + { + final User user = ess.getUser(event.getPlayer()); + + if (ess.getSettings().allowSilentJoinQuit() && user.isAuthorized("essentials.silentquit")) + { + event.setQuitMessage(null); + } + else if (ess.getSettings().isCustomQuitMessage() && event.getQuitMessage() != null) + { + final Player player = event.getPlayer(); + event.setQuitMessage( + ess.getSettings().getCustomQuitMessage() + .replace("{PLAYER}", player.getDisplayName()) + .replace("{USERNAME}", player.getName())); + } + + if (ess.getSettings().removeGodOnDisconnect() && user.isGodModeEnabled()) + { + user.setGodModeEnabled(false); + } + if (user.isVanished()) + { + user.setVanished(false); + } + user.setLogoutLocation(); + if (user.isRecipeSee()) + { + user.getBase().getOpenInventory().getTopInventory().clear(); + } + + for (HumanEntity viewer : user.getBase().getInventory().getViewers()) + { + if (viewer instanceof Player) + { + User uviewer = ess.getUser((Player)viewer); + if (uviewer.isInvSee()) + { + uviewer.getBase().closeInventory(); + } + } + } + + user.updateActivity(false); + user.dispose(); + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onPlayerJoin(final PlayerJoinEvent event) + { + final String joinMessage = event.getJoinMessage(); + ess.runTaskAsynchronously(new Runnable() + { + @Override + public void run() + { + delayedJoin(event.getPlayer(), joinMessage); + } + }); + if (ess.getSettings().allowSilentJoinQuit() || ess.getSettings().isCustomJoinMessage()) + { + event.setJoinMessage(null); + } + } + + public void delayedJoin(final Player player, final String message) + { + if (!player.isOnline()) + { + return; + } + + ess.getBackup().onPlayerJoin(); + final User dUser = ess.getUser(player); + + + if (dUser.isNPC()) + { + dUser.setNPC(false); + } + + final long currentTime = System.currentTimeMillis(); + dUser.checkMuteTimeout(currentTime); + dUser.updateActivity(false); + + IText tempInput = null; + + if (!ess.getSettings().isCommandDisabled("motd")) + { + try + { + tempInput = new TextInput(dUser.getSource(), "motd", true, ess); + } + catch (IOException ex) + { + if (ess.getSettings().isDebug()) + { + LOGGER.log(Level.WARNING, ex.getMessage(), ex); + } + else + { + LOGGER.log(Level.WARNING, ex.getMessage()); + } + } + } + + final IText input = tempInput; + + class DelayJoinTask implements Runnable + { + @Override + public void run() + { + final User user = ess.getUser(player); + + if (!user.getBase().isOnline()) + { + return; + } + + user.startTransaction(); + + user.setLastAccountName(user.getBase().getName()); + user.setLastLogin(currentTime); + user.setDisplayNick(); + updateCompass(user); + + if (!ess.getVanishedPlayers().isEmpty() && !user.isAuthorized("essentials.vanish.see")) + { + for (String p : ess.getVanishedPlayers()) + { + Player toVanish = ess.getServer().getPlayerExact(p); + if (toVanish != null && toVanish.isOnline()) + { + user.getBase().hidePlayer(toVanish); + } + } + } + + if (user.isAuthorized("essentials.sleepingignored")) + { + user.getBase().setSleepingIgnored(true); + } + + if (ess.getSettings().allowSilentJoinQuit() && (user.isAuthorized("essentials.silentjoin") || user.isAuthorized("essentials.silentjoin.vanish"))) + { + if (user.isAuthorized("essentials.silentjoin.vanish")) + { + user.setVanished(true); + } + } + else if (message == null) + { + //NOOP + } + else if (ess.getSettings().isCustomJoinMessage()) + { + ess.getServer().broadcastMessage( + ess.getSettings().getCustomJoinMessage() + .replace("{PLAYER}", player.getDisplayName()) + .replace("{USERNAME}", player.getName())); + } + else if (ess.getSettings().allowSilentJoinQuit()) + { + ess.getServer().broadcastMessage(message); + } + + if (input != null && user.isAuthorized("essentials.motd")) + { + final IText output = new KeywordReplacer(input, user.getSource(), ess); + final TextPager pager = new TextPager(output, true); + pager.showPage("1", null, "motd", user.getSource()); + } + + if (!ess.getSettings().isCommandDisabled("mail") && user.isAuthorized("essentials.mail")) + { + final List mail = user.getMails(); + if (mail.isEmpty()) + { + user.sendMessage(tl("noNewMail")); + } + else + { + user.sendMessage(tl("youHaveNewMail", mail.size())); + } + } + + if (user.isAuthorized("essentials.fly.safelogin")) + { + user.getBase().setFallDistance(0); + if (LocationUtil.shouldFly(user.getLocation())) + { + user.getBase().setAllowFlight(true); + user.getBase().setFlying(true); + user.getBase().sendMessage(tl("flyMode", tl("enabled"), user.getDisplayName())); + } + } + + if (!user.isAuthorized("essentials.speed")) + { + user.getBase().setFlySpeed(0.1f); + user.getBase().setWalkSpeed(0.2f); + } + + user.stopTransaction(); + } + } + + ess.scheduleSyncDelayedTask(new DelayJoinTask()); + } + + // Makes the compass item ingame always point to the first essentials home. #EasterEgg + private void updateCompass(final User user) + { + Location loc = user.getHome(user.getLocation()); + if (loc == null) + { + loc = user.getBase().getBedSpawnLocation(); + } + if (loc != null) + { + final Location updateLoc = loc; + user.getBase().setCompassTarget(updateLoc); + } + } + + @EventHandler(priority = EventPriority.HIGH) + public void onPlayerLogin(final PlayerLoginEvent event) + { + switch (event.getResult()) + { + case KICK_FULL: + final User kfuser = ess.getUser(event.getPlayer()); + if (kfuser.isAuthorized("essentials.joinfullserver")) + { + event.allow(); + return; + } + event.disallow(Result.KICK_FULL, tl("serverFull")); + break; + default: + break; + } + } + + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void onPlayerTeleport(final PlayerTeleportEvent event) + { + final boolean backListener = ess.getSettings().registerBackInListener(); + final boolean teleportInvulnerability = ess.getSettings().isTeleportInvulnerability(); + if (backListener || teleportInvulnerability) + { + final User user = ess.getUser(event.getPlayer()); + //There is TeleportCause.COMMMAND but plugins have to actively pass the cause in on their teleports. + if (backListener && (event.getCause() == TeleportCause.PLUGIN || event.getCause() == TeleportCause.COMMAND)) + { + user.setLastLocation(); + } + if (teleportInvulnerability && (event.getCause() == TeleportCause.PLUGIN || event.getCause() == TeleportCause.COMMAND)) + { + user.enableInvulnerabilityAfterTeleport(); + } + } + } + + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void onPlayerEggThrow(final PlayerEggThrowEvent event) + { + final User user = ess.getUser(event.getPlayer()); + final ItemStack stack = new ItemStack(Material.EGG, 1); + if (user.hasUnlimited(stack)) + { + user.getBase().getInventory().addItem(stack); + user.getBase().updateInventory(); + } + } + + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void onPlayerBucketEmpty(final PlayerBucketEmptyEvent event) + { + final User user = ess.getUser(event.getPlayer()); + if (user.hasUnlimited(new ItemStack(event.getBucket()))) + { + event.getItemStack().setType(event.getBucket()); + ess.scheduleSyncDelayedTask(new Runnable() + { + @Override + public void run() + { + user.getBase().updateInventory(); + } + }); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlayerCommandPreprocess(final PlayerCommandPreprocessEvent event) + { + final Player player = event.getPlayer(); + final String cmd = event.getMessage().toLowerCase(Locale.ENGLISH).split(" ")[0].replace("/", "").toLowerCase(Locale.ENGLISH); + if (ess.getSettings().getSocialSpyCommands().contains(cmd) || ess.getSettings().getSocialSpyCommands().contains("*")) + { + for (User spyer : ess.getOnlineUsers()) + { + if (spyer.isSocialSpyEnabled() && !player.equals(spyer.getBase())) + { + spyer.sendMessage(player.getDisplayName() + " : " + event.getMessage()); + } + } + } + else if (!cmd.equalsIgnoreCase("afk")) + { + final User user = ess.getUser(player); + user.updateActivity(true); + } + } + + @EventHandler(priority = EventPriority.NORMAL) + public void onPlayerChangedWorldFlyReset(final PlayerChangedWorldEvent event) + { + final User user = ess.getUser(event.getPlayer()); + if (user.getBase().getGameMode() != GameMode.CREATIVE && !user.isAuthorized("essentials.fly")) + { + user.getBase().setFallDistance(0f); + user.getBase().setAllowFlight(false); + } + if (!user.isAuthorized("essentials.speed")) + { + user.getBase().setFlySpeed(0.1f); + user.getBase().setWalkSpeed(0.2f); + } + else + { + if (user.getBase().getFlySpeed() > ess.getSettings().getMaxFlySpeed() && !user.isAuthorized("essentials.speed.bypass")) + { + user.getBase().setFlySpeed((float)ess.getSettings().getMaxFlySpeed()); + } + else + { + user.getBase().setFlySpeed(user.getBase().getFlySpeed() * 0.99999f); + } + + if (user.getBase().getWalkSpeed() > ess.getSettings().getMaxWalkSpeed() && !user.isAuthorized("essentials.speed.bypass")) + { + user.getBase().setWalkSpeed((float)ess.getSettings().getMaxWalkSpeed()); + } + else + { + user.getBase().setWalkSpeed(user.getBase().getWalkSpeed() * 0.99999f); + } + } + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onPlayerChangedWorld(final PlayerChangedWorldEvent event) + { + final User user = ess.getUser(event.getPlayer()); + final String newWorld = event.getPlayer().getLocation().getWorld().getName(); + user.setDisplayNick(); + updateCompass(user); + if (ess.getSettings().getNoGodWorlds().contains(newWorld) && user.isGodModeEnabledRaw()) + { + user.sendMessage(tl("noGodWorldWarning")); + } + + if (!user.getWorld().getName().equals(newWorld)) + { + user.sendMessage(tl("currentWorld", newWorld)); + } + if (user.isVanished()) + { + user.setVanished(user.isAuthorized("essentials.vanish")); + } + } + + @EventHandler(priority = EventPriority.NORMAL) + public void onPlayerInteract(final PlayerInteractEvent event) + { + switch (event.getAction()) + { + case RIGHT_CLICK_BLOCK: + if (!event.isCancelled() && event.getClickedBlock().getType() == Material.BED_BLOCK && ess.getSettings().getUpdateBedAtDaytime()) + { + User player = ess.getUser(event.getPlayer()); + if (player.isAuthorized("essentials.sethome.bed")) + { + player.getBase().setBedSpawnLocation(event.getClickedBlock().getLocation()); + player.sendMessage(tl("bedSet", player.getLocation().getWorld().getName(), player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ())); + } + } + break; + case LEFT_CLICK_AIR: + if (event.getPlayer().isFlying()) + { + final User user = ess.getUser(event.getPlayer()); + if (user.isFlyClickJump()) + { + useFlyClickJump(user); + return; + } + } + case LEFT_CLICK_BLOCK: + if (event.getItem() != null && event.getItem().getType() != Material.AIR) + { + final User user = ess.getUser(event.getPlayer()); + user.updateActivity(true); + if (user.hasPowerTools() && user.arePowerToolsEnabled() && usePowertools(user, event.getItem().getTypeId())) + { + event.setCancelled(true); + } + } + break; + default: + break; + } + } + + // This method allows the /jump lock feature to work, allows teleporting while flying #EasterEgg + private void useFlyClickJump(final User user) + { + try + { + final Location otarget = LocationUtil.getTarget(user.getBase()); + + class DelayedClickJumpTask implements Runnable + { + @Override + public void run() + { + Location loc = user.getLocation(); + loc.setX(otarget.getX()); + loc.setZ(otarget.getZ()); + while (LocationUtil.isBlockDamaging(loc.getWorld(), loc.getBlockX(), loc.getBlockY() - 1, loc.getBlockZ())) + { + loc.setY(loc.getY() + 1d); + } + user.getBase().teleport(loc, TeleportCause.PLUGIN); + } + } + ess.scheduleSyncDelayedTask(new DelayedClickJumpTask()); + } + catch (Exception ex) + { + if (ess.getSettings().isDebug()) + { + LOGGER.log(Level.WARNING, ex.getMessage(), ex); + } + } + } + + private boolean usePowertools(final User user, final int id) + { + final List commandList = user.getPowertool(id); + if (commandList == null || commandList.isEmpty()) + { + return false; + } + boolean used = false; + // We need to loop through each command and execute + for (final String command : commandList) + { + if (command.contains("{player}")) + { + continue; + } + else if (command.startsWith("c:")) + { + used = true; + user.getBase().chat(command.substring(2)); + } + else + { + used = true; + + class PowerToolUseTask implements Runnable + { + @Override + public void run() + { + user.getServer().dispatchCommand(user.getBase(), command); + LOGGER.log(Level.INFO, String.format("[PT] %s issued server command: /%s", user.getName(), command)); + } + } + ess.scheduleSyncDelayedTask(new PowerToolUseTask()); + + } + } + return used; + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onPlayerPickupItem(final PlayerPickupItemEvent event) + { + if (ess.getSettings().getDisableItemPickupWhileAfk()) + { + if (ess.getUser(event.getPlayer()).isAfk()) + { + event.setCancelled(true); + } + } + } + + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + public void onInventoryClickEvent(final InventoryClickEvent event) + { + Player refreshPlayer = null; + final Inventory top = event.getView().getTopInventory(); + final InventoryType type = top.getType(); + + if (type == InventoryType.PLAYER) + { + final User user = ess.getUser((Player)event.getWhoClicked()); + final InventoryHolder invHolder = top.getHolder(); + if (invHolder != null && invHolder instanceof HumanEntity) + { + final User invOwner = ess.getUser((Player)invHolder); + if (user.isInvSee() && (!user.isAuthorized("essentials.invsee.modify") + || invOwner.isAuthorized("essentials.invsee.preventmodify") + || !invOwner.getBase().isOnline())) + { + event.setCancelled(true); + refreshPlayer = user.getBase(); + } + } + } + else if (type == InventoryType.ENDER_CHEST) + { + final User user = ess.getUser((Player)event.getWhoClicked()); + if (user.isEnderSee() && (!user.isAuthorized("essentials.enderchest.modify"))) + { + event.setCancelled(true); + refreshPlayer = user.getBase(); + } + } + else if (type == InventoryType.WORKBENCH) + { + User user = ess.getUser((Player)event.getWhoClicked()); + if (user.isRecipeSee()) + { + event.setCancelled(true); + refreshPlayer = user.getBase(); + } + } + else if (type == InventoryType.CHEST && top.getSize() == 9) + { + final User user = ess.getUser((Player)event.getWhoClicked()); + final InventoryHolder invHolder = top.getHolder(); + if (invHolder != null && invHolder instanceof HumanEntity && user.isInvSee()) + { + event.setCancelled(true); + refreshPlayer = user.getBase(); + } + } + + if (refreshPlayer != null) + { + final Player player = refreshPlayer; + ess.scheduleSyncDelayedTask(new Runnable() + { + @Override + public void run() + { + player.updateInventory(); + } + }, 1); + } + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onInventoryCloseEvent(final InventoryCloseEvent event) + { + Player refreshPlayer = null; + final Inventory top = event.getView().getTopInventory(); + final InventoryType type = top.getType(); + if (type == InventoryType.PLAYER) + { + final User user = ess.getUser((Player)event.getPlayer()); + user.setInvSee(false); + refreshPlayer = user.getBase(); + } + else if (type == InventoryType.ENDER_CHEST) + { + final User user = ess.getUser((Player)event.getPlayer()); + user.setEnderSee(false); + refreshPlayer = user.getBase(); + } + else if (type == InventoryType.WORKBENCH) + { + final User user = ess.getUser((Player)event.getPlayer()); + if (user.isRecipeSee()) + { + user.setRecipeSee(false); + event.getView().getTopInventory().clear(); + refreshPlayer = user.getBase(); + } + } + else if (type == InventoryType.CHEST && top.getSize() == 9) + { + final InventoryHolder invHolder = top.getHolder(); + if (invHolder != null && invHolder instanceof HumanEntity) + { + final User user = ess.getUser((Player)event.getPlayer()); + user.setInvSee(false); + refreshPlayer = user.getBase(); + } + } + + if (refreshPlayer != null) + { + final Player player = refreshPlayer; + ess.scheduleSyncDelayedTask(new Runnable() + { + @Override + public void run() + { + player.updateInventory(); + } + }, 1); + } + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onPlayerFishEvent(final PlayerFishEvent event) + { + final User user = ess.getUser(event.getPlayer()); + user.updateActivity(true); + } +} diff --git a/Essentials/src/com/earth2me/essentials/EssentialsPluginListener.java b/Essentials/src/com/earth2me/essentials/EssentialsPluginListener.java new file mode 100644 index 0000000000..e917d2ec3e --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/EssentialsPluginListener.java @@ -0,0 +1,65 @@ +package com.earth2me.essentials; + +import com.earth2me.essentials.perm.PermissionsHandler; +import com.earth2me.essentials.register.payment.Methods; +import java.util.logging.Level; +import net.ess3.api.IEssentials; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.server.PluginDisableEvent; +import org.bukkit.event.server.PluginEnableEvent; + + +public class EssentialsPluginListener implements Listener, IConf +{ + private final transient IEssentials ess; + + public EssentialsPluginListener(final IEssentials ess) + { + this.ess = ess; + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onPluginEnable(final PluginEnableEvent event) + { + if (event.getPlugin().getName().equals("EssentialsChat")) + { + ess.getSettings().setEssentialsChatActive(true); + } + ess.getPermissionsHandler().checkPermissions(); + ess.getAlternativeCommandsHandler().addPlugin(event.getPlugin()); + if (!Methods.hasMethod() && Methods.setMethod(ess.getServer().getPluginManager())) + { + ess.getLogger().log(Level.INFO, "Payment method found (" + Methods.getMethod().getLongName() + " version: " + ess.getPaymentMethod().getMethod().getVersion() + ")"); + } + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onPluginDisable(final PluginDisableEvent event) + { + if (event.getPlugin().getName().equals("EssentialsChat")) + { + ess.getSettings().setEssentialsChatActive(false); + } + PermissionsHandler permHandler = ess.getPermissionsHandler(); + if (permHandler != null) + { + permHandler.checkPermissions(); + } + ess.getAlternativeCommandsHandler().removePlugin(event.getPlugin()); + // Check to see if the plugin thats being disabled is the one we are using + if (ess.getPaymentMethod() != null && Methods.hasMethod() && Methods.checkDisabled(event.getPlugin())) + { + ess.getPaymentMethod().reset(); + ess.getLogger().log(Level.INFO, "Payment method was disabled. No longer accepting payments."); + } + } + + @Override + public void reloadConfig() + { + ess.getPermissionsHandler().setUseSuperperms(ess.getSettings().useBukkitPermissions()); + ess.getPermissionsHandler().checkPermissions(); + } +} diff --git a/Essentials/src/com/earth2me/essentials/EssentialsTimer.java b/Essentials/src/com/earth2me/essentials/EssentialsTimer.java new file mode 100644 index 0000000000..8f75445e2d --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/EssentialsTimer.java @@ -0,0 +1,125 @@ +package com.earth2me.essentials; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Set; +import java.util.UUID; +import java.util.logging.Level; +import net.ess3.api.IEssentials; +import org.bukkit.entity.Player; + + +public class EssentialsTimer implements Runnable +{ + private final transient IEssentials ess; + private final transient Set onlineUsers = new HashSet(); + private transient long lastPoll = System.nanoTime(); + private final LinkedList history = new LinkedList(); + private int skip1 = 0; + private int skip2 = 0; + private final long maxTime = 10 * 1000000; + private final long tickInterval = 50; + + EssentialsTimer(final IEssentials ess) + { + this.ess = ess; + history.add(20d); + } + + @Override + public void run() + { + final long startTime = System.nanoTime(); + final long currentTime = System.currentTimeMillis(); + long timeSpent = (startTime - lastPoll) / 1000; + if (timeSpent == 0) + { + timeSpent = 1; + } + if (history.size() > 10) + { + history.remove(); + } + double tps = tickInterval * 1000000.0 / timeSpent; + if (tps <= 21) + { + history.add(tps); + } + lastPoll = startTime; + int count = 0; + for (Player player : ess.getOnlinePlayers()) + { + count++; + if (skip1 > 0) + { + skip1--; + continue; + } + if (count % 10 == 0) + { + if (System.nanoTime() - startTime > maxTime / 2) + { + skip1 = count - 1; + break; + } + } + try + { + final User user = ess.getUser(player); + onlineUsers.add(user.getBase().getUniqueId()); + user.setLastOnlineActivity(currentTime); + user.checkActivity(); + } + catch (Exception e) + { + ess.getLogger().log(Level.WARNING, "EssentialsTimer Error:", e); + } + } + + count = 0; + final Iterator iterator = onlineUsers.iterator(); + while (iterator.hasNext()) + { + count++; + if (skip2 > 0) + { + skip2--; + continue; + } + if (count % 10 == 0) + { + if (System.nanoTime() - startTime > maxTime) + { + skip2 = count - 1; + break; + } + } + final User user = ess.getUser(iterator.next()); + if (user.getLastOnlineActivity() < currentTime && user.getLastOnlineActivity() > user.getLastLogout()) + { + if (!user.isHidden()) { + user.setLastLogout(user.getLastOnlineActivity()); + } + iterator.remove(); + continue; + } + user.checkMuteTimeout(currentTime); + user.checkJailTimeout(currentTime); + user.resetInvulnerabilityAfterTeleport(); + } + } + + public double getAverageTPS() + { + double avg = 0; + for (Double f : history) + { + if (f != null) + { + avg += f; + } + } + return avg / history.size(); + } +} diff --git a/Essentials/src/com/earth2me/essentials/EssentialsUpgrade.java b/Essentials/src/com/earth2me/essentials/EssentialsUpgrade.java new file mode 100644 index 0000000000..41834bd766 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/EssentialsUpgrade.java @@ -0,0 +1,847 @@ +package com.earth2me.essentials; + +import com.earth2me.essentials.craftbukkit.BanLookup; +import com.earth2me.essentials.craftbukkit.FakeWorld; +import com.earth2me.essentials.settings.Spawns; +import com.earth2me.essentials.storage.YamlStorageWriter; +import com.earth2me.essentials.utils.StringUtil; +import com.google.common.base.Charsets; +import net.ess3.api.IEssentials; +import org.bukkit.BanList; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; + +import javax.net.ssl.HttpsURLConnection; +import java.io.*; +import java.math.BigInteger; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static com.earth2me.essentials.I18n.tl; + + +public class EssentialsUpgrade +{ + private final static Logger LOGGER = Logger.getLogger("Essentials"); + private final transient IEssentials ess; + private final transient EssentialsConf doneFile; + + EssentialsUpgrade(final IEssentials essentials) + { + ess = essentials; + if (!ess.getDataFolder().exists()) + { + ess.getDataFolder().mkdirs(); + } + doneFile = new EssentialsConf(new File(ess.getDataFolder(), "upgrades-done.yml")); + doneFile.load(); + } + + private void moveMotdRulesToFile(String name) + { + if (doneFile.getBoolean("move" + name + "ToFile", false)) + { + return; + } + try + { + final File file = new File(ess.getDataFolder(), name + ".txt"); + if (file.exists()) + { + return; + } + final File configFile = new File(ess.getDataFolder(), "config.yml"); + if (!configFile.exists()) + { + return; + } + final EssentialsConf conf = new EssentialsConf(configFile); + conf.load(); + List lines = conf.getStringList(name); + if (lines != null && !lines.isEmpty()) + { + if (!file.createNewFile()) + { + throw new IOException("Failed to create file " + file); + } + PrintWriter writer = new PrintWriter(file); + + for (String line : lines) + { + writer.println(line); + } + writer.close(); + } + doneFile.setProperty("move" + name + "ToFile", true); + doneFile.save(); + } + catch (IOException e) + { + LOGGER.log(Level.SEVERE, tl("upgradingFilesError"), e); + } + } + + private void removeLinesFromConfig(File file, String regex, String info) throws Exception + { + boolean needUpdate = false; + final BufferedReader bReader = new BufferedReader(new FileReader(file)); + final File tempFile = File.createTempFile("essentialsupgrade", ".tmp.yml", ess.getDataFolder()); + final BufferedWriter bWriter = new BufferedWriter(new FileWriter(tempFile)); + do + { + final String line = bReader.readLine(); + if (line == null) + { + break; + } + if (line.matches(regex)) + { + if (!needUpdate && info != null) + { + bWriter.write(info, 0, info.length()); + bWriter.newLine(); + } + needUpdate = true; + } + else + { + if (line.endsWith("\r\n")) + { + bWriter.write(line, 0, line.length() - 2); + } + else if (line.endsWith("\r") || line.endsWith("\n")) + { + bWriter.write(line, 0, line.length() - 1); + } + else + { + bWriter.write(line, 0, line.length()); + } + bWriter.newLine(); + } + } + while (true); + bReader.close(); + bWriter.close(); + if (needUpdate) + { + if (!file.renameTo(new File(file.getParentFile(), file.getName().concat("." + System.currentTimeMillis() + ".upgradebackup")))) + { + throw new Exception(tl("configFileMoveError")); + } + if (!tempFile.renameTo(file)) + { + throw new Exception(tl("configFileRenameError")); + } + } + else + { + tempFile.delete(); + } + } + + private void updateUsersPowerToolsFormat() + { + if (doneFile.getBoolean("updateUsersPowerToolsFormat", false)) + { + return; + } + final File userdataFolder = new File(ess.getDataFolder(), "userdata"); + if (!userdataFolder.exists() || !userdataFolder.isDirectory()) + { + return; + } + final File[] userFiles = userdataFolder.listFiles(); + + for (File file : userFiles) + { + if (!file.isFile() || !file.getName().endsWith(".yml")) + { + continue; + } + final EssentialsConf config = new EssentialsConf(file); + try + { + config.load(); + if (config.hasProperty("powertools")) + { + @SuppressWarnings("unchecked") + final Map powertools = config.getConfigurationSection("powertools").getValues(false); + if (powertools == null) + { + continue; + } + for (Map.Entry entry : powertools.entrySet()) + { + if (entry.getValue() instanceof String) + { + List temp = new ArrayList(); + temp.add((String)entry.getValue()); + ((Map)powertools).put(entry.getKey(), temp); + } + } + config.forceSave(); + } + } + catch (RuntimeException ex) + { + LOGGER.log(Level.INFO, "File: " + file.toString()); + throw ex; + } + } + doneFile.setProperty("updateUsersPowerToolsFormat", true); + doneFile.save(); + } + + private void updateUsersHomesFormat() + { + if (doneFile.getBoolean("updateUsersHomesFormat", false)) + { + return; + } + final File userdataFolder = new File(ess.getDataFolder(), "userdata"); + if (!userdataFolder.exists() || !userdataFolder.isDirectory()) + { + return; + } + final File[] userFiles = userdataFolder.listFiles(); + + for (File file : userFiles) + { + if (!file.isFile() || !file.getName().endsWith(".yml")) + { + continue; + } + final EssentialsConf config = new EssentialsConf(file); + try + { + + config.load(); + if (config.hasProperty("home") && config.hasProperty("home.default")) + { + @SuppressWarnings("unchecked") + final String defworld = (String)config.getProperty("home.default"); + final Location defloc = getFakeLocation(config, "home.worlds." + defworld); + if (defloc != null) + { + config.setProperty("homes.home", defloc); + } + + Set worlds = config.getConfigurationSection("home.worlds").getKeys(false); + Location loc; + String worldName; + + if (worlds == null) + { + continue; + } + for (String world : worlds) + { + if (defworld.equalsIgnoreCase(world)) + { + continue; + } + loc = getFakeLocation(config, "home.worlds." + world); + if (loc == null) + { + continue; + } + worldName = loc.getWorld().getName().toLowerCase(Locale.ENGLISH); + if (worldName != null && !worldName.isEmpty()) + { + config.setProperty("homes." + worldName, loc); + } + } + config.removeProperty("home"); + config.forceSave(); + } + + } + catch (RuntimeException ex) + { + LOGGER.log(Level.INFO, "File: " + file.toString()); + throw ex; + } + } + doneFile.setProperty("updateUsersHomesFormat", true); + doneFile.save(); + } + + private void sanitizeAllUserFilenames() + { + if (doneFile.getBoolean("sanitizeAllUserFilenames", false)) + { + return; + } + final File usersFolder = new File(ess.getDataFolder(), "userdata"); + if (!usersFolder.exists()) + { + return; + } + final File[] listOfFiles = usersFolder.listFiles(); + for (File listOfFile : listOfFiles) + { + final String filename = listOfFile.getName(); + if (!listOfFile.isFile() || !filename.endsWith(".yml")) + { + continue; + } + final String sanitizedFilename = StringUtil.sanitizeFileName(filename.substring(0, filename.length() - 4)) + ".yml"; + if (sanitizedFilename.equals(filename)) + { + continue; + } + final File tmpFile = new File(listOfFile.getParentFile(), sanitizedFilename + ".tmp"); + final File newFile = new File(listOfFile.getParentFile(), sanitizedFilename); + if (!listOfFile.renameTo(tmpFile)) + { + LOGGER.log(Level.WARNING, tl("userdataMoveError", filename, sanitizedFilename)); + continue; + } + if (newFile.exists()) + { + LOGGER.log(Level.WARNING, tl("duplicatedUserdata", filename, sanitizedFilename)); + continue; + } + if (!tmpFile.renameTo(newFile)) + { + LOGGER.log(Level.WARNING, tl("userdataMoveBackError", sanitizedFilename, sanitizedFilename)); + } + } + doneFile.setProperty("sanitizeAllUserFilenames", true); + doneFile.save(); + } + + private World getFakeWorld(final String name) + { + final File bukkitDirectory = ess.getDataFolder().getParentFile().getParentFile(); + final File worldDirectory = new File(bukkitDirectory, name); + if (worldDirectory.exists() && worldDirectory.isDirectory()) + { + return new FakeWorld(worldDirectory.getName(), World.Environment.NORMAL); + } + return null; + } + + public Location getFakeLocation(EssentialsConf config, String path) + { + String worldName = config.getString((path != null ? path + "." : "") + "world"); + if (worldName == null || worldName.isEmpty()) + { + return null; + } + World world = getFakeWorld(worldName); + if (world == null) + { + return null; + } + return new Location(world, + config.getDouble((path != null ? path + "." : "") + "x", 0), + config.getDouble((path != null ? path + "." : "") + "y", 0), + config.getDouble((path != null ? path + "." : "") + "z", 0), + (float)config.getDouble((path != null ? path + "." : "") + "yaw", 0), + (float)config.getDouble((path != null ? path + "." : "") + "pitch", 0)); + } + + private void deleteOldItemsCsv() + { + if (doneFile.getBoolean("deleteOldItemsCsv", false)) + { + return; + } + final File file = new File(ess.getDataFolder(), "items.csv"); + if (file.exists()) + { + try + { + final Set oldconfigs = new HashSet(); + oldconfigs.add(new BigInteger("66ec40b09ac167079f558d1099e39f10", 16)); // sep 1 + oldconfigs.add(new BigInteger("34284de1ead43b0bee2aae85e75c041d", 16)); // crlf + oldconfigs.add(new BigInteger("c33bc9b8ee003861611bbc2f48eb6f4f", 16)); // jul 24 + oldconfigs.add(new BigInteger("6ff17925430735129fc2a02f830c1daa", 16)); // crlf + + MessageDigest digest = ManagedFile.getDigest(); + final BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); + final DigestInputStream dis = new DigestInputStream(bis, digest); + final byte[] buffer = new byte[1024]; + try + { + while (dis.read(buffer) != -1) + { + } + } + finally + { + dis.close(); + } + + BigInteger hash = new BigInteger(1, digest.digest()); + if (oldconfigs.contains(hash) && !file.delete()) + { + throw new IOException("Could not delete file " + file.toString()); + } + doneFile.setProperty("deleteOldItemsCsv", true); + doneFile.save(); + } + catch (IOException ex) + { + Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex); + } + } + } + + private void updateSpawnsToNewSpawnsConfig() + { + if (doneFile.getBoolean("updateSpawnsToNewSpawnsConfig", false)) + { + return; + } + final File configFile = new File(ess.getDataFolder(), "spawn.yml"); + if (configFile.exists()) + { + + final EssentialsConf config = new EssentialsConf(configFile); + try + { + config.load(); + if (!config.hasProperty("spawns")) + { + final Spawns spawns = new Spawns(); + Set keys = config.getKeys(false); + for (String group : keys) + { + Location loc = getFakeLocation(config, group); + spawns.getSpawns().put(group.toLowerCase(Locale.ENGLISH), loc); + } + if (!configFile.renameTo(new File(ess.getDataFolder(), "spawn.yml.old"))) + { + throw new Exception(tl("fileRenameError", "spawn.yml")); + } + PrintWriter writer = new PrintWriter(configFile); + try + { + new YamlStorageWriter(writer).save(spawns); + } + finally + { + writer.close(); + } + } + } + catch (Exception ex) + { + Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex); + } + } + doneFile.setProperty("updateSpawnsToNewSpawnsConfig", true); + doneFile.save(); + } + + private void updateJailsToNewJailsConfig() + { + if (doneFile.getBoolean("updateJailsToNewJailsConfig", false)) + { + return; + } + final File configFile = new File(ess.getDataFolder(), "jail.yml"); + if (configFile.exists()) + { + + final EssentialsConf config = new EssentialsConf(configFile); + try + { + config.load(); + if (!config.hasProperty("jails")) + { + final com.earth2me.essentials.settings.Jails jails = new com.earth2me.essentials.settings.Jails(); + Set keys = config.getKeys(false); + for (String jailName : keys) + { + Location loc = getFakeLocation(config, jailName); + jails.getJails().put(jailName.toLowerCase(Locale.ENGLISH), loc); + } + if (!configFile.renameTo(new File(ess.getDataFolder(), "jail.yml.old"))) + { + throw new Exception(tl("fileRenameError", "jail.yml")); + } + PrintWriter writer = new PrintWriter(configFile); + try + { + new YamlStorageWriter(writer).save(jails); + } + finally + { + writer.close(); + } + } + } + catch (Exception ex) + { + Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex); + } + } + doneFile.setProperty("updateJailsToNewJailsConfig", true); + doneFile.save(); + } + + private void warnMetrics() + { + if (doneFile.getBoolean("warnMetrics", false)) + { + return; + } + ess.getSettings().setMetricsEnabled(false); + doneFile.setProperty("warnMetrics", true); + doneFile.save(); + } + + private void uuidFileChange() + { + if (doneFile.getBoolean("uuidFileChange", false)) + { + return; + } + + Boolean ignoreUFCache = doneFile.getBoolean("ignore-userfiles-cache", false); + + ess.getLogger().info("#### Starting Essentials UUID userdata conversion in a few seconds. ####"); // TODO TL + ess.getLogger().info("We recommend you take a backup of your server before upgrading from the old username system."); + + try + { + Thread.sleep(15000); + } + catch (InterruptedException ex) + { + // NOOP + } + + uuidFileConvert(ess, ignoreUFCache); + + doneFile.setProperty("uuidFileChange", true); + doneFile.save(); + } + + public static void uuidFileConvert(IEssentials ess, Boolean ignoreUFCache) + { + ess.getLogger().info("Starting Essentials UUID userdata conversion"); // TODO TL + final File userdir = new File(ess.getDataFolder(), "userdata"); + if (!userdir.exists()) + { + return; + } + + List toConvert = new ArrayList(); + for (String string : userdir.list()) + { + if (!string.endsWith(".yml") || string.length() < 5) + { + continue; + } + + final String name = string.substring(0, string.length() - 4); + + try + { + UUID.fromString(name); + } + catch (IllegalArgumentException ex) + { + toConvert.add(name); + } + } + + int countFiles = 0; + int countFails = 0; + int countEssCache = 0; + int countMojang = 0; + + int countTotal = toConvert.size(); + if (countTotal == 0) + { + ess.getLogger().info("Nothing to do!"); + return; + } + + List converted = new ArrayList(); + // Attempt as many from cache as possible first + for (int i = 0; i < countTotal; i++) + { + final String name = toConvert.get(i); + EssentialsConf conf = new EssentialsConf(new File(userdir, name + ".yml")); + conf.load(); + conf.setProperty("lastAccountName", name); + + String uuidstr = conf.getString(ignoreUFCache ? "force-uuid" : "uuid"); + + UUID uuid = null; + try + { + uuid = UUID.fromString(uuidstr); + countEssCache++; + } + catch (Exception e) + { + if (conf.getBoolean("npc", false)) + { + uuid = UUID.nameUUIDFromBytes(("NPC:" + name).getBytes(Charsets.UTF_8)); + countEssCache++; + } + } + + conf.forceSave(); + if (uuid != null) + { + EssentialsUserConf config = new EssentialsUserConf(name, uuid, new File(uuid + ".yml")); + config.convertLegacyFile(); + ess.getUserMap().trackUUID(uuid, name, false); + + converted.add(name); + } + } + + for (String s : converted) + { + toConvert.remove(s); + } + + converted.clear(); + + ess.getLogger().info("Converted " + countEssCache + " files from cache. Now converting " + toConvert.size() + " files using Mojang API"); // TODO TL + + Matcher matcher = Pattern.compile("([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]+)").matcher(""); + + ess.getLogger().info("We estimate that this operation will take " + Math.ceil((toConvert.size() / 60000) * 15) + "minutes due to API restrictions."); // TODO TL + + for (int i = 0; i < toConvert.size(); i += 100) + { + final int end = Math.min(i + 99, countTotal); + List toQuery = toConvert.subList(i, end); + ess.getLogger().info(String.format("Converting files %d to %d (%d files)", i + 1, end, toQuery.size())); // TODO TL + + JSONArray payload = new JSONArray(); + for (String name : toQuery) + { + payload.add(name); + } + + try + { + HttpsURLConnection connection = (HttpsURLConnection) new URL("https://api.mojang.com/profiles/minecraft").openConnection(); + connection.setRequestMethod("POST"); + connection.addRequestProperty("Content-Type", "application/json"); + connection.setDoOutput(true); + + PrintWriter writer = new PrintWriter(connection.getOutputStream()); + writer.print(payload); + writer.flush(); + writer.close(); + + int response = connection.getResponseCode(); + if (response != 200) + { + ess.getLogger().severe("Got error " + response + " - " + connection.getResponseMessage() + " from API"); // TODO better handling + if (response == 429) + { + ess.getLogger().severe("Too many requests sent to Mojang Server. Waiting 1 minute then trying again."); + i -= 100; + try + { + Thread.sleep(60000); + } + catch (InterruptedException e) + { + + } + continue; + } + return; + } + + JSONArray obj = (JSONArray) JSONValue.parse(new InputStreamReader(connection.getInputStream())); + + for (Object object : obj) + { + JSONObject jsonObject = (JSONObject) object; + + String name = ((String)jsonObject.get("name")).toLowerCase(); + String id = (String)jsonObject.get("id"); + + id = matcher.reset(id).replaceAll("$1-$2-$3-$4-$5"); + + UUID uuid = UUID.fromString(id); + + + EssentialsUserConf conf = new EssentialsUserConf(name, uuid, new File(userdir, StringUtil.sanitizeFileName(name) + ".yml")); + conf.convertLegacyFile(); + ess.getUserMap().trackUUID(uuid, name, false); + converted.add(name); + countMojang++; + } + + System.out.println(obj); + } + catch (MalformedURLException e) + { + e.printStackTrace(); + return; + } + catch (IOException e) + { // TODO Better handling + e.printStackTrace(); + return; + } + + try + { + Thread.sleep(1000); + } + catch (InterruptedException e) + { + + } + } + + for (String s : converted) + { + toConvert.remove(s); + } + + converted.clear(); + + ess.getUserMap().getUUIDMap().forceWriteUUIDMap(); + + ess.getLogger().info("Converted " + (countTotal - toConvert.size()) + "/" + countTotal + ". Conversion complete."); + ess.getLogger().info("Converted via cache: " + countEssCache + " :: Converted via lookup: " + countMojang + " :: Failed to convert: " + toConvert.size()); + ess.getLogger().info("To rerun the conversion type /essentials uuidconvert"); + } + + public void banFormatChange() + { + if (doneFile.getBoolean("banFormatChange", false)) + { + return; + } + + ess.getLogger().info("Starting Essentials ban format conversion"); + + final File userdir = new File(ess.getDataFolder(), "userdata"); + if (!userdir.exists()) + { + return; + } + + int countFiles = 0; + + ess.getLogger().info("Found " + userdir.list().length + " files to convert..."); + + for (String string : userdir.list()) + { + if (!string.endsWith(".yml") || string.length() < 5) + { + continue; + } + + final int showProgress = countFiles % 250; + + if (showProgress == 0) + { + ess.getLogger().info("Converted " + countFiles + "/" + userdir.list().length); + } + + countFiles++; + final File pFile = new File(userdir, string); + final EssentialsConf conf = new EssentialsConf(pFile); + conf.load(); + + String banReason; + Long banTimeout; + + try + { + banReason = conf.getConfigurationSection("ban").getString("reason"); + } + catch (NullPointerException n) + { + banReason = null; + } + + final String playerName = conf.getString("lastAccountName"); + if (playerName != null && playerName.length() > 1 && banReason != null && banReason.length() > 1) + { + try + { + if (conf.getConfigurationSection("ban").contains("timeout")) + { + banTimeout = Long.parseLong(conf.getConfigurationSection("ban").getString("timeout")); + } + else + { + banTimeout = 0L; + } + } + catch (NumberFormatException n) + { + banTimeout = 0L; + } + + if (BanLookup.isBanned(ess, playerName)) + { + updateBan(playerName, banReason, banTimeout); + } + } + conf.removeProperty("ban"); + conf.save(); + } + + doneFile.setProperty("banFormatChange", true); + doneFile.save(); + ess.getLogger().info("Ban format update complete."); + } + + private void updateBan(String playerName, String banReason, Long banTimeout) + { + if (banTimeout == 0) + { + Bukkit.getBanList(BanList.Type.NAME).addBan(playerName, banReason, null, Console.NAME); + } + else + { + Bukkit.getBanList(BanList.Type.NAME).addBan(playerName, banReason, new Date(banTimeout), Console.NAME); + } + } + + public void beforeSettings() + { + if (!ess.getDataFolder().exists()) + { + ess.getDataFolder().mkdirs(); + } + moveMotdRulesToFile("motd"); + moveMotdRulesToFile("rules"); + } + + public void afterSettings() + { + sanitizeAllUserFilenames(); + updateUsersPowerToolsFormat(); + updateUsersHomesFormat(); + deleteOldItemsCsv(); + updateSpawnsToNewSpawnsConfig(); + updateJailsToNewJailsConfig(); + uuidFileChange(); + banFormatChange(); + warnMetrics(); + } +} diff --git a/Essentials/src/com/earth2me/essentials/EssentialsUserConf.java b/Essentials/src/com/earth2me/essentials/EssentialsUserConf.java new file mode 100644 index 0000000000..cbfba46b18 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/EssentialsUserConf.java @@ -0,0 +1,76 @@ +package com.earth2me.essentials; + +import com.google.common.base.Charsets; +import com.google.common.io.Files; +import java.io.File; +import java.io.IOException; +import java.util.Locale; +import java.util.UUID; +import java.util.logging.Level; +import org.bukkit.Bukkit; + + +public class EssentialsUserConf extends EssentialsConf +{ + public final String username; + public final UUID uuid; + + public EssentialsUserConf(final String username, final UUID uuid, final File configFile) + { + super(configFile); + this.username = username; + this.uuid = uuid; + } + + @Override + public boolean legacyFileExists() + { + final File file = new File(configFile.getParentFile(), username + ".yml"); + return file.exists(); + } + + @Override + public void convertLegacyFile() + { + final File file = new File(configFile.getParentFile(), username + ".yml"); + try + { + Files.move(file, new File(configFile.getParentFile(), uuid + ".yml")); + } + catch (IOException ex) + { + Bukkit.getLogger().log(Level.WARNING, "Failed to migrate user: " + username, ex); + } + + setProperty("lastAccountName", username); + } + + private File getAltFile() + { + final UUID fn = UUID.nameUUIDFromBytes(("OfflinePlayer:" + username.toLowerCase(Locale.ENGLISH)).getBytes(Charsets.UTF_8)); + return new File(configFile.getParentFile(), fn.toString() + ".yml"); + } + + @Override + public boolean altFileExists() + { + if (username.equals(username.toLowerCase())) + { + return false; + } + return getAltFile().exists(); + } + + @Override + public void convertAltFile() + { + try + { + Files.move(getAltFile(), new File(configFile.getParentFile(), uuid + ".yml")); + } + catch (IOException ex) + { + Bukkit.getLogger().log(Level.WARNING, "Failed to migrate user: " + username, ex); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/ExecuteTimer.java b/Essentials/src/com/earth2me/essentials/ExecuteTimer.java new file mode 100644 index 0000000000..f9da468b5a --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/ExecuteTimer.java @@ -0,0 +1,89 @@ +package com.earth2me.essentials; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + + +public class ExecuteTimer +{ + private final transient List times; + private final transient DecimalFormat decimalFormat = new DecimalFormat("#0.000", DecimalFormatSymbols.getInstance(Locale.US)); + + + public ExecuteTimer() + { + times = new ArrayList(); + } + + public void start() + { + times.clear(); + mark("start"); + + } + + public void mark(final String label) + { + if (!times.isEmpty() || "start".equals(label)) + { + times.add(new ExecuteRecord(label, System.nanoTime())); + } + } + + public String end() + { + final StringBuilder output = new StringBuilder(); + output.append("execution time: "); + String mark; + long time0 = 0; + long time1 = 0; + long time2 = 0; + double duration; + + for (ExecuteRecord pair : times) + { + mark = (String)pair.getMark(); + time2 = (Long)pair.getTime(); + if (time1 > 0) + { + duration = (time2 - time1)/1000000.0; + output.append(mark).append(": ").append(decimalFormat.format(duration)).append("ms - "); + } + else + { + time0 = time2; + } + time1 = time2; + } + duration = (time1 - time0)/1000000.0; + output.append("Total: ").append(decimalFormat.format(duration)).append("ms"); + times.clear(); + return output.toString(); + } + + + private static class ExecuteRecord + { + private final String mark; + private final long time; + + public ExecuteRecord(final String mark, final long time) + { + this.mark = mark; + this.time = time; + } + + public String getMark() + { + return mark; + } + + public long getTime() + { + return time; + } + } +} \ No newline at end of file diff --git a/Essentials/src/com/earth2me/essentials/I18n.java b/Essentials/src/com/earth2me/essentials/I18n.java new file mode 100644 index 0000000000..478b6b5d1c --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/I18n.java @@ -0,0 +1,218 @@ +package com.earth2me.essentials; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.text.MessageFormat; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Pattern; +import net.ess3.api.IEssentials; +import org.bukkit.Bukkit; + + +public class I18n implements net.ess3.api.II18n +{ + private static I18n instance; + private static final String MESSAGES = "messages"; + private final transient Locale defaultLocale = Locale.getDefault(); + private transient Locale currentLocale = defaultLocale; + private transient ResourceBundle customBundle; + private transient ResourceBundle localeBundle; + private final transient ResourceBundle defaultBundle; + private transient Map messageFormatCache = new HashMap(); + private final transient IEssentials ess; + private static final Pattern NODOUBLEMARK = Pattern.compile("''"); + private static final ResourceBundle NULL_BUNDLE = new ResourceBundle() + { + public Enumeration getKeys() + { + return null; + } + + protected Object handleGetObject(String key) + { + return null; + } + }; + + public I18n(final IEssentials ess) + { + this.ess = ess; + defaultBundle = ResourceBundle.getBundle(MESSAGES, Locale.ENGLISH); + localeBundle = defaultBundle; + customBundle = NULL_BUNDLE; + } + + public void onEnable() + { + instance = this; + } + + public void onDisable() + { + instance = null; + } + + @Override + public Locale getCurrentLocale() + { + return currentLocale; + } + + private String translate(final String string) + { + try + { + try + { + return customBundle.getString(string); + } + catch (MissingResourceException ex) + { + return localeBundle.getString(string); + } + } + catch (MissingResourceException ex) + { + Logger.getLogger("Essentials").log(Level.WARNING, String.format("Missing translation key \"%s\" in translation file %s", ex.getKey(), localeBundle.getLocale().toString()), ex); + return defaultBundle.getString(string); + } + } + + public static String tl(final String string, final Object... objects) + { + if (instance == null) + { + return ""; + } + if (objects.length == 0) + { + return NODOUBLEMARK.matcher(instance.translate(string)).replaceAll("'"); + } + else + { + return instance.format(string, objects); + } + } + + public String format(final String string, final Object... objects) + { + String format = translate(string); + MessageFormat messageFormat = messageFormatCache.get(format); + if (messageFormat == null) + { + try + { + messageFormat = new MessageFormat(format); + } + catch (IllegalArgumentException e) + { + ess.getLogger().log(Level.SEVERE, "Invalid Translation key for '" + string + "': " + e.getMessage()); + format = format.replaceAll("\\{(\\D*?)\\}", "\\[$1\\]"); + messageFormat = new MessageFormat(format); + } + messageFormatCache.put(format, messageFormat); + } + return messageFormat.format(objects); + } + + public void updateLocale(final String loc) + { + if (loc != null && !loc.isEmpty()) + { + final String[] parts = loc.split("[_\\.]"); + if (parts.length == 1) + { + currentLocale = new Locale(parts[0]); + } + if (parts.length == 2) + { + currentLocale = new Locale(parts[0], parts[1]); + } + if (parts.length == 3) + { + currentLocale = new Locale(parts[0], parts[1], parts[2]); + } + } + ResourceBundle.clearCache(); + messageFormatCache = new HashMap(); + Logger.getLogger("Essentials").log(Level.INFO, String.format("Using locale %s", currentLocale.toString())); + + try + { + localeBundle = ResourceBundle.getBundle(MESSAGES, currentLocale); + } + catch (MissingResourceException ex) + { + localeBundle = NULL_BUNDLE; + } + + try + { + customBundle = ResourceBundle.getBundle(MESSAGES, currentLocale, new FileResClassLoader(I18n.class.getClassLoader(), ess)); + } + catch (MissingResourceException ex) + { + customBundle = NULL_BUNDLE; + } + } + + public static String capitalCase(final String input) + { + return input == null || input.length() == 0 + ? input + : input.toUpperCase(Locale.ENGLISH).charAt(0) + + input.toLowerCase(Locale.ENGLISH).substring(1); + } + + + private static class FileResClassLoader extends ClassLoader + { + private final transient File dataFolder; + + FileResClassLoader(final ClassLoader classLoader, final IEssentials ess) + { + super(classLoader); + this.dataFolder = ess.getDataFolder(); + } + + @Override + public URL getResource(final String string) + { + final File file = new File(dataFolder, string); + if (file.exists()) + { + try + { + return file.toURI().toURL(); + } + catch (MalformedURLException ex) + { + } + } + return null; + } + + @Override + public InputStream getResourceAsStream(final String string) + { + final File file = new File(dataFolder, string); + if (file.exists()) + { + try + { + return new FileInputStream(file); + } + catch (FileNotFoundException ex) + { + } + } + return null; + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/IConf.java b/Essentials/src/com/earth2me/essentials/IConf.java new file mode 100644 index 0000000000..600c7ed48a --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/IConf.java @@ -0,0 +1,6 @@ +package com.earth2me.essentials; + +public interface IConf +{ + public void reloadConfig(); +} diff --git a/Essentials/src/com/earth2me/essentials/IEssentials.java b/Essentials/src/com/earth2me/essentials/IEssentials.java new file mode 100644 index 0000000000..3f6f057031 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/IEssentials.java @@ -0,0 +1,99 @@ +package com.earth2me.essentials; + +import com.earth2me.essentials.api.IItemDb; +import com.earth2me.essentials.api.IJails; +import com.earth2me.essentials.api.IWarps; +import com.earth2me.essentials.metrics.Metrics; +import com.earth2me.essentials.perm.PermissionsHandler; +import com.earth2me.essentials.register.payment.Methods; +import java.util.Collection; +import java.util.List; +import java.util.UUID; +import org.bukkit.World; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitScheduler; +import org.bukkit.scheduler.BukkitTask; + + +public interface IEssentials extends Plugin +{ + void addReloadListener(IConf listener); + + void reload(); + + boolean onCommandEssentials(CommandSender sender, Command command, String commandLabel, String[] args, ClassLoader classLoader, String commandPath, String permissionPrefix, IEssentialsModule module); + + @Deprecated + User getUser(Object base); + + User getUser(UUID base); + + User getUser(String base); + + User getUser(Player base); + + I18n getI18n(); + + User getOfflineUser(String name); + + World getWorld(String name); + + int broadcastMessage(String message); + + int broadcastMessage(IUser sender, String message); + + int broadcastMessage(String permission, String message); + + ISettings getSettings(); + + BukkitScheduler getScheduler(); + + IJails getJails(); + + IWarps getWarps(); + + Worth getWorth(); + + Backup getBackup(); + + Methods getPaymentMethod(); + + BukkitTask runTaskAsynchronously(Runnable run); + + BukkitTask runTaskLaterAsynchronously(Runnable run, long delay); + + BukkitTask runTaskTimerAsynchronously(Runnable run, long delay, long period); + + int scheduleSyncDelayedTask(Runnable run); + + int scheduleSyncDelayedTask(Runnable run, long delay); + + int scheduleSyncRepeatingTask(Runnable run, long delay, long period); + + TNTExplodeListener getTNTListener(); + + PermissionsHandler getPermissionsHandler(); + + AlternativeCommandsHandler getAlternativeCommandsHandler(); + + void showError(CommandSource sender, Throwable exception, String commandLabel); + + IItemDb getItemDb(); + + UserMap getUserMap(); + + Metrics getMetrics(); + + void setMetrics(Metrics metrics); + + EssentialsTimer getTimer(); + + List getVanishedPlayers(); + + Collection getOnlinePlayers(); + + Iterable getOnlineUsers(); +} diff --git a/Essentials/src/com/earth2me/essentials/IEssentialsModule.java b/Essentials/src/com/earth2me/essentials/IEssentialsModule.java new file mode 100644 index 0000000000..69a1a494c2 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/IEssentialsModule.java @@ -0,0 +1,6 @@ +package com.earth2me.essentials; + + +public interface IEssentialsModule +{ +} diff --git a/Essentials/src/com/earth2me/essentials/IReplyTo.java b/Essentials/src/com/earth2me/essentials/IReplyTo.java new file mode 100644 index 0000000000..ee8e80b4c2 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/IReplyTo.java @@ -0,0 +1,16 @@ +package com.earth2me.essentials; + +public interface IReplyTo +{ + /** + * Sets the user to reply to + * @param user + */ + public void setReplyTo(CommandSource user); + + /** + * Gets the user the sender should reply to + * @return + */ + public CommandSource getReplyTo(); +} diff --git a/Essentials/src/com/earth2me/essentials/ISettings.java b/Essentials/src/com/earth2me/essentials/ISettings.java new file mode 100644 index 0000000000..beab3574ab --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/ISettings.java @@ -0,0 +1,218 @@ +package com.earth2me.essentials; + +import com.earth2me.essentials.commands.IEssentialsCommand; +import com.earth2me.essentials.signs.EssentialsSign; +import com.earth2me.essentials.textreader.IText; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.bukkit.ChatColor; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.event.EventPriority; + + +public interface ISettings extends IConf +{ + boolean areSignsDisabled(); + + IText getAnnounceNewPlayerFormat(); + + boolean getAnnounceNewPlayers(); + + String getNewPlayerKit(); + + String getBackupCommand(); + + long getBackupInterval(); + + String getChatFormat(String group); + + int getChatRadius(); + + char getChatShout(); + + char getChatQuestion(); + + BigDecimal getCommandCost(IEssentialsCommand cmd); + + BigDecimal getCommandCost(String label); + + String getCurrencySymbol(); + + int getOversizedStackSize(); + + int getDefaultStackSize(); + + double getHealCooldown(); + + Set getSocialSpyCommands(); + + Map getKit(String name); + + ConfigurationSection getKits(); + + String getLocale(); + + String getNewbieSpawn(); + + String getNicknamePrefix(); + + ChatColor getOperatorColor() throws Exception; + + boolean getPerWarpPermission(); + + boolean getProtectBoolean(final String configName, boolean def); + + int getProtectCreeperMaxHeight(); + + List getProtectList(final String configName); + + boolean getProtectPreventSpawn(final String creatureName); + + String getProtectString(final String configName); + + boolean getRespawnAtHome(); + + Set getMultipleHomes(); + + int getHomeLimit(String set); + + int getHomeLimit(User user); + + int getSpawnMobLimit(); + + BigDecimal getStartingBalance(); + + boolean isTeleportSafetyEnabled(); + + double getTeleportCooldown(); + + double getTeleportDelay(); + + boolean hidePermissionlessHelp(); + + boolean isCommandDisabled(final IEssentialsCommand cmd); + + boolean isCommandDisabled(String label); + + boolean isCommandOverridden(String name); + + boolean isDebug(); + + boolean isEcoDisabled(); + + boolean isTradeInStacks(int id); + + List itemSpawnBlacklist(); + + List enabledSigns(); + + boolean permissionBasedItemSpawn(); + + boolean showNonEssCommandsInHelp(); + + boolean warnOnBuildDisallow(); + + boolean warnOnSmite(); + + BigDecimal getMaxMoney(); + + BigDecimal getMinMoney(); + + boolean isEcoLogEnabled(); + + boolean isEcoLogUpdateEnabled(); + + boolean removeGodOnDisconnect(); + + boolean changeDisplayName(); + + boolean changePlayerListName(); + + boolean isPlayerCommand(String string); + + boolean useBukkitPermissions(); + + boolean addPrefixSuffix(); + + boolean disablePrefix(); + + boolean disableSuffix(); + + long getAutoAfk(); + + long getAutoAfkKick(); + + boolean getFreezeAfkPlayers(); + + boolean cancelAfkOnMove(); + + boolean cancelAfkOnInteract(); + + boolean areDeathMessagesEnabled(); + + void setDebug(boolean debug); + + Set getNoGodWorlds(); + + boolean getUpdateBedAtDaytime(); + + boolean allowUnsafeEnchantments(); + + boolean getRepairEnchanted(); + + boolean isWorldTeleportPermissions(); + + boolean isWorldHomePermissions(); + + boolean registerBackInListener(); + + boolean getDisableItemPickupWhileAfk(); + + EventPriority getRespawnPriority(); + + long getTpaAcceptCancellation(); + + boolean isMetricsEnabled(); + + void setMetricsEnabled(boolean metricsEnabled); + + long getTeleportInvulnerability(); + + boolean isTeleportInvulnerability(); + + long getLoginAttackDelay(); + + int getSignUsePerSecond(); + + double getMaxFlySpeed(); + + double getMaxWalkSpeed(); + + int getMailsPerMinute(); + + long getEconomyLagWarning(); + + long getPermissionsLagWarning(); + + void setEssentialsChatActive(boolean b); + + long getMaxTempban(); + + Map getListGroupConfig(); + + int getMaxNickLength(); + + int getMaxUserCacheCount(); + + boolean allowSilentJoinQuit(); + + boolean isCustomJoinMessage(); + + String getCustomJoinMessage(); + + boolean isCustomQuitMessage(); + + String getCustomQuitMessage(); +} diff --git a/Essentials/src/com/earth2me/essentials/ITarget.java b/Essentials/src/com/earth2me/essentials/ITarget.java new file mode 100644 index 0000000000..87b867c130 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/ITarget.java @@ -0,0 +1,9 @@ +package com.earth2me.essentials; + +import org.bukkit.Location; + + +public interface ITarget +{ + public Location getLocation(); +} \ No newline at end of file diff --git a/Essentials/src/com/earth2me/essentials/IUser.java b/Essentials/src/com/earth2me/essentials/IUser.java new file mode 100644 index 0000000000..43e729e31c --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/IUser.java @@ -0,0 +1,144 @@ +package com.earth2me.essentials; + +import com.earth2me.essentials.commands.IEssentialsCommand; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; +import java.util.Set; +import net.ess3.api.ITeleport; +import net.ess3.api.MaxMoneyException; +import org.bukkit.Location; +import org.bukkit.entity.Player; + + +public interface IUser +{ + boolean isAuthorized(String node); + + boolean isAuthorized(IEssentialsCommand cmd); + + boolean isAuthorized(IEssentialsCommand cmd, String permissionPrefix); + + void healCooldown() throws Exception; + + void giveMoney(BigDecimal value) throws MaxMoneyException; + + void giveMoney(final BigDecimal value, final CommandSource initiator) throws MaxMoneyException; + + void payUser(final User reciever, final BigDecimal value) throws Exception; + + void takeMoney(BigDecimal value); + + void takeMoney(final BigDecimal value, final CommandSource initiator); + + boolean canAfford(BigDecimal value); + + Boolean canSpawnItem(final int itemId); + + void setLastLocation(); + + void setLogoutLocation(); + + void requestTeleport(final User player, final boolean here); + + ITeleport getTeleport(); + + BigDecimal getMoney(); + + void setMoney(final BigDecimal value) throws MaxMoneyException; + + void setAfk(final boolean set); + + /** + * 'Hidden' Represents when a player is hidden from others. This status includes when the player is hidden via other + * supported plugins. Use isVanished() if you want to check if a user is vanished by Essentials. + * + * @return If the user is hidden or not + * @see isVanished + */ + boolean isHidden(); + + void setHidden(boolean vanish); + + boolean isGodModeEnabled(); + + String getGroup(); + + boolean inGroup(final String group); + + boolean canBuild(); + + long getTeleportRequestTime(); + + void enableInvulnerabilityAfterTeleport(); + + void resetInvulnerabilityAfterTeleport(); + + boolean hasInvulnerabilityAfterTeleport(); + + /** + * 'Vanished' Represents when a player is hidden from others by Essentials. This status does NOT include when the + * player is hidden via other plugins. Use isHidden() if you want to check if a user is vanished by any supported + * plugin. + * + * @return If the user is vanished or not + * @see isHidden + */ + boolean isVanished(); + + void setVanished(boolean vanish); + + boolean isIgnoreExempt(); + + public void sendMessage(String message); + + /* + * UserData + */ + Location getHome(String name) throws Exception; + + Location getHome(Location loc) throws Exception; + + List getHomes(); + + void setHome(String name, Location loc); + + void delHome(String name) throws Exception; + + boolean hasHome(); + + Location getLastLocation(); + + Location getLogoutLocation(); + + long getLastTeleportTimestamp(); + + void setLastTeleportTimestamp(long time); + + String getJail(); + + void setJail(String jail); + + List getMails(); + + void addMail(String mail); + + boolean isAfk(); + + void setConfigProperty(String node, Object object); + + Set getConfigKeys(); + + Map getConfigMap(); + + Map getConfigMap(String node); + + /* + * PlayerExtension + */ + Player getBase(); + + CommandSource getSource(); + + public String getName(); +} diff --git a/Essentials/src/com/earth2me/essentials/ItemDb.java b/Essentials/src/com/earth2me/essentials/ItemDb.java new file mode 100644 index 0000000000..6d0b1725a1 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/ItemDb.java @@ -0,0 +1,313 @@ +package com.earth2me.essentials; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.utils.NumberUtil; +import com.earth2me.essentials.utils.StringUtil; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import net.ess3.api.IEssentials; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + + +public class ItemDb implements IConf, net.ess3.api.IItemDb +{ + private final transient IEssentials ess; + private final transient Map items = new HashMap(); + private final transient Map> names = new HashMap>(); + private final transient Map primaryName = new HashMap(); + private final transient Map durabilities = new HashMap(); + private final transient ManagedFile file; + private final transient Pattern splitPattern = Pattern.compile("((.*)[:+',;.](\\d+))"); + + public ItemDb(final IEssentials ess) + { + this.ess = ess; + file = new ManagedFile("items.csv", ess); + } + + @Override + public void reloadConfig() + { + final List lines = file.getLines(); + + if (lines.isEmpty()) + { + return; + } + + durabilities.clear(); + items.clear(); + names.clear(); + primaryName.clear(); + + for (String line : lines) + { + line = line.trim().toLowerCase(Locale.ENGLISH); + if (line.length() > 0 && line.charAt(0) == '#') + { + continue; + } + + final String[] parts = line.split("[^a-z0-9]"); + if (parts.length < 2) + { + continue; + } + + final int numeric = Integer.parseInt(parts[1]); + final short data = parts.length > 2 && !parts[2].equals("0") ? Short.parseShort(parts[2]) : 0; + String itemName = parts[0].toLowerCase(Locale.ENGLISH); + + durabilities.put(itemName, data); + items.put(itemName, numeric); + + ItemData itemData = new ItemData(numeric, data); + if (names.containsKey(itemData)) + { + List nameList = names.get(itemData); + nameList.add(itemName); + Collections.sort(nameList, new LengthCompare()); + } + else + { + List nameList = new ArrayList(); + nameList.add(itemName); + names.put(itemData, nameList); + primaryName.put(itemData, itemName); + } + } + } + + @Override + public ItemStack get(final String id, final int quantity) throws Exception + { + final ItemStack retval = get(id.toLowerCase(Locale.ENGLISH)); + retval.setAmount(quantity); + return retval; + } + + @Override + public ItemStack get(final String id) throws Exception + { + int itemid = 0; + String itemname = null; + short metaData = 0; + Matcher parts = splitPattern.matcher(id); + if (parts.matches()) + { + itemname = parts.group(2); + metaData = Short.parseShort(parts.group(3)); + } + else + { + itemname = id; + } + + if (NumberUtil.isInt(itemname)) + { + itemid = Integer.parseInt(itemname); + } + else if (NumberUtil.isInt(id)) + { + itemid = Integer.parseInt(id); + } + else + { + itemname = itemname.toLowerCase(Locale.ENGLISH); + } + + if (itemid < 1) + { + if (items.containsKey(itemname)) + { + itemid = items.get(itemname); + if (durabilities.containsKey(itemname) && metaData == 0) + { + metaData = durabilities.get(itemname); + } + } + else if (Material.getMaterial(itemname.toUpperCase(Locale.ENGLISH)) != null) + { + Material bMaterial = Material.getMaterial(itemname.toUpperCase(Locale.ENGLISH)); + itemid = bMaterial.getId(); + } + else + { + try + { + Material bMaterial = Bukkit.getUnsafe().getMaterialFromInternalName(itemname.toLowerCase(Locale.ENGLISH)); + itemid = bMaterial.getId(); + } + catch (Throwable throwable) + { + throw new Exception(tl("unknownItemName", itemname), throwable); + } + } + } + + if (itemid < 1) + { + throw new Exception(tl("unknownItemName", itemname)); + } + + final Material mat = Material.getMaterial(itemid); + if (mat == null) + { + throw new Exception(tl("unknownItemId", itemid)); + } + final ItemStack retval = new ItemStack(mat); + retval.setAmount(mat.getMaxStackSize()); + retval.setDurability(metaData); + return retval; + } + + @Override + public List getMatching(User user, String[] args) throws Exception + { + List is = new ArrayList(); + + if (args.length < 1) + { + is.add(user.getBase().getItemInHand()); + } + else if (args[0].equalsIgnoreCase("hand")) + { + is.add(user.getBase().getItemInHand()); + } + else if (args[0].equalsIgnoreCase("inventory") || args[0].equalsIgnoreCase("invent") || args[0].equalsIgnoreCase("all")) + { + for (ItemStack stack : user.getBase().getInventory().getContents()) + { + if (stack == null || stack.getType() == Material.AIR) + { + continue; + } + is.add(stack); + } + } + else if (args[0].equalsIgnoreCase("blocks")) + { + for (ItemStack stack : user.getBase().getInventory().getContents()) + { + if (stack == null || stack.getTypeId() > 255 || stack.getType() == Material.AIR) + { + continue; + } + is.add(stack); + } + } + else + { + is.add(get(args[0])); + } + + if (is.isEmpty() || is.get(0).getType() == Material.AIR) + { + throw new Exception(tl("itemSellAir")); + } + + return is; + } + + @Override + public String names(ItemStack item) + { + ItemData itemData = new ItemData(item.getTypeId(), item.getDurability()); + List nameList = names.get(itemData); + if (nameList == null) + { + itemData = new ItemData(item.getTypeId(), (short)0); + nameList = names.get(itemData); + if (nameList == null) + { + return null; + } + } + + if (nameList.size() > 15) + { + nameList = nameList.subList(0, 14); + } + return StringUtil.joinList(", ", nameList); + } + + @Override + public String name(ItemStack item) + { + ItemData itemData = new ItemData(item.getTypeId(), item.getDurability()); + String name = primaryName.get(itemData); + if (name == null) + { + itemData = new ItemData(item.getTypeId(), (short)0); + name = primaryName.get(itemData); + if (name == null) + { + return null; + } + } + return name; + } + + + static class ItemData + { + final private int itemNo; + final private short itemData; + + ItemData(final int itemNo, final short itemData) + { + this.itemNo = itemNo; + this.itemData = itemData; + } + + public int getItemNo() + { + return itemNo; + } + + public short getItemData() + { + return itemData; + } + + @Override + public int hashCode() + { + return (31 * itemNo) ^ itemData; + } + + @Override + public boolean equals(Object o) + { + if (o == null) + { + return false; + } + if (!(o instanceof ItemData)) + { + return false; + } + ItemData pairo = (ItemData)o; + return this.itemNo == pairo.getItemNo() + && this.itemData == pairo.getItemData(); + } + } + + + class LengthCompare implements java.util.Comparator + { + public LengthCompare() + { + super(); + } + + @Override + public int compare(String s1, String s2) + { + return s1.length() - s2.length(); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/Jails.java b/Essentials/src/com/earth2me/essentials/Jails.java new file mode 100644 index 0000000000..afbb7673a5 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/Jails.java @@ -0,0 +1,340 @@ +package com.earth2me.essentials; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.storage.AsyncStorageObjectHolder; +import java.io.File; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; +import net.ess3.api.IEssentials; +import net.ess3.api.IUser; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockDamageEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerRespawnEvent; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; +import org.bukkit.plugin.PluginManager; + + +public class Jails extends AsyncStorageObjectHolder implements net.ess3.api.IJails +{ + private static final transient Logger LOGGER = Bukkit.getLogger(); + private static transient boolean enabled = false; + + public Jails(final IEssentials ess) + { + super(ess, com.earth2me.essentials.settings.Jails.class); + reloadConfig(); + } + + private void registerListeners() + { + enabled = true; + final PluginManager pluginManager = ess.getServer().getPluginManager(); + final JailListener blockListener = new JailListener(); + pluginManager.registerEvents(blockListener, ess); + if (ess.getSettings().isDebug()) + { + LOGGER.log(Level.INFO, "Registering Jail listener"); + } + } + + @Override + public File getStorageFile() + { + return new File(ess.getDataFolder(), "jail.yml"); + } + + @Override + public void finishRead() + { + checkRegister(); + } + + @Override + public void finishWrite() + { + checkRegister(); + } + + public void resetListener() + { + enabled = false; + checkRegister(); + } + + private void checkRegister() + { + if (enabled == false && getCount() > 0) + { + registerListeners(); + } + } + + @Override + public Location getJail(final String jailName) throws Exception + { + acquireReadLock(); + try + { + if (getData().getJails() == null || jailName == null + || !getData().getJails().containsKey(jailName.toLowerCase(Locale.ENGLISH))) + { + throw new Exception(tl("jailNotExist")); + } + Location loc = getData().getJails().get(jailName.toLowerCase(Locale.ENGLISH)); + if (loc == null || loc.getWorld() == null) + { + throw new Exception(tl("jailNotExist")); + } + return loc; + } + finally + { + unlock(); + } + } + + @Override + public Collection getList() throws Exception + { + acquireReadLock(); + try + { + if (getData().getJails() == null) + { + return Collections.emptyList(); + } + return new ArrayList(getData().getJails().keySet()); + } + finally + { + unlock(); + } + } + + @Override + public void removeJail(final String jail) throws Exception + { + acquireWriteLock(); + try + { + if (getData().getJails() == null) + { + return; + } + getData().getJails().remove(jail.toLowerCase(Locale.ENGLISH)); + } + finally + { + unlock(); + } + } + + @Override + public void sendToJail(final IUser user, final String jail) throws Exception + { + acquireReadLock(); + try + { + if (user.getBase().isOnline()) + { + Location loc = getJail(jail); + user.getTeleport().now(loc, false, TeleportCause.COMMAND); + } + user.setJail(jail); + } + finally + { + unlock(); + } + } + + @Override + public void setJail(final String jailName, final Location loc) throws Exception + { + acquireWriteLock(); + try + { + if (getData().getJails() == null) + { + getData().setJails(new HashMap()); + } + getData().getJails().put(jailName.toLowerCase(Locale.ENGLISH), loc); + } + finally + { + unlock(); + } + } + + @Override + public int getCount() + { + try + { + return getList().size(); + } + catch (Exception ex) + { + return 0; + } + } + + + private class JailListener implements Listener + { + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onJailBlockBreak(final BlockBreakEvent event) + { + final User user = ess.getUser(event.getPlayer()); + if (user.isJailed()) + { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onJailBlockPlace(final BlockPlaceEvent event) + { + final User user = ess.getUser(event.getPlayer()); + if (user.isJailed()) + { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onJailBlockDamage(final BlockDamageEvent event) + { + final User user = ess.getUser(event.getPlayer()); + if (user.isJailed()) + { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onJailEntityDamageByEntity(final EntityDamageByEntityEvent event) + { + if (event.getCause() != DamageCause.ENTITY_ATTACK || event.getEntity().getType() != EntityType.PLAYER) + { + return; + } + final Entity damager = event.getDamager(); + if (damager.getType() == EntityType.PLAYER) + { + final User user = ess.getUser((Player)damager); + if (user != null && user.isJailed()) + { + event.setCancelled(true); + } + } + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onJailPlayerInteract(final PlayerInteractEvent event) + { + final User user = ess.getUser(event.getPlayer()); + if (user.isJailed()) + { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onJailPlayerRespawn(final PlayerRespawnEvent event) + { + final User user = ess.getUser(event.getPlayer()); + if (!user.isJailed() || user.getJail() == null || user.getJail().isEmpty()) + { + return; + } + + try + { + event.setRespawnLocation(getJail(user.getJail())); + } + catch (Exception ex) + { + if (ess.getSettings().isDebug()) + { + LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage()), ex); + } + else + { + LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage())); + } + } + } + + @EventHandler(priority = EventPriority.HIGH) + public void onJailPlayerTeleport(final PlayerTeleportEvent event) + { + final User user = ess.getUser(event.getPlayer()); + if (!user.isJailed() || user.getJail() == null || user.getJail().isEmpty()) + { + return; + } + + try + { + event.setTo(getJail(user.getJail())); + } + catch (Exception ex) + { + if (ess.getSettings().isDebug()) + { + LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage()), ex); + } + else + { + LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage())); + } + } + user.sendMessage(tl("jailMessage")); + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onJailPlayerJoin(final PlayerJoinEvent event) + { + final User user = ess.getUser(event.getPlayer()); + final long currentTime = System.currentTimeMillis(); + user.checkJailTimeout(currentTime); + if (!user.isJailed() || user.getJail() == null || user.getJail().isEmpty()) + { + return; + } + + try + { + sendToJail(user, user.getJail()); + } + catch (Exception ex) + { + if (ess.getSettings().isDebug()) + { + LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage()), ex); + } + else + { + LOGGER.log(Level.INFO, tl("returnPlayerToJailError", user.getName(), ex.getLocalizedMessage())); + } + } + user.sendMessage(tl("jailMessage")); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/Kit.java b/Essentials/src/com/earth2me/essentials/Kit.java new file mode 100644 index 0000000000..6152e83961 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/Kit.java @@ -0,0 +1,293 @@ +package com.earth2me.essentials; + +import static com.earth2me.essentials.I18n.tl; +import static com.earth2me.essentials.I18n.capitalCase; +import com.earth2me.essentials.Trade.OverflowType; +import com.earth2me.essentials.commands.NoChargeException; +import com.earth2me.essentials.craftbukkit.InventoryWorkaround; +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.earth2me.essentials.utils.NumberUtil; +import java.math.BigDecimal; +import java.util.*; +import java.util.logging.Level; +import net.ess3.api.IEssentials; +import org.bukkit.Material; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.inventory.ItemStack; + + +public class Kit +{ + final IEssentials ess; + final String kitName; + final Map kit; + final Trade charge; + + public Kit(final String kitName, final IEssentials ess) throws Exception + { + this.kitName = kitName; + this.ess = ess; + this.kit = ess.getSettings().getKit(kitName); + this.charge = new Trade("kit-" + kitName, new Trade("kit-kit", ess), ess); + + if (kit == null) + { + throw new Exception(tl("kitNotFound")); + } + } + + //TODO: Convert this to use one of the new text classes? + public static String listKits(final IEssentials ess, final User user) throws Exception + { + try + { + final ConfigurationSection kits = ess.getSettings().getKits(); + final StringBuilder list = new StringBuilder(); + for (String kitItem : kits.getKeys(false)) + { + if (user == null) + { + list.append(" ").append(capitalCase(kitItem)); + } + else if (user.isAuthorized("essentials.kits." + kitItem.toLowerCase(Locale.ENGLISH))) + { + String cost = ""; + String name = capitalCase(kitItem); + BigDecimal costPrice = new Trade("kit-" + kitItem.toLowerCase(Locale.ENGLISH), ess).getCommandCost(user); + if (costPrice.signum() > 0) + { + cost = tl("kitCost", NumberUtil.displayCurrency(costPrice, ess)); + } + + Kit kit = new Kit(kitItem, ess); + if (kit.getNextUse(user) != 0) + { + name = tl("kitDelay", name); + } + + list.append(" ").append(name).append(cost); + } + } + return list.toString().trim(); + } + catch (Exception ex) + { + throw new Exception(tl("kitError"), ex); + } + + } + + public String getName() + { + return kitName; + } + + public void checkPerms(final User user) throws Exception + { + if (!user.isAuthorized("essentials.kits." + kitName)) + { + throw new Exception(tl("noKitPermission", "essentials.kits." + kitName)); + } + } + + public void checkDelay(final User user) throws Exception + { + long nextUse = getNextUse(user); + + if (nextUse == 0L) + { + return; + } + else if (nextUse < 0L) + { + user.sendMessage(tl("kitOnce")); + throw new NoChargeException(); + } + else + { + user.sendMessage(tl("kitTimed", DateUtil.formatDateDiff(nextUse))); + throw new NoChargeException(); + } + } + + public void checkAffordable(final User user) throws Exception + { + charge.isAffordableFor(user); + } + + public void setTime(final User user) throws Exception + { + final Calendar time = new GregorianCalendar(); + user.setKitTimestamp(kitName, time.getTimeInMillis()); + } + + public void chargeUser(final User user) throws Exception + { + charge.charge(user); + } + + public long getNextUse(final User user) throws Exception + { + if (user.isAuthorized("essentials.kit.exemptdelay")) + { + return 0L; + } + + final Calendar time = new GregorianCalendar(); + + double delay = 0; + try + { + // Make sure delay is valid + delay = kit.containsKey("delay") ? ((Number)kit.get("delay")).doubleValue() : 0.0d; + } + catch (Exception e) + { + throw new Exception(tl("kitError2")); + } + + // When was the last kit used? + final long lastTime = user.getKitTimestamp(kitName); + + // When can be use the kit again? + final Calendar delayTime = new GregorianCalendar(); + delayTime.setTimeInMillis(lastTime); + delayTime.add(Calendar.SECOND, (int)delay); + delayTime.add(Calendar.MILLISECOND, (int)((delay * 1000.0) % 1000.0)); + + if (lastTime == 0L || lastTime > time.getTimeInMillis()) + { + // If we have no record of kit use, or its corrupted, give them benifit of the doubt. + return 0L; + } + else if (delay < 0d) + { + // If the kit has a negative kit time, it can only be used once. + return -1; + } + else if (delayTime.before(time)) + { + // If the kit was used in the past, but outside the delay time, it can be used. + return 0L; + } + else + { + // If the kit has been used recently, return the next time it can be used. + return delayTime.getTimeInMillis(); + } + } + + public List getItems(final User user) throws Exception + { + if (kit == null) + { + throw new Exception(tl("kitNotFound")); + } + try + { + final List itemList = new ArrayList(); + final Object kitItems = kit.get("items"); + if (kitItems instanceof List) + { + for (Object item : (List)kitItems) + { + if (item instanceof String) + { + itemList.add(item.toString()); + continue; + } + throw new Exception("Invalid kit item: " + item.toString()); + } + return itemList; + } + throw new Exception("Invalid item list"); + } + catch (Exception e) + { + ess.getLogger().log(Level.WARNING, "Error parsing kit " + kitName + ": " + e.getMessage()); + throw new Exception(tl("kitError2"), e); + } + } + + public void expandItems(final User user) throws Exception + { + expandItems(user, getItems(user)); + } + + public void expandItems(final User user, final List items) throws Exception + { + try + { + IText input = new SimpleTextInput(items); + IText output = new KeywordReplacer(input, user.getSource(), ess); + + boolean spew = false; + final boolean allowUnsafe = ess.getSettings().allowUnsafeEnchantments(); + for (String kitItem : output.getLines()) + { + if (kitItem.startsWith(ess.getSettings().getCurrencySymbol())) + { + BigDecimal value = new BigDecimal(kitItem.substring(ess.getSettings().getCurrencySymbol().length()).trim()); + Trade t = new Trade(value, ess); + t.pay(user, OverflowType.DROP); + continue; + } + + final String[] parts = kitItem.split(" +"); + final ItemStack parseStack = ess.getItemDb().get(parts[0], parts.length > 1 ? Integer.parseInt(parts[1]) : 1); + + if (parseStack.getType() == Material.AIR) + { + continue; + } + + final MetaItemStack metaStack = new MetaItemStack(parseStack); + + if (parts.length > 2) + { + // We pass a null sender here because kits should not do perm checks + metaStack.parseStringMeta(null, allowUnsafe, parts, 2, ess); + } + + final Map overfilled; + final boolean allowOversizedStacks = user.isAuthorized("essentials.oversizedstacks"); + if (allowOversizedStacks) + { + overfilled = InventoryWorkaround.addOversizedItems(user.getBase().getInventory(), ess.getSettings().getOversizedStackSize(), metaStack.getItemStack()); + } + else + { + overfilled = InventoryWorkaround.addItems(user.getBase().getInventory(), metaStack.getItemStack()); + } + for (ItemStack itemStack : overfilled.values()) + { + int spillAmount = itemStack.getAmount(); + if (!allowOversizedStacks) + { + itemStack.setAmount(spillAmount < itemStack.getMaxStackSize() ? spillAmount : itemStack.getMaxStackSize()); + } + while (spillAmount > 0) + { + user.getWorld().dropItemNaturally(user.getLocation(), itemStack); + spillAmount -= itemStack.getAmount(); + } + spew = true; + } + } + user.getBase().updateInventory(); + if (spew) + { + user.sendMessage(tl("kitInvFull")); + } + } + catch (Exception e) + { + user.getBase().updateInventory(); + ess.getLogger().log(Level.WARNING, e.getMessage()); + throw new Exception(tl("kitError2"), e); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/LocationTarget.java b/Essentials/src/com/earth2me/essentials/LocationTarget.java new file mode 100644 index 0000000000..1641373af5 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/LocationTarget.java @@ -0,0 +1,20 @@ +package com.earth2me.essentials; + +import org.bukkit.Location; + + +public class LocationTarget implements ITarget +{ + private final Location location; + + LocationTarget(Location location) + { + this.location = location; + } + + @Override + public Location getLocation() + { + return location; + } +} \ No newline at end of file diff --git a/Essentials/src/com/earth2me/essentials/ManagedFile.java b/Essentials/src/com/earth2me/essentials/ManagedFile.java new file mode 100644 index 0000000000..3fa46d5c32 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/ManagedFile.java @@ -0,0 +1,228 @@ +package com.earth2me.essentials; + +import static com.earth2me.essentials.I18n.tl; +import java.io.*; +import java.math.BigInteger; +import java.security.DigestInputStream; +import java.security.DigestOutputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import net.ess3.api.IEssentials; +import org.bukkit.Bukkit; + + +public class ManagedFile +{ + private static final int BUFFERSIZE = 1024 * 8; + private final transient File file; + + public ManagedFile(final String filename, final IEssentials ess) + { + file = new File(ess.getDataFolder(), filename); + + if (file.exists()) + { + try + { + if (checkForVersion(file, ess.getDescription().getVersion()) && !file.delete()) + { + throw new IOException("Could not delete file " + file.toString()); + } + } + catch (IOException ex) + { + Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex); + } + } + + if (!file.exists()) + { + try + { + copyResourceAscii("/" + filename, file); + } + catch (IOException ex) + { + Bukkit.getLogger().log(Level.SEVERE, tl("itemsCsvNotLoaded"), ex); + } + } + } + + public static void copyResourceAscii(final String resourceName, final File file) throws IOException + { + final InputStreamReader reader = new InputStreamReader(ManagedFile.class.getResourceAsStream(resourceName)); + try + { + final MessageDigest digest = getDigest(); + final DigestOutputStream digestStream = new DigestOutputStream(new FileOutputStream(file), digest); + try + { + final OutputStreamWriter writer = new OutputStreamWriter(digestStream); + try + { + final char[] buffer = new char[BUFFERSIZE]; + do + { + final int length = reader.read(buffer); + if (length >= 0) + { + writer.write(buffer, 0, length); + } + else + { + break; + } + } + while (true); + writer.write("\n"); + writer.flush(); + final BigInteger hashInt = new BigInteger(1, digest.digest()); + digestStream.on(false); + digestStream.write('#'); + digestStream.write(hashInt.toString(16).getBytes()); + } + finally + { + writer.close(); + } + } + finally + { + digestStream.close(); + } + } + finally + { + reader.close(); + } + } + + public static boolean checkForVersion(final File file, final String version) throws IOException + { + if (file.length() < 33) + { + return false; + } + final BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); + try + { + final byte[] buffer = new byte[(int)file.length()]; + int position = 0; + do + { + final int length = bis.read(buffer, position, Math.min((int)file.length() - position, BUFFERSIZE)); + if (length < 0) + { + break; + } + position += length; + } + while (position < file.length()); + final ByteArrayInputStream bais = new ByteArrayInputStream(buffer); + if (bais.skip(file.length() - 33) != file.length() - 33) + { + return false; + } + final BufferedReader reader = new BufferedReader(new InputStreamReader(bais)); + try + { + String hash = reader.readLine(); + if (hash != null && hash.matches("#[a-f0-9]{32}")) + { + hash = hash.substring(1); + bais.reset(); + final String versionline = reader.readLine(); + if (versionline != null && versionline.matches("#version: .+")) + { + final String versioncheck = versionline.substring(10); + if (!versioncheck.equalsIgnoreCase(version)) + { + bais.reset(); + final MessageDigest digest = getDigest(); + final DigestInputStream digestStream = new DigestInputStream(bais, digest); + try + { + final byte[] bytes = new byte[(int)file.length() - 33]; + digestStream.read(bytes); + final BigInteger correct = new BigInteger(hash, 16); + final BigInteger test = new BigInteger(1, digest.digest()); + if (correct.equals(test)) + { + return true; + } + else + { + Bukkit.getLogger().warning("File " + file.toString() + " has been modified by user and file version differs, please update the file manually."); + } + } + finally + { + digestStream.close(); + } + } + } + } + } + finally + { + reader.close(); + } + } + finally + { + bis.close(); + } + return false; + } + + public static MessageDigest getDigest() throws IOException + { + try + { + return MessageDigest.getInstance("MD5"); + } + catch (NoSuchAlgorithmException ex) + { + throw new IOException(ex); + } + } + + public List getLines() + { + try + { + final BufferedReader reader = new BufferedReader(new FileReader(file)); + try + { + final List lines = new ArrayList(); + do + { + final String line = reader.readLine(); + if (line == null) + { + break; + } + else + { + lines.add(line); + } + } + while (true); + return lines; + } + finally + { + reader.close(); + } + } + catch (IOException ex) + { + Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex); + return Collections.emptyList(); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/MetaItemStack.java b/Essentials/src/com/earth2me/essentials/MetaItemStack.java new file mode 100644 index 0000000000..c390286279 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/MetaItemStack.java @@ -0,0 +1,577 @@ +package com.earth2me.essentials; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.textreader.BookInput; +import com.earth2me.essentials.textreader.BookPager; +import com.earth2me.essentials.textreader.IText; +import com.earth2me.essentials.utils.FormatUtil; +import com.earth2me.essentials.utils.NumberUtil; +import java.util.*; +import java.util.regex.Pattern; + +import com.google.common.base.Joiner; +import java.util.logging.Level; +import net.ess3.api.IEssentials; +import org.bukkit.Color; +import org.bukkit.DyeColor; +import org.bukkit.FireworkEffect; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.*; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + + +public class MetaItemStack +{ + private static final Map colorMap = new HashMap(); + private static final Map fireworkShape = new HashMap(); + + static + { + for (DyeColor color : DyeColor.values()) + { + colorMap.put(color.name(), color); + } + for (FireworkEffect.Type type : FireworkEffect.Type.values()) + { + fireworkShape.put(type.name(), type); + } + } + private final transient Pattern splitPattern = Pattern.compile("[:+',;.]"); + private ItemStack stack; + private FireworkEffect.Builder builder = FireworkEffect.builder(); + private PotionEffectType pEffectType; + private PotionEffect pEffect; + private boolean validFirework = false; + private boolean validPotionEffect = false; + private boolean validPotionDuration = false; + private boolean validPotionPower = false; + private boolean completePotion = false; + private int power = 1; + private int duration = 120; + + public MetaItemStack(final ItemStack stack) + { + this.stack = stack.clone(); + } + + public ItemStack getItemStack() + { + return stack; + } + + public boolean isValidFirework() + { + return validFirework; + } + + public boolean isValidPotion() + { + return validPotionEffect && validPotionDuration && validPotionPower; + } + + public FireworkEffect.Builder getFireworkBuilder() + { + return builder; + } + + public PotionEffect getPotionEffect() + { + return pEffect; + } + + public boolean completePotion() + { + return completePotion; + } + + private void resetPotionMeta() + { + pEffect = null; + pEffectType = null; + validPotionEffect = false; + validPotionDuration = false; + validPotionPower = false; + completePotion = true; + } + + public boolean canSpawn(final IEssentials ess) + { + try + { + ess.getServer().getUnsafe().modifyItemStack(stack, "{}"); + return true; + } + catch (NullPointerException npe) + { + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "Itemstack is invalid", npe); + } + return false; + } + catch (NoSuchMethodError nsme) + { + return true; + } + catch (Throwable throwable) + { + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "Itemstack is invalid", throwable); + } + return false; + } + } + + public void parseStringMeta(final CommandSource sender, final boolean allowUnsafe, String[] string, int fromArg, final IEssentials ess) throws Exception + { + if (string[fromArg].startsWith("{") && hasMetaPermission(sender, "vanilla", false, true, ess)) + { + try + { + stack = ess.getServer().getUnsafe().modifyItemStack(stack, Joiner.on(' ').join(Arrays.asList(string).subList(fromArg, string.length))); + } + catch (NullPointerException npe) + { + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "Itemstack is invalid", npe); + } + } + catch (NoSuchMethodError nsme) + { + throw new Exception(tl("noMetaJson"), nsme); + } + catch (Throwable throwable) + { + throw new Exception(throwable.getMessage(), throwable); + } + } + else + { + for (int i = fromArg; i < string.length; i++) + { + addStringMeta(sender, allowUnsafe, string[i], ess); + } + if (validFirework) + { + if (!hasMetaPermission(sender, "firework", true, true, ess)) + { + throw new Exception(tl("noMetaFirework")); + } + FireworkEffect effect = builder.build(); + FireworkMeta fmeta = (FireworkMeta)stack.getItemMeta(); + fmeta.addEffect(effect); + if (fmeta.getEffects().size() > 1 && !hasMetaPermission(sender, "firework-multiple", true, true, ess)) + { + throw new Exception(tl("multipleCharges")); + } + stack.setItemMeta(fmeta); + } + } + } + + public void addStringMeta(final CommandSource sender, final boolean allowUnsafe, final String string, final IEssentials ess) throws Exception + { + final String[] split = splitPattern.split(string, 2); + if (split.length < 1) + { + return; + } + + if (split.length > 1 && split[0].equalsIgnoreCase("name") && hasMetaPermission(sender, "name", false, true, ess)) + { + final String displayName = FormatUtil.replaceFormat(split[1].replace('_', ' ')); + final ItemMeta meta = stack.getItemMeta(); + meta.setDisplayName(displayName); + stack.setItemMeta(meta); + } + else if (split.length > 1 && (split[0].equalsIgnoreCase("lore") || split[0].equalsIgnoreCase("desc")) && hasMetaPermission(sender, "lore", false, true, ess)) + { + final List lore = new ArrayList(); + for (String line : split[1].split("\\|")) + { + lore.add(FormatUtil.replaceFormat(line.replace('_', ' '))); + } + final ItemMeta meta = stack.getItemMeta(); + meta.setLore(lore); + stack.setItemMeta(meta); + } + else if (split.length > 1 && (split[0].equalsIgnoreCase("player") || split[0].equalsIgnoreCase("owner")) && stack.getType() == Material.SKULL_ITEM && hasMetaPermission(sender, "head", false, true, ess)) + { + if (stack.getDurability() == 3) + { + final String owner = split[1]; + final SkullMeta meta = (SkullMeta)stack.getItemMeta(); + meta.setOwner(owner); + stack.setItemMeta(meta); + } + else + { + throw new Exception(tl("onlyPlayerSkulls")); + } + } + else if (split.length > 1 && split[0].equalsIgnoreCase("book") && stack.getType() == Material.WRITTEN_BOOK + && (hasMetaPermission(sender, "book", true, true, ess) || hasMetaPermission(sender, "chapter-" + split[1].toLowerCase(Locale.ENGLISH), true, true, ess))) + { + final BookMeta meta = (BookMeta)stack.getItemMeta(); + final IText input = new BookInput("book", true, ess); + final BookPager pager = new BookPager(input); + + List pages = pager.getPages(split[1]); + meta.setPages(pages); + stack.setItemMeta(meta); + } + else if (split.length > 1 && split[0].equalsIgnoreCase("author") && stack.getType() == Material.WRITTEN_BOOK && hasMetaPermission(sender, "author", false, true, ess)) + { + final String author = FormatUtil.replaceFormat(split[1]); + final BookMeta meta = (BookMeta)stack.getItemMeta(); + meta.setAuthor(author); + stack.setItemMeta(meta); + } + else if (split.length > 1 && split[0].equalsIgnoreCase("title") && stack.getType() == Material.WRITTEN_BOOK && hasMetaPermission(sender, "title", false, true, ess)) + { + final String title = FormatUtil.replaceFormat(split[1].replace('_', ' ')); + final BookMeta meta = (BookMeta)stack.getItemMeta(); + meta.setTitle(title); + stack.setItemMeta(meta); + } + else if (split.length > 1 && split[0].equalsIgnoreCase("power") && stack.getType() == Material.FIREWORK && hasMetaPermission(sender, "firework-power", false, true, ess)) + { + final int power = NumberUtil.isInt(split[1]) ? Integer.parseInt(split[1]) : 0; + final FireworkMeta meta = (FireworkMeta)stack.getItemMeta(); + meta.setPower(power > 3 ? 4 : power); + stack.setItemMeta(meta); + } + else if (stack.getType() == Material.FIREWORK) //WARNING - Meta for fireworks will be ignored after this point. + { + addFireworkMeta(sender, false, string, ess); + } + else if (stack.getType() == Material.POTION) //WARNING - Meta for potions will be ignored after this point. + { + addPotionMeta(sender, false, string, ess); + } + else if (split.length > 1 && (split[0].equalsIgnoreCase("color") || split[0].equalsIgnoreCase("colour")) + && (stack.getType() == Material.LEATHER_BOOTS + || stack.getType() == Material.LEATHER_CHESTPLATE + || stack.getType() == Material.LEATHER_HELMET + || stack.getType() == Material.LEATHER_LEGGINGS)) + { + final String[] color = split[1].split("(\\||,)"); + if (color.length == 3) + { + final int red = NumberUtil.isInt(color[0]) ? Integer.parseInt(color[0]) : 0; + final int green = NumberUtil.isInt(color[1]) ? Integer.parseInt(color[1]) : 0; + final int blue = NumberUtil.isInt(color[2]) ? Integer.parseInt(color[2]) : 0; + final LeatherArmorMeta meta = (LeatherArmorMeta)stack.getItemMeta(); + meta.setColor(Color.fromRGB(red, green, blue)); + stack.setItemMeta(meta); + } + else + { + throw new Exception(tl("leatherSyntax")); + } + } + else + { + parseEnchantmentStrings(sender, allowUnsafe, split, ess); + } + } + + public void addFireworkMeta(final CommandSource sender, final boolean allowShortName, final String string, final IEssentials ess) throws Exception + { + if (stack.getType() == Material.FIREWORK) + { + final String[] split = splitPattern.split(string, 2); + + if (split.length < 2) + { + return; + } + + if (split[0].equalsIgnoreCase("color") || split[0].equalsIgnoreCase("colour") || (allowShortName && split[0].equalsIgnoreCase("c"))) + { + if (validFirework) + { + if (!hasMetaPermission(sender, "firework", true, true, ess)) + { + throw new Exception(tl("noMetaFirework")); + } + FireworkEffect effect = builder.build(); + FireworkMeta fmeta = (FireworkMeta)stack.getItemMeta(); + fmeta.addEffect(effect); + if (fmeta.getEffects().size() > 1 && !hasMetaPermission(sender, "firework-multiple", true, true, ess)) + { + throw new Exception(tl("multipleCharges")); + } + stack.setItemMeta(fmeta); + builder = FireworkEffect.builder(); + } + + List primaryColors = new ArrayList(); + String[] colors = split[1].split(","); + for (String color : colors) + { + if (colorMap.containsKey(color.toUpperCase())) + { + validFirework = true; + primaryColors.add(colorMap.get(color.toUpperCase()).getFireworkColor()); + } + else + { + throw new Exception(tl("invalidFireworkFormat", split[1], split[0])); + } + } + builder.withColor(primaryColors); + } + else if (split[0].equalsIgnoreCase("shape") || split[0].equalsIgnoreCase("type") || (allowShortName && (split[0].equalsIgnoreCase("s") || split[0].equalsIgnoreCase("t")))) + { + FireworkEffect.Type finalEffect = null; + split[1] = (split[1].equalsIgnoreCase("large") ? "BALL_LARGE" : split[1]); + if (fireworkShape.containsKey(split[1].toUpperCase())) + { + finalEffect = fireworkShape.get(split[1].toUpperCase()); + } + else + { + throw new Exception(tl("invalidFireworkFormat", split[1], split[0])); + } + if (finalEffect != null) + { + builder.with(finalEffect); + } + } + else if (split[0].equalsIgnoreCase("fade") || (allowShortName && split[0].equalsIgnoreCase("f"))) + { + List fadeColors = new ArrayList(); + String[] colors = split[1].split(","); + for (String color : colors) + { + if (colorMap.containsKey(color.toUpperCase())) + { + fadeColors.add(colorMap.get(color.toUpperCase()).getFireworkColor()); + } + else + { + throw new Exception(tl("invalidFireworkFormat", split[1], split[0])); + } + } + if (!fadeColors.isEmpty()) + { + builder.withFade(fadeColors); + } + } + else if (split[0].equalsIgnoreCase("effect") || (allowShortName && split[0].equalsIgnoreCase("e"))) + { + String[] effects = split[1].split(","); + for (String effect : effects) + { + if (effect.equalsIgnoreCase("twinkle")) + { + builder.flicker(true); + } + else if (effect.equalsIgnoreCase("trail")) + { + builder.trail(true); + } + else + { + throw new Exception(tl("invalidFireworkFormat", split[1], split[0])); + } + } + } + } + } + + public void addPotionMeta(final CommandSource sender, final boolean allowShortName, final String string, final IEssentials ess) throws Exception + { + if (stack.getType() == Material.POTION) + { + final String[] split = splitPattern.split(string, 2); + + if (split.length < 2) + { + return; + } + + if (split[0].equalsIgnoreCase("effect") || (allowShortName && split[0].equalsIgnoreCase("e"))) + { + pEffectType = Potions.getByName(split[1]); + if (pEffectType != null && pEffectType.getName() != null) + { + if (hasMetaPermission(sender, "potions." + pEffectType.getName().toLowerCase(Locale.ENGLISH), true, false, ess)) + { + validPotionEffect = true; + } + else + { + throw new Exception(tl("noPotionEffectPerm", pEffectType.getName().toLowerCase(Locale.ENGLISH))); + } + } + else + { + throw new Exception(tl("invalidPotionMeta", split[1])); + } + } + else if (split[0].equalsIgnoreCase("power") || (allowShortName && split[0].equalsIgnoreCase("p"))) + { + if (NumberUtil.isInt(split[1])) + { + validPotionPower = true; + power = Integer.parseInt(split[1]); + if (power > 0 && power < 4) + { + power -= 1; + } + } + else + { + throw new Exception(tl("invalidPotionMeta", split[1])); + } + } + else if (split[0].equalsIgnoreCase("duration") || (allowShortName && split[0].equalsIgnoreCase("d"))) + { + if (NumberUtil.isInt(split[1])) + { + validPotionDuration = true; + duration = Integer.parseInt(split[1]) * 20; //Duration is in ticks by default, converted to seconds + } + else + { + throw new Exception(tl("invalidPotionMeta", split[1])); + } + } + + if (isValidPotion()) + { + PotionMeta pmeta = (PotionMeta)stack.getItemMeta(); + pEffect = pEffectType.createEffect(duration, power); + if (pmeta.getCustomEffects().size() > 1 && !hasMetaPermission(sender, "potions.multiple", true, false, ess)) + { + throw new Exception(tl("multiplePotionEffects")); + } + pmeta.addCustomEffect(pEffect, true); + stack.setItemMeta(pmeta); + resetPotionMeta(); + } + } + } + + private void parseEnchantmentStrings(final CommandSource sender, final boolean allowUnsafe, final String[] split, final IEssentials ess) throws Exception + { + final Enchantment enchantment = Enchantments.getByName(split[0]); + if (enchantment == null || !hasMetaPermission(sender, "enchantments." + enchantment.getName().toLowerCase(Locale.ENGLISH), false, false, ess)) + { + return; + } + + int level = -1; + if (split.length > 1) + { + try + { + level = Integer.parseInt(split[1]); + } + catch (NumberFormatException ex) + { + level = -1; + } + } + + if (level < 0 || (!allowUnsafe && level > enchantment.getMaxLevel())) + { + level = enchantment.getMaxLevel(); + } + addEnchantment(sender, allowUnsafe, enchantment, level); + } + + public void addEnchantment(final CommandSource sender, final boolean allowUnsafe, final Enchantment enchantment, final int level) throws Exception + { + if (enchantment == null) + { + throw new Exception(tl("enchantmentNotFound")); + } + try + { + if (stack.getType().equals(Material.ENCHANTED_BOOK)) + { + EnchantmentStorageMeta meta = (EnchantmentStorageMeta)stack.getItemMeta(); + if (level == 0) + { + meta.removeStoredEnchant(enchantment); + } + else + { + meta.addStoredEnchant(enchantment, level, allowUnsafe); + } + stack.setItemMeta(meta); + } + else // all other material types besides ENCHANTED_BOOK + { + if (level == 0) + { + stack.removeEnchantment(enchantment); + } + else + { + if (allowUnsafe) + { + stack.addUnsafeEnchantment(enchantment, level); + } + else + { + stack.addEnchantment(enchantment, level); + } + } + } + } + catch (Exception ex) + { + throw new Exception("Enchantment " + enchantment.getName() + ": " + ex.getMessage(), ex); + } + } + + public Enchantment getEnchantment(final User user, final String name) throws Exception + { + final Enchantment enchantment = Enchantments.getByName(name); + if (enchantment == null) + { + return null; + } + + final String enchantmentName = enchantment.getName().toLowerCase(Locale.ENGLISH); + + if (!hasMetaPermission(user, "enchantments." + enchantmentName, true, false)) + { + throw new Exception(tl("enchantmentPerm", enchantmentName)); + } + return enchantment; + } + + private boolean hasMetaPermission(final CommandSource sender, final String metaPerm, final boolean graceful, final boolean includeBase, final IEssentials ess) throws Exception + { + final User user = sender != null && sender.isPlayer() ? ess.getUser(sender.getPlayer()) : null; + return hasMetaPermission(user, metaPerm, graceful, includeBase); + } + + private boolean hasMetaPermission(final User user, final String metaPerm, final boolean graceful, final boolean includeBase) throws Exception + { + final String permBase = includeBase ? "essentials.itemspawn.meta-" : "essentials."; + if (user == null || user.isAuthorized(permBase + metaPerm)) + { + return true; + } + + if (graceful) + { + return false; + } + else + { + throw new Exception(tl("noMetaPerm", metaPerm)); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/Mob.java b/Essentials/src/com/earth2me/essentials/Mob.java new file mode 100644 index 0000000000..712f5cc0fd --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/Mob.java @@ -0,0 +1,138 @@ +package com.earth2me.essentials; + +import static com.earth2me.essentials.I18n.tl; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; + + +// Suffixes can be appended on the end of a mob name to make it plural +// Entities without a suffix, will default to 's' +public enum Mob +{ + CHICKEN("Chicken", Enemies.FRIENDLY, EntityType.CHICKEN), + COW("Cow", Enemies.FRIENDLY, EntityType.COW), + CREEPER("Creeper", Enemies.ENEMY, EntityType.CREEPER), + GHAST("Ghast", Enemies.ENEMY, EntityType.GHAST), + GIANT("Giant", Enemies.ENEMY, EntityType.GIANT), + HORSE("Horse", Enemies.FRIENDLY, EntityType.HORSE), + PIG("Pig", Enemies.FRIENDLY, EntityType.PIG), + PIGZOMB("PigZombie", Enemies.NEUTRAL, EntityType.PIG_ZOMBIE), + SHEEP("Sheep", Enemies.FRIENDLY, "", EntityType.SHEEP), + SKELETON("Skeleton", Enemies.ENEMY, EntityType.SKELETON), + SLIME("Slime", Enemies.ENEMY, EntityType.SLIME), + SPIDER("Spider", Enemies.ENEMY, EntityType.SPIDER), + SQUID("Squid", Enemies.FRIENDLY, EntityType.SQUID), + ZOMBIE("Zombie", Enemies.ENEMY, EntityType.ZOMBIE), + WOLF("Wolf", Enemies.NEUTRAL, "", EntityType.WOLF), + CAVESPIDER("CaveSpider", Enemies.ENEMY, EntityType.CAVE_SPIDER), + ENDERMAN("Enderman", Enemies.ENEMY, "", EntityType.ENDERMAN), + SILVERFISH("Silverfish", Enemies.ENEMY, "", EntityType.SILVERFISH), + ENDERDRAGON("EnderDragon", Enemies.ENEMY, EntityType.ENDER_DRAGON), + VILLAGER("Villager", Enemies.FRIENDLY, EntityType.VILLAGER), + BLAZE("Blaze", Enemies.ENEMY, EntityType.BLAZE), + MUSHROOMCOW("MushroomCow", Enemies.FRIENDLY, EntityType.MUSHROOM_COW), + MAGMACUBE("MagmaCube", Enemies.ENEMY, EntityType.MAGMA_CUBE), + SNOWMAN("Snowman", Enemies.FRIENDLY, "", EntityType.SNOWMAN), + OCELOT("Ocelot", Enemies.NEUTRAL, EntityType.OCELOT), + IRONGOLEM("IronGolem", Enemies.NEUTRAL, EntityType.IRON_GOLEM), + WITHER("Wither", Enemies.ENEMY, EntityType.WITHER), + BAT("Bat", Enemies.FRIENDLY, EntityType.BAT), + WITCH("Witch", Enemies.ENEMY, EntityType.WITCH), + BOAT("Boat", Enemies.NEUTRAL, EntityType.BOAT), + MINECART("Minecart", Enemies.NEUTRAL, EntityType.MINECART), + MINECART_CHEST("ChestMinecart", Enemies.NEUTRAL, EntityType.MINECART_CHEST), + MINECART_FURNACE("FurnaceMinecart", Enemies.NEUTRAL, EntityType.MINECART_FURNACE), + MINECART_TNT("TNTMinecart", Enemies.NEUTRAL, EntityType.MINECART_TNT), + MINECART_HOPPER("HopperMinecart", Enemies.NEUTRAL, EntityType.MINECART_HOPPER), + MINECART_MOB_SPAWNER("SpawnerMinecart", Enemies.NEUTRAL, EntityType.MINECART_MOB_SPAWNER), + ENDERCRYSTAL("EnderCrystal", Enemies.NEUTRAL, EntityType.ENDER_CRYSTAL), + EXPERIENCEORB("ExperienceOrb", Enemies.NEUTRAL, EntityType.EXPERIENCE_ORB); + public static final Logger logger = Logger.getLogger("Essentials"); + + private Mob(String n, Enemies en, String s, EntityType type) + { + this.suffix = s; + this.name = n; + this.type = en; + this.bukkitType = type; + } + + private Mob(String n, Enemies en, EntityType type) + { + this.name = n; + this.type = en; + this.bukkitType = type; + } + public String suffix = "s"; + final public String name; + final public Enemies type; + final private EntityType bukkitType; + private static final Map hashMap = new HashMap(); + private static final Map bukkitMap = new HashMap(); + + static + { + for (Mob mob : Mob.values()) + { + hashMap.put(mob.name.toLowerCase(Locale.ENGLISH), mob); + bukkitMap.put(mob.bukkitType, mob); + } + } + + public static Set getMobList() + { + return Collections.unmodifiableSet(hashMap.keySet()); + } + + public Entity spawn(final World world, final Server server, final Location loc) throws MobException + { + final Entity entity = world.spawn(loc, (Class)this.bukkitType.getEntityClass()); + if (entity == null) + { + logger.log(Level.WARNING, tl("unableToSpawnMob")); + throw new MobException(); + } + return entity; + } + + + public enum Enemies + { + FRIENDLY("friendly"), + NEUTRAL("neutral"), + ENEMY("enemy"); + + private Enemies(final String type) + { + this.type = type; + } + final protected String type; + } + + public EntityType getType() + { + return bukkitType; + } + + public static Mob fromName(final String name) + { + return hashMap.get(name.toLowerCase(Locale.ENGLISH)); + } + + public static Mob fromBukkitType(final EntityType type) + { + return bukkitMap.get(type); + } + + + public static class MobException extends Exception + { + private static final long serialVersionUID = 1L; + } +} diff --git a/Essentials/src/com/earth2me/essentials/MobData.java b/Essentials/src/com/earth2me/essentials/MobData.java new file mode 100644 index 0000000000..790cc631b2 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/MobData.java @@ -0,0 +1,351 @@ +package com.earth2me.essentials; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.utils.StringUtil; +import java.util.*; +import java.util.logging.Logger; +import org.bukkit.DyeColor; +import org.bukkit.Material; +import org.bukkit.entity.Ageable; +import org.bukkit.entity.Creeper; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.ExperienceOrb; +import org.bukkit.entity.Horse; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Ocelot; +import org.bukkit.entity.Pig; +import org.bukkit.entity.Player; +import org.bukkit.entity.Skeleton; +import org.bukkit.entity.Slime; +import org.bukkit.entity.Tameable; +import org.bukkit.entity.Villager; +import org.bukkit.entity.Wolf; +import org.bukkit.entity.Zombie; +import org.bukkit.inventory.EntityEquipment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.material.Colorable; + + +public enum MobData +{ + BABY_AGEABLE("baby", Ageable.class, Data.BABY, true), + ADULT_AGEABLE("adult", Ageable.class, Data.ADULT, true), + BABY_PIG("piglet", EntityType.PIG, Data.BABY, false), + BABY_WOLF("puppy", EntityType.WOLF, Data.BABY, false), + BABY_CHICKEN("chick", EntityType.CHICKEN, Data.BABY, false), + BABY_HORSE("colt", EntityType.HORSE, Data.BABY, false), + BABY_OCELOT("kitten", EntityType.OCELOT, Data.BABY, false), + BABY_SHEEP("lamb", EntityType.SHEEP, Data.BABY, false), + BABY_COW("calf", EntityType.COW.getEntityClass(), Data.BABY, false), + BABY_VILLAGER("child", EntityType.VILLAGER, Data.BABY, false), + TAMED_TAMEABLE("tamed", Tameable.class, Data.TAMED, true), + TAME_TAMEABLE("tame", Tameable.class, Data.TAMED, false), + RANDOM_SHEEP("random", EntityType.SHEEP, Data.COLORABLE, true), + COLORABLE_SHEEP("", StringUtil.joinList(DyeColor.values()).toLowerCase(Locale.ENGLISH), EntityType.SHEEP, Data.COLORABLE, true), + DONKEY_HORSE("donkey", EntityType.HORSE, Horse.Variant.DONKEY, true), + MULE_HORSE("mule", EntityType.HORSE, Horse.Variant.MULE, true), + SKELETON_HORSE("skeleton", EntityType.HORSE, Horse.Variant.SKELETON_HORSE, true), + UNDEAD_HORSE("undead", EntityType.HORSE, Horse.Variant.UNDEAD_HORSE, true), + ZOMBIE_HORSE("zombie", EntityType.HORSE, Horse.Variant.UNDEAD_HORSE, false), + POLKA_HORSE("polka", EntityType.HORSE, Horse.Style.BLACK_DOTS, true), + SOOTY_HORSE("sooty", EntityType.HORSE, Horse.Style.BLACK_DOTS, false), + BLAZE_HORSE("blaze", EntityType.HORSE, Horse.Style.WHITE, true), + SOCKS_HORSE("socks", EntityType.HORSE, Horse.Style.WHITE, false), + LEOPARD_HORSE("leopard", EntityType.HORSE, Horse.Style.WHITE_DOTS, true), + APPALOOSA_HORSE("appaloosa", EntityType.HORSE, Horse.Style.WHITE_DOTS, false), + PAINT_HORSE("paint", EntityType.HORSE, Horse.Style.WHITEFIELD, true), + MILKY_HORSE("milky", EntityType.HORSE, Horse.Style.WHITEFIELD, false), + SPLOTCHY_HORSE("splotchy", EntityType.HORSE, Horse.Style.WHITEFIELD, false), + BLACK_HORSE("black", EntityType.HORSE, Horse.Color.BLACK, true), + CHESTNUT_HORSE("chestnut", EntityType.HORSE, Horse.Color.CHESTNUT, true), + LIVER_HORSE("liver", EntityType.HORSE, Horse.Color.CHESTNUT, false), + CREAMY_HORSE("creamy", EntityType.HORSE, Horse.Color.CREAMY, true), + FLAXEN_HORSE("flaxen", EntityType.HORSE, Horse.Color.CREAMY, false), + GRAY_HORSE("gray", EntityType.HORSE, Horse.Color.GRAY, true), + DAPPLE_HORSE("dapple", EntityType.HORSE, Horse.Color.GRAY, false), + BUCKSKIN_HORSE("buckskin", EntityType.HORSE, Horse.Color.DARK_BROWN, true), + DARKBROWN_HORSE("darkbrown", EntityType.HORSE, Horse.Color.DARK_BROWN, false), + DARK_HORSE("dark", EntityType.HORSE, Horse.Color.DARK_BROWN, false), + DBROWN_HORSE("dbrown", EntityType.HORSE, Horse.Color.DARK_BROWN, false), + BAY_HORSE("bay", EntityType.HORSE, Horse.Color.BROWN, true), + BROWN_HORSE("brown", EntityType.HORSE, Horse.Color.BROWN, false), + CHEST_HORSE("chest", EntityType.HORSE, Data.CHEST, true), + SADDLE_HORSE("saddle", EntityType.HORSE, Data.HORSESADDLE, true), + GOLD_ARMOR_HORSE("goldarmor", EntityType.HORSE, Material.GOLD_BARDING, true), + DIAMOND_ARMOR_HORSE("diamondarmor", EntityType.HORSE, Material.DIAMOND_BARDING, true), + ARMOR_HORSE("armor", EntityType.HORSE, Material.IRON_BARDING, true), + SIAMESE_CAT("siamese", EntityType.OCELOT, Ocelot.Type.SIAMESE_CAT, true), + WHITE_CAT("white", EntityType.OCELOT, Ocelot.Type.SIAMESE_CAT, false), + RED_CAT("red", EntityType.OCELOT, Ocelot.Type.RED_CAT, true), + ORANGE_CAT("orange", EntityType.OCELOT, Ocelot.Type.RED_CAT, false), + TABBY_CAT("tabby", EntityType.OCELOT, Ocelot.Type.RED_CAT, false), + BLACK_CAT("black", EntityType.OCELOT, Ocelot.Type.BLACK_CAT, true), + TUXEDO_CAT("tuxedo", EntityType.OCELOT, Ocelot.Type.BLACK_CAT, false), + VILLAGER_ZOMBIE("villager", EntityType.ZOMBIE.getEntityClass(), Data.VILLAGER, true), + BABY_ZOMBIE("baby", EntityType.ZOMBIE.getEntityClass(), Data.BABYZOMBIE, true), + ADULT_ZOMBIE("adult", EntityType.ZOMBIE.getEntityClass(), Data.ADULTZOMBIE, true), + DIAMOND_SWORD_ZOMBIE("diamondsword", EntityType.ZOMBIE.getEntityClass(), Material.DIAMOND_SWORD, true), + GOLD_SWORD_ZOMBIE("goldsword", EntityType.ZOMBIE.getEntityClass(), Material.GOLD_SWORD, true), + IRON_SWORD_ZOMBIE("ironsword", EntityType.ZOMBIE.getEntityClass(), Material.IRON_SWORD, true), + STONE_SWORD_ZOMBIE("stonesword", EntityType.ZOMBIE.getEntityClass(), Material.STONE_SWORD, false), + SWORD_ZOMBIE("sword", EntityType.ZOMBIE.getEntityClass(), Material.STONE_SWORD, true), + DIAMOND_SWORD_SKELETON("diamondsword", EntityType.SKELETON, Material.DIAMOND_SWORD, true), + GOLD_SWORD_SKELETON("goldsword", EntityType.SKELETON, Material.GOLD_SWORD, true), + IRON_SWORD_SKELETON("ironsword", EntityType.SKELETON, Material.IRON_SWORD, true), + STONE_SWORD_SKELETON("stonesword", EntityType.SKELETON, Material.STONE_SWORD, false), + SWORD_SKELETON("sword", EntityType.SKELETON, Material.STONE_SWORD, true), + BOW_SKELETON("bow", EntityType.SKELETON, Material.BOW, true), + WHITHER_SKELETON("wither", EntityType.SKELETON, Data.WITHER, true), + POWERED_CREEPER("powered", EntityType.CREEPER, Data.ELECTRIFIED, true), + ELECTRIC_CREEPER("electric", EntityType.CREEPER, Data.ELECTRIFIED, false), + CHARGED_CREEPER("charged", EntityType.CREEPER, Data.ELECTRIFIED, false), + SADDLE_PIG("saddle", EntityType.PIG, Data.PIGSADDLE, true), + ANGRY_WOLF("angry", EntityType.WOLF, Data.ANGRY, true), + RABID_WOLF("rabid", EntityType.WOLF, Data.ANGRY, false), + FARMER_VILLAGER("farmer", EntityType.VILLAGER, Villager.Profession.FARMER, true), + LIBRARIAN_VILLAGER("librarian", EntityType.VILLAGER, Villager.Profession.LIBRARIAN, true), + PRIEST_VILLAGER("priest", EntityType.VILLAGER, Villager.Profession.PRIEST, true), + FATHER_VILLAGER("father", EntityType.VILLAGER, Villager.Profession.PRIEST, false), + SMITH_VILLAGER("smith", EntityType.VILLAGER, Villager.Profession.BLACKSMITH, true), + BUTCHER_VILLAGER("butcher", EntityType.VILLAGER, Villager.Profession.BUTCHER, true), + SIZE_SLIME("", "<1-100>", EntityType.SLIME.getEntityClass(), Data.SIZE, true), + NUM_EXPERIENCE_ORB("", "<1-2000000000>", EntityType.EXPERIENCE_ORB, Data.EXP, true); + + + public enum Data + { + ADULT, + BABY, + CHEST, + ADULTZOMBIE, + BABYZOMBIE, + VILLAGER, + HORSESADDLE, + PIGSADDLE, + ELECTRIFIED, + WITHER, + ANGRY, + TAMED, + COLORABLE, + EXP, + SIZE; + } + public static final Logger logger = Logger.getLogger("Essentials"); + + private MobData(String n, Object type, Object value, boolean isPublic) + { + this.nickname = n; + this.matched = n; + this.helpMessage = n; + this.type = type; + this.value = value; + this.isPublic = isPublic; + } + + private MobData(String n, String h, Object type, Object value, boolean isPublic) + { + this.nickname = n; + this.matched = n; + this.helpMessage = h; + this.type = type; + this.value = value; + this.isPublic = isPublic; + } + final private String nickname; + final private String helpMessage; + final private Object type; + final private Object value; + final private boolean isPublic; + private String matched; + + public static LinkedHashMap getPossibleData(final Entity spawned, boolean publicOnly) + { + LinkedHashMap mobList = new LinkedHashMap(); + for (MobData data : MobData.values()) + { + if (data.type instanceof EntityType && spawned.getType().equals(data.type) && ((publicOnly && data.isPublic) || !publicOnly)) + { + mobList.put(data.nickname.toLowerCase(Locale.ENGLISH), data); + } + else if (data.type instanceof Class && ((Class)data.type).isAssignableFrom(spawned.getClass()) && ((publicOnly && data.isPublic) || !publicOnly)) + { + mobList.put(data.nickname.toLowerCase(Locale.ENGLISH), data); + } + } + + return mobList; + } + + public static List getValidHelp(final Entity spawned) + { + List output = new ArrayList(); + LinkedHashMap posData = getPossibleData(spawned, true); + + for (MobData data : posData.values()) + { + output.add(data.helpMessage); + } + return output; + } + + public static MobData fromData(final Entity spawned, final String name) + { + if (name.isEmpty()) + { + return null; + } + + LinkedHashMap posData = getPossibleData(spawned, false); + for (String data : posData.keySet()) + { + if (name.contains(data)) + { + return posData.get(data); + } + } + return null; + } + + public String getMatched() + { + return this.matched; + } + + public void setData(final Entity spawned, final Player target, final String rawData) throws Exception + { + if (this.value.equals(Data.ANGRY)) + { + ((Wolf)spawned).setAngry(true); + } + else if (this.value.equals(Data.ADULT)) + { + ((Ageable)spawned).setAdult(); + } + else if (this.value.equals(Data.BABY)) + { + ((Ageable)spawned).setBaby(); + } + else if (this.value.equals(Data.ADULTZOMBIE)) + { + ((Zombie)spawned).setBaby(false); + } + else if (this.value.equals(Data.BABYZOMBIE)) + { + ((Zombie)spawned).setBaby(true); + } + else if (this.value.equals(Data.CHEST)) + { + ((Horse)spawned).setTamed(true); + ((Horse)spawned).setCarryingChest(true); + } + else if (this.value.equals(Data.ELECTRIFIED)) + { + ((Creeper)spawned).setPowered(true); + } + else if (this.value.equals(Data.HORSESADDLE)) + { + final Horse horse = ((Horse)spawned); + horse.setTamed(true); + horse.setOwner(target); + horse.getInventory().setSaddle(new ItemStack(Material.SADDLE, 1)); + } + else if (this.value.equals(Data.PIGSADDLE)) + { + ((Pig)spawned).setSaddle(true); + } + else if (this.value.equals(Data.TAMED)) + { + final Tameable tameable = ((Tameable)spawned); + tameable.setTamed(true); + tameable.setOwner(target); + } + else if (this.value.equals(Data.VILLAGER)) + { + ((Zombie)spawned).setVillager(this.value.equals(Data.VILLAGER)); + } + else if (this.value.equals(Data.WITHER)) + { + ((Skeleton)spawned).setSkeletonType(Skeleton.SkeletonType.WITHER); + } + else if (this.value.equals(Data.COLORABLE)) + { + final String color = rawData.toUpperCase(Locale.ENGLISH); + try + { + if (color.equals("RANDOM")) + { + final Random rand = new Random(); + ((Colorable)spawned).setColor(DyeColor.values()[rand.nextInt(DyeColor.values().length)]); + } + else if (!color.isEmpty()) + { + ((Colorable)spawned).setColor(DyeColor.valueOf(color)); + } + this.matched = rawData; + } + catch (Exception e) + { + throw new Exception(tl("sheepMalformedColor"), e); + } + } + else if (this.value.equals(Data.EXP)) + { + try + { + ((ExperienceOrb)spawned).setExperience(Integer.parseInt(rawData)); + this.matched = rawData; + } + catch (NumberFormatException e) + { + throw new Exception(tl("invalidNumber"), e); + } + } + else if (this.value.equals(Data.SIZE)) + { + try + { + ((Slime)spawned).setSize(Integer.parseInt(rawData)); + this.matched = rawData; + } + catch (NumberFormatException e) + { + throw new Exception(tl("slimeMalformedSize"), e); + } + } + else if (this.value instanceof Horse.Color) + { + ((Horse)spawned).setColor((Horse.Color)this.value); + } + else if (this.value instanceof Horse.Style) + { + ((Horse)spawned).setStyle((Horse.Style)this.value); + } + else if (this.value instanceof Horse.Variant) + { + ((Horse)spawned).setVariant((Horse.Variant)this.value); + } + else if (this.value instanceof Ocelot.Type) + { + ((Ocelot)spawned).setCatType((Ocelot.Type)this.value); + } + else if (this.value instanceof Villager.Profession) + { + ((Villager)spawned).setProfession((Villager.Profession)this.value); + } + else if (this.value instanceof Material) + { + if (this.type.equals(EntityType.HORSE)) + { + ((Horse)spawned).setTamed(true); + ((Horse)spawned).getInventory().setArmor(new ItemStack((Material)this.value, 1)); + } + else if (this.type.equals(EntityType.ZOMBIE.getEntityClass()) || this.type.equals(EntityType.SKELETON)) + { + final EntityEquipment invent = ((LivingEntity)spawned).getEquipment(); + invent.setItemInHand(new ItemStack((Material)this.value, 1)); + invent.setItemInHandDropChance(0.1f); + } + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/OfflinePlayer.java b/Essentials/src/com/earth2me/essentials/OfflinePlayer.java new file mode 100644 index 0000000000..2fda39778a --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/OfflinePlayer.java @@ -0,0 +1,1549 @@ +package com.earth2me.essentials; + +import static com.earth2me.essentials.I18n.tl; +import java.net.InetSocketAddress; +import java.util.*; +import org.bukkit.*; +import org.bukkit.block.Block; +import org.bukkit.conversations.Conversation; +import org.bukkit.conversations.ConversationAbandonedEvent; +import org.bukkit.entity.*; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; +import org.bukkit.inventory.*; +import org.bukkit.inventory.InventoryView.Property; +import org.bukkit.map.MapView; +import org.bukkit.metadata.MetadataValue; +import org.bukkit.permissions.Permission; +import org.bukkit.permissions.PermissionAttachment; +import org.bukkit.permissions.PermissionAttachmentInfo; +import org.bukkit.plugin.Plugin; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.scoreboard.Scoreboard; +import org.bukkit.util.Vector; + + +public class OfflinePlayer implements Player +{ + private final transient Server server; + private transient Location location = new Location(null, 0, 0, 0, 0, 0); + private transient World world; + private transient org.bukkit.OfflinePlayer base; + private boolean allowFlight = false; + private boolean isFlying = false; + private String name = null; + + public OfflinePlayer(final UUID uuid, final Server server) + { + this.server = server; + this.world = server.getWorlds().get(0); + this.base = server.getOfflinePlayer(uuid); + this.name = base.getName(); + } + + public OfflinePlayer(final String name, final Server server) + { + this.server = server; + this.world = server.getWorlds().get(0); + this.base = server.getOfflinePlayer(name); + this.name = name; + } + + @Override + public void sendMessage(final String string) + { + } + + @Override + public String getDisplayName() + { + return base.getName(); + } + + @Override + public void setDisplayName(String string) + { + } + + @Override + public void setCompassTarget(Location lctn) + { + } + + @Override + public InetSocketAddress getAddress() + { + return null; + } + + @Override + public void kickPlayer(String string) + { + } + + @Override + public PlayerInventory getInventory() + { + return null; + } + + @Override + public ItemStack getItemInHand() + { + return null; + } + + @Override + public void setItemInHand(ItemStack is) + { + } + + @Override + public double getHealth() + { + return 0; + } + + @Override + public void setHealth(double d) + { + } + + @Override + public Egg throwEgg() + { + return null; + } + + @Override + public Snowball throwSnowball() + { + return null; + } + + @Override + public Arrow shootArrow() + { + return null; + } + + @Override + public boolean isInsideVehicle() + { + return false; + } + + @Override + public boolean leaveVehicle() + { + return false; + } + + @Override + public Vehicle getVehicle() + { + return null; + } + + @Override + public Location getLocation() + { + return location; + } + + @Override + public World getWorld() + { + return world; + } + + public void setLocation(Location loc) + { + location = loc; + world = loc.getWorld(); + } + + public void teleportTo(Location lctn) + { + } + + public void teleportTo(Entity entity) + { + } + + @Override + public int getEntityId() + { + return -1; + } + + @Override + public boolean performCommand(String string) + { + return false; + } + + @Override + public int getRemainingAir() + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void setRemainingAir(int i) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public int getMaximumAir() + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void setMaximumAir(int i) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public boolean isSneaking() + { + return false; + } + + @Override + public void setSneaking(boolean bln) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void updateInventory() + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void chat(String string) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public double getEyeHeight() + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public double getEyeHeight(boolean bln) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public List getLineOfSight(HashSet hs, int i) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public Block getTargetBlock(HashSet hs, int i) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public List getLastTwoTargetBlocks(HashSet hs, int i) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public int getFireTicks() + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public int getMaxFireTicks() + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void setFireTicks(int i) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void remove() + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public Server getServer() + { + return server; + } + + public Vector getMomentum() + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + public void setMomentum(Vector vector) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void setVelocity(Vector vector) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public Vector getVelocity() + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void damage(double d) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void damage(double d, Entity entity) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public Location getEyeLocation() + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void sendRawMessage(String string) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public Location getCompassTarget() + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public int getMaximumNoDamageTicks() + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void setMaximumNoDamageTicks(int i) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public double getLastDamage() + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void setLastDamage(double d) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public int getNoDamageTicks() + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void setNoDamageTicks(int i) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public boolean teleport(Location lctn) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public boolean teleport(Entity entity) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public Entity getPassenger() + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public boolean setPassenger(Entity entity) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public boolean isEmpty() + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public boolean eject() + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void saveData() + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void loadData() + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public boolean isSleeping() + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public int getSleepTicks() + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public List getNearbyEntities(double d, double d1, double d2) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public boolean isDead() + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public float getFallDistance() + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void setFallDistance(float f) + { + } + + @Override + public void setSleepingIgnored(boolean bln) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public boolean isSleepingIgnored() + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void awardAchievement(Achievement a) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void removeAchievement(Achievement achievement) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public boolean hasAchievement(Achievement achievement) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void incrementStatistic(Statistic ststc) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void decrementStatistic(Statistic statistic) throws IllegalArgumentException + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void incrementStatistic(Statistic ststc, int i) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void decrementStatistic(Statistic statistic, int i) throws IllegalArgumentException + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void setStatistic(Statistic statistic, int i) throws IllegalArgumentException + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public int getStatistic(Statistic statistic) throws IllegalArgumentException + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void incrementStatistic(Statistic ststc, Material mtrl) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void decrementStatistic(Statistic statistic, Material material) throws IllegalArgumentException + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public int getStatistic(Statistic statistic, Material material) throws IllegalArgumentException + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void incrementStatistic(Statistic ststc, Material mtrl, int i) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void decrementStatistic(Statistic statistic, Material material, int i) throws IllegalArgumentException + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void setStatistic(Statistic statistic, Material material, int i) throws IllegalArgumentException + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void incrementStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void decrementStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public int getStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void incrementStatistic(Statistic statistic, EntityType entityType, int i) throws IllegalArgumentException + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void decrementStatistic(Statistic statistic, EntityType entityType, int i) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void setStatistic(Statistic statistic, EntityType entityType, int i) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void playNote(Location lctn, byte b, byte b1) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void sendBlockChange(Location lctn, Material mtrl, byte b) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void sendBlockChange(Location lctn, int i, byte b) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void setLastDamageCause(EntityDamageEvent ede) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public EntityDamageEvent getLastDamageCause() + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public void playEffect(Location lctn, Effect effect, int i) + { + throw new UnsupportedOperationException(tl("notSupportedYet")); + } + + @Override + public boolean sendChunkChange(Location lctn, int i, int i1, int i2, byte[] bytes) + { + return true; + } + + @Override + public void playNote(Location lctn, Instrument i, Note note) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setPlayerTime(long l, boolean bln) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long getPlayerTime() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long getPlayerTimeOffset() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isPlayerTimeRelative() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void resetPlayerTime() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isPermissionSet(String string) + { + return false; + } + + @Override + public boolean isPermissionSet(Permission prmsn) + { + return false; + } + + @Override + public boolean hasPermission(String string) + { + return false; + } + + @Override + public boolean hasPermission(Permission prmsn) + { + return false; + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin, String string, boolean bln) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin, String string, boolean bln, int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin, int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void removeAttachment(PermissionAttachment pa) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void recalculatePermissions() + { + } + + @Override + public Set getEffectivePermissions() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void sendMap(MapView mv) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public GameMode getGameMode() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setGameMode(GameMode gm) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getLevel() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setLevel(int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getTotalExperience() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setTotalExperience(int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public float getExhaustion() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setExhaustion(float f) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public float getSaturation() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setSaturation(float f) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getFoodLevel() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setFoodLevel(int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isSprinting() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setSprinting(boolean bln) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setPlayerListName(String name) + { + } + + @Override + public String getPlayerListName() + { + return name; + } + + @Override + public int getTicksLived() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setTicksLived(int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public double getMaxHealth() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void giveExp(int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public float getExp() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setExp(float f) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean teleport(Location lctn, TeleportCause tc) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean teleport(Entity entity, TeleportCause tc) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Player getKiller() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + void setName(final String name) + { + this.name = base.getName(); + if (this.name == null) + { + this.name = name; + } + } + + @Override + public void sendPluginMessage(Plugin plugin, String string, byte[] bytes) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Set getListeningPluginChannels() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setAllowFlight(boolean bln) + { + allowFlight = bln; + } + + @Override + public boolean getAllowFlight() + { + return allowFlight; + } + + @Override + public void setBedSpawnLocation(Location lctn) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setBedSpawnLocation(Location lctn, boolean force) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void playEffect(EntityEffect ee) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void hidePlayer(Player player) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void showPlayer(Player player) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean canSee(Player player) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean addPotionEffect(PotionEffect pe) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean addPotionEffect(PotionEffect pe, boolean bln) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean addPotionEffects(Collection clctn) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean hasPotionEffect(PotionEffectType pet) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void removePotionEffect(PotionEffectType pet) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getActivePotionEffects() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public T launchProjectile(Class arg0) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public EntityType getType() + { + return EntityType.PLAYER; + } + + @Override + public void playEffect(Location lctn, Effect effect, T t) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean setWindowProperty(Property prprt, int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public InventoryView getOpenInventory() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public InventoryView openInventory(Inventory invntr) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public InventoryView openWorkbench(Location lctn, boolean bln) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public InventoryView openEnchanting(Location lctn, boolean bln) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void openInventory(InventoryView iv) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void closeInventory() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ItemStack getItemOnCursor() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setItemOnCursor(ItemStack is) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setMetadata(String string, MetadataValue mv) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List getMetadata(String string) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean hasMetadata(String string) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void removeMetadata(String string, Plugin plugin) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isConversing() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void acceptConversationInput(String string) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean beginConversation(Conversation c) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void abandonConversation(Conversation c) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void sendMessage(String[] strings) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isBlocking() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void abandonConversation(Conversation arg0, ConversationAbandonedEvent arg1) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isFlying() + { + return isFlying; + } + + @Override + public void setFlying(boolean arg0) + { + isFlying = arg0; + } + + @Override + public int getExpToLevel() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean hasLineOfSight(Entity entity) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValid() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setFlySpeed(float value) throws IllegalArgumentException + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setWalkSpeed(float value) throws IllegalArgumentException + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public float getFlySpeed() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public float getWalkSpeed() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Inventory getEnderChest() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void playSound(Location arg0, Sound arg1, float arg2, float arg3) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void giveExpLevels(int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean getRemoveWhenFarAway() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setRemoveWhenFarAway(boolean bln) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public EntityEquipment getEquipment() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setCanPickupItems(boolean bln) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean getCanPickupItems() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Location getLocation(Location lctn) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setTexturePack(String string) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setResourcePack(String s) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setMaxHealth(double i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void resetMaxHealth() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setCustomName(String string) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getCustomName() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setCustomNameVisible(boolean bln) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isCustomNameVisible() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setPlayerWeather(WeatherType arg0) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public WeatherType getPlayerWeather() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void resetPlayerWeather() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isOnGround() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Scoreboard getScoreboard() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setScoreboard(Scoreboard scrbrd) throws IllegalArgumentException, IllegalStateException + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int _INVALID_getLastDamage() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void _INVALID_setLastDamage(int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void _INVALID_damage(int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void _INVALID_damage(int i, Entity entity) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int _INVALID_getHealth() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void _INVALID_setHealth(int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int _INVALID_getMaxHealth() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void _INVALID_setMaxHealth(int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void playSound(Location arg0, String arg1, float arg2, float arg3) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isHealthScaled() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setHealthScaled(boolean arg0) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setHealthScale(double arg0) throws IllegalArgumentException + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public double getHealthScale() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isLeashed() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Entity getLeashHolder() throws IllegalStateException + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean setLeashHolder(Entity arg0) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public T launchProjectile(Class type, Vector vector) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void sendSignChange(Location arg0, String[] arg1) throws IllegalArgumentException + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Location getBedSpawnLocation() + { + return null; + } + + @Override + public String getName() + { + return name; + } + + @Override + public UUID getUniqueId() + { + return base.getUniqueId(); + } + + @Override + public boolean isOp() + { + return base.isOp(); + } + + @Override + public void setOp(boolean value) + { + base.setOp(value); + } + + @Override + public boolean isOnline() + { + return base.isOnline(); + } + + @Override + public boolean isBanned() + { + if (base.getName() == null && getName() != null) + { + return server.getBanList(BanList.Type.NAME).isBanned(getName()); + } + return base.isBanned(); + } + + @Override + public void setBanned(boolean banned) + { + if (base.getName() == null && getName() != null) + { + if (banned) + { + server.getBanList(BanList.Type.NAME).addBan(getName(), null, null, null); + } + else + { + server.getBanList(BanList.Type.NAME).pardon(getName()); + } + } + base.setBanned(banned); + } + + @Override + public boolean isWhitelisted() + { + return base.isWhitelisted(); + } + + @Override + public void setWhitelisted(boolean value) + { + base.setWhitelisted(value); + } + + @Override + public Player getPlayer() + { + return base.getPlayer(); + } + + @Override + public long getFirstPlayed() + { + return base.getFirstPlayed(); + } + + @Override + public long getLastPlayed() + { + return base.getLastPlayed(); + } + + @Override + public boolean hasPlayedBefore() + { + return base.hasPlayedBefore(); + } + + @Override + public Map serialize() + { + return base.serialize(); + } +} diff --git a/Essentials/src/com/earth2me/essentials/PlayerExtension.java b/Essentials/src/com/earth2me/essentials/PlayerExtension.java new file mode 100644 index 0000000000..36c2289e3f --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/PlayerExtension.java @@ -0,0 +1,48 @@ +package com.earth2me.essentials; + +import lombok.Delegate; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.serialization.ConfigurationSerializable; +import org.bukkit.entity.Entity; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.permissions.Permissible; +import org.bukkit.permissions.ServerOperator; + + +public class PlayerExtension +{ + protected Player base; + + public PlayerExtension(final Player base) + { + this.base = base; + } + + public final Player getBase() + { + return base; + } + + public final Player setBase(final Player base) + { + return this.base = base; + } + + public Server getServer() + { + return base.getServer(); + } + + public World getWorld() { + return base.getWorld(); + } + + public Location getLocation() { + return base.getLocation(); + } +} diff --git a/Essentials/src/com/earth2me/essentials/PlayerList.java b/Essentials/src/com/earth2me/essentials/PlayerList.java new file mode 100644 index 0000000000..fb8a1f0bc8 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/PlayerList.java @@ -0,0 +1,156 @@ +package com.earth2me.essentials; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.utils.FormatUtil; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import org.bukkit.Server; +import org.bukkit.entity.Player; + + +public class PlayerList +{ + // Cosmetic list formatting + public static String listUsers(final IEssentials ess, final List users, final String seperator) + { + final StringBuilder groupString = new StringBuilder(); + Collections.sort(users); + boolean needComma = false; + for (User user : users) + { + if (needComma) + { + groupString.append(seperator); + } + needComma = true; + if (user.isAfk()) + { + groupString.append(tl("listAfkTag")); + } + if (user.isHidden()) + { + groupString.append(tl("listHiddenTag")); + } + user.setDisplayNick(); + groupString.append(user.getDisplayName()); + groupString.append("\u00a7f"); + } + return groupString.toString(); + } + + // Produce a user summary: There are 5 out of maximum 10 players online. + public static String listSummary(final IEssentials ess, final User user, final boolean showHidden) + { + Server server = ess.getServer(); + int playerHidden = 0; + int hiddenCount = 0; + for (User onlinePlayer : ess.getOnlineUsers()) + { + if (onlinePlayer.isHidden() || (user != null && !user.getBase().canSee(onlinePlayer.getBase()))) + { + playerHidden++; + if (showHidden || user.getBase().canSee(onlinePlayer.getBase())) + { + hiddenCount++; + } + } + } + String online; + if (hiddenCount > 0) + { + online = tl("listAmountHidden", ess.getOnlinePlayers().size() - playerHidden, hiddenCount, server.getMaxPlayers()); + } + else + { + online = tl("listAmount", ess.getOnlinePlayers().size() - playerHidden, server.getMaxPlayers()); + } + return online; + } + + // Build the basic player list, divided by groups. + public static Map> getPlayerLists(final IEssentials ess, final User sender, final boolean showHidden) + { + Server server = ess.getServer(); + final Map> playerList = new HashMap>(); + for (User onlineUser : ess.getOnlineUsers()) + { + if ((sender == null && !showHidden && onlineUser.isHidden()) || + (sender != null && !showHidden && !sender.getBase().canSee(onlineUser.getBase()))) + { + continue; + } + final String group = FormatUtil.stripFormat(FormatUtil.stripEssentialsFormat(onlineUser.getGroup().toLowerCase())); + List list = playerList.get(group); + if (list == null) + { + list = new ArrayList(); + playerList.put(group, list); + } + list.add(onlineUser); + } + return playerList; + } + + // Handle the merging of groups + public static List getMergedList(final IEssentials ess, final Map> playerList, final String groupName) + { + final Set configGroups = ess.getSettings().getListGroupConfig().keySet(); + final List users = new ArrayList(); + for (String configGroup : configGroups) + { + if (configGroup.equalsIgnoreCase(groupName)) + { + String[] groupValues = ess.getSettings().getListGroupConfig().get(configGroup).toString().trim().split(" "); + for (String groupValue : groupValues) + { + groupValue = groupValue.toLowerCase(Locale.ENGLISH); + if (groupValue == null || groupValue.isEmpty()) + { + continue; + } + List u = playerList.get(groupValue.trim()); + if (u == null || u.isEmpty()) + { + continue; + } + playerList.remove(groupValue); + users.addAll(u); + } + } + } + return users; + } + + // Output a playerlist of just a single group, /list + public static String listGroupUsers(final IEssentials ess, final Map> playerList, final String groupName) throws Exception + { + final List users = getMergedList(ess, playerList, groupName); + final List groupUsers = playerList.get(groupName); + if (groupUsers != null && !groupUsers.isEmpty()) + { + users.addAll(groupUsers); + } + if (users == null || users.isEmpty()) + { + throw new Exception(tl("groupDoesNotExist")); + } + final StringBuilder displayGroupName = new StringBuilder(); + displayGroupName.append(Character.toTitleCase(groupName.charAt(0))); + displayGroupName.append(groupName.substring(1)); + return outputFormat(displayGroupName.toString(), listUsers(ess, users, ", ")); + } + + // Build the output string + public static String outputFormat(final String group, final String message) + { + final StringBuilder outputString = new StringBuilder(); + outputString.append(tl("listGroupTag", FormatUtil.replaceFormat(group))); + outputString.append(message); + return outputString.toString(); + } +} diff --git a/Essentials/src/com/earth2me/essentials/PlayerTarget.java b/Essentials/src/com/earth2me/essentials/PlayerTarget.java new file mode 100644 index 0000000000..6fd714ca15 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/PlayerTarget.java @@ -0,0 +1,22 @@ +package com.earth2me.essentials; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Player; + + +public class PlayerTarget implements ITarget +{ + private final String name; + + public PlayerTarget(Player entity) + { + this.name = entity.getName(); + } + + @Override + public Location getLocation() + { + return Bukkit.getServer().getPlayerExact(name).getLocation(); + } +} \ No newline at end of file diff --git a/Essentials/src/com/earth2me/essentials/Potions.java b/Essentials/src/com/earth2me/essentials/Potions.java new file mode 100644 index 0000000000..616225814a --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/Potions.java @@ -0,0 +1,145 @@ +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.potion.PotionEffectType; + + +public class Potions +{ + private static final Map POTIONS = new HashMap(); + private static final Map ALIASPOTIONS = new HashMap(); + + static + { + + POTIONS.put("speed", PotionEffectType.SPEED); + ALIASPOTIONS.put("fast", PotionEffectType.SPEED); + ALIASPOTIONS.put("runfast", PotionEffectType.SPEED); + ALIASPOTIONS.put("sprint", PotionEffectType.SPEED); + ALIASPOTIONS.put("swift", PotionEffectType.SPEED); + + POTIONS.put("slowness", PotionEffectType.SLOW); + ALIASPOTIONS.put("slow", PotionEffectType.SLOW); + ALIASPOTIONS.put("sluggish", PotionEffectType.SLOW); + + POTIONS.put("haste", PotionEffectType.FAST_DIGGING); + ALIASPOTIONS.put("superpick", PotionEffectType.FAST_DIGGING); + ALIASPOTIONS.put("quickmine", PotionEffectType.FAST_DIGGING); + ALIASPOTIONS.put("digspeed", PotionEffectType.FAST_DIGGING); + ALIASPOTIONS.put("digfast", PotionEffectType.FAST_DIGGING); + ALIASPOTIONS.put("sharp", PotionEffectType.FAST_DIGGING); + + POTIONS.put("fatigue", PotionEffectType.SLOW_DIGGING); + ALIASPOTIONS.put("slow", PotionEffectType.SLOW_DIGGING); + ALIASPOTIONS.put("dull", PotionEffectType.SLOW_DIGGING); + + POTIONS.put("strength", PotionEffectType.INCREASE_DAMAGE); + ALIASPOTIONS.put("strong", PotionEffectType.INCREASE_DAMAGE); + ALIASPOTIONS.put("bull", PotionEffectType.INCREASE_DAMAGE); + ALIASPOTIONS.put("attack", PotionEffectType.INCREASE_DAMAGE); + + POTIONS.put("heal", PotionEffectType.HEAL); + ALIASPOTIONS.put("healthy", PotionEffectType.HEAL); + ALIASPOTIONS.put("instaheal", PotionEffectType.HEAL); + + POTIONS.put("harm", PotionEffectType.HARM); + ALIASPOTIONS.put("harming", PotionEffectType.HARM); + ALIASPOTIONS.put("injure", PotionEffectType.HARM); + ALIASPOTIONS.put("damage", PotionEffectType.HARM); + ALIASPOTIONS.put("inflict", PotionEffectType.HARM); + + POTIONS.put("jump", PotionEffectType.JUMP); + ALIASPOTIONS.put("leap", PotionEffectType.JUMP); + + POTIONS.put("nausea", PotionEffectType.CONFUSION); + ALIASPOTIONS.put("sick", PotionEffectType.CONFUSION); + ALIASPOTIONS.put("sickness", PotionEffectType.CONFUSION); + ALIASPOTIONS.put("confusion", PotionEffectType.CONFUSION); + + POTIONS.put("regeneration", PotionEffectType.REGENERATION); + ALIASPOTIONS.put("regen", PotionEffectType.REGENERATION); + + POTIONS.put("resistance", PotionEffectType.DAMAGE_RESISTANCE); + ALIASPOTIONS.put("dmgresist", PotionEffectType.DAMAGE_RESISTANCE); + ALIASPOTIONS.put("armor", PotionEffectType.DAMAGE_RESISTANCE); + + POTIONS.put("fireresist", PotionEffectType.FIRE_RESISTANCE); + ALIASPOTIONS.put("fireresistance", PotionEffectType.FIRE_RESISTANCE); + ALIASPOTIONS.put("resistfire", PotionEffectType.FIRE_RESISTANCE); + + POTIONS.put("waterbreath", PotionEffectType.WATER_BREATHING); + ALIASPOTIONS.put("waterbreathing", PotionEffectType.WATER_BREATHING); + + POTIONS.put("invisibility", PotionEffectType.INVISIBILITY); + ALIASPOTIONS.put("invisible", PotionEffectType.INVISIBILITY); + ALIASPOTIONS.put("invis", PotionEffectType.INVISIBILITY); + ALIASPOTIONS.put("vanish", PotionEffectType.INVISIBILITY); + ALIASPOTIONS.put("disappear", PotionEffectType.INVISIBILITY); + + POTIONS.put("blindness", PotionEffectType.BLINDNESS); + ALIASPOTIONS.put("blind", PotionEffectType.BLINDNESS); + + POTIONS.put("nightvision", PotionEffectType.NIGHT_VISION); + ALIASPOTIONS.put("vision", PotionEffectType.NIGHT_VISION); + + POTIONS.put("hunger", PotionEffectType.HUNGER); + ALIASPOTIONS.put("hungry", PotionEffectType.HUNGER); + ALIASPOTIONS.put("starve", PotionEffectType.HUNGER); + + POTIONS.put("weakness", PotionEffectType.WEAKNESS); + ALIASPOTIONS.put("weak", PotionEffectType.WEAKNESS); + + POTIONS.put("poison", PotionEffectType.POISON); + ALIASPOTIONS.put("venom", PotionEffectType.POISON); + + POTIONS.put("wither", PotionEffectType.WITHER); + ALIASPOTIONS.put("decay", PotionEffectType.WITHER); + + POTIONS.put("healthboost", PotionEffectType.HEALTH_BOOST); + ALIASPOTIONS.put("boost", PotionEffectType.HEALTH_BOOST); + + POTIONS.put("absorption", PotionEffectType.ABSORPTION); + ALIASPOTIONS.put("absorb", PotionEffectType.ABSORPTION); + + POTIONS.put("saturation", PotionEffectType.SATURATION); + ALIASPOTIONS.put("food", PotionEffectType.SATURATION); + + POTIONS.put("waterbreathing", PotionEffectType.WATER_BREATHING); + ALIASPOTIONS.put("underwaterbreathing", PotionEffectType.WATER_BREATHING); + ALIASPOTIONS.put("waterbreath", PotionEffectType.WATER_BREATHING); + ALIASPOTIONS.put("underwaterbreath", PotionEffectType.WATER_BREATHING); + ALIASPOTIONS.put("air", PotionEffectType.WATER_BREATHING); + } + + public static PotionEffectType getByName(String name) + { + PotionEffectType peffect; + if (NumberUtil.isInt(name)) + { + peffect = PotionEffectType.getById(Integer.parseInt(name)); + } + else + { + peffect = PotionEffectType.getByName(name.toUpperCase(Locale.ENGLISH)); + } + if (peffect == null) + { + peffect = POTIONS.get(name.toLowerCase(Locale.ENGLISH)); + } + if (peffect == null) + { + peffect = ALIASPOTIONS.get(name.toLowerCase(Locale.ENGLISH)); + } + return peffect; + } + + public static Set> entrySet() + { + return POTIONS.entrySet(); + } +} diff --git a/Essentials/src/com/earth2me/essentials/Settings.java b/Essentials/src/com/earth2me/essentials/Settings.java new file mode 100644 index 0000000000..b4eea47052 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/Settings.java @@ -0,0 +1,1237 @@ +package com.earth2me.essentials; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.commands.IEssentialsCommand; +import com.earth2me.essentials.signs.EssentialsSign; +import com.earth2me.essentials.signs.Signs; +import com.earth2me.essentials.textreader.IText; +import com.earth2me.essentials.textreader.SimpleTextInput; +import com.earth2me.essentials.utils.FormatUtil; +import java.io.File; +import java.math.BigDecimal; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; +import net.ess3.api.IEssentials; +import org.bukkit.ChatColor; +import org.bukkit.command.PluginCommand; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.MemoryConfiguration; +import org.bukkit.event.EventPriority; +import org.bukkit.inventory.ItemStack; + + +public class Settings implements net.ess3.api.ISettings +{ + private final transient EssentialsConf config; + private static final Logger logger = Logger.getLogger("Essentials"); + private final transient IEssentials ess; + private boolean metricsEnabled = true; + + public Settings(IEssentials ess) + { + this.ess = ess; + config = new EssentialsConf(new File(ess.getDataFolder(), "config.yml")); + config.setTemplateName("/config.yml"); + reloadConfig(); + } + + @Override + public boolean getRespawnAtHome() + { + return config.getBoolean("respawn-at-home", false); + } + + @Override + public boolean getUpdateBedAtDaytime() + { + return config.getBoolean("update-bed-at-daytime", true); + } + + @Override + public Set getMultipleHomes() + { + final ConfigurationSection section = config.getConfigurationSection("sethome-multiple"); + return section == null ? null : section.getKeys(false); + } + + @Override + public int getHomeLimit(final User user) + { + int limit = 1; + if (user.isAuthorized("essentials.sethome.multiple")) + { + limit = getHomeLimit("default"); + } + + final Set homeList = getMultipleHomes(); + if (homeList != null) + { + for (String set : homeList) + { + if (user.isAuthorized("essentials.sethome.multiple." + set) && (limit < getHomeLimit(set))) + { + limit = getHomeLimit(set); + } + } + } + return limit; + } + + @Override + public int getHomeLimit(final String set) + { + return config.getInt("sethome-multiple." + set, config.getInt("sethome-multiple.default", 3)); + } + private int chatRadius = 0; + + private int _getChatRadius() + { + return config.getInt("chat.radius", config.getInt("chat-radius", 0)); + } + + @Override + public int getChatRadius() + { + return chatRadius; + } + // #easteregg + private char chatShout = '!'; + + private char _getChatShout() + { + return config.getString("chat.shout", "!").charAt(0); + } + + @Override + public char getChatShout() + { + return chatShout; + } + // #easteregg + private char chatQuestion = '?'; + + private char _getChatQuestion() + { + return config.getString("chat.question", "?").charAt(0); + } + + @Override + public char getChatQuestion() + { + return chatQuestion; + } + private boolean teleportSafety; + + public boolean _isTeleportSafetyEnabled() + { + return config.getBoolean("teleport-safety", true); + } + + @Override + public boolean isTeleportSafetyEnabled() + { + return teleportSafety; + } + + @Override + public double getTeleportDelay() + { + return config.getDouble("teleport-delay", 0); + } + + @Override + public int getOversizedStackSize() + { + return config.getInt("oversized-stacksize", 64); + } + + @Override + public int getDefaultStackSize() + { + return config.getInt("default-stack-size", -1); + } + + @Override + public BigDecimal getStartingBalance() + { + return config.getBigDecimal("starting-balance", BigDecimal.ZERO); + } + + @Override + public boolean isCommandDisabled(final IEssentialsCommand cmd) + { + return isCommandDisabled(cmd.getName()); + } + private Set disabledCommands = new HashSet(); + + @Override + public boolean isCommandDisabled(String label) + { + return disabledCommands.contains(label); + } + + private Set getDisabledCommands() + { + Set disCommands = new HashSet(); + for (String c : config.getStringList("disabled-commands")) + { + disCommands.add(c.toLowerCase(Locale.ENGLISH)); + } + for (String c : config.getKeys(false)) + { + if (c.startsWith("disable-")) + { + disCommands.add(c.substring(8).toLowerCase(Locale.ENGLISH)); + } + } + return disCommands; + } + + @Override + public boolean isPlayerCommand(String label) + { + for (String c : config.getStringList("player-commands")) + { + if (!c.equalsIgnoreCase(label)) + { + continue; + } + return true; + } + return false; + } + + @Override + public boolean isCommandOverridden(String name) + { + for (String c : config.getStringList("overridden-commands")) + { + if (!c.equalsIgnoreCase(name)) + { + continue; + } + return true; + } + return config.getBoolean("override-" + name.toLowerCase(Locale.ENGLISH), false); + } + private ConfigurationSection commandCosts; + + @Override + public BigDecimal getCommandCost(IEssentialsCommand cmd) + { + return getCommandCost(cmd.getName()); + } + + private ConfigurationSection _getCommandCosts() + { + if (config.isConfigurationSection("command-costs")) + { + final ConfigurationSection section = config.getConfigurationSection("command-costs"); + final ConfigurationSection newSection = new MemoryConfiguration(); + for (String command : section.getKeys(false)) + { + if (command.charAt(0) == '/') + { + ess.getLogger().warning("Invalid command cost. '" + command + "' should not start with '/'."); + } + if (section.isDouble(command)) + { + newSection.set(command.toLowerCase(Locale.ENGLISH), section.getDouble(command)); + } + else if (section.isInt(command)) + { + newSection.set(command.toLowerCase(Locale.ENGLISH), (double)section.getInt(command)); + } + else if (section.isString(command)) + { + String costString = section.getString(command); + try + { + double cost = Double.parseDouble(costString.trim().replace(getCurrencySymbol(), "").replaceAll("\\W", "")); + newSection.set(command.toLowerCase(Locale.ENGLISH), cost); + } + catch (NumberFormatException ex) + { + ess.getLogger().warning("Invalid command cost for: " + command + " (" + costString + ")"); + } + + } + else + { + ess.getLogger().warning("Invalid command cost for: " + command); + } + } + return newSection; + } + return null; + } + + @Override + public BigDecimal getCommandCost(String name) + { + name = name.replace('.', '_').replace('/', '_'); + if (commandCosts != null) + { + return EssentialsConf.toBigDecimal(commandCosts.getString(name), BigDecimal.ZERO); + } + return BigDecimal.ZERO; + } + private Set socialSpyCommands = new HashSet(); + + private Set _getSocialSpyCommands() + { + Set socialspyCommands = new HashSet(); + + if (config.isList("socialspy-commands")) + { + for (String c : config.getStringList("socialspy-commands")) + { + socialspyCommands.add(c.toLowerCase(Locale.ENGLISH)); + } + } + else + { + socialspyCommands.addAll(Arrays.asList("msg", "r", "mail", "m", "whisper", "emsg", "t", "tell", "er", "reply", "ereply", "email", "action", "describe", "eme", "eaction", "edescribe", "etell", "ewhisper", "pm")); + } + + return socialspyCommands; + } + + @Override + public Set getSocialSpyCommands() + { + return socialSpyCommands; + } + private String nicknamePrefix = "~"; + + private String _getNicknamePrefix() + { + return config.getString("nickname-prefix", "~"); + } + + @Override + public String getNicknamePrefix() + { + return nicknamePrefix; + } + + @Override + public double getTeleportCooldown() + { + return config.getDouble("teleport-cooldown", 0); + } + + @Override + public double getHealCooldown() + { + return config.getDouble("heal-cooldown", 0); + } + private ConfigurationSection kits; + + private ConfigurationSection _getKits() + { + if (config.isConfigurationSection("kits")) + { + final ConfigurationSection section = config.getConfigurationSection("kits"); + final ConfigurationSection newSection = new MemoryConfiguration(); + for (String kitItem : section.getKeys(false)) + { + if (section.isConfigurationSection(kitItem)) + { + newSection.set(kitItem.toLowerCase(Locale.ENGLISH), section.getConfigurationSection(kitItem)); + } + } + return newSection; + } + return null; + } + + @Override + public ConfigurationSection getKits() + { + return kits; + } + + @Override + public Map getKit(String name) + { + name = name.replace('.', '_').replace('/', '_'); + if (getKits() != null) + { + final ConfigurationSection kits = getKits(); + if (kits.isConfigurationSection(name)) + { + return kits.getConfigurationSection(name).getValues(true); + } + } + return null; + } + private ChatColor operatorColor = null; + + @Override + public ChatColor getOperatorColor() + { + return operatorColor; + } + + private ChatColor _getOperatorColor() + { + String colorName = config.getString("ops-name-color", null); + + if (colorName == null) + { + return ChatColor.DARK_RED; + } + if ("none".equalsIgnoreCase(colorName) || colorName.isEmpty()) + { + return null; + } + + try + { + return ChatColor.valueOf(colorName.toUpperCase(Locale.ENGLISH)); + } + catch (IllegalArgumentException ex) + { + } + + return ChatColor.getByChar(colorName); + } + + @Override + public int getSpawnMobLimit() + { + return config.getInt("spawnmob-limit", 10); + } + + @Override + public boolean showNonEssCommandsInHelp() + { + return config.getBoolean("non-ess-in-help", true); + } + + @Override + public boolean hidePermissionlessHelp() + { + return config.getBoolean("hide-permissionless-help", true); + } + + @Override + public int getProtectCreeperMaxHeight() + { + return config.getInt("protect.creeper.max-height", -1); + } + + @Override + public boolean areSignsDisabled() + { + return !signsEnabled; + } + + @Override + public long getBackupInterval() + { + return config.getInt("backup.interval", 1440); // 1440 = 24 * 60 + } + + @Override + public String getBackupCommand() + { + return config.getString("backup.command", null); + } + private final Map chatFormats = Collections.synchronizedMap(new HashMap()); + + @Override + public String getChatFormat(String group) + { + String mFormat = chatFormats.get(group); + if (mFormat == null) + { + mFormat = config.getString("chat.group-formats." + (group == null ? "Default" : group), + config.getString("chat.format", "&7[{GROUP}]&r {DISPLAYNAME}&7:&r {MESSAGE}")); + mFormat = FormatUtil.replaceFormat(mFormat); + mFormat = mFormat.replace("{DISPLAYNAME}", "%1$s"); + mFormat = mFormat.replace("{MESSAGE}", "%2$s"); + mFormat = mFormat.replace("{GROUP}", "{0}"); + mFormat = mFormat.replace("{WORLD}", "{1}"); + mFormat = mFormat.replace("{WORLDNAME}", "{1}"); + mFormat = mFormat.replace("{SHORTWORLDNAME}", "{2}"); + mFormat = mFormat.replace("{TEAMPREFIX}", "{3}"); + mFormat = mFormat.replace("{TEAMSUFFIX}", "{4}"); + mFormat = mFormat.replace("{TEAMNAME}", "{5}"); + mFormat = "§r".concat(mFormat); + chatFormats.put(group, mFormat); + } + return mFormat; + } + + @Override + public boolean getAnnounceNewPlayers() + { + return !config.getString("newbies.announce-format", "-").isEmpty(); + } + + @Override + public IText getAnnounceNewPlayerFormat() + { + return new SimpleTextInput(FormatUtil.replaceFormat(config.getString("newbies.announce-format", "&dWelcome {DISPLAYNAME} to the server!"))); + } + + @Override + public String getNewPlayerKit() + { + return config.getString("newbies.kit", ""); + } + + @Override + public String getNewbieSpawn() + { + return config.getString("newbies.spawnpoint", "default"); + } + + @Override + public boolean getPerWarpPermission() + { + return config.getBoolean("per-warp-permission", false); + } + + @Override + public Map getListGroupConfig() + { + if (config.isConfigurationSection("list")) + { + Map values = config.getConfigurationSection("list").getValues(false); + if (!values.isEmpty()) + { + return values; + } + } + Map defaultMap = new HashMap(); + if (config.getBoolean("sort-list-by-groups", false)) + { + defaultMap.put("ListByGroup", "ListByGroup"); + } + else + { + defaultMap.put("Players", "*"); + } + return defaultMap; + } + + @Override + public void reloadConfig() + { + config.load(); + noGodWorlds = new HashSet(config.getStringList("no-god-in-worlds")); + enabledSigns = _getEnabledSigns(); + teleportSafety = _isTeleportSafetyEnabled(); + teleportInvulnerabilityTime = _getTeleportInvulnerability(); + teleportInvulnerability = _isTeleportInvulnerability(); + disableItemPickupWhileAfk = _getDisableItemPickupWhileAfk(); + registerBackInListener = _registerBackInListener(); + cancelAfkOnInteract = _cancelAfkOnInteract(); + cancelAfkOnMove = _cancelAfkOnMove() && cancelAfkOnInteract; + getFreezeAfkPlayers = _getFreezeAfkPlayers(); + itemSpawnBl = _getItemSpawnBlacklist(); + loginAttackDelay = _getLoginAttackDelay(); + signUsePerSecond = _getSignUsePerSecond(); + kits = _getKits(); + chatFormats.clear(); + changeDisplayName = _changeDisplayName(); + disabledCommands = getDisabledCommands(); + nicknamePrefix = _getNicknamePrefix(); + operatorColor = _getOperatorColor(); + changePlayerListName = _changePlayerListName(); + configDebug = _isDebug(); + prefixsuffixconfigured = _isPrefixSuffixConfigured(); + addprefixsuffix = _addPrefixSuffix(); + disablePrefix = _disablePrefix(); + disableSuffix = _disableSuffix(); + chatRadius = _getChatRadius(); + chatShout = _getChatShout(); + chatQuestion = _getChatQuestion(); + commandCosts = _getCommandCosts(); + socialSpyCommands = _getSocialSpyCommands(); + warnOnBuildDisallow = _warnOnBuildDisallow(); + mailsPerMinute = _getMailsPerMinute(); + maxMoney = _getMaxMoney(); + minMoney = _getMinMoney(); + permissionsLagWarning = _getPermissionsLagWarning(); + economyLagWarning = _getEconomyLagWarning(); + economyLog = _isEcoLogEnabled(); + economyLogUpdate = _isEcoLogUpdateEnabled(); + economyDisabled = _isEcoDisabled(); + allowSilentJoin = _allowSilentJoinQuit(); + customJoinMessage = _getCustomJoinMessage(); + isCustomJoinMessage = !customJoinMessage.equals("none"); + customQuitMessage = _getCustomQuitMessage(); + isCustomQuitMessage = !customQuitMessage.equals("none"); + } + private List itemSpawnBl = new ArrayList(); + + @Override + public List itemSpawnBlacklist() + { + return itemSpawnBl; + } + + private List _getItemSpawnBlacklist() + { + final List epItemSpwn = new ArrayList(); + if (ess.getItemDb() == null) + { + logger.log(Level.FINE, "Aborting ItemSpawnBL read, itemDB not yet loaded."); + return epItemSpwn; + } + for (String itemName : config.getString("item-spawn-blacklist", "").split(",")) + { + itemName = itemName.trim(); + if (itemName.isEmpty()) + { + continue; + } + try + { + final ItemStack iStack = ess.getItemDb().get(itemName); + epItemSpwn.add(iStack.getTypeId()); + } + catch (Exception ex) + { + logger.log(Level.SEVERE, tl("unknownItemInList", itemName, "item-spawn-blacklist")); + } + } + return epItemSpwn; + } + private List enabledSigns = new ArrayList(); + private boolean signsEnabled = false; + + @Override + public List enabledSigns() + { + return enabledSigns; + } + + private List _getEnabledSigns() + { + List newSigns = new ArrayList(); + + for (String signName : config.getStringList("enabledSigns")) + { + signName = signName.trim().toUpperCase(Locale.ENGLISH); + if (signName.isEmpty()) + { + continue; + } + if (signName.equals("COLOR") || signName.equals("COLOUR")) + { + signsEnabled = true; + continue; + } + try + { + newSigns.add(Signs.valueOf(signName).getSign()); + } + catch (Exception ex) + { + logger.log(Level.SEVERE, tl("unknownItemInList", signName, "enabledSigns")); + continue; + } + signsEnabled = true; + } + return newSigns; + } + private boolean warnOnBuildDisallow; + + private boolean _warnOnBuildDisallow() + { + return config.getBoolean("protect.disable.warn-on-build-disallow", false); + } + + @Override + public boolean warnOnBuildDisallow() + { + return warnOnBuildDisallow; + } + private boolean debug = false; + private boolean configDebug = false; + + private boolean _isDebug() + { + return config.getBoolean("debug", false); + } + + @Override + public boolean isDebug() + { + return debug || configDebug; + } + + @Override + public boolean warnOnSmite() + { + return config.getBoolean("warn-on-smite", true); + } + + @Override + public boolean permissionBasedItemSpawn() + { + return config.getBoolean("permission-based-item-spawn", false); + } + + @Override + public String getLocale() + { + return config.getString("locale", ""); + } + + //This method should always only return one character due to the implementation of the calling methods + //If you need to use a string currency, for example "coins", use the translation key 'currency'. + @Override + public String getCurrencySymbol() + { + return config.getString("currency-symbol", "$").concat("$").substring(0, 1).replaceAll("[0-9]", "$"); + } + + // #easteregg + @Override + public boolean isTradeInStacks(int id) + { + return config.getBoolean("trade-in-stacks-" + id, false); + } + // #easteregg + private boolean economyDisabled = false; + + public boolean _isEcoDisabled() + { + return config.getBoolean("disable-eco", false); + } + + @Override + public boolean isEcoDisabled() + { + return economyDisabled; + } + + @Override + public boolean getProtectPreventSpawn(final String creatureName) + { + return config.getBoolean("protect.prevent.spawn." + creatureName, false); + } + + @Override + public List getProtectList(final String configName) + { + final List list = new ArrayList(); + for (String itemName : config.getString(configName, "").split(",")) + { + itemName = itemName.trim(); + if (itemName.isEmpty()) + { + continue; + } + ItemStack itemStack; + try + { + itemStack = ess.getItemDb().get(itemName); + list.add(itemStack.getTypeId()); + } + catch (Exception ex) + { + logger.log(Level.SEVERE, tl("unknownItemInList", itemName, configName)); + } + } + return list; + } + + @Override + public String getProtectString(final String configName) + { + return config.getString(configName, null); + } + + @Override + public boolean getProtectBoolean(final String configName, boolean def) + { + return config.getBoolean(configName, def); + } + private static final BigDecimal MAXMONEY = new BigDecimal("10000000000000"); + private BigDecimal maxMoney = MAXMONEY; + + private BigDecimal _getMaxMoney() + { + return config.getBigDecimal("max-money", MAXMONEY); + } + + @Override + public BigDecimal getMaxMoney() + { + return maxMoney; + } + private static final BigDecimal MINMONEY = new BigDecimal("-10000000000000"); + private BigDecimal minMoney = MINMONEY; + + private BigDecimal _getMinMoney() + { + BigDecimal min = config.getBigDecimal("min-money", MINMONEY); + if (min.signum() > 0) + { + min = min.negate(); + } + return min; + } + + @Override + public BigDecimal getMinMoney() + { + return minMoney; + } + private boolean economyLog = false; + + @Override + public boolean isEcoLogEnabled() + { + return economyLog; + } + + public boolean _isEcoLogEnabled() + { + return config.getBoolean("economy-log-enabled", false); + } + // #easteregg + private boolean economyLogUpdate = false; + + @Override + public boolean isEcoLogUpdateEnabled() + { + return economyLogUpdate; + } + + public boolean _isEcoLogUpdateEnabled() + { + return config.getBoolean("economy-log-update-enabled", false); + } + + @Override + public boolean removeGodOnDisconnect() + { + return config.getBoolean("remove-god-on-disconnect", false); + } + private boolean changeDisplayName = true; + + private boolean _changeDisplayName() + { + return config.getBoolean("change-displayname", true); + } + + @Override + public boolean changeDisplayName() + { + return changeDisplayName; + } + private boolean changePlayerListName = false; + + private boolean _changePlayerListName() + { + return config.getBoolean("change-playerlist", false); + } + + @Override + public boolean changePlayerListName() + { + return changePlayerListName; + } + + @Override + public boolean useBukkitPermissions() + { + return config.getBoolean("use-bukkit-permissions", false); + } + private boolean prefixsuffixconfigured = false; + private boolean addprefixsuffix = false; + private boolean essentialsChatActive = false; + + private boolean _addPrefixSuffix() + { + return config.getBoolean("add-prefix-suffix", false); + } + + private boolean _isPrefixSuffixConfigured() + { + return config.hasProperty("add-prefix-suffix"); + } + + @Override + public void setEssentialsChatActive(boolean essentialsChatActive) + { + this.essentialsChatActive = essentialsChatActive; + } + + @Override + public boolean addPrefixSuffix() + { + return prefixsuffixconfigured ? addprefixsuffix : essentialsChatActive; + } + // #easteregg + private boolean disablePrefix = false; + + private boolean _disablePrefix() + { + return config.getBoolean("disablePrefix", false); + } + + @Override + public boolean disablePrefix() + { + return disablePrefix; + } + // #easteregg + private boolean disableSuffix = false; + + private boolean _disableSuffix() + { + return config.getBoolean("disableSuffix", false); + } + + @Override + public boolean disableSuffix() + { + return disableSuffix; + } + + @Override + public long getAutoAfk() + { + return config.getLong("auto-afk", 300); + } + + @Override + public long getAutoAfkKick() + { + return config.getLong("auto-afk-kick", -1); + } + private boolean getFreezeAfkPlayers; + + @Override + public boolean getFreezeAfkPlayers() + { + return getFreezeAfkPlayers; + } + + private boolean _getFreezeAfkPlayers() + { + return config.getBoolean("freeze-afk-players", false); + } + private boolean cancelAfkOnMove; + + @Override + public boolean cancelAfkOnMove() + { + return cancelAfkOnMove; + } + + private boolean _cancelAfkOnMove() + { + return config.getBoolean("cancel-afk-on-move", true); + } + private boolean cancelAfkOnInteract; + + @Override + public boolean cancelAfkOnInteract() + { + return cancelAfkOnInteract; + } + + private boolean _cancelAfkOnInteract() + { + return config.getBoolean("cancel-afk-on-interact", true); + } + + @Override + public boolean areDeathMessagesEnabled() + { + return config.getBoolean("death-messages", true); + } + private Set noGodWorlds = new HashSet(); + + @Override + public Set getNoGodWorlds() + { + return noGodWorlds; + } + + @Override + public void setDebug(final boolean debug) + { + this.debug = debug; + } + + @Override + public boolean getRepairEnchanted() + { + return config.getBoolean("repair-enchanted", true); + } + + @Override + public boolean allowUnsafeEnchantments() + { + return config.getBoolean("unsafe-enchantments", false); + } + + @Override + public boolean isWorldTeleportPermissions() + { + return config.getBoolean("world-teleport-permissions", false); + } + + @Override + public boolean isWorldHomePermissions() + { + return config.getBoolean("world-home-permissions", false); + } + private boolean registerBackInListener; + + @Override + public boolean registerBackInListener() + { + return registerBackInListener; + } + + private boolean _registerBackInListener() + { + return config.getBoolean("register-back-in-listener", false); + } + private boolean disableItemPickupWhileAfk; + + @Override + public boolean getDisableItemPickupWhileAfk() + { + return disableItemPickupWhileAfk; + } + + private boolean _getDisableItemPickupWhileAfk() + { + return config.getBoolean("disable-item-pickup-while-afk", false); + } + + @Override + public EventPriority getRespawnPriority() + { + String priority = config.getString("respawn-listener-priority", "normal").toLowerCase(Locale.ENGLISH); + if ("lowest".equals(priority)) + { + return EventPriority.LOWEST; + } + if ("low".equals(priority)) + { + return EventPriority.LOW; + } + if ("normal".equals(priority)) + { + return EventPriority.NORMAL; + } + if ("high".equals(priority)) + { + return EventPriority.HIGH; + } + if ("highest".equals(priority)) + { + return EventPriority.HIGHEST; + } + return EventPriority.NORMAL; + } + + @Override + public long getTpaAcceptCancellation() + { + return config.getLong("tpa-accept-cancellation", 120); + } + + @Override + public boolean isMetricsEnabled() + { + return metricsEnabled; + } + + @Override + public void setMetricsEnabled(boolean metricsEnabled) + { + this.metricsEnabled = metricsEnabled; + } + private long teleportInvulnerabilityTime; + + private long _getTeleportInvulnerability() + { + return config.getLong("teleport-invulnerability", 0) * 1000; + } + + @Override + public long getTeleportInvulnerability() + { + return teleportInvulnerabilityTime; + } + private boolean teleportInvulnerability; + + private boolean _isTeleportInvulnerability() + { + return (config.getLong("teleport-invulnerability", 0) > 0); + } + + @Override + public boolean isTeleportInvulnerability() + { + return teleportInvulnerability; + } + private long loginAttackDelay; + + private long _getLoginAttackDelay() + { + return config.getLong("login-attack-delay", 0) * 1000; + } + + @Override + public long getLoginAttackDelay() + { + return loginAttackDelay; + } + private int signUsePerSecond; + + private int _getSignUsePerSecond() + { + final int perSec = config.getInt("sign-use-per-second", 4); + return perSec > 0 ? perSec : 1; + } + + @Override + public int getSignUsePerSecond() + { + return signUsePerSecond; + } + + @Override + public double getMaxFlySpeed() + { + double maxSpeed = config.getDouble("max-fly-speed", 0.8); + return maxSpeed > 1.0 ? 1.0 : Math.abs(maxSpeed); + } + + @Override + public double getMaxWalkSpeed() + { + double maxSpeed = config.getDouble("max-walk-speed", 0.8); + return maxSpeed > 1.0 ? 1.0 : Math.abs(maxSpeed); + } + private int mailsPerMinute; + + private int _getMailsPerMinute() + { + return config.getInt("mails-per-minute", 1000); + } + + @Override + public int getMailsPerMinute() + { + return mailsPerMinute; + } + // #easteregg + private long economyLagWarning; + + private long _getEconomyLagWarning() + { + // Default to 25ms + final long value = (long)(config.getDouble("economy-lag-warning", 25.0) * 1000000); + return value; + } + + @Override + public long getEconomyLagWarning() + { + return economyLagWarning; + } + + // #easteregg + private long permissionsLagWarning; + + private long _getPermissionsLagWarning() + { + // Default to 25ms + final long value = (long)(config.getDouble("permissions-lag-warning", 25.0) * 1000000); + return value; + } + + @Override + public long getPermissionsLagWarning() + { + return permissionsLagWarning; + } + + @Override + public long getMaxTempban() + { + return config.getLong("max-tempban-time", -1); + } + + @Override + public int getMaxNickLength() + { + return config.getInt("max-nick-length", 30); + } + private boolean allowSilentJoin; + + public boolean _allowSilentJoinQuit() + { + return config.getBoolean("allow-silent-join-quit", false); + } + + @Override + public boolean allowSilentJoinQuit() + { + return allowSilentJoin; + } + private String customJoinMessage; + private boolean isCustomJoinMessage; + + public String _getCustomJoinMessage() + { + return FormatUtil.replaceFormat(config.getString("custom-join-message", "none")); + } + + @Override + public String getCustomJoinMessage() + { + return customJoinMessage; + } + + @Override + public boolean isCustomJoinMessage() + { + return isCustomJoinMessage; + } + private String customQuitMessage; + private boolean isCustomQuitMessage; + + public String _getCustomQuitMessage() + { + return FormatUtil.replaceFormat(config.getString("custom-quit-message", "none")); + } + + @Override + public String getCustomQuitMessage() + { + return customQuitMessage; + } + + @Override + public boolean isCustomQuitMessage() + { + return isCustomQuitMessage; + } + + // #easteregg + @Override + public int getMaxUserCacheCount() + { + long count = Runtime.getRuntime().maxMemory() / 1024 / 96; + return config.getInt("max-user-cache-count", (int)count); + } +} diff --git a/Essentials/src/com/earth2me/essentials/SpawnMob.java b/Essentials/src/com/earth2me/essentials/SpawnMob.java new file mode 100644 index 0000000000..a191528dd0 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/SpawnMob.java @@ -0,0 +1,323 @@ +package com.earth2me.essentials; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Mob.MobException; +import com.earth2me.essentials.utils.LocationUtil; +import com.earth2me.essentials.utils.StringUtil; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Set; +import net.ess3.api.IEssentials; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.block.Block; +import org.bukkit.entity.*; +import org.bukkit.inventory.EntityEquipment; +import org.bukkit.inventory.ItemStack; + + +public class SpawnMob +{ + public static String mobList(final User user) + { + final Set mobList = Mob.getMobList(); + final Set availableList = new HashSet(); + for (String mob : mobList) + { + if (user.isAuthorized("essentials.spawnmob." + mob.toLowerCase(Locale.ENGLISH))) + { + availableList.add(mob); + } + } + if (availableList.isEmpty()) + { + availableList.add(tl("none")); + } + return StringUtil.joinList(availableList); + } + + public static List mobParts(final String mobString) + { + String[] mobParts = mobString.split(","); + + List mobs = new ArrayList(); + + for (String mobPart : mobParts) + { + String[] mobDatas = mobPart.split(":"); + mobs.add(mobDatas[0]); + } + return mobs; + } + + public static List mobData(final String mobString) + { + String[] mobParts = mobString.split(","); + + List mobData = new ArrayList(); + + for (String mobPart : mobParts) + { + String[] mobDatas = mobPart.split(":"); + if (mobDatas.length == 1) + { + if (mobPart.contains(":")) + { + mobData.add(""); + } + else + { + mobData.add(null); + } + } + else + { + mobData.add(mobDatas[1]); + } + } + + return mobData; + } + + // This method spawns a mob where the user is looking, owned by user + public static void spawnmob(final IEssentials ess, final Server server, final User user, final List parts, final List data, int mobCount) throws Exception + { + final Block block = LocationUtil.getTarget(user.getBase()).getBlock(); + if (block == null) + { + throw new Exception(tl("unableToSpawnMob")); + } + spawnmob(ess, server, user.getSource(), user, block.getLocation(), parts, data, mobCount); + } + + // This method spawns a mob at target, owned by target + public static void spawnmob(final IEssentials ess, final Server server, final CommandSource sender, final User target, final List parts, final List data, int mobCount) throws Exception + { + spawnmob(ess, server, sender, target, target.getLocation(), parts, data, mobCount); + } + + // This method spawns a mob at loc, owned by target + public static void spawnmob(final IEssentials ess, final Server server, final CommandSource sender, final User target, final Location loc, final List parts, final List data, int mobCount) throws Exception + { + final Location sloc = LocationUtil.getSafeDestination(loc); + + for (int i = 0; i < parts.size(); i++) + { + Mob mob = Mob.fromName(parts.get(i)); + checkSpawnable(ess, sender, mob); + } + + final int serverLimit = ess.getSettings().getSpawnMobLimit(); + int effectiveLimit = serverLimit / parts.size(); + + if (effectiveLimit < 1) + { + effectiveLimit = 1; + while (parts.size() > serverLimit) + { + parts.remove(serverLimit); + } + } + + if (mobCount > effectiveLimit) + { + mobCount = effectiveLimit; + sender.sendMessage(tl("mobSpawnLimit")); + } + + Mob mob = Mob.fromName(parts.get(0)); // Get the first mob + try + { + for (int i = 0; i < mobCount; i++) + { + spawnMob(ess, server, sender, target, sloc, parts, data); + } + sender.sendMessage(mobCount * parts.size() + " " + mob.name.toLowerCase(Locale.ENGLISH) + mob.suffix + " " + tl("spawned")); + } + catch (MobException e1) + { + throw new Exception(tl("unableToSpawnMob"), e1); + } + catch (NumberFormatException e2) + { + throw new Exception(tl("numberRequired"), e2); + } + catch (NullPointerException np) + { + throw new Exception(tl("soloMob"), np); + } + } + + private static void spawnMob(final IEssentials ess, final Server server, final CommandSource sender, final User target, final Location sloc, List parts, List data) throws Exception + { + Mob mob; + Entity spawnedMob = null; + Entity spawnedMount; + + for (int i = 0; i < parts.size(); i++) + { + if (i == 0) + { + mob = Mob.fromName(parts.get(i)); + spawnedMob = mob.spawn(sloc.getWorld(), server, sloc); + defaultMobData(mob.getType(), spawnedMob); + + if (data.get(i) != null) + { + changeMobData(sender, mob.getType(), spawnedMob, data.get(i).toLowerCase(Locale.ENGLISH), target); + } + } + + int next = (i + 1); + if (next < parts.size()) //If it's the last mob in the list, don't set the mount + { + Mob mMob = Mob.fromName(parts.get(next)); + spawnedMount = mMob.spawn(sloc.getWorld(), server, sloc); + defaultMobData(mMob.getType(), spawnedMount); + + if (data.get(next) != null) + { + changeMobData(sender, mMob.getType(), spawnedMount, data.get(next).toLowerCase(Locale.ENGLISH), target); + } + + spawnedMob.setPassenger(spawnedMount); + + spawnedMob = spawnedMount; + } + } + } + + private static void checkSpawnable(IEssentials ess, CommandSource sender, Mob mob) throws Exception + { + if (mob == null) + { + throw new Exception(tl("invalidMob")); + } + + if (ess.getSettings().getProtectPreventSpawn(mob.getType().toString().toLowerCase(Locale.ENGLISH))) + { + throw new Exception(tl("disabledToSpawnMob")); + } + + if (sender.isPlayer() && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.spawnmob." + mob.name.toLowerCase(Locale.ENGLISH))) + { + throw new Exception(tl("noPermToSpawnMob")); + } + } + + private static void changeMobData(final CommandSource sender, final EntityType type, final Entity spawned, final String inputData, final User target) throws Exception + { + String data = inputData; + + if (data.isEmpty()) + { + sender.sendMessage(tl("mobDataList", StringUtil.joinList(MobData.getValidHelp(spawned)))); + } + + if (spawned instanceof Zombie) + { + ((Zombie)spawned).setBaby(false); + } + else if(spawned instanceof Ageable) + { + ((Ageable)spawned).setAdult(); + } + + if (spawned instanceof Zombie || type == EntityType.SKELETON) + { + if (inputData.contains("armor") || inputData.contains("armour")) + { + final EntityEquipment invent = ((LivingEntity)spawned).getEquipment(); + if (inputData.contains("noarmor") || inputData.contains("noarmour")) + { + invent.clear(); + } + else if (inputData.contains("diamond")) + { + invent.setBoots(new ItemStack(Material.DIAMOND_BOOTS, 1)); + invent.setLeggings(new ItemStack(Material.DIAMOND_LEGGINGS, 1)); + invent.setChestplate(new ItemStack(Material.DIAMOND_CHESTPLATE, 1)); + invent.setHelmet(new ItemStack(Material.DIAMOND_HELMET, 1)); + } + else if (inputData.contains("gold")) + { + invent.setBoots(new ItemStack(Material.GOLD_BOOTS, 1)); + invent.setLeggings(new ItemStack(Material.GOLD_LEGGINGS, 1)); + invent.setChestplate(new ItemStack(Material.GOLD_CHESTPLATE, 1)); + invent.setHelmet(new ItemStack(Material.GOLD_HELMET, 1)); + } + else if (inputData.contains("leather")) + { + invent.setBoots(new ItemStack(Material.LEATHER_BOOTS, 1)); + invent.setLeggings(new ItemStack(Material.LEATHER_LEGGINGS, 1)); + invent.setChestplate(new ItemStack(Material.LEATHER_CHESTPLATE, 1)); + invent.setHelmet(new ItemStack(Material.LEATHER_HELMET, 1)); + } + else + { + invent.setBoots(new ItemStack(Material.IRON_BOOTS, 1)); + invent.setLeggings(new ItemStack(Material.IRON_LEGGINGS, 1)); + invent.setChestplate(new ItemStack(Material.IRON_CHESTPLATE, 1)); + invent.setHelmet(new ItemStack(Material.IRON_HELMET, 1)); + } + invent.setBootsDropChance(0f); + invent.setLeggingsDropChance(0f); + invent.setChestplateDropChance(0f); + invent.setHelmetDropChance(0f); + } + + } + + MobData newData = MobData.fromData(spawned, data); + while (newData != null) + { + newData.setData(spawned, target.getBase(), data); + data = data.replace(newData.getMatched(), ""); + newData = MobData.fromData(spawned, data); + } + } + + private static void defaultMobData(final EntityType type, final Entity spawned) + { + if (type == EntityType.SKELETON) + { + final EntityEquipment invent = ((LivingEntity)spawned).getEquipment(); + invent.setItemInHand(new ItemStack(Material.BOW, 1)); + invent.setItemInHandDropChance(0.1f); + + invent.setBoots(new ItemStack(Material.GOLD_BOOTS, 1)); + invent.setBootsDropChance(0.0f); + } + + if (type == EntityType.PIG_ZOMBIE) + { + final PigZombie zombie = ((PigZombie)spawned); + zombie.setVillager(false); + + final EntityEquipment invent = zombie.getEquipment(); + invent.setItemInHand(new ItemStack(Material.GOLD_SWORD, 1)); + invent.setItemInHandDropChance(0.1f); + + invent.setBoots(new ItemStack(Material.GOLD_BOOTS, 1)); + invent.setBootsDropChance(0.0f); + } + + if (type == EntityType.ZOMBIE) + { + final Zombie zombie = ((Zombie)spawned); + zombie.setVillager(false); + + final EntityEquipment invent = zombie.getEquipment(); + invent.setBoots(new ItemStack(Material.GOLD_BOOTS, 1)); + invent.setBootsDropChance(0.0f); + } + + if (type == EntityType.HORSE) + { + ((Horse)spawned).setJumpStrength(1.2); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/TNTExplodeListener.java b/Essentials/src/com/earth2me/essentials/TNTExplodeListener.java new file mode 100644 index 0000000000..2318347c88 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/TNTExplodeListener.java @@ -0,0 +1,62 @@ +package com.earth2me.essentials; + +import net.ess3.api.IEssentials; +import org.bukkit.entity.LivingEntity; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityExplodeEvent; + + +public class TNTExplodeListener implements Listener, Runnable +{ + private final transient IEssentials ess; + private transient boolean enabled = false; + private transient int timer = -1; + + public TNTExplodeListener(final IEssentials ess) + { + super(); + this.ess = ess; + } + + public void enable() + { + if (!enabled) + { + enabled = true; + timer = ess.scheduleSyncDelayedTask(this, 200); + return; + } + if (timer != -1) + { + ess.getScheduler().cancelTask(timer); + timer = ess.scheduleSyncDelayedTask(this, 200); + } + } + + @EventHandler(priority = EventPriority.LOW) + public void onEntityExplode(final EntityExplodeEvent event) + { + if (!enabled) + { + return; + } + if (event.getEntity() instanceof LivingEntity) + { + return; + } + if (event.blockList().size() < 1) + { + return; + } + event.setCancelled(true); + event.getLocation().getWorld().createExplosion(event.getLocation(), 0F); + } + + @Override + public void run() + { + enabled = false; + } +} diff --git a/Essentials/src/com/earth2me/essentials/Teleport.java b/Essentials/src/com/earth2me/essentials/Teleport.java new file mode 100644 index 0000000000..4858ad4239 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/Teleport.java @@ -0,0 +1,296 @@ +package com.earth2me.essentials; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.utils.DateUtil; +import com.earth2me.essentials.utils.LocationUtil; +import java.math.BigDecimal; +import java.util.Calendar; +import java.util.GregorianCalendar; +import net.ess3.api.IEssentials; +import net.ess3.api.IUser; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerRespawnEvent; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + + +public class Teleport implements net.ess3.api.ITeleport +{ + private final IUser teleportOwner; + private final IEssentials ess; + private TimedTeleport timedTeleport; + + public Teleport(IUser user, IEssentials ess) + { + this.teleportOwner = user; + this.ess = ess; + } + + public void cooldown(boolean check) throws Exception + { + final Calendar time = new GregorianCalendar(); + if (teleportOwner.getLastTeleportTimestamp() > 0) + { + // Take the current time, and remove the delay from it. + final double cooldown = ess.getSettings().getTeleportCooldown(); + final Calendar earliestTime = new GregorianCalendar(); + earliestTime.add(Calendar.SECOND, -(int)cooldown); + earliestTime.add(Calendar.MILLISECOND, -(int)((cooldown * 1000.0) % 1000.0)); + // This value contains the most recent time a teleportPlayer could have been used that would allow another use. + final long earliestLong = earliestTime.getTimeInMillis(); + + // When was the last teleportPlayer used? + final Long lastTime = teleportOwner.getLastTeleportTimestamp(); + + if (lastTime > time.getTimeInMillis()) + { + // This is to make sure time didn't get messed up on last teleportPlayer use. + // If this happens, let's give the user the benifit of the doubt. + teleportOwner.setLastTeleportTimestamp(time.getTimeInMillis()); + return; + } + else if (lastTime > earliestLong && !teleportOwner.isAuthorized("essentials.teleport.cooldown.bypass")) + { + time.setTimeInMillis(lastTime); + time.add(Calendar.SECOND, (int)cooldown); + time.add(Calendar.MILLISECOND, (int)((cooldown * 1000.0) % 1000.0)); + throw new Exception(tl("timeBeforeTeleport", DateUtil.formatDateDiff(time.getTimeInMillis()))); + } + } + // if justCheck is set, don't update lastTeleport; we're just checking + if (!check) + { + teleportOwner.setLastTeleportTimestamp(time.getTimeInMillis()); + } + } + + private void warnUser(final IUser user, final double delay) + { + Calendar c = new GregorianCalendar(); + c.add(Calendar.SECOND, (int)delay); + c.add(Calendar.MILLISECOND, (int)((delay * 1000.0) % 1000.0)); + user.sendMessage(tl("dontMoveMessage", DateUtil.formatDateDiff(c.getTimeInMillis()))); + } + + //The now function is used when you want to skip tp delay when teleporting someone to a location or player. + @Override + public void now(Location loc, boolean cooldown, TeleportCause cause) throws Exception + { + if (cooldown) + { + cooldown(false); + } + final ITarget target = new LocationTarget(loc); + now(teleportOwner, target, cause); + } + + @Override + public void now(Player entity, boolean cooldown, TeleportCause cause) throws Exception + { + if (cooldown) + { + cooldown(false); + } + final ITarget target = new PlayerTarget(entity); + now(teleportOwner, target, cause); + teleportOwner.sendMessage(tl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ())); + } + + protected void now(IUser teleportee, ITarget target, TeleportCause cause) throws Exception + { + cancel(false); + teleportee.setLastLocation(); + final Location loc = target.getLocation(); + + if (LocationUtil.isBlockUnsafeForUser(teleportee, loc.getWorld(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())) + { + if (ess.getSettings().isTeleportSafetyEnabled()) + { + if (teleportee.getBase().isInsideVehicle()) + { + teleportee.getBase().leaveVehicle(); + } + teleportee.getBase().teleport(LocationUtil.getSafeDestination(teleportee, loc), cause); + } + else + { + throw new Exception(tl("unsafeTeleportDestination", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); + } + } + else + { + if (teleportee.getBase().isInsideVehicle()) + { + teleportee.getBase().leaveVehicle(); + } + teleportee.getBase().teleport(LocationUtil.getRoundedDestination(loc), cause); + } + } + + //The teleportPlayer function is used when you want to normally teleportPlayer someone to a location or player. + //This method is nolonger used internally and will be removed. + @Deprecated + @Override + public void teleport(Location loc, Trade chargeFor) throws Exception + { + teleport(loc, chargeFor, TeleportCause.PLUGIN); + } + + @Override + public void teleport(Location loc, Trade chargeFor, TeleportCause cause) throws Exception + { + teleport(teleportOwner, new LocationTarget(loc), chargeFor, cause); + } + + //This is used when teleporting to a player + @Override + public void teleport(Player entity, Trade chargeFor, TeleportCause cause) throws Exception + { + ITarget target = new PlayerTarget(entity); + teleportOwner.sendMessage(tl("teleportToPlayer", entity.getDisplayName())); + teleport(teleportOwner, target, chargeFor, cause); + } + + //This is used when teleporting to stored location + @Override + public void teleportPlayer(IUser teleportee, Location loc, Trade chargeFor, TeleportCause cause) throws Exception + { + teleport(teleportee, new LocationTarget(loc), chargeFor, cause); + } + + //This is used on /tphere + @Override + public void teleportPlayer(IUser teleportee, Player entity, Trade chargeFor, TeleportCause cause) throws Exception + { + ITarget target = new PlayerTarget(entity); + teleport(teleportee, target, chargeFor, cause); + teleportee.sendMessage(tl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ())); + teleportOwner.sendMessage(tl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ())); + } + + private void teleport(IUser teleportee, ITarget target, Trade chargeFor, TeleportCause cause) throws Exception + { + double delay = ess.getSettings().getTeleportDelay(); + + Trade cashCharge = chargeFor; + + if (chargeFor != null) + { + chargeFor.isAffordableFor(teleportOwner); + + //This code is to make sure that commandcosts are checked in the initial world, and not in the resulting world. + if (!chargeFor.getCommandCost(teleportOwner).equals(BigDecimal.ZERO)) + { + //By converting a command cost to a regular cost, the command cost permission isn't checked when executing the charge after teleport. + cashCharge = new Trade(chargeFor.getCommandCost(teleportOwner), ess); + } + } + + cooldown(true); + if (delay <= 0 || teleportOwner.isAuthorized("essentials.teleport.timer.bypass") + || teleportee.isAuthorized("essentials.teleport.timer.bypass")) + { + cooldown(false); + now(teleportee, target, cause); + if (cashCharge != null) + { + cashCharge.charge(teleportOwner); + } + return; + } + + cancel(false); + warnUser(teleportee, delay); + initTimer((long)(delay * 1000.0), teleportee, target, cashCharge, cause, false); + } + + //The respawn function is a wrapper used to handle tp fallback, on /jail and /home + @Override + public void respawn(final Trade chargeFor, TeleportCause cause) throws Exception + { + double delay = ess.getSettings().getTeleportDelay(); + if (chargeFor != null) + { + chargeFor.isAffordableFor(teleportOwner); + } + cooldown(true); + if (delay <= 0 || teleportOwner.isAuthorized("essentials.teleport.timer.bypass")) + { + cooldown(false); + respawnNow(teleportOwner, cause); + if (chargeFor != null) + { + chargeFor.charge(teleportOwner); + } + return; + } + + cancel(false); + warnUser(teleportOwner, delay); + initTimer((long)(delay * 1000.0), teleportOwner, null, chargeFor, cause, true); + } + + protected void respawnNow(IUser teleportee, TeleportCause cause) throws Exception + { + final Player player = teleportee.getBase(); + Location bed = player.getBedSpawnLocation(); + if (bed != null) + { + now(teleportee, new LocationTarget(bed), cause); + } + else + { + if (ess.getSettings().isDebug()) + { + ess.getLogger().info("Could not find bed spawn, forcing respawn event."); + } + final PlayerRespawnEvent pre = new PlayerRespawnEvent(player, player.getWorld().getSpawnLocation(), false); + ess.getServer().getPluginManager().callEvent(pre); + now(teleportee, new LocationTarget(pre.getRespawnLocation()), cause); + } + } + + //The warp function is a wrapper used to teleportPlayer a player to a /warp + @Override + public void warp(IUser teleportee, String warp, Trade chargeFor, TeleportCause cause) throws Exception + { + Location loc = ess.getWarps().getWarp(warp); + teleportee.sendMessage(tl("warpingTo", warp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); + if (!teleportee.equals(teleportOwner)) + { + teleportOwner.sendMessage(tl("warpingTo", warp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); + } + teleport(teleportee, new LocationTarget(loc), chargeFor, cause); + } + + //The back function is a wrapper used to teleportPlayer a player /back to their previous location. + @Override + public void back(Trade chargeFor) throws Exception + { + final Location loc = teleportOwner.getLastLocation(); + teleportOwner.sendMessage(tl("backUsageMsg", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); + teleport(teleportOwner, new LocationTarget(loc), chargeFor, TeleportCause.COMMAND); + } + + //This function is used to throw a user back after a jail sentence + @Override + public void back() throws Exception + { + now(teleportOwner, new LocationTarget(teleportOwner.getLastLocation()), TeleportCause.COMMAND); + } + + //If we need to cancelTimer a pending teleportPlayer call this method + private void cancel(boolean notifyUser) + { + if (timedTeleport != null) + { + timedTeleport.cancelTimer(notifyUser); + timedTeleport = null; + } + } + + private void initTimer(long delay, IUser teleportUser, ITarget target, Trade chargeFor, TeleportCause cause, boolean respawn) + { + timedTeleport = new TimedTeleport(teleportOwner, ess, this, delay, teleportUser, target, chargeFor, cause, respawn); + } +} diff --git a/Essentials/src/com/earth2me/essentials/TimedTeleport.java b/Essentials/src/com/earth2me/essentials/TimedTeleport.java new file mode 100644 index 0000000000..e426c1cecd --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/TimedTeleport.java @@ -0,0 +1,177 @@ +package com.earth2me.essentials; + +import static com.earth2me.essentials.I18n.tl; +import java.util.UUID; +import net.ess3.api.IEssentials; +import net.ess3.api.IUser; +import org.bukkit.Location; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + + +public class TimedTeleport implements Runnable +{ + private static final double MOVE_CONSTANT = 0.3; + private final IUser teleportOwner; + private final IEssentials ess; + private final Teleport teleport; + private final UUID timer_teleportee; + private int timer_task = -1; + private final long timer_started; // time this task was initiated + private final long timer_delay; // how long to delay the teleportPlayer + private double timer_health; + // note that I initially stored a clone of the location for reference, but... + // when comparing locations, I got incorrect mismatches (rounding errors, looked like) + // so, the X/Y/Z values are stored instead and rounded off + private final long timer_initX; + private final long timer_initY; + private final long timer_initZ; + private final ITarget timer_teleportTarget; + private final boolean timer_respawn; + private final boolean timer_canMove; + private final Trade timer_chargeFor; + private final TeleportCause timer_cause; + + public TimedTeleport(IUser user, IEssentials ess, Teleport teleport, long delay, IUser teleportUser, ITarget target, Trade chargeFor, TeleportCause cause, boolean respawn) + { + + this.teleportOwner = user; + this.ess = ess; + this.teleport = teleport; + this.timer_started = System.currentTimeMillis(); + this.timer_delay = delay; + this.timer_health = teleportUser.getBase().getHealth(); + this.timer_initX = Math.round(teleportUser.getBase().getLocation().getX() * MOVE_CONSTANT); + this.timer_initY = Math.round(teleportUser.getBase().getLocation().getY() * MOVE_CONSTANT); + this.timer_initZ = Math.round(teleportUser.getBase().getLocation().getZ() * MOVE_CONSTANT); + this.timer_teleportee = teleportUser.getBase().getUniqueId(); + this.timer_teleportTarget = target; + this.timer_chargeFor = chargeFor; + this.timer_cause = cause; + this.timer_respawn = respawn; + this.timer_canMove = user.isAuthorized("essentials.teleport.timer.move"); + + timer_task = ess.runTaskTimerAsynchronously(this, 20, 20).getTaskId(); + } + + @Override + public void run() + { + + if (teleportOwner == null || !teleportOwner.getBase().isOnline() || teleportOwner.getBase().getLocation() == null) + { + cancelTimer(false); + return; + } + + final IUser teleportUser = ess.getUser(this.timer_teleportee); + + if (teleportUser == null || !teleportUser.getBase().isOnline()) + { + cancelTimer(false); + return; + } + + final Location currLocation = teleportUser.getBase().getLocation(); + if (currLocation == null) + { + cancelTimer(false); + return; + } + + if (!timer_canMove + && (Math.round(currLocation.getX() * MOVE_CONSTANT) != timer_initX + || Math.round(currLocation.getY() * MOVE_CONSTANT) != timer_initY + || Math.round(currLocation.getZ() * MOVE_CONSTANT) != timer_initZ + || teleportUser.getBase().getHealth() < timer_health)) + { + // user moved, cancelTimer teleportPlayer + cancelTimer(true); + return; + } + + class DelayedTeleportTask implements Runnable + { + @Override + public void run() + { + + timer_health = teleportUser.getBase().getHealth(); // in case user healed, then later gets injured + final long now = System.currentTimeMillis(); + if (now > timer_started + timer_delay) + { + try + { + teleport.cooldown(false); + } + catch (Exception ex) + { + teleportOwner.sendMessage(tl("cooldownWithMessage", ex.getMessage())); + if (teleportOwner != teleportUser) + { + teleportUser.sendMessage(tl("cooldownWithMessage", ex.getMessage())); + } + } + try + { + cancelTimer(false); + teleportUser.sendMessage(tl("teleportationCommencing")); + + try + { + if (timer_chargeFor != null) + { + timer_chargeFor.isAffordableFor(teleportOwner); + } + if (timer_respawn) + { + teleport.respawnNow(teleportUser, timer_cause); + } + else + { + teleport.now(teleportUser, timer_teleportTarget, timer_cause); + } + if (timer_chargeFor != null) + { + timer_chargeFor.charge(teleportOwner); + } + } + catch (Exception ex) + { + } + + } + catch (Exception ex) + { + ess.showError(teleportOwner.getSource(), ex, "\\ teleport"); + } + } + } + } + ess.scheduleSyncDelayedTask(new DelayedTeleportTask()); + } + + //If we need to cancelTimer a pending teleportPlayer call this method + public void cancelTimer(boolean notifyUser) + { + if (timer_task == -1) + { + return; + } + try + { + ess.getServer().getScheduler().cancelTask(timer_task); + if (notifyUser) + { + teleportOwner.sendMessage(tl("pendingTeleportCancelled")); + if (timer_teleportee != null && !timer_teleportee.equals(teleportOwner.getBase().getUniqueId())) + { + ess.getUser(timer_teleportee).sendMessage(tl("pendingTeleportCancelled")); + } + } + } + finally + { + timer_task = -1; + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/Trade.java b/Essentials/src/com/earth2me/essentials/Trade.java new file mode 100644 index 0000000000..c5298a4b19 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/Trade.java @@ -0,0 +1,452 @@ +package com.earth2me.essentials; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.craftbukkit.InventoryWorkaround; +import com.earth2me.essentials.craftbukkit.SetExpFix; +import com.earth2me.essentials.utils.NumberUtil; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.math.BigDecimal; +import java.text.DateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import net.ess3.api.IEssentials; +import net.ess3.api.IUser; +import net.ess3.api.MaxMoneyException; +import org.bukkit.Location; +import org.bukkit.entity.Item; +import org.bukkit.inventory.ItemStack; + + +public class Trade +{ + private final transient String command; + private final transient Trade fallbackTrade; + private final transient BigDecimal money; + private final transient ItemStack itemStack; + private final transient Integer exp; + private final transient IEssentials ess; + + + public enum TradeType + { + MONEY, + EXP, + ITEM + } + + + public enum OverflowType + { + ABORT, + DROP, + RETURN + } + + public Trade(final String command, final IEssentials ess) + { + this(command, null, null, null, null, ess); + } + + public Trade(final String command, final Trade fallback, final IEssentials ess) + { + this(command, fallback, null, null, null, ess); + } + + @Deprecated + public Trade(final double money, final com.earth2me.essentials.IEssentials ess) + { + this(null, null, BigDecimal.valueOf(money), null, null, (IEssentials)ess); + } + + public Trade(final BigDecimal money, final IEssentials ess) + { + this(null, null, money, null, null, ess); + } + + public Trade(final ItemStack items, final IEssentials ess) + { + this(null, null, null, items, null, ess); + } + + public Trade(final int exp, final IEssentials ess) + { + this(null, null, null, null, exp, ess); + } + + private Trade(final String command, final Trade fallback, final BigDecimal money, final ItemStack item, final Integer exp, final IEssentials ess) + { + this.command = command; + this.fallbackTrade = fallback; + this.money = money; + this.itemStack = item; + this.exp = exp; + this.ess = ess; + } + + public void isAffordableFor(final IUser user) throws ChargeException + { + + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "checking if " + user.getName() + " can afford charge."); + } + + if (getMoney() != null + && getMoney().signum() > 0 + && !user.canAfford(getMoney())) + { + throw new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(getMoney(), ess))); + } + + if (getItemStack() != null + && !user.getBase().getInventory().containsAtLeast(itemStack, itemStack.getAmount())) + { + throw new ChargeException(tl("missingItems", getItemStack().getAmount(), ess.getItemDb().name(getItemStack()))); + } + + BigDecimal money; + if (command != null && !command.isEmpty() + && (money = getCommandCost(user)).signum() > 0 + && !user.canAfford(money)) + { + throw new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(money, ess))); + } + + if (exp != null && exp > 0 + && SetExpFix.getTotalExperience(user.getBase()) < exp) + { + throw new ChargeException(tl("notEnoughExperience")); + } + } + + public boolean pay(final IUser user) throws MaxMoneyException + { + return pay(user, OverflowType.ABORT) == null; + } + + public Map pay(final IUser user, final OverflowType type) throws MaxMoneyException + { + if (getMoney() != null && getMoney().signum() > 0) + { + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "paying user " + user.getName() + " via trade " + getMoney().toPlainString()); + } + user.giveMoney(getMoney()); + } + if (getItemStack() != null) + { + // This stores the would be overflow + Map overFlow = InventoryWorkaround.addAllItems(user.getBase().getInventory(), getItemStack()); + + if (overFlow != null) + { + switch (type) + { + case ABORT: + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "abort paying " + user.getName() + " itemstack " + getItemStack().toString() + " due to lack of inventory space "); + } + + return overFlow; + + case RETURN: + // Pay the user the items, and return overflow + final Map returnStack = InventoryWorkaround.addItems(user.getBase().getInventory(), getItemStack()); + user.getBase().updateInventory(); + + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "paying " + user.getName() + " partial itemstack " + getItemStack().toString() + " with overflow " + returnStack.get(0).toString()); + } + + return returnStack; + + case DROP: + // Pay the users the items directly, and drop the rest, will always return no overflow. + final Map leftOver = InventoryWorkaround.addItems(user.getBase().getInventory(), getItemStack()); + final Location loc = user.getBase().getLocation(); + for (ItemStack loStack : leftOver.values()) + { + final int maxStackSize = loStack.getType().getMaxStackSize(); + final int stacks = loStack.getAmount() / maxStackSize; + final int leftover = loStack.getAmount() % maxStackSize; + final Item[] itemStacks = new Item[stacks + (leftover > 0 ? 1 : 0)]; + for (int i = 0; i < stacks; i++) + { + final ItemStack stack = loStack.clone(); + stack.setAmount(maxStackSize); + itemStacks[i] = loc.getWorld().dropItem(loc, stack); + } + if (leftover > 0) + { + final ItemStack stack = loStack.clone(); + stack.setAmount(leftover); + itemStacks[stacks] = loc.getWorld().dropItem(loc, stack); + } + } + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "paying " + user.getName() + " partial itemstack " + getItemStack().toString() + " and dropping overflow " + leftOver.get(0).toString()); + } + } + } + else if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "paying " + user.getName() + " itemstack " + getItemStack().toString()); + } + user.getBase().updateInventory(); + } + if (getExperience() != null) + { + SetExpFix.setTotalExperience(user.getBase(), SetExpFix.getTotalExperience(user.getBase()) + getExperience()); + } + return null; + } + + public void charge(final IUser user) throws ChargeException + { + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "attempting to charge user " + user.getName()); + } + if (getMoney() != null) + { + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "charging user " + user.getName() + " money " + getMoney().toPlainString()); + } + if (!user.canAfford(getMoney()) && getMoney().signum() > 0) + { + throw new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(getMoney(), ess))); + } + user.takeMoney(getMoney()); + } + if (getItemStack() != null) + { + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "charging user " + user.getName() + " itemstack " + getItemStack().toString()); + } + if (!user.getBase().getInventory().containsAtLeast(getItemStack(), getItemStack().getAmount())) + { + throw new ChargeException(tl("missingItems", getItemStack().getAmount(), getItemStack().getType().toString().toLowerCase(Locale.ENGLISH).replace("_", " "))); + } + user.getBase().getInventory().removeItem(getItemStack()); + user.getBase().updateInventory(); + } + if (command != null) + { + final BigDecimal cost = getCommandCost(user); + if (!user.canAfford(cost) && cost.signum() > 0) + { + throw new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(cost, ess))); + } + user.takeMoney(cost); + } + if (getExperience() != null) + { + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "charging user " + user.getName() + " exp " + getExperience()); + } + final int experience = SetExpFix.getTotalExperience(user.getBase()); + if (experience < getExperience() && getExperience() > 0) + { + throw new ChargeException(tl("notEnoughExperience")); + } + SetExpFix.setTotalExperience(user.getBase(), experience - getExperience()); + } + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "charge user " + user.getName() + " completed"); + } + } + + public BigDecimal getMoney() + { + return money; + } + + public ItemStack getItemStack() + { + return itemStack; + } + + public Integer getExperience() + { + return exp; + } + + public TradeType getType() + { + if (getExperience() != null) + { + return TradeType.EXP; + } + + if (getItemStack() != null) + { + return TradeType.ITEM; + } + + return TradeType.MONEY; + } + + public BigDecimal getCommandCost(final IUser user) + { + BigDecimal cost = BigDecimal.ZERO; + if (command != null && !command.isEmpty()) + { + cost = ess.getSettings().getCommandCost(command.charAt(0) == '/' ? command.substring(1) : command); + if (cost.signum() == 0 && fallbackTrade != null) + { + cost = fallbackTrade.getCommandCost(user); + } + + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "calculated command (" + command + ") cost for " + user.getName() + " as " + cost); + } + } + if (cost.signum() != 0 && (user.isAuthorized("essentials.nocommandcost.all") + || user.isAuthorized("essentials.nocommandcost." + command))) + { + return BigDecimal.ZERO; + } + return cost; + } + private static FileWriter fw = null; + + public static void log(String type, String subtype, String event, String sender, Trade charge, String receiver, Trade pay, Location loc, IEssentials ess) + { + //isEcoLogUpdateEnabled() - This refers to log entries with no location, ie API updates #EasterEgg + //isEcoLogEnabled() - This refers to log entries with with location, ie /pay /sell and eco signs. + + if ((loc == null && !ess.getSettings().isEcoLogUpdateEnabled()) + || (loc != null && !ess.getSettings().isEcoLogEnabled())) + { + return; + } + if (fw == null) + { + try + { + fw = new FileWriter(new File(ess.getDataFolder(), "trade.log"), true); + } + catch (IOException ex) + { + Logger.getLogger("Essentials").log(Level.SEVERE, null, ex); + } + } + StringBuilder sb = new StringBuilder(); + sb.append(type).append(",").append(subtype).append(",").append(event).append(",\""); + sb.append(DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date())); + sb.append("\",\""); + if (sender != null) + { + sb.append(sender); + } + sb.append("\","); + if (charge == null) + { + sb.append("\"\",\"\",\"\""); + } + else + { + if (charge.getItemStack() != null) + { + sb.append(charge.getItemStack().getAmount()).append(","); + sb.append(charge.getItemStack().getType().toString()).append(","); + sb.append(charge.getItemStack().getDurability()); + } + if (charge.getMoney() != null) + { + sb.append(charge.getMoney()).append(","); + sb.append("money").append(","); + sb.append(ess.getSettings().getCurrencySymbol()); + } + if (charge.getExperience() != null) + { + sb.append(charge.getExperience()).append(","); + sb.append("exp").append(","); + sb.append("\"\""); + } + } + sb.append(",\""); + if (receiver != null) + { + sb.append(receiver); + } + sb.append("\","); + if (pay == null) + { + sb.append("\"\",\"\",\"\""); + } + else + { + if (pay.getItemStack() != null) + { + sb.append(pay.getItemStack().getAmount()).append(","); + sb.append(pay.getItemStack().getType().toString()).append(","); + sb.append(pay.getItemStack().getDurability()); + } + if (pay.getMoney() != null) + { + sb.append(pay.getMoney()).append(","); + sb.append("money").append(","); + sb.append(ess.getSettings().getCurrencySymbol()); + } + if (pay.getExperience() != null) + { + sb.append(pay.getExperience()).append(","); + sb.append("exp").append(","); + sb.append("\"\""); + } + } + if (loc == null) + { + sb.append(",\"\",\"\",\"\",\"\""); + } + else + { + sb.append(",\""); + sb.append(loc.getWorld().getName()).append("\","); + sb.append(loc.getBlockX()).append(","); + sb.append(loc.getBlockY()).append(","); + sb.append(loc.getBlockZ()).append(","); + } + sb.append("\n"); + try + { + fw.write(sb.toString()); + fw.flush(); + } + catch (IOException ex) + { + Logger.getLogger("Essentials").log(Level.SEVERE, null, ex); + } + } + + public static void closeLog() + { + if (fw != null) + { + try + { + fw.close(); + } + catch (IOException ex) + { + Logger.getLogger("Essentials").log(Level.SEVERE, null, ex); + } + fw = null; + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/UUIDMap.java b/Essentials/src/com/earth2me/essentials/UUIDMap.java new file mode 100644 index 0000000000..e77a9149d1 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/UUIDMap.java @@ -0,0 +1,212 @@ +package com.earth2me.essentials; + +import com.google.common.io.Files; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentSkipListMap; +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.AtomicInteger; +import java.util.logging.Level; +import java.util.regex.Pattern; +import org.bukkit.Bukkit; + + +public class UUIDMap +{ + private final transient net.ess3.api.IEssentials ess; + private File userList; + private final transient Pattern splitPattern = Pattern.compile(","); + private static final ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor(); + private final AtomicInteger pendingDiskWrites = new AtomicInteger(0); + + public UUIDMap(final net.ess3.api.IEssentials ess) + { + this.ess = ess; + userList = new File(ess.getDataFolder(), "usermap.csv"); + + } + + public void loadAllUsers(final ConcurrentSkipListMap names, final ConcurrentSkipListMap> history) + { + try + { + if (!userList.exists()) + { + userList.createNewFile(); + } + + synchronized (pendingDiskWrites) + { + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "Reading usermap from disk"); + } + + names.clear(); + history.clear(); + + final BufferedReader reader = new BufferedReader(new FileReader(userList)); + try + { + while (true) + { + final String line = reader.readLine(); + if (line == null) + { + break; + } + else + { + final String[] values = splitPattern.split(line); + if (values.length == 2) + { + final String name = values[0]; + final UUID uuid = UUID.fromString(values[1]); + names.put(name, uuid); + if (!history.containsKey(uuid)) + { + final ArrayList list = new ArrayList(); + list.add(name); + history.put(uuid, list); + } + else + { + final ArrayList list = history.get(uuid); + if (!list.contains(name)) + { + list.add(name); + } + } + } + } + } + } + finally + { + reader.close(); + } + } + } + catch (IOException ex) + { + Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex); + } + } + + public void writeUUIDMap() + { + _writeUUIDMap(); + } + + public void forceWriteUUIDMap() + { + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "Forcing usermap write to disk"); + } + try + { + Future future = _writeUUIDMap();; + if (future != null) + { + future.get(); + } + } + catch (InterruptedException ex) + { + ess.getLogger().log(Level.SEVERE, ex.getMessage(), ex); + } + catch (ExecutionException ex) + { + ess.getLogger().log(Level.SEVERE, ex.getMessage(), ex); + } + } + + public Future _writeUUIDMap() + { + final ConcurrentSkipListMap names = ess.getUserMap().getNames(); + if (names.size() < 1) + { + return null; + } + pendingDiskWrites.incrementAndGet(); + Future future = EXECUTOR_SERVICE.submit(new WriteRunner(ess.getDataFolder(), userList, names, pendingDiskWrites)); + return future; + } + + + private static class WriteRunner implements Runnable + { + private final File location; + private final File endFile; + private final ConcurrentSkipListMap names; + private final AtomicInteger pendingDiskWrites; + + private WriteRunner(final File location, final File endFile, final ConcurrentSkipListMap names, final AtomicInteger pendingDiskWrites) + { + this.location = location; + this.endFile = endFile; + this.names = names; + this.pendingDiskWrites = pendingDiskWrites; + } + + @Override + public void run() + { + synchronized (pendingDiskWrites) + { + if (pendingDiskWrites.get() > 1) + { + pendingDiskWrites.decrementAndGet(); + return; + } + + File configFile = null; + + try + { + configFile = File.createTempFile("usermap", ".tmp.csv", location); + + final BufferedWriter bWriter = new BufferedWriter(new FileWriter(configFile)); + for (Map.Entry entry : names.entrySet()) + { + bWriter.write(entry.getKey() + "," + entry.getValue().toString()); + bWriter.newLine(); + } + + bWriter.close(); + Files.move(configFile, endFile); + } + catch (IOException ex) + { + try + { + if (configFile != null && configFile.exists()) + { + Files.move(configFile, new File(endFile.getParentFile(), "usermap.bak.csv")); + } + } + catch (Exception ex2) + { + Bukkit.getLogger().log(Level.SEVERE, ex2.getMessage(), ex2); + } + Bukkit.getLogger().log(Level.WARNING, ex.getMessage(), ex); + } + finally + { + pendingDiskWrites.decrementAndGet(); + } + } + } + } +} \ No newline at end of file diff --git a/Essentials/src/com/earth2me/essentials/User.java b/Essentials/src/com/earth2me/essentials/User.java new file mode 100644 index 0000000000..41a32e5299 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/User.java @@ -0,0 +1,898 @@ +package com.earth2me.essentials; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.commands.IEssentialsCommand; +import com.earth2me.essentials.register.payment.Method; +import com.earth2me.essentials.register.payment.Methods; +import com.earth2me.essentials.utils.DateUtil; +import com.earth2me.essentials.utils.FormatUtil; +import com.earth2me.essentials.utils.NumberUtil; +import java.math.BigDecimal; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; +import net.ess3.api.IEssentials; +import net.ess3.api.MaxMoneyException; +import net.ess3.api.events.AfkStatusChangeEvent; +import net.ess3.api.events.UserBalanceUpdateEvent; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + + +public class User extends UserData implements Comparable, IReplyTo, net.ess3.api.IUser +{ + private static final Logger logger = Logger.getLogger("Essentials"); + private CommandSource replyTo = null; + private transient UUID teleportRequester; + private transient boolean teleportRequestHere; + private transient Location teleportLocation; + private transient boolean vanished; + private transient final Teleport teleport; + private transient long teleportRequestTime; + private transient long lastOnlineActivity; + private transient long lastThrottledAction; + private transient long lastActivity = System.currentTimeMillis(); + private boolean hidden = false; + private boolean rightClickJump = false; + private transient Location afkPosition = null; + private boolean invSee = false; + private boolean recipeSee = false; + private boolean enderSee = false; + private transient long teleportInvulnerabilityTimestamp = 0; + + public User(final Player base, final IEssentials ess) + { + super(base, ess); + teleport = new Teleport(this, ess); + if (isAfk()) + { + afkPosition = this.getLocation(); + } + if (this.getBase().isOnline()) + { + lastOnlineActivity = System.currentTimeMillis(); + } + } + + User update(final Player base) + { + setBase(base); + return this; + } + + @Override + public boolean isAuthorized(final IEssentialsCommand cmd) + { + return isAuthorized(cmd, "essentials."); + } + + @Override + public boolean isAuthorized(final IEssentialsCommand cmd, final String permissionPrefix) + { + return isAuthorized(permissionPrefix + (cmd.getName().equals("r") ? "msg" : cmd.getName())); + } + + @Override + public boolean isAuthorized(final String node) + { + final boolean result = isAuthorizedCheck(node); + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "checking if " + base.getName() + " has " + node + " - " + result); + } + return result; + } + + private boolean isAuthorizedCheck(final String node) + { + + if (base instanceof OfflinePlayer) + { + return false; + } + + try + { + return ess.getPermissionsHandler().hasPermission(base, node); + } + catch (Exception ex) + { + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.SEVERE, "Permission System Error: " + ess.getPermissionsHandler().getName() + " returned: " + ex.getMessage(), ex); + } + else + { + ess.getLogger().log(Level.SEVERE, "Permission System Error: " + ess.getPermissionsHandler().getName() + " returned: " + ex.getMessage()); + } + + return false; + } + } + + @Override + public void healCooldown() throws Exception + { + final Calendar now = new GregorianCalendar(); + if (getLastHealTimestamp() > 0) + { + final double cooldown = ess.getSettings().getHealCooldown(); + final Calendar cooldownTime = new GregorianCalendar(); + cooldownTime.setTimeInMillis(getLastHealTimestamp()); + cooldownTime.add(Calendar.SECOND, (int)cooldown); + cooldownTime.add(Calendar.MILLISECOND, (int)((cooldown * 1000.0) % 1000.0)); + if (cooldownTime.after(now) && !isAuthorized("essentials.heal.cooldown.bypass")) + { + throw new Exception(tl("timeBeforeHeal", DateUtil.formatDateDiff(cooldownTime.getTimeInMillis()))); + } + } + setLastHealTimestamp(now.getTimeInMillis()); + } + + @Override + public void giveMoney(final BigDecimal value) throws MaxMoneyException + { + giveMoney(value, (CommandSource)null); + } + + @Override + public void giveMoney(final BigDecimal value, final CommandSource initiator) throws MaxMoneyException + { + if (value.signum() == 0) + { + return; + } + setMoney(getMoney().add(value)); + sendMessage(tl("addedToAccount", NumberUtil.displayCurrency(value, ess))); + if (initiator != null) + { + initiator.sendMessage(tl("addedToOthersAccount", NumberUtil.displayCurrency(value, ess), this.getDisplayName(), NumberUtil.displayCurrency(getMoney(), ess))); + } + } + + @Override + public void payUser(final User reciever, final BigDecimal value) throws ChargeException, MaxMoneyException + { + if (value.signum() == 0) + { + return; + } + if (canAfford(value)) + { + setMoney(getMoney().subtract(value)); + reciever.setMoney(reciever.getMoney().add(value)); + sendMessage(tl("moneySentTo", NumberUtil.displayCurrency(value, ess), reciever.getDisplayName())); + reciever.sendMessage(tl("moneyRecievedFrom", NumberUtil.displayCurrency(value, ess), getDisplayName())); + } + else + { + throw new ChargeException(tl("notEnoughMoney", NumberUtil.displayCurrency(value, ess))); + } + } + + @Override + public void takeMoney(final BigDecimal value) + { + takeMoney(value, (CommandSource)null); + } + + @Override + public void takeMoney(final BigDecimal value, final CommandSource initiator) + { + if (value.signum() == 0) + { + return; + } + try + { + setMoney(getMoney().subtract(value)); + } + catch (MaxMoneyException ex) + { + ess.getLogger().log(Level.WARNING, "Invalid call to takeMoney, total balance can't be more than the max-money limit.", ex); + } + sendMessage(tl("takenFromAccount", NumberUtil.displayCurrency(value, ess))); + if (initiator != null) + { + initiator.sendMessage(tl("takenFromOthersAccount", NumberUtil.displayCurrency(value, ess), this.getDisplayName(), NumberUtil.displayCurrency(getMoney(), ess))); + } + } + + @Override + public boolean canAfford(final BigDecimal cost) + { + return canAfford(cost, true); + } + + public boolean canAfford(final BigDecimal cost, final boolean permcheck) + { + if (cost.signum() <= 0) + { + return true; + } + final BigDecimal remainingBalance = getMoney().subtract(cost); + if (!permcheck || isAuthorized("essentials.eco.loan")) + { + return (remainingBalance.compareTo(ess.getSettings().getMinMoney()) >= 0); + } + return (remainingBalance.signum() >= 0); + } + + public void dispose() + { + ess.runTaskAsynchronously(new Runnable() + { + @Override + public void run() + { + _dispose(); + } + }); + } + + private void _dispose() + { + if (!base.isOnline()) + { + this.base = new OfflinePlayer(getConfigUUID(), ess.getServer()); + } + cleanup(); + } + + @Override + public Boolean canSpawnItem(final int itemId) + { + return !ess.getSettings().itemSpawnBlacklist().contains(itemId); + } + + @Override + public void setLastLocation() + { + setLastLocation(this.getLocation()); + } + + @Override + public void setLogoutLocation() + { + setLogoutLocation(this.getLocation()); + } + + @Override + public void requestTeleport(final User player, final boolean here) + { + teleportRequestTime = System.currentTimeMillis(); + teleportRequester = player == null ? null : player.getBase().getUniqueId(); + teleportRequestHere = here; + if (player == null) + { + teleportLocation = null; + } + else + { + teleportLocation = here ? player.getLocation() : this.getLocation(); + } + } + + public UUID getTeleportRequest() + { + return teleportRequester; + } + + public boolean isTpRequestHere() + { + return teleportRequestHere; + } + + public Location getTpRequestLocation() + { + return teleportLocation; + } + + public String getNick(final boolean longnick) + { + final StringBuilder prefix = new StringBuilder(); + String nickname; + String suffix = ""; + final String nick = getNickname(); + if (ess.getSettings().isCommandDisabled("nick") || nick == null || nick.isEmpty() || nick.equals(getName())) + { + nickname = getName(); + } + else if (nick.equalsIgnoreCase(getName())) { + nickname = nick; + } + else + { + nickname = ess.getSettings().getNicknamePrefix() + nick; + suffix = "§r"; + } + + if (this.getBase().isOp()) + { + try + { + final ChatColor opPrefix = ess.getSettings().getOperatorColor(); + if (opPrefix != null && opPrefix.toString().length() > 0) + { + prefix.insert(0, opPrefix.toString()); + suffix = "§r"; + } + } + catch (Exception e) + { + } + } + + if (ess.getSettings().addPrefixSuffix()) + { + //These two extra toggles are not documented, because they are mostly redundant #EasterEgg + if (!ess.getSettings().disablePrefix()) + { + final String ptext = ess.getPermissionsHandler().getPrefix(base).replace('&', '§'); + prefix.insert(0, ptext); + suffix = "§r"; + } + if (!ess.getSettings().disableSuffix()) + { + final String stext = ess.getPermissionsHandler().getSuffix(base).replace('&', '§'); + suffix = stext + "§r"; + suffix = suffix.replace("§f§f", "§f").replace("§f§r", "§r").replace("§r§r", "§r"); + } + } + final String strPrefix = prefix.toString(); + String output = strPrefix + nickname + suffix; + if (!longnick && output.length() > 16) + { + output = strPrefix + nickname; + } + if (!longnick && output.length() > 16) + { + output = FormatUtil.lastCode(strPrefix) + nickname; + } + if (!longnick && output.length() > 16) + { + output = FormatUtil.lastCode(strPrefix) + nickname.substring(0, 14); + } + if (output.charAt(output.length() - 1) == '§') + { + output = output.substring(0, output.length() - 1); + } + return output; + } + + public void setDisplayNick() + { + if (base.isOnline() && ess.getSettings().changeDisplayName()) + { + this.getBase().setDisplayName(getNick(true)); + if (ess.getSettings().changePlayerListName()) + { + String name = getNick(false); + try + { + this.getBase().setPlayerListName(name); + } + catch (IllegalArgumentException e) + { + if (ess.getSettings().isDebug()) + { + logger.log(Level.INFO, "Playerlist for " + name + " was not updated. Name clashed with another online player."); + } + } + } + } + } + + public String getDisplayName() + { + return super.getBase().getDisplayName() == null ? super.getBase().getName() : super.getBase().getDisplayName(); + } + + @Override + public Teleport getTeleport() + { + return teleport; + } + + public long getLastOnlineActivity() + { + return lastOnlineActivity; + } + + public void setLastOnlineActivity(final long timestamp) + { + lastOnlineActivity = timestamp; + } + + @Override + public BigDecimal getMoney() + { + final long start = System.nanoTime(); + final BigDecimal value = _getMoney(); + final long elapsed = System.nanoTime() - start; + if (elapsed > ess.getSettings().getEconomyLagWarning()) + { + ess.getLogger().log(Level.INFO, "Lag Notice - Slow Economy Response - Request took over {0}ms!", elapsed / 1000000.0); + } + return value; + } + + private BigDecimal _getMoney() + { + if (ess.getSettings().isEcoDisabled()) + { + if (ess.getSettings().isDebug()) + { + ess.getLogger().info("Internal economy functions disabled, aborting balance check."); + } + return BigDecimal.ZERO; + } + if (Methods.hasMethod()) + { + try + { + final Method method = Methods.getMethod(); + if (!method.hasAccount(this.getName())) + { + throw new Exception(); + } + final Method.MethodAccount account = Methods.getMethod().getAccount(this.getName()); + return BigDecimal.valueOf(account.balance()); + } + catch (Exception ex) + { + } + } + return super.getMoney(); + } + + @Override + public void setMoney(final BigDecimal value) throws MaxMoneyException + { + if (ess.getSettings().isEcoDisabled()) + { + if (ess.getSettings().isDebug()) + { + ess.getLogger().info("Internal economy functions disabled, aborting balance change."); + } + return; + } + final BigDecimal oldBalance = _getMoney(); + if (Methods.hasMethod()) + { + try + { + final Method method = Methods.getMethod(); + if (!method.hasAccount(this.getName())) + { + throw new Exception(); + } + final Method.MethodAccount account = Methods.getMethod().getAccount(this.getName()); + account.set(value.doubleValue()); + } + catch (Exception ex) + { + } + } + super.setMoney(value, true); + ess.getServer().getPluginManager().callEvent(new UserBalanceUpdateEvent(this.getBase(), oldBalance, value)); + Trade.log("Update", "Set", "API", getName(), new Trade(value, ess), null, null, null, ess); + } + + public void updateMoneyCache(final BigDecimal value) + { + if (ess.getSettings().isEcoDisabled()) + { + return; + } + if (Methods.hasMethod() && super.getMoney() != value) + { + try + { + super.setMoney(value, false); + } + catch (MaxMoneyException ex) + { + // We don't want to throw any errors here, just updating a cache + } + } + } + + @Override + public void setAfk(final boolean set) + { + final AfkStatusChangeEvent afkEvent = new AfkStatusChangeEvent(this, set); + ess.getServer().getPluginManager().callEvent(afkEvent); + if (afkEvent.isCancelled()) + { + return; + } + + this.getBase().setSleepingIgnored(this.isAuthorized("essentials.sleepingignored") ? true : set); + if (set && !isAfk()) + { + afkPosition = this.getLocation(); + } + else if (!set && isAfk()) + { + afkPosition = null; + } + _setAfk(set); + } + + public boolean toggleAfk() + { + setAfk(!isAfk()); + return isAfk(); + } + + @Override + public boolean isHidden() + { + return hidden; + } + + public boolean isHidden(final Player player) + { + return hidden || !player.canSee(getBase()); + } + + @Override + public void setHidden(final boolean hidden) + { + this.hidden = hidden; + if (hidden == true) + { + setLastLogout(getLastOnlineActivity()); + } + } + + //Returns true if status expired during this check + public boolean checkJailTimeout(final long currentTime) + { + if (getJailTimeout() > 0 && getJailTimeout() < currentTime && isJailed()) + { + setJailTimeout(0); + setJailed(false); + sendMessage(tl("haveBeenReleased")); + setJail(null); + try + { + getTeleport().back(); + } + catch (Exception ex) + { + try + { + getTeleport().respawn(null, TeleportCause.PLUGIN); + } + catch (Exception ex1) + { + } + } + return true; + } + return false; + } + + //Returns true if status expired during this check + public boolean checkMuteTimeout(final long currentTime) + { + if (getMuteTimeout() > 0 && getMuteTimeout() < currentTime && isMuted()) + { + setMuteTimeout(0); + sendMessage(tl("canTalkAgain")); + setMuted(false); + return true; + } + return false; + } + + public void updateActivity(final boolean broadcast) + { + if (isAfk() && ess.getSettings().cancelAfkOnInteract()) + { + setAfk(false); + if (broadcast && !isHidden()) + { + setDisplayNick(); + final String msg = tl("userIsNotAway", getDisplayName()); + if (!msg.isEmpty()) + { + ess.broadcastMessage(this, msg); + } + } + } + lastActivity = System.currentTimeMillis(); + } + + public void checkActivity() + { + final long autoafkkick = ess.getSettings().getAutoAfkKick(); + if (autoafkkick > 0 && lastActivity > 0 && (lastActivity + (autoafkkick * 1000)) < System.currentTimeMillis() + && !isHidden() && !isAuthorized("essentials.kick.exempt") && !isAuthorized("essentials.afk.kickexempt")) + { + final String kickReason = tl("autoAfkKickReason", autoafkkick / 60.0); + lastActivity = 0; + this.getBase().kickPlayer(kickReason); + + + for (User user : ess.getOnlineUsers()) + { + if (user.isAuthorized("essentials.kick.notify")) + { + user.sendMessage(tl("playerKicked", Console.NAME, getName(), kickReason)); + } + } + } + final long autoafk = ess.getSettings().getAutoAfk(); + if (!isAfk() && autoafk > 0 && lastActivity + autoafk * 1000 < System.currentTimeMillis() && isAuthorized("essentials.afk.auto")) + { + setAfk(true); + if (!isHidden()) + { + setDisplayNick(); + final String msg = tl("userIsAway", getDisplayName()); + if (!msg.isEmpty()) + { + ess.broadcastMessage(this, msg); + } + } + } + } + + public Location getAfkPosition() + { + return afkPosition; + } + + @Override + public boolean isGodModeEnabled() + { + return (super.isGodModeEnabled() && !ess.getSettings().getNoGodWorlds().contains(this.getLocation().getWorld().getName())) + || (isAfk() && ess.getSettings().getFreezeAfkPlayers()); + } + + public boolean isGodModeEnabledRaw() + { + return super.isGodModeEnabled(); + } + + @Override + public String getGroup() + { + final String result = ess.getPermissionsHandler().getGroup(base); + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "looking up groupname of " + base.getName() + " - " + result); + } + return result; + } + + @Override + public boolean inGroup(final String group) + { + final boolean result = ess.getPermissionsHandler().inGroup(base, group); + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "checking if " + base.getName() + " is in group " + group + " - " + result); + } + return result; + } + + @Override + public boolean canBuild() + { + if (this.getBase().isOp()) + { + return true; + } + return ess.getPermissionsHandler().canBuild(base, getGroup()); + } + + public long getTeleportRequestTime() + { + return teleportRequestTime; + } + + public boolean isInvSee() + { + return invSee; + } + + public void setInvSee(final boolean set) + { + invSee = set; + } + + public boolean isEnderSee() + { + return enderSee; + } + + public void setEnderSee(final boolean set) + { + enderSee = set; + } + + @Override + public void enableInvulnerabilityAfterTeleport() + { + final long time = ess.getSettings().getTeleportInvulnerability(); + if (time > 0) + { + teleportInvulnerabilityTimestamp = System.currentTimeMillis() + time; + } + } + + @Override + public void resetInvulnerabilityAfterTeleport() + { + if (teleportInvulnerabilityTimestamp != 0 + && teleportInvulnerabilityTimestamp < System.currentTimeMillis()) + { + teleportInvulnerabilityTimestamp = 0; + } + } + + @Override + public boolean hasInvulnerabilityAfterTeleport() + { + return teleportInvulnerabilityTimestamp != 0 && teleportInvulnerabilityTimestamp >= System.currentTimeMillis(); + } + + public boolean canInteractVanished() + { + return isAuthorized("essentials.vanish.interact"); + } + + @Override + public boolean isVanished() + { + return vanished; + } + + @Override + public void setVanished(final boolean set) + { + vanished = set; + if (set) + { + for (User user : ess.getOnlineUsers()) + { + if (!user.isAuthorized("essentials.vanish.see")) + { + user.getBase().hidePlayer(getBase()); + } + } + setHidden(true); + ess.getVanishedPlayers().add(getName()); + if (isAuthorized("essentials.vanish.effect")) + { + this.getBase().addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, Integer.MAX_VALUE, 1, false)); + } + } + else + { + for (Player p : ess.getOnlinePlayers()) + { + p.showPlayer(getBase()); + } + setHidden(false); + ess.getVanishedPlayers().remove(getName()); + if (isAuthorized("essentials.vanish.effect")) + { + this.getBase().removePotionEffect(PotionEffectType.INVISIBILITY); + } + } + } + + public boolean checkSignThrottle() + { + if (isSignThrottled()) + { + return true; + } + updateThrottle(); + return false; + } + + public boolean isSignThrottled() + { + final long minTime = lastThrottledAction + (1000 / ess.getSettings().getSignUsePerSecond()); + return (System.currentTimeMillis() < minTime); + } + + public void updateThrottle() + { + lastThrottledAction = System.currentTimeMillis(); + } + + public boolean isFlyClickJump() + { + return rightClickJump; + } + + public void setRightClickJump(boolean rightClickJump) + { + this.rightClickJump = rightClickJump; + } + + @Override + public boolean isIgnoreExempt() + { + return this.isAuthorized("essentials.chat.ignoreexempt"); + } + + public boolean isRecipeSee() + { + return recipeSee; + } + + public void setRecipeSee(boolean recipeSee) + { + this.recipeSee = recipeSee; + } + + @Override + public void sendMessage(String message) + { + if (!message.isEmpty()) + { + base.sendMessage(message); + } + } + + @Override + public void setReplyTo(final CommandSource user) + { + replyTo = user; + } + + @Override + public CommandSource getReplyTo() + { + return replyTo; + } + + @Override + public int compareTo(final User other) + { + return FormatUtil.stripFormat(getDisplayName()).compareToIgnoreCase(FormatUtil.stripFormat(other.getDisplayName())); + } + + @Override + public boolean equals(final Object object) + { + if (!(object instanceof User)) + { + return false; + } + return this.getName().equalsIgnoreCase(((User)object).getName()); + + } + + @Override + public int hashCode() + { + return this.getName().hashCode(); + } + + @Override + public CommandSource getSource() + { + return new CommandSource(getBase()); + } + + @Override + public String getName() + { + return this.getBase().getName(); + } +} diff --git a/Essentials/src/com/earth2me/essentials/UserData.java b/Essentials/src/com/earth2me/essentials/UserData.java new file mode 100644 index 0000000000..136e74fbed --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/UserData.java @@ -0,0 +1,972 @@ +package com.earth2me.essentials; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.utils.NumberUtil; +import com.earth2me.essentials.utils.StringUtil; +import java.io.File; +import java.math.BigDecimal; +import java.util.*; +import net.ess3.api.IEssentials; +import net.ess3.api.InvalidWorldException; +import net.ess3.api.MaxMoneyException; +import org.bukkit.Location; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + + +public abstract class UserData extends PlayerExtension implements IConf +{ + protected final transient IEssentials ess; + private final EssentialsUserConf config; + private final File folder; + + protected UserData(Player base, IEssentials ess) + { + super(base); + this.ess = ess; + folder = new File(ess.getDataFolder(), "userdata"); + if (!folder.exists()) + { + folder.mkdirs(); + } + + String filename; + try + { + filename = base.getUniqueId().toString(); + } + catch (Throwable ex) + { + ess.getLogger().warning("Falling back to old username system for " + base.getName()); + filename = base.getName(); + } + + config = new EssentialsUserConf(base.getName(), base.getUniqueId(), new File(folder, filename + ".yml")); + reloadConfig(); + } + + public final void reset() + { + config.forceSave(); + config.getFile().delete(); + if (config.username != null) + { + ess.getUserMap().removeUser(config.username); + } + } + + public final void cleanup() + { + config.cleanup(); + } + + @Override + public final void reloadConfig() + { + config.load(); + money = _getMoney(); + unlimited = _getUnlimited(); + powertools = _getPowertools(); + homes = _getHomes(); + lastLocation = _getLastLocation(); + lastTeleportTimestamp = _getLastTeleportTimestamp(); + lastHealTimestamp = _getLastHealTimestamp(); + jail = _getJail(); + mails = _getMails(); + teleportEnabled = _getTeleportEnabled(); + godmode = _getGodModeEnabled(); + muted = _getMuted(); + muteTimeout = _getMuteTimeout(); + jailed = _getJailed(); + jailTimeout = _getJailTimeout(); + lastLogin = _getLastLogin(); + lastLogout = _getLastLogout(); + lastLoginAddress = _getLastLoginAddress(); + afk = _getAfk(); + geolocation = _getGeoLocation(); + isSocialSpyEnabled = _isSocialSpyEnabled(); + isNPC = _isNPC(); + arePowerToolsEnabled = _arePowerToolsEnabled(); + kitTimestamps = _getKitTimestamps(); + nickname = _getNickname(); + ignoredPlayers = _getIgnoredPlayers(); + logoutLocation = _getLogoutLocation(); + lastAccountName = _getLastAccountName(); + } + private BigDecimal money; + + private BigDecimal _getMoney() + { + BigDecimal result = ess.getSettings().getStartingBalance(); + BigDecimal maxMoney = ess.getSettings().getMaxMoney(); + BigDecimal minMoney = ess.getSettings().getMinMoney(); + + if (config.hasProperty("money")) + { + result = config.getBigDecimal("money", result); + } + if (result.compareTo(maxMoney) > 0) + { + result = maxMoney; + } + if (result.compareTo(minMoney) < 0) + { + result = minMoney; + } + return result; + } + + public BigDecimal getMoney() + { + return money; + } + + public void setMoney(BigDecimal value, boolean throwError) throws MaxMoneyException + { + BigDecimal maxMoney = ess.getSettings().getMaxMoney(); + BigDecimal minMoney = ess.getSettings().getMinMoney(); + if (value.compareTo(maxMoney) > 0) + { + if (throwError) + { + throw new MaxMoneyException(); + } + money = maxMoney; + } + else + { + money = value; + } + if (money.compareTo(minMoney) < 0) + { + money = minMoney; + } + config.setProperty("money", money); + stopTransaction(); + } + private Map homes; + + private Map _getHomes() + { + if (config.isConfigurationSection("homes")) + { + return config.getConfigurationSection("homes").getValues(false); + } + return new HashMap(); + } + + private String getHomeName(String search) + { + if (NumberUtil.isInt(search)) + { + try + { + search = getHomes().get(Integer.parseInt(search) - 1); + } + catch (NumberFormatException e) + { + } + catch (IndexOutOfBoundsException e) + { + } + } + return search; + } + + public Location getHome(String name) throws Exception + { + String search = getHomeName(name); + return config.getLocation("homes." + search, this.getBase().getServer()); + } + + public Location getHome(final Location world) + { + try + { + if (getHomes().isEmpty()) + { + return null; + } + Location loc; + for (String home : getHomes()) + { + loc = config.getLocation("homes." + home, this.getBase().getServer()); + if (world.getWorld() == loc.getWorld()) + { + return loc; + } + + } + loc = config.getLocation("homes." + getHomes().get(0), this.getBase().getServer()); + return loc; + } + catch (InvalidWorldException ex) + { + return null; + } + } + + public List getHomes() + { + return new ArrayList(homes.keySet()); + } + + public void setHome(String name, Location loc) + { + //Invalid names will corrupt the yaml + name = StringUtil.safeString(name); + homes.put(name, loc); + config.setProperty("homes." + name, loc); + config.save(); + } + + public void delHome(String name) throws Exception + { + String search = getHomeName(name); + if (!homes.containsKey(search)) + { + search = StringUtil.safeString(search); + } + if (homes.containsKey(search)) + { + homes.remove(search); + config.removeProperty("homes." + search); + config.save(); + } + else + { + throw new Exception(tl("invalidHome", search)); + } + } + + public boolean hasHome() + { + if (config.hasProperty("home")) + { + return true; + } + return false; + } + private String nickname; + + public String _getNickname() + { + return config.getString("nickname"); + } + + public String getNickname() + { + return nickname; + } + + public void setNickname(String nick) + { + nickname = nick; + config.setProperty("nickname", nick); + config.save(); + } + private List unlimited; + + private List _getUnlimited() + { + return config.getIntegerList("unlimited"); + } + + public List getUnlimited() + { + return unlimited; + } + + public boolean hasUnlimited(ItemStack stack) + { + return unlimited.contains(stack.getTypeId()); + } + + public void setUnlimited(ItemStack stack, boolean state) + { + if (unlimited.contains(stack.getTypeId())) + { + unlimited.remove(Integer.valueOf(stack.getTypeId())); + } + if (state) + { + unlimited.add(stack.getTypeId()); + } + config.setProperty("unlimited", unlimited); + config.save(); + } + private Map powertools; + + private Map _getPowertools() + { + if (config.isConfigurationSection("powertools")) + { + return config.getConfigurationSection("powertools").getValues(false); + } + return new HashMap(); + } + + public void clearAllPowertools() + { + powertools.clear(); + config.setProperty("powertools", powertools); + config.save(); + } + + @SuppressWarnings("unchecked") + public List getPowertool(ItemStack stack) + { + return (List)powertools.get("" + stack.getTypeId()); + } + + @SuppressWarnings("unchecked") + public List getPowertool(int id) + { + return (List)powertools.get("" + id); + } + + public void setPowertool(ItemStack stack, List commandList) + { + if (commandList == null || commandList.isEmpty()) + { + powertools.remove("" + stack.getTypeId()); + } + else + { + powertools.put("" + stack.getTypeId(), commandList); + } + config.setProperty("powertools", powertools); + config.save(); + } + + public boolean hasPowerTools() + { + return !powertools.isEmpty(); + } + private Location lastLocation; + + private Location _getLastLocation() + { + try + { + return config.getLocation("lastlocation", this.getBase().getServer()); + } + catch (InvalidWorldException e) + { + return null; + } + } + + public Location getLastLocation() + { + return lastLocation; + } + + public void setLastLocation(Location loc) + { + if (loc == null || loc.getWorld() == null) + { + return; + } + lastLocation = loc; + config.setProperty("lastlocation", loc); + config.save(); + } + private Location logoutLocation; + + private Location _getLogoutLocation() + { + try + { + return config.getLocation("logoutlocation", this.getBase().getServer()); + } + catch (InvalidWorldException e) + { + return null; + } + } + + public Location getLogoutLocation() + { + return logoutLocation; + } + + public void setLogoutLocation(Location loc) + { + if (loc == null || loc.getWorld() == null) + { + return; + } + logoutLocation = loc; + config.setProperty("logoutlocation", loc); + config.save(); + } + private long lastTeleportTimestamp; + + private long _getLastTeleportTimestamp() + { + return config.getLong("timestamps.lastteleport", 0); + } + + public long getLastTeleportTimestamp() + { + return lastTeleportTimestamp; + } + + public void setLastTeleportTimestamp(long time) + { + lastTeleportTimestamp = time; + config.setProperty("timestamps.lastteleport", time); + config.save(); + } + private long lastHealTimestamp; + + private long _getLastHealTimestamp() + { + return config.getLong("timestamps.lastheal", 0); + } + + public long getLastHealTimestamp() + { + return lastHealTimestamp; + } + + public void setLastHealTimestamp(long time) + { + lastHealTimestamp = time; + config.setProperty("timestamps.lastheal", time); + config.save(); + } + private String jail; + + private String _getJail() + { + return config.getString("jail"); + } + + public String getJail() + { + return jail; + } + + public void setJail(String jail) + { + if (jail == null || jail.isEmpty()) + { + this.jail = null; + config.removeProperty("jail"); + } + else + { + this.jail = jail; + config.setProperty("jail", jail); + } + config.save(); + } + private List mails; + + private List _getMails() + { + return config.getStringList("mail"); + } + + public List getMails() + { + return mails; + } + + public void setMails(List mails) + { + if (mails == null) + { + config.removeProperty("mail"); + mails = _getMails(); + } + else + { + config.setProperty("mail", mails); + } + this.mails = mails; + config.save(); + } + + public void addMail(String mail) + { + mails.add(mail); + setMails(mails); + } + private boolean teleportEnabled; + + private boolean _getTeleportEnabled() + { + return config.getBoolean("teleportenabled", true); + } + + public boolean isTeleportEnabled() + { + return teleportEnabled; + } + + public void setTeleportEnabled(boolean set) + { + teleportEnabled = set; + config.setProperty("teleportenabled", set); + config.save(); + } + private List ignoredPlayers; + + public List _getIgnoredPlayers() + { + return Collections.synchronizedList(config.getStringList("ignore")); + } + + public void setIgnoredPlayers(List players) + { + if (players == null || players.isEmpty()) + { + ignoredPlayers = Collections.synchronizedList(new ArrayList()); + config.removeProperty("ignore"); + } + else + { + ignoredPlayers = players; + config.setProperty("ignore", players); + } + config.save(); + } + + @Deprecated + public boolean isIgnoredPlayer(final String userName) + { + final IUser user = ess.getUser(userName); + if (user == null || !user.getBase().isOnline()) + { + return false; + } + return isIgnoredPlayer(user); + } + + public boolean isIgnoredPlayer(IUser user) + { + return (ignoredPlayers.contains(user.getName().toLowerCase(Locale.ENGLISH)) && !user.isIgnoreExempt()); + } + + public void setIgnoredPlayer(IUser user, boolean set) + { + if (set) + { + ignoredPlayers.add(user.getName().toLowerCase(Locale.ENGLISH)); + } + else + { + ignoredPlayers.remove(user.getName().toLowerCase(Locale.ENGLISH)); + } + setIgnoredPlayers(ignoredPlayers); + } + private boolean godmode; + + private boolean _getGodModeEnabled() + { + return config.getBoolean("godmode", false); + } + + public boolean isGodModeEnabled() + { + return godmode; + } + + public void setGodModeEnabled(boolean set) + { + godmode = set; + config.setProperty("godmode", set); + config.save(); + } + private boolean muted; + + public boolean _getMuted() + { + return config.getBoolean("muted", false); + } + + public boolean getMuted() + { + return muted; + } + + public boolean isMuted() + { + return muted; + } + + public void setMuted(boolean set) + { + muted = set; + config.setProperty("muted", set); + config.save(); + } + private long muteTimeout; + + private long _getMuteTimeout() + { + return config.getLong("timestamps.mute", 0); + } + + public long getMuteTimeout() + { + return muteTimeout; + } + + public void setMuteTimeout(long time) + { + muteTimeout = time; + config.setProperty("timestamps.mute", time); + config.save(); + } + private boolean jailed; + + private boolean _getJailed() + { + return config.getBoolean("jailed", false); + } + + public boolean isJailed() + { + return jailed; + } + + public void setJailed(boolean set) + { + jailed = set; + config.setProperty("jailed", set); + config.save(); + } + + public boolean toggleJailed() + { + boolean ret = !isJailed(); + setJailed(ret); + return ret; + } + private long jailTimeout; + + private long _getJailTimeout() + { + return config.getLong("timestamps.jail", 0); + } + + public long getJailTimeout() + { + return jailTimeout; + } + + public void setJailTimeout(long time) + { + jailTimeout = time; + config.setProperty("timestamps.jail", time); + config.save(); + } + + private long lastLogin; + + private long _getLastLogin() + { + return config.getLong("timestamps.login", 0); + } + + public long getLastLogin() + { + return lastLogin; + } + + private void _setLastLogin(long time) + { + lastLogin = time; + config.setProperty("timestamps.login", time); + } + + public void setLastLogin(long time) + { + _setLastLogin(time); + if (base.getAddress() != null && base.getAddress().getAddress() != null) + { + _setLastLoginAddress(base.getAddress().getAddress().getHostAddress()); + } + config.save(); + } + private long lastLogout; + + private long _getLastLogout() + { + return config.getLong("timestamps.logout", 0); + } + + public long getLastLogout() + { + return lastLogout; + } + + public void setLastLogout(long time) + { + lastLogout = time; + config.setProperty("timestamps.logout", time); + config.save(); + } + private String lastLoginAddress; + + private String _getLastLoginAddress() + { + return config.getString("ipAddress", ""); + } + + public String getLastLoginAddress() + { + return lastLoginAddress; + } + + private void _setLastLoginAddress(String address) + { + lastLoginAddress = address; + config.setProperty("ipAddress", address); + } + private boolean afk; + + private boolean _getAfk() + { + return config.getBoolean("afk", false); + } + + public boolean isAfk() + { + return afk; + } + + public void _setAfk(boolean set) + { + afk = set; + config.setProperty("afk", set); + config.save(); + } + private boolean newplayer; + private String geolocation; + + private String _getGeoLocation() + { + return config.getString("geolocation"); + } + + public String getGeoLocation() + { + return geolocation; + } + + public void setGeoLocation(String geolocation) + { + if (geolocation == null || geolocation.isEmpty()) + { + this.geolocation = null; + config.removeProperty("geolocation"); + } + else + { + this.geolocation = geolocation; + config.setProperty("geolocation", geolocation); + } + config.save(); + } + private boolean isSocialSpyEnabled; + + private boolean _isSocialSpyEnabled() + { + return config.getBoolean("socialspy", false); + } + + public boolean isSocialSpyEnabled() + { + return isSocialSpyEnabled; + } + + public void setSocialSpyEnabled(boolean status) + { + isSocialSpyEnabled = status; + config.setProperty("socialspy", status); + config.save(); + } + private boolean isNPC; + + private boolean _isNPC() + { + return config.getBoolean("npc", false); + } + + public boolean isNPC() + { + return isNPC; + } + private String lastAccountName = null; + + public String getLastAccountName() + { + return lastAccountName; + } + + public String _getLastAccountName() + { + return config.getString("lastAccountName", null); + } + + public void setLastAccountName(String lastAccountName) + { + this.lastAccountName = lastAccountName; + config.setProperty("lastAccountName", lastAccountName); + config.save(); + ess.getUserMap().trackUUID(getConfigUUID(), lastAccountName, true); + } + + public void setNPC(boolean set) + { + isNPC = set; + config.setProperty("npc", set); + config.save(); + } + private boolean arePowerToolsEnabled; + + public boolean arePowerToolsEnabled() + { + return arePowerToolsEnabled; + } + + public void setPowerToolsEnabled(boolean set) + { + arePowerToolsEnabled = set; + config.setProperty("powertoolsenabled", set); + config.save(); + } + + public boolean togglePowerToolsEnabled() + { + boolean ret = !arePowerToolsEnabled(); + setPowerToolsEnabled(ret); + return ret; + } + + private boolean _arePowerToolsEnabled() + { + return config.getBoolean("powertoolsenabled", true); + } + private Map kitTimestamps; + + private Map _getKitTimestamps() + { + + if (config.isConfigurationSection("timestamps.kits")) + { + final ConfigurationSection section = config.getConfigurationSection("timestamps.kits"); + final Map timestamps = new HashMap(); + for (String command : section.getKeys(false)) + { + if (section.isLong(command)) + { + timestamps.put(command.toLowerCase(Locale.ENGLISH), section.getLong(command)); + } + else if (section.isInt(command)) + { + timestamps.put(command.toLowerCase(Locale.ENGLISH), (long)section.getInt(command)); + } + } + return timestamps; + } + return new HashMap(); + } + + public long getKitTimestamp(String name) + { + name = name.replace('.', '_').replace('/', '_'); + if (kitTimestamps != null && kitTimestamps.containsKey(name)) + { + return kitTimestamps.get(name); + } + return 0l; + } + + public void setKitTimestamp(final String name, final long time) + { + kitTimestamps.put(name.toLowerCase(Locale.ENGLISH), time); + config.setProperty("timestamps.kits", kitTimestamps); + config.save(); + } + + public void setConfigProperty(String node, Object object) + { + final String prefix = "info."; + node = prefix + node; + if (object instanceof Map) + { + config.setProperty(node, (Map)object); + } + else if (object instanceof List) + { + config.setProperty(node, (List)object); + } + else if (object instanceof Location) + { + config.setProperty(node, (Location)object); + } + else if (object instanceof ItemStack) + { + config.setProperty(node, (ItemStack)object); + } + else + { + config.setProperty(node, object); + } + config.save(); + } + + public Set getConfigKeys() + { + if (config.isConfigurationSection("info")) + { + return config.getConfigurationSection("info").getKeys(true); + } + return new HashSet(); + } + + public Map getConfigMap() + { + if (config.isConfigurationSection("info")) + { + return config.getConfigurationSection("info").getValues(true); + } + return new HashMap(); + } + + public Map getConfigMap(String node) + { + if (config.isConfigurationSection("info." + node)) + { + return config.getConfigurationSection("info." + node).getValues(true); + } + return new HashMap(); + } + + public UUID getConfigUUID() + { + return config.uuid; + } + + public void save() + { + config.save(); + } + + public void startTransaction() + { + config.startTransaction(); + } + + public void stopTransaction() + { + config.stopTransaction(); + } +} diff --git a/Essentials/src/com/earth2me/essentials/UserMap.java b/Essentials/src/com/earth2me/essentials/UserMap.java new file mode 100644 index 0000000000..a53731599f --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/UserMap.java @@ -0,0 +1,270 @@ +package com.earth2me.essentials; + +import com.earth2me.essentials.utils.StringUtil; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.RemovalCause; +import com.google.common.cache.RemovalListener; +import com.google.common.cache.RemovalNotification; +import com.google.common.util.concurrent.UncheckedExecutionException; +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentSkipListMap; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.ExecutionException; +import net.ess3.api.IEssentials; +import org.bukkit.entity.Player; + + +public class UserMap extends CacheLoader implements IConf +{ + private final transient IEssentials ess; + private final transient Cache users; + private final transient ConcurrentSkipListSet keys = new ConcurrentSkipListSet(); + private final transient ConcurrentSkipListMap names = new ConcurrentSkipListMap(); + private final transient ConcurrentSkipListMap> history = new ConcurrentSkipListMap>(); + private UUIDMap uuidMap; + + public UserMap(final IEssentials ess) + { + super(); + this.ess = ess; + uuidMap = new UUIDMap(ess); + //RemovalListener remListener = new UserMapRemovalListener(); + //users = CacheBuilder.newBuilder().maximumSize(ess.getSettings().getMaxUserCacheCount()).softValues().removalListener(remListener).build(this); + users = CacheBuilder.newBuilder().maximumSize(ess.getSettings().getMaxUserCacheCount()).softValues().build(this); + } + + private void loadAllUsersAsync(final IEssentials ess) + { + ess.runTaskAsynchronously(new Runnable() + { + @Override + public void run() + { + synchronized (users) + { + final File userdir = new File(ess.getDataFolder(), "userdata"); + if (!userdir.exists()) + { + return; + } + keys.clear(); + users.invalidateAll(); + for (String string : userdir.list()) + { + if (!string.endsWith(".yml")) + { + continue; + } + final String name = string.substring(0, string.length() - 4); + try + { + keys.add(UUID.fromString(name)); + } + catch (IllegalArgumentException ex) + { + //Ignore these users till they rejoin. + } + } + uuidMap.loadAllUsers(names, history); + } + } + }); + } + + public boolean userExists(final UUID uuid) + { + return keys.contains(uuid); + } + + public User getUser(final String name) + { + try + { + final String sanitizedName = StringUtil.safeString(name); + if (names.containsKey(sanitizedName)) + { + final UUID uuid = names.get(sanitizedName); + return getUser(uuid); + } + + final File userFile = getUserFileFromString(sanitizedName); + if (userFile.exists()) + { + ess.getLogger().info("Importing user " + name + " to usermap."); + User user = new User(new OfflinePlayer(sanitizedName, ess.getServer()), ess); + trackUUID(user.getBase().getUniqueId(), user.getName(), true); + return user; + } + return null; + } + catch (UncheckedExecutionException ex) + { + return null; + } + } + + public User getUser(final UUID uuid) + { + try + { + return users.get(uuid.toString()); + } + catch (ExecutionException ex) + { + return null; + } + catch (UncheckedExecutionException ex) + { + return null; + } + } + + public void trackUUID(final UUID uuid, final String name, boolean replace) + { + if (uuid != null) + { + keys.add(uuid); + if (name != null && name.length() > 0) + { + final String keyName = StringUtil.safeString(name); + if (!names.containsKey(keyName)) + { + names.put(keyName, uuid); + uuidMap.writeUUIDMap(); + } + else if (!names.get(keyName).equals(uuid)) + { + if (replace) + { + ess.getLogger().info("Found new UUID for " + name + ". Replacing " + names.get(keyName).toString() + " with " + uuid.toString()); + names.put(keyName, uuid); + uuidMap.writeUUIDMap(); + } + else + { + if (ess.getSettings().isDebug()) + { + ess.getLogger().info("Found old UUID for " + name + " (" + uuid.toString() + "). Not adding to usermap."); + } + } + } + } + } + } + + @Override + public User load(final String stringUUID) throws Exception + { + UUID uuid = UUID.fromString(stringUUID); + Player player = ess.getServer().getPlayer(uuid); + if (player != null) + { + final User user = new User(player, ess); + trackUUID(uuid, user.getName(), true); + return user; + } + + final File userFile = getUserFileFromID(uuid); + + if (userFile.exists()) + { + player = new OfflinePlayer(uuid, ess.getServer()); + final User user = new User(player, ess); + ((OfflinePlayer)player).setName(user.getLastAccountName()); + trackUUID(uuid, user.getName(), false); + return user; + } + + throw new Exception("User not found!"); + } + + @Override + public void reloadConfig() + { + getUUIDMap().forceWriteUUIDMap(); + loadAllUsersAsync(ess); + } + + public void invalidateAll() + { + users.invalidateAll(); + } + + public void removeUser(final String name) + { + if (names == null) + { + ess.getLogger().warning("Name collection is null, cannot remove user."); + return; + } + UUID uuid = names.get(name); + if (uuid != null) + { + keys.remove(uuid); + users.invalidate(uuid); + } + names.remove(name); + names.remove(StringUtil.safeString(name)); + } + + public Set getAllUniqueUsers() + { + return Collections.unmodifiableSet(keys.clone()); + } + + public int getUniqueUsers() + { + return keys.size(); + } + + protected ConcurrentSkipListMap getNames() + { + return names; + } + + protected ConcurrentSkipListMap> getHistory() + { + return history; + } + + public List getUserHistory(final UUID uuid) + { + return history.get(uuid); + } + + public UUIDMap getUUIDMap() + { + return uuidMap; + } + + private File getUserFileFromID(final UUID uuid) + { + final File userFolder = new File(ess.getDataFolder(), "userdata"); + return new File(userFolder, uuid.toString() + ".yml"); + } + + public File getUserFileFromString(final String name) + { + final File userFolder = new File(ess.getDataFolder(), "userdata"); + return new File(userFolder, StringUtil.sanitizeFileName(name) + ".yml"); + } +// class UserMapRemovalListener implements RemovalListener +// { +// @Override +// public void onRemoval(final RemovalNotification notification) +// { +// Object value = notification.getValue(); +// if (value != null) +// { +// ((User)value).cleanup(); +// } +// } +// } +} diff --git a/Essentials/src/com/earth2me/essentials/Warps.java b/Essentials/src/com/earth2me/essentials/Warps.java new file mode 100644 index 0000000000..3e0f93a55a --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/Warps.java @@ -0,0 +1,180 @@ +package com.earth2me.essentials; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.commands.WarpNotFoundException; +import com.earth2me.essentials.utils.StringUtil; +import java.io.File; +import java.io.IOException; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; +import net.ess3.api.InvalidNameException; +import net.ess3.api.InvalidWorldException; +import org.bukkit.Location; +import org.bukkit.Server; + + +public class Warps implements IConf, net.ess3.api.IWarps +{ + private static final Logger logger = Logger.getLogger("Essentials"); + private final Map warpPoints = new HashMap(); + private final File warpsFolder; + private final Server server; + + public Warps(Server server, File dataFolder) + { + this.server = server; + warpsFolder = new File(dataFolder, "warps"); + if (!warpsFolder.exists()) + { + warpsFolder.mkdirs(); + } + reloadConfig(); + } + + @Override + public boolean isEmpty() + { + return warpPoints.isEmpty(); + } + + @Override + public Collection getList() + { + final List keys = new ArrayList(); + for (StringIgnoreCase stringIgnoreCase : warpPoints.keySet()) + { + keys.add(stringIgnoreCase.getString()); + } + Collections.sort(keys, String.CASE_INSENSITIVE_ORDER); + return keys; + } + + @Override + public Location getWarp(String warp) throws WarpNotFoundException, InvalidWorldException + { + EssentialsConf conf = warpPoints.get(new StringIgnoreCase(warp)); + if (conf == null) + { + throw new WarpNotFoundException(); + } + return conf.getLocation(null, server); + } + + @Override + public void setWarp(String name, Location loc) throws Exception + { + String filename = StringUtil.sanitizeFileName(name); + EssentialsConf conf = warpPoints.get(new StringIgnoreCase(name)); + if (conf == null) + { + File confFile = new File(warpsFolder, filename + ".yml"); + if (confFile.exists()) + { + throw new Exception(tl("similarWarpExist")); + } + conf = new EssentialsConf(confFile); + warpPoints.put(new StringIgnoreCase(name), conf); + } + conf.setProperty(null, loc); + conf.setProperty("name", name); + try + { + conf.saveWithError(); + } + catch (IOException ex) + { + throw new IOException(tl("invalidWarpName")); + } + } + + @Override + public void removeWarp(String name) throws Exception + { + EssentialsConf conf = warpPoints.get(new StringIgnoreCase(name)); + if (conf == null) + { + throw new Exception(tl("warpNotExist")); + } + if (!conf.getFile().delete()) + { + throw new Exception(tl("warpDeleteError")); + } + warpPoints.remove(new StringIgnoreCase(name)); + } + + @Override + public final void reloadConfig() + { + warpPoints.clear(); + File[] listOfFiles = warpsFolder.listFiles(); + if (listOfFiles.length >= 1) + { + for (int i = 0; i < listOfFiles.length; i++) + { + String filename = listOfFiles[i].getName(); + if (listOfFiles[i].isFile() && filename.endsWith(".yml")) + { + try + { + EssentialsConf conf = new EssentialsConf(listOfFiles[i]); + conf.load(); + String name = conf.getString("name"); + if (name != null) + { + warpPoints.put(new StringIgnoreCase(name), conf); + } + } + catch (Exception ex) + { + logger.log(Level.WARNING, tl("loadWarpError", filename), ex); + } + } + } + } + } + + //This is here for future 3.x api support. Not implemented here becasue storage is handled differently + @Override + public File getWarpFile(String name) throws InvalidNameException + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getCount() + { + return getList().size(); + } + + private static class StringIgnoreCase + { + private final String string; + + public StringIgnoreCase(String string) + { + this.string = string; + } + + @Override + public int hashCode() + { + return getString().toLowerCase(Locale.ENGLISH).hashCode(); + } + + @Override + public boolean equals(Object o) + { + if (o instanceof StringIgnoreCase) + { + return getString().equalsIgnoreCase(((StringIgnoreCase)o).getString()); + } + return false; + } + + public String getString() + { + return string; + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/Worth.java b/Essentials/src/com/earth2me/essentials/Worth.java new file mode 100644 index 0000000000..91394a35a9 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/Worth.java @@ -0,0 +1,176 @@ +package com.earth2me.essentials; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.commands.NotEnoughArgumentsException; +import java.io.File; +import java.math.BigDecimal; +import java.util.Locale; +import java.util.logging.Logger; +import org.bukkit.Material; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.inventory.ItemStack; + + +public class Worth implements IConf +{ + private final EssentialsConf config; + + public Worth(File dataFolder) + { + config = new EssentialsConf(new File(dataFolder, "worth.yml")); + config.setTemplateName("/worth.yml"); + config.load(); + } + + public BigDecimal getPrice(ItemStack itemStack) + { + String itemname = itemStack.getType().toString().toLowerCase(Locale.ENGLISH).replace("_", ""); + BigDecimal result; + + //First check for matches with item name + result = config.getBigDecimal("worth." + itemname + "." + itemStack.getDurability(), BigDecimal.ONE.negate()); + if (result.signum() < 0) + { + final ConfigurationSection itemNameMatch = config.getConfigurationSection("worth." + itemname); + if (itemNameMatch != null && itemNameMatch.getKeys(false).size() == 1) + { + result = config.getBigDecimal("worth." + itemname + ".0", BigDecimal.ONE.negate()); + } + } + if (result.signum() < 0) + { + result = config.getBigDecimal("worth." + itemname + ".*", BigDecimal.ONE.negate()); + } + if (result.signum() < 0) + { + result = config.getBigDecimal("worth." + itemname, BigDecimal.ONE.negate()); + } + + //Now we should check for item ID + if (result.signum() < 0) + { + result = config.getBigDecimal("worth." + itemStack.getTypeId() + "." + itemStack.getDurability(), BigDecimal.ONE.negate()); + } + if (result.signum() < 0) + { + final ConfigurationSection itemNumberMatch = config.getConfigurationSection("worth." + itemStack.getTypeId()); + if (itemNumberMatch != null && itemNumberMatch.getKeys(false).size() == 1) + { + result = config.getBigDecimal("worth." + itemStack.getTypeId() + ".0", BigDecimal.ONE.negate()); + } + } + if (result.signum() < 0) + { + result = config.getBigDecimal("worth." + itemStack.getTypeId() + ".*", BigDecimal.ONE.negate()); + } + if (result.signum() < 0) + { + result = config.getBigDecimal("worth." + itemStack.getTypeId(), BigDecimal.ONE.negate()); + } + + //This is to match the old worth syntax + if (result.signum() < 0) + { + result = config.getBigDecimal("worth-" + itemStack.getTypeId(), BigDecimal.ONE.negate()); + } + if (result.signum() < 0) + { + return null; + } + return result; + } + + public int getAmount(IEssentials ess, User user, ItemStack is, String[] args, boolean isBulkSell) throws Exception + { + if (is == null || is.getType() == Material.AIR) + { + throw new Exception(tl("itemSellAir")); + } + int id = is.getTypeId(); + int amount = 0; + + if (args.length > 1) + { + try + { + amount = Integer.parseInt(args[1].replaceAll("[^0-9]", "")); + } + catch (NumberFormatException ex) + { + throw new NotEnoughArgumentsException(ex); + } + if (args[1].startsWith("-")) + { + amount = -amount; + } + } + + boolean stack = args.length > 1 && args[1].endsWith("s"); + boolean requireStack = ess.getSettings().isTradeInStacks(id); + + if (requireStack && !stack) + { + throw new Exception(tl("itemMustBeStacked")); + } + + int max = 0; + for (ItemStack s : user.getBase().getInventory().getContents()) + { + if (s == null || !s.isSimilar(is)) + { + continue; + } + max += s.getAmount(); + } + + if (stack) + { + amount *= is.getType().getMaxStackSize(); + } + if (amount < 1) + { + amount += max; + } + + if (requireStack) + { + amount -= amount % is.getType().getMaxStackSize(); + } + if (amount > max || amount < 1) + { + if (!isBulkSell) + { + user.sendMessage(tl("itemNotEnough2")); + user.sendMessage(tl("itemNotEnough3")); + throw new Exception(tl("itemNotEnough1")); + } + else + { + return amount; + } + } + + return amount; + } + + public void setPrice(ItemStack itemStack, double price) + { + if (itemStack.getType().getData() == null) + { + config.setProperty("worth." + itemStack.getType().toString().toLowerCase(Locale.ENGLISH).replace("_", ""), price); + } + else + { + // Bukkit-bug: getDurability still contains the correct value, while getData().getData() is 0. + config.setProperty("worth." + itemStack.getType().toString().toLowerCase(Locale.ENGLISH).replace("_", "") + "." + itemStack.getDurability(), price); + } + config.removeProperty("worth-" + itemStack.getTypeId()); + config.save(); + } + + @Override + public void reloadConfig() + { + config.load(); + } +} diff --git a/Essentials/src/com/earth2me/essentials/api/Economy.java b/Essentials/src/com/earth2me/essentials/api/Economy.java new file mode 100644 index 0000000000..35c733ae02 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/api/Economy.java @@ -0,0 +1,464 @@ +package com.earth2me.essentials.api; + +import com.earth2me.essentials.EssentialsConf; +import com.earth2me.essentials.EssentialsUserConf; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import static com.earth2me.essentials.api.Economy.add; +import static com.earth2me.essentials.api.Economy.divide; +import static com.earth2me.essentials.api.Economy.format; +import static com.earth2me.essentials.api.Economy.getMoneyExact; +import static com.earth2me.essentials.api.Economy.hasEnough; +import static com.earth2me.essentials.api.Economy.hasLess; +import static com.earth2me.essentials.api.Economy.hasMore; +import static com.earth2me.essentials.api.Economy.multiply; +import static com.earth2me.essentials.api.Economy.setMoney; +import static com.earth2me.essentials.api.Economy.substract; +import com.earth2me.essentials.utils.NumberUtil; +import com.earth2me.essentials.utils.StringUtil; +import com.google.common.base.Charsets; +import java.io.File; +import java.math.BigDecimal; +import java.math.MathContext; +import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; +import net.ess3.api.IEssentials; +import net.ess3.api.MaxMoneyException; + + +/** + * Instead of using this api directly, we recommend to use the register plugin: http://bit.ly/RegisterMethod + */ +public class Economy +{ + public Economy() + { + } + private static final Logger logger = Logger.getLogger("Essentials"); + private static IEssentials ess; + private static final String noCallBeforeLoad = "Essentials API is called before Essentials is loaded."; + public static final MathContext MATH_CONTEXT = MathContext.DECIMAL128; + + /** + * @param aEss the ess to set + */ + public static void setEss(IEssentials aEss) + { + ess = aEss; + } + + private static void createNPCFile(String name) + { + File folder = new File(ess.getDataFolder(), "userdata"); + name = StringUtil.safeString(name); + if (!folder.exists()) + { + folder.mkdirs(); + } + UUID npcUUID = UUID.nameUUIDFromBytes(("NPC:" + name).getBytes(Charsets.UTF_8)); + EssentialsUserConf npcConfig = new EssentialsUserConf(name, npcUUID, new File(folder, npcUUID.toString() + ".yml")); + npcConfig.load(); + npcConfig.setProperty("npc", true); + npcConfig.setProperty("lastAccountName", name); + npcConfig.setProperty("money", ess.getSettings().getStartingBalance()); + npcConfig.forceSave(); + ess.getUserMap().trackUUID(npcUUID, name, false); + } + + private static void deleteNPC(String name) + { + User user = ess.getUser(name); + user.reset(); + } + + private static User getUserByName(String name) + { + if (ess == null) + { + throw new RuntimeException(noCallBeforeLoad); + } + if (name == null) + { + throw new RuntimeException("Economy username cannot be null"); + } + return ess.getUser(name); + } + + /** + * Returns the balance of a user + * + * @param name Name of the user + * @return balance + * @throws UserDoesNotExistException + */ + @Deprecated + public static double getMoney(String name) throws UserDoesNotExistException + { + return getMoneyExact(name).doubleValue(); + } + + public static BigDecimal getMoneyExact(String name) throws UserDoesNotExistException + { + User user = getUserByName(name); + if (user == null) + { + throw new UserDoesNotExistException(name); + } + return user.getMoney(); + } + + /** + * Sets the balance of a user + * + * @param name Name of the user + * @param balance The balance you want to set + * @throws UserDoesNotExistException If a user by that name does not exists + * @throws NoLoanPermittedException If the user is not allowed to have a negative balance + */ + @Deprecated + public static void setMoney(String name, double balance) throws UserDoesNotExistException, NoLoanPermittedException + { + try + { + setMoney(name, BigDecimal.valueOf(balance)); + } + catch (ArithmeticException e) + { + logger.log(Level.WARNING, "Failed to set balance of " + name + " to " + balance + ": " + e.getMessage(), e); + } + } + + public static void setMoney(String name, BigDecimal balance) throws UserDoesNotExistException, NoLoanPermittedException + { + User user = getUserByName(name); + if (user == null) + { + throw new UserDoesNotExistException(name); + } + if (balance.compareTo(ess.getSettings().getMinMoney()) < 0) + { + throw new NoLoanPermittedException(); + } + if (balance.signum() < 0 && !user.isAuthorized("essentials.eco.loan")) + { + throw new NoLoanPermittedException(); + } + try + { + user.setMoney(balance); + } + catch (MaxMoneyException ex) + { + //TODO: Update API to show max balance errors + } + Trade.log("API", "Set", "API", name, new Trade(balance, ess), null, null, null, ess); + } + + /** + * Adds money to the balance of a user + * + * @param name Name of the user + * @param amount The money you want to add + * @throws UserDoesNotExistException If a user by that name does not exists + * @throws NoLoanPermittedException If the user is not allowed to have a negative balance + */ + @Deprecated + public static void add(String name, double amount) throws UserDoesNotExistException, NoLoanPermittedException + { + try + { + add(name, BigDecimal.valueOf(amount)); + } + catch (ArithmeticException e) + { + logger.log(Level.WARNING, "Failed to add " + amount + " to balance of " + name + ": " + e.getMessage(), e); + } + } + + public static void add(String name, BigDecimal amount) throws UserDoesNotExistException, NoLoanPermittedException, ArithmeticException + { + BigDecimal result = getMoneyExact(name).add(amount, MATH_CONTEXT); + setMoney(name, result); + Trade.log("API", "Add", "API", name, new Trade(amount, ess), null, null, null, ess); + } + + /** + * Substracts money from the balance of a user + * + * @param name Name of the user + * @param amount The money you want to substract + * @throws UserDoesNotExistException If a user by that name does not exists + * @throws NoLoanPermittedException If the user is not allowed to have a negative balance + */ + @Deprecated + public static void subtract(String name, double amount) throws UserDoesNotExistException, NoLoanPermittedException + { + try + { + substract(name, BigDecimal.valueOf(amount)); + } + catch (ArithmeticException e) + { + logger.log(Level.WARNING, "Failed to substract " + amount + " of balance of " + name + ": " + e.getMessage(), e); + } + } + + public static void substract(String name, BigDecimal amount) throws UserDoesNotExistException, NoLoanPermittedException, ArithmeticException + { + BigDecimal result = getMoneyExact(name).subtract(amount, MATH_CONTEXT); + setMoney(name, result); + Trade.log("API", "Subtract", "API", name, new Trade(amount, ess), null, null, null, ess); + } + + /** + * Divides the balance of a user by a value + * + * @param name Name of the user + * @param value The balance is divided by this value + * @throws UserDoesNotExistException If a user by that name does not exists + * @throws NoLoanPermittedException If the user is not allowed to have a negative balance + */ + @Deprecated + public static void divide(String name, double amount) throws UserDoesNotExistException, NoLoanPermittedException + { + try + { + divide(name, BigDecimal.valueOf(amount)); + } + catch (ArithmeticException e) + { + logger.log(Level.WARNING, "Failed to divide balance of " + name + " by " + amount + ": " + e.getMessage(), e); + } + } + + public static void divide(String name, BigDecimal amount) throws UserDoesNotExistException, NoLoanPermittedException, ArithmeticException + { + BigDecimal result = getMoneyExact(name).divide(amount, MATH_CONTEXT); + setMoney(name, result); + Trade.log("API", "Divide", "API", name, new Trade(amount, ess), null, null, null, ess); + } + + /** + * Multiplies the balance of a user by a value + * + * @param name Name of the user + * @param value The balance is multiplied by this value + * @throws UserDoesNotExistException If a user by that name does not exists + * @throws NoLoanPermittedException If the user is not allowed to have a negative balance + */ + @Deprecated + public static void multiply(String name, double amount) throws UserDoesNotExistException, NoLoanPermittedException + { + try + { + multiply(name, BigDecimal.valueOf(amount)); + } + catch (ArithmeticException e) + { + logger.log(Level.WARNING, "Failed to multiply balance of " + name + " by " + amount + ": " + e.getMessage(), e); + } + } + + public static void multiply(String name, BigDecimal amount) throws UserDoesNotExistException, NoLoanPermittedException, ArithmeticException + { + BigDecimal result = getMoneyExact(name).multiply(amount, MATH_CONTEXT); + setMoney(name, result); + Trade.log("API", "Multiply", "API", name, new Trade(amount, ess), null, null, null, ess); + } + + /** + * Resets the balance of a user to the starting balance + * + * @param name Name of the user + * @throws UserDoesNotExistException If a user by that name does not exists + * @throws NoLoanPermittedException If the user is not allowed to have a negative balance + */ + public static void resetBalance(String name) throws UserDoesNotExistException, NoLoanPermittedException + { + if (ess == null) + { + throw new RuntimeException(noCallBeforeLoad); + } + setMoney(name, ess.getSettings().getStartingBalance()); + Trade.log("API", "Reset", "API", name, new Trade(BigDecimal.ZERO, ess), null, null, null, ess); + } + + /** + * @param name Name of the user + * @param amount The amount of money the user should have + * @return true, if the user has more or an equal amount of money + * @throws UserDoesNotExistException If a user by that name does not exists + */ + @Deprecated + public static boolean hasEnough(String name, double amount) throws UserDoesNotExistException + { + try + { + return hasEnough(name, BigDecimal.valueOf(amount)); + } + catch (ArithmeticException e) + { + logger.log(Level.WARNING, "Failed to compare balance of " + name + " with " + amount + ": " + e.getMessage(), e); + return false; + } + } + + public static boolean hasEnough(String name, BigDecimal amount) throws UserDoesNotExistException, ArithmeticException + { + return amount.compareTo(getMoneyExact(name)) <= 0; + } + + /** + * @param name Name of the user + * @param amount The amount of money the user should have + * @return true, if the user has more money + * @throws UserDoesNotExistException If a user by that name does not exists + */ + @Deprecated + public static boolean hasMore(String name, double amount) throws UserDoesNotExistException + { + try + { + return hasMore(name, BigDecimal.valueOf(amount)); + } + catch (ArithmeticException e) + { + logger.log(Level.WARNING, "Failed to compare balance of " + name + " with " + amount + ": " + e.getMessage(), e); + return false; + } + } + + public static boolean hasMore(String name, BigDecimal amount) throws UserDoesNotExistException, ArithmeticException + { + return amount.compareTo(getMoneyExact(name)) < 0; + } + + /** + * @param name Name of the user + * @param amount The amount of money the user should not have + * @return true, if the user has less money + * @throws UserDoesNotExistException If a user by that name does not exists + */ + @Deprecated + public static boolean hasLess(String name, double amount) throws UserDoesNotExistException + { + try + { + return hasLess(name, BigDecimal.valueOf(amount)); + } + catch (ArithmeticException e) + { + logger.log(Level.WARNING, "Failed to compare balance of " + name + " with " + amount + ": " + e.getMessage(), e); + return false; + } + } + + public static boolean hasLess(String name, BigDecimal amount) throws UserDoesNotExistException, ArithmeticException + { + return amount.compareTo(getMoneyExact(name)) > 0; + } + + /** + * Test if the user has a negative balance + * + * @param name Name of the user + * @return true, if the user has a negative balance + * @throws UserDoesNotExistException If a user by that name does not exists + */ + public static boolean isNegative(String name) throws UserDoesNotExistException + { + return getMoneyExact(name).signum() < 0; + } + + /** + * Formats the amount of money like all other Essentials functions. Example: $100000 or $12345.67 + * + * @param amount The amount of money + * @return Formatted money + */ + @Deprecated + public static String format(double amount) + { + try + { + return format(BigDecimal.valueOf(amount)); + } + catch (NumberFormatException e) + { + logger.log(Level.WARNING, "Failed to display " + amount + ": " + e.getMessage(), e); + return "NaN"; + } + } + + public static String format(BigDecimal amount) + { + if (ess == null) + { + throw new RuntimeException(noCallBeforeLoad); + } + return NumberUtil.displayCurrency(amount, ess); + } + + /** + * Test if a player exists to avoid the UserDoesNotExistException + * + * @param name Name of the user + * @return true, if the user exists + */ + public static boolean playerExists(String name) + { + return getUserByName(name) != null; + } + + /** + * Test if a player is a npc + * + * @param name Name of the player + * @return true, if it's a npc + * @throws UserDoesNotExistException + */ + public static boolean isNPC(String name) throws UserDoesNotExistException + { + User user = getUserByName(name); + if (user == null) + { + throw new UserDoesNotExistException(name); + } + return user.isNPC(); + } + + /** + * Creates dummy files for a npc, if there is no player yet with that name. + * + * @param name Name of the player + * @return true, if a new npc was created + */ + public static boolean createNPC(String name) + { + User user = getUserByName(name); + if (user == null) + { + createNPCFile(name); + return true; + } + return false; + } + + /** + * Deletes a user, if it is marked as npc. + * + * @param name Name of the player + * @throws UserDoesNotExistException + */ + public static void removeNPC(String name) throws UserDoesNotExistException + { + User user = getUserByName(name); + if (user == null) + { + throw new UserDoesNotExistException(name); + } + deleteNPC(name); + } +} diff --git a/Essentials/src/com/earth2me/essentials/api/II18n.java b/Essentials/src/com/earth2me/essentials/api/II18n.java new file mode 100644 index 0000000000..6845ba8d10 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/api/II18n.java @@ -0,0 +1,13 @@ +package com.earth2me.essentials.api; + +import java.util.Locale; + + +public interface II18n +{ + /** + * Gets the current locale setting + * @return the current locale, if not set it will return the default locale + */ + Locale getCurrentLocale(); +} diff --git a/Essentials/src/com/earth2me/essentials/api/IItemDb.java b/Essentials/src/com/earth2me/essentials/api/IItemDb.java new file mode 100644 index 0000000000..a1da6dd8eb --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/api/IItemDb.java @@ -0,0 +1,20 @@ + +package com.earth2me.essentials.api; + +import com.earth2me.essentials.User; +import java.util.List; +import org.bukkit.inventory.ItemStack; + + +public interface IItemDb +{ + ItemStack get(final String name, final int quantity) throws Exception; + + ItemStack get(final String name) throws Exception; + + public String names(ItemStack item); + + public String name(ItemStack item); + + List getMatching(User user, String[] args) throws Exception; +} diff --git a/Essentials/src/com/earth2me/essentials/api/IJails.java b/Essentials/src/com/earth2me/essentials/api/IJails.java new file mode 100644 index 0000000000..ea45ea73ab --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/api/IJails.java @@ -0,0 +1,53 @@ +package com.earth2me.essentials.api; + +import java.util.Collection; +import net.ess3.api.IUser; +import org.bukkit.Location; + + +public interface IJails extends IReload +{ + /** + * Gets the location of the jail with the given name + * @param jailName The name of the jail + * @return the location of the jail + * @throws Exception if the jail does not exist + */ + Location getJail(String jailName) throws Exception; + + /** + * Gets a list of jails by names + * @return a list of jails, if there are none the list will be empty + * @throws Exception + */ + Collection getList() throws Exception; + + /** + * Gets the number of jails + * @return the size of the list of jails + */ + int getCount(); + + /** + * Remove the jail with the given name + * @param jail the jail to remove + * @throws Exception if the jail does not exist + */ + void removeJail(String jail) throws Exception; + + /** + * Attempts to send the given user to the given jail + * @param user the user to send to jail + * @param jail the jail to send the user to + * @throws Exception if the user is offline or jail does not exist + */ + void sendToJail(IUser user, String jail) throws Exception; + + /** + * Set a new jail with the given name and location + * @param jailName the name of the jail being set + * @param loc the location of the jail being set + * @throws Exception + */ + void setJail(String jailName, Location loc) throws Exception; +} diff --git a/Essentials/src/com/earth2me/essentials/api/IReload.java b/Essentials/src/com/earth2me/essentials/api/IReload.java new file mode 100644 index 0000000000..75403b55c3 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/api/IReload.java @@ -0,0 +1,7 @@ +package com.earth2me.essentials.api; + + +public interface IReload +{ + void onReload(); +} diff --git a/Essentials/src/com/earth2me/essentials/api/ITeleport.java b/Essentials/src/com/earth2me/essentials/api/ITeleport.java new file mode 100644 index 0000000000..a14f4a5e13 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/api/ITeleport.java @@ -0,0 +1,112 @@ +package com.earth2me.essentials.api; + +import com.earth2me.essentials.Trade; +import net.ess3.api.IUser; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerTeleportEvent; + + +public interface ITeleport +{ + /** + * Used to skip teleportPlayer delay when teleporting someone to a location or player. + * + * @param loc - Where should the player end up + * @param cooldown - If cooldown should be enforced + * @param cause - The reported teleportPlayer cause + * @throws Exception + */ + void now(Location loc, boolean cooldown, PlayerTeleportEvent.TeleportCause cause) throws Exception; + + /** + * Used to skip teleportPlayer delay when teleporting someone to a location or player. + * + * @param entity - Where should the player end up + * @param cooldown - If cooldown should be enforced + * @param cause - The reported teleportPlayer cause + * @throws Exception + */ + void now(Player entity, boolean cooldown, PlayerTeleportEvent.TeleportCause cause) throws Exception; + + @Deprecated + void teleport(Location loc, Trade chargeFor) throws Exception; + + /** + * Teleport a player to a specific location + * + * @param loc - Where should the player end up + * @param chargeFor - What the user will be charged if teleportPlayer is successful + * @param cause - The reported teleportPlayer cause + * @throws Exception + */ + void teleport(Location loc, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause) throws Exception; + + /** + * Teleport a player to a specific player + * + * @param entity - Where should the player end up + * @param chargeFor - What the user will be charged if teleportPlayer is successful + * @param cause - The reported teleportPlayer cause + * @throws Exception + */ + void teleport(Player entity, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause) throws Exception; + + /** + * Teleport a player to a specific location + * + * @param otherUser - Which user will be teleported + * @param loc - Where should the player end up + * @param chargeFor - What the user will be charged if teleportPlayer is successful + * @param cause - The reported teleportPlayer cause + * @throws Exception + */ + void teleportPlayer(IUser otherUser, Location loc, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause) throws Exception; + + /** + * Teleport a player to a specific player + * + * @param otherUser - Which user will be teleported + * @param entity - Where should the player end up + * @param chargeFor - What the user will be charged if teleportPlayer is successful + * @param cause - The reported teleportPlayer cause + * @throws Exception + */ + void teleportPlayer(IUser otherUser, Player entity, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause) throws Exception; + + /** + * Teleport wrapper used to handle tp fallback on /jail and /home + * + * @param chargeFor - What the user will be charged if teleportPlayer is successful + * @param cause - The reported teleportPlayer cause + * @throws Exception + */ + public void respawn(final Trade chargeFor, PlayerTeleportEvent.TeleportCause cause) throws Exception; + + /** + * Teleport wrapper used to handle /warp teleports + * + * @param otherUser - Which user will be teleported + * @param warp - The name of the warp the user will be teleported too. + * @param chargeFor - What the user will be charged if teleportPlayer is successful + * @param cause - The reported teleportPlayer cause + * @throws Exception + */ + public void warp(IUser otherUser, String warp, Trade chargeFor, PlayerTeleportEvent.TeleportCause cause) throws Exception; + + /** + * Teleport wrapper used to handle /back teleports + * + * @param chargeFor - What the user will be charged if teleportPlayer is successful + * @throws Exception + */ + public void back(Trade chargeFor) throws Exception; + + /** + * Teleport wrapper used to handle throwing user home after a jail sentence + * + * @throws Exception + */ + public void back() throws Exception; + +} diff --git a/Essentials/src/com/earth2me/essentials/api/IWarps.java b/Essentials/src/com/earth2me/essentials/api/IWarps.java new file mode 100644 index 0000000000..705822d8e7 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/api/IWarps.java @@ -0,0 +1,68 @@ +package com.earth2me.essentials.api; + +import com.earth2me.essentials.IConf; +import com.earth2me.essentials.commands.WarpNotFoundException; +import java.io.File; +import java.util.Collection; +import org.bukkit.Location; + + +public interface IWarps extends IConf +{ + /** + * Get a warp by name + * + * @param warp - Warp name + * @return - Location the warp is set to + * @throws WarpNotFoundException When the warp is not found + * @throws InvalidWorldException When the world the warp is in is not found + */ + Location getWarp(String warp) throws WarpNotFoundException, net.ess3.api.InvalidWorldException; + + /** + * Gets a list of warps + * + * @return - A {@link Collection} of warps + */ + Collection getList(); + + /** + * Gets the number of warps + * + * @return the size of the list of warps + */ + int getCount(); + + /** + * Delete a warp from the warp DB + * + * @param name - Name of warp + * @throws Exception + */ + void removeWarp(String name) throws Exception; + + /** + * Set a warp + * + * @param name - Name of warp + * @param loc - Location of warp + * @throws Exception + */ + void setWarp(String name, Location loc) throws Exception; + + /** + * Check to see if the file is empty + * + * @return + */ + boolean isEmpty(); + + /** + * Get a warp file note: this is not yet implemented, as 3.x uses different storage methods + * + * @param name - name of file + * @return - an instance of the file + * @throws InvalidNameException - When the file is not found + */ + File getWarpFile(String name) throws net.ess3.api.InvalidNameException; +} diff --git a/Essentials/src/com/earth2me/essentials/api/InvalidNameException.java b/Essentials/src/com/earth2me/essentials/api/InvalidNameException.java new file mode 100644 index 0000000000..b62a74ce3f --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/api/InvalidNameException.java @@ -0,0 +1,16 @@ +package com.earth2me.essentials.api; + + +public class InvalidNameException extends Exception +{ + /** + * NOTE: This is not implemented yet, just here for future 3.x api support + * Allow serialization of the InvalidNameException exception + */ + private static final long serialVersionUID = 1485321420293663139L; + + public InvalidNameException(Throwable thrwbl) + { + super(thrwbl); + } +} diff --git a/Essentials/src/com/earth2me/essentials/api/InvalidWorldException.java b/Essentials/src/com/earth2me/essentials/api/InvalidWorldException.java new file mode 100644 index 0000000000..e5b87464ce --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/api/InvalidWorldException.java @@ -0,0 +1,20 @@ +package com.earth2me.essentials.api; + +import static com.earth2me.essentials.I18n.tl; + + +public class InvalidWorldException extends Exception +{ + private final String world; + + public InvalidWorldException(final String world) + { + super(tl("invalidWorld")); + this.world = world; + } + + public String getWorld() + { + return this.world; + } +} diff --git a/Essentials/src/com/earth2me/essentials/api/NoLoanPermittedException.java b/Essentials/src/com/earth2me/essentials/api/NoLoanPermittedException.java new file mode 100644 index 0000000000..234369f3d8 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/api/NoLoanPermittedException.java @@ -0,0 +1,7 @@ +package com.earth2me.essentials.api; + + +public class NoLoanPermittedException extends net.ess3.api.NoLoanPermittedException +{ + +} diff --git a/Essentials/src/com/earth2me/essentials/api/UserDoesNotExistException.java b/Essentials/src/com/earth2me/essentials/api/UserDoesNotExistException.java new file mode 100644 index 0000000000..fd51c04e88 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/api/UserDoesNotExistException.java @@ -0,0 +1,12 @@ +package com.earth2me.essentials.api; + +import static com.earth2me.essentials.I18n.tl; + + +public class UserDoesNotExistException extends Exception +{ + public UserDoesNotExistException(String name) + { + super(tl("userDoesNotExist", name)); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandafk.java b/Essentials/src/com/earth2me/essentials/commands/Commandafk.java new file mode 100644 index 0000000000..0052677b50 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandafk.java @@ -0,0 +1,71 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Server; + + +public class Commandafk extends EssentialsCommand +{ + public Commandafk() + { + super("afk"); + } + + @Override + public void run(Server server, User user, String commandLabel, String[] args) throws Exception + { + if (args.length > 0 && user.isAuthorized("essentials.afk.others")) + { + User afkUser = getPlayer(server, user, args, 0); + toggleAfk(afkUser); + } + else + { + toggleAfk(user); + } + } + + @Override + public void run(Server server, CommandSource sender, String commandLabel, String[] args) throws Exception + { + if (args.length > 0) + { + User afkUser = getPlayer(server, args, 0, true, false); + toggleAfk(afkUser); + } + else + { + throw new NotEnoughArgumentsException(); + } + } + + private void toggleAfk(User user) + { + user.setDisplayNick(); + String msg = ""; + if (!user.toggleAfk()) + { + //user.sendMessage(_("markedAsNotAway")); + if (!user.isHidden()) + { + msg = tl("userIsNotAway", user.getDisplayName()); + } + user.updateActivity(false); + } + else + { + //user.sendMessage(_("markedAsAway")); + if (!user.isHidden()) + { + msg = tl("userIsAway", user.getDisplayName()); + } + } + if (!msg.isEmpty()) + { + ess.broadcastMessage(user, msg); + } + } +} + diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandantioch.java b/Essentials/src/com/earth2me/essentials/commands/Commandantioch.java new file mode 100644 index 0000000000..c9b7e54ed5 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandantioch.java @@ -0,0 +1,29 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.LocationUtil; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.entity.TNTPrimed; + +// This command has a in theme message that only shows if you supply a parameter #EasterEgg +public class Commandantioch extends EssentialsCommand +{ + public Commandantioch() + { + super("antioch"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length > 0) + { + ess.broadcastMessage(user, "...lobbest thou thy Holy Hand Grenade of Antioch towards thy foe,"); + ess.broadcastMessage(user, "who being naughty in My sight, shall snuff it."); + } + + final Location loc = LocationUtil.getTarget(user.getBase()); + loc.getWorld().spawn(loc, TNTPrimed.class); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandback.java b/Essentials/src/com/earth2me/essentials/commands/Commandback.java new file mode 100644 index 0000000000..5db82d0484 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandback.java @@ -0,0 +1,33 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import org.bukkit.Server; + + +public class Commandback extends EssentialsCommand +{ + public Commandback() + { + super("back"); + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (user.getLastLocation() == null) + { + throw new Exception(tl("noLocationFound")); + } + if (user.getWorld() != user.getLastLocation().getWorld() && ess.getSettings().isWorldTeleportPermissions() + && !user.isAuthorized("essentials.worlds." + user.getLastLocation().getWorld().getName())) + { + throw new Exception(tl("noPerm", "essentials.worlds." + user.getLastLocation().getWorld().getName())); + } + final Trade charge = new Trade(this.getName(), ess); + charge.isAffordableFor(user); + user.getTeleport().back(charge); + throw new NoChargeException(); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandbackup.java b/Essentials/src/com/earth2me/essentials/commands/Commandbackup.java new file mode 100644 index 0000000000..a384cb6bd7 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandbackup.java @@ -0,0 +1,32 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.Backup; +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import org.bukkit.Server; + + +public class Commandbackup extends EssentialsCommand +{ + public Commandbackup() + { + super("backup"); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + final Backup backup = ess.getBackup(); + if (backup == null) + { + throw new Exception(tl("backupDisabled")); + } + final String command = ess.getSettings().getBackupCommand(); + if (command == null || "".equals(command) || "save-all".equalsIgnoreCase(command)) + { + throw new Exception(tl("backupDisabled")); + } + backup.run(); + sender.sendMessage(tl("backupStarted")); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandbalance.java b/Essentials/src/com/earth2me/essentials/commands/Commandbalance.java new file mode 100644 index 0000000000..5015c3574d --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandbalance.java @@ -0,0 +1,49 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.NumberUtil; +import java.math.BigDecimal; +import org.bukkit.Server; + + +public class Commandbalance extends EssentialsCommand +{ + public Commandbalance() + { + super("balance"); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + User target = getPlayer(server, args, 0, true, true); + sender.sendMessage(tl("balanceOther", target.isHidden() ? target.getName() : target.getDisplayName(), NumberUtil.displayCurrency(target.getMoney(), ess))); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length == 1 && user.isAuthorized("essentials.balance.others")) + { + final User target = getPlayer(server, args, 0, true, true); + final BigDecimal bal = target.getMoney(); + user.sendMessage(tl("balanceOther", target.isHidden() ? target.getName() : target.getDisplayName(), NumberUtil.displayCurrency(bal, ess))); + } + else if (args.length < 2) + { + final BigDecimal bal = user.getMoney(); + user.sendMessage(tl("balance", NumberUtil.displayCurrency(bal, ess))); + } + else + { + throw new NotEnoughArgumentsException(); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandbalancetop.java b/Essentials/src/com/earth2me/essentials/commands/Commandbalancetop.java new file mode 100644 index 0000000000..41f78ad111 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandbalancetop.java @@ -0,0 +1,199 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.textreader.SimpleTextInput; +import com.earth2me.essentials.textreader.TextPager; +import com.earth2me.essentials.utils.NumberUtil; +import java.math.BigDecimal; +import java.text.DateFormat; +import java.util.*; +import java.util.Map.Entry; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import org.bukkit.Server; + + +public class Commandbalancetop extends EssentialsCommand +{ + public Commandbalancetop() + { + super("balancetop"); + } + private static final int CACHETIME = 2 * 60 * 1000; + public static final int MINUSERS = 50; + private static final SimpleTextInput cache = new SimpleTextInput(); + private static long cacheage = 0; + private static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + int page = 0; + boolean force = false; + if (args.length > 0) + { + try + { + page = Integer.parseInt(args[0]); + } + catch (NumberFormatException ex) + { + if (args[0].equalsIgnoreCase("force") + && (!sender.isPlayer() || ess.getUser(sender.getPlayer()).isAuthorized("essentials.balancetop.force"))) + { + force = true; + } + } + } + + if (!force && lock.readLock().tryLock()) + { + try + { + if (cacheage > System.currentTimeMillis() - CACHETIME) + { + outputCache(sender, commandLabel, page); + return; + } + if (ess.getUserMap().getUniqueUsers() > MINUSERS) + { + sender.sendMessage(tl("orderBalances", ess.getUserMap().getUniqueUsers())); + } + } + finally + { + lock.readLock().unlock(); + } + ess.runTaskAsynchronously(new Viewer(sender, commandLabel, page, force)); + } + else + { + if (ess.getUserMap().getUniqueUsers() > MINUSERS) + { + sender.sendMessage(tl("orderBalances", ess.getUserMap().getUniqueUsers())); + } + ess.runTaskAsynchronously(new Viewer(sender, commandLabel, page, force)); + } + + } + + private static void outputCache(final CommandSource sender, String command, int page) + { + final Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(cacheage); + final DateFormat format = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); + sender.sendMessage(tl("balanceTop", format.format(cal.getTime()))); + new TextPager(cache).showPage(Integer.toString(page), null, "balancetop", sender); + } + + + private class Calculator implements Runnable + { + private final transient Viewer viewer; + private final boolean force; + + public Calculator(final Viewer viewer, final boolean force) + { + this.viewer = viewer; + this.force = force; + } + + @Override + public void run() + { + lock.writeLock().lock(); + try + { + if (force || cacheage <= System.currentTimeMillis() - CACHETIME) + { + cache.getLines().clear(); + final Map balances = new HashMap(); + BigDecimal totalMoney = BigDecimal.ZERO; + if (ess.getSettings().isEcoDisabled()) + { + if (ess.getSettings().isDebug()) + { + ess.getLogger().info("Internal economy functions disabled, aborting baltop."); + } + } + else + { + for (UUID u : ess.getUserMap().getAllUniqueUsers()) + { + final User user = ess.getUserMap().getUser(u); + if (user != null) + { + final BigDecimal userMoney = user.getMoney(); + user.updateMoneyCache(userMoney); + totalMoney = totalMoney.add(userMoney); + final String name = user.isHidden() ? user.getName() : user.getDisplayName(); + balances.put(name, userMoney); + } + } + } + + final List> sortedEntries = new ArrayList>(balances.entrySet()); + Collections.sort(sortedEntries, new Comparator>() + { + @Override + public int compare(final Entry entry1, final Entry entry2) + { + return entry2.getValue().compareTo(entry1.getValue()); + } + }); + + cache.getLines().add(tl("serverTotal", NumberUtil.displayCurrency(totalMoney, ess))); + int pos = 1; + for (Map.Entry entry : sortedEntries) + { + cache.getLines().add(pos + ". " + entry.getKey() + ", " + NumberUtil.displayCurrency(entry.getValue(), ess)); + pos++; + } + cacheage = System.currentTimeMillis(); + } + } + finally + { + lock.writeLock().unlock(); + } + ess.runTaskAsynchronously(viewer); + } + } + + + private class Viewer implements Runnable + { + private final transient CommandSource sender; + private final transient int page; + private final transient boolean force; + private final transient String commandLabel; + + public Viewer(final CommandSource sender, final String commandLabel, final int page, final boolean force) + { + this.sender = sender; + this.page = page; + this.force = force; + this.commandLabel = commandLabel; + } + + @Override + public void run() + { + lock.readLock().lock(); + try + { + if (!force && cacheage > System.currentTimeMillis() - CACHETIME) + { + outputCache(sender, commandLabel, page); + return; + } + } + finally + { + lock.readLock().unlock(); + } + ess.runTaskAsynchronously(new Calculator(new Viewer(sender, commandLabel, page, false), force)); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandban.java b/Essentials/src/com/earth2me/essentials/commands/Commandban.java new file mode 100644 index 0000000000..7a594c8d20 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandban.java @@ -0,0 +1,80 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import com.earth2me.essentials.Console; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.OfflinePlayer; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.FormatUtil; +import java.util.logging.Level; +import org.bukkit.BanList; +import org.bukkit.Bukkit; +import org.bukkit.Server; + + +public class Commandban extends EssentialsCommand +{ + public Commandban() + { + super("ban"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + boolean nomatch = false; + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + User user; + try + { + user = getPlayer(server, args, 0, true, true); + } + catch (PlayerNotFoundException e) + { + nomatch = true; + user = ess.getUser(new OfflinePlayer(args[0], ess.getServer())); + } + if (!user.getBase().isOnline()) + { + if (sender.isPlayer() && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.ban.offline")) + { + throw new Exception(tl("banExemptOffline")); + } + } + else + { + if (user.isAuthorized("essentials.ban.exempt") && sender.isPlayer()) + { + throw new Exception(tl("banExempt")); + } + } + + final String senderName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.NAME; + String banReason; + if (args.length > 1) + { + banReason = FormatUtil.replaceFormat(getFinalArg(args, 1).replace("\\n", "\n").replace("|", "\n")); + } + else + { + banReason = tl("defaultBanReason"); + } + + ess.getServer().getBanList(BanList.Type.NAME).addBan(user.getName(), banReason, null, senderName); + + String banDisplay = tl("banFormat", banReason, senderName); + + user.getBase().kickPlayer(banDisplay); + server.getLogger().log(Level.INFO, tl("playerBanned", senderName, user.getName(), banDisplay)); + + if (nomatch) + { + sender.sendMessage(tl("userUnknown", user.getName())); + } + + ess.broadcastMessage("essentials.ban.notify", tl("playerBanned", senderName, user.getName(), banReason)); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandbanip.java b/Essentials/src/com/earth2me/essentials/commands/Commandbanip.java new file mode 100644 index 0000000000..f538ba4ae5 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandbanip.java @@ -0,0 +1,70 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import com.earth2me.essentials.Console; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.FormatUtil; +import java.util.logging.Level; +import org.bukkit.BanList; +import org.bukkit.Bukkit; +import org.bukkit.Server; + + +//TODO: Add kick to online players matching ip ban. +public class Commandbanip extends EssentialsCommand +{ + public Commandbanip() + { + super("banip"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + final String senderName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.NAME; + + String ipAddress; + if (FormatUtil.validIP(args[0])) + { + ipAddress = args[0]; + } + else + { + try + { + User player = getPlayer(server, args, 0, true, true); + ipAddress = player.getLastLoginAddress(); + } + catch (PlayerNotFoundException ex) + { + ipAddress = args[0]; + } + } + + if (ipAddress.isEmpty()) + { + throw new PlayerNotFoundException(); + } + + String banReason; + if (args.length > 1) + { + banReason = FormatUtil.replaceFormat(getFinalArg(args, 1).replace("\\n", "\n").replace("|", "\n")); + } + else + { + banReason = tl("defaultBanReason"); + } + + ess.getServer().getBanList(BanList.Type.IP).addBan(ipAddress, banReason, null, senderName); + server.getLogger().log(Level.INFO, tl("playerBanIpAddress", senderName, ipAddress, banReason)); + + ess.broadcastMessage("essentials.ban.notify", tl("playerBanIpAddress", senderName, ipAddress, banReason)); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandbigtree.java b/Essentials/src/com/earth2me/essentials/commands/Commandbigtree.java new file mode 100644 index 0000000000..ed5b7957e1 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandbigtree.java @@ -0,0 +1,51 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.LocationUtil; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.TreeType; + + +public class Commandbigtree extends EssentialsCommand +{ + public Commandbigtree() + { + super("bigtree"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + TreeType tree; + if (args.length > 0 && args[0].equalsIgnoreCase("redwood")) + { + tree = TreeType.TALL_REDWOOD; + } + else if (args.length > 0 && args[0].equalsIgnoreCase("tree")) + { + tree = TreeType.BIG_TREE; + } + else if (args.length > 0 && args[0].equalsIgnoreCase("jungle")) + { + tree = TreeType.JUNGLE; + } + else + { + throw new NotEnoughArgumentsException(); + } + + final Location loc = LocationUtil.getTarget(user.getBase()); + final Location safeLocation = LocationUtil.getSafeDestination(loc); + final boolean success = user.getWorld().generateTree(safeLocation, tree); + if (success) + { + user.sendMessage(tl("bigTreeSuccess")); + } + else + { + throw new Exception(tl("bigTreeFailure")); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandbook.java b/Essentials/src/com/earth2me/essentials/commands/Commandbook.java new file mode 100644 index 0000000000..9b602c357a --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandbook.java @@ -0,0 +1,92 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BookMeta; + + +public class Commandbook extends EssentialsCommand +{ + public Commandbook() + { + super("book"); + } + + //TODO: Translate this + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + final ItemStack item = user.getBase().getItemInHand(); + final String player = user.getName(); + if (item.getType() == Material.WRITTEN_BOOK) + { + BookMeta bmeta = (BookMeta)item.getItemMeta(); + + if (args.length > 1 && args[0].equalsIgnoreCase("author")) + { + if (user.isAuthorized("essentials.book.author") && (isAuthor(bmeta, player) || user.isAuthorized("essentials.book.others"))) + { + bmeta.setAuthor(args[1]); + item.setItemMeta(bmeta); + user.sendMessage(tl("bookAuthorSet", getFinalArg(args, 1))); + } + else + { + throw new Exception(tl("denyChangeAuthor")); + } + } + else if (args.length > 1 && args[0].equalsIgnoreCase("title")) + { + if (user.isAuthorized("essentials.book.title") && (isAuthor(bmeta, player) || user.isAuthorized("essentials.book.others"))) + { + bmeta.setTitle(args[1]); + item.setItemMeta(bmeta); + user.sendMessage(tl("bookTitleSet", getFinalArg(args, 1))); + } + else + { + throw new Exception(tl("denyChangeTitle")); + } + } + else + { + if (isAuthor(bmeta, player) || user.isAuthorized("essentials.book.others")) + { + ItemStack newItem = new ItemStack(Material.BOOK_AND_QUILL, item.getAmount()); + newItem.setItemMeta(bmeta); + user.getBase().setItemInHand(newItem); + user.sendMessage(tl("editBookContents")); + } + else + { + throw new Exception(tl("denyBookEdit")); + } + } + } + else if (item.getType() == Material.BOOK_AND_QUILL) + { + BookMeta bmeta = (BookMeta)item.getItemMeta(); + if (!user.isAuthorized("essentials.book.author")) + { + bmeta.setAuthor(player); + } + ItemStack newItem = new ItemStack(Material.WRITTEN_BOOK, item.getAmount()); + newItem.setItemMeta(bmeta); + user.getBase().setItemInHand(newItem); + user.sendMessage(tl("bookLocked")); + } + else + { + throw new Exception(tl("holdBook")); + } + } + + private boolean isAuthor(BookMeta bmeta, String player) + { + String author = bmeta.getAuthor(); + return author != null && author.equalsIgnoreCase(player); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandbreak.java b/Essentials/src/com/earth2me/essentials/commands/Commandbreak.java new file mode 100644 index 0000000000..f4b4a67647 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandbreak.java @@ -0,0 +1,48 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.block.Block; +import org.bukkit.event.block.BlockBreakEvent; + + +public class Commandbreak extends EssentialsCommand +{ + public Commandbreak() + { + super("break"); + } + + //TODO: Switch to use util class + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + final Block block = user.getBase().getTargetBlock(null, 20); + if (block == null) + { + throw new NoChargeException(); + } + if (block.getType() == Material.AIR) + { + throw new NoChargeException(); + } + if (block.getType() == Material.BEDROCK && !user.isAuthorized("essentials.break.bedrock")) + { + throw new Exception(tl("noBreakBedrock")); + } + //final List list = (List)block.getDrops(); + //final BlockBreakEvent event = new BlockBreakEvent(block, user.getBase(), list); + final BlockBreakEvent event = new BlockBreakEvent(block, user.getBase()); + server.getPluginManager().callEvent(event); + if (event.isCancelled()) + { + throw new NoChargeException(); + } + else + { + block.setType(Material.AIR); + } + } +} \ No newline at end of file diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandbroadcast.java b/Essentials/src/com/earth2me/essentials/commands/Commandbroadcast.java new file mode 100644 index 0000000000..2b692b78bb --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandbroadcast.java @@ -0,0 +1,38 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.FormatUtil; +import org.bukkit.Server; + + +public class Commandbroadcast extends EssentialsCommand +{ + public Commandbroadcast() + { + super("broadcast"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + sendBroadcast(user.getDisplayName(), args); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + sendBroadcast(sender.getSender().getName(), args); + } + + private void sendBroadcast(final String name, final String[] args) throws NotEnoughArgumentsException + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + ess.broadcastMessage(tl("broadcast", FormatUtil.replaceFormat(getFinalArg(args, 0)).replace("\\n", "\n"), name)); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandburn.java b/Essentials/src/com/earth2me/essentials/commands/Commandburn.java new file mode 100644 index 0000000000..e9665a7453 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandburn.java @@ -0,0 +1,33 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Server; + + +public class Commandburn extends EssentialsCommand +{ + public Commandburn() + { + super("burn"); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 2) + { + throw new NotEnoughArgumentsException(); + } + + if (args[0].trim().length() < 2) + { + throw new NotEnoughArgumentsException(); + } + + User user = getPlayer(server, sender, args, 0); + user.getBase().setFireTicks(Integer.parseInt(args[1]) * 20); + sender.sendMessage(tl("burnMsg", user.getDisplayName(), Integer.parseInt(args[1]))); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandclearinventory.java b/Essentials/src/com/earth2me/essentials/commands/Commandclearinventory.java new file mode 100644 index 0000000000..311cb3e13c --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandclearinventory.java @@ -0,0 +1,161 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.NumberUtil; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Locale; +import org.bukkit.Server; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + + +public class Commandclearinventory extends EssentialsCommand +{ + public Commandclearinventory() + { + super("clearinventory"); + } + private static final int BASE_AMOUNT = 100000; + private static final int EXTENDED_CAP = 8; + + @Override + public void run(Server server, User user, String commandLabel, String[] args) throws Exception + { + parseCommand(server, user.getSource(), args, user.isAuthorized("essentials.clearinventory.others"), user.isAuthorized("essentials.clearinventory.all") || user.isAuthorized("essentials.clearinventory.multiple")); + } + + @Override + protected void run(Server server, CommandSource sender, String commandLabel, String[] args) throws Exception + { + parseCommand(server, sender, args, true, true); + } + + private void parseCommand(Server server, CommandSource sender, String[] args, boolean allowOthers, boolean allowAll) throws Exception + { + Collection players = new ArrayList(); + int offset = 0; + + if (sender.isPlayer()) + { + players.add(sender.getPlayer()); + } + + if (allowAll && args.length > 0 && args[0].contentEquals("*")) + { + sender.sendMessage(tl("inventoryClearingFromAll")); + offset = 1; + players = ess.getOnlinePlayers(); + } + else if (allowOthers && args.length > 0 && args[0].trim().length() > 2) + { + offset = 1; + players = server.matchPlayer(args[0].trim()); + } + + if (players.size() < 1) + { + throw new PlayerNotFoundException(); + } + for (Player player : players) + { + clearHandler(sender, player, args, offset, players.size() < EXTENDED_CAP); + } + } + + protected void clearHandler(CommandSource sender, Player player, String[] args, int offset, boolean showExtended) throws Exception + { + short data = -1; + int type = -1; + int amount = -1; + + if (args.length > (offset + 1) && NumberUtil.isInt(args[(offset + 1)])) + { + amount = Integer.parseInt(args[(offset + 1)]); + } + if (args.length > offset) + { + if (args[offset].equalsIgnoreCase("**")) + { + type = -2; + } + else if (!args[offset].equalsIgnoreCase("*")) + { + final String[] split = args[offset].split(":"); + final ItemStack item = ess.getItemDb().get(split[0]); + type = item.getTypeId(); + + if (split.length > 1 && NumberUtil.isInt(split[1])) + { + data = Short.parseShort(split[1]); + } + else + { + data = item.getDurability(); + } + } + } + + if (type == -1) // type -1 represents wildcard or all items + { + if (showExtended) + { + sender.sendMessage(tl("inventoryClearingAllItems", player.getDisplayName())); + } + player.getInventory().clear(); + } + else if (type == -2) // type -2 represents double wildcard or all items and armor + { + if (showExtended) + { + sender.sendMessage(tl("inventoryClearingAllArmor", player.getDisplayName())); + } + player.getInventory().clear(); + player.getInventory().setArmorContents(null); + } + else + { + if (data == -1) // data -1 means that all subtypes will be cleared + { + ItemStack stack = new ItemStack(type); + if (showExtended) + { + sender.sendMessage(tl("inventoryClearingAllStack", stack.getType().toString().toLowerCase(Locale.ENGLISH), player.getDisplayName())); + } + player.getInventory().clear(type, data); + } + else if (amount == -1) // amount -1 means all items will be cleared + { + ItemStack stack = new ItemStack(type, BASE_AMOUNT, data); + ItemStack removedStack = player.getInventory().removeItem(stack).get(0); + final int removedAmount = (BASE_AMOUNT - removedStack.getAmount()); + if (removedAmount > 0 || showExtended) + { + sender.sendMessage(tl("inventoryClearingStack", removedAmount, stack.getType().toString().toLowerCase(Locale.ENGLISH), player.getDisplayName())); + } + } + else + { + if (amount < 0) + { + amount = 1; + } + ItemStack stack = new ItemStack(type, amount, data); + if (player.getInventory().containsAtLeast(stack, amount)) + { + sender.sendMessage(tl("inventoryClearingStack", amount, stack.getType().toString().toLowerCase(Locale.ENGLISH), player.getDisplayName())); + player.getInventory().removeItem(stack); + } + else + { + if (showExtended) + { + sender.sendMessage(tl("inventoryClearFail", player.getDisplayName(), amount, stack.getType().toString().toLowerCase(Locale.ENGLISH))); + } + } + } + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandcompass.java b/Essentials/src/com/earth2me/essentials/commands/Commandcompass.java new file mode 100644 index 0000000000..53dce03d19 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandcompass.java @@ -0,0 +1,58 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Server; + + +public class Commandcompass extends EssentialsCommand +{ + public Commandcompass() + { + super("compass"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + final int bearing = (int)(user.getLocation().getYaw() + 180 + 360) % 360; + String dir; + if (bearing < 23) + { + dir = "N"; + } + else if (bearing < 68) + { + dir = "NE"; + } + else if (bearing < 113) + { + dir = "E"; + } + else if (bearing < 158) + { + dir = "SE"; + } + else if (bearing < 203) + { + dir = "S"; + } + else if (bearing < 248) + { + dir = "SW"; + } + else if (bearing < 293) + { + dir = "W"; + } + else if (bearing < 338) + { + dir = "NW"; + } + else + { + dir = "N"; + } + user.sendMessage(tl("compassBearing", dir, bearing)); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandcondense.java b/Essentials/src/com/earth2me/essentials/commands/Commandcondense.java new file mode 100644 index 0000000000..fd04088905 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandcondense.java @@ -0,0 +1,221 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import java.util.*; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.Recipe; +import org.bukkit.inventory.ShapedRecipe; +import org.bukkit.inventory.ShapelessRecipe; +import com.earth2me.essentials.ChargeException; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.Trade.OverflowType; +import com.earth2me.essentials.User; +import net.ess3.api.MaxMoneyException; + + +public class Commandcondense extends EssentialsCommand +{ + public Commandcondense() + { + super("condense"); + } + private Map condenseList = new HashMap(); + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + List is = new ArrayList(); + + boolean validateReverse = false; + if (args.length > 0) + { + is = ess.getItemDb().getMatching(user, args); + } + else + { + for (ItemStack stack : user.getBase().getInventory().getContents()) + { + if (stack == null || stack.getType() == Material.AIR) + { + continue; + } + is.add(stack); + } + validateReverse = true; + } + + boolean didConvert = false; + for (final ItemStack itemStack : is) + { + if (condenseStack(user, itemStack, validateReverse)) + { + didConvert = true; + } + } + user.getBase().updateInventory(); + + if (didConvert) + { + user.sendMessage(tl("itemsConverted")); + } + else + { + user.sendMessage(tl("itemsNotConverted")); + throw new NoChargeException(); + } + } + + private boolean condenseStack(final User user, final ItemStack stack, final boolean validateReverse) throws ChargeException, MaxMoneyException + { + final SimpleRecipe condenseType = getCondenseType(stack); + if (condenseType != null) + { + final ItemStack input = condenseType.getInput(); + final ItemStack result = condenseType.getResult(); + + if (validateReverse) + { + boolean pass = false; + for (Recipe revRecipe : ess.getServer().getRecipesFor(input)) + { + if (getStackOnRecipeMatch(revRecipe, result) != null) + { + pass = true; + break; + } + } + if (!pass) + { + return false; + } + } + + int amount = 0; + + for (final ItemStack contents : user.getBase().getInventory().getContents()) + { + if (contents != null && contents.isSimilar(stack)) + { + amount += contents.getAmount(); + } + } + + int output = ((amount / input.getAmount()) * result.getAmount()); + amount -= amount % input.getAmount(); + + if (amount > 0) + { + input.setAmount(amount); + result.setAmount(output); + final Trade remove = new Trade(input, ess); + final Trade add = new Trade(result, ess); + remove.charge(user); + add.pay(user, OverflowType.DROP); + return true; + } + } + return false; + } + + private SimpleRecipe getCondenseType(final ItemStack stack) + { + if (condenseList.containsKey(stack)) + { + return condenseList.get(stack); + } + + final Iterator intr = ess.getServer().recipeIterator(); + while (intr.hasNext()) + { + final Recipe recipe = intr.next(); + final Collection recipeItems = getStackOnRecipeMatch(recipe, stack); + + if (recipeItems != null && (recipeItems.size() == 4 || recipeItems.size() == 9) + && (recipeItems.size() > recipe.getResult().getAmount())) + { + final ItemStack input = stack.clone(); + input.setAmount(recipeItems.size()); + final SimpleRecipe newRecipe = new SimpleRecipe(recipe.getResult(), input); + condenseList.put(stack, newRecipe); + return newRecipe; + } + } + + condenseList.put(stack, null); + return null; + } + + private Collection getStackOnRecipeMatch(final Recipe recipe, final ItemStack stack) + { + final Collection inputList; + + if (recipe instanceof ShapedRecipe) + { + ShapedRecipe sRecipe = (ShapedRecipe)recipe; + inputList = sRecipe.getIngredientMap().values(); + } + else if (recipe instanceof ShapelessRecipe) + { + ShapelessRecipe slRecipe = (ShapelessRecipe)recipe; + inputList = slRecipe.getIngredientList(); + } + else + { + return null; + } + + boolean match = true; + Iterator iter = inputList.iterator(); + while (iter.hasNext()) + { + ItemStack inputSlot = iter.next(); + if (inputSlot == null) + { + iter.remove(); + continue; + } + + if (inputSlot.getDurability() == Short.MAX_VALUE) + { + inputSlot.setDurability((short)0); + } + if (!inputSlot.isSimilar(stack)) + { + match = false; + } + } + + if (match) + { + return inputList; + } + return null; + } + + + private class SimpleRecipe implements Recipe + { + private ItemStack result; + private ItemStack input; + + private SimpleRecipe(ItemStack result, ItemStack input) + { + this.result = result; + this.input = input; + } + + @Override + public ItemStack getResult() + { + return result.clone(); + } + + public ItemStack getInput() + { + return input.clone(); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandcustomtext.java b/Essentials/src/com/earth2me/essentials/commands/Commandcustomtext.java new file mode 100644 index 0000000000..8f08e3ce00 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandcustomtext.java @@ -0,0 +1,45 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import com.earth2me.essentials.textreader.IText; +import com.earth2me.essentials.textreader.KeywordReplacer; +import com.earth2me.essentials.textreader.TextInput; +import com.earth2me.essentials.textreader.TextPager; +import com.earth2me.essentials.utils.NumberUtil; +import org.bukkit.Server; + + +public class Commandcustomtext extends EssentialsCommand +{ + public Commandcustomtext() + { + super("customtext"); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (sender.isPlayer()) + { + ess.getUser(sender.getPlayer()).setDisplayNick(); + } + + final IText input = new TextInput(sender, "custom", true, ess); + final IText output = new KeywordReplacer(input, sender, ess); + final TextPager pager = new TextPager(output); + String chapter = commandLabel; + String page; + + if (commandLabel.equalsIgnoreCase("customtext") && args.length > 0 && !NumberUtil.isInt(commandLabel)) + { + chapter = args[0]; + page = args.length > 1 ? args[1] : null; + } + else + { + page = args.length > 0 ? args[0] : null; + } + + pager.showPage(chapter, page, null, sender); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commanddelhome.java b/Essentials/src/com/earth2me/essentials/commands/Commanddelhome.java new file mode 100644 index 0000000000..8459700a51 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commanddelhome.java @@ -0,0 +1,62 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import java.util.Locale; +import org.bukkit.Server; + + +public class Commanddelhome extends EssentialsCommand +{ + public Commanddelhome() + { + super("delhome"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + User user = ess.getUser(sender.getPlayer()); + String name; + String[] expandedArg; + + //Allowing both formats /sethome khobbits house | /sethome khobbits:house + final String[] nameParts = args[0].split(":"); + if (nameParts[0].length() != args[0].length()) + { + expandedArg = nameParts; + } + else + { + expandedArg = args; + } + + if (expandedArg.length > 1 && (user == null || user.isAuthorized("essentials.delhome.others"))) + { + user = getPlayer(server, expandedArg, 0, true, true); + name = expandedArg[1]; + } + else if (user == null) + { + throw new NotEnoughArgumentsException(); + } + else + { + name = expandedArg[0]; + } + + if (name.equalsIgnoreCase("bed")) + { + throw new Exception(tl("invalidHomeName")); + } + + user.delHome(name.toLowerCase(Locale.ENGLISH)); + sender.sendMessage(tl("deleteHome", name)); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commanddeljail.java b/Essentials/src/com/earth2me/essentials/commands/Commanddeljail.java new file mode 100644 index 0000000000..7b5937a09e --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commanddeljail.java @@ -0,0 +1,26 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import org.bukkit.Server; + + +public class Commanddeljail extends EssentialsCommand +{ + public Commanddeljail() + { + super("deljail"); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + ess.getJails().removeJail(args[0]); + sender.sendMessage(tl("deleteJail", args[0])); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commanddelwarp.java b/Essentials/src/com/earth2me/essentials/commands/Commanddelwarp.java new file mode 100644 index 0000000000..4fbf5f91c4 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commanddelwarp.java @@ -0,0 +1,26 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import org.bukkit.Server; + + +public class Commanddelwarp extends EssentialsCommand +{ + public Commanddelwarp() + { + super("delwarp"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + ess.getWarps().removeWarp(args[0]); + sender.sendMessage(tl("deleteWarp", args[0])); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commanddepth.java b/Essentials/src/com/earth2me/essentials/commands/Commanddepth.java new file mode 100644 index 0000000000..b7d56b6a1c --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commanddepth.java @@ -0,0 +1,32 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Server; + + +public class Commanddepth extends EssentialsCommand +{ + public Commanddepth() + { + super("depth"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + final int depth = user.getLocation().getBlockY() - 63; + if (depth > 0) + { + user.sendMessage(tl("depthAboveSea", depth)); + } + else if (depth < 0) + { + user.sendMessage(tl("depthBelowSea", (-depth))); + } + else + { + user.sendMessage(tl("depth")); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandeco.java b/Essentials/src/com/earth2me/essentials/commands/Commandeco.java new file mode 100644 index 0000000000..f589dcfed2 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandeco.java @@ -0,0 +1,124 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.ChargeException; +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.NumberUtil; +import java.math.BigDecimal; +import java.util.Locale; +import net.ess3.api.MaxMoneyException; +import org.bukkit.Server; + + +public class Commandeco extends EssentialsLoopCommand +{ + Commandeco.EcoCommands cmd; + BigDecimal amount; + + public Commandeco() + { + super("eco"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 2) + { + throw new NotEnoughArgumentsException(); + } + + BigDecimal startingBalance = ess.getSettings().getStartingBalance(); + + try + { + cmd = Commandeco.EcoCommands.valueOf(args[0].toUpperCase(Locale.ENGLISH)); + amount = (cmd == Commandeco.EcoCommands.RESET) ? startingBalance : new BigDecimal(args[2].replaceAll("[^0-9\\.]", "")); + } + catch (Exception ex) + { + throw new NotEnoughArgumentsException(ex); + } + + loopOfflinePlayers(server, sender, false, true, args[1], args); + + if (cmd == Commandeco.EcoCommands.RESET || cmd == Commandeco.EcoCommands.SET) + { + if (args[1].contentEquals("**")) + { + server.broadcastMessage(tl("resetBalAll", NumberUtil.displayCurrency(amount, ess))); + } + else if (args[1].contentEquals("*")) + { + server.broadcastMessage(tl("resetBal", NumberUtil.displayCurrency(amount, ess))); + } + } + } + + @Override + protected void updatePlayer(final Server server, final CommandSource sender, final User player, final String[] args) throws NotEnoughArgumentsException, ChargeException, MaxMoneyException + { + switch (cmd) + { + case GIVE: + player.giveMoney(amount, sender); + break; + + case TAKE: + take(amount, player, sender); + break; + + case RESET: + case SET: + set(amount, player, sender); + break; + } + } + + private void take(BigDecimal amount, final User player, final CommandSource sender) throws ChargeException + { + BigDecimal money = player.getMoney(); + BigDecimal minBalance = ess.getSettings().getMinMoney(); + if (money.subtract(amount).compareTo(minBalance) > 0) + { + player.takeMoney(amount, sender); + } + else if (sender == null) + { + try + { + player.setMoney(minBalance); + } + catch (MaxMoneyException ex) + { + // Take shouldn't be able to throw a max money exception + } + player.sendMessage(tl("takenFromAccount", NumberUtil.displayCurrency(player.getMoney(), ess))); + } + else + { + throw new ChargeException(tl("insufficientFunds")); + } + } + + private void set(BigDecimal amount, final User player, final CommandSource sender) throws MaxMoneyException + { + BigDecimal minBalance = ess.getSettings().getMinMoney(); + BigDecimal maxBalance = ess.getSettings().getMaxMoney(); + boolean underMinimum = (amount.compareTo(minBalance) < 0); + boolean aboveMax = (amount.compareTo(maxBalance) > 0); + player.setMoney(underMinimum ? minBalance : aboveMax ? maxBalance : amount); + player.sendMessage(tl("setBal", NumberUtil.displayCurrency(player.getMoney(), ess))); + if (sender != null) + { + sender.sendMessage(tl("setBalOthers", player.getDisplayName(), NumberUtil.displayCurrency(player.getMoney(), ess))); + } + } + + + private enum EcoCommands + { + GIVE, TAKE, SET, RESET + } +} \ No newline at end of file diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandenchant.java b/Essentials/src/com/earth2me/essentials/commands/Commandenchant.java new file mode 100644 index 0000000000..feb04e97b6 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandenchant.java @@ -0,0 +1,80 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.Enchantments; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.MetaItemStack; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.StringUtil; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; + + +public class Commandenchant extends EssentialsCommand +{ + public Commandenchant() + { + super("enchant"); + } + + //TODO: Implement charge costs: final Trade charge = new Trade("enchant-" + enchantmentName, ess); + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + final ItemStack stack = user.getBase().getItemInHand(); + if (stack == null || stack.getType() == Material.AIR) + { + throw new Exception(tl("nothingInHand")); + } + if (args.length == 0) + { + final Set enchantmentslist = new TreeSet(); + for (Map.Entry entry : Enchantments.entrySet()) + { + final String enchantmentName = entry.getValue().getName().toLowerCase(Locale.ENGLISH); + if (enchantmentslist.contains(enchantmentName) || (user.isAuthorized("essentials.enchantments." + enchantmentName) && entry.getValue().canEnchantItem(stack))) + { + enchantmentslist.add(entry.getKey()); + //enchantmentslist.add(enchantmentName); + } + } + throw new NotEnoughArgumentsException(tl("enchantments", StringUtil.joinList(enchantmentslist.toArray()))); + } + + int level = -1; + if (args.length > 1) + { + try + { + level = Integer.parseInt(args[1]); + } + catch (NumberFormatException ex) + { + level = -1; + } + } + + final boolean allowUnsafe = ess.getSettings().allowUnsafeEnchantments() && user.isAuthorized("essentials.enchantments.allowunsafe"); + + final MetaItemStack metaStack = new MetaItemStack(stack); + final Enchantment enchantment = metaStack.getEnchantment(user, args[0]); + metaStack.addEnchantment(user.getSource(), allowUnsafe, enchantment, level); + user.getBase().getInventory().setItemInHand(metaStack.getItemStack()); + + user.getBase().updateInventory(); + final String enchantmentName = enchantment.getName().toLowerCase(Locale.ENGLISH); + if (level == 0) + { + user.sendMessage(tl("enchantmentRemoved", enchantmentName.replace('_', ' '))); + } + else + { + user.sendMessage(tl("enchantmentApplied", enchantmentName.replace('_', ' '))); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandenderchest.java b/Essentials/src/com/earth2me/essentials/commands/Commandenderchest.java new file mode 100644 index 0000000000..94f27c42ed --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandenderchest.java @@ -0,0 +1,32 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.User; +import org.bukkit.Server; + + +public class Commandenderchest extends EssentialsCommand +{ + public Commandenderchest() + { + super("enderchest"); + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length > 0 && user.isAuthorized("essentials.enderchest.others")) + { + final User invUser = getPlayer(server, user, args, 0); + user.getBase().closeInventory(); + user.getBase().openInventory(invUser.getBase().getEnderChest()); + user.setEnderSee(true); + } + else + { + user.getBase().closeInventory(); + user.getBase().openInventory(user.getBase().getEnderChest()); + user.setEnderSee(false); + } + + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandessentials.java b/Essentials/src/com/earth2me/essentials/commands/Commandessentials.java new file mode 100644 index 0000000000..54f409b8e1 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandessentials.java @@ -0,0 +1,382 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import com.earth2me.essentials.EssentialsUpgrade; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.UserMap; +import com.earth2me.essentials.metrics.Metrics; +import com.earth2me.essentials.utils.DateUtil; +import com.earth2me.essentials.utils.NumberUtil; +import com.google.common.base.Charsets; +import java.io.IOException; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.UUID; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.Sound; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; + +// This command has 4 undocumented behaviours #EasterEgg +public class Commandessentials extends EssentialsCommand +{ + public Commandessentials() + { + super("essentials"); + } + private transient int taskid; + private final transient Map noteBlocks = new HashMap(); + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length == 0) + { + run_disabled(server, sender, commandLabel, args); + } + else if (args[0].equalsIgnoreCase("debug")) + { + run_debug(server, sender, commandLabel, args); + } + else if (args[0].equalsIgnoreCase("nya")) + { + run_nya(server, sender, commandLabel, args); + } + else if (args[0].equalsIgnoreCase("moo")) + { + run_moo(server, sender, commandLabel, args); + } + else if (args[0].equalsIgnoreCase("reset")) + { + run_reset(server, sender, commandLabel, args); + } + else if (args[0].equalsIgnoreCase("opt-out")) + { + run_optout(server, sender, commandLabel, args); + } + else if (args[0].equalsIgnoreCase("cleanup")) + { + run_cleanup(server, sender, commandLabel, args); + } + else if (args[0].equalsIgnoreCase("uuidconvert")) + { + run_uuidconvert(server, sender, commandLabel, args); + } + else if (args[0].equalsIgnoreCase("uuidtest")) + { + run_uuidtest(server, sender, commandLabel, args); + } + else + { + run_reload(server, sender, commandLabel, args); + } + } + + //If you do not supply an argument this command will list 'overridden' commands. + private void run_disabled(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + sender.sendMessage("/ "); + + final StringBuilder disabledCommands = new StringBuilder(); + for (Map.Entry entry : ess.getAlternativeCommandsHandler().disabledCommands().entrySet()) + { + if (disabledCommands.length() > 0) + { + disabledCommands.append(", "); + } + disabledCommands.append(entry.getKey()).append(" => ").append(entry.getValue()); + } + if (disabledCommands.length() > 0) + { + sender.sendMessage(tl("blockList")); + sender.sendMessage(disabledCommands.toString()); + } + } + + private void run_reset(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 2) + { + throw new Exception("/ reset "); + } + final User user = getPlayer(server, args, 1, true, true); + user.reset(); + sender.sendMessage("Reset Essentials userdata for player: " + user.getDisplayName()); + } + + private void run_debug(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + ess.getSettings().setDebug(!ess.getSettings().isDebug()); + sender.sendMessage("Essentials " + ess.getDescription().getVersion() + " debug mode " + (ess.getSettings().isDebug() ? "enabled" : "disabled")); + } + + private void run_reload(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + ess.reload(); + sender.sendMessage(tl("essentialsReload", ess.getDescription().getVersion())); + } + + private void run_nya(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + final Map noteMap = new HashMap(); + noteMap.put("1F#", 0.5f); + noteMap.put("1G", 0.53f); + noteMap.put("1G#", 0.56f); + noteMap.put("1A", 0.6f); + noteMap.put("1A#", 0.63f); + noteMap.put("1B", 0.67f); + noteMap.put("1C", 0.7f); + noteMap.put("1C#", 0.76f); + noteMap.put("1D", 0.8f); + noteMap.put("1D#", 0.84f); + noteMap.put("1E", 0.9f); + noteMap.put("1F", 0.94f); + noteMap.put("2F#", 1.0f); + noteMap.put("2G", 1.06f); + noteMap.put("2G#", 1.12f); + noteMap.put("2A", 1.18f); + noteMap.put("2A#", 1.26f); + noteMap.put("2B", 1.34f); + noteMap.put("2C", 1.42f); + noteMap.put("2C#", 1.5f); + noteMap.put("2D", 1.6f); + noteMap.put("2D#", 1.68f); + noteMap.put("2E", 1.78f); + noteMap.put("2F", 1.88f); + final String tuneStr = "1D#,1E,2F#,,2A#,1E,1D#,1E,2F#,2B,2D#,2E,2D#,2A#,2B,,2F#,,1D#,1E,2F#,2B,2C#,2A#,2B,2C#,2E,2D#,2E,2C#,,2F#,,2G#,,1D,1D#,,1C#,1D,1C#,1B,,1B,,1C#,,1D,,1D,1C#,1B,1C#,1D#,2F#,2G#,1D#,2F#,1C#,1D#,1B,1C#,1B,1D#,,2F#,,2G#,1D#,2F#,1C#,1D#,1B,1D,1D#,1D,1C#,1B,1C#,1D,,1B,1C#,1D#,2F#,1C#,1D,1C#,1B,1C#,,1B,,1C#,,2F#,,2G#,,1D,1D#,,1C#,1D,1C#,1B,,1B,,1C#,,1D,,1D,1C#,1B,1C#,1D#,2F#,2G#,1D#,2F#,1C#,1D#,1B,1C#,1B,1D#,,2F#,,2G#,1D#,2F#,1C#,1D#,1B,1D,1D#,1D,1C#,1B,1C#,1D,,1B,1C#,1D#,2F#,1C#,1D,1C#,1B,1C#,,1B,,1B,,1B,,1F#,1G#,1B,,1F#,1G#,1B,1C#,1D#,1B,1E,1D#,1E,2F#,1B,,1B,,1F#,1G#,1B,1E,1D#,1C#,1B,,,,1F#,1B,,1F#,1G#,1B,,1F#,1G#,1B,1B,1C#,1D#,1B,1F#,1G#,1F#,1B,,1B,1A#,1B,1F#,1G#,1B,1E,1D#,1E,2F#,1B,,1A#,,1B,,1F#,1G#,1B,,1F#,1G#,1B,1C#,1D#,1B,1E,1D#,1E,2F#,1B,,1B,,1F#,1G#,1B,1F#,1E,1D#,1C#,1B,,,,1F#,1B,,1F#,1G#,1B,,1F#,1G#,1B,1B,1C#,1D#,1B,1F#,1G#,1F#,1B,,1B,1A#,1B,1F#,1G#,1B,1E,1D#,1E,2F#,1B,,1A#,,1B,,1F#,1G#,1B,,1F#,1G#,1B,1C#,1D#,1B,1E,1D#,1E,2F#,1B,,1B,,1F#,1G#,1B,1F#,1E,1D#,1C#,1B,,,,1F#,1B,,1F#,1G#,1B,,1F#,1G#,1B,1B,1C#,1D#,1B,1F#,1G#,1F#,1B,,1B,1A#,1B,1F#,1G#,1B,1E,1D#,1E,2F#,1B,,1A#,,1B,,1F#,1G#,1B,,1F#,1G#,1B,1C#,1D#,1B,1E,1D#,1E,2F#,1B,,1B,,1F#,1G#,1B,1F#,1E,1D#,1C#,1B,,,,1F#,1B,,1F#,1G#,1B,,1F#,1G#,1B,1B,1C#,1D#,1B,1F#,1G#,1F#,1B,,1B,1A#,1B,1F#,1G#,1B,1E,1D#,1E,2F#,1B,,1A#,,1B,,1F#,1G#,1B,,1F#,1G#,1B,1C#,1D#,1B,1E,1D#,1E,2F#,1B,,1B,,1F#,1G#,1B,1F#,1E,1D#,1C#,1B,,,,1F#,1B,,1F#,1G#,1B,,1F#,1G#,1B,1B,1C#,1D#,1B,1F#,1G#,1F#,1B,,1B,1A#,1B,1F#,1G#,1B,1E,1D#,1E,2F#,1B,,1B,,"; + final String[] tune = tuneStr.split(","); + taskid = ess.scheduleSyncRepeatingTask(new Runnable() + { + int i = 0; + + @Override + public void run() + { + final String note = tune[i]; + i++; + if (i >= tune.length) + { + Commandessentials.this.stopTune(); + } + if (note == null || note.isEmpty()) + { + return; + } + for (Player onlinePlayer : ess.getOnlinePlayers()) + { + onlinePlayer.playSound(onlinePlayer.getLocation(), Sound.NOTE_PIANO, 1, noteMap.get(note)); + } + } + }, 20, 2); + } + + private void stopTune() + { + ess.getScheduler().cancelTask(taskid); + for (Block block : noteBlocks.values()) + { + if (block.getType() == Material.NOTE_BLOCK) + { + block.setType(Material.AIR); + } + } + noteBlocks.clear(); + } + private final String[] consoleMoo = new String[] + { + " (__)", + " (oo)", + " /------\\/", + " / | ||", + " * /\\---/\\", + " ~~ ~~", + "....\"Have you mooed today?\"..." + }; + private final String[] playerMoo = new String[] + { + " (__)", + " (oo)", + " /------\\/", + " / | | |", + " * /\\---/\\", + " ~~ ~~", + "....\"Have you mooed today?\"..." + }; + + private void run_moo(final Server server, final CommandSource sender, final String command, final String args[]) + { + if (args.length == 2 && args[1].equals("moo")) + { + for (String s : consoleMoo) + { + logger.info(s); + } + for (Player player : ess.getOnlinePlayers()) + { + player.sendMessage(playerMoo); + player.playSound(player.getLocation(), Sound.COW_IDLE, 1, 1.0f); + } + } + else + { + if (sender.isPlayer()) + { + sender.getSender().sendMessage(playerMoo); + final Player player = sender.getPlayer(); + player.playSound(player.getLocation(), Sound.COW_IDLE, 1, 1.0f); + + } + else + { + sender.getSender().sendMessage(consoleMoo); + } + } + } + + private void run_optout(final Server server, final CommandSource sender, final String command, final String args[]) + { + final Metrics metrics = ess.getMetrics(); + try + { + sender.sendMessage("Essentials collects simple metrics to highlight which features to concentrate work on in the future."); + if (metrics.isOptOut()) + { + metrics.enable(); + } + else + { + metrics.disable(); + } + sender.sendMessage("Anonymous Metrics are now " + (metrics.isOptOut() ? "disabled" : "enabled") + " for all plugins."); + } + catch (IOException ex) + { + sender.sendMessage("Unable to modify 'plugins/PluginMetrics/config.yml': " + ex.getMessage()); + } + } + + private void run_cleanup(final Server server, final CommandSource sender, final String command, final String args[]) throws Exception + { + if (args.length < 2 || !NumberUtil.isInt(args[1])) + { + sender.sendMessage("This sub-command will delete users who havent logged in in the last days."); + sender.sendMessage("Optional parameters define the minium amount required to prevent deletion."); + sender.sendMessage("Unless you define larger default values, this command wil ignore people who have more than 0 money/homes."); + throw new Exception("/ cleanup [money] [homes]"); + } + sender.sendMessage(tl("cleaning")); + + final long daysArg = Long.parseLong(args[1]); + final double moneyArg = args.length >= 3 ? Double.parseDouble(args[2].replaceAll("[^0-9\\.]", "")) : 0; + final int homesArg = args.length >= 4 && NumberUtil.isInt(args[3]) ? Integer.parseInt(args[3]) : 0; + final UserMap userMap = ess.getUserMap(); + + ess.runTaskAsynchronously(new Runnable() + { + @Override + public void run() + { + Long currTime = System.currentTimeMillis(); + for (UUID u : userMap.getAllUniqueUsers()) + { + final User user = ess.getUserMap().getUser(u); + if (user == null) + { + continue; + } + + long lastLog = user.getLastLogout(); + if (lastLog == 0) + { + lastLog = user.getLastLogin(); + } + if (lastLog == 0) + { + user.setLastLogin(currTime); + } + + if (user.isNPC()) + { + continue; + } + + long timeDiff = currTime - lastLog; + long milliDays = daysArg * 24L * 60L * 60L * 1000L; + int homeCount = user.getHomes().size(); + double moneyCount = user.getMoney().doubleValue(); + + if ((lastLog == 0) || (timeDiff < milliDays) + || (homeCount > homesArg) || (moneyCount > moneyArg)) + { + continue; + } + + if (ess.getSettings().isDebug()) + { + ess.getLogger().info("Deleting user: " + user.getName() + " Money: " + moneyCount + " Homes: " + homeCount + " Last seen: " + DateUtil.formatDateDiff(lastLog)); + } + + user.reset(); + } + sender.sendMessage(tl("cleaned")); + } + }); + + } + + private void run_uuidconvert(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + sender.sendMessage("Starting Essentials UUID userdata conversion, this may lag the server."); + + Boolean ignoreUFCache = (args.length > 2 && args[1].toLowerCase(Locale.ENGLISH).contains("ignore")); + EssentialsUpgrade.uuidFileConvert(ess, ignoreUFCache); + + sender.sendMessage("UUID conversion complete, check your server log for more information."); + } + + private void run_uuidtest(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 2) + { + throw new Exception("/ uuidtest "); + } + String name = args[1]; + sender.sendMessage("Looking up UUID for " + name); + + UUID onlineUUID = null; + + for (Player player : ess.getOnlinePlayers()) + { + if (player.getName().equalsIgnoreCase(name)) + { + onlineUUID = player.getUniqueId(); + break; + } + } + + UUID essUUID = ess.getUserMap().getUser(name).getConfigUUID(); + + org.bukkit.OfflinePlayer player = ess.getServer().getOfflinePlayer(name); + UUID bukkituuid = player.getUniqueId(); + sender.sendMessage("Bukkit Lookup: " + bukkituuid.toString()); + + if (onlineUUID != null && onlineUUID != bukkituuid) + { + sender.sendMessage("Online player: " + onlineUUID.toString()); + } + + if (essUUID != null && essUUID != bukkituuid) + { + sender.sendMessage("Essentials config: " + essUUID.toString()); + } + + UUID npcuuid = UUID.nameUUIDFromBytes(("NPC:" + name).getBytes(Charsets.UTF_8)); + sender.sendMessage("NPC UUID: " + npcuuid.toString()); + + UUID offlineuuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(Charsets.UTF_8)); + sender.sendMessage("Offline Mode UUID: " + offlineuuid.toString()); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandexp.java b/Essentials/src/com/earth2me/essentials/commands/Commandexp.java new file mode 100644 index 0000000000..3100c97082 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandexp.java @@ -0,0 +1,205 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.craftbukkit.SetExpFix; +import com.earth2me.essentials.utils.NumberUtil; +import java.util.List; +import java.util.Locale; +import org.bukkit.Server; +import org.bukkit.entity.Player; + + +public class Commandexp extends EssentialsCommand +{ + public Commandexp() + { + super("exp"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length == 0) + { + showExp(user.getSource(), user); + } + else if (args.length > 1 && args[0].equalsIgnoreCase("set") && user.isAuthorized("essentials.exp.set")) + { + if (args.length == 3 && user.isAuthorized("essentials.exp.set.others")) + { + expMatch(server, user.getSource(), args[1], args[2], false); + } + else + { + setExp(user.getSource(), user, args[1], false); + } + } + else if (args.length > 1 && args[0].equalsIgnoreCase("give") && user.isAuthorized("essentials.exp.give")) + { + if (args.length == 3 && user.isAuthorized("essentials.exp.give.others")) + { + expMatch(server, user.getSource(), args[1], args[2], true); + } + else + { + setExp(user.getSource(), user, args[1], true); + } + } + else if (args[0].equalsIgnoreCase("show")) + { + if (args.length >= 2 && user.isAuthorized("essentials.exp.others")) + { + String match = args[1].trim(); + showMatch(server, user.getSource(), match); + } + else + { + showExp(user.getSource(), user); + } + } + else + { + if (args.length >= 1 && NumberUtil.isInt(args[0].toLowerCase(Locale.ENGLISH).replace("l", "")) && user.isAuthorized("essentials.exp.give")) + { + if (args.length >= 2 && user.isAuthorized("essentials.exp.give.others")) + { + expMatch(server, user.getSource(), args[1], args[0], true); + } + else + { + setExp(user.getSource(), user, args[0], true); + } + } + else if (args.length >= 1 && user.isAuthorized("essentials.exp.others")) + { + String match = args[0].trim(); + showMatch(server, user.getSource(), match); + } + else + { + showExp(user.getSource(), user); + } + } + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + else if (args.length > 2 && args[0].equalsIgnoreCase("set")) + { + expMatch(server, sender, args[1], args[2], false); + } + else if (args.length > 2 && args[0].equalsIgnoreCase("give")) + { + expMatch(server, sender, args[1], args[2], true); + } + else + { + String match = args[0].trim(); + if (args.length >= 2 && NumberUtil.isInt(args[0].toLowerCase(Locale.ENGLISH).replace("l", ""))) + { + match = args[1].trim(); + expMatch(server, sender, match, args[0], true); + } + else if (args.length == 1) + { + match = args[0].trim(); + } + showMatch(server, sender, match); + } + } + + private void showMatch(final Server server, final CommandSource sender, final String match) throws PlayerNotFoundException + { + boolean skipHidden = sender.isPlayer() && !ess.getUser(sender.getPlayer()).canInteractVanished(); + boolean foundUser = false; + final List matchedPlayers = server.matchPlayer(match); + for (Player matchPlayer : matchedPlayers) + { + final User player = ess.getUser(matchPlayer); + if (skipHidden && player.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(matchPlayer)) + { + continue; + } + foundUser = true; + showExp(sender, player); + } + if (!foundUser) + { + throw new PlayerNotFoundException(); + } + } + + private void expMatch(final Server server, final CommandSource sender, final String match, String amount, final boolean give) throws NotEnoughArgumentsException, PlayerNotFoundException + { + boolean skipHidden = sender.isPlayer() && !ess.getUser(sender.getPlayer()).canInteractVanished(); + boolean foundUser = false; + final List matchedPlayers = server.matchPlayer(match); + for (Player matchPlayer : matchedPlayers) + { + final User player = ess.getUser(matchPlayer); + if (skipHidden && player.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(matchPlayer)) + { + continue; + } + foundUser = true; + setExp(sender, player, amount, give); + } + if (!foundUser) + { + throw new PlayerNotFoundException(); + } + } + + private void showExp(final CommandSource sender, final User target) + { + sender.sendMessage(tl("exp", target.getDisplayName(), SetExpFix.getTotalExperience(target.getBase()), target.getBase().getLevel(), SetExpFix.getExpUntilNextLevel(target.getBase()))); + } + + //TODO: Limit who can give negative exp? + private void setExp(final CommandSource sender, final User target, String strAmount, final boolean give) throws NotEnoughArgumentsException + { + long amount; + strAmount = strAmount.toLowerCase(Locale.ENGLISH); + if (strAmount.contains("l")) + { + strAmount = strAmount.replaceAll("l", ""); + int neededLevel = Integer.parseInt(strAmount); + if (give) + { + neededLevel += target.getBase().getLevel(); + } + amount = (long)SetExpFix.getExpToLevel(neededLevel); + SetExpFix.setTotalExperience(target.getBase(), 0); + } + else + { + amount = Long.parseLong(strAmount); + if (amount > Integer.MAX_VALUE || amount < Integer.MIN_VALUE) + { + throw new NotEnoughArgumentsException(); + } + } + + if (give) + { + amount += SetExpFix.getTotalExperience(target.getBase()); + } + if (amount > Integer.MAX_VALUE) + { + amount = (long)Integer.MAX_VALUE; + } + if (amount < 0l) + { + amount = 0l; + } + SetExpFix.setTotalExperience(target.getBase(), (int)amount); + sender.sendMessage(tl("expSet", target.getDisplayName(), amount)); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandext.java b/Essentials/src/com/earth2me/essentials/commands/Commandext.java new file mode 100644 index 0000000000..8cba548ad4 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandext.java @@ -0,0 +1,52 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Server; +import org.bukkit.entity.Player; + + +public class Commandext extends EssentialsLoopCommand +{ + public Commandext() + { + super("ext"); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + loopOnlinePlayers(server, sender, true, true, args[0], null); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + extPlayer(user.getBase()); + user.sendMessage(tl("extinguish")); + return; + } + + loopOnlinePlayers(server, user.getSource(), true, true, args[0], null); + } + + @Override + protected void updatePlayer(final Server server, final CommandSource sender, final User player, final String[] args) + { + extPlayer(player.getBase()); + sender.sendMessage(tl("extinguishOthers", player.getDisplayName())); + } + + private void extPlayer(final Player player) + { + player.setFireTicks(0); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandfeed.java b/Essentials/src/com/earth2me/essentials/commands/Commandfeed.java new file mode 100644 index 0000000000..545475ed38 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandfeed.java @@ -0,0 +1,76 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Server; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.FoodLevelChangeEvent; + + +public class Commandfeed extends EssentialsLoopCommand +{ + public Commandfeed() + { + super("feed"); + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (!user.isAuthorized("essentials.feed.cooldown.bypass")) + { + user.healCooldown(); + } + + if (args.length > 0 && user.isAuthorized("essentials.feed.others")) + { + loopOnlinePlayers(server, user.getSource(), true, true, args[0], null); + return; + } + + feedPlayer(user.getBase()); + user.sendMessage(tl("feed")); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + loopOnlinePlayers(server, sender, true, true, args[0], null); + } + + @Override + protected void updatePlayer(final Server server, final CommandSource sender, final User player, final String[] args) throws PlayerExemptException + { + try + { + feedPlayer(player.getBase()); + sender.sendMessage(tl("feedOther", player.getDisplayName())); + } + catch (QuietAbortException e) + { + //Handle Quietly + } + } + + private void feedPlayer(final Player player) throws QuietAbortException + { + final int amount = 30; + + final FoodLevelChangeEvent flce = new FoodLevelChangeEvent(player, amount); + ess.getServer().getPluginManager().callEvent(flce); + if (flce.isCancelled()) + { + throw new QuietAbortException(); + } + + player.setFoodLevel(flce.getFoodLevel() > 20 ? 20 : flce.getFoodLevel()); + player.setSaturation(10); + player.setExhaustion(0F); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandfireball.java b/Essentials/src/com/earth2me/essentials/commands/Commandfireball.java new file mode 100644 index 0000000000..d4759802a8 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandfireball.java @@ -0,0 +1,58 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.User; +import org.bukkit.Server; +import org.bukkit.entity.*; +import org.bukkit.util.Vector; + + +public class Commandfireball extends EssentialsCommand +{ + public Commandfireball() + { + super("fireball"); + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + Class type = Fireball.class; + Projectile projectile; + int speed = 2; + if (args.length > 0) + { + if (args[0].equalsIgnoreCase("small")) + { + type = SmallFireball.class; + } + else if (args[0].equalsIgnoreCase("arrow")) + { + type = Arrow.class; + } + else if (args[0].equalsIgnoreCase("skull")) + { + type = WitherSkull.class; + } + else if (args[0].equalsIgnoreCase("egg")) + { + type = Egg.class; + } + else if(args[0].equalsIgnoreCase("snowball")) + { + type = Snowball.class; + } + else if(args[0].equalsIgnoreCase("expbottle")) + { + type = ThrownExpBottle.class; + } + else if(args[0].equalsIgnoreCase("large")) + { + type = LargeFireball.class; + } + } + final Vector direction = user.getBase().getEyeLocation().getDirection().multiply(speed); + projectile = (Projectile)user.getWorld().spawn(user.getBase().getEyeLocation().add(direction.getX(), direction.getY(), direction.getZ()), type); + projectile.setShooter(user.getBase()); + projectile.setVelocity(direction); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandfirework.java b/Essentials/src/com/earth2me/essentials/commands/Commandfirework.java new file mode 100644 index 0000000000..f154a28bff --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandfirework.java @@ -0,0 +1,152 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.MetaItemStack; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.NumberUtil; +import java.util.regex.Pattern; +import org.bukkit.FireworkEffect; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Firework; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.FireworkMeta; +import org.bukkit.util.Vector; + +//This command has quite a complicated syntax, in theory it has 4 seperate syntaxes which are all variable: +// +//1: /firework clear - This clears all of the effects on a firework stack +// +//2: /firework power - This changes the base power of a firework +// +//3: /firework fire - This 'fires' a copy of the firework held. +//3: /firework fire - This 'fires' a number of copies of the firework held. +//3: /firework fire - This 'fires' a copy of the firework held, in the direction you are looking, #easteregg +// +//4: /firework [meta] - This will add an effect to the firework stack held +//4: /firework color: - The minimum you need to set an effect is 'color' +//4: Full Syntax: color: [fade:] [shape:] [effect:] +//4: Possible Shapes: star, ball, large, creeper, burst +//4: Possible Effects trail, twinkle + +public class Commandfirework extends EssentialsCommand +{ + + public Commandfirework() + { + super("firework"); + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + final ItemStack stack = user.getBase().getItemInHand(); + if (stack.getType() == Material.FIREWORK) + { + if (args.length > 0) + { + if (args[0].equalsIgnoreCase("clear")) + { + FireworkMeta fmeta = (FireworkMeta)stack.getItemMeta(); + fmeta.clearEffects(); + stack.setItemMeta(fmeta); + user.sendMessage(tl("fireworkEffectsCleared")); + } + else if (args.length > 1 && (args[0].equalsIgnoreCase("power") || (args[0].equalsIgnoreCase("p")))) + { + FireworkMeta fmeta = (FireworkMeta)stack.getItemMeta(); + try + { + int power = Integer.parseInt(args[1]); + fmeta.setPower(power > 3 ? 4 : power); + } + catch (NumberFormatException e) + { + throw new Exception(tl("invalidFireworkFormat", args[1], args[0])); + } + stack.setItemMeta(fmeta); + } + else if ((args[0].equalsIgnoreCase("fire") || (args[0].equalsIgnoreCase("f"))) + && user.isAuthorized("essentials.firework.fire")) + { + int amount = 1; + boolean direction = false; + if (args.length > 1) + { + if (NumberUtil.isInt(args[1])) + { + final int serverLimit = ess.getSettings().getSpawnMobLimit(); + amount = Integer.parseInt(args[1]); + if (amount > serverLimit) + { + amount = serverLimit; + user.sendMessage(tl("mobSpawnLimit")); + } + } + else + { + direction = true; + } + } + for (int i = 0; i < amount; i++) + { + Firework firework = (Firework)user.getWorld().spawnEntity(user.getLocation(), EntityType.FIREWORK); + FireworkMeta fmeta = (FireworkMeta)stack.getItemMeta(); + if (direction) + { + final Vector vector = user.getBase().getEyeLocation().getDirection().multiply(0.070); + if (fmeta.getPower() > 1) + { + fmeta.setPower(1); + } + firework.setVelocity(vector); + } + firework.setFireworkMeta(fmeta); + } + } + else + { + final MetaItemStack mStack = new MetaItemStack(stack); + for (String arg : args) + { + try + { + mStack.addFireworkMeta(user.getSource(), true, arg, ess); + } + catch (Exception e) + { + user.sendMessage(tl("fireworkSyntax")); + throw e; + } + } + + if (mStack.isValidFirework()) + { + FireworkMeta fmeta = (FireworkMeta)mStack.getItemStack().getItemMeta(); + FireworkEffect effect = mStack.getFireworkBuilder().build(); + if (fmeta.getEffects().size() > 0 && !user.isAuthorized("essentials.firework.multiple")) + { + throw new Exception(tl("multipleCharges")); + } + fmeta.addEffect(effect); + stack.setItemMeta(fmeta); + } + else + { + user.sendMessage(tl("fireworkSyntax")); + throw new Exception(tl("fireworkColor")); + } + } + } + else + { + throw new NotEnoughArgumentsException(); + } + } + else + { + throw new Exception(tl("holdFirework")); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandfly.java b/Essentials/src/com/earth2me/essentials/commands/Commandfly.java new file mode 100644 index 0000000000..790d351ab1 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandfly.java @@ -0,0 +1,69 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Server; + + +public class Commandfly extends EssentialsToggleCommand +{ + public Commandfly() + { + super("fly", "essentials.fly.others"); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + toggleOtherPlayers(server, sender, args); + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length == 1) + { + Boolean toggle = matchToggleArgument(args[0]); + if (toggle == null && user.isAuthorized(othersPermission)) + { + toggleOtherPlayers(server, user.getSource(), args); + } + else + { + togglePlayer(user.getSource(), user, toggle); + } + } + else if (args.length == 2 && user.isAuthorized(othersPermission)) + { + toggleOtherPlayers(server, user.getSource(), args); + } + else + { + togglePlayer(user.getSource(), user, null); + } + } + + @Override + void togglePlayer(CommandSource sender, User user, Boolean enabled) + { + if (enabled == null) + { + enabled = !user.getBase().getAllowFlight(); + } + + user.getBase().setFallDistance(0f); + user.getBase().setAllowFlight(enabled); + + if (!user.getBase().getAllowFlight()) + { + user.getBase().setFlying(false); + } + + user.sendMessage(tl("flyMode", tl(enabled ? "enabled" : "disabled"), user.getDisplayName())); + if (!sender.isPlayer() || !sender.getPlayer().equals(user.getBase())) + { + sender.sendMessage(tl("flyMode", tl(enabled ? "enabled" : "disabled"), user.getDisplayName())); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandgamemode.java b/Essentials/src/com/earth2me/essentials/commands/Commandgamemode.java new file mode 100644 index 0000000000..4b91d05829 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandgamemode.java @@ -0,0 +1,136 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import java.util.List; +import java.util.Locale; +import org.bukkit.GameMode; +import org.bukkit.Server; +import org.bukkit.entity.Player; + + +public class Commandgamemode extends EssentialsCommand +{ + public Commandgamemode() + { + super("gamemode"); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + GameMode gameMode; + if (args.length == 0) + { + throw new NotEnoughArgumentsException(); + } + else if (args.length == 1) + { + gameMode = matchGameMode(commandLabel); + gamemodeOtherPlayers(server, sender, gameMode, args[0]); + } + else if (args.length == 2) + { + gameMode = matchGameMode(args[0].toLowerCase(Locale.ENGLISH)); + gamemodeOtherPlayers(server, sender, gameMode, args[1]); + } + + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + GameMode gameMode; + if (args.length == 0) + { + gameMode = matchGameMode(commandLabel); + } + else if (args.length > 1 && args[1].trim().length() > 2 && user.isAuthorized("essentials.gamemode.others")) + { + gameMode = matchGameMode(args[0].toLowerCase(Locale.ENGLISH)); + gamemodeOtherPlayers(server, user.getSource(), gameMode, args[1]); + return; + } + else + { + try + { + gameMode = matchGameMode(args[0].toLowerCase(Locale.ENGLISH)); + } + catch (NotEnoughArgumentsException e) + { + if (user.isAuthorized("essentials.gamemode.others")) + { + gameMode = matchGameMode(commandLabel); + gamemodeOtherPlayers(server, user.getSource(), gameMode, args[0]); + return; + } + throw new NotEnoughArgumentsException(); + } + } + if (gameMode == null) + { + gameMode = user.getBase().getGameMode() == GameMode.SURVIVAL ? GameMode.CREATIVE : user.getBase().getGameMode() == GameMode.CREATIVE ? GameMode.ADVENTURE : GameMode.SURVIVAL; + } + user.getBase().setGameMode(gameMode); + user.sendMessage(tl("gameMode", tl(user.getBase().getGameMode().toString().toLowerCase(Locale.ENGLISH)), user.getDisplayName())); + } + + private void gamemodeOtherPlayers(final Server server, final CommandSource sender, final GameMode gameMode, final String name) throws NotEnoughArgumentsException, PlayerNotFoundException + { + if (name.trim().length() < 2 || gameMode == null) + { + throw new NotEnoughArgumentsException(tl("gameModeInvalid")); + } + + boolean skipHidden = sender.isPlayer() && !ess.getUser(sender.getPlayer()).canInteractVanished(); + boolean foundUser = false; + final List matchedPlayers = server.matchPlayer(name); + for (Player matchPlayer : matchedPlayers) + { + final User player = ess.getUser(matchPlayer); + if (skipHidden && player.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(matchPlayer)) + { + continue; + } + foundUser = true; + player.getBase().setGameMode(gameMode); + sender.sendMessage(tl("gameMode", tl(player.getBase().getGameMode().toString().toLowerCase(Locale.ENGLISH)), player.getDisplayName())); + } + if (!foundUser) + { + throw new PlayerNotFoundException(); + } + } + + private GameMode matchGameMode(String modeString) throws NotEnoughArgumentsException + { + GameMode mode = null; + if (modeString.equalsIgnoreCase("gmc") || modeString.equalsIgnoreCase("egmc") + || modeString.contains("creat") || modeString.equalsIgnoreCase("1") || modeString.equalsIgnoreCase("c")) + { + mode = GameMode.CREATIVE; + } + else if (modeString.equalsIgnoreCase("gms") || modeString.equalsIgnoreCase("egms") + || modeString.contains("survi") || modeString.equalsIgnoreCase("0") || modeString.equalsIgnoreCase("s")) + { + mode = GameMode.SURVIVAL; + } + else if (modeString.equalsIgnoreCase("gma") || modeString.equalsIgnoreCase("egma") + || modeString.contains("advent") || modeString.equalsIgnoreCase("2") || modeString.equalsIgnoreCase("a")) + { + mode = GameMode.ADVENTURE; + } + else if (modeString.equalsIgnoreCase("gmt") || modeString.equalsIgnoreCase("egmt") + || modeString.contains("toggle") || modeString.contains("cycle") || modeString.equalsIgnoreCase("t")) + { + mode = null; + } + else + { + throw new NotEnoughArgumentsException(); + } + return mode; + } +} \ No newline at end of file diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandgc.java b/Essentials/src/com/earth2me/essentials/commands/Commandgc.java new file mode 100644 index 0000000000..db44323519 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandgc.java @@ -0,0 +1,79 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.utils.DateUtil; +import com.earth2me.essentials.utils.NumberUtil; +import java.lang.management.ManagementFactory; +import java.util.List; +import java.util.logging.Level; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Chunk; +import org.bukkit.Server; +import org.bukkit.World; + + +public class Commandgc extends EssentialsCommand +{ + public Commandgc() + { + super("gc"); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + double tps = ess.getTimer().getAverageTPS(); + ChatColor color; + if (tps >= 18.0) + { + color = ChatColor.GREEN; + } + else if (tps >= 15.0) + { + color = ChatColor.YELLOW; + } + else + { + color = ChatColor.RED; + } + + sender.sendMessage(tl("uptime", DateUtil.formatDateDiff(ManagementFactory.getRuntimeMXBean().getStartTime()))); + sender.sendMessage(tl("tps", "" + color + NumberUtil.formatDouble(tps))); + sender.sendMessage(tl("gcmax", (Runtime.getRuntime().maxMemory() / 1024 / 1024))); + sender.sendMessage(tl("gctotal", (Runtime.getRuntime().totalMemory() / 1024 / 1024))); + sender.sendMessage(tl("gcfree", (Runtime.getRuntime().freeMemory() / 1024 / 1024))); + + List worlds = server.getWorlds(); + for (World w : worlds) + { + String worldType = "World"; + switch (w.getEnvironment()) + { + case NETHER: + worldType = "Nether"; + break; + case THE_END: + worldType = "The End"; + break; + } + + int tileEntities = 0; + + try + { + for (Chunk chunk : w.getLoadedChunks()) + { + tileEntities += chunk.getTileEntities().length; + } + } + catch (java.lang.ClassCastException ex) + { + Bukkit.getLogger().log(Level.SEVERE, "Corrupted chunk data on world " + w, ex); + } + + sender.sendMessage(tl("gcWorld", worldType, w.getName(), w.getLoadedChunks().length, w.getEntities().size(), tileEntities)); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandgetpos.java b/Essentials/src/com/earth2me/essentials/commands/Commandgetpos.java new file mode 100644 index 0000000000..f76d28e03c --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandgetpos.java @@ -0,0 +1,53 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Location; +import org.bukkit.Server; + + +public class Commandgetpos extends EssentialsCommand +{ + public Commandgetpos() + { + super("getpos"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length > 0 && user.isAuthorized("essentials.getpos.others")) + { + final User otherUser = getPlayer(server, user, args, 0); + outputPosition(user.getSource(), otherUser.getLocation(), user.getLocation()); + return; + } + outputPosition(user.getSource(), user.getLocation(), null); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + final User user = getPlayer(server, args, 0, true, false); + outputPosition(sender, user.getLocation(), null); + } + + private void outputPosition(final CommandSource sender, final Location coords, final Location distance) + { + sender.sendMessage(tl("currentWorld", coords.getWorld().getName())); + sender.sendMessage(tl("posX", coords.getBlockX())); + sender.sendMessage(tl("posY", coords.getBlockY())); + sender.sendMessage(tl("posZ", coords.getBlockZ())); + sender.sendMessage(tl("posYaw", (coords.getYaw() + 180 + 360) % 360)); + sender.sendMessage(tl("posPitch", coords.getPitch())); + if (distance != null && coords.getWorld().equals(distance.getWorld())) + { + sender.sendMessage(tl("distance", coords.distance(distance))); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandgive.java b/Essentials/src/com/earth2me/essentials/commands/Commandgive.java new file mode 100644 index 0000000000..8e8a6dfc41 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandgive.java @@ -0,0 +1,122 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.MetaItemStack; +import com.earth2me.essentials.User; +import com.earth2me.essentials.craftbukkit.InventoryWorkaround; +import com.earth2me.essentials.utils.NumberUtil; +import java.util.Locale; +import java.util.Map; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.inventory.ItemStack; + + +public class Commandgive extends EssentialsCommand +{ + public Commandgive() + { + super("give"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 2) + { + throw new NotEnoughArgumentsException(); + } + + ItemStack stack = ess.getItemDb().get(args[1]); + + final String itemname = stack.getType().toString().toLowerCase(Locale.ENGLISH).replace("_", ""); + if (sender.isPlayer() + && (ess.getSettings().permissionBasedItemSpawn() + ? (!ess.getUser(sender.getPlayer()).isAuthorized("essentials.itemspawn.item-all") + && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.itemspawn.item-" + itemname) + && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.itemspawn.item-" + stack.getTypeId())) + : (!ess.getUser(sender.getPlayer()).isAuthorized("essentials.itemspawn.exempt") + && !ess.getUser(sender.getPlayer()).canSpawnItem(stack.getTypeId())))) + { + throw new Exception(tl("cantSpawnItem", itemname)); + } + + final User giveTo = getPlayer(server, sender, args, 0); + + try + { + if (args.length > 3 && NumberUtil.isInt(args[2]) && NumberUtil.isInt(args[3])) + { + stack.setAmount(Integer.parseInt(args[2])); + stack.setDurability(Short.parseShort(args[3])); + } + else if (args.length > 2 && Integer.parseInt(args[2]) > 0) + { + stack.setAmount(Integer.parseInt(args[2])); + } + else if (ess.getSettings().getDefaultStackSize() > 0) + { + stack.setAmount(ess.getSettings().getDefaultStackSize()); + } + else if (ess.getSettings().getOversizedStackSize() > 0 && giveTo.isAuthorized("essentials.oversizedstacks")) + { + stack.setAmount(ess.getSettings().getOversizedStackSize()); + } + } + catch (NumberFormatException e) + { + throw new NotEnoughArgumentsException(); + } + + MetaItemStack metaStack = new MetaItemStack(stack); + if (!metaStack.canSpawn(ess)) + { + throw new Exception(tl("unableToSpawnItem", itemname)); + } + + if (args.length > 3) + { + boolean allowUnsafe = ess.getSettings().allowUnsafeEnchantments(); + if (allowUnsafe && sender.isPlayer() && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.enchantments.allowunsafe")) + { + allowUnsafe = false; + } + + int metaStart = NumberUtil.isInt(args[3]) ? 4 : 3; + + if (args.length > metaStart) + { + metaStack.parseStringMeta(sender, allowUnsafe, args, metaStart, ess); + } + + stack = metaStack.getItemStack(); + } + + if (stack.getType() == Material.AIR) + { + throw new Exception(tl("cantSpawnItem", "Air")); + } + + final String itemName = stack.getType().toString().toLowerCase(Locale.ENGLISH).replace('_', ' '); + sender.sendMessage(tl("giveSpawn", stack.getAmount(), itemName, giveTo.getDisplayName())); + + Map leftovers; + + if (giveTo.isAuthorized("essentials.oversizedstacks")) + { + leftovers = InventoryWorkaround.addOversizedItems(giveTo.getBase().getInventory(), ess.getSettings().getOversizedStackSize(), stack); + } + else + { + leftovers = InventoryWorkaround.addItems(giveTo.getBase().getInventory(), stack); + } + + for (ItemStack item : leftovers.values()) + { + sender.sendMessage(tl("giveSpawnFailure", item.getAmount(), itemName, giveTo.getDisplayName())); + } + + giveTo.getBase().updateInventory(); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandgod.java b/Essentials/src/com/earth2me/essentials/commands/Commandgod.java new file mode 100644 index 0000000000..b758f64937 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandgod.java @@ -0,0 +1,76 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import net.ess3.api.events.GodStatusChangeEvent; +import org.bukkit.Server; + + +public class Commandgod extends EssentialsToggleCommand +{ + public Commandgod() + { + super("god", "essentials.god.others"); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + toggleOtherPlayers(server, sender, args); + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length == 1) + { + Boolean toggle = matchToggleArgument(args[0]); + if (toggle == null && user.isAuthorized(othersPermission)) + { + toggleOtherPlayers(server, user.getSource(), args); + } + else + { + togglePlayer(user.getSource(), user, toggle); + } + } + else if (args.length == 2 && user.isAuthorized(othersPermission)) + { + toggleOtherPlayers(server, user.getSource(), args); + } + else + { + togglePlayer(user.getSource(), user, null); + } + } + + @Override + void togglePlayer(CommandSource sender, User user, Boolean enabled) + { + if (enabled == null) + { + enabled = !user.isGodModeEnabled(); + } + + final User controller = sender.isPlayer() ? ess.getUser(sender.getPlayer()) : null; + final GodStatusChangeEvent godEvent = new GodStatusChangeEvent(controller, user, enabled); + ess.getServer().getPluginManager().callEvent(godEvent); + if (!godEvent.isCancelled()) + { + user.setGodModeEnabled(enabled); + + if (enabled && user.getBase().getHealth() != 0) + { + user.getBase().setHealth(user.getBase().getMaxHealth()); + user.getBase().setFoodLevel(20); + } + + user.sendMessage(tl("godMode", enabled ? tl("enabled") : tl("disabled"))); + if (!sender.isPlayer() || !sender.getPlayer().equals(user.getBase())) + { + sender.sendMessage(tl("godMode", tl(enabled ? "godEnabledFor" : "godDisabledFor", user.getDisplayName()))); + } + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandhat.java b/Essentials/src/com/earth2me/essentials/commands/Commandhat.java new file mode 100644 index 0000000000..4f042ba609 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandhat.java @@ -0,0 +1,62 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.craftbukkit.InventoryWorkaround; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; + + +public class Commandhat extends EssentialsCommand +{ + public Commandhat() + { + super("hat"); + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length > 0 && (args[0].contains("rem") || args[0].contains("off") || args[0].equalsIgnoreCase("0"))) + { + final PlayerInventory inv = user.getBase().getInventory(); + final ItemStack head = inv.getHelmet(); + if (head == null || head.getType() == Material.AIR) + { + user.sendMessage(tl("hatEmpty")); + } + else + { + final ItemStack air = new ItemStack(Material.AIR); + inv.setHelmet(air); + InventoryWorkaround.addItems(user.getBase().getInventory(), head); + user.sendMessage(tl("hatRemoved")); + } + } + else + { + if (user.getBase().getItemInHand().getType() != Material.AIR) + { + final ItemStack hand = user.getBase().getItemInHand(); + if (hand.getType().getMaxDurability() == 0) + { + final PlayerInventory inv = user.getBase().getInventory(); + final ItemStack head = inv.getHelmet(); + inv.setHelmet(hand); + inv.setItemInHand(head); + user.sendMessage(tl("hatPlaced")); + } + else + { + user.sendMessage(tl("hatArmor")); + } + } + else + { + user.sendMessage(tl("hatFail")); + } + } + } +} \ No newline at end of file diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandheal.java b/Essentials/src/com/earth2me/essentials/commands/Commandheal.java new file mode 100644 index 0000000000..6890af09f7 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandheal.java @@ -0,0 +1,94 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Server; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.EntityRegainHealthEvent; +import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason; +import org.bukkit.potion.PotionEffect; + + +public class Commandheal extends EssentialsLoopCommand +{ + public Commandheal() + { + super("heal"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (!user.isAuthorized("essentials.heal.cooldown.bypass")) + { + user.healCooldown(); + } + + if (args.length > 0 && user.isAuthorized("essentials.heal.others")) + { + loopOnlinePlayers(server, user.getSource(), true, true, args[0], null); + return; + } + + healPlayer(user); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + loopOnlinePlayers(server, sender, true, true, args[0], null); + } + + @Override + protected void updatePlayer(final Server server, final CommandSource sender, final User player, final String[] args) throws PlayerExemptException + { + try + { + healPlayer(player); + sender.sendMessage(tl("healOther", player.getDisplayName())); + } + catch (QuietAbortException e) + { + //Handle Quietly + } + } + + private void healPlayer(final User user) throws PlayerExemptException, QuietAbortException + { + final Player player = user.getBase(); + + if (player.getHealth() == 0) + { + throw new PlayerExemptException(tl("healDead")); + } + + final double amount = player.getMaxHealth() - player.getHealth(); + final EntityRegainHealthEvent erhe = new EntityRegainHealthEvent(player, amount, RegainReason.CUSTOM); + ess.getServer().getPluginManager().callEvent(erhe); + if (erhe.isCancelled()) + { + throw new QuietAbortException(); + } + + double newAmount = player.getHealth() + erhe.getAmount(); + if (newAmount > player.getMaxHealth()) + { + newAmount = player.getMaxHealth(); + } + + player.setHealth(newAmount); + player.setFoodLevel(20); + player.setFireTicks(0); + user.sendMessage(tl("heal")); + for (PotionEffect effect : player.getActivePotionEffects()) + { + player.removePotionEffect(effect.getType()); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandhelp.java b/Essentials/src/com/earth2me/essentials/commands/Commandhelp.java new file mode 100644 index 0000000000..d037c3c79f --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandhelp.java @@ -0,0 +1,60 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.textreader.*; +import com.earth2me.essentials.utils.NumberUtil; +import java.util.Locale; +import org.bukkit.Server; + + +public class Commandhelp extends EssentialsCommand +{ + public Commandhelp() + { + super("help"); + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + IText output; + String pageStr = args.length > 0 ? args[0] : null; + String chapterPageStr = args.length > 1 ? args[1] : null; + String command = commandLabel; + final IText input = new TextInput(user.getSource(), "help", false, ess); + + if (input.getLines().isEmpty()) + { + if (NumberUtil.isInt(pageStr) || pageStr == null) + { + output = new HelpInput(user, "", ess); + } + else + { + if (pageStr.length() > 26) + { + pageStr = pageStr.substring(0, 25); + } + output = new HelpInput(user, pageStr.toLowerCase(Locale.ENGLISH), ess); + command = command.concat(" ").concat(pageStr); + pageStr = chapterPageStr; + } + chapterPageStr = null; + } + else + { + user.setDisplayNick(); + output = new KeywordReplacer(input, user.getSource(), ess); + } + final TextPager pager = new TextPager(output); + pager.showPage(pageStr, chapterPageStr, command, user.getSource()); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + sender.sendMessage(tl("helpConsole")); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandhelpop.java b/Essentials/src/com/earth2me/essentials/commands/Commandhelpop.java new file mode 100644 index 0000000000..b83b5b6958 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandhelpop.java @@ -0,0 +1,47 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import com.earth2me.essentials.Console; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.FormatUtil; +import java.util.logging.Level; +import org.bukkit.Server; + + +public class Commandhelpop extends EssentialsCommand +{ + public Commandhelpop() + { + super("helpop"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + user.setDisplayNick(); + final String message = sendMessage(server, user.getSource(), user.getDisplayName(), args); + if (!user.isAuthorized("essentials.helpop.receive")) + { + user.sendMessage(message); + } + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + sendMessage(server, sender, Console.NAME, args); + } + + private String sendMessage(final Server server, final CommandSource sender, final String from, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + final String message = tl("helpOp", from, FormatUtil.stripFormat(getFinalArg(args, 0))); + server.getLogger().log(Level.INFO, message); + ess.broadcastMessage("essentials.helpop.receive", message); + return message; + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandhome.java b/Essentials/src/com/earth2me/essentials/commands/Commandhome.java new file mode 100644 index 0000000000..62b0c4161c --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandhome.java @@ -0,0 +1,129 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.StringUtil; +import java.util.List; +import java.util.Locale; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + + +public class Commandhome extends EssentialsCommand +{ + public Commandhome() + { + super("home"); + } + + // This method contains an undocumented translation parameters #EasterEgg + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + final Trade charge = new Trade(this.getName(), ess); + User player = user; + String homeName = ""; + String[] nameParts; + if (args.length > 0) + { + nameParts = args[0].split(":"); + if (nameParts[0].length() == args[0].length() || !user.isAuthorized("essentials.home.others")) + { + homeName = nameParts[0]; + } + else + { + player = getPlayer(server, nameParts, 0, true, true); + if (nameParts.length > 1) + { + homeName = nameParts[1]; + } + } + } + try + { + if ("bed".equalsIgnoreCase(homeName) && user.isAuthorized("essentials.home.bed")) + { + final Location bed = player.getBase().getBedSpawnLocation(); + if (bed != null) + { + user.getTeleport().teleport(bed, charge, TeleportCause.COMMAND); + throw new NoChargeException(); + } + else + { + throw new Exception(tl("bedMissing")); + } + } + goHome(user, player, homeName.toLowerCase(Locale.ENGLISH), charge); + } + catch (NotEnoughArgumentsException e) + { + Location bed = player.getBase().getBedSpawnLocation(); + final List homes = player.getHomes(); + if (homes.isEmpty() && player.equals(user)) + { + user.getTeleport().respawn(charge, TeleportCause.COMMAND); + } + else if (homes.isEmpty()) + { + throw new Exception(tl("noHomeSetPlayer")); + } + else if (homes.size() == 1 && player.equals(user)) + { + goHome(user, player, homes.get(0), charge); + } + else + { + final int count = homes.size(); + if (user.isAuthorized("essentials.home.bed")) + { + if (bed != null) + { + homes.add(tl("bed")); + } + else + { + homes.add(tl("bedNull")); + } + } + user.sendMessage(tl("homes", StringUtil.joinList(homes), count, getHomeLimit(player))); + } + } + throw new NoChargeException(); + } + + private String getHomeLimit(final User player) + { + if (!player.getBase().isOnline()) + { + return "?"; + } + if (player.isAuthorized("essentials.sethome.multiple.unlimited")) + { + return "*"; + } + return Integer.toString(ess.getSettings().getHomeLimit(player)); + } + + private void goHome(final User user, final User player, final String home, final Trade charge) throws Exception + { + if (home.length() < 1) + { + throw new NotEnoughArgumentsException(); + } + final Location loc = player.getHome(home); + if (loc == null) + { + throw new NotEnoughArgumentsException(); + } + if (user.getWorld() != loc.getWorld() && ess.getSettings().isWorldHomePermissions() + && !user.isAuthorized("essentials.worlds." + loc.getWorld().getName())) + { + throw new Exception(tl("noPerm", "essentials.worlds." + loc.getWorld().getName())); + } + user.getTeleport().teleport(loc, charge, TeleportCause.COMMAND); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandignore.java b/Essentials/src/com/earth2me/essentials/commands/Commandignore.java new file mode 100644 index 0000000000..c5bc21d466 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandignore.java @@ -0,0 +1,58 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Server; + + +public class Commandignore extends EssentialsCommand +{ + public Commandignore() + { + super("ignore"); + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + StringBuilder sb = new StringBuilder(); + for (String s : user._getIgnoredPlayers()) + { + sb.append(s).append(" "); + } + String ignoredList = sb.toString().trim(); + user.sendMessage(ignoredList.length() > 0 ? tl("ignoredList", ignoredList) : tl("noIgnored")); + } + else + { + User player; + try + { + player = getPlayer(server, args, 0, true, true); + } + catch (PlayerNotFoundException ex) + { + player = ess.getOfflineUser(args[0]); + } + if (player == null) + { + throw new PlayerNotFoundException(); + } + if (player.isIgnoreExempt()) { + user.sendMessage(tl("ignoreExempt")); + } + else if (user.isIgnoredPlayer(player)) + { + user.setIgnoredPlayer(player, false); + user.sendMessage(tl("unignorePlayer", player.getName())); + } + else + { + user.setIgnoredPlayer(player, true); + user.sendMessage(tl("ignorePlayer", player.getName())); + } + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandinfo.java b/Essentials/src/com/earth2me/essentials/commands/Commandinfo.java new file mode 100644 index 0000000000..2ee915f7c4 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandinfo.java @@ -0,0 +1,31 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import com.earth2me.essentials.textreader.IText; +import com.earth2me.essentials.textreader.KeywordReplacer; +import com.earth2me.essentials.textreader.TextInput; +import com.earth2me.essentials.textreader.TextPager; +import org.bukkit.Server; + + +public class Commandinfo extends EssentialsCommand +{ + public Commandinfo() + { + super("info"); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (sender.isPlayer()) + { + ess.getUser(sender.getPlayer()).setDisplayNick(); + } + + final IText input = new TextInput(sender, "info", true, ess); + final IText output = new KeywordReplacer(input, sender, ess); + final TextPager pager = new TextPager(output); + pager.showPage(args.length > 0 ? args[0] : null, args.length > 1 ? args[1] : null, commandLabel, sender); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandinvsee.java b/Essentials/src/com/earth2me/essentials/commands/Commandinvsee.java new file mode 100644 index 0000000000..f1800eb8e3 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandinvsee.java @@ -0,0 +1,40 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.User; +import org.bukkit.Server; +import org.bukkit.inventory.Inventory; + + +public class Commandinvsee extends EssentialsCommand +{ + public Commandinvsee() + { + super("invsee"); + } + + //This method has a hidden param, which if given will display the equip slots. #easteregg + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + final User invUser = getPlayer(server, user, args, 0); + Inventory inv; + + if (args.length > 1 && user.isAuthorized("essentials.invsee.equip")) + { + inv = server.createInventory(invUser.getBase(), 9, "Equipped"); + inv.setContents(invUser.getBase().getInventory().getArmorContents()); + } + else + { + inv = invUser.getBase().getInventory(); + } + user.getBase().closeInventory(); + user.getBase().openInventory(inv); + user.setInvSee(true); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commanditem.java b/Essentials/src/com/earth2me/essentials/commands/Commanditem.java new file mode 100644 index 0000000000..97d818172a --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commanditem.java @@ -0,0 +1,86 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.MetaItemStack; +import com.earth2me.essentials.User; +import com.earth2me.essentials.craftbukkit.InventoryWorkaround; +import java.util.Locale; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.inventory.ItemStack; + + +public class Commanditem extends EssentialsCommand +{ + public Commanditem() + { + super("item"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + ItemStack stack = ess.getItemDb().get(args[0]); + + final String itemname = stack.getType().toString().toLowerCase(Locale.ENGLISH).replace("_", ""); + if (ess.getSettings().permissionBasedItemSpawn() + ? (!user.isAuthorized("essentials.itemspawn.item-all") + && !user.isAuthorized("essentials.itemspawn.item-" + itemname) + && !user.isAuthorized("essentials.itemspawn.item-" + stack.getTypeId())) + : (!user.isAuthorized("essentials.itemspawn.exempt") + && !user.canSpawnItem(stack.getTypeId()))) + { + throw new Exception(tl("cantSpawnItem", itemname)); + } + try + { + if (args.length > 1 && Integer.parseInt(args[1]) > 0) + { + stack.setAmount(Integer.parseInt(args[1])); + } + else if (ess.getSettings().getDefaultStackSize() > 0) + { + stack.setAmount(ess.getSettings().getDefaultStackSize()); + } + else if (ess.getSettings().getOversizedStackSize() > 0 && user.isAuthorized("essentials.oversizedstacks")) + { + stack.setAmount(ess.getSettings().getOversizedStackSize()); + } + } + catch (NumberFormatException e) + { + throw new NotEnoughArgumentsException(); + } + if (args.length > 2) + { + MetaItemStack metaStack = new MetaItemStack(stack); + final boolean allowUnsafe = ess.getSettings().allowUnsafeEnchantments() && user.isAuthorized("essentials.enchantments.allowunsafe"); + + metaStack.parseStringMeta(user.getSource(), allowUnsafe, args, 2, ess); + + stack = metaStack.getItemStack(); + } + + + if (stack.getType() == Material.AIR) + { + throw new Exception(tl("cantSpawnItem", "Air")); + } + + final String displayName = stack.getType().toString().toLowerCase(Locale.ENGLISH).replace('_', ' '); + user.sendMessage(tl("itemSpawn", stack.getAmount(), displayName)); + if (user.isAuthorized("essentials.oversizedstacks")) + { + InventoryWorkaround.addOversizedItems(user.getBase().getInventory(), ess.getSettings().getOversizedStackSize(), stack); + } + else + { + InventoryWorkaround.addItems(user.getBase().getInventory(), stack); + } + user.getBase().updateInventory(); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commanditemdb.java b/Essentials/src/com/earth2me/essentials/commands/Commanditemdb.java new file mode 100644 index 0000000000..02ea1c637c --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commanditemdb.java @@ -0,0 +1,55 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.inventory.ItemStack; + + +public class Commanditemdb extends EssentialsCommand +{ + public Commanditemdb() + { + super("itemdb"); + } + + @Override + protected void run(Server server, CommandSource sender, String commandLabel, String[] args) throws Exception + { + ItemStack itemStack = null; + boolean itemHeld = false; + if (args.length < 1) + { + if (sender.isPlayer()) + { + itemHeld = true; + itemStack = sender.getPlayer().getItemInHand(); + } + if (itemStack == null) + { + throw new NotEnoughArgumentsException(); + } + } + else + { + itemStack = ess.getItemDb().get(args[0]); + } + sender.sendMessage(tl("itemType", itemStack.getType().toString(), itemStack.getTypeId() + ":" + Integer.toString(itemStack.getDurability()))); + + if (itemHeld && itemStack.getType() != Material.AIR) + { + int maxuses = itemStack.getType().getMaxDurability(); + int durability = ((maxuses + 1) - itemStack.getDurability()); + if (maxuses != 0) + { + sender.sendMessage(tl("durability", Integer.toString(durability))); + } + } + final String itemNameList = ess.getItemDb().names(itemStack); + if (itemNameList != null) + { + sender.sendMessage(tl("itemNames", ess.getItemDb().names(itemStack))); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandjails.java b/Essentials/src/com/earth2me/essentials/commands/Commandjails.java new file mode 100644 index 0000000000..5fe61032d2 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandjails.java @@ -0,0 +1,20 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import com.earth2me.essentials.utils.StringUtil; +import org.bukkit.Server; + + +public class Commandjails extends EssentialsCommand +{ + public Commandjails() + { + super("jails"); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + sender.sendMessage("§7" + StringUtil.joinList(" ", ess.getJails().getList())); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandjump.java b/Essentials/src/com/earth2me/essentials/commands/Commandjump.java new file mode 100644 index 0000000000..228df82b03 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandjump.java @@ -0,0 +1,57 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.LocationUtil; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + +// This method contains an undocumented sub command #EasterEgg +public class Commandjump extends EssentialsCommand +{ + public Commandjump() + { + super("jump"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length > 0 && args[0].contains("lock") && user.isAuthorized("essentials.jump.lock")) + { + if (user.isFlyClickJump()) + { + user.setRightClickJump(false); + user.sendMessage("Flying wizard mode disabled"); + } + else + { + user.setRightClickJump(true); + user.sendMessage("Enabling flying wizard mode"); + } + return; + } + + Location loc; + final Location cloc = user.getLocation(); + + try + { + loc = LocationUtil.getTarget(user.getBase()); + loc.setYaw(cloc.getYaw()); + loc.setPitch(cloc.getPitch()); + loc.setY(loc.getY() + 1); + } + catch (NullPointerException ex) + { + throw new Exception(tl("jumpError"), ex); + } + + final Trade charge = new Trade(this.getName(), ess); + charge.isAffordableFor(user); + user.getTeleport().teleport(loc, charge, TeleportCause.COMMAND); + throw new NoChargeException(); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandkick.java b/Essentials/src/com/earth2me/essentials/commands/Commandkick.java new file mode 100644 index 0000000000..f4c2bdaca9 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandkick.java @@ -0,0 +1,51 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import com.earth2me.essentials.Console; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.FormatUtil; +import java.util.logging.Level; +import org.bukkit.Server; + + +public class Commandkick extends EssentialsCommand +{ + public Commandkick() + { + super("kick"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + final User target = getPlayer(server, args, 0, true, false); + if (sender.isPlayer()) + { + User user = ess.getUser(sender.getPlayer()); + if (target.isHidden(sender.getPlayer()) && !user.canInteractVanished() && !sender.getPlayer().canSee(target.getBase())) + { + throw new PlayerNotFoundException(); + } + + if (target.isAuthorized("essentials.kick.exempt")) + { + throw new Exception(tl("kickExempt")); + } + } + + String kickReason = args.length > 1 ? getFinalArg(args, 1) : tl("kickDefault"); + kickReason = FormatUtil.replaceFormat(kickReason.replace("\\n", "\n").replace("|", "\n")); + + target.getBase().kickPlayer(kickReason); + final String senderName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.NAME; + + server.getLogger().log(Level.INFO, tl("playerKicked", senderName, target.getName(), kickReason)); + ess.broadcastMessage("essentials.kick.notify", tl("playerKicked", senderName, target.getName(), kickReason)); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandkickall.java b/Essentials/src/com/earth2me/essentials/commands/Commandkickall.java new file mode 100644 index 0000000000..745da13e3e --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandkickall.java @@ -0,0 +1,32 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.utils.FormatUtil; +import org.bukkit.Server; +import org.bukkit.entity.Player; + + +public class Commandkickall extends EssentialsCommand +{ + public Commandkickall() + { + super("kickall"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + String kickReason = args.length > 0 ? getFinalArg(args, 0) : tl("kickDefault"); + kickReason = FormatUtil.replaceFormat(kickReason.replace("\\n", "\n").replace("|", "\n")); + + for (Player onlinePlayer : ess.getOnlinePlayers()) + { + if (!sender.isPlayer() || !onlinePlayer.getName().equalsIgnoreCase(sender.getPlayer().getName())) + { + onlinePlayer.kickPlayer(kickReason); + } + } + sender.sendMessage(tl("kickedAll")); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandkill.java b/Essentials/src/com/earth2me/essentials/commands/Commandkill.java new file mode 100644 index 0000000000..6c40623717 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandkill.java @@ -0,0 +1,52 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Server; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.EntityDamageEvent; + + +public class Commandkill extends EssentialsLoopCommand +{ + public Commandkill() + { + super("kill"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + loopOnlinePlayers(server, sender, true, true, args[0], null); + } + + @Override + protected void updatePlayer(final Server server, final CommandSource sender, final User user, final String[] args) throws PlayerExemptException + { + final Player matchPlayer = user.getBase(); + if (sender.isPlayer() && user.isAuthorized("essentials.kill.exempt") && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.kill.force")) + { + throw new PlayerExemptException(tl("killExempt", matchPlayer.getDisplayName())); + } + final EntityDamageEvent ede = new EntityDamageEvent(matchPlayer, sender.isPlayer() && sender.getPlayer().getName().equals(matchPlayer.getName()) ? EntityDamageEvent.DamageCause.SUICIDE : EntityDamageEvent.DamageCause.CUSTOM, Short.MAX_VALUE); + server.getPluginManager().callEvent(ede); + if (ede.isCancelled() && sender.isPlayer() && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.kill.force")) + { + return; + } + matchPlayer.damage(Short.MAX_VALUE); + + if (matchPlayer.getHealth() > 0) + { + matchPlayer.setHealth(0); + } + + sender.sendMessage(tl("kill", matchPlayer.getDisplayName())); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandkit.java b/Essentials/src/com/earth2me/essentials/commands/Commandkit.java new file mode 100644 index 0000000000..aa3f21d3b3 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandkit.java @@ -0,0 +1,125 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Kit; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.StringUtil; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.logging.Level; +import org.bukkit.Server; + + +public class Commandkit extends EssentialsCommand +{ + public Commandkit() + { + super("kit"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + final String kitList = Kit.listKits(ess, user); + user.sendMessage(kitList.length() > 0 ? tl("kits", kitList) : tl("noKits")); + throw new NoChargeException(); + } + else if (args.length > 1 && user.isAuthorized("essentials.kit.others")) + { + final User userTo = getPlayer(server, user, args, 1); + final String kitNames = StringUtil.sanitizeString(args[0].toLowerCase(Locale.ENGLISH)).trim(); + giveKits(userTo, user, kitNames); + } + else + { + final String kitNames = StringUtil.sanitizeString(args[0].toLowerCase(Locale.ENGLISH)).trim(); + giveKits(user, user, kitNames); + } + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 2) + { + final String kitList = Kit.listKits(ess, null); + sender.sendMessage(kitList.length() > 0 ? tl("kits", kitList) : tl("noKits")); + throw new NoChargeException(); + } + else + { + final User userTo = getPlayer(server, args, 1, true, false); + final String[] kits = args[0].toLowerCase(Locale.ENGLISH).split(","); + + for (final String kitName : kits) + { + final Kit kit = new Kit(kitName, ess); + kit.expandItems(userTo); + + sender.sendMessage(tl("kitGiveTo", kitName, userTo.getDisplayName())); + userTo.sendMessage(tl("kitReceive", kitName)); + } + } + } + + private void giveKits(final User userTo, final User userFrom, final String kitNames) throws Exception + { + if (kitNames.isEmpty()) + { + throw new Exception(tl("kitNotFound")); + } + String[] kitList = kitNames.split(","); + + List kits = new ArrayList(); + + for (final String kitName : kitList) + { + if (kitName.isEmpty()) + { + throw new Exception(tl("kitNotFound")); + } + + Kit kit = new Kit(kitName, ess); + kit.checkPerms(userFrom); + kit.checkDelay(userFrom); + kit.checkAffordable(userFrom); + kits.add(kit); + } + + for (final Kit kit : kits) + { + try + { + + kit.checkDelay(userFrom); + kit.checkAffordable(userFrom); + kit.setTime(userFrom); + kit.expandItems(userTo); + kit.chargeUser(userTo); + + if (!userFrom.equals(userTo)) + { + userFrom.sendMessage(tl("kitGiveTo", kit.getName(), userTo.getDisplayName())); + } + + userTo.sendMessage(tl("kitReceive", kit.getName())); + + } + catch (NoChargeException ex) + { + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "Soft kit error, abort spawning " + kit.getName(), ex); + } + } + catch (Exception ex) + { + ess.showError(userFrom.getSource(), ex, "\\ kit: " + kit.getName()); + } + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandkittycannon.java b/Essentials/src/com/earth2me/essentials/commands/Commandkittycannon.java new file mode 100644 index 0000000000..507e1d7d35 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandkittycannon.java @@ -0,0 +1,48 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.Mob; +import com.earth2me.essentials.User; +import java.util.Random; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.entity.Ocelot; + +// This command is not documented on the wiki #EasterEgg +public class Commandkittycannon extends EssentialsCommand +{ + private static final Random random = new Random(); + + public Commandkittycannon() + { + super("kittycannon"); + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + final Mob cat = Mob.OCELOT; + final Ocelot ocelot = (Ocelot)cat.spawn(user.getWorld(), server, user.getBase().getEyeLocation()); + if (ocelot == null) + { + return; + } + final int i = random.nextInt(Ocelot.Type.values().length); + ocelot.setCatType(Ocelot.Type.values()[i]); + ocelot.setTamed(true); + ocelot.setBaby(); + ocelot.setVelocity(user.getBase().getEyeLocation().getDirection().multiply(2)); + + class KittyCannonExplodeTask implements Runnable + { + @Override + public void run() + { + final Location loc = ocelot.getLocation(); + ocelot.remove(); + loc.getWorld().createExplosion(loc, 0F); + } + } + ess.scheduleSyncDelayedTask(new KittyCannonExplodeTask(), 20); + + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandlightning.java b/Essentials/src/com/earth2me/essentials/commands/Commandlightning.java new file mode 100644 index 0000000000..75e3c05796 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandlightning.java @@ -0,0 +1,61 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Server; +import org.bukkit.entity.LightningStrike; + + +public class Commandlightning extends EssentialsLoopCommand +{ + int power = 5; + + public Commandlightning() + { + super("lightning"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + User user; + if (sender.isPlayer()) + { + user = ess.getUser(sender.getPlayer()); + if ((args.length < 1 || user != null && !user.isAuthorized("essentials.lightning.others"))) + { + user.getWorld().strikeLightning(user.getBase().getTargetBlock(null, 600).getLocation()); + return; + } + } + + if (args.length > 1) + { + try + { + power = Integer.parseInt(args[1]); + } + catch (NumberFormatException ex) + { + } + } + loopOnlinePlayers(server, sender, true, true, args[0], null); + } + + @Override + protected void updatePlayer(final Server server, final CommandSource sender, final User matchUser, final String[] args) + { + sender.sendMessage(tl("lightningUse", matchUser.getDisplayName())); + final LightningStrike strike = matchUser.getBase().getWorld().strikeLightningEffect(matchUser.getBase().getLocation()); + + if (!matchUser.isGodModeEnabled()) + { + matchUser.getBase().damage(power, strike); + } + if (ess.getSettings().warnOnSmite()) + { + matchUser.sendMessage(tl("lightningSmited")); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandlist.java b/Essentials/src/com/earth2me/essentials/commands/Commandlist.java new file mode 100644 index 0000000000..bb54757217 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandlist.java @@ -0,0 +1,139 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.PlayerList; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.FormatUtil; +import com.earth2me.essentials.utils.NumberUtil; +import java.util.*; +import org.bukkit.Server; + + +public class Commandlist extends EssentialsCommand +{ + public Commandlist() + { + super("list"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + boolean showHidden = true; + User user = null; + if (sender.isPlayer()) + { + user = ess.getUser(sender.getPlayer()); + showHidden = user.isAuthorized("essentials.list.hidden") || user.canInteractVanished(); + } + sender.sendMessage(PlayerList.listSummary(ess, user, showHidden)); + final Map> playerList = PlayerList.getPlayerLists(ess, user, showHidden); + + if (args.length > 0) + { + sender.sendMessage(PlayerList.listGroupUsers(ess, playerList, args[0].toLowerCase())); + } + else + { + sendGroupedList(sender, commandLabel, playerList); + } + } + + // Output the standard /list output, when no group is specified + private void sendGroupedList(CommandSource sender, String commandLabel, Map> playerList) + { + final Set configGroups = ess.getSettings().getListGroupConfig().keySet(); + final List asterisk = new ArrayList(); + + // Loop through the custom defined groups and display them + for (String oConfigGroup : configGroups) + { + String groupValue = ess.getSettings().getListGroupConfig().get(oConfigGroup).toString().trim(); + String configGroup = oConfigGroup.toLowerCase(); + + // If the group value is an asterisk, then skip it, and handle it later + if (groupValue.equals("*")) + { + asterisk.add(oConfigGroup); + continue; + } + + // If the group value is hidden, we don't need to display it + if (groupValue.equalsIgnoreCase("hidden")) + { + playerList.remove(configGroup); + continue; + } + + List outputUserList = new ArrayList(); + final List matchedList = playerList.get(configGroup); + + // If the group value is an int, then we might need to truncate it + if (NumberUtil.isInt(groupValue)) + { + if (matchedList != null && !matchedList.isEmpty()) + { + playerList.remove(configGroup); + outputUserList.addAll(matchedList); + int limit = Integer.parseInt(groupValue); + if (matchedList.size() > limit) + { + sender.sendMessage(PlayerList.outputFormat(oConfigGroup, tl("groupNumber", matchedList.size(), commandLabel, FormatUtil.stripFormat(configGroup)))); + } + else + { + sender.sendMessage(PlayerList.outputFormat(oConfigGroup, PlayerList.listUsers(ess, outputUserList, ", "))); + } + continue; + } + } + + outputUserList = PlayerList.getMergedList(ess, playerList, configGroup); + + // If we have no users, than we don't need to continue parsing this group + if (outputUserList == null || outputUserList.isEmpty()) + { + continue; + } + + sender.sendMessage(PlayerList.outputFormat(oConfigGroup, PlayerList.listUsers(ess, outputUserList, ", "))); + } + + String[] onlineGroups = playerList.keySet().toArray(new String[0]); + Arrays.sort(onlineGroups, String.CASE_INSENSITIVE_ORDER); + + // If we have an asterisk group, then merge all remaining groups + if (!asterisk.isEmpty()) + { + List asteriskUsers = new ArrayList(); + for (String onlineGroup : onlineGroups) + { + asteriskUsers.addAll(playerList.get(onlineGroup)); + } + for (String key : asterisk) + { + playerList.put(key, asteriskUsers); + } + onlineGroups = asterisk.toArray(new String[0]); + } + + // If we have any groups remaining after the custom groups loop through and display them + for (String onlineGroup : onlineGroups) + { + List users = playerList.get(onlineGroup); + String groupName = asterisk.isEmpty() ? users.get(0).getGroup() : onlineGroup; + + if (ess.getPermissionsHandler().getName().equals("ConfigPermissions")) + { + groupName = tl("connectedPlayers"); + } + if (users == null || users.isEmpty()) + { + continue; + } + + sender.sendMessage(PlayerList.outputFormat(groupName, PlayerList.listUsers(ess, users, ", "))); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandmail.java b/Essentials/src/com/earth2me/essentials/commands/Commandmail.java new file mode 100644 index 0000000000..0e4869df50 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandmail.java @@ -0,0 +1,177 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.textreader.IText; +import com.earth2me.essentials.textreader.SimpleTextInput; +import com.earth2me.essentials.textreader.SimpleTextPager; +import com.earth2me.essentials.textreader.TextPager; +import com.earth2me.essentials.utils.FormatUtil; +import com.earth2me.essentials.utils.StringUtil; +import org.bukkit.Server; + +import java.util.List; + +import java.util.UUID; + + +public class Commandmail extends EssentialsCommand +{ + private static int mailsPerMinute = 0; + private static long timestamp = 0; + + public Commandmail() + { + super("mail"); + } + + //TODO: Tidy this up / TL these errors. + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length >= 1 && "read".equalsIgnoreCase(args[0])) + { + final List mail = user.getMails(); + if (mail.isEmpty()) + { + user.sendMessage(tl("noMail")); + throw new NoChargeException(); + } + + IText input = new SimpleTextInput(mail); + final TextPager pager = new TextPager(input); + pager.showPage(args.length > 1 ? args[1] : null, null, commandLabel + " " + args[0], user.getSource()); + + user.sendMessage(tl("mailClear")); + return; + } + if (args.length >= 3 && "send".equalsIgnoreCase(args[0])) + { + if (!user.isAuthorized("essentials.mail.send")) + { + throw new Exception(tl("noPerm", "essentials.mail.send")); + } + + if (user.isMuted()) + { + throw new Exception(tl("voiceSilenced")); + } + + User u = getPlayer(server, args[1], true, true); + if (u == null) + { + throw new Exception(tl("playerNeverOnServer", args[1])); + } + + final String mail = tl("mailFormat", user.getName(), StringUtil.sanitizeString(FormatUtil.stripFormat(getFinalArg(args, 2)))); + if (mail.length() > 1000) + { + throw new Exception(tl("mailTooLong")); + } + + if (!u.isIgnoredPlayer(user)) + { + if (Math.abs(System.currentTimeMillis() - timestamp) > 60000) + { + timestamp = System.currentTimeMillis(); + mailsPerMinute = 0; + } + mailsPerMinute++; + if (mailsPerMinute > ess.getSettings().getMailsPerMinute()) + { + throw new Exception(tl("mailDelay", ess.getSettings().getMailsPerMinute())); + } + u.addMail(tl("mailMessage", mail)); + } + + user.sendMessage(tl("mailSentTo", u.getDisplayName(), u.getName())); + user.sendMessage(mail); + return; + } + if (args.length > 1 && "sendall".equalsIgnoreCase(args[0])) + { + if (!user.isAuthorized("essentials.mail.sendall")) + { + throw new Exception(tl("noPerm", "essentials.mail.sendall")); + } + ess.runTaskAsynchronously(new SendAll(tl("mailFormat", user.getName(), FormatUtil.stripFormat(getFinalArg(args, 1))))); + user.sendMessage(tl("mailSent")); + return; + } + if (args.length >= 1 && "clear".equalsIgnoreCase(args[0])) + { + user.setMails(null); + user.sendMessage(tl("mailCleared")); + return; + } + throw new NotEnoughArgumentsException(); + } + + @Override + protected void run(Server server, CommandSource sender, String commandLabel, String[] args) throws Exception + { + if (args.length >= 1 && "read".equalsIgnoreCase(args[0])) + { + throw new Exception(tl("onlyPlayers", commandLabel + " read")); + } + else if (args.length >= 1 && "clear".equalsIgnoreCase(args[0])) + { + throw new Exception(tl("onlyPlayers", commandLabel + " clear")); + } + else if (args.length >= 3 && "send".equalsIgnoreCase(args[0])) + { + User u = getPlayer(server, args[1], true, true); + if (u == null) + { + throw new Exception(tl("playerNeverOnServer", args[1])); + } + u.addMail(tl("mailFormat", "Server", getFinalArg(args, 2))); + sender.sendMessage(tl("mailSent")); + return; + } + else if (args.length >= 2 && "sendall".equalsIgnoreCase(args[0])) + { + ess.runTaskAsynchronously(new SendAll(tl("mailFormat", "Server", getFinalArg(args, 1)))); + sender.sendMessage(tl("mailSent")); + return; + } + else if (args.length >= 2) + { + //allow sending from console without "send" argument, since it's the only thing the console can do + User u = getPlayer(server, args[0], true, true); + if (u == null) + { + throw new Exception(tl("playerNeverOnServer", args[0])); + } + u.addMail(tl("mailFormat", "Server", getFinalArg(args, 1))); + sender.sendMessage(tl("mailSent")); + return; + } + throw new NotEnoughArgumentsException(); + } + + + private class SendAll implements Runnable + { + String message; + + public SendAll(String message) + { + this.message = message; + } + + @Override + public void run() + { + for (UUID userid : ess.getUserMap().getAllUniqueUsers()) + { + User user = ess.getUserMap().getUser(userid); + if (user != null) + { + user.addMail(message); + } + } + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandme.java b/Essentials/src/com/earth2me/essentials/commands/Commandme.java new file mode 100644 index 0000000000..6dadd0a9c4 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandme.java @@ -0,0 +1,50 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.FormatUtil; +import org.bukkit.Server; + + +public class Commandme extends EssentialsCommand +{ + public Commandme() + { + super("me"); + } + + @Override + public void run(Server server, User user, String commandLabel, String[] args) throws Exception + { + if (user.isMuted()) + { + throw new Exception(tl("voiceSilenced")); + } + + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + String message = getFinalArg(args, 0); + message = FormatUtil.formatMessage(user, "essentials.chat", message); + + user.setDisplayNick(); + ess.broadcastMessage(user, tl("action", user.getDisplayName(), message)); + } + + @Override + public void run(Server server, CommandSource sender, String commandLabel, String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + String message = getFinalArg(args, 0); + message = FormatUtil.replaceFormat(message); + + ess.getServer().broadcastMessage(tl("action", "@", message)); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandmore.java b/Essentials/src/com/earth2me/essentials/commands/Commandmore.java new file mode 100644 index 0000000000..f0fa43efc3 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandmore.java @@ -0,0 +1,50 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import java.util.Locale; +import org.bukkit.Server; +import org.bukkit.inventory.ItemStack; + + +public class Commandmore extends EssentialsCommand +{ + public Commandmore() + { + super("more"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + final ItemStack stack = user.getBase().getItemInHand(); + if (stack == null) + { + throw new Exception(tl("cantSpawnItem", "Air")); + } + if (stack.getAmount() >= ((user.isAuthorized("essentials.oversizedstacks")) + ? ess.getSettings().getOversizedStackSize() : stack.getMaxStackSize())) + { + throw new Exception(tl("fullStack")); + } + final String itemname = stack.getType().toString().toLowerCase(Locale.ENGLISH).replace("_", ""); + if (ess.getSettings().permissionBasedItemSpawn() + ? (!user.isAuthorized("essentials.itemspawn.item-all") + && !user.isAuthorized("essentials.itemspawn.item-" + itemname) + && !user.isAuthorized("essentials.itemspawn.item-" + stack.getTypeId())) + : (!user.isAuthorized("essentials.itemspawn.exempt") + && !user.canSpawnItem(stack.getTypeId()))) + { + throw new Exception(tl("cantSpawnItem", itemname)); + } + if (user.isAuthorized("essentials.oversizedstacks")) + { + stack.setAmount(ess.getSettings().getOversizedStackSize()); + } + else + { + stack.setAmount(stack.getMaxStackSize()); + } + user.getBase().updateInventory(); + } +} \ No newline at end of file diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandmotd.java b/Essentials/src/com/earth2me/essentials/commands/Commandmotd.java new file mode 100644 index 0000000000..58c8da6699 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandmotd.java @@ -0,0 +1,31 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import com.earth2me.essentials.textreader.IText; +import com.earth2me.essentials.textreader.KeywordReplacer; +import com.earth2me.essentials.textreader.TextInput; +import com.earth2me.essentials.textreader.TextPager; +import org.bukkit.Server; + + +public class Commandmotd extends EssentialsCommand +{ + public Commandmotd() + { + super("motd"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (sender.isPlayer()) + { + ess.getUser(sender.getPlayer()).setDisplayNick(); + } + + final IText input = new TextInput(sender, "motd", true, ess); + final IText output = new KeywordReplacer(input, sender, ess); + final TextPager pager = new TextPager(output); + pager.showPage(args.length > 0 ? args[0] : null, args.length > 1 ? args[1] : null, commandLabel, sender); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandmsg.java b/Essentials/src/com/earth2me/essentials/commands/Commandmsg.java new file mode 100644 index 0000000000..6427427305 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandmsg.java @@ -0,0 +1,86 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import com.earth2me.essentials.Console; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.IReplyTo; +import com.earth2me.essentials.User; +import static com.earth2me.essentials.commands.EssentialsCommand.getFinalArg; +import com.earth2me.essentials.utils.FormatUtil; +import org.bukkit.Server; +import org.bukkit.command.CommandSender; + + +public class Commandmsg extends EssentialsLoopCommand +{ + final String translatedMe = tl("me"); + + public Commandmsg() + { + super("msg"); + } + + @Override + public void run(Server server, CommandSource sender, String commandLabel, String[] args) throws Exception + { + if (args.length < 2 || args[0].trim().length() < 2 || args[1].trim().isEmpty()) + { + throw new NotEnoughArgumentsException(); + } + + String message = getFinalArg(args, 1); + boolean canWildcard; + if (sender.isPlayer()) + { + User user = ess.getUser(sender.getPlayer()); + if (user.isMuted()) + { + throw new Exception(tl("voiceSilenced")); + } + message = FormatUtil.formatMessage(user, "essentials.msg", message); + canWildcard = user.isAuthorized("essentials.msg.multiple"); + } + else + { + message = FormatUtil.replaceFormat(message); + canWildcard = true; + } + + if (args[0].equalsIgnoreCase(Console.NAME)) + { + final IReplyTo replyTo = sender.isPlayer() ? ess.getUser(sender.getPlayer()) : Console.getConsoleReplyTo(); + final String senderName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.NAME; + + sender.sendMessage(tl("msgFormat", translatedMe, Console.NAME, message)); + CommandSender cs = Console.getCommandSender(server); + cs.sendMessage(tl("msgFormat", senderName, translatedMe, message)); + replyTo.setReplyTo(new CommandSource(cs)); + Console.getConsoleReplyTo().setReplyTo(sender); + return; + } + + loopOnlinePlayers(server, sender, canWildcard, canWildcard, args[0], new String[]{message}); + } + + @Override + protected void updatePlayer(final Server server, final CommandSource sender, final User matchedUser, final String[] args) + { + final IReplyTo replyTo = sender.isPlayer() ? ess.getUser(sender.getPlayer()) : Console.getConsoleReplyTo(); + final String senderName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.NAME; + + if (matchedUser.isAfk()) + { + sender.sendMessage(tl("userAFK", matchedUser.getDisplayName())); + } + + sender.sendMessage(tl("msgFormat", translatedMe, matchedUser.getDisplayName(), args[0])); + if (sender.isPlayer() && matchedUser.isIgnoredPlayer(ess.getUser(sender.getPlayer()))) + { + return; + } + + matchedUser.sendMessage(tl("msgFormat", senderName, translatedMe, args[0])); + replyTo.setReplyTo(matchedUser.getSource()); + matchedUser.setReplyTo(sender); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandmute.java b/Essentials/src/com/earth2me/essentials/commands/Commandmute.java new file mode 100644 index 0000000000..fc44bc20c7 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandmute.java @@ -0,0 +1,95 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.OfflinePlayer; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.DateUtil; +import java.util.logging.Level; +import org.bukkit.Server; + + +public class Commandmute extends EssentialsCommand +{ + public Commandmute() + { + super("mute"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + boolean nomatch = false; + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + User user; + try + { + user = getPlayer(server, args, 0, true, true); + } + catch (PlayerNotFoundException e) + { + nomatch = true; + user = ess.getUser(new OfflinePlayer(args[0], ess.getServer())); + } + if (!user.getBase().isOnline()) + { + if (sender.isPlayer() && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.mute.offline")) + { + throw new Exception(tl("muteExemptOffline")); + } + } + else + { + if (user.isAuthorized("essentials.mute.exempt") && sender.isPlayer()) + { + throw new Exception(tl("muteExempt")); + } + } + + long muteTimestamp = 0; + + if (args.length > 1) + { + final String time = getFinalArg(args, 1); + muteTimestamp = DateUtil.parseDateDiff(time, true); + user.setMuted(true); + } + else + { + user.setMuted(!user.getMuted()); + } + user.setMuteTimeout(muteTimestamp); + final boolean muted = user.getMuted(); + String muteTime = DateUtil.formatDateDiff(muteTimestamp); + + if (nomatch) + { + sender.sendMessage(tl("userUnknown", user.getName())); + } + + if (muted) + { + if (muteTimestamp > 0) + { + sender.sendMessage(tl("mutedPlayerFor", user.getDisplayName(), muteTime)); + user.sendMessage(tl("playerMutedFor", muteTime)); + } + else + { + sender.sendMessage(tl("mutedPlayer", user.getDisplayName())); + user.sendMessage(tl("playerMuted")); + } + final String message = tl("muteNotify", sender.getSender().getName(), user.getName(), muteTime); + server.getLogger().log(Level.INFO, message); + ess.broadcastMessage("essentials.mute.notify", message); + } + else + { + sender.sendMessage(tl("unmutedPlayer", user.getDisplayName())); + user.sendMessage(tl("playerUnmuted")); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandnear.java b/Essentials/src/com/earth2me/essentials/commands/Commandnear.java new file mode 100644 index 0000000000..a31c220cab --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandnear.java @@ -0,0 +1,129 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.entity.Player; + + +public class Commandnear extends EssentialsCommand +{ + public Commandnear() + { + super("near"); + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + long maxRadius = ess.getSettings().getChatRadius(); + + if (maxRadius == 0) + { + maxRadius = 200; + } + + long radius = maxRadius; + + User otherUser = null; + + if (args.length > 0) + { + try + { + radius = Long.parseLong(args[0]); + } + catch (NumberFormatException e) + { + try + { + otherUser = getPlayer(server, user, args, 0); + } + catch (Exception ex) + { + } + } + if (args.length > 1 && otherUser != null) + { + try + { + radius = Long.parseLong(args[1]); + } + catch (NumberFormatException e) + { + } + } + } + + radius = Math.abs(radius); + + if (radius > maxRadius && !user.isAuthorized("essentials.near.maxexempt")) + { + user.sendMessage(tl("radiusTooBig", maxRadius)); + radius = maxRadius; + } + + if (otherUser == null || !user.isAuthorized("essentials.near.others")) + { + otherUser = user; + } + user.sendMessage(tl("nearbyPlayers", getLocal(server, otherUser, radius))); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length == 0) + { + throw new NotEnoughArgumentsException(); + } + final User otherUser = getPlayer(server, args, 0, true, false); + long radius = 200; + if (args.length > 1) + { + try + { + radius = Long.parseLong(args[1]); + } + catch (NumberFormatException e) + { + } + } + sender.sendMessage(tl("nearbyPlayers", getLocal(server, otherUser, radius))); + } + + private String getLocal(final Server server, final User user, final long radius) + { + final Location loc = user.getLocation(); + final World world = loc.getWorld(); + final StringBuilder output = new StringBuilder(); + final long radiusSquared = radius * radius; + boolean showHidden = user.canInteractVanished(); + + for (User player: ess.getOnlineUsers()) + { + if (!player.equals(user) && (!player.isHidden(user.getBase()) || showHidden || user.getBase().canSee(player.getBase()))) + { + final Location playerLoc = player.getLocation(); + if (playerLoc.getWorld() != world) + { + continue; + } + + final long delta = (long)playerLoc.distanceSquared(loc); + if (delta < radiusSquared) + { + if (output.length() > 0) + { + output.append(", "); + } + output.append(player.getDisplayName()).append("§f(§4").append((long)Math.sqrt(delta)).append("m§f)"); + } + } + } + return output.length() > 1 ? output.toString() : tl("none"); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandnick.java b/Essentials/src/com/earth2me/essentials/commands/Commandnick.java new file mode 100644 index 0000000000..fb8914fe4d --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandnick.java @@ -0,0 +1,143 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.FormatUtil; +import java.util.Locale; +import net.ess3.api.events.NickChangeEvent; +import org.bukkit.Server; +import org.bukkit.entity.Player; + + +public class Commandnick extends EssentialsLoopCommand +{ + public Commandnick() + { + super("nick"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + if (!ess.getSettings().changeDisplayName()) + { + throw new Exception(tl("nickDisplayName")); + } + + if (args.length > 1 && user.isAuthorized("essentials.nick.others")) + { + final String[] nickname = formatNickname(user, args[1]).split(" "); + loopOfflinePlayers(server, user.getSource(), false, true, args[0], nickname); + user.sendMessage(tl("nickChanged")); + } + else + { + final String[] nickname = formatNickname(user, args[0]).split(" "); + updatePlayer(server, user.getSource(), user, nickname); + } + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 2) + { + throw new NotEnoughArgumentsException(); + } + if (!ess.getSettings().changeDisplayName()) + { + throw new Exception(tl("nickDisplayName")); + } + final String[] nickname = formatNickname(null, args[1]).split(" "); + loopOfflinePlayers(server, sender, false, true, args[0], nickname); + sender.sendMessage(tl("nickChanged")); + } + + @Override + protected void updatePlayer(final Server server, final CommandSource sender, final User target, final String[] args) throws NotEnoughArgumentsException + { + final String nick = args[0]; + if (target.getName().equalsIgnoreCase(nick)) + { + String oldName = target.getDisplayName(); + setNickname(server, sender, target, nick); + if (!target.getDisplayName().equalsIgnoreCase(oldName)) + { + target.sendMessage(tl("nickNoMore")); + } + target.sendMessage(tl("nickSet", target.getDisplayName())); + } + else if ("off".equalsIgnoreCase(nick)) + { + setNickname(server, sender, target, null); + target.sendMessage(tl("nickNoMore")); + } + else if (nickInUse(server, target, nick)) + { + throw new NotEnoughArgumentsException(tl("nickInUse")); + } + else + { + setNickname(server, sender, target, nick); + target.sendMessage(tl("nickSet", target.getDisplayName())); + } + } + + private String formatNickname(final User user, final String nick) throws Exception + { + String newNick = user == null ? FormatUtil.replaceFormat(nick) : FormatUtil.formatString(user, "essentials.nick", nick); + if (!newNick.matches("^[a-zA-Z_0-9\u00a7]+$")) + { + throw new Exception(tl("nickNamesAlpha")); + } + else if (newNick.length() > ess.getSettings().getMaxNickLength()) + { + throw new Exception(tl("nickTooLong")); + } + else if (FormatUtil.stripFormat(newNick).length() < 1) + { + throw new Exception(tl("nickNamesAlpha")); + } + return newNick; + } + + private boolean nickInUse(final Server server, final User target, String nick) + { + final String lowerNick = FormatUtil.stripFormat(nick.toLowerCase(Locale.ENGLISH)); + for (final Player onlinePlayer : ess.getOnlinePlayers()) + { + if (target.getBase().getName().equals(onlinePlayer.getName())) + { + continue; + } + final String matchNick = FormatUtil.stripFormat(onlinePlayer.getDisplayName().replace(ess.getSettings().getNicknamePrefix(), "")); + if (lowerNick.equals(matchNick.toLowerCase(Locale.ENGLISH)) + || lowerNick.equals(onlinePlayer.getName().toLowerCase(Locale.ENGLISH))) + { + return true; + } + } + if (ess.getUser(lowerNick) != null && ess.getUser(lowerNick) != target) + { + return true; + } + return false; + } + + private void setNickname(final Server server, final CommandSource sender, final User target, final String nickname) + { + final User controller = sender.isPlayer() ? ess.getUser(sender.getPlayer()) : null; + final NickChangeEvent nickEvent = new NickChangeEvent(controller, target, nickname); + server.getPluginManager().callEvent(nickEvent); + if (!nickEvent.isCancelled()) + { + target.setNickname(nickname); + target.setDisplayNick(); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandnuke.java b/Essentials/src/com/earth2me/essentials/commands/Commandnuke.java new file mode 100644 index 0000000000..e82c46c8d9 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandnuke.java @@ -0,0 +1,59 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import java.util.ArrayList; +import java.util.Collection; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.entity.TNTPrimed; + + +public class Commandnuke extends EssentialsCommand +{ + public Commandnuke() + { + super("nuke"); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws NoSuchFieldException, NotEnoughArgumentsException + { + Collection targets; + if (args.length > 0) + { + targets = new ArrayList(); + int pos = 0; + for (String arg : args) + { + targets.add(getPlayer(server, sender, args, pos).getBase()); + pos++; + } + } + else + { + targets = ess.getOnlinePlayers(); + } + ess.getTNTListener().enable(); + for (Player player : targets) + { + if (player == null) + { + continue; + } + player.sendMessage(tl("nuke")); + final Location loc = player.getLocation(); + final World world = loc.getWorld(); + for (int x = -10; x <= 10; x += 5) + { + for (int z = -10; z <= 10; z += 5) + { + final Location tntloc = new Location(world, loc.getBlockX() + x, world.getHighestBlockYAt(loc) + 64, loc.getBlockZ() + z); + final TNTPrimed tnt = world.spawn(tntloc, TNTPrimed.class); + } + } + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandpay.java b/Essentials/src/com/earth2me/essentials/commands/Commandpay.java new file mode 100644 index 0000000000..a83df4ac71 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandpay.java @@ -0,0 +1,55 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.ChargeException; +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import java.math.BigDecimal; +import net.ess3.api.MaxMoneyException; +import org.bukkit.Server; + + +public class Commandpay extends EssentialsLoopCommand +{ + BigDecimal amount; + + public Commandpay() + { + super("pay"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 2) + { + throw new NotEnoughArgumentsException(); + } + + String stringAmount = args[1].replaceAll("[^0-9\\.]", ""); + + if (stringAmount.length() < 1) + { + throw new NotEnoughArgumentsException(); + } + + amount = new BigDecimal(stringAmount); + loopOnlinePlayers(server, user.getSource(), false, user.isAuthorized("essentials.pay.multiple"), args[0], args); + } + + @Override + protected void updatePlayer(final Server server, final CommandSource sender, final User player, final String[] args) throws ChargeException + { + User user = ess.getUser(sender.getPlayer()); + try + { + user.payUser(player, amount); + Trade.log("Command", "Pay", "Player", user.getName(), new Trade(amount, ess), player.getName(), new Trade(amount, ess), user.getLocation(), ess); + } + catch (MaxMoneyException ex) + { + sender.sendMessage(tl("maxMoney")); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandping.java b/Essentials/src/com/earth2me/essentials/commands/Commandping.java new file mode 100644 index 0000000000..1535ad6a21 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandping.java @@ -0,0 +1,29 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.utils.FormatUtil; +import org.bukkit.Server; + +// This command can be used to echo messages to the users screen, mostly useless but also an #EasterEgg +public class Commandping extends EssentialsCommand +{ + public Commandping() + { + super("ping"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + + sender.sendMessage(tl("pong")); + } + else + { + sender.sendMessage(FormatUtil.replaceFormat(getFinalArg(args, 0))); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandpotion.java b/Essentials/src/com/earth2me/essentials/commands/Commandpotion.java new file mode 100644 index 0000000000..108644649c --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandpotion.java @@ -0,0 +1,93 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.MetaItemStack; +import com.earth2me.essentials.Potions; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.StringUtil; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + + +public class Commandpotion extends EssentialsCommand +{ + public Commandpotion() + { + super("potion"); + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + final ItemStack stack = user.getBase().getItemInHand(); + + if (args.length == 0) + { + final Set potionslist = new TreeSet(); + for (Map.Entry entry : Potions.entrySet()) + { + final String potionName = entry.getValue().getName().toLowerCase(Locale.ENGLISH); + if (potionslist.contains(potionName) || (user.isAuthorized("essentials.potion." + potionName))) + { + potionslist.add(entry.getKey()); + } + } + throw new NotEnoughArgumentsException(tl("potions", StringUtil.joinList(potionslist.toArray()))); + } + + if (stack.getType() == Material.POTION) + { + PotionMeta pmeta = (PotionMeta)stack.getItemMeta(); + if (args.length > 0) + { + if (args[0].equalsIgnoreCase("clear")) + { + pmeta.clearCustomEffects(); + stack.setItemMeta(pmeta); + } + else if (args[0].equalsIgnoreCase("apply") && user.isAuthorized("essentials.potion.apply")) + { + for (PotionEffect effect : pmeta.getCustomEffects()) + { + effect.apply(user.getBase()); + } + } + else if (args.length < 3) + { + throw new NotEnoughArgumentsException(); + } + else + { + final MetaItemStack mStack = new MetaItemStack(stack); + for (String arg : args) + { + mStack.addPotionMeta(user.getSource(), true, arg, ess); + } + if (mStack.completePotion()) + { + pmeta = (PotionMeta)mStack.getItemStack().getItemMeta(); + stack.setItemMeta(pmeta); + } + else + { + user.sendMessage(tl("invalidPotion")); + throw new NotEnoughArgumentsException(); + } + } + } + + } + else + { + throw new Exception(tl("holdPotion")); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandpowertool.java b/Essentials/src/com/earth2me/essentials/commands/Commandpowertool.java new file mode 100644 index 0000000000..9c951395c0 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandpowertool.java @@ -0,0 +1,130 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.StringUtil; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.inventory.ItemStack; + + +public class Commandpowertool extends EssentialsCommand +{ + public Commandpowertool() + { + super("powertool"); + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + final String command = getFinalArg(args, 0); + final ItemStack itemStack = user.getBase().getItemInHand(); + powertool(server, user.getSource(), user, commandLabel, itemStack, command); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 3) //running from console means inserting a player and item before the standard syntax + { + throw new Exception("When running from console, usage is: /" + commandLabel + " "); + } + + final User user = getPlayer(server, args, 0, true, true); + final ItemStack itemStack = ess.getItemDb().get(args[1]); + final String command = getFinalArg(args, 2); + powertool(server, sender, user, commandLabel, itemStack, command); + } + + protected void powertool(final Server server, final CommandSource sender, final User user, final String commandLabel, final ItemStack itemStack, String command) throws Exception + { + // check to see if this is a clear all command + if (command != null && command.equalsIgnoreCase("d:")) + { + user.clearAllPowertools(); + sender.sendMessage(tl("powerToolClearAll")); + return; + } + + if (itemStack == null || itemStack.getType() == Material.AIR) + { + throw new Exception(tl("powerToolAir")); + } + + final String itemName = itemStack.getType().toString().toLowerCase(Locale.ENGLISH).replaceAll("_", " "); + List powertools = user.getPowertool(itemStack); + if (command != null && !command.isEmpty()) + { + if (command.equalsIgnoreCase("l:")) + { + if (powertools == null || powertools.isEmpty()) + { + throw new Exception(tl("powerToolListEmpty", itemName)); + } + else + { + sender.sendMessage(tl("powerToolList", StringUtil.joinList(powertools), itemName)); + } + throw new NoChargeException(); + } + if (command.startsWith("r:")) + { + command = command.substring(2); + if (!powertools.contains(command)) + { + throw new Exception(tl("powerToolNoSuchCommandAssigned", command, itemName)); + } + + powertools.remove(command); + sender.sendMessage(tl("powerToolRemove", command, itemName)); + } + else + { + if (command.startsWith("a:")) + { + if (sender.isPlayer() && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.powertool.append")) + { + throw new Exception(tl("noPerm", "essentials.powertool.append")); + } + command = command.substring(2); + if (powertools.contains(command)) + { + throw new Exception(tl("powerToolAlreadySet", command, itemName)); + } + } + else if (powertools != null && !powertools.isEmpty()) + { + // Replace all commands with this one + powertools.clear(); + } + else + { + powertools = new ArrayList(); + } + + powertools.add(command); + sender.sendMessage(tl("powerToolAttach", StringUtil.joinList(powertools), itemName)); + } + } + else + { + if (powertools != null) + { + powertools.clear(); + } + sender.sendMessage(tl("powerToolRemoveAll", itemName)); + } + + if (!user.arePowerToolsEnabled()) + { + user.setPowerToolsEnabled(true); + user.sendMessage(tl("powerToolsEnabled")); + } + user.setPowertool(itemStack, powertools); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandpowertooltoggle.java b/Essentials/src/com/earth2me/essentials/commands/Commandpowertooltoggle.java new file mode 100644 index 0000000000..a71f3887d1 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandpowertooltoggle.java @@ -0,0 +1,27 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Server; + + +public class Commandpowertooltoggle extends EssentialsCommand +{ + public Commandpowertooltoggle() + { + super("powertooltoggle"); + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (!user.hasPowerTools()) + { + user.sendMessage(tl("noPowerTools")); + return; + } + user.sendMessage(user.togglePowerToolsEnabled() + ? tl("powerToolsEnabled") + : tl("powerToolsDisabled")); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandptime.java b/Essentials/src/com/earth2me/essentials/commands/Commandptime.java new file mode 100644 index 0000000000..edb16d5d78 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandptime.java @@ -0,0 +1,246 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.DescParseTickFormat; +import java.util.*; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.entity.Player; + + +public class Commandptime extends EssentialsCommand +{ + private static final Set getAliases = new HashSet(); + + static + { + getAliases.add("get"); + getAliases.add("list"); + getAliases.add("show"); + getAliases.add("display"); + } + + public Commandptime() + { + super("ptime"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + // Which Players(s) / Users(s) are we interested in? + String userSelector = null; + if (args.length == 2) + { + userSelector = args[1]; + } + Set users = getUsers(server, sender, userSelector); + + // If no arguments we are reading the time + if (args.length == 0) + { + getUsersTime(sender, users); + return; + } + + if (sender.isPlayer()) + { + User user = ess.getUser(sender.getPlayer()); + if (user != null && (!users.contains(user) || users.size() > 1) && !user.isAuthorized("essentials.ptime.others")) + { + user.sendMessage(tl("pTimeOthersPermission")); + return; + } + } + + Long ticks; + // Parse the target time int ticks from args[0] + String timeParam = args[0]; + boolean relative = true; + if (timeParam.startsWith("@")) + { + relative = false; + timeParam = timeParam.substring(1); + } + + if (getAliases.contains(timeParam)) + { + getUsersTime(sender, users); + return; + } + else if (DescParseTickFormat.meansReset(timeParam)) + { + ticks = null; + } + else + { + try + { + ticks = DescParseTickFormat.parse(timeParam); + } + catch (NumberFormatException e) + { + throw new NotEnoughArgumentsException(e); + } + } + + setUsersTime(sender, users, ticks, relative); + } + + /** + * Used to get the time and inform + */ + private void getUsersTime(final CommandSource sender, final Collection users) + { + if (users.size() > 1) + { + sender.sendMessage(tl("pTimePlayers")); + } + + for (User user : users) + { + if (user.getBase().getPlayerTimeOffset() == 0) + { + sender.sendMessage(tl("pTimeNormal", user.getName())); + } + else + { + String time = DescParseTickFormat.format(user.getBase().getPlayerTime()); + if (!user.getBase().isPlayerTimeRelative()) + { + sender.sendMessage(tl("pTimeCurrentFixed", user.getName(), time)); + } + else + { + sender.sendMessage(tl("pTimeCurrent", user.getName(), time)); + } + } + } + } + + /** + * Used to set the time and inform of the change + */ + private void setUsersTime(final CommandSource sender, final Collection users, final Long ticks, Boolean relative) + { + // Update the time + if (ticks == null) + { + // Reset + for (User user : users) + { + user.getBase().resetPlayerTime(); + } + } + else + { + // Set + for (User user : users) + { + final World world = user.getWorld(); + long time = user.getBase().getPlayerTime(); + time -= time % 24000; + time += 24000 + ticks; + if (relative) + { + time -= world.getTime(); + } + user.getBase().setPlayerTime(time, relative); + } + } + + final StringBuilder msg = new StringBuilder(); + for (User user : users) + { + if (msg.length() > 0) + { + msg.append(", "); + } + + msg.append(user.getName()); + } + + // Inform the sender of the change + if (ticks == null) + { + sender.sendMessage(tl("pTimeReset", msg.toString())); + } + else + { + String time = DescParseTickFormat.format(ticks); + if (!relative) + { + sender.sendMessage(tl("pTimeSetFixed", time, msg.toString())); + } + else + { + sender.sendMessage(tl("pTimeSet", time, msg.toString())); + } + } + } + + /** + * Used to parse an argument of the type "users(s) selector" + */ + private Set getUsers(final Server server, final CommandSource sender, final String selector) throws Exception + { + final Set users = new TreeSet(new UserNameComparator()); + // If there is no selector we want the sender itself. Or all users if sender isn't a user. + if (selector == null) + { + if (sender.isPlayer()) + { + final User user = ess.getUser(sender.getPlayer()); + users.add(user); + } + else + { + for (User user : ess.getOnlineUsers()) + { + users.add(user); + } + } + return users; + } + + // Try to find the user with name = selector + User user = null; + final List matchedPlayers = server.matchPlayer(selector); + if (!matchedPlayers.isEmpty()) + { + user = ess.getUser(matchedPlayers.get(0)); + } + + if (user != null) + { + users.add(user); + } + // If that fails, Is the argument something like "*" or "all"? + else if (selector.equalsIgnoreCase("*") || selector.equalsIgnoreCase("all")) + { + for (User u : ess.getOnlineUsers()) + { + users.add(u); + } + } + // We failed to understand the world target... + else + { + throw new PlayerNotFoundException(); + } + + return users; + } +} + + +class UserNameComparator implements Comparator +{ + @Override + public int compare(User a, User b) + { + return a.getName().compareTo(b.getName()); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandpweather.java b/Essentials/src/com/earth2me/essentials/commands/Commandpweather.java new file mode 100644 index 0000000000..69e0295dc4 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandpweather.java @@ -0,0 +1,186 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import java.util.*; +import org.bukkit.Server; +import org.bukkit.WeatherType; +import org.bukkit.entity.Player; + + +public class Commandpweather extends EssentialsCommand +{ + public static final Set getAliases = new HashSet(); + public static final Map weatherAliases = new HashMap(); + + static + { + getAliases.add("get"); + getAliases.add("list"); + getAliases.add("show"); + getAliases.add("display"); + weatherAliases.put("sun", WeatherType.CLEAR); + weatherAliases.put("clear", WeatherType.CLEAR); + weatherAliases.put("storm", WeatherType.DOWNFALL); + weatherAliases.put("thunder", WeatherType.DOWNFALL); + } + + public Commandpweather() + { + super("pweather"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + // Which Players(s) / Users(s) are we interested in? + String userSelector = null; + if (args.length == 2) + { + userSelector = args[1]; + } + Set users = getUsers(server, sender, userSelector); + + if (args.length == 0) + { + getUsersWeather(sender, users); + return; + } + + if (getAliases.contains(args[0])) + { + getUsersWeather(sender, users); + return; + } + + if (sender.isPlayer()) + { + User user = ess.getUser(sender.getPlayer()); + if (user != null && (!users.contains(user) || users.size() > 1) && !user.isAuthorized("essentials.pweather.others")) + { + user.sendMessage(tl("pWeatherOthersPermission")); + return; + } + } + + setUsersWeather(sender, users, args[0].toLowerCase()); + } + + /** + * Used to get the time and inform + */ + private void getUsersWeather(final CommandSource sender, final Collection users) + { + if (users.size() > 1) + { + sender.sendMessage(tl("pWeatherPlayers")); + } + + for (User user : users) + { + if (user.getBase().getPlayerWeather() == null) + { + sender.sendMessage(tl("pWeatherNormal", user.getName())); + } + else + { + sender.sendMessage(tl("pWeatherCurrent", user.getName(), user.getBase().getPlayerWeather().toString().toLowerCase(Locale.ENGLISH))); + } + } + } + + /** + * Used to set the time and inform of the change + */ + private void setUsersWeather(final CommandSource sender, final Collection users, final String weatherType) throws Exception + { + + final StringBuilder msg = new StringBuilder(); + for (User user : users) + { + if (msg.length() > 0) + { + msg.append(", "); + } + + msg.append(user.getName()); + } + + if (weatherType.equalsIgnoreCase("reset")) + { + for (User user : users) + { + user.getBase().resetPlayerWeather(); + } + + sender.sendMessage(tl("pWeatherReset", msg)); + } + else + { + if (!weatherAliases.containsKey(weatherType)) + { + throw new NotEnoughArgumentsException(tl("pWeatherInvalidAlias")); + } + + for (User user : users) + { + user.getBase().setPlayerWeather(weatherAliases.get(weatherType)); + } + sender.sendMessage(tl("pWeatherSet", weatherType, msg.toString())); + } + } + + /** + * Used to parse an argument of the type "users(s) selector" + */ + private Set getUsers(final Server server, final CommandSource sender, final String selector) throws Exception + { + final Set users = new TreeSet(new UserNameComparator()); + // If there is no selector we want the sender itself. Or all users if sender isn't a user. + if (selector == null) + { + if (sender.isPlayer()) + { + final User user = ess.getUser(sender.getPlayer()); + users.add(user); + } + else + { + for (User user : ess.getOnlineUsers()) + { + users.add(user); + } + } + return users; + } + + // Try to find the user with name = selector + User user = null; + final List matchedPlayers = server.matchPlayer(selector); + if (!matchedPlayers.isEmpty()) + { + user = ess.getUser(matchedPlayers.get(0)); + } + + if (user != null) + { + users.add(user); + } + // If that fails, Is the argument something like "*" or "all"? + else if (selector.equalsIgnoreCase("*") || selector.equalsIgnoreCase("all")) + { + for (User u : ess.getOnlineUsers()) + { + users.add(u); + } + } + // We failed to understand the world target... + else + { + throw new PlayerNotFoundException(); + } + + return users; + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandr.java b/Essentials/src/com/earth2me/essentials/commands/Commandr.java new file mode 100644 index 0000000000..b79d10f1ee --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandr.java @@ -0,0 +1,77 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import com.earth2me.essentials.Console; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.IReplyTo; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.FormatUtil; +import org.bukkit.Server; + + +public class Commandr extends EssentialsCommand +{ + public Commandr() + { + super("r"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + String message = getFinalArg(args, 0); + IReplyTo replyTo; + String senderName; + + if (sender.isPlayer()) + { + User user = ess.getUser(sender.getPlayer()); + message = FormatUtil.formatMessage(user, "essentials.msg", message); + replyTo = user; + senderName = user.getDisplayName(); + } + else + { + message = FormatUtil.replaceFormat(message); + replyTo = Console.getConsoleReplyTo(); + senderName = Console.NAME; + } + + final CommandSource target = replyTo.getReplyTo(); + + if (target == null || (target.isPlayer() && !target.getPlayer().isOnline())) + { + throw new Exception(tl("foreverAlone")); + } + + final String targetName = target.isPlayer() ? target.getPlayer().getDisplayName() : Console.NAME; + + sender.sendMessage(tl("msgFormat", tl("me"), targetName, message)); + if (target.isPlayer()) + { + User player = ess.getUser(target.getPlayer()); + if (sender.isPlayer() && player.isIgnoredPlayer(ess.getUser(sender.getPlayer()))) + { + return; + } + } + target.sendMessage(tl("msgFormat", senderName, tl("me"), message)); + replyTo.setReplyTo(target); + if (target != sender) + { + if (target.isPlayer()) + { + ess.getUser(target.getPlayer()).setReplyTo(sender); + } + else + { + Console.getConsoleReplyTo().setReplyTo(sender); + } + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandrealname.java b/Essentials/src/com/earth2me/essentials/commands/Commandrealname.java new file mode 100644 index 0000000000..55cdadbfb7 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandrealname.java @@ -0,0 +1,48 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.FormatUtil; +import java.util.Locale; +import org.bukkit.Server; +import org.bukkit.entity.Player; + + +public class Commandrealname extends EssentialsCommand +{ + public Commandrealname() + { + super("realname"); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + final String whois = args[0].toLowerCase(Locale.ENGLISH); + boolean skipHidden = sender.isPlayer() && !ess.getUser(sender.getPlayer()).canInteractVanished(); + boolean foundUser = false; + for (User u: ess.getOnlineUsers()) + { + if (skipHidden && u.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(u.getBase())) + { + continue; + } + u.setDisplayNick(); + final String displayName = FormatUtil.stripFormat(u.getDisplayName()).toLowerCase(Locale.ENGLISH); + if (displayName.contains(whois)) + { + foundUser = true; + sender.sendMessage(u.getDisplayName() + " " + tl("is") + " " + u.getName()); + } + } + if (!foundUser) + { + throw new PlayerNotFoundException(); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandrecipe.java b/Essentials/src/com/earth2me/essentials/commands/Commandrecipe.java new file mode 100755 index 0000000000..ec4fa896f5 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandrecipe.java @@ -0,0 +1,202 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.NumberUtil; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.inventory.*; + + +public class Commandrecipe extends EssentialsCommand +{ + public Commandrecipe() + { + super("recipe"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + final ItemStack itemType = ess.getItemDb().get(args[0]); + int recipeNo = 0; + + if (args.length > 1) + { + if (NumberUtil.isInt(args[1])) + { + recipeNo = Integer.parseInt(args[1]) - 1; + } + else + { + throw new Exception(tl("invalidNumber")); + } + } + + final List recipesOfType = ess.getServer().getRecipesFor(itemType); + if (recipesOfType.size() < 1) + { + throw new Exception(tl("recipeNone", getMaterialName(itemType))); + } + + if (recipeNo < 0 || recipeNo >= recipesOfType.size()) + { + throw new Exception(tl("recipeBadIndex")); + } + + final Recipe selectedRecipe = recipesOfType.get(recipeNo); + sender.sendMessage(tl("recipe", getMaterialName(itemType), recipeNo + 1, recipesOfType.size())); + + if (selectedRecipe instanceof FurnaceRecipe) + { + furnaceRecipe(sender, (FurnaceRecipe)selectedRecipe); + } + else if (selectedRecipe instanceof ShapedRecipe) + { + shapedRecipe(sender, (ShapedRecipe)selectedRecipe, sender.isPlayer()); + } + else if (selectedRecipe instanceof ShapelessRecipe) + { + if (recipesOfType.size() == 1 && itemType.getType() == Material.FIREWORK) + { + ShapelessRecipe shapelessRecipe = new ShapelessRecipe(itemType); + shapelessRecipe.addIngredient(Material.SULPHUR); + shapelessRecipe.addIngredient(Material.PAPER); + shapelessRecipe.addIngredient(Material.FIREWORK_CHARGE); + shapelessRecipe(sender, shapelessRecipe, sender.isPlayer()); + } + else + { + shapelessRecipe(sender, (ShapelessRecipe)selectedRecipe, sender.isPlayer()); + } + } + + if (recipesOfType.size() > 1 && args.length == 1) + { + sender.sendMessage(tl("recipeMore", commandLabel, args[0], getMaterialName(itemType))); + } + } + + public void furnaceRecipe(final CommandSource sender, final FurnaceRecipe recipe) + { + sender.sendMessage(tl("recipeFurnace", getMaterialName(recipe.getInput()))); + } + + public void shapedRecipe(final CommandSource sender, final ShapedRecipe recipe, final boolean showWindow) + { + final Map recipeMap = recipe.getIngredientMap(); + + if (showWindow) + { + final User user = ess.getUser(sender.getPlayer()); + user.getBase().closeInventory(); + user.setRecipeSee(true); + final InventoryView view = user.getBase().openWorkbench(null, true); + final String[] recipeShape = recipe.getShape(); + final Map ingredientMap = recipe.getIngredientMap(); + for (int j = 0; j < recipeShape.length; j++) + { + for (int k = 0; k < recipeShape[j].length(); k++) + { + final ItemStack item = ingredientMap.get(recipeShape[j].toCharArray()[k]); + if (item == null) + { + continue; + } + item.setAmount(0); + view.getTopInventory().setItem(j * 3 + k + 1, item); + } + } + } + else + { + final HashMap colorMap = new HashMap(); + int i = 1; + for (Character c : "abcdefghi".toCharArray()) + { + ItemStack item = recipeMap.get(c); + if (!colorMap.containsKey(item == null ? null : item.getType())) + { + colorMap.put(item == null ? null : item.getType(), String.valueOf(i++)); + } + } + final Material[][] materials = new Material[3][3]; + for (int j = 0; j < recipe.getShape().length; j++) + { + for (int k = 0; k < recipe.getShape()[j].length(); k++) + { + ItemStack item = recipe.getIngredientMap().get(recipe.getShape()[j].toCharArray()[k]); + materials[j][k] = item == null ? null : item.getType(); + } + } + sender.sendMessage(tl("recipeGrid", colorMap.get(materials[0][0]), colorMap.get(materials[0][1]), colorMap.get(materials[0][2]))); + sender.sendMessage(tl("recipeGrid", colorMap.get(materials[1][0]), colorMap.get(materials[1][1]), colorMap.get(materials[1][2]))); + sender.sendMessage(tl("recipeGrid", colorMap.get(materials[2][0]), colorMap.get(materials[2][1]), colorMap.get(materials[2][2]))); + + StringBuilder s = new StringBuilder(); + for (Material items : colorMap.keySet().toArray(new Material[colorMap.size()])) + { + s.append(tl("recipeGridItem", colorMap.get(items), getMaterialName(items))); + } + sender.sendMessage(tl("recipeWhere", s.toString())); + } + } + + public void shapelessRecipe(final CommandSource sender, final ShapelessRecipe recipe, final boolean showWindow) + { + final List ingredients = recipe.getIngredientList(); + if (showWindow) + { + final User user = ess.getUser(sender.getPlayer()); + user.setRecipeSee(true); + final InventoryView view = user.getBase().openWorkbench(null, true); + for (int i = 0; i < ingredients.size(); i++) + { + view.setItem(i + 1, ingredients.get(i)); + } + + } + else + { + StringBuilder s = new StringBuilder(); + for (int i = 0; i < ingredients.size(); i++) + { + s.append(getMaterialName(ingredients.get(i))); + if (i != ingredients.size() - 1) + { + s.append(","); + } + s.append(" "); + } + sender.sendMessage(tl("recipeShapeless", s.toString())); + } + } + + public String getMaterialName(final ItemStack stack) + { + if (stack == null) + { + return tl("recipeNothing"); + } + return getMaterialName(stack.getType()); + } + + public String getMaterialName(final Material type) + { + if (type == null) + { + return tl("recipeNothing"); + } + return type.toString().replace("_", " ").toLowerCase(Locale.ENGLISH); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandremove.java b/Essentials/src/com/earth2me/essentials/commands/Commandremove.java new file mode 100644 index 0000000000..ef9d3c6af2 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandremove.java @@ -0,0 +1,326 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Mob; +import com.earth2me.essentials.User; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import org.bukkit.Chunk; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.entity.*; + +// This could be rewritten in a simpler form if we made a mapping of all Entity names to their types (which would also provide possible mod support) + +public class Commandremove extends EssentialsCommand +{ + public Commandremove() + { + super("remove"); + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + World world = user.getWorld(); + int radius = 0; + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + if (args.length >= 2) + { + try + { + radius = Integer.parseInt(args[1]); + } + catch (NumberFormatException e) + { + world = ess.getWorld(args[1]); + } + } + if (args.length >= 3) + { + // This is to prevent breaking the old syntax + radius = 0; + world = ess.getWorld(args[2]); + } + parseCommand(server, user.getSource(), args, world, radius); + + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 2) + { + throw new NotEnoughArgumentsException(); + } + World world = ess.getWorld(args[1]); + parseCommand(server, sender, args, world, 0); + } + + private void parseCommand(Server server, CommandSource sender, String[] args, World world, int radius) throws Exception + { + List types = new ArrayList(); + List customTypes = new ArrayList(); + + if (world == null) + { + throw new Exception(tl("invalidWorld")); + } + + if (args[0].contentEquals("*") || args[0].contentEquals("all")) + { + types.add(0, "ALL"); + } + else + { + for (String entityType : args[0].split(",")) + { + ToRemove toRemove; + try + { + toRemove = ToRemove.valueOf(entityType.toUpperCase(Locale.ENGLISH)); + } + catch (Exception e) + { + try + { + toRemove = ToRemove.valueOf(entityType.concat("S").toUpperCase(Locale.ENGLISH)); + } + catch (Exception ee) + { + toRemove = ToRemove.CUSTOM; + customTypes.add(entityType); + } + } + types.add(toRemove.toString()); + } + } + removeHandler(sender, types, customTypes, world, radius); + } + + private void removeHandler(CommandSource sender, List types, List customTypes, World world, int radius) + { + int removed = 0; + if (radius > 0) + { + radius *= radius; + } + + ArrayList removeTypes = new ArrayList(); + ArrayList customRemoveTypes = new ArrayList(); + + for (String s : types) + { + removeTypes.add(ToRemove.valueOf(s)); + } + + boolean warnUser = false; + + for (String s : customTypes) + { + Mob mobType = Mob.fromName(s); + if (mobType == null) + { + warnUser = true; + } + else + { + customRemoveTypes.add(mobType); + } + } + + if (warnUser) + { + sender.sendMessage(tl("invalidMob")); + } + + for (Chunk chunk : world.getLoadedChunks()) + { + for (Entity e : chunk.getEntities()) + { + if (radius > 0) + { + if (sender.getPlayer().getLocation().distanceSquared(e.getLocation()) > radius) + { + continue; + } + } + if (e instanceof HumanEntity) + { + continue; + } + + for (ToRemove toRemove : removeTypes) + { + + // We should skip any TAMED animals unless we are specifially targetting them. + if (e instanceof Tameable && ((Tameable)e).isTamed() + && !removeTypes.contains(ToRemove.TAMED)) + { + continue; + } + + // We should skip any NAMED animals unless we are specifially targetting them. + if (e instanceof LivingEntity && ((LivingEntity)e).getCustomName() != null + && !removeTypes.contains(ToRemove.NAMED)) + { + continue; + } + + switch (toRemove) + { + case TAMED: + if (e instanceof Tameable && ((Tameable)e).isTamed()) + { + e.remove(); + removed++; + } + break; + case NAMED: + if (e instanceof LivingEntity && ((LivingEntity)e).getCustomName() != null) + { + e.remove(); + removed++; + } + break; + case DROPS: + if (e instanceof Item) + { + e.remove(); + removed++; + } + break; + case ARROWS: + if (e instanceof Projectile) + { + e.remove(); + removed++; + } + break; + case BOATS: + if (e instanceof Boat) + { + e.remove(); + removed++; + } + break; + case MINECARTS: + if (e instanceof Minecart) + { + e.remove(); + removed++; + } + break; + case XP: + if (e instanceof ExperienceOrb) + { + e.remove(); + removed++; + } + break; + case PAINTINGS: + if (e instanceof Painting) + { + e.remove(); + removed++; + } + break; + case ITEMFRAMES: + if (e instanceof ItemFrame) + { + e.remove(); + removed++; + } + break; + case ENDERCRYSTALS: + if (e instanceof EnderCrystal) + { + e.remove(); + removed++; + } + break; + case AMBIENT: + if (e instanceof Flying) + { + e.remove(); + removed++; + } + break; + case HOSTILE: + case MONSTERS: + if (e instanceof Monster || e instanceof ComplexLivingEntity || e instanceof Flying || e instanceof Slime) + { + e.remove(); + removed++; + } + break; + case PASSIVE: + case ANIMALS: + if (e instanceof Animals || e instanceof NPC || e instanceof Snowman || e instanceof WaterMob || e instanceof Ambient) + { + e.remove(); + removed++; + } + break; + case MOBS: + if (e instanceof Animals || e instanceof NPC || e instanceof Snowman || e instanceof WaterMob + || e instanceof Monster || e instanceof ComplexLivingEntity || e instanceof Flying || e instanceof Slime || e instanceof Ambient) + { + e.remove(); + removed++; + } + break; + case ENTITIES: + case ALL: + if (e instanceof Entity) + { + e.remove(); + removed++; + } + break; + case CUSTOM: + for (Mob type : customRemoveTypes) + { + if (e.getType() == type.getType()) + { + e.remove(); + removed++; + } + } + break; + } + } + } + } + sender.sendMessage(tl("removed", removed)); + } + + + private enum ToRemove + { + DROPS, + ARROWS, + BOATS, + MINECARTS, + XP, + PAINTINGS, + ITEMFRAMES, + ENDERCRYSTALS, + HOSTILE, + MONSTERS, + PASSIVE, + ANIMALS, + AMBIENT, + MOBS, + ENTITIES, + ALL, + CUSTOM, + TAMED, + NAMED + } +} \ No newline at end of file diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandrepair.java b/Essentials/src/com/earth2me/essentials/commands/Commandrepair.java new file mode 100644 index 0000000000..f0b503d2df --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandrepair.java @@ -0,0 +1,151 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.*; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.utils.StringUtil; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import net.ess3.api.IUser; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.inventory.ItemStack; + + +public class Commandrepair extends EssentialsCommand +{ + public Commandrepair() + { + super("repair"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1 || args[0].equalsIgnoreCase("hand") || !user.isAuthorized("essentials.repair.all")) + { + repairHand(user); + } + else if (args[0].equalsIgnoreCase("all")) + { + final Trade charge = new Trade("repair-all", ess); + charge.isAffordableFor(user); + repairAll(user); + charge.charge(user); + } + else + { + throw new NotEnoughArgumentsException(); + } + } + + public void repairHand(User user) throws Exception + { + final ItemStack item = user.getBase().getItemInHand(); + if (item == null || item.getType().isBlock() || item.getDurability() == 0) + { + throw new Exception(tl("repairInvalidType")); + } + + if (!item.getEnchantments().isEmpty() + && !ess.getSettings().getRepairEnchanted() + && !user.isAuthorized("essentials.repair.enchanted")) + { + throw new Exception(tl("repairEnchanted")); + } + + final String itemName = item.getType().toString().toLowerCase(Locale.ENGLISH); + final Trade charge = new Trade("repair-" + itemName.replace('_', '-'), new Trade("repair-" + item.getTypeId(), new Trade("repair-item", ess), ess), ess); + + charge.isAffordableFor(user); + + repairItem(item); + + charge.charge(user); + user.getBase().updateInventory(); + user.sendMessage(tl("repair", itemName.replace('_', ' '))); + } + + public void repairAll(User user) throws Exception + { + final List repaired = new ArrayList(); + repairItems(user.getBase().getInventory().getContents(), user, repaired); + + if (user.isAuthorized("essentials.repair.armor")) + { + repairItems(user.getBase().getInventory().getArmorContents(), user, repaired); + } + + user.getBase().updateInventory(); + if (repaired.isEmpty()) + { + throw new Exception(tl("repairNone")); + } + else + { + user.sendMessage(tl("repair", StringUtil.joinList(repaired))); + } + } + + private void repairItem(final ItemStack item) throws Exception + { + final Material material = Material.getMaterial(item.getTypeId()); + if (material.isBlock() || material.getMaxDurability() < 1) + { + throw new Exception(tl("repairInvalidType")); + } + + if (item.getDurability() == 0) + { + throw new Exception(tl("repairAlreadyFixed")); + } + + item.setDurability((short)0); + } + + private void repairItems(final ItemStack[] items, final IUser user, final List repaired) + { + for (ItemStack item : items) + { + if (item == null || item.getType().isBlock() || item.getDurability() == 0) + { + continue; + } + final String itemName = item.getType().toString().toLowerCase(Locale.ENGLISH); + final Trade charge = new Trade("repair-" + itemName.replace('_', '-'), new Trade("repair-" + item.getTypeId(), new Trade("repair-item", ess), ess), ess); + try + { + charge.isAffordableFor(user); + } + catch (ChargeException ex) + { + user.sendMessage(ex.getMessage()); + continue; + } + if (!item.getEnchantments().isEmpty() + && !ess.getSettings().getRepairEnchanted() + && !user.isAuthorized("essentials.repair.enchanted")) + { + continue; + } + + try + { + repairItem(item); + } + catch (Exception e) + { + continue; + } + try + { + charge.charge(user); + } + catch (ChargeException ex) + { + user.sendMessage(ex.getMessage()); + } + repaired.add(itemName.replace('_', ' ')); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandrules.java b/Essentials/src/com/earth2me/essentials/commands/Commandrules.java new file mode 100644 index 0000000000..f9a109a517 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandrules.java @@ -0,0 +1,31 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import com.earth2me.essentials.textreader.IText; +import com.earth2me.essentials.textreader.KeywordReplacer; +import com.earth2me.essentials.textreader.TextInput; +import com.earth2me.essentials.textreader.TextPager; +import org.bukkit.Server; + + +public class Commandrules extends EssentialsCommand +{ + public Commandrules() + { + super("rules"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (sender.isPlayer()) + { + ess.getUser(sender.getPlayer()).setDisplayNick(); + } + + final IText input = new TextInput(sender, "rules", true, ess); + final IText output = new KeywordReplacer(input, sender, ess); + final TextPager pager = new TextPager(output); + pager.showPage(args.length > 0 ? args[0] : null, args.length > 1 ? args[1] : null, commandLabel, sender); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandseen.java b/Essentials/src/com/earth2me/essentials/commands/Commandseen.java new file mode 100644 index 0000000000..fd4ad69b17 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandseen.java @@ -0,0 +1,237 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.UserMap; +import com.earth2me.essentials.craftbukkit.BanLookup; +import com.earth2me.essentials.utils.DateUtil; +import com.earth2me.essentials.utils.FormatUtil; +import com.earth2me.essentials.utils.StringUtil; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import org.bukkit.BanList; +import java.util.UUID; +import org.bukkit.BanEntry; +import org.bukkit.Location; +import org.bukkit.Server; + + +public class Commandseen extends EssentialsCommand +{ + public Commandseen() + { + super("seen"); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + seen(server, sender, args, true, true, true); + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + seen(server, user.getSource(), args, user.isAuthorized("essentials.seen.banreason"), user.isAuthorized("essentials.seen.extra"), user.isAuthorized("essentials.seen.ipsearch")); + } + + protected void seen(final Server server, final CommandSource sender, final String[] args, final boolean showBan, final boolean extra, final boolean ipLookup) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + User player = ess.getOfflineUser(args[0]); + if (player == null) + { + if (ipLookup && FormatUtil.validIP(args[0])) + { + seenIP(server, sender, args[0]); + return; + } + else if (ess.getServer().getBanList(BanList.Type.IP).isBanned(args[0])) + { + sender.sendMessage(tl("isIpBanned", args[0])); + return; + } + else if (BanLookup.isBanned(ess, args[0])) + { + sender.sendMessage(tl("whoisBanned", showBan ? BanLookup.getBanEntry(ess, args[0]).getReason() : tl("true"))); + return; + } + else + { + try + { + player = getPlayer(server, sender, args, 0); + } + catch (NoSuchFieldException e) + { + throw new PlayerNotFoundException(); + } + } + } + if (player.getBase().isOnline() && canInteractWith(sender, player)) + { + seenOnline(server, sender, player, showBan, extra); + } + else + { + seenOffline(server, sender, player, showBan, extra); + } + + } + + private void seenOnline(final Server server, final CommandSource sender, final User user, final boolean showBan, final boolean extra) throws Exception + { + + user.setDisplayNick(); + sender.sendMessage(tl("seenOnline", user.getDisplayName(), DateUtil.formatDateDiff(user.getLastLogin()))); + + if (ess.getSettings().isDebug()) + { + ess.getLogger().info("UUID: " + user.getBase().getUniqueId().toString()); + } + + List history = ess.getUserMap().getUserHistory(user.getBase().getUniqueId()); + if (history != null && history.size() > 1) + { + sender.sendMessage(tl("seenAccounts", StringUtil.joinListSkip(", ", user.getName(), history))); + } + + if (user.isAfk()) + { + sender.sendMessage(tl("whoisAFK", tl("true"))); + } + if (user.isJailed()) + { + sender.sendMessage(tl("whoisJail", (user.getJailTimeout() > 0 + ? DateUtil.formatDateDiff(user.getJailTimeout()) + : tl("true")))); + } + if (user.isMuted()) + { + sender.sendMessage(tl("whoisMuted", (user.getMuteTimeout() > 0 + ? DateUtil.formatDateDiff(user.getMuteTimeout()) + : tl("true")))); + } + final String location = user.getGeoLocation(); + if (location != null && (!(sender.isPlayer()) || ess.getUser(sender.getPlayer()).isAuthorized("essentials.geoip.show"))) + { + sender.sendMessage(tl("whoisGeoLocation", location)); + } + if (extra) + { + sender.sendMessage(tl("whoisIPAddress", user.getBase().getAddress().getAddress().toString())); + } + } + + private void seenOffline(final Server server, final CommandSource sender, User user, final boolean showBan, final boolean extra) throws Exception + { + user.setDisplayNick(); + if (user.getLastLogout() > 0) + { + sender.sendMessage(tl("seenOffline", user.getName(), DateUtil.formatDateDiff(user.getLastLogout()))); + } + else + { + sender.sendMessage(tl("userUnknown", user.getName())); + } + + if (ess.getSettings().isDebug()) + { + ess.getLogger().info("UUID: " + user.getBase().getUniqueId().toString()); + } + + List history = ess.getUserMap().getUserHistory(user.getBase().getUniqueId()); + if (history != null && history.size() > 1) + { + sender.sendMessage(tl("seenAccounts", StringUtil.joinListSkip(", ", user.getName(), history))); + } + + if (BanLookup.isBanned(ess, user)) + { + final BanEntry banEntry = BanLookup.getBanEntry(ess, user.getName()); + final String reason = showBan ? banEntry.getReason() : tl("true"); + sender.sendMessage(tl("whoisBanned", reason)); + if (banEntry.getExpiration() != null) + { + Date expiry = banEntry.getExpiration(); + String expireString = tl("now"); + if (expiry.after(new Date())) + { + expireString = DateUtil.formatDateDiff(expiry.getTime()); + } + sender.sendMessage(tl("whoisTempBanned", expireString)); + } + } + + final String location = user.getGeoLocation(); + if (location != null && (!(sender.isPlayer()) || ess.getUser(sender.getPlayer()).isAuthorized("essentials.geoip.show"))) + { + sender.sendMessage(tl("whoisGeoLocation", location)); + } + if (extra) + { + if (!user.getLastLoginAddress().isEmpty()) + { + sender.sendMessage(tl("whoisIPAddress", user.getLastLoginAddress())); + } + final Location loc = user.getLogoutLocation(); + if (loc != null) + { + sender.sendMessage(tl("whoisLocation", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); + } + } + } + + private void seenIP(final Server server, final CommandSource sender, final String ipAddress) throws Exception + { + final UserMap userMap = ess.getUserMap(); + + if (ess.getServer().getBanList(BanList.Type.IP).isBanned(ipAddress)) + { + sender.sendMessage(tl("isIpBanned", ipAddress)); + } + + sender.sendMessage(tl("runningPlayerMatch", ipAddress)); + + ess.runTaskAsynchronously(new Runnable() + { + @Override + public void run() + { + final List matches = new ArrayList(); + for (final UUID u : userMap.getAllUniqueUsers()) + { + final User user = ess.getUserMap().getUser(u); + if (user == null) + { + continue; + } + + final String uIPAddress = user.getLastLoginAddress(); + + if (!uIPAddress.isEmpty() && uIPAddress.equalsIgnoreCase(ipAddress)) + { + matches.add(user.getName()); + } + } + + if (matches.size() > 0) + { + sender.sendMessage(tl("matchingIPAddress")); + sender.sendMessage(StringUtil.joinList(matches)); + } + else + { + sender.sendMessage(tl("noMatchingPlayers")); + } + + } + }); + + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandsell.java b/Essentials/src/com/earth2me/essentials/commands/Commandsell.java new file mode 100644 index 0000000000..aa5eea1257 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandsell.java @@ -0,0 +1,111 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.NumberUtil; +import java.math.BigDecimal; +import java.util.List; +import java.util.Locale; +import java.util.logging.Level; +import org.bukkit.Server; +import org.bukkit.inventory.ItemStack; + + +public class Commandsell extends EssentialsCommand +{ + public Commandsell() + { + super("sell"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + BigDecimal totalWorth = BigDecimal.ZERO; + String type = ""; + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + List is = ess.getItemDb().getMatching(user, args); + int count = 0; + + boolean isBulk = is.size() > 1; + + for (ItemStack stack : is) + { + try + { + if (stack.getAmount() > 0) + { + totalWorth = totalWorth.add(sellItem(user, stack, args, isBulk)); + stack = stack.clone(); + count++; + for (ItemStack zeroStack : is) + { + if (zeroStack.isSimilar(stack)) + { + zeroStack.setAmount(0); + } + } + } + } + catch (Exception e) + { + if (!isBulk) + { + throw e; + } + } + } + if (count != 1) + { + if (args[0].equalsIgnoreCase("blocks")) + { + user.sendMessage(tl("totalWorthBlocks", type, NumberUtil.displayCurrency(totalWorth, ess))); + } + else + { + user.sendMessage(tl("totalWorthAll", type, NumberUtil.displayCurrency(totalWorth, ess))); + } + } + } + + private BigDecimal sellItem(User user, ItemStack is, String[] args, boolean isBulkSell) throws Exception + { + int amount = ess.getWorth().getAmount(ess, user, is, args, isBulkSell); + BigDecimal worth = ess.getWorth().getPrice(is); + + if (worth == null) + { + throw new Exception(tl("itemCannotBeSold")); + } + + if (amount <= 0) + { + if (!isBulkSell) { + user.sendMessage(tl("itemSold", NumberUtil.displayCurrency(BigDecimal.ZERO, ess), BigDecimal.ZERO, is.getType().toString().toLowerCase(Locale.ENGLISH), NumberUtil.displayCurrency(worth, ess))); + } + return BigDecimal.ZERO; + } + + BigDecimal result = worth.multiply(BigDecimal.valueOf(amount)); + + //TODO: Prices for Enchantments + final ItemStack ris = is.clone(); + ris.setAmount(amount); + if (!user.getBase().getInventory().containsAtLeast(ris, amount)) + { + // This should never happen. + throw new IllegalStateException("Trying to remove more items than are available."); + } + user.getBase().getInventory().removeItem(ris); + user.getBase().updateInventory(); + Trade.log("Command", "Sell", "Item", user.getName(), new Trade(ris, ess), user.getName(), new Trade(result, ess), user.getLocation(), ess); + user.giveMoney(result); + user.sendMessage(tl("itemSold", NumberUtil.displayCurrency(result, ess), amount, is.getType().toString().toLowerCase(Locale.ENGLISH), NumberUtil.displayCurrency(worth, ess))); + logger.log(Level.INFO, tl("itemSoldConsole", user.getDisplayName(), is.getType().toString().toLowerCase(Locale.ENGLISH), NumberUtil.displayCurrency(result, ess), amount, NumberUtil.displayCurrency(worth, ess))); + return result; + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandsethome.java b/Essentials/src/com/earth2me/essentials/commands/Commandsethome.java new file mode 100644 index 0000000000..866a15c1e8 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandsethome.java @@ -0,0 +1,91 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.LocationUtil; +import com.earth2me.essentials.utils.NumberUtil; +import java.util.Locale; +import org.bukkit.Location; +import org.bukkit.Server; + + +public class Commandsethome extends EssentialsCommand +{ + public Commandsethome() + { + super("sethome"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, String[] args) throws Exception + { + User usersHome = user; + String name = "home"; + final Location location = user.getLocation(); + + if (args.length > 0) + { + //Allowing both formats /sethome khobbits house | /sethome khobbits:house + final String[] nameParts = args[0].split(":"); + if (nameParts[0].length() != args[0].length()) + { + args = nameParts; + } + + if (args.length < 2) + { + name = args[0].toLowerCase(Locale.ENGLISH); + } + else + { + name = args[1].toLowerCase(Locale.ENGLISH); + if (user.isAuthorized("essentials.sethome.others")) + { + usersHome = getPlayer(server, args[0], true, true); + if (usersHome == null) + { + throw new PlayerNotFoundException(); + } + } + } + } + if (checkHomeLimit(user, usersHome, name)) + { + name = "home"; + } + if ("bed".equals(name) || NumberUtil.isInt(name)) + { + throw new NoSuchFieldException(tl("invalidHomeName")); + } + + if (!ess.getSettings().isTeleportSafetyEnabled() && LocationUtil.isBlockUnsafeForUser(usersHome, location.getWorld(), location.getBlockX(), location.getBlockY(), location.getBlockZ())) + { + throw new Exception(tl("unsafeTeleportDestination", location.getWorld().getName(), location.getBlockX(), location.getBlockY(), location.getBlockZ())); + } + + usersHome.setHome(name, location); + user.sendMessage(tl("homeSet", user.getLocation().getWorld().getName(), user.getLocation().getBlockX(), user.getLocation().getBlockY(), user.getLocation().getBlockZ(), name)); + + } + + private boolean checkHomeLimit(final User user, final User usersHome, String name) throws Exception + { + if (!user.isAuthorized("essentials.sethome.multiple.unlimited")) + { + int limit = ess.getSettings().getHomeLimit(user); + if (usersHome.getHomes().size() == limit && usersHome.getHomes().contains(name)) + { + return false; + } + if (usersHome.getHomes().size() >= limit) + { + throw new Exception(tl("maxHomes", ess.getSettings().getHomeLimit(user))); + } + if (limit == 1) + { + return true; + } + } + return false; + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandsetjail.java b/Essentials/src/com/earth2me/essentials/commands/Commandsetjail.java new file mode 100644 index 0000000000..9cf89bfaf6 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandsetjail.java @@ -0,0 +1,27 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.StringUtil; +import org.bukkit.Server; + + +public class Commandsetjail extends EssentialsCommand +{ + public Commandsetjail() + { + super("setjail"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + ess.getJails().setJail(args[0], user.getLocation()); + user.sendMessage(tl("jailSet", StringUtil.sanitizeString(args[0]))); + + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandsetwarp.java b/Essentials/src/com/earth2me/essentials/commands/Commandsetwarp.java new file mode 100644 index 0000000000..b0fa51caf6 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandsetwarp.java @@ -0,0 +1,58 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.api.IWarps; +import com.earth2me.essentials.utils.NumberUtil; +import com.earth2me.essentials.utils.StringUtil; +import net.ess3.api.InvalidWorldException; +import org.bukkit.Location; +import org.bukkit.Server; + + +public class Commandsetwarp extends EssentialsCommand +{ + public Commandsetwarp() + { + super("setwarp"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + if (NumberUtil.isInt(args[0]) || args[0].isEmpty()) + { + throw new NoSuchFieldException(tl("invalidWarpName")); + } + + final Location loc = user.getLocation(); + final IWarps warps = ess.getWarps(); + Location warpLoc = null; + + try + { + warpLoc = warps.getWarp(args[0]); + } + catch (WarpNotFoundException ex) + { + } + catch (InvalidWorldException ex) + { + } + + if (warpLoc == null || user.isAuthorized("essentials.warp.overwrite." + StringUtil.safeString(args[0]))) + { + warps.setWarp(args[0], loc); + } + else + { + throw new Exception(tl("warpOverwrite")); + } + user.sendMessage(tl("warpSet", args[0])); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandsetworth.java b/Essentials/src/com/earth2me/essentials/commands/Commandsetworth.java new file mode 100644 index 0000000000..3a0e6b5eaf --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandsetworth.java @@ -0,0 +1,55 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Server; +import org.bukkit.inventory.ItemStack; + + +public class Commandsetworth extends EssentialsCommand +{ + public Commandsetworth() + { + super("setworth"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + ItemStack stack; + String price; + + if (args.length == 1) + { + stack = user.getBase().getInventory().getItemInHand(); + price = args[0]; + } + else + { + stack = ess.getItemDb().get(args[0]); + price = args[1]; + } + + ess.getWorth().setPrice(stack, Double.parseDouble(price)); + user.sendMessage(tl("worthSet")); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 2) + { + throw new NotEnoughArgumentsException(); + } + + ItemStack stack = ess.getItemDb().get(args[0]); + ess.getWorth().setPrice(stack, Double.parseDouble(args[1])); + sender.sendMessage(tl("worthSet")); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandskull.java b/Essentials/src/com/earth2me/essentials/commands/Commandskull.java new file mode 100644 index 0000000000..4f00e991ff --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandskull.java @@ -0,0 +1,69 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.craftbukkit.InventoryWorkaround; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.SkullMeta; + +public class Commandskull extends EssentialsCommand +{ + public Commandskull() + { + super("skull"); + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + String owner; + + if (args.length > 0 && user.isAuthorized("essentials.skull.others")) { + if (!args[0].matches("^[A-Za-z0-9_]+$")) { + throw new IllegalArgumentException(tl("alphaNames")); + } + owner = args[0]; + } + else { + owner = user.getName(); + } + + ItemStack itemSkull = user.getBase().getItemInHand(); + SkullMeta metaSkull = null; + boolean spawn = false; + + if (itemSkull != null && itemSkull.getType() == Material.SKULL_ITEM && itemSkull.getDurability() == 3) { + metaSkull = (SkullMeta) itemSkull.getItemMeta(); + } + else if (user.isAuthorized("essentials.skull.spawn")) + { + itemSkull = new ItemStack(Material.SKULL_ITEM, 1, (byte) 3); + metaSkull = (SkullMeta) itemSkull.getItemMeta(); + spawn = true; + } + else { + throw new Exception(tl("invalidSkull")); + } + + if (metaSkull.hasOwner() && !user.isAuthorized("essentials.skull.modify")) + { + throw new Exception(tl("noPermissionSkull")); + } + + metaSkull.setDisplayName("§fSkull of " + owner); + metaSkull.setOwner(owner); + + itemSkull.setItemMeta(metaSkull); + + if (spawn) { + InventoryWorkaround.addItems(user.getBase().getInventory(), itemSkull); + user.sendMessage(tl("givenSkull", owner)); + } + else { + user.sendMessage(tl("skullChanged", owner)); + } + } + +} \ No newline at end of file diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandsocialspy.java b/Essentials/src/com/earth2me/essentials/commands/Commandsocialspy.java new file mode 100644 index 0000000000..8b23396374 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandsocialspy.java @@ -0,0 +1,64 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Server; + + +public class Commandsocialspy extends EssentialsToggleCommand +{ + public Commandsocialspy() + { + super("socialspy", "essentials.socialspy.others"); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + toggleOtherPlayers(server, sender, args); + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length == 1) + { + Boolean toggle = matchToggleArgument(args[0]); + if (toggle == null && user.isAuthorized(othersPermission)) + { + toggleOtherPlayers(server, user.getSource(), args); + } + else + { + togglePlayer(user.getSource(), user, toggle); + } + } + else if (args.length == 2 && user.isAuthorized(othersPermission)) + { + toggleOtherPlayers(server, user.getSource(), args); + } + else + { + togglePlayer(user.getSource(), user, null); + } + } + + @Override + void togglePlayer(CommandSource sender, User user, Boolean enabled) throws NotEnoughArgumentsException + { + if (enabled == null) + { + enabled = !user.isSocialSpyEnabled(); + } + + user.setSocialSpyEnabled(enabled); + + + user.sendMessage(tl("socialSpy", user.getDisplayName(), enabled ? tl("enabled") : tl("disabled"))); + if (!sender.isPlayer() || !sender.getPlayer().equals(user.getBase())) + { + sender.sendMessage(tl("socialSpy", user.getDisplayName(), enabled ? tl("enabled") : tl("disabled"))); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandspawner.java b/Essentials/src/com/earth2me/essentials/commands/Commandspawner.java new file mode 100644 index 0000000000..96c871c4cf --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandspawner.java @@ -0,0 +1,79 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Mob; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.LocationUtil; +import com.earth2me.essentials.utils.NumberUtil; +import com.earth2me.essentials.utils.StringUtil; +import java.util.Locale; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.block.CreatureSpawner; + + +public class Commandspawner extends EssentialsCommand +{ + public Commandspawner() + { + super("spawner"); + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1 || args[0].length() < 2) + { + throw new NotEnoughArgumentsException(tl("mobsAvailable", StringUtil.joinList(Mob.getMobList()))); + } + + final Location target = LocationUtil.getTarget(user.getBase()); + if (target == null || target.getBlock().getType() != Material.MOB_SPAWNER) + { + throw new Exception(tl("mobSpawnTarget")); + } + + String name = args[0]; + int delay = 0; + + Mob mob = null; + mob = Mob.fromName(name); + if (mob == null) + { + throw new Exception(tl("invalidMob")); + } + if (ess.getSettings().getProtectPreventSpawn(mob.getType().toString().toLowerCase(Locale.ENGLISH))) + { + throw new Exception(tl("disabledToSpawnMob")); + } + if (!user.isAuthorized("essentials.spawner." + mob.name.toLowerCase(Locale.ENGLISH))) + { + throw new Exception(tl("noPermToSpawnMob")); + } + if (args.length > 1) + { + if (NumberUtil.isInt(args[1])) + { + delay = Integer.parseInt(args[1]); + } + } + final Trade charge = new Trade("spawner-" + mob.name.toLowerCase(Locale.ENGLISH), ess); + charge.isAffordableFor(user); + try + { + CreatureSpawner spawner = (CreatureSpawner)target.getBlock().getState(); + spawner.setSpawnedType(mob.getType()); + spawner.setDelay(delay); + spawner.update(); + } + catch (Throwable ex) + { + throw new Exception(tl("mobSpawnError"), ex); + } + charge.charge(user); + user.sendMessage(tl("setSpawner", mob.name)); + + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandspawnmob.java b/Essentials/src/com/earth2me/essentials/commands/Commandspawnmob.java new file mode 100644 index 0000000000..2626d9dad4 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandspawnmob.java @@ -0,0 +1,69 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Mob; +import com.earth2me.essentials.SpawnMob; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.StringUtil; +import java.util.List; +import org.bukkit.Server; + + +public class Commandspawnmob extends EssentialsCommand +{ + public Commandspawnmob() + { + super("spawnmob"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + final String mobList = SpawnMob.mobList(user); + throw new NotEnoughArgumentsException(tl("mobsAvailable", mobList)); + } + + List mobParts = SpawnMob.mobParts(args[0]); + List mobData = SpawnMob.mobData(args[0]); + + int mobCount = 1; + if (args.length >= 2) + { + mobCount = Integer.parseInt(args[1]); + } + + if (mobParts.size() > 1 && !user.isAuthorized("essentials.spawnmob.stack")) + { + throw new Exception(tl("cannotStackMob")); + } + + if (args.length >= 3) + { + final User target = getPlayer(ess.getServer(), user, args, 2); + SpawnMob.spawnmob(ess, server, user.getSource(), target, mobParts, mobData, mobCount); + return; + } + + SpawnMob.spawnmob(ess, server, user, mobParts, mobData, mobCount); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 3) + { + final String mobList = StringUtil.joinList(Mob.getMobList()); + throw new NotEnoughArgumentsException(tl("mobsAvailable", mobList)); + } + + List mobParts = SpawnMob.mobParts(args[0]); + List mobData = SpawnMob.mobData(args[0]); + int mobCount = Integer.parseInt(args[1]); + + final User target = getPlayer(ess.getServer(), args, 2, true, false); + SpawnMob.spawnmob(ess, server, sender, target, mobParts, mobData, mobCount); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandspeed.java b/Essentials/src/com/earth2me/essentials/commands/Commandspeed.java new file mode 100644 index 0000000000..620f439565 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandspeed.java @@ -0,0 +1,178 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import java.util.List; +import org.bukkit.Server; +import org.bukkit.entity.Player; + + +public class Commandspeed extends EssentialsCommand +{ + public Commandspeed() + { + super("speed"); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 2) + { + throw new NotEnoughArgumentsException(); + } + final boolean isFly = isFlyMode(args[0]); + final float speed = getMoveSpeed(args[1]); + speedOtherPlayers(server, sender, isFly, true, speed, args[2]); + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + boolean isFly; + float speed; + boolean isBypass = user.isAuthorized("essentials.speed.bypass"); + if (args.length == 1) + { + isFly = flyPermCheck(user, user.getBase().isFlying()); + speed = getMoveSpeed(args[0]); + } + else + { + isFly = flyPermCheck(user, isFlyMode(args[0])); + speed = getMoveSpeed(args[1]); + if (args.length > 2 && user.isAuthorized("essentials.speed.others")) + { + if (args[2].trim().length() < 2) + { + throw new PlayerNotFoundException(); + } + speedOtherPlayers(server, user.getSource(), isFly, isBypass, speed, args[2]); + return; + } + } + + if (isFly) + { + user.getBase().setFlySpeed(getRealMoveSpeed(speed, isFly, isBypass)); + user.sendMessage(tl("moveSpeed", tl("flying"), speed, user.getDisplayName())); + } + else + { + user.getBase().setWalkSpeed(getRealMoveSpeed(speed, isFly, isBypass)); + user.sendMessage(tl("moveSpeed", tl("walking"), speed, user.getDisplayName())); + } + } + + private void speedOtherPlayers(final Server server, final CommandSource sender, final boolean isFly, final boolean isBypass, final float speed, final String name) throws PlayerNotFoundException + { + boolean skipHidden = sender.isPlayer() && !ess.getUser(sender.getPlayer()).canInteractVanished(); + boolean foundUser = false; + final List matchedPlayers = server.matchPlayer(name); + for (Player matchPlayer : matchedPlayers) + { + final User player = ess.getUser(matchPlayer); + if (skipHidden && player.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(matchPlayer)) + { + continue; + } + foundUser = true; + if (isFly) + { + matchPlayer.setFlySpeed(getRealMoveSpeed(speed, isFly, isBypass)); + sender.sendMessage(tl("moveSpeed", tl("flying"), speed, matchPlayer.getDisplayName())); + } + else + { + matchPlayer.setWalkSpeed(getRealMoveSpeed(speed, isFly, isBypass)); + sender.sendMessage(tl("moveSpeed", tl("walking"), speed, matchPlayer.getDisplayName())); + } + } + if (!foundUser) + { + throw new PlayerNotFoundException(); + } + } + + private Boolean flyPermCheck(User user, boolean input) throws Exception + { + boolean canFly = user.isAuthorized("essentials.speed.fly"); + boolean canWalk = user.isAuthorized("essentials.speed.walk"); + if (input && canFly || !input && canWalk || !canFly && !canWalk) + { + return input; + } + else if (canWalk) + { + return false; + } + return true; + } + + private boolean isFlyMode(final String modeString) throws NotEnoughArgumentsException + { + boolean isFlyMode; + if (modeString.contains("fly") || modeString.equalsIgnoreCase("f")) + { + isFlyMode = true; + } + else if (modeString.contains("walk") || modeString.contains("run") + || modeString.equalsIgnoreCase("w") || modeString.equalsIgnoreCase("r")) + { + isFlyMode = false; + } + else + { + throw new NotEnoughArgumentsException(); + } + return isFlyMode; + } + + private float getMoveSpeed(final String moveSpeed) throws NotEnoughArgumentsException + { + float userSpeed; + try + { + userSpeed = Float.parseFloat(moveSpeed); + if (userSpeed > 10f) + { + userSpeed = 10f; + } + else if (userSpeed < 0.0001f) + { + userSpeed = 0.0001f; + } + } + catch (NumberFormatException e) + { + throw new NotEnoughArgumentsException(); + } + return userSpeed; + } + + private float getRealMoveSpeed(final float userSpeed, final boolean isFly, final boolean isBypass) + { + final float defaultSpeed = isFly ? 0.1f : 0.2f; + float maxSpeed = 1f; + if (!isBypass) + { + maxSpeed = (float)(isFly ? ess.getSettings().getMaxFlySpeed() : ess.getSettings().getMaxWalkSpeed()); + } + + if (userSpeed < 1f) + { + return defaultSpeed * userSpeed; + } + else + { + float ratio = ((userSpeed - 1) / 9) * (maxSpeed - defaultSpeed); + return ratio + defaultSpeed; + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandsudo.java b/Essentials/src/com/earth2me/essentials/commands/Commandsudo.java new file mode 100644 index 0000000000..9c9bb2df9f --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandsudo.java @@ -0,0 +1,72 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import java.util.Locale; +import java.util.logging.Logger; +import org.bukkit.Server; + + +public class Commandsudo extends EssentialsCommand +{ + public Commandsudo() + { + super("sudo"); + } + private static final Logger LOGGER = Logger.getLogger("Essentials"); + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 2) + { + throw new NotEnoughArgumentsException(); + } + + final User user = getPlayer(server, sender, args, 0); + if (args[1].toLowerCase(Locale.ENGLISH).startsWith("c:")) + { + if (user.isAuthorized("essentials.sudo.exempt") && sender.isPlayer()) + { + throw new Exception(tl("sudoExempt")); + } + user.getBase().chat(getFinalArg(args, 1).substring(2)); + return; + } + final String[] arguments = new String[args.length - 1]; + if (arguments.length > 0) + { + System.arraycopy(args, 1, arguments, 0, args.length - 1); + } + + if (user.isAuthorized("essentials.sudo.exempt") && sender.isPlayer()) + { + throw new Exception(tl("sudoExempt")); + } + + final String command = getFinalArg(arguments, 0); + + sender.sendMessage(tl("sudoRun", user.getDisplayName(), command, "")); + + if (command != null && command.length() > 0) + { + class SudoCommandTask implements Runnable + { + @Override + public void run() + { + try + { + ess.getServer().dispatchCommand(user.getBase(), command); + } + catch (Exception e) + { + sender.sendMessage(tl("errorCallingCommand", command)); + } + } + } + ess.scheduleSyncDelayedTask(new SudoCommandTask()); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandsuicide.java b/Essentials/src/com/earth2me/essentials/commands/Commandsuicide.java new file mode 100644 index 0000000000..fdd9e0bbbc --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandsuicide.java @@ -0,0 +1,30 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Server; +import org.bukkit.event.entity.EntityDamageEvent; + + +public class Commandsuicide extends EssentialsCommand +{ + public Commandsuicide() + { + super("suicide"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + EntityDamageEvent ede = new EntityDamageEvent(user.getBase(), EntityDamageEvent.DamageCause.SUICIDE, Short.MAX_VALUE); + server.getPluginManager().callEvent(ede); + user.getBase().damage(Short.MAX_VALUE); + if (user.getBase().getHealth() > 0) + { + user.getBase().setHealth(0); + } + user.sendMessage(tl("suicideMessage")); + user.setDisplayNick(); + ess.broadcastMessage(user, tl("suicideSuccess", user.getDisplayName())); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandtempban.java b/Essentials/src/com/earth2me/essentials/commands/Commandtempban.java new file mode 100644 index 0000000000..da8af1a138 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandtempban.java @@ -0,0 +1,75 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import com.earth2me.essentials.Console; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.DateUtil; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.logging.Level; +import org.bukkit.BanList; +import org.bukkit.Server; + + +public class Commandtempban extends EssentialsCommand +{ + public Commandtempban() + { + super("tempban"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 2) + { + throw new NotEnoughArgumentsException(); + } + final User user = getPlayer(server, args, 0, true, true); + if (!user.getBase().isOnline()) + { + if (sender.isPlayer() + && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.tempban.offline")) + { + sender.sendMessage(tl("tempbanExemptOffline")); + return; + } + } + else + { + if (user.isAuthorized("essentials.tempban.exempt") && sender.isPlayer()) + { + sender.sendMessage(tl("tempbanExempt")); + return; + } + } + final String time = getFinalArg(args, 1); + final long banTimestamp = DateUtil.parseDateDiff(time, true); + String banReason = DateUtil.removeTimePattern(time); + + final long maxBanLength = ess.getSettings().getMaxTempban() * 1000; + if (maxBanLength > 0 && ((banTimestamp - GregorianCalendar.getInstance().getTimeInMillis()) > maxBanLength) + && sender.isPlayer() && !(ess.getUser(sender.getPlayer()).isAuthorized("essentials.tempban.unlimited"))) + { + sender.sendMessage(tl("oversizedTempban")); + throw new NoChargeException(); + } + + if (banReason.length() < 2) + { + banReason = tl("defaultBanReason"); + } + + final String senderName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.NAME; + ess.getServer().getBanList(BanList.Type.NAME).addBan(user.getName(), banReason, new Date(banTimestamp), senderName); + final String expiry = DateUtil.formatDateDiff(banTimestamp); + + final String banDisplay = tl("tempBanned", expiry, senderName, banReason); + user.getBase().kickPlayer(banDisplay); + + final String message = tl("playerTempBanned", senderName, user.getName(), expiry, banReason); + server.getLogger().log(Level.INFO, message); + ess.broadcastMessage("essentials.ban.notify", message); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandthunder.java b/Essentials/src/com/earth2me/essentials/commands/Commandthunder.java new file mode 100644 index 0000000000..25deb69c04 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandthunder.java @@ -0,0 +1,41 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Server; +import org.bukkit.World; + + +public class Commandthunder extends EssentialsCommand +{ + public Commandthunder() + { + super("thunder"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + final World world = user.getWorld(); + final boolean setThunder = args[0].equalsIgnoreCase("true"); + if (args.length > 1) + { + + world.setThundering(setThunder ? true : false); + world.setThunderDuration(Integer.parseInt(args[1]) * 20); + user.sendMessage(tl("thunderDuration", (setThunder ? tl("enabled") : tl("disabled")), Integer.parseInt(args[1]))); + + } + else + { + world.setThundering(setThunder ? true : false); + user.sendMessage(tl("thunder", setThunder ? tl("enabled") : tl("disabled"))); + } + + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandtime.java b/Essentials/src/com/earth2me/essentials/commands/Commandtime.java new file mode 100644 index 0000000000..2d456073ae --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandtime.java @@ -0,0 +1,187 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.DescParseTickFormat; +import com.earth2me.essentials.utils.NumberUtil; +import java.util.*; +import org.bukkit.Server; +import org.bukkit.World; + + +public class Commandtime extends EssentialsCommand +{ + public Commandtime() + { + super("time"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + boolean add = false; + final List argList = new ArrayList(Arrays.asList(args)); + if (argList.remove("set") && !argList.isEmpty() && NumberUtil.isInt(argList.get(0))) + { + argList.set(0, argList.get(0) + "t"); + } + if (argList.remove("add") && !argList.isEmpty() && NumberUtil.isInt(argList.get(0))) + { + add = true; + argList.set(0, argList.get(0) + "t"); + } + final String[] validArgs = argList.toArray(new String[0]); + + // Which World(s) are we interested in? + String worldSelector = null; + if (validArgs.length == 2) + { + worldSelector = validArgs[1]; + } + final Set worlds = getWorlds(server, sender, worldSelector); + final String setTime; + + // If no arguments we are reading the time + if (validArgs.length == 0) + { + if (commandLabel.equalsIgnoreCase("day") || commandLabel.equalsIgnoreCase("eday")) + { + setTime = "day"; + } + else if (commandLabel.equalsIgnoreCase("night") || commandLabel.equalsIgnoreCase("enight")) + { + setTime = "night"; + } + else + { + getWorldsTime(sender, worlds); + throw new NoChargeException(); + } + } + else + { + setTime = validArgs[0]; + } + + final User user = ess.getUser(sender.getPlayer()); + if (user != null && !user.isAuthorized("essentials.time.set")) + { + throw new Exception(tl("timeSetPermission")); + } + + // Parse the target time int ticks from args[0] + long ticks; + try + { + ticks = DescParseTickFormat.parse(setTime); + } + catch (NumberFormatException e) + { + throw new NotEnoughArgumentsException(e); + } + + setWorldsTime(sender, worlds, ticks, add); + } + + /** + * Used to get the time and inform + */ + private void getWorldsTime(final CommandSource sender, final Collection worlds) + { + if (worlds.size() == 1) + { + final Iterator iter = worlds.iterator(); + sender.sendMessage(DescParseTickFormat.format(iter.next().getTime())); + return; + } + + for (World world : worlds) + { + sender.sendMessage(tl("timeWorldCurrent", world.getName(), DescParseTickFormat.format(world.getTime()))); + } + } + + /** + * Used to set the time and inform of the change + */ + private void setWorldsTime(final CommandSource sender, final Collection worlds, final long ticks, final boolean add) + { + // Update the time + for (World world : worlds) + { + long time = world.getTime(); + if (!add) + { + time -= time % 24000; + } + world.setTime(time + (add ? 0 : 24000) + ticks); + } + + final StringBuilder output = new StringBuilder(); + for (World world : worlds) + { + if (output.length() > 0) + { + output.append(", "); + } + + output.append(world.getName()); + } + + sender.sendMessage(tl("timeWorldSet", DescParseTickFormat.format(ticks), output.toString())); + } + + /** + * Used to parse an argument of the type "world(s) selector" + */ + private Set getWorlds(final Server server, final CommandSource sender, final String selector) throws Exception + { + final Set worlds = new TreeSet(new WorldNameComparator()); + + // If there is no selector we want the world the user is currently in. Or all worlds if it isn't a user. + if (selector == null) + { + if (sender.isPlayer()) + { + + final User user = ess.getUser(sender.getPlayer()); + worlds.add(user.getWorld()); + } + else + { + worlds.addAll(server.getWorlds()); + } + return worlds; + } + + // Try to find the world with name = selector + final World world = server.getWorld(selector); + if (world != null) + { + worlds.add(world); + } + // If that fails, Is the argument something like "*" or "all"? + else if (selector.equalsIgnoreCase("*") || selector.equalsIgnoreCase("all")) + { + worlds.addAll(server.getWorlds()); + } + // We failed to understand the world target... + else + { + throw new Exception(tl("invalidWorld")); + } + + return worlds; + } +} + + +class WorldNameComparator implements Comparator +{ + @Override + public int compare(final World a, final World b) + { + return a.getName().compareTo(b.getName()); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandtogglejail.java b/Essentials/src/com/earth2me/essentials/commands/Commandtogglejail.java new file mode 100644 index 0000000000..8d67a21d09 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandtogglejail.java @@ -0,0 +1,104 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.DateUtil; +import org.bukkit.Server; + + +public class Commandtogglejail extends EssentialsCommand +{ + public Commandtogglejail() + { + super("togglejail"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + final User player = getPlayer(server, args, 0, true, true); + + if (args.length >= 2 && !player.isJailed()) + { + if (!player.getBase().isOnline()) + { + if (sender.isPlayer() + && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.togglejail.offline")) + { + sender.sendMessage(tl("mayNotJailOffline")); + return; + } + } + else + { + if (player.isAuthorized("essentials.jail.exempt")) + { + sender.sendMessage(tl("mayNotJail")); + return; + } + } + if (player.getBase().isOnline()) + { + ess.getJails().sendToJail(player, args[1]); + } + else + { + // Check if jail exists + ess.getJails().getJail(args[1]); + } + player.setJailed(true); + player.sendMessage(tl("userJailed")); + player.setJail(null); + player.setJail(args[1]); + long timeDiff = 0; + if (args.length > 2) + { + final String time = getFinalArg(args, 2); + timeDiff = DateUtil.parseDateDiff(time, true); + player.setJailTimeout(timeDiff); + } + sender.sendMessage((timeDiff > 0 + ? tl("playerJailedFor", player.getName(), DateUtil.formatDateDiff(timeDiff)) + : tl("playerJailed", player.getName()))); + return; + } + + if (args.length >= 2 && player.isJailed() && !args[1].equalsIgnoreCase(player.getJail())) + { + sender.sendMessage(tl("jailAlreadyIncarcerated", player.getJail())); + return; + } + + if (args.length >= 2 && player.isJailed() && args[1].equalsIgnoreCase(player.getJail())) + { + final String time = getFinalArg(args, 2); + final long timeDiff = DateUtil.parseDateDiff(time, true); + player.setJailTimeout(timeDiff); + sender.sendMessage(tl("jailSentenceExtended", DateUtil.formatDateDiff(timeDiff))); + return; + } + + if (args.length == 1 || (args.length == 2 && args[1].equalsIgnoreCase(player.getJail()))) + { + if (!player.isJailed()) + { + throw new NotEnoughArgumentsException(); + } + player.setJailed(false); + player.setJailTimeout(0); + player.sendMessage(tl("jailReleasedPlayerNotify")); + player.setJail(null); + if (player.getBase().isOnline()) + { + player.getTeleport().back(); + } + sender.sendMessage(tl("jailReleased", player.getName())); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandtop.java b/Essentials/src/com/earth2me/essentials/commands/Commandtop.java new file mode 100644 index 0000000000..d41646f2d5 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandtop.java @@ -0,0 +1,31 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.LocationUtil; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + + +public class Commandtop extends EssentialsCommand +{ + public Commandtop() + { + super("top"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + final int topX = user.getLocation().getBlockX(); + final int topZ = user.getLocation().getBlockZ(); + final float pitch = user.getLocation().getPitch(); + final float yaw = user.getLocation().getYaw(); + final Location loc = LocationUtil.getSafeDestination(new Location(user.getWorld(), topX, user.getWorld().getMaxHeight(), topZ, yaw, pitch)); + user.getTeleport().teleport(loc, new Trade(this.getName(), ess), TeleportCause.COMMAND); + user.sendMessage(tl("teleportTop", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); + + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandtp.java b/Essentials/src/com/earth2me/essentials/commands/Commandtp.java new file mode 100644 index 0000000000..ee39388049 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandtp.java @@ -0,0 +1,146 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import com.earth2me.essentials.Console; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + + +public class Commandtp extends EssentialsCommand +{ + public Commandtp() + { + super("tp"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + switch (args.length) + { + case 0: + throw new NotEnoughArgumentsException(); + + case 1: + final User player = getPlayer(server, user, args, 0); + if (!player.isTeleportEnabled()) + { + throw new Exception(tl("teleportDisabled", player.getDisplayName())); + } + if (user.getWorld() != player.getWorld() && ess.getSettings().isWorldTeleportPermissions() + && !user.isAuthorized("essentials.worlds." + player.getWorld().getName())) + { + throw new Exception(tl("noPerm", "essentials.worlds." + player.getWorld().getName())); + } + final Trade charge = new Trade(this.getName(), ess); + charge.isAffordableFor(user); + user.getTeleport().teleport(player.getBase(), charge, TeleportCause.COMMAND); + throw new NoChargeException(); + case 3: + if (!user.isAuthorized("essentials.tp.position")) + { + throw new Exception(tl("noPerm", "essentials.tp.position")); + } + final double x2 = args[0].startsWith("~") ? user.getLocation().getX() + Integer.parseInt(args[0].substring(1)) : Integer.parseInt(args[0]); + final double y2 = args[1].startsWith("~") ? user.getLocation().getY() + Integer.parseInt(args[1].substring(1)) : Integer.parseInt(args[1]); + final double z2 = args[2].startsWith("~") ? user.getLocation().getZ() + Integer.parseInt(args[2].substring(1)) : Integer.parseInt(args[2]); + if (x2 > 30000000 || y2 > 30000000 || z2 > 30000000 || x2 < -30000000 || y2 < -30000000 || z2 < -30000000) + { + throw new NotEnoughArgumentsException(tl("teleportInvalidLocation")); + } + final Location locpos = new Location(user.getWorld(), x2, y2, z2, user.getLocation().getYaw(), user.getLocation().getPitch()); + user.getTeleport().now(locpos, false, TeleportCause.COMMAND); + user.sendMessage(tl("teleporting", locpos.getWorld().getName(), locpos.getBlockX(), locpos.getBlockY(), locpos.getBlockZ())); + break; + case 4: + if (!user.isAuthorized("essentials.tp.others")) + { + throw new Exception(tl("noPerm", "essentials.tp.others")); + } + if (!user.isAuthorized("essentials.tp.position")) + { + throw new Exception(tl("noPerm", "essentials.tp.position")); + } + final User target2 = getPlayer(server, user, args, 0); + final double x = args[1].startsWith("~") ? target2.getLocation().getX() + Integer.parseInt(args[1].substring(1)) : Integer.parseInt(args[1]); + final double y = args[2].startsWith("~") ? target2.getLocation().getY() + Integer.parseInt(args[2].substring(1)) : Integer.parseInt(args[2]); + final double z = args[3].startsWith("~") ? target2.getLocation().getZ() + Integer.parseInt(args[3].substring(1)) : Integer.parseInt(args[3]); + if (x > 30000000 || y > 30000000 || z > 30000000 || x < -30000000 || y < -30000000 || z < -30000000) + { + throw new NotEnoughArgumentsException(tl("teleportInvalidLocation")); + } + final Location locposother = new Location(target2.getWorld(), x, y, z, target2.getLocation().getYaw(), target2.getLocation().getPitch()); + if (!target2.isTeleportEnabled()) + { + throw new Exception(tl("teleportDisabled", target2.getDisplayName())); + } + user.sendMessage(tl("teleporting", locposother.getWorld().getName(), locposother.getBlockX(), locposother.getBlockY(), locposother.getBlockZ())); + target2.getTeleport().now(locposother, false, TeleportCause.COMMAND); + target2.sendMessage(tl("teleporting", locposother.getWorld().getName(), locposother.getBlockX(), locposother.getBlockY(), locposother.getBlockZ())); + break; + case 2: + default: + if (!user.isAuthorized("essentials.tp.others")) + { + throw new Exception(tl("noPerm", "essentials.tp.others")); + } + final User target = getPlayer(server, user, args, 0); + final User toPlayer = getPlayer(server, user, args, 1); + if (!target.isTeleportEnabled()) + { + throw new Exception(tl("teleportDisabled", target.getDisplayName())); + } + if (!toPlayer.isTeleportEnabled()) + { + throw new Exception(tl("teleportDisabled", toPlayer.getDisplayName())); + } + if (target.getWorld() != toPlayer.getWorld() && ess.getSettings().isWorldTeleportPermissions() + && !user.isAuthorized("essentials.worlds." + toPlayer.getWorld().getName())) + { + throw new Exception(tl("noPerm", "essentials.worlds." + toPlayer.getWorld().getName())); + } + target.sendMessage(tl("teleportAtoB", user.getDisplayName(), toPlayer.getDisplayName())); + target.getTeleport().now(toPlayer.getBase(), false, TeleportCause.COMMAND); + break; + } + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 2) + { + throw new NotEnoughArgumentsException(); + } + + final User target = getPlayer(server, args, 0, true, false); + if (args.length == 2) + { + final User toPlayer = getPlayer(server, args, 1, true, false); + target.sendMessage(tl("teleportAtoB", Console.NAME, toPlayer.getDisplayName())); + target.getTeleport().now(toPlayer.getBase(), false, TeleportCause.COMMAND); + } + else if (args.length > 3) + { + final double x = args[1].startsWith("~") ? target.getLocation().getX() + Integer.parseInt(args[1].substring(1)) : Integer.parseInt(args[1]); + final double y = args[2].startsWith("~") ? target.getLocation().getY() + Integer.parseInt(args[2].substring(1)) : Integer.parseInt(args[2]); + final double z = args[3].startsWith("~") ? target.getLocation().getZ() + Integer.parseInt(args[3].substring(1)) : Integer.parseInt(args[3]); + if (x > 30000000 || y > 30000000 || z > 30000000 || x < -30000000 || y < -30000000 || z < -30000000) + { + throw new NotEnoughArgumentsException(tl("teleportInvalidLocation")); + } + final Location loc = new Location(target.getWorld(), x, y, z, target.getLocation().getYaw(), target.getLocation().getPitch()); + sender.sendMessage(tl("teleporting", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); + target.getTeleport().now(loc, false, TeleportCause.COMMAND); + target.sendMessage(tl("teleporting", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); + } + else + { + throw new NotEnoughArgumentsException(); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandtpa.java b/Essentials/src/com/earth2me/essentials/commands/Commandtpa.java new file mode 100644 index 0000000000..94dd672bbb --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandtpa.java @@ -0,0 +1,50 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Server; + + +public class Commandtpa extends EssentialsCommand +{ + public Commandtpa() + { + super("tpa"); + } + + @Override + public void run(Server server, User user, String commandLabel, String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + User player = getPlayer(server, user, args, 0); + if (user.getName().equalsIgnoreCase(player.getName())) + { + throw new NotEnoughArgumentsException(); + } + if (!player.isTeleportEnabled()) + { + throw new Exception(tl("teleportDisabled", player.getDisplayName())); + } + if (user.getWorld() != player.getWorld() && ess.getSettings().isWorldTeleportPermissions() + && !user.isAuthorized("essentials.worlds." + player.getWorld().getName())) + { + throw new Exception(tl("noPerm", "essentials.worlds." + player.getWorld().getName())); + } + if (!player.isIgnoredPlayer(user)) + { + player.requestTeleport(user, false); + player.sendMessage(tl("teleportRequest", user.getDisplayName())); + player.sendMessage(tl("typeTpaccept")); + player.sendMessage(tl("typeTpdeny")); + if (ess.getSettings().getTpaAcceptCancellation() != 0) + { + player.sendMessage(tl("teleportRequestTimeoutInfo", ess.getSettings().getTpaAcceptCancellation())); + } + } + user.sendMessage(tl("requestSent", player.getDisplayName())); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandtpaall.java b/Essentials/src/com/earth2me/essentials/commands/Commandtpaall.java new file mode 100644 index 0000000000..4cbd9603bb --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandtpaall.java @@ -0,0 +1,69 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Server; +import org.bukkit.entity.Player; + + +public class Commandtpaall extends EssentialsCommand +{ + public Commandtpaall() + { + super("tpaall"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + if (sender.isPlayer()) + { + teleportAAllPlayers(server, sender, ess.getUser(sender.getPlayer())); + return; + } + throw new NotEnoughArgumentsException(); + } + + final User target = getPlayer(server, sender, args, 0); + teleportAAllPlayers(server, sender, target); + } + + private void teleportAAllPlayers(final Server server, final CommandSource sender, final User target) + { + sender.sendMessage(tl("teleportAAll")); + for (User player : ess.getOnlineUsers()) + { + if (target == player) + { + continue; + } + if (!player.isTeleportEnabled()) + { + continue; + } + if (sender.equals(target.getBase()) + && target.getWorld() != player.getWorld() && ess.getSettings().isWorldTeleportPermissions() + && !target.isAuthorized("essentials.worlds." + target.getWorld().getName())) + { + continue; + } + try + { + player.requestTeleport(target, true); + player.sendMessage(tl("teleportHereRequest", target.getDisplayName())); + player.sendMessage(tl("typeTpaccept")); + if (ess.getSettings().getTpaAcceptCancellation() != 0) + { + player.sendMessage(tl("teleportRequestTimeoutInfo", ess.getSettings().getTpaAcceptCancellation())); + } + } + catch (Exception ex) + { + ess.showError(sender, ex, getName()); + } + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandtpaccept.java b/Essentials/src/com/earth2me/essentials/commands/Commandtpaccept.java new file mode 100644 index 0000000000..ed56a62757 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandtpaccept.java @@ -0,0 +1,88 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + + +public class Commandtpaccept extends EssentialsCommand +{ + public Commandtpaccept() + { + super("tpaccept"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + final User requester; + try + { + requester = ess.getUser(user.getTeleportRequest()); + } + catch (Exception ex) + { + throw new Exception(tl("noPendingRequest")); + } + + if (!requester.getBase().isOnline()) + { + throw new Exception(tl("noPendingRequest")); + } + + if (user.isTpRequestHere() && ((!requester.isAuthorized("essentials.tpahere") && !requester.isAuthorized("essentials.tpaall")) + || (user.getWorld() != requester.getWorld() && ess.getSettings().isWorldTeleportPermissions() + && !user.isAuthorized("essentials.worlds." + user.getWorld().getName())))) + { + throw new Exception(tl("noPendingRequest")); + } + + if (!user.isTpRequestHere() && (!requester.isAuthorized("essentials.tpa") + || (user.getWorld() != requester.getWorld() && ess.getSettings().isWorldTeleportPermissions() + && !user.isAuthorized("essentials.worlds." + requester.getWorld().getName())))) + { + throw new Exception(tl("noPendingRequest")); + } + + if (args.length > 0 && !requester.getName().contains(args[0])) + { + throw new Exception(tl("noPendingRequest")); + } + + long timeout = ess.getSettings().getTpaAcceptCancellation(); + if (timeout != 0 && (System.currentTimeMillis() - user.getTeleportRequestTime()) / 1000 > timeout) + { + user.requestTeleport(null, false); + throw new Exception(tl("requestTimedOut")); + } + + final Trade charge = new Trade(this.getName(), ess); + user.sendMessage(tl("requestAccepted")); + requester.sendMessage(tl("requestAcceptedFrom", user.getDisplayName())); + + try + { + if (user.isTpRequestHere()) + { + final Location loc = user.getTpRequestLocation(); + requester.getTeleport().teleportPlayer(user, user.getTpRequestLocation(), charge, TeleportCause.COMMAND); + requester.sendMessage(tl("teleporting", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); + } + else + { + requester.getTeleport().teleport(user.getBase(), charge, TeleportCause.COMMAND); + } + } + catch (Exception ex) + { + user.sendMessage(tl("pendingTeleportCancelled")); + ess.showError(requester.getSource(), ex, commandLabel); + } + user.requestTeleport(null, false); + throw new NoChargeException(); + } + +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandtpahere.java b/Essentials/src/com/earth2me/essentials/commands/Commandtpahere.java new file mode 100644 index 0000000000..d0d3e47fde --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandtpahere.java @@ -0,0 +1,50 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Server; + + +public class Commandtpahere extends EssentialsCommand +{ + public Commandtpahere() + { + super("tpahere"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + final User player = getPlayer(server, user, args, 0); + if (user.getName().equalsIgnoreCase(player.getName())) + { + throw new NotEnoughArgumentsException(); + } + if (!player.isTeleportEnabled()) + { + throw new Exception(tl("teleportDisabled", player.getDisplayName())); + } + if (user.getWorld() != player.getWorld() && ess.getSettings().isWorldTeleportPermissions() + && !user.isAuthorized("essentials.worlds." + user.getWorld().getName())) + { + throw new Exception(tl("noPerm", "essentials.worlds." + user.getWorld().getName())); + } + if (!player.isIgnoredPlayer(user)) + { + player.requestTeleport(user, true); + player.sendMessage(tl("teleportHereRequest", user.getDisplayName())); + player.sendMessage(tl("typeTpaccept")); + player.sendMessage(tl("typeTpdeny")); + if (ess.getSettings().getTpaAcceptCancellation() != 0) + { + player.sendMessage(tl("teleportRequestTimeoutInfo", ess.getSettings().getTpaAcceptCancellation())); + } + } + user.sendMessage(tl("requestSent", player.getDisplayName())); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandtpall.java b/Essentials/src/com/earth2me/essentials/commands/Commandtpall.java new file mode 100644 index 0000000000..c850fad2e1 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandtpall.java @@ -0,0 +1,62 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + + +public class Commandtpall extends EssentialsCommand +{ + public Commandtpall() + { + super("tpall"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + if (sender.isPlayer()) + { + teleportAllPlayers(server, sender, ess.getUser(sender.getPlayer())); + return; + } + throw new NotEnoughArgumentsException(); + } + + final User target = getPlayer(server, sender, args, 0); + teleportAllPlayers(server, sender, target); + } + + private void teleportAllPlayers(Server server, CommandSource sender, User target) + { + sender.sendMessage(tl("teleportAll")); + final Location loc = target.getLocation(); + for (User player : ess.getOnlineUsers()) + { + if (target == player) + { + continue; + } + if (sender.equals(target.getBase()) + && target.getWorld() != player.getWorld() && ess.getSettings().isWorldTeleportPermissions() + && !target.isAuthorized("essentials.worlds." + target.getWorld().getName())) + { + continue; + } + try + { + player.getTeleport().now(loc, false, TeleportCause.COMMAND); + } + catch (Exception ex) + { + ess.showError(sender, ex, getName()); + } + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandtpdeny.java b/Essentials/src/com/earth2me/essentials/commands/Commandtpdeny.java new file mode 100644 index 0000000000..c0dfde4468 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandtpdeny.java @@ -0,0 +1,28 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Server; + + +public class Commandtpdeny extends EssentialsCommand +{ + public Commandtpdeny() + { + super("tpdeny"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + final User player = ess.getUser(user.getTeleportRequest()); + if (player == null) + { + throw new Exception(tl("noPendingRequest")); + } + + user.sendMessage(tl("requestDenied")); + player.sendMessage(tl("requestDeniedFrom", user.getDisplayName())); + user.requestTeleport(null, false); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandtphere.java b/Essentials/src/com/earth2me/essentials/commands/Commandtphere.java new file mode 100644 index 0000000000..ec792b2893 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandtphere.java @@ -0,0 +1,33 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import org.bukkit.Server; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + + +public class Commandtphere extends EssentialsCommand +{ + public Commandtphere() + { + super("tphere"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + final User player = getPlayer(server, user, args, 0); + if (!player.isTeleportEnabled()) + { + throw new Exception(tl("teleportDisabled", player.getDisplayName())); + } + if (user.getWorld() != player.getWorld() && ess.getSettings().isWorldTeleportPermissions() + && !user.isAuthorized("essentials.worlds." + user.getWorld().getName())) + { + throw new Exception(tl("noPerm", "essentials.worlds." + user.getWorld().getName())); + } + user.getTeleport().teleportPlayer(player, user.getBase(), new Trade(this.getName(), ess), TeleportCause.COMMAND); + throw new NoChargeException(); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandtpo.java b/Essentials/src/com/earth2me/essentials/commands/Commandtpo.java new file mode 100644 index 0000000000..0befdfc3b9 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandtpo.java @@ -0,0 +1,53 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Server; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + + +public class Commandtpo extends EssentialsCommand +{ + public Commandtpo() + { + super("tpo"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + switch (args.length) + { + case 0: + throw new NotEnoughArgumentsException(); + + case 1: + final User player = getPlayer(server, user, args, 0); + if (user.getWorld() != player.getWorld() && ess.getSettings().isWorldTeleportPermissions() + && !user.isAuthorized("essentials.worlds." + player.getWorld().getName())) + { + throw new Exception(tl("noPerm", "essentials.worlds." + player.getWorld().getName())); + } + user.getTeleport().now(player.getBase(), false, TeleportCause.COMMAND); + break; + + default: + if (!user.isAuthorized("essentials.tp.others")) + { + throw new Exception(tl("noPerm", "essentials.tp.others")); + } + final User target = getPlayer(server, user, args, 0); + final User toPlayer = getPlayer(server, user, args, 1); + + if (target.getWorld() != toPlayer.getWorld() && ess.getSettings().isWorldTeleportPermissions() + && !user.isAuthorized("essentials.worlds." + toPlayer.getWorld().getName())) + { + throw new Exception(tl("noPerm", "essentials.worlds." + toPlayer.getWorld().getName())); + } + + target.getTeleport().now(toPlayer.getBase(), false, TeleportCause.COMMAND); + target.sendMessage(tl("teleportAtoB", user.getDisplayName(), toPlayer.getDisplayName())); + break; + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandtpohere.java b/Essentials/src/com/earth2me/essentials/commands/Commandtpohere.java new file mode 100644 index 0000000000..bb0d924ebb --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandtpohere.java @@ -0,0 +1,36 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Server; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + + +public class Commandtpohere extends EssentialsCommand +{ + public Commandtpohere() + { + super("tpohere"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + //Just basically the old tphere command + final User player = getPlayer(server, user, args, 0); + + if (user.getWorld() != player.getWorld() && ess.getSettings().isWorldTeleportPermissions() + && !user.isAuthorized("essentials.worlds." + user.getWorld().getName())) + { + throw new Exception(tl("noPerm", "essentials.worlds." + user.getWorld().getName())); + } + + // Verify permission + player.getTeleport().now(user.getBase(), false, TeleportCause.COMMAND); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandtppos.java b/Essentials/src/com/earth2me/essentials/commands/Commandtppos.java new file mode 100644 index 0000000000..0d48acc59e --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandtppos.java @@ -0,0 +1,80 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + + +public class Commandtppos extends EssentialsCommand +{ + public Commandtppos() + { + super("tppos"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 3) + { + throw new NotEnoughArgumentsException(); + } + + final double x = args[0].startsWith("~") ? user.getLocation().getX() + Integer.parseInt(args[0].substring(1)) : Integer.parseInt(args[0]); + final double y = args[1].startsWith("~") ? user.getLocation().getY() + Integer.parseInt(args[1].substring(1)) : Integer.parseInt(args[1]); + final double z = args[2].startsWith("~") ? user.getLocation().getZ() + Integer.parseInt(args[2].substring(1)) : Integer.parseInt(args[2]); + final Location loc = new Location(user.getWorld(), x, y, z, user.getLocation().getYaw(), user.getLocation().getPitch()); + if (args.length > 3) + { + loc.setYaw((Float.parseFloat(args[3]) + 180 + 360) % 360); + } + if (args.length > 4) + { + loc.setPitch(Float.parseFloat(args[4])); + } + if (x > 30000000 || y > 30000000 || z > 30000000 || x < -30000000 || y < -30000000 || z < -30000000) + { + throw new NotEnoughArgumentsException(tl("teleportInvalidLocation")); + } + final Trade charge = new Trade(this.getName(), ess); + charge.isAffordableFor(user); + user.sendMessage(tl("teleporting", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); + user.getTeleport().teleport(loc, charge, TeleportCause.COMMAND); + throw new NoChargeException(); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 4) + { + throw new NotEnoughArgumentsException(); + } + + User user = getPlayer(server, args, 0, true, false); + final double x = args[1].startsWith("~") ? user.getLocation().getX() + Integer.parseInt(args[1].substring(1)) : Integer.parseInt(args[1]); + final double y = args[2].startsWith("~") ? user.getLocation().getY() + Integer.parseInt(args[2].substring(1)) : Integer.parseInt(args[2]); + final double z = args[3].startsWith("~") ? user.getLocation().getZ() + Integer.parseInt(args[3].substring(1)) : Integer.parseInt(args[3]); + final Location loc = new Location(user.getWorld(), x, y, z, user.getLocation().getYaw(), user.getLocation().getPitch()); + if (args.length > 4) + { + loc.setYaw((Float.parseFloat(args[4]) + 180 + 360) % 360); + } + if (args.length > 5) + { + loc.setPitch(Float.parseFloat(args[5])); + } + if (x > 30000000 || y > 30000000 || z > 30000000 || x < -30000000 || y < -30000000 || z < -30000000) + { + throw new NotEnoughArgumentsException(tl("teleportInvalidLocation")); + } + sender.sendMessage(tl("teleporting", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); + user.sendMessage(tl("teleporting", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); + user.getTeleport().teleport(loc, null, TeleportCause.COMMAND); + + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandtptoggle.java b/Essentials/src/com/earth2me/essentials/commands/Commandtptoggle.java new file mode 100644 index 0000000000..3bc02b02e1 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandtptoggle.java @@ -0,0 +1,63 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Server; + + +public class Commandtptoggle extends EssentialsToggleCommand +{ + public Commandtptoggle() + { + super("tptoggle", "essentials.tptoggle.others"); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + toggleOtherPlayers(server, sender, args); + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length == 1) + { + Boolean toggle = matchToggleArgument(args[0]); + if (toggle == null && user.isAuthorized(othersPermission)) + { + toggleOtherPlayers(server, user.getSource(), args); + } + else + { + togglePlayer(user.getSource(), user, toggle); + } + } + else if (args.length == 2 && user.isAuthorized(othersPermission)) + { + toggleOtherPlayers(server, user.getSource(), args); + } + else + { + togglePlayer(user.getSource(), user, null); + } + } + + @Override + void togglePlayer(CommandSource sender, User user, Boolean enabled) + { + if (enabled == null) + { + enabled = !user.isTeleportEnabled(); + } + + user.setTeleportEnabled(enabled); + + user.sendMessage(enabled ? tl("teleportationEnabled") : tl("teleportationDisabled")); + if (!sender.isPlayer() || !sender.getPlayer().equals(user.getBase())) + { + sender.sendMessage(enabled ? tl("teleportationEnabledFor", user.getDisplayName()) : tl("teleportationDisabledFor", user.getDisplayName())); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandtree.java b/Essentials/src/com/earth2me/essentials/commands/Commandtree.java new file mode 100644 index 0000000000..1a50e8f558 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandtree.java @@ -0,0 +1,91 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.Essentials; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.LocationUtil; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.TreeType; + + +public class Commandtree extends EssentialsCommand +{ + public Commandtree() + { + super("tree"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + TreeType tree = TreeType.BIRCH; + try // update check + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + else if (args[0].equalsIgnoreCase("birch")) + { + tree = TreeType.BIRCH; + } + else if (args[0].equalsIgnoreCase("redwood")) + { + tree = TreeType.REDWOOD; + } + else if (args[0].equalsIgnoreCase("tree")) + { + tree = TreeType.TREE; + } + else if (args[0].equalsIgnoreCase("redmushroom")) + { + tree = TreeType.RED_MUSHROOM; + } + else if (args[0].equalsIgnoreCase("brownmushroom")) + { + tree = TreeType.BROWN_MUSHROOM; + } + else if (args[0].equalsIgnoreCase("jungle")) + { + tree = TreeType.SMALL_JUNGLE; + } + else if (args[0].equalsIgnoreCase("junglebush")) + { + tree = TreeType.JUNGLE_BUSH; + } + else if (args[0].equalsIgnoreCase("swamp")) + { + tree = TreeType.SWAMP; + } + else if (args[0].equalsIgnoreCase("acacia")) + { + tree = TreeType.ACACIA; + } + else if (args[0].equalsIgnoreCase("darkoak")) + { + tree = TreeType.DARK_OAK; + } + else + { + throw new NotEnoughArgumentsException(); + } + } + catch (java.lang.NoSuchFieldError e) + { + Essentials.wrongVersion(); + } + + final Location loc = LocationUtil.getTarget(user.getBase()); + final Location safeLocation = LocationUtil.getSafeDestination(loc); + final boolean success = user.getWorld().generateTree(safeLocation, tree); + if (success) + { + user.sendMessage(tl("treeSpawned")); + } + else + { + user.sendMessage(tl("treeFailure")); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandunban.java b/Essentials/src/com/earth2me/essentials/commands/Commandunban.java new file mode 100644 index 0000000000..b4cb70bf5e --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandunban.java @@ -0,0 +1,51 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import com.earth2me.essentials.Console; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import java.util.logging.Level; +import org.bukkit.BanList; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.Server; + + +public class Commandunban extends EssentialsCommand +{ + public Commandunban() + { + super("unban"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + String name; + try + { + final User user = getPlayer(server, args, 0, true, true); + name = user.getName(); + ess.getServer().getBanList(BanList.Type.NAME).pardon(name); + } + catch (NoSuchFieldException e) + { + final OfflinePlayer player = server.getOfflinePlayer(args[0]); + name = player.getName(); + if (!player.isBanned()) + { + throw new Exception(tl("playerNotFound"), e); + } + ess.getServer().getBanList(BanList.Type.NAME).pardon(name); + } + + final String senderName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.NAME; + server.getLogger().log(Level.INFO, tl("playerUnbanned", senderName, name)); + + ess.broadcastMessage("essentials.ban.notify", tl("playerUnbanned", senderName, name)); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandunbanip.java b/Essentials/src/com/earth2me/essentials/commands/Commandunbanip.java new file mode 100644 index 0000000000..9157a3274c --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandunbanip.java @@ -0,0 +1,59 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import com.earth2me.essentials.Console; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.FormatUtil; +import java.util.logging.Level; +import org.bukkit.BanList; +import org.bukkit.Bukkit; +import org.bukkit.Server; + + +public class Commandunbanip extends EssentialsCommand +{ + public Commandunbanip() + { + super("unbanip"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + String ipAddress; + if (FormatUtil.validIP(args[0])) + { + ipAddress = args[0]; + } + else + { + try + { + User player = getPlayer(server, args, 0, true, true); + ipAddress = player.getLastLoginAddress(); + } + catch (PlayerNotFoundException ex) + { + ipAddress = args[0]; + } + } + + if (ipAddress.isEmpty()) + { + throw new PlayerNotFoundException(); + } + + + ess.getServer().getBanList(BanList.Type.IP).pardon(ipAddress); + final String senderName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.NAME; + server.getLogger().log(Level.INFO, tl("playerUnbanIpAddress", senderName, ipAddress)); + + ess.broadcastMessage("essentials.ban.notify", tl("playerUnbanIpAddress", senderName, ipAddress)); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandunlimited.java b/Essentials/src/com/earth2me/essentials/commands/Commandunlimited.java new file mode 100644 index 0000000000..c07f900b8d --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandunlimited.java @@ -0,0 +1,120 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import java.util.List; +import java.util.Locale; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.inventory.ItemStack; + + +public class Commandunlimited extends EssentialsCommand +{ + public Commandunlimited() + { + super("unlimited"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + User target = user; + + if (args.length > 1 && user.isAuthorized("essentials.unlimited.others")) + { + target = getPlayer(server, user, args, 1); + } + + if (args[0].equalsIgnoreCase("list")) + { + final String list = getList(target); + user.sendMessage(list); + } + else if (args[0].equalsIgnoreCase("clear")) + { + final List itemList = target.getUnlimited(); + + int index = 0; + while (itemList.size() > index) + { + final Integer item = itemList.get(index); + if (toggleUnlimited(user, target, item.toString()) == false) + { + index++; + } + } + } + else + { + toggleUnlimited(user, target, args[0]); + } + } + + private String getList(final User target) + { + final StringBuilder output = new StringBuilder(); + output.append(tl("unlimitedItems")).append(" "); + boolean first = true; + final List items = target.getUnlimited(); + if (items.isEmpty()) + { + output.append(tl("none")); + } + for (Integer integer : items) + { + if (!first) + { + output.append(", "); + } + first = false; + final String matname = Material.getMaterial(integer).toString().toLowerCase(Locale.ENGLISH).replace("_", ""); + output.append(matname); + } + + return output.toString(); + } + + private Boolean toggleUnlimited(final User user, final User target, final String item) throws Exception + { + final ItemStack stack = ess.getItemDb().get(item, 1); + stack.setAmount(Math.min(stack.getType().getMaxStackSize(), 2)); + + final String itemname = stack.getType().toString().toLowerCase(Locale.ENGLISH).replace("_", ""); + if (ess.getSettings().permissionBasedItemSpawn() + && (!user.isAuthorized("essentials.unlimited.item-all") + && !user.isAuthorized("essentials.unlimited.item-" + itemname) + && !user.isAuthorized("essentials.unlimited.item-" + stack.getTypeId()) + && !((stack.getType() == Material.WATER_BUCKET || stack.getType() == Material.LAVA_BUCKET) + && user.isAuthorized("essentials.unlimited.item-bucket")))) + { + throw new Exception(tl("unlimitedItemPermission", itemname)); + } + + String message = "disableUnlimited"; + boolean enableUnlimited = false; + if (!target.hasUnlimited(stack)) + { + message = "enableUnlimited"; + enableUnlimited = true; + if (!target.getBase().getInventory().containsAtLeast(stack, stack.getAmount())) + { + target.getBase().getInventory().addItem(stack); + } + } + + if (user != target) + { + user.sendMessage(tl(message, itemname, target.getDisplayName())); + } + target.sendMessage(tl(message, itemname, target.getDisplayName())); + target.setUnlimited(stack, enableUnlimited); + + return true; + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandvanish.java b/Essentials/src/com/earth2me/essentials/commands/Commandvanish.java new file mode 100644 index 0000000000..fd2bd6d924 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandvanish.java @@ -0,0 +1,67 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Server; + + +public class Commandvanish extends EssentialsToggleCommand +{ + public Commandvanish() + { + super("vanish", "essentials.vanish.others"); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + toggleOtherPlayers(server, sender, args); + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length == 1) + { + Boolean toggle = matchToggleArgument(args[0]); + if (toggle == null && user.isAuthorized(othersPermission)) + { + toggleOtherPlayers(server, user.getSource(), args); + } + else + { + togglePlayer(user.getSource(), user, toggle); + } + } + else if (args.length == 2 && user.isAuthorized(othersPermission)) + { + toggleOtherPlayers(server, user.getSource(), args); + } + else + { + togglePlayer(user.getSource(), user, null); + } + } + + @Override + void togglePlayer(CommandSource sender, User user, Boolean enabled) throws NotEnoughArgumentsException + { + if (enabled == null) + { + enabled = !user.isVanished(); + } + + user.setVanished(enabled); + user.sendMessage(tl("vanish", user.getDisplayName(), enabled ? tl("enabled") : tl("disabled"))); + + if (enabled == true) + { + user.sendMessage(tl("vanished")); + } + if (!sender.isPlayer() || !sender.getPlayer().equals(user.getBase())) + { + sender.sendMessage(tl("vanish", user.getDisplayName(), enabled ? tl("enabled") : tl("disabled"))); + } + } +} \ No newline at end of file diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandwarp.java b/Essentials/src/com/earth2me/essentials/commands/Commandwarp.java new file mode 100644 index 0000000000..8c2e88a4a0 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandwarp.java @@ -0,0 +1,132 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import com.earth2me.essentials.api.IWarps; +import com.earth2me.essentials.utils.NumberUtil; +import com.earth2me.essentials.utils.StringUtil; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import net.ess3.api.IUser; +import org.bukkit.Server; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + + +public class Commandwarp extends EssentialsCommand +{ + private static final int WARPS_PER_PAGE = 20; + + public Commandwarp() + { + super("warp"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + if (args.length == 0 || args[0].matches("[0-9]+")) + { + if (!user.isAuthorized("essentials.warp.list")) + { + throw new Exception(tl("warpListPermission")); + } + warpList(user.getSource(), args, user); + throw new NoChargeException(); + } + if (args.length > 0) + { + //TODO: Remove 'otherplayers' permission. + User otherUser = null; + if (args.length == 2 && (user.isAuthorized("essentials.warp.otherplayers") || user.isAuthorized("essentials.warp.others"))) + { + otherUser = getPlayer(server, user, args, 1); + warpUser(user, otherUser, args[0]); + throw new NoChargeException(); + } + warpUser(user, user, args[0]); + throw new NoChargeException(); + } + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 2 || NumberUtil.isInt(args[0])) + { + warpList(sender, args, null); + throw new NoChargeException(); + } + User otherUser = getPlayer(server, args, 1, true, false); + otherUser.getTeleport().warp(otherUser, args[0], null, TeleportCause.COMMAND); + throw new NoChargeException(); + + } + + //TODO: Use one of the new text classes, like /help ? + private void warpList(final CommandSource sender, final String[] args, final IUser user) throws Exception + { + final IWarps warps = ess.getWarps(); + final List warpNameList = new ArrayList(warps.getList()); + + if (user != null) + { + final Iterator iterator = warpNameList.iterator(); + while (iterator.hasNext()) + { + final String warpName = iterator.next(); + if (ess.getSettings().getPerWarpPermission() && !user.isAuthorized("essentials.warps." + warpName)) + { + iterator.remove(); + } + } + } + if (warpNameList.isEmpty()) + { + throw new Exception(tl("noWarpsDefined")); + } + int page = 1; + if (args.length > 0 && NumberUtil.isInt(args[0])) + { + page = Integer.parseInt(args[0]); + } + + final int maxPages = (int)Math.ceil(warpNameList.size() / (double)WARPS_PER_PAGE); + + if (page > maxPages) + { + page = maxPages; + } + + final int warpPage = (page - 1) * WARPS_PER_PAGE; + final String warpList = StringUtil.joinList(warpNameList.subList(warpPage, warpPage + Math.min(warpNameList.size() - warpPage, WARPS_PER_PAGE))); + + if (warpNameList.size() > WARPS_PER_PAGE) + { + sender.sendMessage(tl("warpsCount", warpNameList.size(), page, maxPages)); + sender.sendMessage(tl("warpList", warpList)); + } + else + { + sender.sendMessage(tl("warps", warpList)); + } + } + + private void warpUser(final User owner, final User user, final String name) throws Exception + { + final Trade chargeWarp = new Trade("warp-" + name.toLowerCase(Locale.ENGLISH).replace('_', '-'), ess); + final Trade chargeCmd = new Trade(this.getName(), ess); + final BigDecimal fullCharge = chargeWarp.getCommandCost(user).add(chargeCmd.getCommandCost(user)); + final Trade charge = new Trade(fullCharge, ess); + charge.isAffordableFor(owner); + if (ess.getSettings().getPerWarpPermission() && !owner.isAuthorized("essentials.warps." + name)) + { + throw new Exception(tl("warpUsePermission")); + } + owner.getTeleport().warp(user, name, charge, TeleportCause.COMMAND); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandweather.java b/Essentials/src/com/earth2me/essentials/commands/Commandweather.java new file mode 100644 index 0000000000..0b7ae924fd --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandweather.java @@ -0,0 +1,92 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import org.bukkit.Server; +import org.bukkit.World; + + +public class Commandweather extends EssentialsCommand +{ + public Commandweather() + { + super("weather"); + } + + //TODO: Remove duplication + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + final boolean isStorm; + if (args.length < 1) + { + if (commandLabel.equalsIgnoreCase("sun") || commandLabel.equalsIgnoreCase("esun")) + { + isStorm = false; + } + else if (commandLabel.equalsIgnoreCase("storm") || commandLabel.equalsIgnoreCase("estorm") + || commandLabel.equalsIgnoreCase("rain") || commandLabel.equalsIgnoreCase("erain")) + { + isStorm = true; + } + else + { + throw new NotEnoughArgumentsException(); + } + } + else + { + isStorm = args[0].equalsIgnoreCase("storm"); + } + final World world = user.getWorld(); + if (args.length > 1) + { + + world.setStorm(isStorm); + world.setWeatherDuration(Integer.parseInt(args[1]) * 20); + user.sendMessage(isStorm + ? tl("weatherStormFor", world.getName(), args[1]) + : tl("weatherSunFor", world.getName(), args[1])); + } + else + { + world.setStorm(isStorm); + user.sendMessage(isStorm + ? tl("weatherStorm", world.getName()) + : tl("weatherSun", world.getName())); + } + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 2) //running from console means inserting a world arg before other args + { + throw new Exception("When running from console, usage is: /" + commandLabel + " [duration]"); + } + + final boolean isStorm = args[1].equalsIgnoreCase("storm"); + final World world = server.getWorld(args[0]); + if (world == null) + { + throw new Exception(tl("weatherInvalidWorld", args[0])); + } + if (args.length > 2) + { + + world.setStorm(isStorm); + world.setWeatherDuration(Integer.parseInt(args[2]) * 20); + sender.sendMessage(isStorm + ? tl("weatherStormFor", world.getName(), args[2]) + : tl("weatherSunFor", world.getName(), args[2])); + } + else + { + world.setStorm(isStorm); + sender.sendMessage(isStorm + ? tl("weatherStorm", world.getName()) + : tl("weatherSun", world.getName())); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandwhois.java b/Essentials/src/com/earth2me/essentials/commands/Commandwhois.java new file mode 100644 index 0000000000..a22bd48708 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandwhois.java @@ -0,0 +1,65 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.craftbukkit.SetExpFix; +import com.earth2me.essentials.utils.DateUtil; +import com.earth2me.essentials.utils.NumberUtil; +import java.util.Locale; +import org.bukkit.Server; + + +public class Commandwhois extends EssentialsCommand +{ + public Commandwhois() + { + super("whois"); + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + User user = getPlayer(server, sender, args, 0); + + sender.sendMessage(tl("whoisTop", user.getName())); + user.setDisplayNick(); + sender.sendMessage(tl("whoisNick", user.getDisplayName())); + sender.sendMessage(tl("whoisHealth", user.getBase().getHealth())); + sender.sendMessage(tl("whoisHunger", user.getBase().getFoodLevel(), user.getBase().getSaturation())); + sender.sendMessage(tl("whoisExp", SetExpFix.getTotalExperience(user.getBase()), user.getBase().getLevel())); + sender.sendMessage(tl("whoisLocation", user.getLocation().getWorld().getName(), user.getLocation().getBlockX(), user.getLocation().getBlockY(), user.getLocation().getBlockZ())); + if (!ess.getSettings().isEcoDisabled()) + { + sender.sendMessage(tl("whoisMoney", NumberUtil.displayCurrency(user.getMoney(), ess))); + } + sender.sendMessage(tl("whoisIPAddress", user.getBase().getAddress().getAddress().toString())); + final String location = user.getGeoLocation(); + if (location != null + && (sender.isPlayer() ? ess.getUser(sender.getPlayer()).isAuthorized("essentials.geoip.show") : true)) + { + sender.sendMessage(tl("whoisGeoLocation", location)); + } + sender.sendMessage(tl("whoisGamemode", tl(user.getBase().getGameMode().toString().toLowerCase(Locale.ENGLISH)))); + sender.sendMessage(tl("whoisGod", (user.isGodModeEnabled() ? tl("true") : tl("false")))); + sender.sendMessage(tl("whoisOp", (user.getBase().isOp() ? tl("true") : tl("false")))); + sender.sendMessage(tl("whoisFly", user.getBase().getAllowFlight() ? tl("true") : tl("false"), user.getBase().isFlying() ? tl("flying") : tl("notFlying"))); + sender.sendMessage(tl("whoisAFK", (user.isAfk() ? tl("true") : tl("false")))); + sender.sendMessage(tl("whoisJail", (user.isJailed() + ? user.getJailTimeout() > 0 + ? DateUtil.formatDateDiff(user.getJailTimeout()) + : tl("true") + : tl("false")))); + sender.sendMessage(tl("whoisMuted", (user.isMuted() + ? user.getMuteTimeout() > 0 + ? DateUtil.formatDateDiff(user.getMuteTimeout()) + : tl("true") + : tl("false")))); + + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandworkbench.java b/Essentials/src/com/earth2me/essentials/commands/Commandworkbench.java new file mode 100644 index 0000000000..61b0f19f4c --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandworkbench.java @@ -0,0 +1,20 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.User; +import org.bukkit.Server; + + +public class Commandworkbench extends EssentialsCommand +{ + public Commandworkbench() + { + super("workbench"); + } + + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + user.getBase().openWorkbench(null, true); + } +} \ No newline at end of file diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandworld.java b/Essentials/src/com/earth2me/essentials/commands/Commandworld.java new file mode 100644 index 0000000000..1a6d3ea7ba --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandworld.java @@ -0,0 +1,84 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import java.util.List; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + + +public class Commandworld extends EssentialsCommand +{ + public Commandworld() + { + super("world"); + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + World world; + + if (args.length < 1) + { + World nether = null; + + final List worlds = server.getWorlds(); + + for (World world2 : worlds) + { + if (world2.getEnvironment() == World.Environment.NETHER) + { + nether = world2; + break; + } + } + if (nether == null) + { + return; + } + world = user.getWorld() == nether ? worlds.get(0) : nether; + } + else + { + world = ess.getWorld(getFinalArg(args, 0)); + if (world == null) + { + user.sendMessage(tl("invalidWorld")); + user.sendMessage(tl("possibleWorlds", server.getWorlds().size() - 1)); + user.sendMessage(tl("typeWorldName")); + throw new NoChargeException(); + } + } + + if (ess.getSettings().isWorldTeleportPermissions() && !user.isAuthorized("essentials.worlds." + world.getName())) + { + throw new Exception(tl("noPerm", "essentials.worlds." + world.getName())); + } + + double factor; + if (user.getWorld().getEnvironment() == World.Environment.NETHER && world.getEnvironment() == World.Environment.NORMAL) + { + factor = 8.0; + } + else if (user.getWorld().getEnvironment() == World.Environment.NORMAL && world.getEnvironment() == World.Environment.NETHER) + { + factor = 1.0 / 8.0; + } + else + { + factor = 1.0; + } + + final Location loc = user.getLocation(); + final Location target = new Location(world, loc.getBlockX() * factor + .5, loc.getBlockY(), loc.getBlockZ() * factor + .5); + + final Trade charge = new Trade(this.getName(), ess); + charge.isAffordableFor(user); + user.getTeleport().teleport(target, charge, TeleportCause.COMMAND); + throw new NoChargeException(); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandworth.java b/Essentials/src/com/earth2me/essentials/commands/Commandworth.java new file mode 100644 index 0000000000..648eb4139f --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandworth.java @@ -0,0 +1,137 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.NumberUtil; +import java.math.BigDecimal; +import java.util.List; +import java.util.Locale; +import org.bukkit.Server; +import org.bukkit.inventory.ItemStack; + + +public class Commandworth extends EssentialsCommand +{ + public Commandworth() + { + super("worth"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + BigDecimal totalWorth = BigDecimal.ZERO; + String type = ""; + + List is = ess.getItemDb().getMatching(user, args); + int count = 0; + + boolean isBulk = is.size() > 1; + + for (ItemStack stack : is) + { + try + { + if (stack.getAmount() > 0) + { + totalWorth = totalWorth.add(itemWorth(user.getSource(), user, stack, args)); + stack = stack.clone(); + count++; + for (ItemStack zeroStack : is) + { + if (zeroStack.isSimilar(stack)) + { + zeroStack.setAmount(0); + } + } + } + + } + catch (Exception e) + { + if (!isBulk) + { + throw e; + } + } + } + if (count > 1) + { + if (args.length > 0 && args[0].equalsIgnoreCase("blocks")) + { + user.sendMessage(tl("totalSellableBlocks", type, NumberUtil.displayCurrency(totalWorth, ess))); + } + else + { + user.sendMessage(tl("totalSellableAll", type, NumberUtil.displayCurrency(totalWorth, ess))); + } + } + } + + @Override + public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + ItemStack stack = ess.getItemDb().get(args[0]); + + itemWorth(sender, null, stack, args); + } + + private BigDecimal itemWorth(CommandSource sender, User user, ItemStack is, String[] args) throws Exception + { + int amount = 1; + if (user == null) + { + if (args.length > 1) + { + try + { + amount = Integer.parseInt(args[1].replaceAll("[^0-9]", "")); + } + catch (NumberFormatException ex) + { + throw new NotEnoughArgumentsException(ex); + } + + } + } + else + { + amount = ess.getWorth().getAmount(ess, user, is, args, true); + } + + BigDecimal worth = ess.getWorth().getPrice(is); + + if (worth == null) + { + throw new Exception(tl("itemCannotBeSold")); + } + + if (amount < 0) + { + amount = 0; + } + + BigDecimal result = worth.multiply(BigDecimal.valueOf(amount)); + + sender.sendMessage(is.getDurability() != 0 + ? tl("worthMeta", + is.getType().toString().toLowerCase(Locale.ENGLISH).replace("_", ""), + is.getDurability(), + NumberUtil.displayCurrency(result, ess), + amount, + NumberUtil.displayCurrency(worth, ess)) + : tl("worth", + is.getType().toString().toLowerCase(Locale.ENGLISH).replace("_", ""), + NumberUtil.displayCurrency(result, ess), + amount, + NumberUtil.displayCurrency(worth, ess))); + + return result; + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/EssentialsCommand.java b/Essentials/src/com/earth2me/essentials/commands/EssentialsCommand.java new file mode 100644 index 0000000000..bfd1843be8 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/EssentialsCommand.java @@ -0,0 +1,243 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.*; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.utils.FormatUtil; +import java.util.List; +import java.util.Locale; +import java.util.UUID; +import java.util.logging.Logger; +import net.ess3.api.IEssentials; +import org.bukkit.Server; +import org.bukkit.command.Command; +import org.bukkit.entity.Player; + + +public abstract class EssentialsCommand implements IEssentialsCommand +{ + private final transient String name; + protected transient IEssentials ess; + protected transient IEssentialsModule module; + protected static final Logger logger = Logger.getLogger("Essentials"); + + protected EssentialsCommand(final String name) + { + this.name = name; + } + + @Override + public void setEssentials(final IEssentials ess) + { + this.ess = ess; + } + + @Override + public void setEssentialsModule(final IEssentialsModule module) + { + this.module = module; + } + + @Override + public String getName() + { + return name; + } + + // Get online players - only show vanished if source has permission + protected User getPlayer(final Server server, final CommandSource sender, final String[] args, final int pos) throws PlayerNotFoundException, NotEnoughArgumentsException + { + if (sender.isPlayer()) + { + User user = ess.getUser(sender.getPlayer()); + return getPlayer(server, user, args, pos); + } + return getPlayer(server, args, pos, true, false); + } + + // Get online players - only show vanished if source has permission + protected User getPlayer(final Server server, final CommandSource sender, final String searchTerm) throws PlayerNotFoundException, NotEnoughArgumentsException + { + if (sender.isPlayer()) + { + User user = ess.getUser(sender.getPlayer()); + return getPlayer(server, user, searchTerm, user.canInteractVanished(), false); + } + return getPlayer(server, searchTerm, true, false); + } + + // Get online players - only show vanished if source has permission + protected User getPlayer(final Server server, final User user, final String[] args, final int pos) throws PlayerNotFoundException, NotEnoughArgumentsException + { + return getPlayer(server, user, args, pos, user.canInteractVanished(), false); + } + + // Get online or offline players, this method allows for raw access + protected User getPlayer(final Server server, final String[] args, final int pos, boolean getHidden, final boolean getOffline) throws PlayerNotFoundException, NotEnoughArgumentsException + { + return getPlayer(server, null, args, pos, getHidden, getOffline); + } + + private User getPlayer(final Server server, final User sourceUser, final String[] args, final int pos, boolean getHidden, final boolean getOffline) throws PlayerNotFoundException, NotEnoughArgumentsException + { + if (args.length <= pos) + { + throw new NotEnoughArgumentsException(); + } + if (args[pos].isEmpty()) + { + throw new PlayerNotFoundException(); + } + return getPlayer(server, sourceUser, args[pos], getHidden, getOffline); + } + + // Get online or offline players, this method allows for raw access + protected User getPlayer(final Server server, final String searchTerm, boolean getHidden, final boolean getOffline) throws PlayerNotFoundException + { + return getPlayer(server, null, searchTerm, getHidden, getOffline); + } + + private User getPlayer(final Server server, final User sourceUser, final String searchTerm, boolean getHidden, final boolean getOffline) throws PlayerNotFoundException + { + final User user; + Player exPlayer; + + try + { + exPlayer = server.getPlayer(UUID.fromString(searchTerm)); + } + catch (IllegalArgumentException ex) + { + exPlayer = server.getPlayer(searchTerm); + } + + if (exPlayer != null) + { + user = ess.getUser(exPlayer); + } + else + { + user = ess.getUser(searchTerm); + } + + if (user != null) + { + if (!getOffline && !user.getBase().isOnline()) + { + throw new PlayerNotFoundException(); + } + + if (getHidden || canInteractWith(sourceUser, user)) + { + return user; + } + throw new PlayerNotFoundException(); + } + final List matches = server.matchPlayer(searchTerm); + + if (matches.isEmpty()) + { + final String matchText = searchTerm.toLowerCase(Locale.ENGLISH); + for (User userMatch : ess.getOnlineUsers()) + { + if (getHidden || canInteractWith(sourceUser, userMatch)) + { + final String displayName = FormatUtil.stripFormat(userMatch.getDisplayName()).toLowerCase(Locale.ENGLISH); + if (displayName.contains(matchText)) + { + return userMatch; + } + } + } + } + else + { + for (Player player : matches) + { + final User userMatch = ess.getUser(player); + if (userMatch.getDisplayName().startsWith(searchTerm) && (getHidden || canInteractWith(sourceUser, userMatch))) + { + return userMatch; + } + } + final User userMatch = ess.getUser(matches.get(0)); + if (getHidden || canInteractWith(sourceUser, userMatch)) + { + return userMatch; + } + } + throw new PlayerNotFoundException(); + } + + @Override + public final void run(final Server server, + final User user, + final String commandLabel, + final Command cmd, + final String[] args) throws Exception + { + final Trade charge = new Trade(this.getName(), ess); + charge.isAffordableFor(user); + run(server, user, commandLabel, args); + charge.charge(user); + } + + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + run(server, user.getSource(), commandLabel, args); + } + + @Override + public final void run(final Server server, final CommandSource sender, final String commandLabel, final Command cmd, final String[] args) throws Exception + { + run(server, sender, commandLabel, args); + } + + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + throw new Exception(tl("onlyPlayers", commandLabel)); + } + + public static String getFinalArg(final String[] args, final int start) + { + final StringBuilder bldr = new StringBuilder(); + for (int i = start; i < args.length; i++) + { + if (i != start) + { + bldr.append(" "); + } + bldr.append(args[i]); + } + return bldr.toString(); + } + + boolean canInteractWith(CommandSource interactor, User interactee) + { + if (interactor == null) + { + return !interactee.isHidden(); + } + + if (interactor.isPlayer()) + { + return canInteractWith(ess.getUser(interactor.getPlayer()), interactee); + } + + return true; // console + } + + private static boolean canInteractWith(User interactor, User interactee) + { + if (interactor == null) + { + return !interactee.isHidden(); + } + + if (interactor.equals(interactee)) + { + return true; + } + + return interactor.getBase().canSee(interactee.getBase()); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/EssentialsLoopCommand.java b/Essentials/src/com/earth2me/essentials/commands/EssentialsLoopCommand.java new file mode 100644 index 0000000000..ccb297f143 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/EssentialsLoopCommand.java @@ -0,0 +1,149 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.ChargeException; +import com.earth2me.essentials.CommandSource; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.FormatUtil; +import java.util.List; +import java.util.Locale; +import java.util.UUID; +import net.ess3.api.MaxMoneyException; +import org.bukkit.Server; +import org.bukkit.entity.Player; + + +public abstract class EssentialsLoopCommand extends EssentialsCommand +{ + public EssentialsLoopCommand(String command) + { + super(command); + } + + protected void loopOfflinePlayers(final Server server, final CommandSource sender, final boolean multipleStringMatches, boolean matchWildcards, final String searchTerm, final String[] commandArgs) + throws PlayerNotFoundException, NotEnoughArgumentsException, PlayerExemptException, ChargeException, MaxMoneyException + { + if (searchTerm.isEmpty()) + { + throw new PlayerNotFoundException(); + } + + if (matchWildcards && searchTerm.contentEquals("**")) + { + for (UUID sUser : ess.getUserMap().getAllUniqueUsers()) + { + final User matchedUser = ess.getUser(sUser); + updatePlayer(server, sender, matchedUser, commandArgs); + } + } + else if (matchWildcards && searchTerm.contentEquals("*")) + { + boolean skipHidden = sender.isPlayer() && !ess.getUser(sender.getPlayer()).canInteractVanished(); + for (User onlineUser : ess.getOnlineUsers()) + { + if (skipHidden && onlineUser.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(onlineUser.getBase())) + { + continue; + } + updatePlayer(server, sender, onlineUser, commandArgs); + } + } + else if (multipleStringMatches) + { + if (searchTerm.trim().length() < 3) + { + throw new PlayerNotFoundException(); + } + final List matchedPlayers = server.matchPlayer(searchTerm); + if (matchedPlayers.isEmpty()) + { + final User matchedUser = getPlayer(server, searchTerm, true, true); + updatePlayer(server, sender, matchedUser, commandArgs); + } + for (Player matchPlayer : matchedPlayers) + { + final User matchedUser = ess.getUser(matchPlayer); + updatePlayer(server, sender, matchedUser, commandArgs); + } + } + else + { + final User user = getPlayer(server, searchTerm, true, true); + updatePlayer(server, sender, user, commandArgs); + } + } + + protected void loopOnlinePlayers(final Server server, final CommandSource sender, final boolean multipleStringMatches, boolean matchWildcards, final String searchTerm, final String[] commandArgs) + throws PlayerNotFoundException, NotEnoughArgumentsException, PlayerExemptException, ChargeException, MaxMoneyException + { + if (searchTerm.isEmpty()) + { + throw new PlayerNotFoundException(); + } + + boolean skipHidden = sender.isPlayer() && !ess.getUser(sender.getPlayer()).canInteractVanished(); + + if (matchWildcards && (searchTerm.contentEquals("**") || searchTerm.contentEquals("*"))) + { + for (User onlineUser : ess.getOnlineUsers()) + { + if (skipHidden && onlineUser.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(onlineUser.getBase())) + { + continue; + } + updatePlayer(server, sender, onlineUser, commandArgs); + } + } + else if (multipleStringMatches) + { + if (searchTerm.trim().length() < 2) + { + throw new PlayerNotFoundException(); + } + boolean foundUser = false; + final List matchedPlayers = server.matchPlayer(searchTerm); + + if (matchedPlayers.isEmpty()) + { + final String matchText = searchTerm.toLowerCase(Locale.ENGLISH); + for (User player : ess.getOnlineUsers()) + { + if (skipHidden && player.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(player.getBase())) + { + continue; + } + final String displayName = FormatUtil.stripFormat(player.getDisplayName()).toLowerCase(Locale.ENGLISH); + if (displayName.contains(matchText)) + { + foundUser = true; + updatePlayer(server, sender, player, commandArgs); + } + } + } + else + { + for (Player matchPlayer : matchedPlayers) + { + final User player = ess.getUser(matchPlayer); + if (skipHidden && player.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(matchPlayer)) + { + continue; + } + foundUser = true; + updatePlayer(server, sender, player, commandArgs); + } + } + if (!foundUser) + { + throw new PlayerNotFoundException(); + } + } + else + { + final User player = getPlayer(server, sender, searchTerm); + updatePlayer(server, sender, player, commandArgs); + } + } + + protected abstract void updatePlayer(Server server, CommandSource sender, User user, String[] args) + throws NotEnoughArgumentsException, PlayerExemptException, ChargeException, MaxMoneyException; +} diff --git a/Essentials/src/com/earth2me/essentials/commands/EssentialsToggleCommand.java b/Essentials/src/com/earth2me/essentials/commands/EssentialsToggleCommand.java new file mode 100644 index 0000000000..deed20a13f --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/EssentialsToggleCommand.java @@ -0,0 +1,76 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import com.earth2me.essentials.User; +import java.util.List; +import org.bukkit.Server; +import org.bukkit.entity.Player; + + +public abstract class EssentialsToggleCommand extends EssentialsCommand +{ + String othersPermission; + + public EssentialsToggleCommand(String command, String othersPermission) + { + super(command); + this.othersPermission = othersPermission; + } + + protected Boolean matchToggleArgument(final String arg) + { + if (arg.equalsIgnoreCase("on") || arg.startsWith("ena") || arg.equalsIgnoreCase("1")) + { + return true; + } + else if (arg.equalsIgnoreCase("off") || arg.startsWith("dis") || arg.equalsIgnoreCase("0")) + { + return false; + } + return null; + } + + protected void toggleOtherPlayers(final Server server, final CommandSource sender, final String[] args) throws PlayerNotFoundException, NotEnoughArgumentsException + { + if (args.length < 1 || args[0].trim().length() < 2) + { + throw new PlayerNotFoundException(); + } + + boolean skipHidden = sender.isPlayer() && !ess.getUser(sender.getPlayer()).canInteractVanished(); + boolean foundUser = false; + final List matchedPlayers = server.matchPlayer(args[0]); + for (Player matchPlayer : matchedPlayers) + { + final User player = ess.getUser(matchPlayer); + if (skipHidden && player.isHidden(sender.getPlayer()) && !sender.getPlayer().canSee(matchPlayer)) + { + continue; + } + foundUser = true; + if (args.length > 1) + { + Boolean toggle = matchToggleArgument(args[1]); + if (toggle == true) + { + togglePlayer(sender, player, true); + } + else + { + togglePlayer(sender, player, false); + } + } + else + { + togglePlayer(sender, player, null); + } + } + if (!foundUser) + { + throw new PlayerNotFoundException(); + } + } + + // Make sure when implementing this method that all 3 Boolean states are handled, 'null' should toggle the existing state. + abstract void togglePlayer(CommandSource sender, User user, Boolean enabled) throws NotEnoughArgumentsException; +} diff --git a/Essentials/src/com/earth2me/essentials/commands/IEssentialsCommand.java b/Essentials/src/com/earth2me/essentials/commands/IEssentialsCommand.java new file mode 100644 index 0000000000..1eb2418881 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/IEssentialsCommand.java @@ -0,0 +1,24 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.CommandSource; +import com.earth2me.essentials.IEssentialsModule; +import com.earth2me.essentials.User; +import net.ess3.api.IEssentials; +import org.bukkit.Server; +import org.bukkit.command.Command; + + +public interface IEssentialsCommand +{ + String getName(); + + void run(Server server, User user, String commandLabel, Command cmd, String[] args) + throws Exception; + + void run(Server server, CommandSource sender, String commandLabel, Command cmd, String[] args) + throws Exception; + + void setEssentials(IEssentials ess); + + void setEssentialsModule(IEssentialsModule module); +} diff --git a/Essentials/src/com/earth2me/essentials/commands/NoChargeException.java b/Essentials/src/com/earth2me/essentials/commands/NoChargeException.java new file mode 100644 index 0000000000..bb00887921 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/NoChargeException.java @@ -0,0 +1,10 @@ +package com.earth2me.essentials.commands; + + +public class NoChargeException extends Exception +{ + public NoChargeException() + { + super("Will charge later"); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/NotEnoughArgumentsException.java b/Essentials/src/com/earth2me/essentials/commands/NotEnoughArgumentsException.java new file mode 100644 index 0000000000..0c47b98932 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/NotEnoughArgumentsException.java @@ -0,0 +1,20 @@ +package com.earth2me.essentials.commands; + + +public class NotEnoughArgumentsException extends Exception +{ + public NotEnoughArgumentsException() + { + super(""); + } + + public NotEnoughArgumentsException(final String string) + { + super(string); + } + + public NotEnoughArgumentsException(final Throwable ex) + { + super("", ex); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/PlayerExemptException.java b/Essentials/src/com/earth2me/essentials/commands/PlayerExemptException.java new file mode 100644 index 0000000000..a916402aae --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/PlayerExemptException.java @@ -0,0 +1,9 @@ +package com.earth2me.essentials.commands; + +public class PlayerExemptException extends NoSuchFieldException +{ + public PlayerExemptException(String message) + { + super(message); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/PlayerNotFoundException.java b/Essentials/src/com/earth2me/essentials/commands/PlayerNotFoundException.java new file mode 100644 index 0000000000..1f5a00fbd0 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/PlayerNotFoundException.java @@ -0,0 +1,11 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; + +public class PlayerNotFoundException extends NoSuchFieldException +{ + public PlayerNotFoundException() + { + super(tl("playerNotFound")); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/QuietAbortException.java b/Essentials/src/com/earth2me/essentials/commands/QuietAbortException.java new file mode 100644 index 0000000000..2667ef0d36 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/QuietAbortException.java @@ -0,0 +1,15 @@ +package com.earth2me.essentials.commands; + + +public class QuietAbortException extends Exception +{ + public QuietAbortException() + { + super(); + } + + public QuietAbortException(String message) + { + super(message); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/WarpNotFoundException.java b/Essentials/src/com/earth2me/essentials/commands/WarpNotFoundException.java new file mode 100644 index 0000000000..38573bfda5 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/WarpNotFoundException.java @@ -0,0 +1,16 @@ +package com.earth2me.essentials.commands; + +import static com.earth2me.essentials.I18n.tl; + +public class WarpNotFoundException extends Exception +{ + public WarpNotFoundException() + { + super(tl("warpNotExist")); + } + + public WarpNotFoundException(String message) + { + super(message); + } +} diff --git a/Essentials/src/com/earth2me/essentials/craftbukkit/BanLookup.java b/Essentials/src/com/earth2me/essentials/craftbukkit/BanLookup.java new file mode 100644 index 0000000000..e5d26667d2 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/craftbukkit/BanLookup.java @@ -0,0 +1,36 @@ +package com.earth2me.essentials.craftbukkit; + +import com.earth2me.essentials.User; +import java.util.Iterator; +import java.util.Set; +import net.ess3.api.IEssentials; +import org.bukkit.BanEntry; +import org.bukkit.BanList; + + +public class BanLookup +{ + public static Boolean isBanned(IEssentials ess, User user) + { + return isBanned(ess, user.getName()); + } + + public static Boolean isBanned(IEssentials ess, String name) + { + return getBanEntry(ess, name) != null; + } + + public static BanEntry getBanEntry(IEssentials ess, String name) + { + Set benteries = ess.getServer().getBanList(BanList.Type.NAME).getBanEntries(); + for (BanEntry banEnt : benteries) + { + if (banEnt.getTarget().equals(name)) + { + return banEnt; + } + } + return null; + } + +} diff --git a/Essentials/src/com/earth2me/essentials/craftbukkit/FakeWorld.java b/Essentials/src/com/earth2me/essentials/craftbukkit/FakeWorld.java new file mode 100644 index 0000000000..df7a237fac --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/craftbukkit/FakeWorld.java @@ -0,0 +1,744 @@ +package com.earth2me.essentials.craftbukkit; + +import java.io.File; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import org.bukkit.*; +import org.bukkit.block.Biome; +import org.bukkit.block.Block; +import org.bukkit.entity.*; +import org.bukkit.generator.BlockPopulator; +import org.bukkit.generator.ChunkGenerator; +import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.MetadataValue; +import org.bukkit.plugin.Plugin; +import org.bukkit.util.Vector; + + +public class FakeWorld implements World +{ + private final String name; + private final Environment env; + + public FakeWorld(String string, Environment environment) + { + this.name = string; + this.env = environment; + } + + @Override + public Block getBlockAt(int i, int i1, int i2) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Block getBlockAt(Location lctn) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getBlockTypeIdAt(int i, int i1, int i2) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getBlockTypeIdAt(Location lctn) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getHighestBlockYAt(int i, int i1) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getHighestBlockYAt(Location lctn) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Chunk getChunkAt(int i, int i1) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Chunk getChunkAt(Location lctn) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Chunk getChunkAt(Block block) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isChunkLoaded(Chunk chunk) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Chunk[] getLoadedChunks() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void loadChunk(Chunk chunk) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isChunkLoaded(int i, int i1) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void loadChunk(int i, int i1) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean loadChunk(int i, int i1, boolean bln) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean unloadChunk(int i, int i1) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean unloadChunk(int i, int i1, boolean bln) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean unloadChunk(int i, int i1, boolean bln, boolean bln1) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean unloadChunkRequest(int i, int i1) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean unloadChunkRequest(int i, int i1, boolean bln) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean regenerateChunk(int i, int i1) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean refreshChunk(int i, int i1) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Item dropItem(Location lctn, ItemStack is) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Item dropItemNaturally(Location lctn, ItemStack is) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Arrow spawnArrow(Location lctn, Vector vector, float f, float f1) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean generateTree(Location lctn, TreeType tt) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean generateTree(Location lctn, TreeType tt, BlockChangeDelegate bcd) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LivingEntity spawnCreature(Location lctn, CreatureType ct) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LightningStrike strikeLightning(Location lctn) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LightningStrike strikeLightningEffect(Location lctn) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List getEntities() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List getLivingEntities() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List getPlayers() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getName() + { + return name; + } + + @Override + public Location getSpawnLocation() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean setSpawnLocation(int i, int i1, int i2) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long getTime() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setTime(long l) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long getFullTime() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setFullTime(long l) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean hasStorm() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setStorm(boolean bln) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getWeatherDuration() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setWeatherDuration(int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isThundering() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setThundering(boolean bln) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getThunderDuration() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setThunderDuration(int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Environment getEnvironment() + { + return env; + } + + @Override + public long getSeed() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean getPVP() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setPVP(boolean bln) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void save() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean createExplosion(double d, double d1, double d2, float f) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean createExplosion(Location lctn, float f) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ChunkGenerator getGenerator() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List getPopulators() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void playEffect(Location lctn, Effect effect, int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void playEffect(Location lctn, Effect effect, int i, int i1) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean createExplosion(double d, double d1, double d2, float f, boolean bln) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean createExplosion(Location lctn, float f, boolean bln) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public T spawn(Location lctn, Class type) throws IllegalArgumentException + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ChunkSnapshot getEmptyChunkSnapshot(int i, int i1, boolean bln, boolean bln1) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setSpawnFlags(boolean bln, boolean bln1) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean getAllowAnimals() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean getAllowMonsters() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public UUID getUID() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Block getHighestBlockAt(int i, int i1) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Block getHighestBlockAt(Location lctn) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Biome getBiome(int i, int i1) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public double getTemperature(int i, int i1) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public double getHumidity(int i, int i1) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean unloadChunk(Chunk chunk) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getMaxHeight() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean getKeepSpawnInMemory() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setKeepSpawnInMemory(boolean bln) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isAutoSave() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setAutoSave(boolean bln) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Difficulty getDifficulty() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setDifficulty(Difficulty difficulty) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getSeaLevel() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public File getWorldFolder() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getEntitiesByClass(Class... types) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public WorldType getWorldType() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void sendPluginMessage(Plugin plugin, String string, byte[] bytes) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Set getListeningPluginChannels() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean canGenerateStructures() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long getTicksPerAnimalSpawns() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setTicksPerAnimalSpawns(int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long getTicksPerMonsterSpawns() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setTicksPerMonsterSpawns(int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getEntitiesByClass(Class type) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getEntitiesByClasses(Class... types) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LivingEntity spawnCreature(Location arg0, EntityType arg1) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void playEffect(Location lctn, Effect effect, T t) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void playEffect(Location lctn, Effect effect, T t, int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setMetadata(String string, MetadataValue mv) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List getMetadata(String string) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean hasMetadata(String string) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void removeMetadata(String string, Plugin plugin) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setBiome(int arg0, int arg1, Biome arg2) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getMonsterSpawnLimit() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setMonsterSpawnLimit(int arg0) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getAnimalSpawnLimit() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setAnimalSpawnLimit(int arg0) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getWaterAnimalSpawnLimit() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setWaterAnimalSpawnLimit(int arg0) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Entity spawnEntity(Location lctn, EntityType et) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isChunkInUse(int x, int z) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public FallingBlock spawnFallingBlock(Location location, Material material, byte data) throws IllegalArgumentException + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public FallingBlock spawnFallingBlock(Location location, int blockId, byte blockData) throws IllegalArgumentException + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void playSound(Location arg0, Sound arg1, float arg2, float arg3) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getAmbientSpawnLimit() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setAmbientSpawnLimit(int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String[] getGameRules() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getGameRuleValue(String string) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean setGameRuleValue(String string, String string1) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isGameRule(String string) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean createExplosion(double d, double d1, double d2, float f, boolean bln, boolean bln1) + { + throw new UnsupportedOperationException("Not supported yet."); + } +} diff --git a/Essentials/src/com/earth2me/essentials/craftbukkit/InventoryWorkaround.java b/Essentials/src/com/earth2me/essentials/craftbukkit/InventoryWorkaround.java new file mode 100644 index 0000000000..ac83645b01 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/craftbukkit/InventoryWorkaround.java @@ -0,0 +1,162 @@ +package com.earth2me.essentials.craftbukkit; + +import java.util.HashMap; +import java.util.Map; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +/* + * This class can be removed when https://github.com/Bukkit/CraftBukkit/pull/193 is accepted to CraftBukkit + */ + +public final class InventoryWorkaround +{ + private InventoryWorkaround() + { + } + + private static int firstPartial(final Inventory inventory, final ItemStack item, final int maxAmount) + { + if (item == null) + { + return -1; + } + final ItemStack[] stacks = inventory.getContents(); + for (int i = 0; i < stacks.length; i++) + { + final ItemStack cItem = stacks[i]; + if (cItem != null && cItem.getAmount() < maxAmount && cItem.isSimilar(item)) + { + return i; + } + } + return -1; + } + + // Returns what it couldnt store + // This will will abort if it couldn't store all items + public static Map addAllItems(final Inventory inventory, final ItemStack... items) + { + final Inventory fakeInventory = Bukkit.getServer().createInventory(null, inventory.getType()); + fakeInventory.setContents(inventory.getContents()); + Map overFlow = addItems(fakeInventory, items); + if (overFlow.isEmpty()) + { + addItems(inventory, items); + return null; + } + return addItems(fakeInventory, items); + } + + // Returns what it couldnt store + public static Map addItems(final Inventory inventory, final ItemStack... items) + { + return addOversizedItems(inventory, 0, items); + } + + // Returns what it couldnt store + // Set oversizedStack to below normal stack size to disable oversized stacks + public static Map addOversizedItems(final Inventory inventory, final int oversizedStacks, final ItemStack... items) + { + final Map leftover = new HashMap(); + + /* + * TODO: some optimization - Create a 'firstPartial' with a 'fromIndex' - Record the lastPartial per Material - + * Cache firstEmpty result + */ + + // combine items + + final ItemStack[] combined = new ItemStack[items.length]; + for (ItemStack item : items) + { + if (item == null || item.getAmount() < 1) + { + continue; + } + for (int j = 0; j < combined.length; j++) + { + if (combined[j] == null) + { + combined[j] = item.clone(); + break; + } + if (combined[j].isSimilar(item)) + { + combined[j].setAmount(combined[j].getAmount() + item.getAmount()); + break; + } + } + } + + + for (int i = 0; i < combined.length; i++) + { + final ItemStack item = combined[i]; + if (item == null || item.getType() == Material.AIR) + { + continue; + } + + while (true) + { + // Do we already have a stack of it? + final int maxAmount = oversizedStacks > item.getType().getMaxStackSize() ? oversizedStacks : item.getType().getMaxStackSize(); + final int firstPartial = firstPartial(inventory, item, maxAmount); + + // Drat! no partial stack + if (firstPartial == -1) + { + // Find a free spot! + final int firstFree = inventory.firstEmpty(); + + if (firstFree == -1) + { + // No space at all! + leftover.put(i, item); + break; + } + else + { + // More than a single stack! + if (item.getAmount() > maxAmount) + { + final ItemStack stack = item.clone(); + stack.setAmount(maxAmount); + inventory.setItem(firstFree, stack); + item.setAmount(item.getAmount() - maxAmount); + } + else + { + // Just store it + inventory.setItem(firstFree, item); + break; + } + } + } + else + { + // So, apparently it might only partially fit, well lets do just that + final ItemStack partialItem = inventory.getItem(firstPartial); + + final int amount = item.getAmount(); + final int partialAmount = partialItem.getAmount(); + + // Check if it fully fits + if (amount + partialAmount <= maxAmount) + { + partialItem.setAmount(amount + partialAmount); + break; + } + + // It fits partially + partialItem.setAmount(maxAmount); + item.setAmount(amount + partialAmount - maxAmount); + } + } + } + return leftover; + } +} diff --git a/Essentials/src/com/earth2me/essentials/craftbukkit/SetExpFix.java b/Essentials/src/com/earth2me/essentials/craftbukkit/SetExpFix.java new file mode 100644 index 0000000000..e484ebfe1c --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/craftbukkit/SetExpFix.java @@ -0,0 +1,102 @@ +package com.earth2me.essentials.craftbukkit; + +import org.bukkit.entity.Player; + + +public class SetExpFix +{ + //This method is used to update both the recorded total experience and displayed total experience. + //We reset both types to prevent issues. + public static void setTotalExperience(final Player player, final int exp) + { + if (exp < 0) + { + throw new IllegalArgumentException("Experience is negative!"); + } + player.setExp(0); + player.setLevel(0); + player.setTotalExperience(0); + + //This following code is technically redundant now, as bukkit now calulcates levels more or less correctly + //At larger numbers however... player.getExp(3000), only seems to give 2999, putting the below calculations off. + int amount = exp; + while (amount > 0) + { + final int expToLevel = getExpAtLevel(player); + amount -= expToLevel; + if (amount >= 0) + { + // give until next level + player.giveExp(expToLevel); + } + else + { + // give the rest + amount += expToLevel; + player.giveExp(amount); + amount = 0; + } + } + } + + private static int getExpAtLevel(final Player player) + { + return getExpAtLevel(player.getLevel()); + } + + public static int getExpAtLevel(final int level) + { + if (level > 29) + { + return 62 + (level - 30) * 7; + } + if (level > 15) + { + return 17 + (level - 15) * 3; + } + return 17; + } + + public static int getExpToLevel(final int level) + { + int currentLevel = 0; + int exp = 0; + + while (currentLevel < level) + { + exp += getExpAtLevel(currentLevel); + currentLevel++; + } + if (exp < 0) + { + exp = Integer.MAX_VALUE; + } + return exp; + } + + //This method is required because the bukkit player.getTotalExperience() method, shows exp that has been 'spent'. + //Without this people would be able to use exp and then still sell it. + public static int getTotalExperience(final Player player) + { + int exp = (int)Math.round(getExpAtLevel(player) * player.getExp()); + int currentLevel = player.getLevel(); + + while (currentLevel > 0) + { + currentLevel--; + exp += getExpAtLevel(currentLevel); + } + if (exp < 0) + { + exp = Integer.MAX_VALUE; + } + return exp; + } + + public static int getExpUntilNextLevel(final Player player) + { + int exp = (int)Math.round(getExpAtLevel(player) * player.getExp()); + int nextLevel = player.getLevel(); + return getExpAtLevel(nextLevel) - exp; + } +} diff --git a/Essentials/src/com/earth2me/essentials/metrics/Metrics.java b/Essentials/src/com/earth2me/essentials/metrics/Metrics.java new file mode 100644 index 0000000000..07229f0912 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/metrics/Metrics.java @@ -0,0 +1,847 @@ +package com.earth2me.essentials.metrics; + +/* + * Copyright 2011 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. + */ + +import com.earth2me.essentials.IEssentials; +import java.io.*; +import java.net.Proxy; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLEncoder; +import java.util.*; +import java.util.logging.Level; +import java.util.zip.GZIPOutputStream; +import org.bukkit.Bukkit; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginDescriptionFile; +import org.bukkit.scheduler.BukkitTask; + +public class Metrics +{ + + /** + * The current revision number + */ + private static final int REVISION = 7; + + /** + * The base url of the metrics domain + */ + private static final String BASE_URL = "http://report-metrics.essentials3.net"; + + /** + * The url used to report a server's status + */ + private static final String REPORT_URL = "/plugin/%s"; + + /** + * Interval of time to ping (in minutes) + */ + private static final int PING_INTERVAL = 15; + + /** + * The plugin this metrics submits for + */ + private final Plugin plugin; + + /** + * All of the custom graphs to submit to metrics + */ + private final Set graphs = Collections.synchronizedSet(new HashSet()); + + /** + * 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); + } + + /** + * 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. + */ + public void start() + { + synchronized (optOutLock) + { + // Did we opt out? + if (isOptOut()) + { + return; + } + + // Is metrics already running? + if (task != null) + { + return; + } + + // 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); + } + } + + /** + * 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 = ((IEssentials)plugin).getOnlinePlayers().size(); + + // END server software specific section -- all code below does not use any code outside of this class / Java + + // Construct the post data + StringBuilder json = new StringBuilder(1024); + json.append('{'); + + // The plugin's description file containg all of the plugin data such as name, version, author, etc + appendJSONPair(json, "guid", guid); + appendJSONPair(json, "plugin_version", pluginVersion); + appendJSONPair(json, "server_version", serverVersion); + appendJSONPair(json, "players_online", Integer.toString(playersOnline)); + + // 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"; + } + + appendJSONPair(json, "osname", osname); + appendJSONPair(json, "osarch", osarch); + appendJSONPair(json, "osversion", osversion); + appendJSONPair(json, "cores", Integer.toString(coreCount)); + appendJSONPair(json, "auth_mode", onlineMode ? "1" : "0"); + appendJSONPair(json, "java_version", java_version); + + // If we're pinging, append it + if (isPing) + { + appendJSONPair(json, "ping", "1"); + } + + if (graphs.size() > 0) + { + synchronized (graphs) + { + json.append(','); + json.append('"'); + json.append("graphs"); + json.append('"'); + json.append(':'); + json.append('{'); + + boolean firstGraph = true; + + final Iterator iter = graphs.iterator(); + + while (iter.hasNext()) + { + Graph graph = iter.next(); + + StringBuilder graphJson = new StringBuilder(); + graphJson.append('{'); + + for (Plotter plotter : graph.getPlotters()) + { + appendJSONPair(graphJson, plotter.getColumnName(), Integer.toString(plotter.getValue())); + } + + graphJson.append('}'); + + if (!firstGraph) + { + json.append(','); + } + + json.append(escapeJSON(graph.getName())); + json.append(':'); + json.append(graphJson); + + firstGraph = false; + } + + json.append('}'); + } + } + + // close json + json.append('}'); + + // Create the url + URL url = new URL(BASE_URL + String.format(REPORT_URL, urlEncode(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(); + } + + + byte[] uncompressed = json.toString().getBytes(); + byte[] compressed = gzip(json.toString()); + + // Headers + connection.addRequestProperty("User-Agent", "MCStats/" + REVISION); + connection.addRequestProperty("Content-Type", "application/json"); + connection.addRequestProperty("Content-Encoding", "gzip"); + connection.addRequestProperty("Content-Length", Integer.toString(compressed.length)); + connection.addRequestProperty("Accept", "application/json"); + connection.addRequestProperty("Connection", "close"); + + connection.setDoOutput(true); + + if (debug) + { + System.out.println("[Metrics] Prepared request for " + pluginName + " uncompressed=" + uncompressed.length + " compressed=" + compressed.length); + } + + // Write the data + OutputStream os = connection.getOutputStream(); + os.write(compressed); + os.flush(); + + // Now read the response + final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + String response = reader.readLine(); + + // close resources + os.close(); + reader.close(); + + if (response == null || response.startsWith("ERR") || response.startsWith("7")) + { + if (response == null) + { + response = "null"; + } + else if (response.startsWith("7")) + { + response = response.substring(response.startsWith("7,") ? 2 : 1); + } + + throw new IOException(response); + } + else + { + // Is this the first update this hour? + if (response.equals("1") || response.contains("This is your first update this hour")) + { + synchronized (graphs) + { + final Iterator iter = graphs.iterator(); + + while (iter.hasNext()) + { + final Graph graph = iter.next(); + + for (Plotter plotter : graph.getPlotters()) + { + plotter.reset(); + } + } + } + } + } + } + + /** + * GZip compress a string of bytes + * + * @param input + * @return + */ + public static byte[] gzip(String input) + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + GZIPOutputStream gzos = null; + + try + { + gzos = new GZIPOutputStream(baos); + gzos.write(input.getBytes("UTF-8")); + } + catch (IOException e) + { + e.printStackTrace(); + } + finally + { + if (gzos != null) + { + try + { + gzos.close(); + } + catch (IOException ignore) + { + } + } + } + + return baos.toByteArray(); + } + + /** + * 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; + } + } + + /** + * Appends a json encoded key/value pair to the given string builder. + * + * @param json + * @param key + * @param value + * @throws UnsupportedEncodingException + */ + private static void appendJSONPair(StringBuilder json, String key, String value) throws UnsupportedEncodingException + { + boolean isValueNumeric; + + try + { + Double.parseDouble(value); + isValueNumeric = true; + } + catch (NumberFormatException e) + { + isValueNumeric = false; + } + + if (json.charAt(json.length() - 1) != '{') + { + json.append(','); + } + + json.append(escapeJSON(key)); + json.append(':'); + + if (isValueNumeric) + { + json.append(value); + } + else + { + json.append(escapeJSON(value)); + } + } + + /** + * Escape a string to create a valid JSON string + * + * @param text + * @return + */ + private static String escapeJSON(String text) + { + StringBuilder builder = new StringBuilder(); + + builder.append('"'); + for (int index = 0; index < text.length(); index++) + { + char chr = text.charAt(index); + + switch (chr) + { + case '"': + case '\\': + builder.append('\\'); + builder.append(chr); + break; + case '\b': + builder.append("\\b"); + break; + case '\t': + builder.append("\\t"); + break; + case '\n': + builder.append("\\n"); + break; + case '\r': + builder.append("\\r"); + break; + default: + if (chr < ' ') + { + String t = "000" + Integer.toHexString(chr); + builder.append("\\u" + t.substring(t.length() - 4)); + } + else + { + builder.append(chr); + } + break; + } + } + builder.append('"'); + + return builder.toString(); + } + + /** + * Encode text as UTF-8 + * + * @param text the text to encode + * @return the encoded text, as UTF-8 + */ + private static String urlEncode(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 plotters = new LinkedHashSet(); + + 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 unmodifiable set of the plotter objects in the graph + * + * @return an unmodifiable {@link java.util.Set} of the plotter objects + */ + public Set 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(); + } + } +} \ No newline at end of file diff --git a/Essentials/src/com/earth2me/essentials/metrics/MetricsListener.java b/Essentials/src/com/earth2me/essentials/metrics/MetricsListener.java new file mode 100644 index 0000000000..2edbf1a80a --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/metrics/MetricsListener.java @@ -0,0 +1,39 @@ +package com.earth2me.essentials.metrics; + +import com.earth2me.essentials.User; +import java.util.logging.Level; +import net.ess3.api.IEssentials; +import org.bukkit.Server; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; + + +public class MetricsListener implements Listener +{ + private final transient Server server; + private final transient IEssentials ess; + private final transient MetricsStarter starter; + + public MetricsListener(final IEssentials parent, final MetricsStarter starter) + { + this.ess = parent; + this.server = parent.getServer(); + this.starter = starter; + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onPlayerJoin(final PlayerJoinEvent event) + { + final User player = ess.getUser(event.getPlayer()); + if (ess.getSettings().isMetricsEnabled() == false && (player.isAuthorized("essentials.essentials") || player.isAuthorized("bukkit.broadcast.admin"))) + { + player.sendMessage("PluginMetrics collects minimal statistic data, starting in about 5 minutes."); + player.sendMessage("To opt out, disabling metrics for all plugins, run /essentials opt-out"); + ess.getLogger().log(Level.INFO, "[Metrics] Admin join - Starting 5 minute opt-out period."); + ess.getSettings().setMetricsEnabled(true); + ess.runTaskLaterAsynchronously(starter, 5 * 1200); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/metrics/MetricsStarter.java b/Essentials/src/com/earth2me/essentials/metrics/MetricsStarter.java new file mode 100644 index 0000000000..0ce1622175 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/metrics/MetricsStarter.java @@ -0,0 +1,242 @@ +package com.earth2me.essentials.metrics; + +import com.earth2me.essentials.metrics.Metrics.Graph; +import com.earth2me.essentials.metrics.Metrics.Plotter; +import com.earth2me.essentials.register.payment.Method; +import com.earth2me.essentials.register.payment.methods.VaultEco; +import com.earth2me.essentials.signs.EssentialsSign; +import java.util.Locale; +import java.util.logging.Level; +import net.ess3.api.IEssentials; +import org.bukkit.configuration.ConfigurationSection; + + +public class MetricsStarter implements Runnable +{ + private final IEssentials ess; + private transient Boolean start; + + + private enum Modules + { + Essentials, + EssentialsAntiBuild, + EssentialsAntiCheat, + EssentialsChat, + EssentialsSpawn, + EssentialsProtect, + EssentialsGeoIP, + EssentialsXMPP + }; + + public MetricsStarter(final IEssentials plugin) + { + ess = plugin; + try + { + + final Metrics metrics = new Metrics(ess); + ess.setMetrics(metrics); + + if (!metrics.isOptOut()) + { + if (ess.getSettings().isMetricsEnabled()) + { + start = true; + } + else + { + ess.getLogger().info("This plugin collects minimal statistic data and sends it to http://metrics.essentials3.net."); + ess.getLogger().info("You can opt out, disabling metrics for all plugins, by running /essentials opt-out"); + ess.getLogger().info("This will start 5 minutes after the first admin/op joins."); + start = false; + } + return; + } + } + catch (Exception ex) + { + metricsError(ex); + } + } + + @Override + public void run() + { + try + { + final Metrics metrics = ess.getMetrics(); + + final Graph moduleGraph = metrics.createGraph("Modules Used"); + for (Modules module : Modules.values()) + { + final String moduleName = module.toString(); + if (ess.getServer().getPluginManager().isPluginEnabled(moduleName)) + { + moduleGraph.addPlotter(new SimplePlotter(moduleName)); + } + } + + final Graph localeGraph = metrics.createGraph("Locale"); + localeGraph.addPlotter(new SimplePlotter(ess.getI18n().getCurrentLocale().getDisplayLanguage(Locale.ENGLISH))); + + final Graph featureGraph = metrics.createGraph("Features"); + featureGraph.addPlotter(new Plotter("Unique Accounts") + { + @Override + public int getValue() + { + return ess.getUserMap().getUniqueUsers(); + } + }); + featureGraph.addPlotter(new Plotter("Jails") + { + @Override + public int getValue() + { + return ess.getJails().getCount(); + } + }); + featureGraph.addPlotter(new Plotter("Kits") + { + @Override + public int getValue() + { + ConfigurationSection kits = ess.getSettings().getKits(); + if (kits == null) + { + return 0; + } + return kits.getKeys(false).size(); + } + }); + featureGraph.addPlotter(new Plotter("Warps") + { + @Override + public int getValue() + { + return ess.getWarps().getCount(); + } + }); + + final Graph enabledGraph = metrics.createGraph("EnabledFeatures"); + enabledGraph.addPlotter(new SimplePlotter("Total")); + final String BKcommand = ess.getSettings().getBackupCommand(); + if (BKcommand != null && !"".equals(BKcommand)) + { + enabledGraph.addPlotter(new SimplePlotter("Backup")); + } + if (ess.getJails().getCount() > 0) + { + enabledGraph.addPlotter(new SimplePlotter("Jails")); + } + if (ess.getSettings().getKits() != null && ess.getSettings().getKits().getKeys(false).size() > 0) + { + enabledGraph.addPlotter(new SimplePlotter("Kits")); + } + if (ess.getWarps().getCount() > 0) + { + enabledGraph.addPlotter(new SimplePlotter("Warps")); + } + if (ess.getSettings().getTeleportCooldown() > 0) + { + enabledGraph.addPlotter(new SimplePlotter("TeleportCooldown")); + } + if (ess.getSettings().getTeleportDelay() > 0) + { + enabledGraph.addPlotter(new SimplePlotter("TeleportDelay")); + } + if (!ess.getSettings().areSignsDisabled()) + { + enabledGraph.addPlotter(new SimplePlotter("Signs")); + } + if (ess.getSettings().getAutoAfk() > 0) + { + enabledGraph.addPlotter(new SimplePlotter("AutoAFK")); + } + if (ess.getSettings().changePlayerListName()) + { + enabledGraph.addPlotter(new SimplePlotter("PlayerListName")); + } + if (ess.getSettings().getOperatorColor() != null) + { + enabledGraph.addPlotter(new SimplePlotter("OpColour")); + } + if (ess.getSettings().changeDisplayName()) + { + enabledGraph.addPlotter(new SimplePlotter("DisplayName")); + } + if (ess.getSettings().getChatRadius() >= 1) + { + enabledGraph.addPlotter(new SimplePlotter("LocalChat")); + } + + final Graph depGraph = metrics.createGraph("Dependencies"); + final Method method = ess.getPaymentMethod().getMethod(); + if (method != null) + { + String version; + if (method instanceof VaultEco) + { + version = ((VaultEco)method).getEconomy(); + } + else + { + version = method.getVersion(); + final int dashPosition = version.indexOf('-'); + if (dashPosition > 0) + { + version = version.substring(0, dashPosition); + } + } + depGraph.addPlotter(new SimplePlotter(method.getName() + " " + version)); + } + depGraph.addPlotter(new SimplePlotter(ess.getPermissionsHandler().getName())); + + final Graph signGraph = metrics.createGraph("Signs"); + for (EssentialsSign sign : ess.getSettings().enabledSigns()) + { + signGraph.addPlotter(new SimplePlotter(sign.getName())); + } + + metrics.start(); + + } + catch (Exception ex) + { + metricsError(ex); + } + } + + public void metricsError(final Exception ex) + { + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage(), ex); + } + else + { + ess.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage()); + } + } + + public Boolean getStart() + { + return start; + } + + + private class SimplePlotter extends Plotter + { + public SimplePlotter(final String name) + { + super(name); + } + + @Override + public int getValue() + { + return 1; + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/perm/BPermissions2Handler.java b/Essentials/src/com/earth2me/essentials/perm/BPermissions2Handler.java new file mode 100644 index 0000000000..791ffbe92b --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/perm/BPermissions2Handler.java @@ -0,0 +1,59 @@ +package com.earth2me.essentials.perm; + +import de.bananaco.bpermissions.api.ApiLayer; +import de.bananaco.bpermissions.api.util.CalculableType; +import java.util.Arrays; +import java.util.List; +import org.bukkit.entity.Player; + + +public class BPermissions2Handler extends SuperpermsHandler +{ + public BPermissions2Handler() + { + + } + + @Override + public String getGroup(final Player base) + { + final List groups = getGroups(base); + if (groups == null || groups.isEmpty()) + { + return null; + } + return groups.get(0); + } + + @Override + public List getGroups(final Player base) + { + final String[] groups = ApiLayer.getGroups(base.getWorld().getName(), CalculableType.USER, base.getName()); + return Arrays.asList(groups); + } + + @Override + public boolean inGroup(final Player base, final String group) + { + return ApiLayer.hasGroupRecursive(base.getWorld().getName(), CalculableType.USER, base.getName(), group); + } + + @Override + public boolean canBuild(final Player base, final String group) + { + return hasPermission(base, "bPermissions.build"); + } + + @Override + public String getPrefix(final Player base) + { + return ApiLayer.getValue(base.getWorld().getName(), CalculableType.USER, base.getName(), "prefix"); + } + + @Override + public String getSuffix(final Player base) + { + return ApiLayer.getValue(base.getWorld().getName(), CalculableType.USER, base.getName(), "suffix"); + } + +} diff --git a/Essentials/src/com/earth2me/essentials/perm/ConfigPermissionsHandler.java b/Essentials/src/com/earth2me/essentials/perm/ConfigPermissionsHandler.java new file mode 100644 index 0000000000..d77af5ce1a --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/perm/ConfigPermissionsHandler.java @@ -0,0 +1,30 @@ +package com.earth2me.essentials.perm; + +import net.ess3.api.IEssentials; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + + +public class ConfigPermissionsHandler extends SuperpermsHandler +{ + private final transient IEssentials ess; + + public ConfigPermissionsHandler(final Plugin ess) + { + this.ess = (IEssentials)ess; + } + + @Override + public boolean canBuild(final Player base, final String group) + { + return true; + } + + @Override + public boolean hasPermission(final Player base, final String node) + { + final String[] cmds = node.split("\\.", 2); + return ess.getSettings().isPlayerCommand(cmds[cmds.length - 1]) || super.hasPermission(base, node); + } + +} diff --git a/Essentials/src/com/earth2me/essentials/perm/GroupManagerHandler.java b/Essentials/src/com/earth2me/essentials/perm/GroupManagerHandler.java new file mode 100644 index 0000000000..83dd1a846a --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/perm/GroupManagerHandler.java @@ -0,0 +1,114 @@ +package com.earth2me.essentials.perm; + +import java.util.Arrays; +import java.util.List; +import org.anjocaido.groupmanager.GroupManager; +import org.anjocaido.groupmanager.dataholder.worlds.WorldsHolder; +import org.anjocaido.groupmanager.permissions.AnjoPermissionsHandler; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + + +public class GroupManagerHandler implements IPermissionsHandler +{ + private final transient GroupManager groupManager; + + public GroupManagerHandler(final Plugin permissionsPlugin) + { + groupManager = ((GroupManager)permissionsPlugin); + } + + @Override + public String getGroup(final Player base) + { + final AnjoPermissionsHandler handler = getHandler(base); + if (handler == null) + { + return null; + } + return handler.getGroup(base.getName()); + } + + @Override + public List getGroups(final Player base) + { + final AnjoPermissionsHandler handler = getHandler(base); + if (handler == null) + { + return null; + } + return Arrays.asList(handler.getGroups(base.getName())); + } + + @Override + public boolean canBuild(final Player base, final String group) + { + final AnjoPermissionsHandler handler = getHandler(base); + if (handler == null) + { + return false; + } + return handler.canUserBuild(base.getName()); + } + + @Override + public boolean inGroup(final Player base, final String group) + { + AnjoPermissionsHandler handler = getHandler(base); + if (handler == null) + { + return false; + } + return handler.inGroup(base.getName(), group); + } + + @Override + public boolean hasPermission(final Player base, final String node) + { + AnjoPermissionsHandler handler = getHandler(base); + if (handler == null) + { + return false; + } + return handler.has(base, node); + } + + @Override + public String getPrefix(final Player base) + { + AnjoPermissionsHandler handler = getHandler(base); + if (handler == null) + { + return null; + } + return handler.getUserPrefix(base.getName()); + } + + @Override + public String getSuffix(final Player base) + { + AnjoPermissionsHandler handler = getHandler(base); + if (handler == null) + { + return null; + } + return handler.getUserSuffix(base.getName()); + } + + private AnjoPermissionsHandler getHandler(final Player base) + { + final WorldsHolder holder = groupManager.getWorldsHolder(); + if (holder == null) + { + return null; + } + try + { + return holder.getWorldPermissions(base); + } + catch (NullPointerException ex) + { + return null; + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/perm/IPermissionsHandler.java b/Essentials/src/com/earth2me/essentials/perm/IPermissionsHandler.java new file mode 100644 index 0000000000..27af48e8ce --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/perm/IPermissionsHandler.java @@ -0,0 +1,22 @@ +package com.earth2me.essentials.perm; + +import java.util.List; +import org.bukkit.entity.Player; + + +public interface IPermissionsHandler +{ + String getGroup(Player base); + + List getGroups(Player base); + + boolean canBuild(Player base, String group); + + boolean inGroup(Player base, String group); + + boolean hasPermission(Player base, String node); + + String getPrefix(Player base); + + String getSuffix(Player base); +} diff --git a/Essentials/src/com/earth2me/essentials/perm/NullPermissionsHandler.java b/Essentials/src/com/earth2me/essentials/perm/NullPermissionsHandler.java new file mode 100644 index 0000000000..b51aeb055e --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/perm/NullPermissionsHandler.java @@ -0,0 +1,51 @@ +package com.earth2me.essentials.perm; + +import java.util.Collections; +import java.util.List; +import org.bukkit.entity.Player; + + +public class NullPermissionsHandler implements IPermissionsHandler +{ + @Override + public String getGroup(final Player base) + { + return null; + } + + @Override + public List getGroups(final Player base) + { + return Collections.emptyList(); + } + + @Override + public boolean canBuild(final Player base, final String group) + { + return false; + } + + @Override + public boolean inGroup(final Player base, final String group) + { + return false; + } + + @Override + public boolean hasPermission(final Player base, final String node) + { + return false; + } + + @Override + public String getPrefix(final Player base) + { + return null; + } + + @Override + public String getSuffix(final Player base) + { + return null; + } +} diff --git a/Essentials/src/com/earth2me/essentials/perm/PermissionsBukkitHandler.java b/Essentials/src/com/earth2me/essentials/perm/PermissionsBukkitHandler.java new file mode 100644 index 0000000000..908ce78f3e --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/perm/PermissionsBukkitHandler.java @@ -0,0 +1,78 @@ +package com.earth2me.essentials.perm; + +import com.platymuus.bukkit.permissions.Group; +import com.platymuus.bukkit.permissions.PermissionInfo; +import com.platymuus.bukkit.permissions.PermissionsPlugin; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + + +public class PermissionsBukkitHandler extends SuperpermsHandler +{ + private final transient PermissionsPlugin plugin; + + public PermissionsBukkitHandler(final Plugin plugin) + { + this.plugin = (PermissionsPlugin)plugin; + } + + @Override + public String getGroup(final Player base) + { + final List groups = getPBGroups(base); + if (groups == null || groups.isEmpty()) + { + return null; + } + return groups.get(0).getName(); + } + + @Override + public List getGroups(final Player base) + { + final List groups = getPBGroups(base); + if (groups.size() == 1) + { + return Collections.singletonList(groups.get(0).getName()); + } + final List groupNames = new ArrayList(groups.size()); + for (Group group : groups) + { + groupNames.add(group.getName()); + } + return groupNames; + } + + private List getPBGroups(final Player base) + { + final PermissionInfo info = plugin.getPlayerInfo(base.getName()); + if (info == null) + { + return Collections.emptyList(); + } + final List groups = info.getGroups(); + if (groups == null || groups.isEmpty()) + { + return Collections.emptyList(); + } + return groups; + } + + @Override + public boolean inGroup(final Player base, final String group) + { + final List groups = getPBGroups(base); + for (Group group1 : groups) + { + if (group1.getName().equalsIgnoreCase(group)) + { + return true; + } + } + return false; + } + +} diff --git a/Essentials/src/com/earth2me/essentials/perm/PermissionsExHandler.java b/Essentials/src/com/earth2me/essentials/perm/PermissionsExHandler.java new file mode 100644 index 0000000000..e61dfc30bd --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/perm/PermissionsExHandler.java @@ -0,0 +1,108 @@ +package com.earth2me.essentials.perm; + +import java.util.Arrays; +import java.util.List; +import org.bukkit.entity.Player; +import ru.tehkode.permissions.PermissionManager; +import ru.tehkode.permissions.PermissionUser; +import ru.tehkode.permissions.bukkit.PermissionsEx; + + +public class PermissionsExHandler extends SuperpermsHandler +{ + private final transient PermissionManager manager; + + public PermissionsExHandler() + { + manager = PermissionsEx.getPermissionManager(); + } + + @Override + public String getGroup(final Player base) + { + final PermissionUser user = manager.getUser(base.getName()); + if (user == null) + { + return null; + } + + String[] groupsNames = user.getGroupsNames(); + if (groupsNames == null || groupsNames.length == 0) + { + return null; + } + + return groupsNames[0]; + } + + @Override + public List getGroups(final Player base) + { + final PermissionUser user = manager.getUser(base.getName()); + if (user == null) + { + return null; + } + + String[] groupsNames = user.getGroupsNames(); + if (groupsNames == null) + { + return null; + } + + return Arrays.asList(groupsNames); + } + + @Override + public boolean canBuild(final Player base, final String group) + { + final PermissionUser user = manager.getUser(base.getName()); + if (user == null) + { + return false; + } + + return user.getOptionBoolean("build", base.getWorld().getName(), false); + } + + @Override + public boolean inGroup(final Player base, final String group) + { + final PermissionUser user = manager.getUser(base.getName()); + if (user == null) + { + return false; + } + + return user.inGroup(group); + } + + @Override + public boolean hasPermission(final Player base, final String node) + { + return super.hasPermission(base, node); + } + + @Override + public String getPrefix(final Player base) + { + final PermissionUser user = manager.getUser(base.getName()); + if (user == null) + { + return null; + } + return user.getPrefix(base.getWorld().getName()); + } + + @Override + public String getSuffix(final Player base) + { + final PermissionUser user = manager.getUser(base.getName()); + if (user == null) + { + return null; + } + + return user.getSuffix(base.getWorld().getName()); + } +} diff --git a/Essentials/src/com/earth2me/essentials/perm/PermissionsHandler.java b/Essentials/src/com/earth2me/essentials/perm/PermissionsHandler.java new file mode 100644 index 0000000000..f92027afab --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/perm/PermissionsHandler.java @@ -0,0 +1,229 @@ +package com.earth2me.essentials.perm; + +import com.earth2me.essentials.Essentials; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginManager; + + +public class PermissionsHandler implements IPermissionsHandler +{ + private transient IPermissionsHandler handler = new NullPermissionsHandler(); + private transient String defaultGroup = "default"; + private final transient Essentials ess; + private static final Logger LOGGER = Logger.getLogger("Essentials"); + private transient boolean useSuperperms = false; + + public PermissionsHandler(final Essentials plugin) + { + this.ess = plugin; + } + + public PermissionsHandler(final Essentials plugin, final boolean useSuperperms) + { + this.ess = plugin; + this.useSuperperms = useSuperperms; + } + + public PermissionsHandler(final Essentials plugin, final String defaultGroup) + { + this.ess = plugin; + this.defaultGroup = defaultGroup; + } + + @Override + public String getGroup(final Player base) + { + final long start = System.nanoTime(); + String group = handler.getGroup(base); + if (group == null) + { + group = defaultGroup; + } + checkPermLag(start); + return group; + } + + @Override + public List getGroups(final Player base) + { + final long start = System.nanoTime(); + List groups = handler.getGroups(base); + if (groups == null || groups.isEmpty()) + { + groups = Collections.singletonList(defaultGroup); + } + checkPermLag(start); + return Collections.unmodifiableList(groups); + } + + @Override + public boolean canBuild(final Player base, final String group) + { + return handler.canBuild(base, group); + } + + @Override + public boolean inGroup(final Player base, final String group) + { + final long start = System.nanoTime(); + final boolean result = handler.inGroup(base, group); + checkPermLag(start); + return result; + } + + @Override + public boolean hasPermission(final Player base, final String node) + { + return handler.hasPermission(base, node); + } + + @Override + public String getPrefix(final Player base) + { + final long start = System.nanoTime(); + String prefix = handler.getPrefix(base); + if (prefix == null) + { + prefix = ""; + } + checkPermLag(start); + return prefix; + } + + @Override + public String getSuffix(final Player base) + { + final long start = System.nanoTime(); + String suffix = handler.getSuffix(base); + if (suffix == null) + { + suffix = ""; + } + checkPermLag(start); + return suffix; + } + + public void checkPermissions() + { + final PluginManager pluginManager = ess.getServer().getPluginManager(); + + final Plugin permExPlugin = pluginManager.getPlugin("PermissionsEx"); + if (permExPlugin != null && permExPlugin.isEnabled()) + { + if (!(handler instanceof PermissionsExHandler)) + { + LOGGER.log(Level.INFO, "Essentials: Using PermissionsEx based permissions."); + handler = new PermissionsExHandler(); + } + return; + } + + final Plugin GMplugin = pluginManager.getPlugin("GroupManager"); + if (GMplugin != null && GMplugin.isEnabled()) + { + if (!(handler instanceof GroupManagerHandler)) + { + LOGGER.log(Level.INFO, "Essentials: Using GroupManager based permissions."); + handler = new GroupManagerHandler(GMplugin); + } + return; + } + + final Plugin permBukkitPlugin = pluginManager.getPlugin("PermissionsBukkit"); + if (permBukkitPlugin != null && permBukkitPlugin.isEnabled()) + { + if (!(handler instanceof PermissionsBukkitHandler)) + { + LOGGER.log(Level.INFO, "Essentials: Using PermissionsBukkit based permissions."); + handler = new PermissionsBukkitHandler(permBukkitPlugin); + } + return; + } + + final Plugin simplyPermsPlugin = pluginManager.getPlugin("SimplyPerms"); + if (simplyPermsPlugin != null && simplyPermsPlugin.isEnabled()) + { + if (!(handler instanceof SimplyPermsHandler)) + { + LOGGER.log(Level.INFO, "Essentials: Using SimplyPerms based permissions."); + handler = new SimplyPermsHandler(simplyPermsPlugin); + } + return; + } + + final Plugin privPlugin = pluginManager.getPlugin("Privileges"); + if (privPlugin != null && privPlugin.isEnabled()) + { + if (!(handler instanceof PrivilegesHandler)) + { + LOGGER.log(Level.INFO, "Essentials: Using Privileges based permissions."); + handler = new PrivilegesHandler(privPlugin); + } + return; + } + + final Plugin bPermPlugin = pluginManager.getPlugin("bPermissions"); + if (bPermPlugin != null && bPermPlugin.isEnabled()) + { + if (!(handler instanceof BPermissions2Handler)) + { + LOGGER.log(Level.INFO, "Essentials: Using bPermissions2 based permissions."); + handler = new BPermissions2Handler(); + } + return; + } + + final Plugin zPermsPlugin = pluginManager.getPlugin("zPermissions"); + if (zPermsPlugin != null && zPermsPlugin.isEnabled()) + { + if (!(handler instanceof ZPermissionsHandler)) + { + LOGGER.log(Level.INFO, "Essentials: Using zPermissions based permissions."); + handler = new ZPermissionsHandler(ess); + } + return; + } + + if (useSuperperms) + { + if (!(handler instanceof SuperpermsHandler)) + { + LOGGER.log(Level.INFO, "Essentials: Using superperms based permissions."); + handler = new SuperpermsHandler(); + } + } + else + { + if (!(handler instanceof ConfigPermissionsHandler)) + { + LOGGER.log(Level.INFO, "Essentials: Using config file enhanced permissions."); + LOGGER.log(Level.INFO, "Permissions listed in as player-commands will be given to all users."); + handler = new ConfigPermissionsHandler(ess); + } + } + } + + public void setUseSuperperms(final boolean useSuperperms) + { + this.useSuperperms = useSuperperms; + } + + public String getName() + { + return handler.getClass().getSimpleName().replace("Handler", ""); + } + + private void checkPermLag(long start) + { + final long elapsed = System.nanoTime() - start; + if (elapsed > ess.getSettings().getPermissionsLagWarning()) + { + ess.getLogger().log(Level.INFO, "Lag Notice - Slow Permissions System (" + getName() + ") Response - Request took over {0}ms!", elapsed / 1000000.0); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/perm/PrivilegesHandler.java b/Essentials/src/com/earth2me/essentials/perm/PrivilegesHandler.java new file mode 100644 index 0000000000..03db3502b7 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/perm/PrivilegesHandler.java @@ -0,0 +1,61 @@ +package com.earth2me.essentials.perm; + +import java.util.ArrayList; +import java.util.List; +import net.krinsoft.privileges.Privileges; +import net.krinsoft.privileges.groups.Group; +import net.krinsoft.privileges.groups.GroupManager; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + +public class PrivilegesHandler extends SuperpermsHandler +{ + private final transient Privileges plugin; + private final GroupManager manager; + + public PrivilegesHandler(final Plugin plugin) + { + this.plugin = (Privileges) plugin; + this.manager = this.plugin.getGroupManager(); + } + + @Override + public String getGroup(final Player base) + { + Group group = manager.getGroup(base); + if (group == null) + { + return null; + } + return group.getName(); + } + + @Override + public List getGroups(final Player base) + { + Group group = manager.getGroup(base); + if (group == null) + { + return new ArrayList(); + } + return group.getGroupTree(); + } + + @Override + public boolean inGroup(final Player base, final String group) + { + Group pGroup = manager.getGroup(base); + if (pGroup == null) + { + return false; + } + return pGroup.isMemberOf(group); + } + + @Override + public boolean canBuild(Player base, String group) + { + return hasPermission(base, "privileges.build"); + } + +} diff --git a/Essentials/src/com/earth2me/essentials/perm/SimplyPermsHandler.java b/Essentials/src/com/earth2me/essentials/perm/SimplyPermsHandler.java new file mode 100644 index 0000000000..093a1551f1 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/perm/SimplyPermsHandler.java @@ -0,0 +1,56 @@ +package com.earth2me.essentials.perm; + +import java.util.List; +import net.crystalyx.bukkit.simplyperms.SimplyAPI; +import net.crystalyx.bukkit.simplyperms.SimplyPlugin; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + +public class SimplyPermsHandler extends SuperpermsHandler +{ + + private final transient SimplyAPI api; + + public SimplyPermsHandler(final Plugin plugin) + { + this.api = ((SimplyPlugin) plugin).getAPI(); + } + + @Override + public String getGroup(final Player base) + { + final List groups = api.getPlayerGroups(base.getName()); + if (groups == null || groups.isEmpty()) + { + return null; + } + return groups.get(0); + } + + @Override + public List getGroups(final Player base) + { + return api.getPlayerGroups(base.getName()); + } + + @Override + public boolean inGroup(final Player base, final String group) + { + final List groups = api.getPlayerGroups(base.getName()); + for (String group1 : groups) + { + if (group1.equalsIgnoreCase(group)) + { + return true; + } + } + return false; + } + + @Override + public boolean canBuild(Player base, String group) + { + return hasPermission(base, "permissions.allow.build"); + } + +} diff --git a/Essentials/src/com/earth2me/essentials/perm/SuperpermsHandler.java b/Essentials/src/com/earth2me/essentials/perm/SuperpermsHandler.java new file mode 100644 index 0000000000..0b4b930583 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/perm/SuperpermsHandler.java @@ -0,0 +1,67 @@ +package com.earth2me.essentials.perm; + +import java.util.List; +import org.bukkit.entity.Player; + + +public class SuperpermsHandler implements IPermissionsHandler +{ + @Override + public String getGroup(final Player base) + { + return null; + } + + @Override + public List getGroups(final Player base) + { + return null; + } + + @Override + public boolean canBuild(final Player base, final String group) + { + return false; + } + + @Override + public boolean inGroup(final Player base, final String group) + { + return hasPermission(base, "group." + group); + } + + @Override + public boolean hasPermission(final Player base, String node) + { + String permCheck = node; + int index; + while (true) + { + if (base.isPermissionSet(permCheck)) + { + return base.hasPermission(permCheck); + } + + index = node.lastIndexOf('.'); + if (index < 1) + { + return base.hasPermission("*"); + } + + node = node.substring(0, index); + permCheck = node + ".*"; + } + } + + @Override + public String getPrefix(final Player base) + { + return null; + } + + @Override + public String getSuffix(final Player base) + { + return null; + } +} diff --git a/Essentials/src/com/earth2me/essentials/perm/ZPermissionsHandler.java b/Essentials/src/com/earth2me/essentials/perm/ZPermissionsHandler.java new file mode 100644 index 0000000000..6be67b3fe8 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/perm/ZPermissionsHandler.java @@ -0,0 +1,185 @@ +package com.earth2me.essentials.perm; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.server.ServiceRegisterEvent; +import org.bukkit.plugin.Plugin; +import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsService; + + +public class ZPermissionsHandler extends SuperpermsHandler implements Listener +{ + private ZPermissionsService service = null; + private boolean hasGetPlayerPrimaryGroup = false; // This is a post-1.0 addition + + public ZPermissionsHandler(Plugin plugin) + { + acquireZPermissionsService(); + if (!isReady()) + { + // Shouldn't get to this point, since caller checks if zPerms + // is enabled. But for the sake of correctness... + Bukkit.getPluginManager().registerEvents(this, plugin); + } + } + + @EventHandler + public void onServiceRegister(ServiceRegisterEvent event) + { + if (ZPermissionsService.class.equals(event.getProvider().getService())) + { + acquireZPermissionsService(); + } + } + + @Override + public String getGroup(Player base) + { + if (!isReady()) + { + return super.getGroup(base); + } + else + { + return getPrimaryGroup(base.getName()); + } + } + + @Override + public List getGroups(Player base) + { + if (!isReady()) + { + return super.getGroups(base); + } + else + { + return new ArrayList(service.getPlayerGroups(base.getName())); + } + } + + @Override + public boolean inGroup(Player base, String group) + { + if (!isReady()) + { + return super.inGroup(base, group); + } + else + { + Set groups = service.getPlayerGroups(base.getName()); + for (String test : groups) + { + if (test.equalsIgnoreCase(group)) + { + return true; + } + } + return false; + } + } + + @Override + public String getPrefix(Player base) + { + if (!isReady()) + { + return super.getPrefix(base); + } + else + { + return getPrefixSuffix(base, "prefix"); + } + } + + @Override + public String getSuffix(Player base) + { + if (!isReady()) + { + return super.getSuffix(base); + } + else + { + return getPrefixSuffix(base, "suffix"); + } + } + + private String getPrefixSuffix(Player base, String metadataName) + { + String playerPrefixSuffix; + try + { + playerPrefixSuffix = service.getPlayerMetadata(base.getName(), metadataName, String.class); + } + catch (IllegalStateException e) + { + // User error. They set prefix to a non-string. + playerPrefixSuffix = null; + } + if (playerPrefixSuffix == null) + { + // Try prefix/suffix of their "primary group" + try + { + return service.getGroupMetadata(getPrimaryGroup(base.getName()), metadataName, String.class); + } + catch (IllegalStateException e) + { + // User error, again + return null; + } + } + else + { + return playerPrefixSuffix; + } + } + + private void acquireZPermissionsService() + { + service = Bukkit.getServicesManager().load(ZPermissionsService.class); + if (isReady()) + { + // getPlayerPrimaryGroup(String) was added in an unreleased version + // Check if it exists. + try + { + service.getClass().getMethod("getPlayerPrimaryGroup", String.class); + hasGetPlayerPrimaryGroup = true; + } + catch (NoSuchMethodException e) + { + hasGetPlayerPrimaryGroup = false; + } + catch (SecurityException e) + { + hasGetPlayerPrimaryGroup = false; + } + } + } + + private boolean isReady() + { + return service != null; + } + + private String getPrimaryGroup(String playerName) + { + if (hasGetPlayerPrimaryGroup) + { + return service.getPlayerPrimaryGroup(playerName); + } + else + { + // Fall back to using highest-weight assigned group + List groups = service.getPlayerAssignedGroups(playerName); + return groups.get(0); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/register/payment/Method.java b/Essentials/src/com/earth2me/essentials/register/payment/Method.java new file mode 100644 index 0000000000..c4c9d401aa --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/register/payment/Method.java @@ -0,0 +1,217 @@ +package com.earth2me.essentials.register.payment; + +import org.bukkit.plugin.Plugin; + + +/** + * Interface to be implemented by a payment method. + * + * @author Nijikokun (@nijikokun) + * @copyright Copyright (C) 2011 + * @license AOL license + */ +public interface Method +{ + /** + * Encodes the Plugin into an Object disguised as the Plugin. If you want the original Plugin Class you must cast it + * to the correct Plugin, to do so you have to verify the name and or version then cast. + * + *
+	 *  if(method.getName().equalsIgnoreCase("iConomy"))
+	 *   iConomy plugin = ((iConomy)method.getPlugin());
+ * + * @return + * Object + * @see #getName() + * @see #getVersion() + */ + public Object getPlugin(); + + /** + * Returns the actual name of this method. + * + * @return String Plugin name. + */ + public String getName(); + + /** + * Returns the reported name of this method. + * + * @return String Plugin name. + */ + public String getLongName(); + + /** + * Returns the actual version of this method. + * + * @return String Plugin version. + */ + public String getVersion(); + + /** + * Returns the amount of decimal places that get stored + * NOTE: it will return -1 if there is no rounding + * + * @return int for each decimal place + */ + public int fractionalDigits(); + + /** + * Formats amounts into this payment methods style of currency display. + * + * @param amount Double + * @return String - Formatted Currency Display. + */ + public String format(double amount); + + /** + * Allows the verification of bank API existence in this payment method. + * + * @return boolean + */ + public boolean hasBanks(); + + /** + * Determines the existence of a bank via name. + * + * @param bank Bank name + * @return boolean + * @see #hasBanks + */ + public boolean hasBank(String bank); + + /** + * Determines the existence of an account via name. + * + * @param name Account name + * @return boolean + */ + public boolean hasAccount(String name); + + /** + * Check to see if an account name is tied to a bank. + * + * @param bank Bank name + * @param name Account name + * @return boolean + */ + public boolean hasBankAccount(String bank, String name); + + /** + * Forces an account creation + * + * @param name Account name + * @return boolean + */ + public boolean createAccount(String name); + + /** + * Forces an account creation + * + * @param name Account name + * @param balance Initial account balance + * @return boolean + */ + public boolean createAccount(String name, Double balance); + + /** + * Returns a MethodAccount class for an account name. + * + * @param name Account name + * @return MethodAccount or Null + */ + public MethodAccount getAccount(String name); + + /** + * Returns a MethodBankAccount class for an account name. + * + * @param bank Bank name + * @param name Account name + * @return MethodBankAccount or Null + */ + public MethodBankAccount getBankAccount(String bank, String name); + + /** + * Checks to verify the compatibility between this Method and a plugin. + * Internal usage only, for the most part. + * + * @param plugin Plugin + * @return boolean + */ + public boolean isCompatible(Plugin plugin); + + /** + * Set Plugin data. + * + * @param plugin Plugin + */ + public void setPlugin(Plugin plugin); + + + /** + * Contains Calculator and Balance functions for Accounts. + */ + public interface MethodAccount + { + public double balance(); + + public boolean set(double amount); + + public boolean add(double amount); + + public boolean subtract(double amount); + + public boolean multiply(double amount); + + public boolean divide(double amount); + + public boolean hasEnough(double amount); + + public boolean hasOver(double amount); + + public boolean hasUnder(double amount); + + public boolean isNegative(); + + public boolean remove(); + + @Override + public String toString(); + } + + + /** + * Contains Calculator and Balance functions for Bank Accounts. + */ + public interface MethodBankAccount + { + public double balance(); + + public String getBankName(); + + public int getBankId(); + + public boolean set(double amount); + + public boolean add(double amount); + + public boolean subtract(double amount); + + public boolean multiply(double amount); + + public boolean divide(double amount); + + public boolean hasEnough(double amount); + + public boolean hasOver(double amount); + + public boolean hasUnder(double amount); + + public boolean isNegative(); + + public boolean remove(); + + @Override + public String toString(); + } +} diff --git a/Essentials/src/com/earth2me/essentials/register/payment/Methods.java b/Essentials/src/com/earth2me/essentials/register/payment/Methods.java new file mode 100644 index 0000000000..3ba5393b1e --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/register/payment/Methods.java @@ -0,0 +1,294 @@ +package com.earth2me.essentials.register.payment; + +import java.util.HashSet; +import java.util.Set; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginManager; + + +/** + * The + * Methods initializes Methods that utilize the Method interface based on a "first come, first served" + * basis. + * + * Allowing you to check whether a payment method exists or not. + * + * Methods also allows you to set a preferred method of payment before it captures payment plugins in the initialization + * process. + * + * in + * bukkit.yml:
+ *  economy:
+ *      preferred: "iConomy"
+ * 
+ * + * @author: Nijikokun (@nijikokun) @copyright: Copyright (C) 2011 @license: AOL license + * + */ +public class Methods +{ + private static String version = null; + private static boolean self = false; + private static Method Method = null; + private static String preferred = ""; + private static final Set Methods = new HashSet(); + private static final Set Dependencies = new HashSet(); + private static final Set Attachables = new HashSet(); + + static + { + _init(); + } + + /** + * Implement all methods along with their respective name & class. + */ + private static void _init() + { + addMethod("iConomy", new com.earth2me.essentials.register.payment.methods.iCo6()); + addMethod("iConomy", new com.earth2me.essentials.register.payment.methods.iCo5()); + addMethod("BOSEconomy", new com.earth2me.essentials.register.payment.methods.BOSE7()); + addMethod("Currency", new com.earth2me.essentials.register.payment.methods.MCUR()); + Dependencies.add("MultiCurrency"); + addMethod("Vault", new com.earth2me.essentials.register.payment.methods.VaultEco()); + } + + /** + * Used by the plugin to setup version + * + * @param v version + */ + public static void setVersion(String v) + { + version = v; + } + + /** + * Use to reset methods during disable + */ + public static void reset() + { + version = null; + self = false; + Method = null; + preferred = ""; + Attachables.clear(); + } + + /** + * Use to get version of Register plugin + * + * @return version + */ + public static String getVersion() + { + return version; + } + + /** + * Returns an array of payment method names that have been loaded through the + * _init method. + * + * @return + * Set - Array of payment methods that are loaded. + * @see #setMethod(org.bukkit.plugin.Plugin) + */ + public static Set getDependencies() + { + return Dependencies; + } + + /** + * Interprets Plugin class data to verify whether it is compatible with an existing payment method to use for + * payments and other various economic activity. + * + * @param plugin Plugin data from bukkit, Internal Class file. + * @return Method or Null + */ + public static Method createMethod(Plugin plugin) + { + for (Method method : Methods) + { + if (method.isCompatible(plugin)) + { + method.setPlugin(plugin); + return method; + } + } + + return null; + } + + private static void addMethod(String name, Method method) + { + Dependencies.add(name); + Methods.add(method); + } + + /** + * Verifies if Register has set a payment method for usage yet. + * + * @return + * boolean + * @see #setMethod(org.bukkit.plugin.Plugin) + * @see #checkDisabled(org.bukkit.plugin.Plugin) + */ + public static boolean hasMethod() + { + return (Method != null); + } + + /** + * Checks Plugin Class against a multitude of checks to verify it's usability as a payment method. + * + * @param PluginManager the plugin manager for the server + * @return + * boolean True on success, False on failure. + */ + public static boolean setMethod(PluginManager manager) + { + if (hasMethod()) + { + return true; + } + + if (self) + { + self = false; + return false; + } + + int count = 0; + boolean match = false; + Plugin plugin = null; + + for (String name : getDependencies()) + { + if (hasMethod()) + { + break; + } + + plugin = manager.getPlugin(name); + if (plugin == null || !plugin.isEnabled()) + { + continue; + } + + Method current = createMethod(plugin); + if (current == null) + { + continue; + } + + if (preferred.isEmpty()) + { + Method = current; + } + else + { + Attachables.add(current); + } + } + + if (!preferred.isEmpty()) + { + do + { + if (hasMethod()) + { + match = true; + } + else + { + for (Method attached : Attachables) + { + if (attached == null) + { + continue; + } + + if (hasMethod()) + { + match = true; + break; + } + + if (preferred.isEmpty()) + { + Method = attached; + } + + if (count == 0) + { + if (preferred.equalsIgnoreCase(attached.getName())) + { + Method = attached; + } + else + { + Method = attached; + } + } + } + + count++; + } + } + while (!match); + } + + return hasMethod(); + } + + /** + * Sets the preferred economy + * + * @return + * boolean + */ + public static boolean setPreferred(String check) + { + if (getDependencies().contains(check)) + { + preferred = check; + return true; + } + + return false; + } + + /** + * Grab the existing and initialized (hopefully) Method Class. + * + * @return + * Method or + * Null + */ + public static Method getMethod() + { + return Method; + } + + /** + * Verify is a plugin is disabled, only does this if we there is an existing payment method initialized in Register. + * + * @param method Plugin data from bukkit, Internal Class file. + * @return + * boolean + */ + public static boolean checkDisabled(Plugin method) + { + if (!hasMethod()) + { + return true; + } + + if (Method.isCompatible(method)) + { + Method = null; + } + + return (Method == null); + } +} diff --git a/Essentials/src/com/earth2me/essentials/register/payment/methods/BOSE7.java b/Essentials/src/com/earth2me/essentials/register/payment/methods/BOSE7.java new file mode 100644 index 0000000000..a554548ea7 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/register/payment/methods/BOSE7.java @@ -0,0 +1,323 @@ +package com.earth2me.essentials.register.payment.methods; + +import com.earth2me.essentials.register.payment.Method; +import cosine.boseconomy.BOSEconomy; +import org.bukkit.plugin.Plugin; + + +/** + * BOSEconomy 7 Implementation of Method + * + * @author Acrobot + * @author Nijikokun (@nijikokun) @copyright (c) 2011 @license AOL license + * + */ +public class BOSE7 implements Method +{ + private BOSEconomy BOSEconomy; + + @Override + public BOSEconomy getPlugin() + { + return this.BOSEconomy; + } + + @Override + public String getName() + { + return "BOSEconomy"; + } + + @Override + public String getLongName() + { + return getName(); + } + + @Override + public String getVersion() + { + return "0.7.0"; + } + + @Override + public int fractionalDigits() + { + return this.BOSEconomy.getFractionalDigits(); + } + + @Override + public String format(double amount) + { + String currency = this.BOSEconomy.getMoneyNamePlural(); + + if (amount == 1) + { + currency = this.BOSEconomy.getMoneyName(); + } + + return amount + " " + currency; + } + + @Override + public boolean hasBanks() + { + return true; + } + + @Override + public boolean hasBank(String bank) + { + return this.BOSEconomy.bankExists(bank); + } + + @Override + public boolean hasAccount(String name) + { + return this.BOSEconomy.playerRegistered(name, false); + } + + @Override + public boolean hasBankAccount(String bank, String name) + { + return this.BOSEconomy.isBankOwner(bank, name) || this.BOSEconomy.isBankMember(bank, name); + } + + @Override + public boolean createAccount(String name) + { + if (hasAccount(name)) + { + return false; + } + + this.BOSEconomy.registerPlayer(name); + return true; + } + + @Override + public boolean createAccount(String name, Double balance) + { + if (hasAccount(name)) + { + return false; + } + + this.BOSEconomy.registerPlayer(name); + this.BOSEconomy.setPlayerMoney(name, balance, false); + return true; + } + + @Override + public MethodAccount getAccount(String name) + { + if (!hasAccount(name)) + { + return null; + } + + return new BOSEAccount(name, this.BOSEconomy); + } + + @Override + public MethodBankAccount getBankAccount(String bank, String name) + { + if (!hasBankAccount(bank, name)) + { + return null; + } + + return new BOSEBankAccount(bank, BOSEconomy); + } + + @Override + public boolean isCompatible(Plugin plugin) + { + return plugin.getDescription().getName().equalsIgnoreCase("boseconomy") + && plugin instanceof BOSEconomy + && !plugin.getDescription().getVersion().equals("0.6.2"); + } + + @Override + public void setPlugin(Plugin plugin) + { + BOSEconomy = (BOSEconomy)plugin; + } + + + public class BOSEAccount implements MethodAccount + { + private final String name; + private final BOSEconomy BOSEconomy; + + public BOSEAccount(String name, BOSEconomy bOSEconomy) + { + this.name = name; + this.BOSEconomy = bOSEconomy; + } + + @Override + public double balance() + { + return this.BOSEconomy.getPlayerMoneyDouble(this.name); + } + + @Override + public boolean set(double amount) + { + return this.BOSEconomy.setPlayerMoney(this.name, amount, false); + } + + @Override + public boolean add(double amount) + { + return this.BOSEconomy.addPlayerMoney(this.name, amount, false); + } + + @Override + public boolean subtract(double amount) + { + double balance = this.balance(); + return this.BOSEconomy.setPlayerMoney(this.name, (balance - amount), false); + } + + @Override + public boolean multiply(double amount) + { + double balance = this.balance(); + return this.BOSEconomy.setPlayerMoney(this.name, (balance * amount), false); + } + + @Override + public boolean divide(double amount) + { + double balance = this.balance(); + return this.BOSEconomy.setPlayerMoney(this.name, (balance / amount), false); + } + + @Override + public boolean hasEnough(double amount) + { + return (this.balance() >= amount); + } + + @Override + public boolean hasOver(double amount) + { + return (this.balance() > amount); + } + + @Override + public boolean hasUnder(double amount) + { + return (this.balance() < amount); + } + + @Override + public boolean isNegative() + { + return (this.balance() < 0); + } + + @Override + public boolean remove() + { + return false; + } + } + + + public class BOSEBankAccount implements MethodBankAccount + { + private final String bank; + private final BOSEconomy BOSEconomy; + + public BOSEBankAccount(String bank, BOSEconomy bOSEconomy) + { + this.bank = bank; + this.BOSEconomy = bOSEconomy; + } + + @Override + public String getBankName() + { + return this.bank; + } + + @Override + public int getBankId() + { + return -1; + } + + @Override + public double balance() + { + return this.BOSEconomy.getBankMoneyDouble(bank); + } + + @Override + public boolean set(double amount) + { + return this.BOSEconomy.setBankMoney(bank, amount, true); + } + + @Override + public boolean add(double amount) + { + double balance = this.balance(); + return this.BOSEconomy.setBankMoney(bank, (balance + amount), false); + } + + @Override + public boolean subtract(double amount) + { + double balance = this.balance(); + return this.BOSEconomy.setBankMoney(bank, (balance - amount), false); + } + + @Override + public boolean multiply(double amount) + { + double balance = this.balance(); + return this.BOSEconomy.setBankMoney(bank, (balance * amount), false); + } + + @Override + public boolean divide(double amount) + { + double balance = this.balance(); + return this.BOSEconomy.setBankMoney(bank, (balance / amount), false); + } + + @Override + public boolean hasEnough(double amount) + { + return (this.balance() >= amount); + } + + @Override + public boolean hasOver(double amount) + { + return (this.balance() > amount); + } + + @Override + public boolean hasUnder(double amount) + { + return (this.balance() < amount); + } + + @Override + public boolean isNegative() + { + return (this.balance() < 0); + } + + @Override + public boolean remove() + { + return this.BOSEconomy.removeBank(bank); + } + } +} \ No newline at end of file diff --git a/Essentials/src/com/earth2me/essentials/register/payment/methods/MCUR.java b/Essentials/src/com/earth2me/essentials/register/payment/methods/MCUR.java new file mode 100644 index 0000000000..efcb20fb98 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/register/payment/methods/MCUR.java @@ -0,0 +1,195 @@ +package com.earth2me.essentials.register.payment.methods; + +import com.earth2me.essentials.register.payment.Method; +import me.ashtheking.currency.Currency; +import me.ashtheking.currency.CurrencyList; +import org.bukkit.plugin.Plugin; + + +/** + * MultiCurrency Method implementation. + * + * @author Acrobot @copyright (c) 2011 @license AOL license + */ +public class MCUR implements Method +{ + private Currency currencyList; + + @Override + public Object getPlugin() + { + return this.currencyList; + } + + @Override + public String getName() + { + return "MultiCurrency"; + } + + @Override + public String getLongName() + { + return getName(); + } + + @Override + public String getVersion() + { + return "0.09"; + } + + @Override + public int fractionalDigits() + { + return -1; + } + + @Override + public String format(double amount) + { + return amount + " Currency"; + } + + @Override + public boolean hasBanks() + { + return false; + } + + @Override + public boolean hasBank(String bank) + { + return false; + } + + @Override + public boolean hasAccount(String name) + { + return true; + } + + @Override + public boolean hasBankAccount(String bank, String name) + { + return false; + } + + @Override + public boolean createAccount(String name) + { + CurrencyList.setValue((String)CurrencyList.maxCurrency(name)[0], name, 0); + return true; + } + + @Override + public boolean createAccount(String name, Double balance) + { + CurrencyList.setValue((String)CurrencyList.maxCurrency(name)[0], name, balance); + return true; + } + + @Override + public MethodAccount getAccount(String name) + { + return new MCurrencyAccount(name); + } + + @Override + public MethodBankAccount getBankAccount(String bank, String name) + { + return null; + } + + @Override + public boolean isCompatible(Plugin plugin) + { + return (plugin.getDescription().getName().equalsIgnoreCase("Currency") + || plugin.getDescription().getName().equalsIgnoreCase("MultiCurrency")) + && plugin instanceof Currency; + } + + @Override + public void setPlugin(Plugin plugin) + { + currencyList = (Currency)plugin; + } + + + public class MCurrencyAccount implements MethodAccount + { + private final String name; + + public MCurrencyAccount(String name) + { + this.name = name; + } + + @Override + public double balance() + { + return CurrencyList.getValue((String)CurrencyList.maxCurrency(name)[0], name); + } + + @Override + public boolean set(double amount) + { + CurrencyList.setValue((String)CurrencyList.maxCurrency(name)[0], name, amount); + return true; + } + + @Override + public boolean add(double amount) + { + return CurrencyList.add(name, amount); + } + + @Override + public boolean subtract(double amount) + { + return CurrencyList.subtract(name, amount); + } + + @Override + public boolean multiply(double amount) + { + return CurrencyList.multiply(name, amount); + } + + @Override + public boolean divide(double amount) + { + return CurrencyList.divide(name, amount); + } + + @Override + public boolean hasEnough(double amount) + { + return CurrencyList.hasEnough(name, amount); + } + + @Override + public boolean hasOver(double amount) + { + return CurrencyList.hasOver(name, amount); + } + + @Override + public boolean hasUnder(double amount) + { + return CurrencyList.hasUnder(name, amount); + } + + @Override + public boolean isNegative() + { + return CurrencyList.isNegative(name); + } + + @Override + public boolean remove() + { + return CurrencyList.remove(name); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/register/payment/methods/VaultEco.java b/Essentials/src/com/earth2me/essentials/register/payment/methods/VaultEco.java new file mode 100644 index 0000000000..b1863c4871 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/register/payment/methods/VaultEco.java @@ -0,0 +1,347 @@ +package com.earth2me.essentials.register.payment.methods; + +import com.earth2me.essentials.register.payment.Method; +import net.milkbowl.vault.Vault; +import net.milkbowl.vault.economy.Economy; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.RegisteredServiceProvider; + + +public class VaultEco implements Method +{ + private Vault vault; + private Economy economy; + + @Override + public Vault getPlugin() + { + return this.vault; + } + + @Override + public boolean createAccount(String name, Double amount) + { + if (hasAccount(name)) + { + return false; + } + + return false; + } + + @Override + public String getName() + { + return this.vault.getDescription().getName(); + } + + public String getEconomy() + { + return economy == null ? "NoEco" : economy.getName(); + } + + @Override + public String getLongName() + { + return getName().concat(" - Economy: ").concat(getEconomy()); + } + + @Override + public String getVersion() + { + return this.vault.getDescription().getVersion(); + } + + @Override + public int fractionalDigits() + { + return 0; + } + + @Override + public String format(double amount) + { + return this.economy.format(amount); + } + + @Override + public boolean hasBanks() + { + return this.economy.hasBankSupport(); + } + + @Override + public boolean hasBank(String bank) + { + return this.economy.getBanks().contains(bank); + } + + @Override + public boolean hasAccount(String name) + { + return this.economy.hasAccount(name); + } + + @Override + public boolean hasBankAccount(String bank, String name) + { + return this.economy.isBankOwner(bank, name).transactionSuccess() + || this.economy.isBankMember(bank, name).transactionSuccess(); + } + + @Override + public boolean createAccount(String name) + { + return this.economy.createBank(name, "").transactionSuccess(); + } + + public boolean createAccount(String name, double balance) + { + if (!this.economy.createBank(name, "").transactionSuccess()) + { + return false; + } + return this.economy.bankDeposit(name, balance).transactionSuccess(); + } + + @Override + public MethodAccount getAccount(String name) + { + if (!hasAccount(name)) + { + return null; + } + + return new VaultAccount(name, this.economy); + } + + @Override + public MethodBankAccount getBankAccount(String bank, String name) + { + if (!hasBankAccount(bank, name)) + { + return null; + } + + return new VaultBankAccount(bank, economy); + } + + @Override + public boolean isCompatible(Plugin plugin) + { + try + { + RegisteredServiceProvider ecoPlugin = plugin.getServer().getServicesManager().getRegistration(net.milkbowl.vault.economy.Economy.class); + return plugin instanceof Vault && ecoPlugin != null && !ecoPlugin.getProvider().getName().equals("Essentials Economy"); + } + catch (LinkageError e) + { + return false; + } + catch (Exception e) + { + return false; + } + } + + @Override + public void setPlugin(Plugin plugin) + { + this.vault = (Vault)plugin; + RegisteredServiceProvider economyProvider = this.vault.getServer().getServicesManager().getRegistration(net.milkbowl.vault.economy.Economy.class); + if (economyProvider != null) + { + this.economy = economyProvider.getProvider(); + } + } + + + public class VaultAccount implements MethodAccount + { + private final String name; + private final Economy economy; + + public VaultAccount(String name, Economy economy) + { + this.name = name; + this.economy = economy; + } + + @Override + public double balance() + { + return this.economy.getBalance(this.name); + } + + @Override + public boolean set(double amount) + { + if (!this.economy.withdrawPlayer(this.name, this.balance()).transactionSuccess()) + { + return false; + } + if (amount == 0) + { + return true; + } + return this.economy.depositPlayer(this.name, amount).transactionSuccess(); + } + + @Override + public boolean add(double amount) + { + return this.economy.depositPlayer(this.name, amount).transactionSuccess(); + } + + @Override + public boolean subtract(double amount) + { + return this.economy.withdrawPlayer(this.name, amount).transactionSuccess(); + } + + @Override + public boolean multiply(double amount) + { + double balance = this.balance(); + return this.set(balance * amount); + } + + @Override + public boolean divide(double amount) + { + double balance = this.balance(); + return this.set(balance / amount); + } + + @Override + public boolean hasEnough(double amount) + { + return (this.balance() >= amount); + } + + @Override + public boolean hasOver(double amount) + { + return (this.balance() > amount); + } + + @Override + public boolean hasUnder(double amount) + { + return (this.balance() < amount); + } + + @Override + public boolean isNegative() + { + return (this.balance() < 0); + } + + @Override + public boolean remove() + { + return this.set(0.0); + } + } + + + public class VaultBankAccount implements MethodBankAccount + { + private final String bank; + private final Economy economy; + + public VaultBankAccount(String bank, Economy economy) + { + this.bank = bank; + this.economy = economy; + } + + @Override + public String getBankName() + { + return this.bank; + } + + @Override + public int getBankId() + { + return -1; + } + + @Override + public double balance() + { + return this.economy.bankBalance(this.bank).balance; + } + + @Override + public boolean set(double amount) + { + if (!this.economy.bankWithdraw(this.bank, this.balance()).transactionSuccess()) + { + return false; + } + if (amount == 0) + { + return true; + } + return this.economy.bankDeposit(this.bank, amount).transactionSuccess(); + } + + @Override + public boolean add(double amount) + { + return this.economy.bankDeposit(this.bank, amount).transactionSuccess(); + } + + @Override + public boolean subtract(double amount) + { + return this.economy.bankWithdraw(this.bank, amount).transactionSuccess(); + } + + @Override + public boolean multiply(double amount) + { + double balance = this.balance(); + return this.set(balance * amount); + } + + @Override + public boolean divide(double amount) + { + double balance = this.balance(); + return this.set(balance / amount); + } + + @Override + public boolean hasEnough(double amount) + { + return (this.balance() >= amount); + } + + @Override + public boolean hasOver(double amount) + { + return (this.balance() > amount); + } + + @Override + public boolean hasUnder(double amount) + { + return (this.balance() < amount); + } + + @Override + public boolean isNegative() + { + return (this.balance() < 0); + } + + @Override + public boolean remove() + { + return this.set(0.0); + } + } +} \ No newline at end of file diff --git a/Essentials/src/com/earth2me/essentials/register/payment/methods/iCo5.java b/Essentials/src/com/earth2me/essentials/register/payment/methods/iCo5.java new file mode 100644 index 0000000000..75f0528468 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/register/payment/methods/iCo5.java @@ -0,0 +1,376 @@ +package com.earth2me.essentials.register.payment.methods; + +import com.earth2me.essentials.register.payment.Method; +import com.iConomy.iConomy; +import com.iConomy.system.Account; +import com.iConomy.system.BankAccount; +import com.iConomy.system.Holdings; +import com.iConomy.util.Constants; +import org.bukkit.plugin.Plugin; + + +/** + * iConomy 5 Implementation of Method + * + * @author Nijikokun (@nijikokun) @copyright (c) 2011 @license AOL license + * + */ +public class iCo5 implements Method +{ + private iConomy iConomy; + + @Override + public iConomy getPlugin() + { + return this.iConomy; + } + + @Override + public String getName() + { + return "iConomy"; + } + + @Override + public String getLongName() + { + return getName(); + } + + @Override + public String getVersion() + { + return "5"; + } + + @Override + public int fractionalDigits() + { + return 2; + } + + @Override + public String format(double amount) + { + return com.iConomy.iConomy.format(amount); + } + + @Override + public boolean hasBanks() + { + return Constants.Banking; + } + + @Override + public boolean hasBank(String bank) + { + return (hasBanks()) && com.iConomy.iConomy.Banks.exists(bank); + } + + @Override + public boolean hasAccount(String name) + { + return com.iConomy.iConomy.hasAccount(name); + } + + @Override + public boolean hasBankAccount(String bank, String name) + { + return (hasBank(bank)) && com.iConomy.iConomy.getBank(bank).hasAccount(name); + } + + @Override + public boolean createAccount(String name) + { + if (hasAccount(name)) + { + return false; + } + + return com.iConomy.iConomy.Accounts.create(name); + } + + @Override + public boolean createAccount(String name, Double balance) + { + if (hasAccount(name)) + { + return false; + } + + if (!com.iConomy.iConomy.Accounts.create(name)) + { + return false; + } + + getAccount(name).set(balance); + + return true; + } + + @Override + public MethodAccount getAccount(String name) + { + return new iCoAccount(com.iConomy.iConomy.getAccount(name)); + } + + @Override + public MethodBankAccount getBankAccount(String bank, String name) + { + return new iCoBankAccount(com.iConomy.iConomy.getBank(bank).getAccount(name)); + } + + @Override + public boolean isCompatible(Plugin plugin) + { + return plugin.getDescription().getName().equalsIgnoreCase("iconomy") + && plugin.getClass().getName().equals("com.iConomy.iConomy") + && plugin instanceof iConomy; + } + + @Override + public void setPlugin(Plugin plugin) + { + iConomy = (iConomy)plugin; + } + + + public class iCoAccount implements MethodAccount + { + private final Account account; + private final Holdings holdings; + + public iCoAccount(Account account) + { + this.account = account; + this.holdings = account.getHoldings(); + } + + public Account getiCoAccount() + { + return account; + } + + @Override + public double balance() + { + return this.holdings.balance(); + } + + @Override + public boolean set(double amount) + { + if (this.holdings == null) + { + return false; + } + this.holdings.set(amount); + return true; + } + + @Override + public boolean add(double amount) + { + if (this.holdings == null) + { + return false; + } + this.holdings.add(amount); + return true; + } + + @Override + public boolean subtract(double amount) + { + if (this.holdings == null) + { + return false; + } + this.holdings.subtract(amount); + return true; + } + + @Override + public boolean multiply(double amount) + { + if (this.holdings == null) + { + return false; + } + this.holdings.multiply(amount); + return true; + } + + @Override + public boolean divide(double amount) + { + if (this.holdings == null) + { + return false; + } + this.holdings.divide(amount); + return true; + } + + @Override + public boolean hasEnough(double amount) + { + return this.holdings.hasEnough(amount); + } + + @Override + public boolean hasOver(double amount) + { + return this.holdings.hasOver(amount); + } + + @Override + public boolean hasUnder(double amount) + { + return this.holdings.hasUnder(amount); + } + + @Override + public boolean isNegative() + { + return this.holdings.isNegative(); + } + + @Override + public boolean remove() + { + if (this.account == null) + { + return false; + } + this.account.remove(); + return true; + } + } + + + public class iCoBankAccount implements MethodBankAccount + { + private final BankAccount account; + private final Holdings holdings; + + public iCoBankAccount(BankAccount account) + { + this.account = account; + this.holdings = account.getHoldings(); + } + + public BankAccount getiCoBankAccount() + { + return account; + } + + @Override + public String getBankName() + { + return this.account.getBankName(); + } + + @Override + public int getBankId() + { + return this.account.getBankId(); + } + + @Override + public double balance() + { + return this.holdings.balance(); + } + + @Override + public boolean set(double amount) + { + if (this.holdings == null) + { + return false; + } + this.holdings.set(amount); + return true; + } + + @Override + public boolean add(double amount) + { + if (this.holdings == null) + { + return false; + } + this.holdings.add(amount); + return true; + } + + @Override + public boolean subtract(double amount) + { + if (this.holdings == null) + { + return false; + } + this.holdings.subtract(amount); + return true; + } + + @Override + public boolean multiply(double amount) + { + if (this.holdings == null) + { + return false; + } + this.holdings.multiply(amount); + return true; + } + + @Override + public boolean divide(double amount) + { + if (this.holdings == null) + { + return false; + } + this.holdings.divide(amount); + return true; + } + + @Override + public boolean hasEnough(double amount) + { + return this.holdings.hasEnough(amount); + } + + @Override + public boolean hasOver(double amount) + { + return this.holdings.hasOver(amount); + } + + @Override + public boolean hasUnder(double amount) + { + return this.holdings.hasUnder(amount); + } + + @Override + public boolean isNegative() + { + return this.holdings.isNegative(); + } + + @Override + public boolean remove() + { + if (this.account == null) + { + return false; + } + this.account.remove(); + return true; + } + } +} \ No newline at end of file diff --git a/Essentials/src/com/earth2me/essentials/register/payment/methods/iCo6.java b/Essentials/src/com/earth2me/essentials/register/payment/methods/iCo6.java new file mode 100644 index 0000000000..bf0c1c60a3 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/register/payment/methods/iCo6.java @@ -0,0 +1,242 @@ +package com.earth2me.essentials.register.payment.methods; + +import com.earth2me.essentials.register.payment.Method; +import com.iCo6.iConomy; +import com.iCo6.system.Account; +import com.iCo6.system.Accounts; +import com.iCo6.system.Holdings; +import org.bukkit.plugin.Plugin; + + +/** + * iConomy 6 Implementation of Method + * + * @author Nijikokun (@nijikokun) @copyright (c) 2011 @license AOL license + * + */ +public class iCo6 implements Method +{ + private iConomy iConomy; + + @Override + public iConomy getPlugin() + { + return this.iConomy; + } + + @Override + public String getName() + { + return "iConomy"; + } + + @Override + public String getLongName() + { + return getName(); + } + + @Override + public String getVersion() + { + return "6"; + } + + @Override + public int fractionalDigits() + { + return 2; + } + + @Override + public String format(double amount) + { + return com.iCo6.iConomy.format(amount); + } + + @Override + public boolean hasBanks() + { + return false; + } + + @Override + public boolean hasBank(String bank) + { + return false; + } + + @Override + public boolean hasAccount(String name) + { + return (new Accounts()).exists(name); + } + + @Override + public boolean hasBankAccount(String bank, String name) + { + return false; + } + + @Override + public boolean createAccount(String name) + { + if (hasAccount(name)) + { + return false; + } + + return (new Accounts()).create(name); + } + + @Override + public boolean createAccount(String name, Double balance) + { + if (hasAccount(name)) + { + return false; + } + + return (new Accounts()).create(name, balance); + } + + @Override + public MethodAccount getAccount(String name) + { + return new iCoAccount((new Accounts()).get(name)); + } + + @Override + public MethodBankAccount getBankAccount(String bank, String name) + { + return null; + } + + @Override + public boolean isCompatible(Plugin plugin) + { + return plugin.getDescription().getName().equalsIgnoreCase("iconomy") + && plugin.getClass().getName().equals("com.iCo6.iConomy") + && plugin instanceof iConomy; + } + + @Override + public void setPlugin(Plugin plugin) + { + iConomy = (iConomy)plugin; + } + + + public class iCoAccount implements MethodAccount + { + private final Account account; + private final Holdings holdings; + + public iCoAccount(Account account) + { + this.account = account; + this.holdings = account.getHoldings(); + } + + public Account getiCoAccount() + { + return account; + } + + @Override + public double balance() + { + return this.holdings.getBalance(); + } + + @Override + public boolean set(double amount) + { + if (this.holdings == null) + { + return false; + } + this.holdings.setBalance(amount); + return true; + } + + @Override + public boolean add(double amount) + { + if (this.holdings == null) + { + return false; + } + this.holdings.add(amount); + return true; + } + + @Override + public boolean subtract(double amount) + { + if (this.holdings == null) + { + return false; + } + this.holdings.subtract(amount); + return true; + } + + @Override + public boolean multiply(double amount) + { + if (this.holdings == null) + { + return false; + } + this.holdings.multiply(amount); + return true; + } + + @Override + public boolean divide(double amount) + { + if (this.holdings == null) + { + return false; + } + this.holdings.divide(amount); + return true; + } + + @Override + public boolean hasEnough(double amount) + { + return this.holdings.hasEnough(amount); + } + + @Override + public boolean hasOver(double amount) + { + return this.holdings.hasOver(amount); + } + + @Override + public boolean hasUnder(double amount) + { + return this.holdings.hasUnder(amount); + } + + @Override + public boolean isNegative() + { + return this.holdings.isNegative(); + } + + @Override + public boolean remove() + { + if (this.account == null) + { + return false; + } + this.account.remove(); + return true; + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/settings/Jails.java b/Essentials/src/com/earth2me/essentials/settings/Jails.java new file mode 100644 index 0000000000..4f9b79197c --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/settings/Jails.java @@ -0,0 +1,18 @@ +package com.earth2me.essentials.settings; + +import com.earth2me.essentials.storage.MapValueType; +import com.earth2me.essentials.storage.StorageObject; +import java.util.HashMap; +import java.util.Map; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.bukkit.Location; + + +@Data +@EqualsAndHashCode(callSuper = false) +public class Jails implements StorageObject +{ + @MapValueType(Location.class) + private Map jails = new HashMap(); +} diff --git a/Essentials/src/com/earth2me/essentials/settings/Spawns.java b/Essentials/src/com/earth2me/essentials/settings/Spawns.java new file mode 100644 index 0000000000..a0afa450cd --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/settings/Spawns.java @@ -0,0 +1,18 @@ +package com.earth2me.essentials.settings; + +import com.earth2me.essentials.storage.MapValueType; +import com.earth2me.essentials.storage.StorageObject; +import java.util.HashMap; +import java.util.Map; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.bukkit.Location; + + +@Data +@EqualsAndHashCode(callSuper = false) +public class Spawns implements StorageObject +{ + @MapValueType(Location.class) + private Map spawns = new HashMap(); +} diff --git a/Essentials/src/com/earth2me/essentials/signs/EssentialsSign.java b/Essentials/src/com/earth2me/essentials/signs/EssentialsSign.java new file mode 100644 index 0000000000..6231bbc09c --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/EssentialsSign.java @@ -0,0 +1,634 @@ +package com.earth2me.essentials.signs; + +import com.earth2me.essentials.*; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.utils.NumberUtil; +import java.math.BigDecimal; +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; +import net.ess3.api.IEssentials; +import net.ess3.api.MaxMoneyException; +import net.ess3.api.events.SignBreakEvent; +import net.ess3.api.events.SignCreateEvent; +import net.ess3.api.events.SignInteractEvent; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.Sign; +import org.bukkit.entity.Player; +import org.bukkit.event.block.SignChangeEvent; +import org.bukkit.inventory.ItemStack; + + +public class EssentialsSign +{ + private static final Set EMPTY_SET = new HashSet(); + protected static final BigDecimal MINTRANSACTION = new BigDecimal("0.01"); + protected transient final String signName; + + public EssentialsSign(final String signName) + { + this.signName = signName; + } + + protected final boolean onSignCreate(final SignChangeEvent event, final IEssentials ess) + { + final ISign sign = new EventSign(event); + final User user = ess.getUser(event.getPlayer()); + if (!(user.isAuthorized("essentials.signs." + signName.toLowerCase(Locale.ENGLISH) + ".create") + || user.isAuthorized("essentials.signs.create." + signName.toLowerCase(Locale.ENGLISH)))) + { + // Return true, so other plugins can use the same sign title, just hope + // they won't change it to §1[Signname] + return true; + } + sign.setLine(0, tl("signFormatFail", this.signName)); + + final SignCreateEvent signEvent = new SignCreateEvent(sign, this, user); + ess.getServer().getPluginManager().callEvent(signEvent); + if (signEvent.isCancelled()) + { + return false; + } + + try + { + final boolean ret = onSignCreate(sign, user, getUsername(user), ess); + if (ret) + { + sign.setLine(0, getSuccessName()); + } + return ret; + } + catch (ChargeException ex) + { + showError(ess, user.getSource(), ex, signName); + } + catch (SignException ex) + { + showError(ess, user.getSource(), ex, signName); + } + // Return true, so the player sees the wrong sign. + return true; + } + + public String getSuccessName() + { + return tl("signFormatSuccess", this.signName); + } + + public String getTemplateName() + { + return tl("signFormatTemplate", this.signName); + } + + public String getName() + { + return this.signName; + } + + public String getUsername(final User user) + { + return user.getName().substring(0, user.getName().length() > 13 ? 13 : user.getName().length()); + } + + protected final boolean onSignInteract(final Block block, final Player player, final IEssentials ess) + { + final ISign sign = new BlockSign(block); + final User user = ess.getUser(player); + if (user.checkSignThrottle()) + { + return false; + } + try + { + if (user.getBase().isDead() || !(user.isAuthorized("essentials.signs." + signName.toLowerCase(Locale.ENGLISH) + ".use") + || user.isAuthorized("essentials.signs.use." + signName.toLowerCase(Locale.ENGLISH)))) + { + return false; + } + + final SignInteractEvent signEvent = new SignInteractEvent(sign, this, user); + ess.getServer().getPluginManager().callEvent(signEvent); + if (signEvent.isCancelled()) + { + return false; + } + + return onSignInteract(sign, user, getUsername(user), ess); + } + catch (ChargeException ex) + { + showError(ess, user.getSource(), ex, signName); + return false; + } + catch (Exception ex) + { + showError(ess, user.getSource(), ex, signName); + return false; + } + } + + protected final boolean onSignBreak(final Block block, final Player player, final IEssentials ess) throws MaxMoneyException + { + final ISign sign = new BlockSign(block); + final User user = ess.getUser(player); + try + { + if (!(user.isAuthorized("essentials.signs." + signName.toLowerCase(Locale.ENGLISH) + ".break") + || user.isAuthorized("essentials.signs.break." + signName.toLowerCase(Locale.ENGLISH)))) + { + return false; + } + + final SignBreakEvent signEvent = new SignBreakEvent(sign, this, user); + ess.getServer().getPluginManager().callEvent(signEvent); + if (signEvent.isCancelled()) + { + return false; + } + + return onSignBreak(sign, user, getUsername(user), ess); + } + catch (SignException ex) + { + showError(ess, user.getSource(), ex, signName); + return false; + } + } + + protected boolean onSignCreate(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException, ChargeException + { + return true; + } + + protected boolean onSignInteract(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException, ChargeException, MaxMoneyException + { + return true; + } + + protected boolean onSignBreak(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException, MaxMoneyException + { + return true; + } + + protected final boolean onBlockPlace(final Block block, final Player player, final IEssentials ess) + { + User user = ess.getUser(player); + try + { + return onBlockPlace(block, user, getUsername(user), ess); + } + catch (ChargeException ex) + { + showError(ess, user.getSource(), ex, signName); + } + catch (SignException ex) + { + showError(ess, user.getSource(), ex, signName); + } + return false; + } + + protected final boolean onBlockInteract(final Block block, final Player player, final IEssentials ess) + { + User user = ess.getUser(player); + try + { + return onBlockInteract(block, user, getUsername(user), ess); + } + catch (ChargeException ex) + { + showError(ess, user.getSource(), ex, signName); + } + catch (SignException ex) + { + showError(ess, user.getSource(), ex, signName); + } + return false; + } + + protected final boolean onBlockBreak(final Block block, final Player player, final IEssentials ess) throws MaxMoneyException + { + User user = ess.getUser(player); + try + { + return onBlockBreak(block, user, getUsername(user), ess); + } + catch (SignException ex) + { + showError(ess, user.getSource(), ex, signName); + } + return false; + } + + protected boolean onBlockBreak(final Block block, final IEssentials ess) + { + return true; + } + + protected boolean onBlockExplode(final Block block, final IEssentials ess) + { + return true; + } + + protected boolean onBlockBurn(final Block block, final IEssentials ess) + { + return true; + } + + protected boolean onBlockIgnite(final Block block, final IEssentials ess) + { + return true; + } + + protected boolean onBlockPush(final Block block, final IEssentials ess) + { + return true; + } + + protected static boolean checkIfBlockBreaksSigns(final Block block) + { + final Block sign = block.getRelative(BlockFace.UP); + if (sign.getType() == Material.SIGN_POST && isValidSign(new BlockSign(sign))) + { + return true; + } + final BlockFace[] directions = new BlockFace[] + { + BlockFace.NORTH, + BlockFace.EAST, + BlockFace.SOUTH, + BlockFace.WEST + }; + for (BlockFace blockFace : directions) + { + final Block signblock = block.getRelative(blockFace); + if (signblock.getType() == Material.WALL_SIGN) + { + try + { + final org.bukkit.material.Sign signMat = (org.bukkit.material.Sign)signblock.getState().getData(); + if (signMat != null && signMat.getFacing() == blockFace && isValidSign(new BlockSign(signblock))) + { + return true; + } + } + catch (NullPointerException ex) + { + // Sometimes signs enter a state of being semi broken, having no text or state data, usually while burning. + } + } + } + return false; + } + + public static boolean isValidSign(final ISign sign) + { + return sign.getLine(0).matches("§1\\[.*\\]"); + } + + protected boolean onBlockPlace(final Block block, final User player, final String username, final IEssentials ess) throws SignException, ChargeException + { + return true; + } + + protected boolean onBlockInteract(final Block block, final User player, final String username, final IEssentials ess) throws SignException, ChargeException + { + return true; + } + + protected boolean onBlockBreak(final Block block, final User player, final String username, final IEssentials ess) throws SignException, MaxMoneyException + { + return true; + } + + public Set getBlocks() + { + return EMPTY_SET; + } + + public boolean areHeavyEventRequired() + { + return false; + } + + private String getSignText(final ISign sign, final int lineNumber) + { + return sign.getLine(lineNumber).trim(); + } + + protected final void validateTrade(final ISign sign, final int index, final IEssentials ess) throws SignException + { + final String line = getSignText(sign, index); + if (line.isEmpty()) + { + return; + } + final Trade trade = getTrade(sign, index, 0, ess); + final BigDecimal money = trade.getMoney(); + if (money != null) + { + sign.setLine(index, NumberUtil.shortCurrency(money, ess)); + } + } + + protected final void validateTrade(final ISign sign, final int amountIndex, final int itemIndex, + final User player, final IEssentials ess) throws SignException + { + final String itemType = getSignText(sign, itemIndex); + if (itemType.equalsIgnoreCase("exp") || itemType.equalsIgnoreCase("xp")) + { + int amount = getIntegerPositive(getSignText(sign, amountIndex)); + sign.setLine(amountIndex, Integer.toString(amount)); + sign.setLine(itemIndex, "exp"); + return; + } + final Trade trade = getTrade(sign, amountIndex, itemIndex, player, ess); + final ItemStack item = trade.getItemStack(); + sign.setLine(amountIndex, Integer.toString(item.getAmount())); + sign.setLine(itemIndex, itemType); + } + + protected final Trade getTrade(final ISign sign, final int amountIndex, final int itemIndex, + final User player, final IEssentials ess) throws SignException + { + final String itemType = getSignText(sign, itemIndex); + if (itemType.equalsIgnoreCase("exp") || itemType.equalsIgnoreCase("xp")) + { + final int amount = getIntegerPositive(getSignText(sign, amountIndex)); + return new Trade(amount, ess); + } + final ItemStack item = getItemStack(itemType, 1, ess); + final int amount = Math.min(getIntegerPositive(getSignText(sign, amountIndex)), item.getType().getMaxStackSize() * player.getBase().getInventory().getSize()); + if (item.getType() == Material.AIR || amount < 1) + { + throw new SignException(tl("moreThanZero")); + } + item.setAmount(amount); + return new Trade(item, ess); + } + + protected final void validateInteger(final ISign sign, final int index) throws SignException + { + final String line = getSignText(sign, index); + if (line.isEmpty()) + { + throw new SignException("Empty line " + index); + } + final int quantity = getIntegerPositive(line); + sign.setLine(index, Integer.toString(quantity)); + } + + protected final int getIntegerPositive(final String line) throws SignException + { + final int quantity = getInteger(line); + if (quantity < 1) + { + throw new SignException(tl("moreThanZero")); + } + return quantity; + } + + protected final int getInteger(final String line) throws SignException + { + try + { + final int quantity = Integer.parseInt(line); + + return quantity; + } + catch (NumberFormatException ex) + { + throw new SignException("Invalid sign", ex); + } + } + + protected final ItemStack getItemStack(final String itemName, final int quantity, final IEssentials ess) throws SignException + { + try + { + final ItemStack item = ess.getItemDb().get(itemName); + item.setAmount(quantity); + return item; + } + catch (Exception ex) + { + throw new SignException(ex.getMessage(), ex); + } + } + + protected final ItemStack getItemMeta(final ItemStack item, final String meta, final IEssentials ess) throws SignException + { + ItemStack stack = item; + try + { + if (!meta.isEmpty()) + { + MetaItemStack metaStack = new MetaItemStack(stack); + final boolean allowUnsafe = ess.getSettings().allowUnsafeEnchantments(); + metaStack.addStringMeta(null, allowUnsafe, meta, ess); + stack = metaStack.getItemStack(); + } + } + catch (Exception ex) + { + throw new SignException(ex.getMessage(), ex); + } + return stack; + } + + protected final BigDecimal getMoney(final String line) throws SignException + { + final boolean isMoney = line.matches("^[^0-9-\\.][\\.0-9]+$"); + return isMoney ? getBigDecimalPositive(line.substring(1)) : null; + } + + protected final BigDecimal getBigDecimalPositive(final String line) throws SignException + { + final BigDecimal quantity = getBigDecimal(line); + if (quantity.compareTo(MINTRANSACTION) < 0) + { + throw new SignException(tl("moreThanZero")); + } + return quantity; + } + + protected final BigDecimal getBigDecimal(final String line) throws SignException + { + try + { + return new BigDecimal(line); + } + catch (ArithmeticException ex) + { + throw new SignException(ex.getMessage(), ex); + } + catch (NumberFormatException ex) + { + throw new SignException(ex.getMessage(), ex); + } + } + + protected final Trade getTrade(final ISign sign, final int index, final IEssentials ess) throws SignException + { + return getTrade(sign, index, 1, ess); + } + + protected final Trade getTrade(final ISign sign, final int index, final int decrement, final IEssentials ess) throws SignException + { + final String line = getSignText(sign, index); + if (line.isEmpty()) + { + return new Trade(signName.toLowerCase(Locale.ENGLISH) + "sign", ess); + } + + final BigDecimal money = getMoney(line); + if (money == null) + { + final String[] split = line.split("[ :]+", 2); + if (split.length != 2) + { + throw new SignException(tl("invalidCharge")); + } + final int quantity = getIntegerPositive(split[0]); + + final String item = split[1].toLowerCase(Locale.ENGLISH); + if (item.equalsIgnoreCase("times")) + { + sign.setLine(index, (quantity - decrement) + " times"); + sign.updateSign(); + return new Trade(signName.toLowerCase(Locale.ENGLISH) + "sign", ess); + } + else if (item.equalsIgnoreCase("exp") || item.equalsIgnoreCase("xp")) + { + sign.setLine(index, quantity + " exp"); + return new Trade(quantity, ess); + } + else + { + final ItemStack stack = getItemStack(item, quantity, ess); + sign.setLine(index, quantity + " " + item); + return new Trade(stack, ess); + } + } + else + { + return new Trade(money, ess); + } + } + + private void showError(final IEssentials ess, final CommandSource sender, final Throwable exception, final String signName) + { + ess.showError(sender, exception, "\\ sign: " + signName); + } + + + static class EventSign implements ISign + { + private final transient SignChangeEvent event; + private final transient Block block; + private final transient Sign sign; + + EventSign(final SignChangeEvent event) + { + this.event = event; + this.block = event.getBlock(); + this.sign = (Sign)block.getState(); + } + + @Override + public final String getLine(final int index) + { + StringBuilder builder = new StringBuilder(); + for (char c : event.getLine(index).toCharArray()) + { + if (c < 0xF700 || c > 0xF747) + { + builder.append(c); + } + } + return builder.toString(); + //return event.getLine(index); // Above code can be removed and replaced with this line when https://github.com/Bukkit/Bukkit/pull/982 is merged. + } + + @Override + public final void setLine(final int index, final String text) + { + event.setLine(index, text); + sign.setLine(index, text); + updateSign(); + } + + @Override + public Block getBlock() + { + return block; + } + + @Override + public void updateSign() + { + sign.update(); + } + } + + + static class BlockSign implements ISign + { + private final transient Sign sign; + private final transient Block block; + + BlockSign(final Block block) + { + this.block = block; + this.sign = (Sign)block.getState(); + } + + @Override + public final String getLine(final int index) + { + StringBuilder builder = new StringBuilder(); + for (char c : sign.getLine(index).toCharArray()) + { + if (c < 0xF700 || c > 0xF747) + { + builder.append(c); + } + } + return builder.toString(); + //return event.getLine(index); // Above code can be removed and replaced with this line when https://github.com/Bukkit/Bukkit/pull/982 is merged. + } + + @Override + public final void setLine(final int index, final String text) + { + sign.setLine(index, text); + } + + @Override + public final Block getBlock() + { + return block; + } + + @Override + public final void updateSign() + { + sign.update(); + } + } + + + public interface ISign + { + public String getLine(final int index); + + public void setLine(final int index, final String text); + + public Block getBlock(); + + public void updateSign(); + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignBalance.java b/Essentials/src/com/earth2me/essentials/signs/SignBalance.java new file mode 100644 index 0000000000..bd5b10f09b --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignBalance.java @@ -0,0 +1,22 @@ +package com.earth2me.essentials.signs; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.NumberUtil; +import net.ess3.api.IEssentials; + + +public class SignBalance extends EssentialsSign +{ + public SignBalance() + { + super("Balance"); + } + + @Override + protected boolean onSignInteract(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException + { + player.sendMessage(tl("balance", NumberUtil.displayCurrency(player.getMoney(), ess))); + return true; + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignBlockListener.java b/Essentials/src/com/earth2me/essentials/signs/SignBlockListener.java new file mode 100644 index 0000000000..9b4e87d93a --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignBlockListener.java @@ -0,0 +1,304 @@ +package com.earth2me.essentials.signs; + +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.FormatUtil; +import java.util.logging.Level; +import java.util.logging.Logger; +import net.ess3.api.IEssentials; +import net.ess3.api.MaxMoneyException; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.Sign; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.*; + + +public class SignBlockListener implements Listener +{ + private static final Logger LOGGER = Logger.getLogger("Essentials"); + private static final Material WALL_SIGN = Material.WALL_SIGN; + private static final Material SIGN_POST = Material.SIGN_POST; + private final transient IEssentials ess; + + public SignBlockListener(IEssentials ess) + { + this.ess = ess; + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onSignBlockBreak(final BlockBreakEvent event) + { + if (ess.getSettings().areSignsDisabled()) + { + event.getHandlers().unregister(this); + return; + } + try + { + if (protectSignsAndBlocks(event.getBlock(), event.getPlayer())) + { + event.setCancelled(true); + } + } + catch (MaxMoneyException ex) + { + event.setCancelled(true); + } + } + + public boolean protectSignsAndBlocks(final Block block, final Player player) throws MaxMoneyException + { + // prevent any signs be broken by destroying the block they are attached to + if (EssentialsSign.checkIfBlockBreaksSigns(block)) + { + LOGGER.log(Level.INFO, "Prevented that a block was broken next to a sign."); + return true; + } + + final Material mat = block.getType(); + if (mat == SIGN_POST || mat == WALL_SIGN) + { + final Sign csign = (Sign)block.getState(); + + for (EssentialsSign sign : ess.getSettings().enabledSigns()) + { + if (csign.getLine(0).equalsIgnoreCase(sign.getSuccessName()) + && !sign.onSignBreak(block, player, ess)) + { + return true; + } + } + } + + for (EssentialsSign sign : ess.getSettings().enabledSigns()) + { + if (sign.areHeavyEventRequired() && sign.getBlocks().contains(block.getType()) + && !sign.onBlockBreak(block, player, ess)) + { + LOGGER.log(Level.INFO, "A block was protected by a sign."); + return true; + } + } + return false; + } + + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + public void onSignSignChange2(final SignChangeEvent event) + { + if (ess.getSettings().areSignsDisabled()) + { + event.getHandlers().unregister(this); + return; + } + User user = ess.getUser(event.getPlayer()); + + for (int i = 0; i < 4; i++) + { + event.setLine(i, FormatUtil.formatString(user, "essentials.signs", event.getLine(i))); + } + + final String topLine = event.getLine(0); + //We loop through all sign types here to prevent clashes with preexisting signs later + for (Signs signs : Signs.values()) + { + final EssentialsSign sign = signs.getSign(); + if (topLine.equalsIgnoreCase(sign.getSuccessName())) + { + event.setLine(0, FormatUtil.stripFormat(topLine)); + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onSignSignChange(final SignChangeEvent event) + { + if (ess.getSettings().areSignsDisabled()) + { + event.getHandlers().unregister(this); + return; + } + + for (EssentialsSign sign : ess.getSettings().enabledSigns()) + { + if (event.getLine(0).equalsIgnoreCase(sign.getSuccessName())) + { + event.setCancelled(true); + return; + } + if (event.getLine(0).equalsIgnoreCase(sign.getTemplateName()) + && !sign.onSignCreate(event, ess)) + { + event.setCancelled(true); + return; + } + } + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onSignBlockPlace(final BlockPlaceEvent event) + { + if (ess.getSettings().areSignsDisabled()) + { + event.getHandlers().unregister(this); + return; + } + + final Block against = event.getBlockAgainst(); + if ((against.getType() == WALL_SIGN + || against.getType() == SIGN_POST) + && EssentialsSign.isValidSign(new EssentialsSign.BlockSign(against))) + { + event.setCancelled(true); + return; + } + final Block block = event.getBlock(); + if (block.getType() == WALL_SIGN + || block.getType() == SIGN_POST) + { + return; + } + for (EssentialsSign sign : ess.getSettings().enabledSigns()) + { + if (sign.areHeavyEventRequired() && sign.getBlocks().contains(block.getType()) + && !sign.onBlockPlace(block, event.getPlayer(), ess)) + { + event.setCancelled(true); + return; + } + } + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onSignBlockBurn(final BlockBurnEvent event) + { + if (ess.getSettings().areSignsDisabled()) + { + event.getHandlers().unregister(this); + return; + } + + final Block block = event.getBlock(); + if (((block.getType() == WALL_SIGN + || block.getType() == SIGN_POST) + && EssentialsSign.isValidSign(new EssentialsSign.BlockSign(block))) + || EssentialsSign.checkIfBlockBreaksSigns(block)) + { + event.setCancelled(true); + return; + } + for (EssentialsSign sign : ess.getSettings().enabledSigns()) + { + if (sign.areHeavyEventRequired() && sign.getBlocks().contains(block.getType()) + && !sign.onBlockBurn(block, ess)) + { + event.setCancelled(true); + return; + } + } + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onSignBlockIgnite(final BlockIgniteEvent event) + { + if (ess.getSettings().areSignsDisabled()) + { + event.getHandlers().unregister(this); + return; + } + + final Block block = event.getBlock(); + if (((block.getType() == WALL_SIGN + || block.getType() == SIGN_POST) + && EssentialsSign.isValidSign(new EssentialsSign.BlockSign(block))) + || EssentialsSign.checkIfBlockBreaksSigns(block)) + { + event.setCancelled(true); + return; + } + for (EssentialsSign sign : ess.getSettings().enabledSigns()) + { + if (sign.areHeavyEventRequired() && sign.getBlocks().contains(block.getType()) + && !sign.onBlockIgnite(block, ess)) + { + event.setCancelled(true); + return; + } + } + } + + @EventHandler(priority = EventPriority.LOW) + public void onSignBlockPistonExtend(final BlockPistonExtendEvent event) + { + if (ess.getSettings().areSignsDisabled()) + { + event.getHandlers().unregister(this); + return; + } + + for (Block block : event.getBlocks()) + { + if (((block.getType() == WALL_SIGN + || block.getType() == SIGN_POST) + && EssentialsSign.isValidSign(new EssentialsSign.BlockSign(block))) + || EssentialsSign.checkIfBlockBreaksSigns(block)) + { + event.setCancelled(true); + return; + } + for (EssentialsSign sign : ess.getSettings().enabledSigns()) + { + if (sign.areHeavyEventRequired() && sign.getBlocks().contains(block.getType()) + && !sign.onBlockPush(block, ess)) + { + event.setCancelled(true); + return; + } + } + } + } + + @EventHandler(priority = EventPriority.LOW) + public void onSignBlockPistonRetract(final BlockPistonRetractEvent event) + { + if (ess.getSettings().areSignsDisabled()) + { + event.getHandlers().unregister(this); + return; + } + + if (event.isSticky()) + { + final Block pistonBaseBlock = event.getBlock(); + final Block[] affectedBlocks = new Block[] + { + pistonBaseBlock, + pistonBaseBlock.getRelative(event.getDirection()), + event.getRetractLocation().getBlock() + }; + + for (Block block : affectedBlocks) + { + if (((block.getType() == WALL_SIGN + || block.getType() == SIGN_POST) + && EssentialsSign.isValidSign(new EssentialsSign.BlockSign(block))) + || EssentialsSign.checkIfBlockBreaksSigns(block)) + { + event.setCancelled(true); + return; + } + for (EssentialsSign sign : ess.getSettings().enabledSigns()) + { + if (sign.areHeavyEventRequired() && sign.getBlocks().contains(block.getType()) + && !sign.onBlockPush(block, ess)) + { + event.setCancelled(true); + return; + } + } + } + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignBuy.java b/Essentials/src/com/earth2me/essentials/signs/SignBuy.java new file mode 100644 index 0000000000..13c7799c7c --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignBuy.java @@ -0,0 +1,39 @@ +package com.earth2me.essentials.signs; + +import com.earth2me.essentials.ChargeException; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import net.ess3.api.IEssentials; +import net.ess3.api.MaxMoneyException; + + +public class SignBuy extends EssentialsSign +{ + public SignBuy() + { + super("Buy"); + } + + @Override + protected boolean onSignCreate(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException + { + validateTrade(sign, 1, 2, player, ess); + validateTrade(sign, 3, ess); + return true; + } + + @Override + protected boolean onSignInteract(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException, ChargeException, MaxMoneyException + { + final Trade items = getTrade(sign, 1, 2, player, ess); + final Trade charge = getTrade(sign, 3, ess); + charge.isAffordableFor(player); + if (!items.pay(player)) + { + throw new ChargeException("Inventory full"); //TODO: TL + } + charge.charge(player); + Trade.log("Sign", "Buy", "Interact", username, charge, username, items, sign.getBlock().getLocation(), ess); + return true; + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignDisposal.java b/Essentials/src/com/earth2me/essentials/signs/SignDisposal.java new file mode 100644 index 0000000000..981f5499d3 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignDisposal.java @@ -0,0 +1,20 @@ +package com.earth2me.essentials.signs; + +import com.earth2me.essentials.User; +import net.ess3.api.IEssentials; + + +public class SignDisposal extends EssentialsSign +{ + public SignDisposal() + { + super("Disposal"); + } + + @Override + protected boolean onSignInteract(final ISign sign, final User player, final String username, final IEssentials ess) + { + player.getBase().openInventory(ess.getServer().createInventory(player.getBase(), 36, "Disposal")); + return true; + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignEnchant.java b/Essentials/src/com/earth2me/essentials/signs/SignEnchant.java new file mode 100644 index 0000000000..89cfa30e94 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignEnchant.java @@ -0,0 +1,160 @@ +package com.earth2me.essentials.signs; + +import com.earth2me.essentials.*; +import static com.earth2me.essentials.I18n.tl; +import java.util.Locale; +import net.ess3.api.IEssentials; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; + + +public class SignEnchant extends EssentialsSign +{ + public SignEnchant() + { + super("Enchant"); + } + + @Override + protected boolean onSignCreate(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException, ChargeException + { + final ItemStack stack; + try + { + stack = sign.getLine(1).equals("*") || sign.getLine(1).equalsIgnoreCase("any") ? null : getItemStack(sign.getLine(1), 1, ess); + } + catch (SignException e) + { + sign.setLine(1, "§c"); + throw e; + } + final String[] enchantLevel = sign.getLine(2).split(":"); + if (enchantLevel.length != 2) + { + sign.setLine(2, "§c"); + throw new SignException(tl("invalidSignLine", 3)); + } + final Enchantment enchantment = Enchantments.getByName(enchantLevel[0]); + if (enchantment == null) + { + sign.setLine(2, "§c"); + throw new SignException(tl("enchantmentNotFound")); + } + int level; + try + { + level = Integer.parseInt(enchantLevel[1]); + } + catch (NumberFormatException ex) + { + sign.setLine(2, "§c"); + throw new SignException(ex.getMessage(), ex); + } + final boolean allowUnsafe = ess.getSettings().allowUnsafeEnchantments() + && player.isAuthorized("essentials.enchantments.allowunsafe") && player.isAuthorized("essentials.signs.enchant.allowunsafe"); + if (level < 0 || (!allowUnsafe && level > enchantment.getMaxLevel())) + { + level = enchantment.getMaxLevel(); + sign.setLine(2, enchantLevel[0] + ":" + level); + } + try + { + if (stack != null) + { + if (allowUnsafe) + { + stack.addUnsafeEnchantment(enchantment, level); + } + else + { + stack.addEnchantment(enchantment, level); + } + } + } + catch (Throwable ex) + { + throw new SignException(ex.getMessage(), ex); + } + getTrade(sign, 3, ess); + return true; + } + + @Override + protected boolean onSignInteract(ISign sign, User player, String username, IEssentials ess) throws SignException, ChargeException + { + final ItemStack search = sign.getLine(1).equals("*") || sign.getLine(1).equalsIgnoreCase("any") ? null : getItemStack(sign.getLine(1), 1, ess); + final Trade charge = getTrade(sign, 3, ess); + charge.isAffordableFor(player); + final String[] enchantLevel = sign.getLine(2).split(":"); + if (enchantLevel.length != 2) + { + throw new SignException(tl("invalidSignLine", 3)); + } + final Enchantment enchantment = Enchantments.getByName(enchantLevel[0]); + if (enchantment == null) + { + throw new SignException(tl("enchantmentNotFound")); + } + int level; + try + { + level = Integer.parseInt(enchantLevel[1]); + } + catch (NumberFormatException ex) + { + level = enchantment.getMaxLevel(); + } + + final ItemStack playerHand = player.getBase().getItemInHand(); + if (playerHand == null + || playerHand.getAmount() != 1 + || (playerHand.containsEnchantment(enchantment) + && playerHand.getEnchantmentLevel(enchantment) == level)) + { + throw new SignException(tl("missingItems", 1, sign.getLine(1))); + } + if (search != null && playerHand.getType() != search.getType()) + { + throw new SignException(tl("missingItems", 1, search.getType().toString().toLowerCase(Locale.ENGLISH).replace('_', ' '))); + } + + final ItemStack toEnchant = playerHand; + try + { + if (level == 0) + { + toEnchant.removeEnchantment(enchantment); + } + else + { + if (ess.getSettings().allowUnsafeEnchantments() && player.isAuthorized("essentials.signs.enchant.allowunsafe")) + { + toEnchant.addUnsafeEnchantment(enchantment, level); + } + else + { + toEnchant.addEnchantment(enchantment, level); + } + } + } + catch (Exception ex) + { + throw new SignException(ex.getMessage(), ex); + } + + final String enchantmentName = enchantment.getName().toLowerCase(Locale.ENGLISH); + if (level == 0) + { + player.sendMessage(tl("enchantmentRemoved", enchantmentName.replace('_', ' '))); + } + else + { + player.sendMessage(tl("enchantmentApplied", enchantmentName.replace('_', ' '))); + } + + charge.charge(player); + Trade.log("Sign", "Enchant", "Interact", username, charge, username, charge, sign.getBlock().getLocation(), ess); + player.getBase().updateInventory(); + return true; + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignEntityListener.java b/Essentials/src/com/earth2me/essentials/signs/SignEntityListener.java new file mode 100644 index 0000000000..d6753a943a --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignEntityListener.java @@ -0,0 +1,80 @@ +package com.earth2me.essentials.signs; + +import net.ess3.api.IEssentials; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityChangeBlockEvent; +import org.bukkit.event.entity.EntityExplodeEvent; + + +public class SignEntityListener implements Listener +{ + private final transient IEssentials ess; + + public SignEntityListener(final IEssentials ess) + { + this.ess = ess; + } + + @EventHandler(priority = EventPriority.LOW) + public void onSignEntityExplode(final EntityExplodeEvent event) + { + if (ess.getSettings().areSignsDisabled()) + { + event.getHandlers().unregister(this); + return; + } + + for (Block block : event.blockList()) + { + if (((block.getType() == Material.WALL_SIGN + || block.getType() == Material.SIGN_POST) + && EssentialsSign.isValidSign(new EssentialsSign.BlockSign(block))) + || EssentialsSign.checkIfBlockBreaksSigns(block)) + { + event.setCancelled(true); + return; + } + for (EssentialsSign sign : ess.getSettings().enabledSigns()) + { + if (sign.areHeavyEventRequired() && sign.getBlocks().contains(block.getType())) + { + event.setCancelled(!sign.onBlockExplode(block, ess)); + return; + } + } + } + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onSignEntityChangeBlock(final EntityChangeBlockEvent event) + { + if (ess.getSettings().areSignsDisabled()) + { + event.getHandlers().unregister(this); + return; + } + + final Block block = event.getBlock(); + if (((block.getType() == Material.WALL_SIGN + || block.getType() == Material.SIGN_POST) + && EssentialsSign.isValidSign(new EssentialsSign.BlockSign(block))) + || EssentialsSign.checkIfBlockBreaksSigns(block)) + { + event.setCancelled(true); + return; + } + for (EssentialsSign sign : ess.getSettings().enabledSigns()) + { + if (sign.areHeavyEventRequired() && sign.getBlocks().contains(block.getType()) + && !sign.onBlockBreak(block, ess)) + { + event.setCancelled(true); + return; + } + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignException.java b/Essentials/src/com/earth2me/essentials/signs/SignException.java new file mode 100644 index 0000000000..9c9ab44a2b --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignException.java @@ -0,0 +1,15 @@ +package com.earth2me.essentials.signs; + + +public class SignException extends Exception +{ + public SignException(final String message) + { + super(message); + } + + public SignException(final String message, final Throwable throwable) + { + super(message, throwable); + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignFree.java b/Essentials/src/com/earth2me/essentials/signs/SignFree.java new file mode 100644 index 0000000000..9771d48681 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignFree.java @@ -0,0 +1,62 @@ +package com.earth2me.essentials.signs; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import net.ess3.api.IEssentials; +import org.bukkit.Material; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + + +public class SignFree extends EssentialsSign +{ + public SignFree() + { + super("Free"); + } + + @Override + protected boolean onSignCreate(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException + { + try { + ItemStack item = getItemStack(sign.getLine(1), 1, ess); + item = getItemMeta(item, sign.getLine(2), ess); + item = getItemMeta(item, sign.getLine(3), ess); + } + catch (SignException ex) + { + sign.setLine(1, "§c"); + throw new SignException(ex.getMessage(), ex); + } + return true; + } + + @Override + protected boolean onSignInteract(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException + { + ItemStack itemStack = getItemStack(sign.getLine(1), 1, ess); + itemStack = getItemMeta(itemStack, sign.getLine(2), ess); + final ItemStack item = getItemMeta(itemStack, sign.getLine(3), ess); + + if (item.getType() == Material.AIR) + { + throw new SignException(tl("cantSpawnItem", "Air")); + } + + item.setAmount(item.getType().getMaxStackSize()); + + ItemMeta meta = item.getItemMeta(); + + final String displayName = meta.hasDisplayName() ? meta.getDisplayName() : item.getType().toString(); + + Inventory invent = ess.getServer().createInventory(player.getBase(), 36, displayName); + for (int i = 0; i < 36; i++) { + invent.addItem(item); + } + player.getBase().openInventory(invent); + Trade.log("Sign", "Free", "Interact", username, null, username, new Trade(item, ess), sign.getBlock().getLocation(), ess); + return true; + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignGameMode.java b/Essentials/src/com/earth2me/essentials/signs/SignGameMode.java new file mode 100644 index 0000000000..51580f7dec --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignGameMode.java @@ -0,0 +1,73 @@ +package com.earth2me.essentials.signs; + +import com.earth2me.essentials.ChargeException; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import java.util.Locale; +import net.ess3.api.IEssentials; +import org.bukkit.GameMode; +import org.bukkit.entity.Player; + + +public class SignGameMode extends EssentialsSign +{ + public SignGameMode() + { + super("GameMode"); + } + + @Override + protected boolean onSignCreate(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException + { + final String gamemode = sign.getLine(1); + if (gamemode.isEmpty()) + { + sign.setLine(1, "Survival"); + } + + validateTrade(sign, 2, ess); + + return true; + } + + @Override + protected boolean onSignInteract(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException, ChargeException + { + final Trade charge = getTrade(sign, 2, ess); + final String mode = sign.getLine(1).trim(); + + if (mode.isEmpty()) + { + throw new SignException(tl("invalidSignLine", 2)); + } + + charge.isAffordableFor(player); + + performSetMode(mode.toLowerCase(Locale.ENGLISH), player.getBase()); + player.sendMessage(tl("gameMode", tl(player.getBase().getGameMode().toString().toLowerCase(Locale.ENGLISH)), player.getDisplayName())); + Trade.log("Sign", "gameMode", "Interact", username, null, username, charge, sign.getBlock().getLocation(), ess); + charge.charge(player); + return true; + } + + private void performSetMode(String mode, Player player) throws SignException + { + if (mode.contains("survi") || mode.equalsIgnoreCase("0")) + { + player.setGameMode(GameMode.SURVIVAL); + } + else if (mode.contains("creat") || mode.equalsIgnoreCase("1")) + { + player.setGameMode(GameMode.CREATIVE); + } + else if (mode.contains("advent") || mode.equalsIgnoreCase("2")) + { + player.setGameMode(GameMode.ADVENTURE); + } + else + { + throw new SignException(tl("invalidSignLine", 2)); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignHeal.java b/Essentials/src/com/earth2me/essentials/signs/SignHeal.java new file mode 100644 index 0000000000..9f19d29684 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignHeal.java @@ -0,0 +1,41 @@ +package com.earth2me.essentials.signs; + +import com.earth2me.essentials.ChargeException; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import net.ess3.api.IEssentials; + + +public class SignHeal extends EssentialsSign +{ + public SignHeal() + { + super("Heal"); + } + + @Override + protected boolean onSignCreate(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException + { + validateTrade(sign, 1, ess); + return true; + } + + @Override + protected boolean onSignInteract(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException, ChargeException + { + if (player.getBase().getHealth() == 0) + { + throw new SignException(tl("healDead")); + } + final Trade charge = getTrade(sign, 1, ess); + charge.isAffordableFor(player); + player.getBase().setHealth(20); + player.getBase().setFoodLevel(20); + player.getBase().setFireTicks(0); + player.sendMessage(tl("youAreHealed")); + charge.charge(player); + Trade.log("Sign", "Heal", "Interact", username, null, username, charge, sign.getBlock().getLocation(), ess); + return true; + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignInfo.java b/Essentials/src/com/earth2me/essentials/signs/SignInfo.java new file mode 100644 index 0000000000..d890b521d7 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignInfo.java @@ -0,0 +1,56 @@ +package com.earth2me.essentials.signs; + +import com.earth2me.essentials.ChargeException; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import com.earth2me.essentials.textreader.IText; +import com.earth2me.essentials.textreader.KeywordReplacer; +import com.earth2me.essentials.textreader.TextInput; +import com.earth2me.essentials.textreader.TextPager; +import java.io.IOException; +import net.ess3.api.IEssentials; + + +public class SignInfo extends EssentialsSign +{ + public SignInfo() + { + super("Info"); + } + + @Override + protected boolean onSignCreate(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException + { + validateTrade(sign, 3, ess); + return true; + } + + @Override + protected boolean onSignInteract(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException, ChargeException + { + final Trade charge = getTrade(sign, 3, ess); + charge.isAffordableFor(player); + + String chapter = sign.getLine(1); + String page = sign.getLine(2); + + final IText input; + try + { + player.setDisplayNick(); + input = new TextInput(player.getSource(), "info", true, ess); + final IText output = new KeywordReplacer(input, player.getSource(), ess); + final TextPager pager = new TextPager(output); + pager.showPage(chapter, page, null, player.getSource()); + + } + catch (IOException ex) + { + throw new SignException(ex.getMessage(), ex); + } + + charge.charge(player); + Trade.log("Sign", "Info", "Interact", username, null, username, charge, sign.getBlock().getLocation(), ess); + return true; + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignKit.java b/Essentials/src/com/earth2me/essentials/signs/SignKit.java new file mode 100644 index 0000000000..c956ef1048 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignKit.java @@ -0,0 +1,90 @@ +package com.earth2me.essentials.signs; + +import com.earth2me.essentials.*; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.commands.NoChargeException; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import net.ess3.api.IEssentials; + + +public class SignKit extends EssentialsSign +{ + public SignKit() + { + super("Kit"); + } + + @Override + protected boolean onSignCreate(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException + { + validateTrade(sign, 3, ess); + + final String kitName = sign.getLine(1).toLowerCase(Locale.ENGLISH).trim(); + + if (kitName.isEmpty()) + { + sign.setLine(1, "§dKit name!"); + return false; + } + else + { + try + { + ess.getSettings().getKit(kitName); + } + catch (Exception ex) + { + throw new SignException(ex.getMessage(), ex); + } + final String group = sign.getLine(2); + if ("Everyone".equalsIgnoreCase(group) || "Everybody".equalsIgnoreCase(group)) + { + sign.setLine(2, "§2Everyone"); + } + return true; + } + } + + @Override + protected boolean onSignInteract(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException, ChargeException + { + final String kitName = sign.getLine(1).toLowerCase(Locale.ENGLISH).trim(); + final String group = sign.getLine(2).trim(); + if ((!group.isEmpty() && ("§2Everyone".equals(group) || player.inGroup(group))) + || (group.isEmpty() && (player.isAuthorized("essentials.kits." + kitName)))) + { + final Trade charge = getTrade(sign, 3, ess); + charge.isAffordableFor(player); + try + { + final Kit kit = new Kit(kitName, ess); + kit.checkDelay(player); + kit.setTime(player); + kit.expandItems(player); + + charge.charge(player); + Trade.log("Sign", "Kit", "Interact", username, null, username, charge, sign.getBlock().getLocation(), ess); + } + catch (NoChargeException ex) + { + return false; + } + catch (Exception ex) + { + throw new SignException(ex.getMessage(), ex); + } + return true; + } + else + { + if (group.isEmpty()) { + throw new SignException(tl("noKitPermission", "essentials.kits." + kitName)); + } + else { + throw new SignException(tl("noKitGroup", group)); + } + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignMail.java b/Essentials/src/com/earth2me/essentials/signs/SignMail.java new file mode 100644 index 0000000000..85f150eca7 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignMail.java @@ -0,0 +1,32 @@ +package com.earth2me.essentials.signs; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import java.util.List; +import net.ess3.api.IEssentials; + + +public class SignMail extends EssentialsSign +{ + public SignMail() + { + super("Mail"); + } + + @Override + protected boolean onSignInteract(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException + { + final List mail = player.getMails(); + if (mail.isEmpty()) + { + player.sendMessage(tl("noNewMail")); + return false; + } + for (String s : mail) + { + player.sendMessage(s); + } + player.sendMessage(tl("markMailAsRead")); + return true; + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignPlayerListener.java b/Essentials/src/com/earth2me/essentials/signs/SignPlayerListener.java new file mode 100644 index 0000000000..042c5003fa --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignPlayerListener.java @@ -0,0 +1,93 @@ +package com.earth2me.essentials.signs; + +import java.util.logging.Level; +import net.ess3.api.IEssentials; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.Sign; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; + + +public class SignPlayerListener implements Listener +{ + private final transient IEssentials ess; + + public SignPlayerListener(final IEssentials ess) + { + this.ess = ess; + } + + //This following code below listens to cancelled events to fix a bukkit issue + //Right clicking signs with a block in hand, can now fire cancelled events. + //This is because when the block place is cancelled (for example not enough space for the block to be placed), + //the event will be marked as cancelled, thus preventing 30% of sign purchases. + @EventHandler(priority = EventPriority.LOW) + public void onSignPlayerInteract(final PlayerInteractEvent event) + { + if (ess.getSettings().areSignsDisabled()) + { + event.getHandlers().unregister(this); + return; + } + if (event.getAction() != Action.RIGHT_CLICK_BLOCK && event.getAction() != Action.RIGHT_CLICK_AIR) + { + return; + } + final Block block; + if (event.isCancelled() && event.getAction() == Action.RIGHT_CLICK_AIR) + { + Block targetBlock = null; + try + { + targetBlock = event.getPlayer().getTargetBlock(null, 5); + } + catch (IllegalStateException ex) + { + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.WARNING, ex.getMessage(), ex); + } + } + block = targetBlock; + } + else + { + block = event.getClickedBlock(); + } + if (block == null) + { + return; + } + + final Material mat = block.getType(); + if (mat == Material.SIGN_POST || mat == Material.WALL_SIGN) + { + final String csign = ((Sign)block.getState()).getLine(0); + for (EssentialsSign sign : ess.getSettings().enabledSigns()) + { + if (csign.equalsIgnoreCase(sign.getSuccessName())) + { + sign.onSignInteract(block, event.getPlayer(), ess); + event.setCancelled(true); + return; + } + } + } + else + { + for (EssentialsSign sign : ess.getSettings().enabledSigns()) + { + if (sign.areHeavyEventRequired() && sign.getBlocks().contains(block.getType()) + && !sign.onBlockInteract(block, event.getPlayer(), ess)) + { + event.setCancelled(true); + return; + } + } + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignProtection.java b/Essentials/src/com/earth2me/essentials/signs/SignProtection.java new file mode 100644 index 0000000000..501782968e --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignProtection.java @@ -0,0 +1,356 @@ +package com.earth2me.essentials.signs; + +import com.earth2me.essentials.*; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Trade.OverflowType; +import com.earth2me.essentials.utils.FormatUtil; +import java.util.*; +import net.ess3.api.IEssentials; +import net.ess3.api.MaxMoneyException; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.Sign; +import org.bukkit.inventory.ItemStack; + + +@Deprecated // This sign will be removed soon +public class SignProtection extends EssentialsSign +{ + private final transient Set protectedBlocks = EnumSet.noneOf(Material.class); + + public SignProtection() + { + super("Protection"); + protectedBlocks.add(Material.CHEST); + protectedBlocks.add(Material.BURNING_FURNACE); + protectedBlocks.add(Material.FURNACE); + protectedBlocks.add(Material.DISPENSER); + } + + @Override + protected boolean onSignCreate(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException, ChargeException + { + sign.setLine(3, "§4" + username); + if (hasAdjacentBlock(sign.getBlock())) + { + final SignProtectionState state = isBlockProtected(sign.getBlock(), player, username, true); + if (state == SignProtectionState.NOSIGN || state == SignProtectionState.OWNER + || player.isAuthorized("essentials.signs.protection.override")) + { + sign.setLine(3, "§1" + username); + return true; + } + } + player.sendMessage(tl("signProtectInvalidLocation")); + return false; + } + + @Override + protected boolean onSignBreak(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException + { + final SignProtectionState state = checkProtectionSign(sign, player, username); + return state == SignProtectionState.OWNER; + } + + public boolean hasAdjacentBlock(final Block block, final Block... ignoredBlocks) + { + final Block[] faces = getAdjacentBlocks(block); + for (Block b : faces) + { + for (Block ignoredBlock : ignoredBlocks) + { + if (b.getLocation().equals(ignoredBlock.getLocation())) + { + //TODO: What? + } + } + if (protectedBlocks.contains(b.getType())) + { + return true; + } + } + return false; + } + + private void checkIfSignsAreBroken(final Block block, final User player, final String username, final IEssentials ess) throws MaxMoneyException + { + final Map signs = getConnectedSigns(block, player, username, false); + for (Map.Entry entry : signs.entrySet()) + { + if (entry.getValue() != SignProtectionState.NOSIGN) + { + final Block sign = entry.getKey().getBlock(); + if (!hasAdjacentBlock(sign, block)) + { + block.setType(Material.AIR); + final Trade trade = new Trade(new ItemStack(Material.SIGN, 1), ess); + trade.pay(player, OverflowType.DROP); + } + } + } + } + + private Map getConnectedSigns(final Block block, final User user, final String username, boolean secure) + { + final Map signs = new HashMap(); + getConnectedSigns(block, signs, user, username, secure ? 4 : 2); + return signs; + } + + private void getConnectedSigns(final Block block, final Map signs, final User user, final String username, final int depth) + { + final Block[] faces = getAdjacentBlocks(block); + for (Block b : faces) + { + final Location loc = b.getLocation(); + if (signs.containsKey(loc)) + { + continue; + } + final SignProtectionState check = checkProtectionSign(b, user, username); + signs.put(loc, check); + + if (protectedBlocks.contains(b.getType()) && depth > 0) + { + getConnectedSigns(b, signs, user, username, depth - 1); + } + } + } + + private SignProtectionState checkProtectionSign(final Block block, final User user, final String username) + { + if (block.getType() == Material.SIGN_POST || block.getType() == Material.WALL_SIGN) + { + final BlockSign sign = new BlockSign(block); + if (sign.getLine(0).equals(this.getSuccessName())) + { + return checkProtectionSign(sign, user, username); + } + } + return SignProtectionState.NOSIGN; + } + + private SignProtectionState checkProtectionSign(final ISign sign, final User user, final String username) + { + if (user == null || username == null) + { + return SignProtectionState.NOT_ALLOWED; + } + if (user.isAuthorized("essentials.signs.protection.override")) + { + return SignProtectionState.OWNER; + } + if (FormatUtil.stripFormat(sign.getLine(3)).equalsIgnoreCase(username)) + { + return SignProtectionState.OWNER; + } + for (int i = 1; i <= 2; i++) + { + final String line = sign.getLine(i); + if (line.startsWith("(") && line.endsWith(")") && user.inGroup(line.substring(1, line.length() - 1))) + { + return SignProtectionState.ALLOWED; + } + else if (line.equalsIgnoreCase(username)) + { + return SignProtectionState.ALLOWED; + } + } + return SignProtectionState.NOT_ALLOWED; + } + + private Block[] getAdjacentBlocks(final Block block) + { + return new Block[] + { + block.getRelative(BlockFace.NORTH), + block.getRelative(BlockFace.SOUTH), + block.getRelative(BlockFace.EAST), + block.getRelative(BlockFace.WEST), + block.getRelative(BlockFace.DOWN), + block.getRelative(BlockFace.UP) + }; + } + + public SignProtectionState isBlockProtected(final Block block, final User user, final String username, boolean secure) + { + final Map signs = getConnectedSigns(block, user, username, secure); + SignProtectionState retstate = SignProtectionState.NOSIGN; + for (SignProtectionState state : signs.values()) + { + if (state == SignProtectionState.ALLOWED) + { + retstate = state; + } + else if (state == SignProtectionState.NOT_ALLOWED && retstate != SignProtectionState.ALLOWED) + { + retstate = state; + } + } + if (!secure || retstate == SignProtectionState.NOSIGN) + { + for (SignProtectionState state : signs.values()) + { + if (state == SignProtectionState.OWNER) + { + return state; + } + } + } + return retstate; + } + + public boolean isBlockProtected(final Block block) + { + final Block[] faces = getAdjacentBlocks(block); + for (Block b : faces) + { + if (b.getType() == Material.SIGN_POST || b.getType() == Material.WALL_SIGN) + { + final Sign sign = (Sign)b.getState(); + if (sign.getLine(0).equalsIgnoreCase("§1[Protection]")) + { + return true; + } + } + if (protectedBlocks.contains(b.getType())) + { + final Block[] faceChest = getAdjacentBlocks(b); + + for (Block a : faceChest) + { + if (a.getType() == Material.SIGN_POST || a.getType() == Material.WALL_SIGN) + { + final Sign sign = (Sign)a.getState(); + if (sign.getLine(0).equalsIgnoreCase("§1[Protection]")) + { + return true; + } + } + } + } + } + return false; + } + + @Override + public Set getBlocks() + { + return protectedBlocks; + } + + @Override + public boolean areHeavyEventRequired() + { + return true; + } + + @Override + protected boolean onBlockPlace(final Block block, final User player, final String username, final IEssentials ess) throws SignException + { + for (Block adjBlock : getAdjacentBlocks(block)) + { + final SignProtectionState state = isBlockProtected(adjBlock, player, username, true); + + if ((state == SignProtectionState.ALLOWED || state == SignProtectionState.NOT_ALLOWED) + && !player.isAuthorized("essentials.signs.protection.override")) + { + player.sendMessage(tl("noPlacePermission", block.getType().toString().toLowerCase(Locale.ENGLISH))); + return false; + } + } + return true; + + } + + @Override + protected boolean onBlockInteract(final Block block, final User player, final String username, final IEssentials ess) throws SignException + { + final SignProtectionState state = isBlockProtected(block, player, username, false); + + if (state == SignProtectionState.OWNER || state == SignProtectionState.NOSIGN || state == SignProtectionState.ALLOWED) + { + return true; + } + + if (state == SignProtectionState.NOT_ALLOWED + && player.isAuthorized("essentials.signs.protection.override")) + { + return true; + } + + + player.sendMessage(tl("noAccessPermission", block.getType().toString().toLowerCase(Locale.ENGLISH))); + return false; + } + + @Override + protected boolean onBlockBreak(final Block block, final User player, final String username, final IEssentials ess) throws SignException, MaxMoneyException + { + final SignProtectionState state = isBlockProtected(block, player, username, false); + + if (state == SignProtectionState.OWNER || state == SignProtectionState.NOSIGN) + { + checkIfSignsAreBroken(block, player, username, ess); + return true; + } + + if ((state == SignProtectionState.ALLOWED || state == SignProtectionState.NOT_ALLOWED) + && player.isAuthorized("essentials.signs.protection.override")) + { + checkIfSignsAreBroken(block, player, username, ess); + return true; + } + + + player.sendMessage(tl("noDestroyPermission", block.getType().toString().toLowerCase(Locale.ENGLISH))); + return false; + } + + @Override + public boolean onBlockBreak(final Block block, final IEssentials ess) + { + final SignProtectionState state = isBlockProtected(block, null, null, false); + + return state == SignProtectionState.NOSIGN; + } + + @Override + public boolean onBlockExplode(final Block block, final IEssentials ess) + { + final SignProtectionState state = isBlockProtected(block, null, null, false); + + return state == SignProtectionState.NOSIGN; + } + + @Override + public boolean onBlockBurn(final Block block, final IEssentials ess) + { + final SignProtectionState state = isBlockProtected(block, null, null, false); + + return state == SignProtectionState.NOSIGN; + } + + @Override + public boolean onBlockIgnite(final Block block, final IEssentials ess) + { + final SignProtectionState state = isBlockProtected(block, null, null, false); + + return state == SignProtectionState.NOSIGN; + } + + @Override + public boolean onBlockPush(final Block block, final IEssentials ess) + { + final SignProtectionState state = isBlockProtected(block, null, null, false); + + return state == SignProtectionState.NOSIGN; + } + + public enum SignProtectionState + { + NOT_ALLOWED, ALLOWED, NOSIGN, OWNER + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignRepair.java b/Essentials/src/com/earth2me/essentials/signs/SignRepair.java new file mode 100644 index 0000000000..91c4a4314f --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignRepair.java @@ -0,0 +1,70 @@ +package com.earth2me.essentials.signs; + +import com.earth2me.essentials.ChargeException; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import com.earth2me.essentials.commands.Commandrepair; +import com.earth2me.essentials.commands.NotEnoughArgumentsException; +import net.ess3.api.IEssentials; + + +public class SignRepair extends EssentialsSign +{ + public SignRepair() + { + super("Repair"); + } + + @Override + protected boolean onSignCreate(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException + { + final String repairTarget = sign.getLine(1); + if (repairTarget.isEmpty()) + { + sign.setLine(1, "Hand"); + } + else if (!repairTarget.equalsIgnoreCase("all") && !repairTarget.equalsIgnoreCase("hand")) + { + sign.setLine(1, "§c"); + throw new SignException(tl("invalidSignLine", 2)); + } + validateTrade(sign, 2, ess); + return true; + } + + @Override + protected boolean onSignInteract(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException, ChargeException + { + final Trade charge = getTrade(sign, 2, ess); + charge.isAffordableFor(player); + + Commandrepair command = new Commandrepair(); + command.setEssentials(ess); + + try + { + if (sign.getLine(1).equalsIgnoreCase("hand")) + { + command.repairHand(player); + } + else if (sign.getLine(1).equalsIgnoreCase("all")) + { + command.repairAll(player); + } + else + { + throw new NotEnoughArgumentsException(); + } + + } + catch (Exception ex) + { + throw new SignException(ex.getMessage(), ex); + } + + charge.charge(player); + Trade.log("Sign", "Repair", "Interact", username, null, username, charge, sign.getBlock().getLocation(), ess); + return true; + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignSell.java b/Essentials/src/com/earth2me/essentials/signs/SignSell.java new file mode 100644 index 0000000000..45fee196ea --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignSell.java @@ -0,0 +1,37 @@ +package com.earth2me.essentials.signs; + +import com.earth2me.essentials.ChargeException; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.Trade.OverflowType; +import com.earth2me.essentials.User; +import net.ess3.api.IEssentials; +import net.ess3.api.MaxMoneyException; + + +public class SignSell extends EssentialsSign +{ + public SignSell() + { + super("Sell"); + } + + @Override + protected boolean onSignCreate(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException + { + validateTrade(sign, 1, 2, player, ess); + validateTrade(sign, 3, ess); + return true; + } + + @Override + protected boolean onSignInteract(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException, ChargeException, MaxMoneyException + { + final Trade charge = getTrade(sign, 1, 2, player, ess); + final Trade money = getTrade(sign, 3, ess); + charge.isAffordableFor(player); + money.pay(player, OverflowType.DROP); + charge.charge(player); + Trade.log("Sign", "Sell", "Interact", username, charge, username, money, sign.getBlock().getLocation(), ess); + return true; + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignSpawnmob.java b/Essentials/src/com/earth2me/essentials/signs/SignSpawnmob.java new file mode 100644 index 0000000000..4916d131b6 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignSpawnmob.java @@ -0,0 +1,44 @@ +package com.earth2me.essentials.signs; + +import com.earth2me.essentials.*; +import java.util.List; +import net.ess3.api.IEssentials; + + +public class SignSpawnmob extends EssentialsSign +{ + public SignSpawnmob() + { + super("Spawnmob"); + } + + @Override + protected boolean onSignCreate(ISign sign, User player, String username, IEssentials ess) throws SignException, ChargeException + { + validateInteger(sign, 1); + validateTrade(sign, 3, ess); + return true; + } + + @Override + protected boolean onSignInteract(ISign sign, User player, String username, IEssentials ess) throws SignException, ChargeException + { + final Trade charge = getTrade(sign, 3, ess); + charge.isAffordableFor(player); + + try + { + List mobParts = SpawnMob.mobParts(sign.getLine(2)); + List mobData = SpawnMob.mobData(sign.getLine(2)); + SpawnMob.spawnmob(ess, ess.getServer(), player.getSource(), player, mobParts, mobData, Integer.parseInt(sign.getLine(1))); + } + catch (Exception ex) + { + throw new SignException(ex.getMessage(), ex); + } + + charge.charge(player); + Trade.log("Sign", "Spawnmob", "Interact", username, null, username, charge, sign.getBlock().getLocation(), ess); + return true; + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignTime.java b/Essentials/src/com/earth2me/essentials/signs/SignTime.java new file mode 100644 index 0000000000..2f6390f7ad --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignTime.java @@ -0,0 +1,59 @@ +package com.earth2me.essentials.signs; + +import com.earth2me.essentials.ChargeException; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import net.ess3.api.IEssentials; + + +public class SignTime extends EssentialsSign +{ + public SignTime() + { + super("Time"); + } + + @Override + protected boolean onSignCreate(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException + { + validateTrade(sign, 2, ess); + final String timeString = sign.getLine(1); + if ("Day".equalsIgnoreCase(timeString)) + { + sign.setLine(1, "§2Day"); + return true; + } + if ("Night".equalsIgnoreCase(timeString)) + { + sign.setLine(1, "§2Night"); + return true; + } + throw new SignException(tl("onlyDayNight")); + } + + @Override + protected boolean onSignInteract(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException, ChargeException + { + final Trade charge = getTrade(sign, 2, ess); + charge.isAffordableFor(player); + final String timeString = sign.getLine(1); + long time = player.getWorld().getTime(); + time -= time % 24000; + if ("§2Day".equalsIgnoreCase(timeString)) + { + player.getWorld().setTime(time + 24000); + charge.charge(player); + Trade.log("Sign", "TimeDay", "Interact", username, null, username, charge, sign.getBlock().getLocation(), ess); + return true; + } + if ("§2Night".equalsIgnoreCase(timeString)) + { + player.getWorld().setTime(time + 37700); + charge.charge(player); + Trade.log("Sign", "TimeNight", "Interact", username, null, username, charge, sign.getBlock().getLocation(), ess); + return true; + } + throw new SignException(tl("onlyDayNight")); + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignTrade.java b/Essentials/src/com/earth2me/essentials/signs/SignTrade.java new file mode 100644 index 0000000000..59910cb4d4 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignTrade.java @@ -0,0 +1,442 @@ +package com.earth2me.essentials.signs; + +import com.earth2me.essentials.*; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Trade.OverflowType; +import com.earth2me.essentials.Trade.TradeType; +import com.earth2me.essentials.utils.NumberUtil; +import java.math.BigDecimal; +import java.util.Map; +import net.ess3.api.IEssentials; +import net.ess3.api.MaxMoneyException; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +//TODO: TL exceptions +public class SignTrade extends EssentialsSign +{ + public SignTrade() + { + super("Trade"); + } + + @Override + protected boolean onSignCreate(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException, ChargeException + { + validateTrade(sign, 1, false, ess); + validateTrade(sign, 2, true, ess); + final Trade trade = getTrade(sign, 2, AmountType.ROUNDED, true, ess); + final Trade charge = getTrade(sign, 1, AmountType.ROUNDED, false, ess); + if (trade.getType() == charge.getType() + && (trade.getType() != TradeType.ITEM || trade.getItemStack().isSimilar(charge.getItemStack()))) + { + throw new SignException("You cannot trade for the same item type."); + } + trade.isAffordableFor(player); + sign.setLine(3, "§8" + username); + trade.charge(player); + Trade.log("Sign", "Trade", "Create", username, trade, username, null, sign.getBlock().getLocation(), ess); + return true; + } + + @Override + protected boolean onSignInteract(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException, ChargeException, MaxMoneyException + { + if (sign.getLine(3).substring(2).equalsIgnoreCase(username)) + { + final Trade store = rechargeSign(sign, ess, player); + Trade stored; + try + { + stored = getTrade(sign, 1, AmountType.TOTAL, true, ess); + subtractAmount(sign, 1, stored, ess); + + Map withdraw = stored.pay(player, OverflowType.RETURN); + + if (withdraw == null) + { + Trade.log("Sign", "Trade", "Withdraw", username, store, username, null, sign.getBlock().getLocation(), ess); + } + else + { + setAmount(sign, 1, BigDecimal.valueOf(withdraw.get(0).getAmount()), ess); + Trade.log("Sign", "Trade", "Withdraw", username, stored, username, new Trade(withdraw.get(0), ess), sign.getBlock().getLocation(), ess); + } + } + catch (SignException e) + { + if (store == null) + { + throw new SignException(tl("tradeSignEmptyOwner"), e); + } + } + Trade.log("Sign", "Trade", "Deposit", username, store, username, null, sign.getBlock().getLocation(), ess); + } + else + { + final Trade charge = getTrade(sign, 1, AmountType.COST, false, ess); + final Trade trade = getTrade(sign, 2, AmountType.COST, true, ess); + charge.isAffordableFor(player); + addAmount(sign, 1, charge, ess); + subtractAmount(sign, 2, trade, ess); + if (!trade.pay(player)) + { + subtractAmount(sign, 1, charge, ess); + addAmount(sign, 2, trade, ess); + throw new ChargeException("Full inventory"); + } + charge.charge(player); + Trade.log("Sign", "Trade", "Interact", sign.getLine(3), charge, username, trade, sign.getBlock().getLocation(), ess); + } + sign.updateSign(); + return true; + } + + private Trade rechargeSign(final ISign sign, final IEssentials ess, final User player) throws SignException, ChargeException + { + final Trade trade = getTrade(sign, 2, AmountType.COST, false, ess); + if (trade.getItemStack() != null && player.getBase().getItemInHand() != null + && trade.getItemStack().getType() == player.getBase().getItemInHand().getType() + && trade.getItemStack().getDurability() == player.getBase().getItemInHand().getDurability() + && trade.getItemStack().getEnchantments().equals(player.getBase().getItemInHand().getEnchantments())) + { + int amount = player.getBase().getItemInHand().getAmount(); + amount -= amount % trade.getItemStack().getAmount(); + if (amount > 0) + { + final ItemStack stack = player.getBase().getItemInHand().clone(); + stack.setAmount(amount); + final Trade store = new Trade(stack, ess); + addAmount(sign, 2, store, ess); + store.charge(player); + return store; + } + } + return null; + } + + @Override + protected boolean onSignBreak(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException, MaxMoneyException + { + final String signOwner = sign.getLine(3); + + final boolean isOwner = (signOwner.length() > 3 && signOwner.substring(2).equalsIgnoreCase(username)); + final boolean canBreak = isOwner ? true : player.isAuthorized("essentials.signs.trade.override"); + final boolean canCollect = isOwner ? true : player.isAuthorized("essentials.signs.trade.override.collect"); + + if (canBreak) + { + try + { + final Trade stored1 = getTrade(sign, 1, AmountType.TOTAL, false, ess); + final Trade stored2 = getTrade(sign, 2, AmountType.TOTAL, false, ess); + + if (!canCollect) + { + Trade.log("Sign", "Trade", "Destroy", signOwner, stored2, username, stored1, sign.getBlock().getLocation(), ess); + return true; + } + + final Map withdraw1 = stored1.pay(player, OverflowType.RETURN); + final Map withdraw2 = stored2.pay(player, OverflowType.RETURN); + + if (withdraw1 == null && withdraw2 == null) + { + Trade.log("Sign", "Trade", "Break", signOwner, stored2, username, stored1, sign.getBlock().getLocation(), ess); + return true; + } + + setAmount(sign, 1, BigDecimal.valueOf(withdraw1 == null ? 0L : withdraw1.get(0).getAmount()), ess); + Trade.log("Sign", "Trade", "Withdraw", signOwner, stored1, username, withdraw1 == null ? null : new Trade(withdraw1.get(0), ess), sign.getBlock().getLocation(), ess); + + setAmount(sign, 2, BigDecimal.valueOf(withdraw2 == null ? 0L : withdraw2.get(0).getAmount()), ess); + Trade.log("Sign", "Trade", "Withdraw", signOwner, stored2, username, withdraw2 == null ? null : new Trade(withdraw2.get(0), ess), sign.getBlock().getLocation(), ess); + + sign.updateSign(); + } + catch (SignException e) + { + if (player.isAuthorized("essentials.signs.trade.override")) + { + return true; + } + throw e; + } + return false; + } + else + { + return false; + } + } + + protected final void validateTrade(final ISign sign, final int index, final boolean amountNeeded, final IEssentials ess) throws SignException + { + final String line = sign.getLine(index).trim(); + if (line.isEmpty()) + { + throw new SignException("Empty line"); + } + final String[] split = line.split("[ :]+"); + + if (split.length == 1 && !amountNeeded) + { + final BigDecimal money = getMoney(split[0]); + if (money != null) + { + if (NumberUtil.shortCurrency(money, ess).length() * 2 > 15) + { + throw new SignException("Line can be too long!"); + } + sign.setLine(index, NumberUtil.shortCurrency(money, ess) + ":0"); + return; + } + } + + if (split.length == 2 && amountNeeded) + { + final BigDecimal money = getMoney(split[0]); + BigDecimal amount = getBigDecimalPositive(split[1]); + if (money != null && amount != null) + { + amount = amount.subtract(amount.remainder(money)); + if (amount.compareTo(MINTRANSACTION) < 0 || money.compareTo(MINTRANSACTION) < 0) + { + throw new SignException(tl("moreThanZero")); + } + sign.setLine(index, NumberUtil.shortCurrency(money, ess) + ":" + NumberUtil.shortCurrency(amount, ess).substring(1)); + return; + } + } + + if (split.length == 2 && !amountNeeded) + { + final int amount = getIntegerPositive(split[0]); + + if (amount < 1) + { + throw new SignException(tl("moreThanZero")); + } + if (!(split[1].equalsIgnoreCase("exp") || split[1].equalsIgnoreCase("xp")) + && getItemStack(split[1], amount, ess).getType() == Material.AIR) + { + throw new SignException(tl("moreThanZero")); + } + String newline = amount + " " + split[1] + ":0"; + if ((newline + amount).length() > 15) + { + throw new SignException("Line can be too long!"); + } + sign.setLine(index, newline); + return; + } + + if (split.length == 3 && amountNeeded) + { + final int stackamount = getIntegerPositive(split[0]); + int amount = getIntegerPositive(split[2]); + amount -= amount % stackamount; + if (amount < 1 || stackamount < 1) + { + throw new SignException(tl("moreThanZero")); + } + if (!(split[1].equalsIgnoreCase("exp") || split[1].equalsIgnoreCase("xp")) + && getItemStack(split[1], stackamount, ess).getType() == Material.AIR) + { + throw new SignException(tl("moreThanZero")); + } + sign.setLine(index, stackamount + " " + split[1] + ":" + amount); + return; + } + throw new SignException(tl("invalidSignLine", index + 1)); + } + + protected final Trade getTrade(final ISign sign, final int index, final AmountType amountType, final boolean notEmpty, final IEssentials ess) throws SignException + { + final String line = sign.getLine(index).trim(); + if (line.isEmpty()) + { + throw new SignException("Empty line"); + } + final String[] split = line.split("[ :]+"); + + if (split.length == 2) + { + try + { + final BigDecimal money = getMoney(split[0]); + final BigDecimal amount = notEmpty ? getBigDecimalPositive(split[1]) : getBigDecimal(split[1]); + if (money != null && amount != null) + { + return new Trade(amountType == AmountType.COST ? money : amount, ess); + } + } + catch (SignException e) + { + throw new SignException(tl("tradeSignEmpty"), e); + } + } + + if (split.length == 3) + { + if (split[1].equalsIgnoreCase("exp") || split[1].equalsIgnoreCase("xp")) + { + final int stackamount = getIntegerPositive(split[0]); + int amount = getInteger(split[2]); + if (amountType == AmountType.ROUNDED) + { + amount -= amount % stackamount; + } + if (notEmpty && (amount < 1 || stackamount < 1)) + { + throw new SignException(tl("tradeSignEmpty")); + } + return new Trade((amountType == AmountType.COST ? stackamount : amount), ess); + } + else + { + final int stackamount = getIntegerPositive(split[0]); + final ItemStack item = getItemStack(split[1], stackamount, ess); + int amount = getInteger(split[2]); + if (amountType == AmountType.ROUNDED) + { + amount -= amount % stackamount; + } + if (notEmpty && (amount < 1 || stackamount < 1 || item.getType() == Material.AIR || amount < stackamount)) + { + throw new SignException(tl("tradeSignEmpty")); + } + item.setAmount(amountType == AmountType.COST ? stackamount : amount); + return new Trade(item, ess); + } + } + throw new SignException(tl("invalidSignLine", index + 1)); + } + + protected final void subtractAmount(final ISign sign, final int index, final Trade trade, final IEssentials ess) throws SignException + { + final BigDecimal money = trade.getMoney(); + if (money != null) + { + changeAmount(sign, index, money.negate(), ess); + } + final ItemStack item = trade.getItemStack(); + if (item != null) + { + changeAmount(sign, index, BigDecimal.valueOf(-item.getAmount()), ess); + } + final Integer exp = trade.getExperience(); + if (exp != null) + { + changeAmount(sign, index, BigDecimal.valueOf(-exp.intValue()), ess); + } + } + + protected final void addAmount(final ISign sign, final int index, final Trade trade, final IEssentials ess) throws SignException + { + final BigDecimal money = trade.getMoney(); + if (money != null) + { + changeAmount(sign, index, money, ess); + } + final ItemStack item = trade.getItemStack(); + if (item != null) + { + changeAmount(sign, index, BigDecimal.valueOf(item.getAmount()), ess); + } + final Integer exp = trade.getExperience(); + if (exp != null) + { + changeAmount(sign, index, BigDecimal.valueOf(exp.intValue()), ess); + } + } + + //TODO: Translate these exceptions. + private void changeAmount(final ISign sign, final int index, final BigDecimal value, final IEssentials ess) throws SignException + { + final String line = sign.getLine(index).trim(); + if (line.isEmpty()) + { + throw new SignException("Empty line"); + } + final String[] split = line.split("[ :]+"); + + if (split.length == 2) + { + final BigDecimal amount = getBigDecimal(split[1]).add(value); + setAmount(sign, index, amount, ess); + return; + } + if (split.length == 3) + { + final BigDecimal amount = getBigDecimal(split[2]).add(value); + setAmount(sign, index, amount, ess); + return; + } + throw new SignException(tl("invalidSignLine", index + 1)); + } + + //TODO: Translate these exceptions. + private void setAmount(final ISign sign, final int index, final BigDecimal value, final IEssentials ess) throws SignException + { + + final String line = sign.getLine(index).trim(); + if (line.isEmpty()) + { + throw new SignException("Empty line"); + } + final String[] split = line.split("[ :]+"); + + if (split.length == 2) + { + final BigDecimal money = getMoney(split[0]); + final BigDecimal amount = getBigDecimal(split[1]); + if (money != null && amount != null) + { + final String newline = NumberUtil.shortCurrency(money, ess) + ":" + NumberUtil.shortCurrency(value, ess).substring(1); + if (newline.length() > 15) + { + throw new SignException("This sign is full: Line too long!"); + } + sign.setLine(index, newline); + return; + } + } + + if (split.length == 3) + { + if (split[1].equalsIgnoreCase("exp") || split[1].equalsIgnoreCase("xp")) + { + final int stackamount = getIntegerPositive(split[0]); + final String newline = stackamount + " " + split[1] + ":" + (value.intValueExact()); + if (newline.length() > 15) + { + throw new SignException("This sign is full: Line too long!"); + } + sign.setLine(index, newline); + return; + } + else + { + final int stackamount = getIntegerPositive(split[0]); + getItemStack(split[1], stackamount, ess); + final String newline = stackamount + " " + split[1] + ":" + (value.intValueExact()); + if (newline.length() > 15) + { + throw new SignException("This sign is full: Line too long!"); + } + sign.setLine(index, newline); + return; + } + } + throw new SignException(tl("invalidSignLine", index + 1)); + } + + + public enum AmountType + { + TOTAL, + ROUNDED, + COST + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignWarp.java b/Essentials/src/com/earth2me/essentials/signs/SignWarp.java new file mode 100644 index 0000000000..2281ec6501 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignWarp.java @@ -0,0 +1,72 @@ +package com.earth2me.essentials.signs; + +import com.earth2me.essentials.ChargeException; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import net.ess3.api.IEssentials; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + + +public class SignWarp extends EssentialsSign +{ + public SignWarp() + { + super("Warp"); + } + + @Override + protected boolean onSignCreate(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException + { + validateTrade(sign, 3, ess); + final String warpName = sign.getLine(1); + + if (warpName.isEmpty()) + { + sign.setLine(1, "§c"); + throw new SignException(tl("invalidSignLine", 1)); + } + else + { + try + { + ess.getWarps().getWarp(warpName); + } + catch (Exception ex) + { + throw new SignException(ex.getMessage(), ex); + } + final String group = sign.getLine(2); + if ("Everyone".equalsIgnoreCase(group) || "Everybody".equalsIgnoreCase(group)) + { + sign.setLine(2, "§2Everyone"); + } + return true; + } + } + + @Override + protected boolean onSignInteract(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException, ChargeException + { + final String warpName = sign.getLine(1); + final String group = sign.getLine(2); + if ((!group.isEmpty() + && ("§2Everyone".equals(group) + || player.inGroup(group))) + || (group.isEmpty() && (!ess.getSettings().getPerWarpPermission() || player.isAuthorized("essentials.warps." + warpName)))) + { + final Trade charge = getTrade(sign, 3, ess); + try + { + player.getTeleport().warp(player, warpName, charge, TeleportCause.PLUGIN); + Trade.log("Sign", "Warp", "Interact", username, null, username, charge, sign.getBlock().getLocation(), ess); + } + catch (Exception ex) + { + throw new SignException(ex.getMessage(), ex); + } + return true; + } + return false; + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignWeather.java b/Essentials/src/com/earth2me/essentials/signs/SignWeather.java new file mode 100644 index 0000000000..910adeb328 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignWeather.java @@ -0,0 +1,58 @@ +package com.earth2me.essentials.signs; + +import com.earth2me.essentials.ChargeException; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import net.ess3.api.IEssentials; + + +public class SignWeather extends EssentialsSign +{ + public SignWeather() + { + super("Weather"); + } + + @Override + protected boolean onSignCreate(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException + { + validateTrade(sign, 2, ess); + final String timeString = sign.getLine(1); + if ("Sun".equalsIgnoreCase(timeString)) + { + sign.setLine(1, "§2Sun"); + return true; + } + if ("Storm".equalsIgnoreCase(timeString)) + { + sign.setLine(1, "§2Storm"); + return true; + } + sign.setLine(1, "§c"); + throw new SignException(tl("onlySunStorm")); + } + + @Override + protected boolean onSignInteract(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException, ChargeException + { + final Trade charge = getTrade(sign, 2, ess); + charge.isAffordableFor(player); + final String weatherString = sign.getLine(1); + if ("§2Sun".equalsIgnoreCase(weatherString)) + { + player.getWorld().setStorm(false); + charge.charge(player); + Trade.log("Sign", "WeatherSun", "Interact", username, null, username, charge, sign.getBlock().getLocation(), ess); + return true; + } + if ("§2Storm".equalsIgnoreCase(weatherString)) + { + player.getWorld().setStorm(true); + charge.charge(player); + Trade.log("Sign", "WeatherStorm", "Interact", username, null, username, charge, sign.getBlock().getLocation(), ess); + return true; + } + throw new SignException(tl("onlySunStorm")); + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/Signs.java b/Essentials/src/com/earth2me/essentials/signs/Signs.java new file mode 100644 index 0000000000..8076cb2a70 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/Signs.java @@ -0,0 +1,35 @@ +package com.earth2me.essentials.signs; + +//This enum is used when checking to see what signs are enabled +public enum Signs +{ + BALANCE(new SignBalance()), + BUY(new SignBuy()), + DISPOSAL(new SignDisposal()), + ENCHANT(new SignEnchant()), + FREE(new SignFree()), + GAMEMODE(new SignGameMode()), + HEAL(new SignHeal()), + INFO(new SignInfo()), + KIT(new SignKit()), + MAIL(new SignMail()), + PROTECTION(new SignProtection()), + REPAIR(new SignRepair()), + SELL(new SignSell()), + SPAWNMOB(new SignSpawnmob()), + TIME(new SignTime()), + TRADE(new SignTrade()), + WARP(new SignWarp()), + WEATHER(new SignWeather()); + private final EssentialsSign sign; + + private Signs(final EssentialsSign sign) + { + this.sign = sign; + } + + public EssentialsSign getSign() + { + return sign; + } +} diff --git a/Essentials/src/com/earth2me/essentials/storage/AbstractDelayedYamlFileReader.java b/Essentials/src/com/earth2me/essentials/storage/AbstractDelayedYamlFileReader.java new file mode 100644 index 0000000000..752a482892 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/storage/AbstractDelayedYamlFileReader.java @@ -0,0 +1,71 @@ +package com.earth2me.essentials.storage; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.logging.Level; +import net.ess3.api.IEssentials; +import org.bukkit.Bukkit; + + +public abstract class AbstractDelayedYamlFileReader implements Runnable +{ + private final transient File file; + private final transient Class clazz; + protected final transient IEssentials plugin; + + public AbstractDelayedYamlFileReader(final IEssentials ess, final File file, final Class clazz) + { + this.file = file; + this.clazz = clazz; + this.plugin = ess; + ess.runTaskAsynchronously(this); + } + + public abstract void onStart(); + + @Override + public void run() + { + onStart(); + try + { + final FileReader reader = new FileReader(file); + try + { + final T object = new YamlStorageReader(reader, plugin).load(clazz); + onSuccess(object); + } + finally + { + try + { + reader.close(); + } + catch (IOException ex) + { + Bukkit.getLogger().log(Level.SEVERE, "File can't be closed: " + file.toString(), ex); + } + } + + } + catch (FileNotFoundException ex) + { + onException(); + if (plugin.getSettings() == null || plugin.getSettings().isDebug()) + { + Bukkit.getLogger().log(Level.INFO, "File not found: " + file.toString()); + } + } + catch (ObjectLoadException ex) + { + onException(); + Bukkit.getLogger().log(Level.SEVERE, "File broken: " + file.toString(), ex.getCause()); + } + } + + public abstract void onSuccess(T object); + + public abstract void onException(); +} diff --git a/Essentials/src/com/earth2me/essentials/storage/AbstractDelayedYamlFileWriter.java b/Essentials/src/com/earth2me/essentials/storage/AbstractDelayedYamlFileWriter.java new file mode 100644 index 0000000000..cf1c1c90e3 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/storage/AbstractDelayedYamlFileWriter.java @@ -0,0 +1,54 @@ +package com.earth2me.essentials.storage; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintWriter; +import java.util.logging.Level; +import net.ess3.api.IEssentials; +import org.bukkit.Bukkit; + + +public abstract class AbstractDelayedYamlFileWriter implements Runnable +{ + private final transient File file; + + public AbstractDelayedYamlFileWriter(IEssentials ess, File file) + { + this.file = file; + ess.runTaskAsynchronously(this); + } + + public abstract StorageObject getObject(); + + @Override + public void run() + { + PrintWriter pw = null; + try + { + final StorageObject object = getObject(); + final File folder = file.getParentFile(); + if (!folder.exists()) + { + folder.mkdirs(); + } + pw = new PrintWriter(file); + new YamlStorageWriter(pw).save(object); + } + catch (FileNotFoundException ex) + { + Bukkit.getLogger().log(Level.SEVERE, file.toString(), ex); + } + finally + { + onFinish(); + if (pw != null) + { + pw.close(); + } + } + + } + + public abstract void onFinish(); +} diff --git a/Essentials/src/com/earth2me/essentials/storage/AsyncStorageObjectHolder.java b/Essentials/src/com/earth2me/essentials/storage/AsyncStorageObjectHolder.java new file mode 100644 index 0000000000..5282587e79 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/storage/AsyncStorageObjectHolder.java @@ -0,0 +1,167 @@ +package com.earth2me.essentials.storage; + +import com.earth2me.essentials.IConf; +import java.io.File; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.logging.Level; +import net.ess3.api.IEssentials; +import net.ess3.api.IReload; +import org.bukkit.Bukkit; + + +public abstract class AsyncStorageObjectHolder implements IConf, IStorageObjectHolder, IReload +{ + private transient T data; + private final transient ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); + private final transient Class clazz; + protected final transient IEssentials ess; + + public AsyncStorageObjectHolder(final IEssentials ess, final Class clazz) + { + this.ess = ess; + this.clazz = clazz; + try + { + this.data = clazz.newInstance(); + } + catch (IllegalAccessException ex) + { + Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex); + } + catch (InstantiationException ex) + { + Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex); + } + } + + @Override + public T getData() + { + return data; + } + + @Override + public void acquireReadLock() + { + rwl.readLock().lock(); + } + + @Override + public void acquireWriteLock() + { + while (rwl.getReadHoldCount() > 0) + { + rwl.readLock().unlock(); + } + rwl.writeLock().lock(); + rwl.readLock().lock(); + } + + @Override + public void close() + { + unlock(); + } + + @Override + public void unlock() + { + if (rwl.isWriteLockedByCurrentThread()) + { + rwl.writeLock().unlock(); + new StorageObjectDataWriter(); + } + while (rwl.getReadHoldCount() > 0) + { + rwl.readLock().unlock(); + } + } + + @Override + public void reloadConfig() + { + new StorageObjectDataReader(); + } + + @Override + public void onReload() + { + new StorageObjectDataReader(); + } + + public abstract void finishRead(); + + public abstract void finishWrite(); + + public abstract File getStorageFile(); + + + private class StorageObjectDataWriter extends AbstractDelayedYamlFileWriter + { + StorageObjectDataWriter() + { + super(ess, getStorageFile()); + } + + @Override + public StorageObject getObject() + { + acquireReadLock(); + return getData(); + } + + @Override + public void onFinish() + { + unlock(); + finishWrite(); + } + } + + + private class StorageObjectDataReader extends AbstractDelayedYamlFileReader + { + StorageObjectDataReader() + { + super(ess, getStorageFile(), clazz); + } + + @Override + public void onStart() + { + rwl.writeLock().lock(); + } + + @Override + public void onSuccess(final T object) + { + if (object != null) + { + data = object; + } + rwl.writeLock().unlock(); + finishRead(); + } + + @Override + public void onException() + { + if (data == null) + { + try + { + data = clazz.newInstance(); + } + catch (IllegalAccessException ex) + { + Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex); + } + catch (InstantiationException ex) + { + Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex); + } + } + rwl.writeLock().unlock(); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/storage/BukkitConstructor.java b/Essentials/src/com/earth2me/essentials/storage/BukkitConstructor.java new file mode 100644 index 0000000000..cf0a656a67 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/storage/BukkitConstructor.java @@ -0,0 +1,406 @@ +package com.earth2me.essentials.storage; + +import com.earth2me.essentials.utils.NumberUtil; +import java.lang.reflect.Field; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.material.MaterialData; +import org.bukkit.plugin.Plugin; +import org.yaml.snakeyaml.TypeDescription; +import org.yaml.snakeyaml.constructor.Constructor; +import org.yaml.snakeyaml.constructor.CustomClassLoaderConstructor; +import org.yaml.snakeyaml.error.YAMLException; +import org.yaml.snakeyaml.introspector.Property; +import org.yaml.snakeyaml.nodes.*; + + +public class BukkitConstructor extends CustomClassLoaderConstructor +{ + private final transient Plugin plugin; + + public BukkitConstructor(final Class clazz, final Plugin plugin) + { + super(clazz, plugin.getClass().getClassLoader()); + this.plugin = plugin; + yamlClassConstructors.put(NodeId.scalar, new ConstructBukkitScalar()); + yamlClassConstructors.put(NodeId.mapping, new ConstructBukkitMapping()); + } + + + private class ConstructBukkitScalar extends ConstructScalar + { + @Override + public Object construct(final Node node) + { + if (node.getType().equals(Material.class)) + { + final String val = (String)constructScalar((ScalarNode)node); + Material mat; + if (NumberUtil.isInt(val)) + { + final int typeId = Integer.parseInt(val); + mat = Material.getMaterial(typeId); + } + else + { + mat = Material.matchMaterial(val); + } + return mat; + } + if (node.getType().equals(MaterialData.class)) + { + final String val = (String)constructScalar((ScalarNode)node); + if (val.isEmpty()) + { + return null; + } + final String[] split = val.split("[:+',;.]", 2); + if (split.length == 0) + { + return null; + } + Material mat; + if (NumberUtil.isInt(split[0])) + { + final int typeId = Integer.parseInt(split[0]); + mat = Material.getMaterial(typeId); + } + else + { + mat = Material.matchMaterial(split[0]); + } + if (mat == null) + { + return null; + } + byte data = 0; + if (split.length == 2 && NumberUtil.isInt(split[1])) + { + data = Byte.parseByte(split[1]); + } + return new MaterialData(mat, data); + } + if (node.getType().equals(ItemStack.class)) + { + final String val = (String)constructScalar((ScalarNode)node); + if (val.isEmpty()) + { + return null; + } + final String[] split1 = val.split("\\W"); + if (split1.length == 0) + { + return null; + } + final String[] split2 = split1[0].split("[:+',;.]", 2); + if (split2.length == 0) + { + return null; + } + Material mat; + if (NumberUtil.isInt(split2[0])) + { + final int typeId = Integer.parseInt(split2[0]); + mat = Material.getMaterial(typeId); + } + else + { + mat = Material.matchMaterial(split2[0]); + } + if (mat == null) + { + return null; + } + short data = 0; + if (split2.length == 2 && NumberUtil.isInt(split2[1])) + { + data = Short.parseShort(split2[1]); + } + int size = mat.getMaxStackSize(); + if (split1.length > 1 && NumberUtil.isInt(split1[1])) + { + size = Integer.parseInt(split1[1]); + } + final ItemStack stack = new ItemStack(mat, size, data); + if (split1.length > 2) + { + for (int i = 2; i < split1.length; i++) + { + final String[] split3 = split1[0].split("[:+',;.]", 2); + if (split3.length < 1) + { + continue; + } + Enchantment enchantment; + if (NumberUtil.isInt(split3[0])) + { + final int enchantId = Integer.parseInt(split3[0]); + enchantment = Enchantment.getById(enchantId); + } + else + { + enchantment = Enchantment.getByName(split3[0].toUpperCase(Locale.ENGLISH)); + } + if (enchantment == null) + { + continue; + } + int level = enchantment.getStartLevel(); + if (split3.length == 2 && NumberUtil.isInt(split3[1])) + { + level = Integer.parseInt(split3[1]); + } + if (level < enchantment.getStartLevel()) + { + level = enchantment.getStartLevel(); + } + if (level > enchantment.getMaxLevel()) + { + level = enchantment.getMaxLevel(); + } + stack.addUnsafeEnchantment(enchantment, level); + } + } + return stack; + } + if (node.getType().equals(EnchantmentLevel.class)) + { + final String val = (String)constructScalar((ScalarNode)node); + if (val.isEmpty()) + { + return null; + } + final String[] split = val.split("[:+',;.]", 2); + if (split.length == 0) + { + return null; + } + Enchantment enchant; + if (NumberUtil.isInt(split[0])) + { + final int typeId = Integer.parseInt(split[0]); + enchant = Enchantment.getById(typeId); + } + else + { + enchant = Enchantment.getByName(split[0].toUpperCase(Locale.ENGLISH)); + } + if (enchant == null) + { + return null; + } + int level = enchant.getStartLevel(); + if (split.length == 2 && NumberUtil.isInt(split[1])) + { + level = Integer.parseInt(split[1]); + } + if (level < enchant.getStartLevel()) + { + level = enchant.getStartLevel(); + } + if (level > enchant.getMaxLevel()) + { + level = enchant.getMaxLevel(); + } + return new EnchantmentLevel(enchant, level); + } + return super.construct(node); + } + } + + + private class ConstructBukkitMapping extends ConstructMapping + { + @Override + public Object construct(final Node node) + { + if (node.getType().equals(Location.class)) + { + //TODO: NPE checks + final MappingNode mnode = (MappingNode)node; + String worldName = ""; + double x = 0, y = 0, z = 0; + float yaw = 0, pitch = 0; + if (mnode.getValue().size() < 4) + { + return null; + } + for (NodeTuple nodeTuple : mnode.getValue()) + { + final String key = (String)constructScalar((ScalarNode)nodeTuple.getKeyNode()); + final ScalarNode snode = (ScalarNode)nodeTuple.getValueNode(); + if (key.equalsIgnoreCase("world")) + { + worldName = (String)constructScalar(snode); + } + if (key.equalsIgnoreCase("x")) + { + x = Double.parseDouble((String)constructScalar(snode)); + } + if (key.equalsIgnoreCase("y")) + { + y = Double.parseDouble((String)constructScalar(snode)); + } + if (key.equalsIgnoreCase("z")) + { + z = Double.parseDouble((String)constructScalar(snode)); + } + if (key.equalsIgnoreCase("yaw")) + { + yaw = Float.parseFloat((String)constructScalar(snode)); + } + if (key.equalsIgnoreCase("pitch")) + { + pitch = Float.parseFloat((String)constructScalar(snode)); + } + } + if (worldName == null || worldName.isEmpty()) + { + return null; + } + final World world = Bukkit.getWorld(worldName); + if (world == null) + { + return null; + } + return new Location(world, x, y, z, yaw, pitch); + } + return super.construct(node); + } + + @Override + protected Object constructJavaBean2ndStep(final MappingNode node, final Object object) + { + Map, TypeDescription> typeDefinitions; + try + { + final Field typeDefField = Constructor.class.getDeclaredField("typeDefinitions"); + typeDefField.setAccessible(true); + typeDefinitions = (Map, TypeDescription>)typeDefField.get((Constructor)BukkitConstructor.this); + if (typeDefinitions == null) + { + throw new NullPointerException(); + } + } + catch (Exception ex) + { + throw new YAMLException(ex); + } + flattenMapping(node); + final Class beanType = node.getType(); + final List nodeValue = node.getValue(); + for (NodeTuple tuple : nodeValue) + { + ScalarNode keyNode; + if (tuple.getKeyNode() instanceof ScalarNode) + { + // key must be scalar + keyNode = (ScalarNode)tuple.getKeyNode(); + } + else + { + throw new YAMLException("Keys must be scalars but found: " + tuple.getKeyNode()); + } + final Node valueNode = tuple.getValueNode(); + // keys can only be Strings + keyNode.setType(String.class); + final String key = (String)constructObject(keyNode); + try + { + Property property; + try + { + property = getProperty(beanType, key); + } + catch (YAMLException e) + { + continue; + } + valueNode.setType(property.getType()); + final TypeDescription memberDescription = typeDefinitions.get(beanType); + boolean typeDetected = false; + if (memberDescription != null) + { + switch (valueNode.getNodeId()) + { + case sequence: + final SequenceNode snode = (SequenceNode)valueNode; + final Class memberType = memberDescription.getListPropertyType(key); + if (memberType != null) + { + snode.setListType(memberType); + typeDetected = true; + } + else if (property.getType().isArray()) + { + snode.setListType(property.getType().getComponentType()); + typeDetected = true; + } + break; + case mapping: + final MappingNode mnode = (MappingNode)valueNode; + final Class keyType = memberDescription.getMapKeyType(key); + if (keyType != null) + { + mnode.setTypes(keyType, memberDescription.getMapValueType(key)); + typeDetected = true; + } + break; + } + } + if (!typeDetected && valueNode.getNodeId() != NodeId.scalar) + { + // only if there is no explicit TypeDescription + final Class[] arguments = property.getActualTypeArguments(); + if (arguments != null) + { + // type safe (generic) collection may contain the + // proper class + if (valueNode.getNodeId() == NodeId.sequence) + { + final Class t = arguments[0]; + final SequenceNode snode = (SequenceNode)valueNode; + snode.setListType(t); + } + else if (valueNode.getTag().equals(Tag.SET)) + { + final Class t = arguments[0]; + final MappingNode mnode = (MappingNode)valueNode; + mnode.setOnlyKeyType(t); + mnode.setUseClassConstructor(true); + } + else if (property.getType().isAssignableFrom(Map.class)) + { + final Class ketType = arguments[0]; + final Class valueType = arguments[1]; + final MappingNode mnode = (MappingNode)valueNode; + mnode.setTypes(ketType, valueType); + mnode.setUseClassConstructor(true); + } + else + { + // the type for collection entries cannot be + // detected + } + } + } + final Object value = constructObject(valueNode); + property.set(object, value); + } + catch (Exception e) + { + throw new YAMLException("Cannot create property=" + key + " for JavaBean=" + + object + "; " + e.getMessage(), e); + } + } + return object; + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/storage/Comment.java b/Essentials/src/com/earth2me/essentials/storage/Comment.java new file mode 100644 index 0000000000..8cb9d4d31b --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/storage/Comment.java @@ -0,0 +1,12 @@ +package com.earth2me.essentials.storage; + +import java.lang.annotation.*; + + +@Target(ElementType.FIELD) +@Documented +@Retention(RetentionPolicy.RUNTIME) +public @interface Comment +{ + String[] value() default ""; +} \ No newline at end of file diff --git a/Essentials/src/com/earth2me/essentials/storage/EnchantmentLevel.java b/Essentials/src/com/earth2me/essentials/storage/EnchantmentLevel.java new file mode 100644 index 0000000000..f4cacea673 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/storage/EnchantmentLevel.java @@ -0,0 +1,80 @@ +package com.earth2me.essentials.storage; + +import java.util.Map.Entry; +import org.bukkit.enchantments.Enchantment; + + +public class EnchantmentLevel implements Entry +{ + private Enchantment enchantment; + private int level; + + public EnchantmentLevel(final Enchantment enchantment, final int level) + { + this.enchantment = enchantment; + this.level = level; + } + + public Enchantment getEnchantment() + { + return enchantment; + } + + public void setEnchantment(final Enchantment enchantment) + { + this.enchantment = enchantment; + } + + public int getLevel() + { + return level; + } + + public void setLevel(final int level) + { + this.level = level; + } + + @Override + public Enchantment getKey() + { + return enchantment; + } + + @Override + public Integer getValue() + { + return level; + } + + @Override + public Integer setValue(final Integer v) + { + int t = level; + level = v; + return t; + } + + @Override + public int hashCode() + { + return enchantment.hashCode() ^ level; + } + + @Override + public boolean equals(final Object obj) + { + if (obj instanceof Entry) + { + final Entry entry = (Entry)obj; + if (entry.getKey() instanceof Enchantment + && entry.getValue() instanceof Integer) + { + final Enchantment enchant = (Enchantment)entry.getKey(); + final Integer lvl = (Integer)entry.getValue(); + return this.enchantment.equals(enchant) && this.level == lvl.intValue(); + } + } + return false; + } +} diff --git a/Essentials/src/com/earth2me/essentials/storage/IStorageObjectHolder.java b/Essentials/src/com/earth2me/essentials/storage/IStorageObjectHolder.java new file mode 100644 index 0000000000..4e860bd8c2 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/storage/IStorageObjectHolder.java @@ -0,0 +1,15 @@ +package com.earth2me.essentials.storage; + + +public interface IStorageObjectHolder +{ + T getData(); + + void acquireReadLock(); + + void acquireWriteLock(); + + void close(); + + void unlock(); +} diff --git a/Essentials/src/com/earth2me/essentials/storage/IStorageReader.java b/Essentials/src/com/earth2me/essentials/storage/IStorageReader.java new file mode 100644 index 0000000000..d59adafe03 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/storage/IStorageReader.java @@ -0,0 +1,7 @@ +package com.earth2me.essentials.storage; + + +public interface IStorageReader +{ + T load(final Class clazz) throws ObjectLoadException; +} diff --git a/Essentials/src/com/earth2me/essentials/storage/IStorageWriter.java b/Essentials/src/com/earth2me/essentials/storage/IStorageWriter.java new file mode 100644 index 0000000000..5b84988695 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/storage/IStorageWriter.java @@ -0,0 +1,7 @@ +package com.earth2me.essentials.storage; + + +public interface IStorageWriter +{ + void save(final StorageObject object); +} diff --git a/Essentials/src/com/earth2me/essentials/storage/ListType.java b/Essentials/src/com/earth2me/essentials/storage/ListType.java new file mode 100644 index 0000000000..9bf6e2e645 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/storage/ListType.java @@ -0,0 +1,14 @@ +package com.earth2me.essentials.storage; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface ListType +{ + Class value() default String.class; +} diff --git a/Essentials/src/com/earth2me/essentials/storage/MapKeyType.java b/Essentials/src/com/earth2me/essentials/storage/MapKeyType.java new file mode 100644 index 0000000000..aa162e51c7 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/storage/MapKeyType.java @@ -0,0 +1,14 @@ +package com.earth2me.essentials.storage; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface MapKeyType +{ + Class value() default String.class; +} \ No newline at end of file diff --git a/Essentials/src/com/earth2me/essentials/storage/MapValueType.java b/Essentials/src/com/earth2me/essentials/storage/MapValueType.java new file mode 100644 index 0000000000..1b5fff978c --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/storage/MapValueType.java @@ -0,0 +1,14 @@ +package com.earth2me.essentials.storage; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface MapValueType +{ + Class value() default String.class; +} \ No newline at end of file diff --git a/Essentials/src/com/earth2me/essentials/storage/ObjectLoadException.java b/Essentials/src/com/earth2me/essentials/storage/ObjectLoadException.java new file mode 100644 index 0000000000..8b804abc3f --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/storage/ObjectLoadException.java @@ -0,0 +1,10 @@ +package com.earth2me.essentials.storage; + + +public class ObjectLoadException extends Exception +{ + public ObjectLoadException(Throwable thrwbl) + { + super(thrwbl); + } +} diff --git a/Essentials/src/com/earth2me/essentials/storage/StorageObject.java b/Essentials/src/com/earth2me/essentials/storage/StorageObject.java new file mode 100644 index 0000000000..0c66fefcf7 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/storage/StorageObject.java @@ -0,0 +1,6 @@ +package com.earth2me.essentials.storage; + + +public interface StorageObject +{ +} diff --git a/Essentials/src/com/earth2me/essentials/storage/YamlStorageReader.java b/Essentials/src/com/earth2me/essentials/storage/YamlStorageReader.java new file mode 100644 index 0000000000..6f921ec10d --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/storage/YamlStorageReader.java @@ -0,0 +1,123 @@ +package com.earth2me.essentials.storage; + +import java.io.Reader; +import java.lang.reflect.Field; +import java.util.*; +import java.util.concurrent.locks.ReentrantLock; +import org.bukkit.plugin.Plugin; +import org.yaml.snakeyaml.TypeDescription; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.Constructor; + + +public class YamlStorageReader implements IStorageReader +{ + private transient static final Map PREPARED_YAMLS = Collections.synchronizedMap(new HashMap()); + private transient static final Map LOCKS = new HashMap(); + private transient final Reader reader; + private transient final Plugin plugin; + + public YamlStorageReader(final Reader reader, final Plugin plugin) + { + this.reader = reader; + this.plugin = plugin; + } + + @Override + public T load(final Class clazz) throws ObjectLoadException + { + Yaml yaml = PREPARED_YAMLS.get(clazz); + if (yaml == null) + { + yaml = new Yaml(prepareConstructor(clazz)); + PREPARED_YAMLS.put(clazz, yaml); + } + ReentrantLock lock; + synchronized (LOCKS) + { + lock = LOCKS.get(clazz); + if (lock == null) + { + lock = new ReentrantLock(); + } + } + lock.lock(); + try + { + T object = (T)yaml.load(reader); + if (object == null) { + object = clazz.newInstance(); + } + return object; + } + catch (IllegalAccessException ex) + { + throw new ObjectLoadException(ex); + } + catch (InstantiationException ex) + { + throw new ObjectLoadException(ex); + } + finally + { + lock.unlock(); + } + } + + private Constructor prepareConstructor(final Class clazz) + { + final Constructor constructor = new BukkitConstructor(clazz, plugin); + final Set classes = new HashSet(); + + prepareConstructor(constructor, classes, clazz); + return constructor; + } + + private void prepareConstructor(final Constructor constructor, final Set classes, final Class clazz) + { + classes.add(clazz); + final TypeDescription description = new TypeDescription(clazz); + for (Field field : clazz.getDeclaredFields()) + { + prepareList(field, description, classes, constructor); + prepareMap(field, description, classes, constructor); + if (StorageObject.class.isAssignableFrom(field.getType()) + && !classes.contains(field.getType())) + { + prepareConstructor(constructor, classes, field.getType()); + } + } + constructor.addTypeDescription(description); + } + + private void prepareList(final Field field, final TypeDescription description, final Set classes, final Constructor constructor) + { + final ListType listType = field.getAnnotation(ListType.class); + if (listType != null) + { + description.putListPropertyType(field.getName(), listType.value()); + if (StorageObject.class.isAssignableFrom(listType.value()) + && !classes.contains(listType.value())) + { + prepareConstructor(constructor, classes, listType.value()); + } + } + } + + private void prepareMap(final Field field, final TypeDescription description, final Set classes, final Constructor constructor) + { + final MapValueType mapType = field.getAnnotation(MapValueType.class); + if (mapType != null) + { + final MapKeyType mapKeyType = field.getAnnotation(MapKeyType.class); + description.putMapPropertyType(field.getName(), + mapKeyType == null ? String.class : mapKeyType.value(), + mapType.value()); + if (StorageObject.class.isAssignableFrom(mapType.value()) + && !classes.contains(mapType.value())) + { + prepareConstructor(constructor, classes, mapType.value()); + } + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/storage/YamlStorageWriter.java b/Essentials/src/com/earth2me/essentials/storage/YamlStorageWriter.java new file mode 100644 index 0000000000..f08e734f82 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/storage/YamlStorageWriter.java @@ -0,0 +1,340 @@ +package com.earth2me.essentials.storage; + +import java.io.PrintWriter; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Collections; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Pattern; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.material.MaterialData; +import org.yaml.snakeyaml.Yaml; + + +public class YamlStorageWriter implements IStorageWriter +{ + private transient static final Pattern NON_WORD_PATTERN = Pattern.compile("\\W"); + private transient static final Yaml YAML = new Yaml(); + private transient final PrintWriter writer; + + public YamlStorageWriter(final PrintWriter writer) + { + this.writer = writer; + } + + @Override + public void save(final StorageObject object) + { + try + { + writeToFile(object, 0, object.getClass()); + } + catch (IllegalArgumentException ex) + { + Logger.getLogger(YamlStorageWriter.class.getName()).log(Level.SEVERE, null, ex); + } + catch (IllegalAccessException ex) + { + Logger.getLogger(YamlStorageWriter.class.getName()).log(Level.SEVERE, null, ex); + } + } + + private void writeToFile(final Object object, final int depth, final Class clazz) throws IllegalAccessException + { + for (Field field : clazz.getDeclaredFields()) + { + final int modifier = field.getModifiers(); + if (Modifier.isPrivate(modifier) && !Modifier.isTransient(modifier) && !Modifier.isStatic(modifier)) + { + field.setAccessible(true); + + final Object data = field.get(object); + if (writeKey(field, depth, data)) + { + continue; + } + if (data instanceof StorageObject) + { + writer.println(); + writeToFile(data, depth + 1, data.getClass()); + } + else if (data instanceof Map) + { + writeMap((Map)data, depth + 1); + } + else if (data instanceof Collection) + { + writeCollection((Collection)data, depth + 1); + } + else if (data instanceof Location) + { + writeLocation((Location)data, depth + 1); + } + else + { + writeScalar(data); + writer.println(); + } + } + } + } + + private boolean writeKey(final Field field, final int depth, final Object data) + { + final boolean commentPresent = writeComment(field, depth); + if (data == null && !commentPresent) + { + return true; + } + writeIndention(depth); + if (data == null && commentPresent) + { + writer.print('#'); + } + final String name = field.getName(); + writer.print(name); + writer.print(": "); + if (data == null && commentPresent) + { + writer.println(); + writer.println(); + return true; + } + return false; + } + + private boolean writeComment(final Field field, final int depth) + { + final boolean commentPresent = field.isAnnotationPresent(Comment.class); + if (commentPresent) + { + final Comment comments = field.getAnnotation(Comment.class); + for (String comment : comments.value()) + { + final String trimmed = comment.trim(); + if (trimmed.isEmpty()) + { + continue; + } + writeIndention(depth); + writer.print("# "); + writer.print(trimmed); + writer.println(); + } + } + return commentPresent; + } + + private void writeCollection(final Collection data, final int depth) throws IllegalAccessException + { + writer.println(); + if (data.isEmpty()) + { + writer.println(); + } + for (Object entry : data) + { + if (entry != null) + { + writeIndention(depth); + writer.print("- "); + if (entry instanceof StorageObject) + { + writer.println(); + writeToFile(entry, depth + 1, entry.getClass()); + } + else if (entry instanceof Location) + { + writeLocation((Location)entry, depth + 1); + } + else + { + writeScalar(entry); + } + } + } + writer.println(); + } + + private void writeMap(final Map data, final int depth) throws IllegalArgumentException, IllegalAccessException + { + writer.println(); + if (data.isEmpty()) + { + writer.println(); + } + for (Entry entry : data.entrySet()) + { + final Object value = entry.getValue(); + if (value != null) + { + writeIndention(depth); + writeKey(entry.getKey()); + writer.print(": "); + if (value instanceof StorageObject) + { + writer.println(); + writeToFile(value, depth + 1, value.getClass()); + } + else if (value instanceof Collection) + { + writeCollection((Collection)value, depth + 1); + } + else if (value instanceof Location) + { + writeLocation((Location)value, depth + 1); + } + else + { + writeScalar(value); + writer.println(); + } + } + } + } + + private void writeIndention(final int depth) + { + for (int i = 0; i < depth; i++) + { + writer.print(" "); + } + } + + private void writeScalar(final Object data) + { + if (data instanceof String || data instanceof Boolean || data instanceof Number) + { + synchronized (YAML) + { + YAML.dumpAll(Collections.singletonList(data).iterator(), writer); + } + } + else if (data instanceof Material) + { + writeMaterial(data); + writer.println(); + } + else if (data instanceof MaterialData) + { + writeMaterialData(data); + writer.println(); + } + else if (data instanceof ItemStack) + { + writeItemStack(data); + writer.println(); + } + else if (data instanceof EnchantmentLevel) + { + writeEnchantmentLevel(data); + writer.println(); + } + else + { + throw new UnsupportedOperationException(); + } + } + + private void writeKey(final Object data) + { + if (data instanceof String || data instanceof Boolean || data instanceof Number) + { + String output = data.toString(); + if (NON_WORD_PATTERN.matcher(output).find()) + { + writer.print('"'); + writer.print(output.replace("\"", "\\\"")); + writer.print('"'); + } + else + { + writer.print(output); + } + } + else if (data instanceof Material) + { + writeMaterial(data); + } + else if (data instanceof MaterialData) + { + writeMaterialData(data); + } + else if (data instanceof EnchantmentLevel) + { + writeEnchantmentLevel(data); + } + else + { + throw new UnsupportedOperationException(); + } + } + + private void writeMaterial(final Object data) + { + writer.print(data.toString().toLowerCase(Locale.ENGLISH)); + } + + private void writeMaterialData(final Object data) + { + final MaterialData matData = (MaterialData)data; + writeMaterial(matData.getItemType()); + if (matData.getData() > 0) + { + writer.print(':'); + writer.print(matData.getData()); + } + } + + private void writeItemStack(final Object data) + { + final ItemStack itemStack = (ItemStack)data; + writeMaterialData(itemStack.getData()); + writer.print(' '); + writer.print(itemStack.getAmount()); + for (Entry entry : itemStack.getEnchantments().entrySet()) + { + writer.print(' '); + writeEnchantmentLevel(entry); + } + } + + private void writeEnchantmentLevel(Object data) + { + final Entry enchLevel = (Entry)data; + writer.print(enchLevel.getKey().getName().toLowerCase(Locale.ENGLISH)); + writer.print(':'); + writer.print(enchLevel.getValue()); + } + + private void writeLocation(final Location entry, final int depth) + { + writer.println(); + writeIndention(depth); + writer.print("world: "); + writeScalar(entry.getWorld().getName()); + writeIndention(depth); + writer.print("x: "); + writeScalar(entry.getX()); + writeIndention(depth); + writer.print("y: "); + writeScalar(entry.getY()); + writeIndention(depth); + writer.print("z: "); + writeScalar(entry.getZ()); + writeIndention(depth); + writer.print("yaw: "); + writeScalar(entry.getYaw()); + writeIndention(depth); + writer.print("pitch: "); + writeScalar(entry.getPitch()); + } +} diff --git a/Essentials/src/com/earth2me/essentials/textreader/BookInput.java b/Essentials/src/com/earth2me/essentials/textreader/BookInput.java new file mode 100644 index 0000000000..4c0ee92363 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/textreader/BookInput.java @@ -0,0 +1,130 @@ +package com.earth2me.essentials.textreader; + +import java.io.*; +import java.lang.ref.SoftReference; +import java.util.*; +import net.ess3.api.IEssentials; + + +public class BookInput implements IText +{ + private final static HashMap> cache = new HashMap>(); + private final transient List lines; + private final transient List chapters; + private final transient Map bookmarks; + private final transient long lastChange; + + public BookInput(final String filename, final boolean createFile, final IEssentials ess) throws IOException + { + + File file = null; + if (file == null || !file.exists()) + { + file = new File(ess.getDataFolder(), filename + ".txt"); + } + if (!file.exists()) + { + if (createFile) + { + final InputStream input = ess.getResource(filename + ".txt"); + final OutputStream output = new FileOutputStream(file); + try + { + final byte[] buffer = new byte[1024]; + int length = input.read(buffer); + while (length > 0) + { + output.write(buffer, 0, length); + length = input.read(buffer); + } + } + finally + { + output.close(); + input.close(); + } + ess.getLogger().info("File " + filename + ".txt does not exist. Creating one for you."); + } + } + if (!file.exists()) + { + lastChange = 0; + lines = Collections.emptyList(); + chapters = Collections.emptyList(); + bookmarks = Collections.emptyMap(); + throw new FileNotFoundException("Could not create " + filename + ".txt"); + } + else + { + lastChange = file.lastModified(); + boolean readFromfile; + synchronized (cache) + { + final SoftReference inputRef = cache.get(file.getName()); + BookInput input; + if (inputRef == null || (input = inputRef.get()) == null || input.lastChange < lastChange) + { + lines = new ArrayList(); + chapters = new ArrayList(); + bookmarks = new HashMap(); + cache.put(file.getName(), new SoftReference(this)); + readFromfile = true; + } + else + { + lines = Collections.unmodifiableList(input.getLines()); + chapters = Collections.unmodifiableList(input.getChapters()); + bookmarks = Collections.unmodifiableMap(input.getBookmarks()); + readFromfile = false; + } + } + if (readFromfile) + { + final Reader reader = new InputStreamReader(new FileInputStream(file), "utf-8"); + final BufferedReader bufferedReader = new BufferedReader(reader); + try + { + int lineNumber = 0; + while (bufferedReader.ready()) + { + final String line = bufferedReader.readLine(); + if (line == null) + { + break; + } + if (line.length() > 0 && line.charAt(0) == '#') + { + bookmarks.put(line.substring(1).toLowerCase(Locale.ENGLISH).replaceAll("&[0-9a-fk]", ""), lineNumber); + chapters.add(line.substring(1).replace('&', '§').replace("§§", "&")); + } + lines.add(line.replace('&', '§').replace("§§", "&")); + lineNumber++; + } + } + finally + { + reader.close(); + bufferedReader.close(); + } + } + } + } + + @Override + public List getLines() + { + return lines; + } + + @Override + public List getChapters() + { + return chapters; + } + + @Override + public Map getBookmarks() + { + return bookmarks; + } +} diff --git a/Essentials/src/com/earth2me/essentials/textreader/BookPager.java b/Essentials/src/com/earth2me/essentials/textreader/BookPager.java new file mode 100644 index 0000000000..b84bfea792 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/textreader/BookPager.java @@ -0,0 +1,181 @@ +package com.earth2me.essentials.textreader; + +import static com.earth2me.essentials.I18n.tl; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; + + +public class BookPager +{ + private final transient IText text; + final double pageMax = 254; + final double charMax = 18.5; + final int lineMax = 12; + + public BookPager(final IText text) + { + this.text = text; + } + + public List getPages(final String pageStr) throws Exception + { + List lines = text.getLines(); + List chapters = text.getChapters(); + List pageLines = new ArrayList(); + Map bookmarks = text.getBookmarks(); + + //This checks to see if we have the chapter in the index + if (!bookmarks.containsKey(pageStr.toLowerCase(Locale.ENGLISH))) + { + throw new Exception(tl("infoUnknownChapter")); + } + + //Since we have a valid chapter, count the number of lines in the chapter + final int chapterstart = bookmarks.get(pageStr.toLowerCase(Locale.ENGLISH)) + 1; + int chapterend; + for (chapterend = chapterstart; chapterend < lines.size(); chapterend++) + { + final String line = lines.get(chapterend); + if (line.length() > 0 && line.charAt(0) == '#') + { + break; + } + } + + List pages = new ArrayList(); + double pageLength = 0; + + for (int lineNo = chapterstart; lineNo < chapterend; lineNo += 1) + { + String pageLine = lines.get(lineNo); + String tempLine; + + final int lineLength = pageLine.length(); + double length = 0; + int pointer = 0; + int start = 0; + double weight = 1; + boolean forcePageEnd = false; + + while (pointer < lineLength) + { + Character letter = pageLine.charAt(pointer); + + if (pageLine.charAt(start) == ' ') + { + start++; + pointer++; + continue; + } + + if (pageLength >= pageMax) + { + length = charMax; + pageLength = 0; + forcePageEnd = true; + } + + if (length >= charMax || (letter == '\u00a7' && length + 1 >= charMax)) + { + int pos = pointer; + int rollback = 0; + while (pos > start && pageLine.charAt(pos) != ' ' && pageLine.charAt(pos) != "\n".charAt(0)) + { + rollback++; + pos--; + } + if (pos != start) + { + pointer = pos; + pageLength -= rollback; + } + + tempLine = pageLine.substring(start, pointer); + pageLines.add(tempLine); + if (buildPage(pages, pageLines, forcePageEnd)) + { + pageLength = 0; + } + forcePageEnd = false; + + start = pointer; + length = 0; + pageLength += 1; + } + + pageLength++; + + if (letter == '\u00a7' && pointer + 1 < lineLength) + { + Character nextLetter = pageLine.charAt(pointer + 1); + if (nextLetter == 'l' || nextLetter == 'L') + { + weight = 1.25; + } + else + { + weight = 1; + } + pointer++; + } + else if (letter == 'i' || letter == '.' || letter == ',' || letter == '!' || letter == ':' || letter == ';' || letter == '|') + { + length += (0.34 * weight); + } + else if (letter == 'l' || letter == '\'' || letter == '`') + { + length += (0.53 * weight); + } + else if (letter == ' ' || letter == 't' || letter == 'I' || letter == '[' || letter == ']') + { + length += (0.69 * weight); + } + else if (letter == 'f' || letter == 'k' || letter == '"' || letter == '*' + || letter == '(' || letter == ')' || letter == '{' || letter == '}' || letter == '<' || letter == '>') + { + length += (0.85 * weight); + } + else if (letter == '@' || letter == '~') + { + length += (1.2 * weight); + } + else + { + length += weight; + } + pointer++; + } + + if (length > 0) + { + tempLine = pageLine.substring(start, lineLength); + pageLines.add(tempLine); + if (buildPage(pages, pageLines, false)) + { + pageLength = 0; + } + } + } + + buildPage(pages, pageLines, true); + return pages; + } + + boolean buildPage(List pages, List lines, boolean override) + { + if (override || lines.size() > lineMax) + { + StringBuilder newPage = new StringBuilder(); + for (String aline : lines) + { + newPage.append(aline).append("\n"); + } + pages.add(newPage.toString()); + lines.clear(); + return true; + } + return false; + } +} diff --git a/Essentials/src/com/earth2me/essentials/textreader/HelpInput.java b/Essentials/src/com/earth2me/essentials/textreader/HelpInput.java new file mode 100644 index 0000000000..1e74871d4f --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/textreader/HelpInput.java @@ -0,0 +1,171 @@ +package com.earth2me.essentials.textreader; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import java.io.IOException; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; +import net.ess3.api.IEssentials; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginDescriptionFile; + + +public class HelpInput implements IText +{ + private static final String DESCRIPTION = "description"; + private static final String PERMISSION = "permission"; + private static final String PERMISSIONS = "permissions"; + private static final Logger logger = Logger.getLogger("Essentials"); + private final transient List lines = new ArrayList(); + private final transient List chapters = new ArrayList(); + private final transient Map bookmarks = new HashMap(); + + public HelpInput(final User user, final String match, final IEssentials ess) throws IOException + { + boolean reported = false; + final List newLines = new ArrayList(); + String pluginName = ""; + String pluginNameLow = ""; + if (!match.equalsIgnoreCase("")) + { + lines.add(tl("helpMatching", match)); + } + + for (Plugin p : ess.getServer().getPluginManager().getPlugins()) + { + try + { + final List pluginLines = new ArrayList(); + final PluginDescriptionFile desc = p.getDescription(); + final Map> cmds = desc.getCommands(); + pluginName = p.getDescription().getName(); + pluginNameLow = pluginName.toLowerCase(Locale.ENGLISH); + if (pluginNameLow.equals(match)) + { + lines.clear(); + newLines.clear(); + lines.add(tl("helpFrom", p.getDescription().getName())); + } + final boolean isOnWhitelist = user.isAuthorized("essentials.help." + pluginNameLow); + + for (Map.Entry> k : cmds.entrySet()) + { + try + { + if (!match.equalsIgnoreCase("") && (!pluginNameLow.contains(match)) && (!k.getKey().toLowerCase(Locale.ENGLISH).contains(match)) + && (!(k.getValue().get(DESCRIPTION) instanceof String + && ((String)k.getValue().get(DESCRIPTION)).toLowerCase(Locale.ENGLISH).contains(match)))) + { + continue; + } + + if (pluginNameLow.contains("essentials")) + { + final String node = "essentials." + k.getKey(); + if (!ess.getSettings().isCommandDisabled(k.getKey()) && user.isAuthorized(node)) + { + pluginLines.add(tl("helpLine", k.getKey(), k.getValue().get(DESCRIPTION))); + } + } + else + { + if (ess.getSettings().showNonEssCommandsInHelp()) + { + final Map value = k.getValue(); + Object permissions = null; + if (value.containsKey(PERMISSION)) + { + permissions = value.get(PERMISSION); + } + else if (value.containsKey(PERMISSIONS)) + { + permissions = value.get(PERMISSIONS); + } + if (isOnWhitelist || user.isAuthorized("essentials.help." + pluginNameLow + "." + k.getKey())) + { + pluginLines.add(tl("helpLine", k.getKey(), value.get(DESCRIPTION))); + } + else if (permissions instanceof List && !((List)permissions).isEmpty()) + { + boolean enabled = false; + for (Object o : (List)permissions) + { + if (o instanceof String && user.isAuthorized(o.toString())) + { + enabled = true; + break; + } + } + if (enabled) + { + pluginLines.add(tl("helpLine", k.getKey(), value.get(DESCRIPTION))); + } + } + else if (permissions instanceof String && !"".equals(permissions)) + { + if (user.isAuthorized(permissions.toString())) + { + pluginLines.add(tl("helpLine", k.getKey(), value.get(DESCRIPTION))); + } + } + else + { + if (!ess.getSettings().hidePermissionlessHelp()) + { + pluginLines.add(tl("helpLine", k.getKey(), value.get(DESCRIPTION))); + } + } + } + } + } + catch (NullPointerException ex) + { + } + } + if (!pluginLines.isEmpty()) + { + newLines.addAll(pluginLines); + if (pluginNameLow.equals(match)) + { + break; + } + if (match.equalsIgnoreCase("")) + { + lines.add(tl("helpPlugin", pluginName, pluginNameLow)); + } + } + } + catch (NullPointerException ex) + { + } + catch (Exception ex) + { + if (!reported) + { + logger.log(Level.WARNING, tl("commandHelpFailedForPlugin", pluginNameLow), ex); + } + reported = true; + } + } + lines.addAll(newLines); + } + + @Override + public List getLines() + { + return lines; + } + + @Override + public List getChapters() + { + return chapters; + } + + @Override + public Map getBookmarks() + { + return bookmarks; + } +} diff --git a/Essentials/src/com/earth2me/essentials/textreader/IText.java b/Essentials/src/com/earth2me/essentials/textreader/IText.java new file mode 100644 index 0000000000..60db6dadf0 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/textreader/IText.java @@ -0,0 +1,17 @@ +package com.earth2me.essentials.textreader; + +import java.util.List; +import java.util.Map; + + +public interface IText +{ + // Contains the raw text lines + List getLines(); + + // Chapters contain the names that are displayed automatically if the file doesn't contain a introduction chapter. + List getChapters(); + + // Bookmarks contains the string mappings from 'chapters' to line numbers. + Map getBookmarks(); +} diff --git a/Essentials/src/com/earth2me/essentials/textreader/KeywordReplacer.java b/Essentials/src/com/earth2me/essentials/textreader/KeywordReplacer.java new file mode 100644 index 0000000000..c2c40b1dc2 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/textreader/KeywordReplacer.java @@ -0,0 +1,419 @@ +package com.earth2me.essentials.textreader; + +import com.earth2me.essentials.CommandSource; +import com.earth2me.essentials.ExecuteTimer; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.PlayerList; +import com.earth2me.essentials.User; +import static com.earth2me.essentials.textreader.KeywordType.DISPLAYNAME; +import static com.earth2me.essentials.textreader.KeywordType.PLAYER; +import com.earth2me.essentials.utils.DateUtil; +import com.earth2me.essentials.utils.DescParseTickFormat; +import com.earth2me.essentials.utils.NumberUtil; +import java.lang.management.ManagementFactory; +import java.text.DateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.logging.Level; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import net.ess3.api.IEssentials; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + + +public class KeywordReplacer implements IText +{ + private static final Pattern KEYWORD = Pattern.compile("\\{([^\\{\\}]+)\\}"); + private static final Pattern KEYWORDSPLIT = Pattern.compile("\\:"); + private final transient IText input; + private final transient List replaced; + private final transient IEssentials ess; + private final transient boolean includePrivate; + private transient ExecuteTimer execTimer; + private final EnumMap keywordCache = new EnumMap(KeywordType.class); + + public KeywordReplacer(final IText input, final CommandSource sender, final IEssentials ess) + { + this.input = input; + this.replaced = new ArrayList(this.input.getLines().size()); + this.ess = ess; + this.includePrivate = true; + replaceKeywords(sender); + } + + public KeywordReplacer(final IText input, final CommandSource sender, final IEssentials ess, final boolean showPrivate) + { + this.input = input; + this.replaced = new ArrayList(this.input.getLines().size()); + this.ess = ess; + this.includePrivate = showPrivate; + replaceKeywords(sender); + } + + private void replaceKeywords(final CommandSource sender) + { + execTimer = new ExecuteTimer(); + execTimer.start(); + User user = null; + if (sender.isPlayer()) + { + user = ess.getUser(sender.getPlayer()); + } + execTimer.mark("User Grab"); + + for (int i = 0; i < input.getLines().size(); i++) + { + String line = input.getLines().get(i); + final Matcher matcher = KEYWORD.matcher(line); + + while (matcher.find()) + { + final String fullMatch = matcher.group(0); + final String keywordMatch = matcher.group(1); + final String[] matchTokens = KEYWORDSPLIT.split(keywordMatch); + line = replaceLine(line, fullMatch, matchTokens, user); + } + replaced.add(line); + } + + execTimer.mark("Text Replace"); + final String timeroutput = execTimer.end(); + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "Keyword Replacer " + timeroutput); + } + } + + private String replaceLine(String line, final String fullMatch, final String[] matchTokens, final User user) + { + final String keyword = matchTokens[0]; + try + { + String replacer = null; + KeywordType validKeyword = KeywordType.valueOf(keyword); + if (validKeyword.getType().equals(KeywordCachable.CACHEABLE) && keywordCache.containsKey(validKeyword)) + { + replacer = keywordCache.get(validKeyword).toString(); + } + else if (validKeyword.getType().equals(KeywordCachable.SUBVALUE)) + { + String subKeyword = ""; + if (matchTokens.length > 1) + { + subKeyword = matchTokens[1].toLowerCase(Locale.ENGLISH); + } + + if (keywordCache.containsKey(validKeyword)) + { + Map values = (Map)keywordCache.get(validKeyword); + if (values.containsKey(subKeyword)) + { + replacer = values.get(subKeyword); + } + } + } + + if (validKeyword.isPrivate() && !includePrivate) + { + replacer = ""; + } + + if (replacer == null) + { + replacer = ""; + switch (validKeyword) + { + case PLAYER: + case DISPLAYNAME: + if (user != null) + { + replacer = user.getDisplayName(); + } + break; + case USERNAME: + if (user != null) + { + replacer = user.getName(); + } + break; + case BALANCE: + if (user != null) + { + replacer = NumberUtil.displayCurrency(user.getMoney(), ess); + } + break; + case MAILS: + if (user != null) + { + replacer = Integer.toString(user.getMails().size()); + } + break; + case WORLD: + case WORLDNAME: + if (user != null) + { + final Location location = user.getLocation(); + replacer = location == null || location.getWorld() == null ? "" : location.getWorld().getName(); + } + break; + case ONLINE: + int playerHidden = 0; + for (User u : ess.getOnlineUsers()) + { + if (u.isHidden()) + { + playerHidden++; + } + } + replacer = Integer.toString(ess.getOnlinePlayers().size() - playerHidden); + break; + case UNIQUE: + replacer = Integer.toString(ess.getUserMap().getUniqueUsers()); + break; + case WORLDS: + final StringBuilder worldsBuilder = new StringBuilder(); + for (World w : ess.getServer().getWorlds()) + { + if (worldsBuilder.length() > 0) + { + worldsBuilder.append(", "); + } + worldsBuilder.append(w.getName()); + } + replacer = worldsBuilder.toString(); + break; + case PLAYERLIST: + final Map outputList; + if (keywordCache.containsKey(validKeyword)) + { + outputList = (Map)keywordCache.get(validKeyword); + } + else + { + final boolean showHidden; + if (user == null) + { + showHidden = true; + } + else + { + showHidden = user.isAuthorized("essentials.list.hidden") || user.canInteractVanished(); + } + + //First lets build the per group playerlist + final Map> playerList = PlayerList.getPlayerLists(ess, user, showHidden); + outputList = new HashMap(); + for (String groupName : playerList.keySet()) + { + final List groupUsers = playerList.get(groupName); + if (groupUsers != null && !groupUsers.isEmpty()) + { + outputList.put(groupName, PlayerList.listUsers(ess, groupUsers, " ")); + } + } + + //Now lets build the all user playerlist + final StringBuilder playerlistBuilder = new StringBuilder(); + for (Player p : ess.getOnlinePlayers()) + { + if (ess.getUser(p).isHidden()) + { + continue; + } + if (playerlistBuilder.length() > 0) + { + playerlistBuilder.append(", "); + } + playerlistBuilder.append(p.getDisplayName()); + } + outputList.put("", playerlistBuilder.toString()); + keywordCache.put(validKeyword, outputList); + } + + //Now thats all done, output the one we want and cache the rest. + if (matchTokens.length == 1) + { + replacer = outputList.get(""); + } + else if (outputList.containsKey(matchTokens[1].toLowerCase(Locale.ENGLISH))) + { + replacer = outputList.get(matchTokens[1].toLowerCase(Locale.ENGLISH)); + } + else if (matchTokens.length > 2) + { + replacer = matchTokens[2]; + } + + keywordCache.put(validKeyword, outputList); + break; + case TIME: + replacer = DateFormat.getTimeInstance(DateFormat.MEDIUM, ess.getI18n().getCurrentLocale()).format(new Date()); + break; + case DATE: + replacer = DateFormat.getDateInstance(DateFormat.MEDIUM, ess.getI18n().getCurrentLocale()).format(new Date()); + break; + case WORLDTIME12: + if (user != null) + { + replacer = DescParseTickFormat.format12(user.getWorld() == null ? 0 : user.getWorld().getTime()); + } + break; + case WORLDTIME24: + if (user != null) + { + replacer = DescParseTickFormat.format24(user.getWorld() == null ? 0 : user.getWorld().getTime()); + } + break; + case WORLDDATE: + if (user != null) + { + replacer = DateFormat.getDateInstance(DateFormat.MEDIUM, ess.getI18n().getCurrentLocale()).format(DescParseTickFormat.ticksToDate(user.getWorld() == null ? 0 : user.getWorld().getFullTime())); + } + break; + case COORDS: + if (user != null) + { + final Location location = user.getLocation(); + replacer = tl("coordsKeyword", location.getBlockX(), location.getBlockY(), location.getBlockZ()); + } + break; + case TPS: + replacer = NumberUtil.formatDouble(ess.getTimer().getAverageTPS()); + break; + case UPTIME: + replacer = DateUtil.formatDateDiff(ManagementFactory.getRuntimeMXBean().getStartTime()); + break; + case IP: + if (user != null) + { + replacer = user.getBase().getAddress() == null || user.getBase().getAddress().getAddress() == null ? "" : user.getBase().getAddress().getAddress().toString(); + } + break; + case ADDRESS: + if (user != null) + { + replacer = user.getBase().getAddress() == null ? "" : user.getBase().getAddress().toString(); + } + break; + case PLUGINS: + final StringBuilder pluginlistBuilder = new StringBuilder(); + for (Plugin p : ess.getServer().getPluginManager().getPlugins()) + { + if (pluginlistBuilder.length() > 0) + { + pluginlistBuilder.append(", "); + } + pluginlistBuilder.append(p.getDescription().getName()); + } + replacer = pluginlistBuilder.toString(); + break; + case VERSION: + replacer = ess.getServer().getVersion(); + break; + default: + replacer = "N/A"; + break; + } + + //If this is just a regular keyword, lets throw it into the cache + if (validKeyword.getType().equals(KeywordCachable.CACHEABLE)) + { + keywordCache.put(validKeyword, replacer); + } + } + + line = line.replace(fullMatch, replacer); + } + catch (IllegalArgumentException ex) + { + } + + return line; + } + + @Override + public List getLines() + { + return replaced; + } + + @Override + public List getChapters() + { + return input.getChapters(); + } + + @Override + public Map getBookmarks() + { + return input.getBookmarks(); + } +} + +//When adding a keyword here, you also need to add the implementation above +enum KeywordType +{ + PLAYER(KeywordCachable.CACHEABLE), + DISPLAYNAME(KeywordCachable.CACHEABLE), + USERNAME(KeywordCachable.NOTCACHEABLE), + BALANCE(KeywordCachable.CACHEABLE), + MAILS(KeywordCachable.CACHEABLE), + WORLD(KeywordCachable.CACHEABLE), + WORLDNAME(KeywordCachable.CACHEABLE), + ONLINE(KeywordCachable.CACHEABLE), + UNIQUE(KeywordCachable.CACHEABLE), + WORLDS(KeywordCachable.CACHEABLE), + PLAYERLIST(KeywordCachable.SUBVALUE, true), + TIME(KeywordCachable.CACHEABLE), + DATE(KeywordCachable.CACHEABLE), + WORLDTIME12(KeywordCachable.CACHEABLE), + WORLDTIME24(KeywordCachable.CACHEABLE), + WORLDDATE(KeywordCachable.CACHEABLE), + COORDS(KeywordCachable.CACHEABLE), + TPS(KeywordCachable.CACHEABLE), + UPTIME(KeywordCachable.CACHEABLE), + IP(KeywordCachable.CACHEABLE, true), + ADDRESS(KeywordCachable.CACHEABLE, true), + PLUGINS(KeywordCachable.CACHEABLE, true), + VERSION(KeywordCachable.CACHEABLE, true); + private final KeywordCachable type; + private final boolean isPrivate; + + KeywordType(KeywordCachable type) + { + this.type = type; + this.isPrivate = false; + } + + KeywordType(KeywordCachable type, boolean isPrivate) + { + this.type = type; + this.isPrivate = isPrivate; + } + + public KeywordCachable getType() + { + return type; + } + + public boolean isPrivate() + { + return isPrivate; + } +} + + +enum KeywordCachable +{ + CACHEABLE, // This keyword can be cached as a string + SUBVALUE, // This keyword can be cached as a map + NOTCACHEABLE; // This keyword should never be cached +} \ No newline at end of file diff --git a/Essentials/src/com/earth2me/essentials/textreader/SimpleTextInput.java b/Essentials/src/com/earth2me/essentials/textreader/SimpleTextInput.java new file mode 100644 index 0000000000..f15ce6df56 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/textreader/SimpleTextInput.java @@ -0,0 +1,41 @@ +package com.earth2me.essentials.textreader; + +import java.util.*; + + +public class SimpleTextInput implements IText +{ + private final transient List lines = new ArrayList(); + + public SimpleTextInput(final String input) + { + lines.addAll(Arrays.asList(input.split("\\n"))); + } + + public SimpleTextInput(final List input) + { + lines.addAll(input); + } + + public SimpleTextInput() + { + } + + @Override + public List getLines() + { + return lines; + } + + @Override + public List getChapters() + { + return Collections.emptyList(); + } + + @Override + public Map getBookmarks() + { + return Collections.emptyMap(); + } +} diff --git a/Essentials/src/com/earth2me/essentials/textreader/SimpleTextPager.java b/Essentials/src/com/earth2me/essentials/textreader/SimpleTextPager.java new file mode 100644 index 0000000000..2556201f1e --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/textreader/SimpleTextPager.java @@ -0,0 +1,36 @@ +package com.earth2me.essentials.textreader; + +import com.earth2me.essentials.CommandSource; +import java.util.List; + +public class SimpleTextPager +{ + private final transient IText text; + + public SimpleTextPager(final IText text) + { + this.text = text; + } + + public void showPage(final CommandSource sender) + { + for (String line : text.getLines()) + { + sender.sendMessage(line); + } + } + + public List getLines() + { + return text.getLines(); + } + + public String getLine(int line) + { + if (text.getLines().size() < line) + { + return null; + } + return text.getLines().get(line); + } +} diff --git a/Essentials/src/com/earth2me/essentials/textreader/TextInput.java b/Essentials/src/com/earth2me/essentials/textreader/TextInput.java new file mode 100644 index 0000000000..7de60979dc --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/textreader/TextInput.java @@ -0,0 +1,143 @@ +package com.earth2me.essentials.textreader; + +import com.earth2me.essentials.CommandSource; +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.FormatUtil; +import com.earth2me.essentials.utils.StringUtil; +import java.io.*; +import java.lang.ref.SoftReference; +import java.util.*; +import net.ess3.api.IEssentials; + + +public class TextInput implements IText +{ + private static final HashMap> cache = new HashMap>(); + private final transient List lines; + private final transient List chapters; + private final transient Map bookmarks; + private final transient long lastChange; + + public TextInput(final CommandSource sender, final String filename, final boolean createFile, final IEssentials ess) throws IOException + { + + File file = null; + if (sender.isPlayer()) + { + final User user = ess.getUser(sender.getPlayer()); + file = new File(ess.getDataFolder(), filename + "_" + StringUtil.sanitizeFileName(user.getName()) + ".txt"); + if (!file.exists()) + { + file = new File(ess.getDataFolder(), filename + "_" + StringUtil.sanitizeFileName(user.getGroup()) + ".txt"); + } + } + if (file == null || !file.exists()) + { + file = new File(ess.getDataFolder(), filename + ".txt"); + } + if (file.exists()) + { + lastChange = file.lastModified(); + boolean readFromfile; + synchronized (cache) + { + final SoftReference inputRef = cache.get(file.getName()); + TextInput input; + if (inputRef == null || (input = inputRef.get()) == null || input.lastChange < lastChange) + { + lines = new ArrayList(); + chapters = new ArrayList(); + bookmarks = new HashMap(); + cache.put(file.getName(), new SoftReference(this)); + readFromfile = true; + } + else + { + lines = Collections.unmodifiableList(input.getLines()); + chapters = Collections.unmodifiableList(input.getChapters()); + bookmarks = Collections.unmodifiableMap(input.getBookmarks()); + readFromfile = false; + } + } + if (readFromfile) + { + final Reader reader = new InputStreamReader(new FileInputStream(file), "utf-8"); + final BufferedReader bufferedReader = new BufferedReader(reader); + try + { + int lineNumber = 0; + while (bufferedReader.ready()) + { + final String line = bufferedReader.readLine(); + if (line == null) + { + break; + } + if (line.length() > 1 && line.charAt(0) == '#') + { + String[] titles = line.substring(1).trim().replace(" ", "_").split(","); + chapters.add(FormatUtil.replaceFormat(titles[0])); + for (String title : titles) + { + bookmarks.put(FormatUtil.stripEssentialsFormat(title.toLowerCase(Locale.ENGLISH)), lineNumber); + } + } + lines.add(FormatUtil.replaceFormat(line)); + lineNumber++; + } + } + finally + { + reader.close(); + bufferedReader.close(); + } + } + } + else + { + lastChange = 0; + lines = Collections.emptyList(); + chapters = Collections.emptyList(); + bookmarks = Collections.emptyMap(); + if (createFile) + { + final InputStream input = ess.getResource(filename + ".txt"); + final OutputStream output = new FileOutputStream(file); + try + { + final byte[] buffer = new byte[1024]; + int length = input.read(buffer); + while (length > 0) + { + output.write(buffer, 0, length); + length = input.read(buffer); + } + } + finally + { + output.close(); + input.close(); + } + throw new FileNotFoundException("File " + filename + ".txt does not exist. Creating one for you."); + } + } + } + + @Override + public List getLines() + { + return lines; + } + + @Override + public List getChapters() + { + return chapters; + } + + @Override + public Map getBookmarks() + { + return bookmarks; + } +} diff --git a/Essentials/src/com/earth2me/essentials/textreader/TextPager.java b/Essentials/src/com/earth2me/essentials/textreader/TextPager.java new file mode 100644 index 0000000000..13b8aca001 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/textreader/TextPager.java @@ -0,0 +1,173 @@ +package com.earth2me.essentials.textreader; + +import com.earth2me.essentials.CommandSource; +import com.earth2me.essentials.I18n; +import static com.earth2me.essentials.I18n.tl; +import java.util.List; +import java.util.Locale; +import java.util.Map; + + +public class TextPager +{ + private final transient IText text; + private final transient boolean onePage; + + public TextPager(final IText text) + { + this(text, false); + } + + public TextPager(final IText text, final boolean onePage) + { + this.text = text; + this.onePage = onePage; + } + + public void showPage(final String pageStr, final String chapterPageStr, final String commandName, final CommandSource sender) + { + List lines = text.getLines(); + List chapters = text.getChapters(); + Map bookmarks = text.getBookmarks(); + + //This code deals with the initial chapter. We use this to display the initial output or contents. + //We also use this code to display some extra information if we don't intend to use chapters + if (pageStr == null || pageStr.isEmpty() || pageStr.matches("[0-9]+")) + { + //If an info file starts with a chapter title, list the chapters + //If not display the text up until the first chapter. + if (!lines.isEmpty() && lines.get(0).startsWith("#")) + { + if (onePage) + { + return; + } + sender.sendMessage(tl("infoChapter")); + final StringBuilder sb = new StringBuilder(); + boolean first = true; + for (String string : chapters) + { + if (!first) + { + sb.append(", "); + } + first = false; + sb.append(string); + } + sender.sendMessage(sb.toString()); + return; + } + else + { + int page = 1; + try + { + page = Integer.parseInt(pageStr); + } + catch (NumberFormatException ex) + { + page = 1; + } + if (page < 1) + { + page = 1; + } + + int start = onePage ? 0 : (page - 1) * 9; + int end; + for (end = 0; end < lines.size(); end++) + { + String line = lines.get(end); + if (line.startsWith("#")) + { + break; + } + } + + int pages = end / 9 + (end % 9 > 0 ? 1 : 0); + if (!onePage && commandName != null) + { + + StringBuilder content = new StringBuilder(); + final String[] title = commandName.split(" ", 2); + if (title.length > 1) + { + content.append(I18n.capitalCase(title[0])).append(": "); + content.append(title[1]); + } + else + { + content.append(I18n.capitalCase(commandName)); + } + sender.sendMessage(tl("infoPages", page, pages, content)); + } + for (int i = start; i < end && i < start + (onePage ? 20 : 9); i++) + { + sender.sendMessage("§r" + lines.get(i)); + } + if (!onePage && page < pages && commandName != null) + { + sender.sendMessage(tl("readNextPage", commandName, page + 1)); + } + return; + } + } + + //If we have a chapter, check to see if we have a page number + int chapterpage = 0; + if (chapterPageStr != null) + { + try + { + chapterpage = Integer.parseInt(chapterPageStr) - 1; + } + catch (NumberFormatException ex) + { + chapterpage = 0; + } + if (chapterpage < 0) + { + chapterpage = 0; + } + } + + //This checks to see if we have the chapter in the index + if (!bookmarks.containsKey(pageStr.toLowerCase(Locale.ENGLISH))) + { + sender.sendMessage(tl("infoUnknownChapter")); + return; + } + + //Since we have a valid chapter, count the number of lines in the chapter + final int chapterstart = bookmarks.get(pageStr.toLowerCase(Locale.ENGLISH)) + 1; + int chapterend; + for (chapterend = chapterstart; chapterend < lines.size(); chapterend++) + { + final String line = lines.get(chapterend); + if (line.length() > 0 && line.charAt(0) == '#') + { + break; + } + } + + //Display the chapter from the starting position + final int start = chapterstart + (onePage ? 0 : chapterpage * 9); + final int page = chapterpage + 1; + final int pages = (chapterend - chapterstart) / 9 + ((chapterend - chapterstart) % 9 > 0 ? 1 : 0); + if (!onePage && commandName != null) + { + StringBuilder content = new StringBuilder(); + content.append(I18n.capitalCase(commandName)).append(": "); + content.append(pageStr); + sender.sendMessage(tl("infoChapterPages", content, page, pages)); + } + for (int i = start; i < chapterend && i < start + (onePage ? 20 : 9); i++) + { + sender.sendMessage("§r" + lines.get(i)); + } + if (!onePage && page < pages && commandName != null) + { + sender.sendMessage(tl("readNextPage", commandName, pageStr + " " + (page + 1))); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/utils/DateUtil.java b/Essentials/src/com/earth2me/essentials/utils/DateUtil.java new file mode 100644 index 0000000000..77a374f885 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/utils/DateUtil.java @@ -0,0 +1,182 @@ +package com.earth2me.essentials.utils; + +import static com.earth2me.essentials.I18n.tl; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +public class DateUtil +{ + private static Pattern timePattern = Pattern.compile("(?:([0-9]+)\\s*y[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*mo[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*w[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*d[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*h[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*m[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*(?:s[a-z]*)?)?", Pattern.CASE_INSENSITIVE); + + public static String removeTimePattern(String input) + { + return timePattern.matcher(input).replaceFirst("").trim(); + } + + public static long parseDateDiff(String time, boolean future) throws Exception + { + Matcher m = timePattern.matcher(time); + int years = 0; + int months = 0; + int weeks = 0; + int days = 0; + int hours = 0; + int minutes = 0; + int seconds = 0; + boolean found = false; + while (m.find()) + { + if (m.group() == null || m.group().isEmpty()) + { + continue; + } + for (int i = 0; i < m.groupCount(); i++) + { + if (m.group(i) != null && !m.group(i).isEmpty()) + { + found = true; + break; + } + } + if (found) + { + if (m.group(1) != null && !m.group(1).isEmpty()) + { + years = Integer.parseInt(m.group(1)); + } + if (m.group(2) != null && !m.group(2).isEmpty()) + { + months = Integer.parseInt(m.group(2)); + } + if (m.group(3) != null && !m.group(3).isEmpty()) + { + weeks = Integer.parseInt(m.group(3)); + } + if (m.group(4) != null && !m.group(4).isEmpty()) + { + days = Integer.parseInt(m.group(4)); + } + if (m.group(5) != null && !m.group(5).isEmpty()) + { + hours = Integer.parseInt(m.group(5)); + } + if (m.group(6) != null && !m.group(6).isEmpty()) + { + minutes = Integer.parseInt(m.group(6)); + } + if (m.group(7) != null && !m.group(7).isEmpty()) + { + seconds = Integer.parseInt(m.group(7)); + } + break; + } + } + if (!found) + { + throw new Exception(tl("illegalDate")); + } + Calendar c = new GregorianCalendar(); + if (years > 0) + { + c.add(Calendar.YEAR, years * (future ? 1 : -1)); + } + if (months > 0) + { + c.add(Calendar.MONTH, months * (future ? 1 : -1)); + } + if (weeks > 0) + { + c.add(Calendar.WEEK_OF_YEAR, weeks * (future ? 1 : -1)); + } + if (days > 0) + { + c.add(Calendar.DAY_OF_MONTH, days * (future ? 1 : -1)); + } + if (hours > 0) + { + c.add(Calendar.HOUR_OF_DAY, hours * (future ? 1 : -1)); + } + if (minutes > 0) + { + c.add(Calendar.MINUTE, minutes * (future ? 1 : -1)); + } + if (seconds > 0) + { + c.add(Calendar.SECOND, seconds * (future ? 1 : -1)); + } + Calendar max = new GregorianCalendar(); + max.add(Calendar.YEAR, 10); + if (c.after(max)) + { + return max.getTimeInMillis(); + } + return c.getTimeInMillis(); + } + + static int dateDiff(int type, Calendar fromDate, Calendar toDate, boolean future) + { + int diff = 0; + long savedDate = fromDate.getTimeInMillis(); + while ((future && !fromDate.after(toDate)) || (!future && !fromDate.before(toDate))) + { + savedDate = fromDate.getTimeInMillis(); + fromDate.add(type, future ? 1 : -1); + diff++; + } + diff--; + fromDate.setTimeInMillis(savedDate); + return diff; + } + + public static String formatDateDiff(long date) + { + Calendar c = new GregorianCalendar(); + c.setTimeInMillis(date); + Calendar now = new GregorianCalendar(); + return DateUtil.formatDateDiff(now, c); + } + + public static String formatDateDiff(Calendar fromDate, Calendar toDate) + { + boolean future = false; + if (toDate.equals(fromDate)) + { + return tl("now"); + } + if (toDate.after(fromDate)) + { + future = true; + } + StringBuilder sb = new StringBuilder(); + int[] types = new int[] + { + Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH, Calendar.HOUR_OF_DAY, Calendar.MINUTE, Calendar.SECOND + }; + String[] names = new String[] + { + tl("year"), tl("years"), tl("month"), tl("months"), tl("day"), tl("days"), tl("hour"), tl("hours"), tl("minute"), tl("minutes"), tl("second"), tl("seconds") + }; + int accuracy = 0; + for (int i = 0; i < types.length; i++) + { + if (accuracy > 2) + { + break; + } + int diff = dateDiff(types[i], fromDate, toDate, future); + if (diff > 0) + { + accuracy++; + sb.append(" ").append(diff).append(" ").append(names[i * 2 + (diff > 1 ? 1 : 0)]); + } + } + if (sb.length() == 0) + { + return "now"; + } + return sb.toString().trim(); + } +} diff --git a/Essentials/src/com/earth2me/essentials/utils/DescParseTickFormat.java b/Essentials/src/com/earth2me/essentials/utils/DescParseTickFormat.java new file mode 100644 index 0000000000..f2087f914a --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/utils/DescParseTickFormat.java @@ -0,0 +1,292 @@ +package com.earth2me.essentials.utils; + +import static com.earth2me.essentials.I18n.tl; +import java.text.SimpleDateFormat; +import java.util.*; + + +/** + * This utility class is used for converting between the ingame time in ticks to ingame time as a friendly string. Note + * that the time is INGAME. + * + * http://www.minecraftwiki.net/wiki/Day/night_cycle + * + * @author Olof Larsson + */ +public final class DescParseTickFormat +{ + // ============================================ + // First some information vars. TODO: Should this be in a config file? + // -------------------------------------------- + public static final Map nameToTicks = new LinkedHashMap(); + public static final Set resetAliases = new HashSet(); + public static final int ticksAtMidnight = 18000; + public static final int ticksPerDay = 24000; + public static final int ticksPerHour = 1000; + public static final double ticksPerMinute = 1000d / 60d; + public static final double ticksPerSecond = 1000d / 60d / 60d; + private static final SimpleDateFormat SDFTwentyFour = new SimpleDateFormat("HH:mm", Locale.ENGLISH); + private static final SimpleDateFormat SDFTwelve = new SimpleDateFormat("h:mm aa", Locale.ENGLISH); + + static + { + SDFTwentyFour.setTimeZone(TimeZone.getTimeZone("GMT")); + SDFTwelve.setTimeZone(TimeZone.getTimeZone("GMT")); + + nameToTicks.put("sunrise", 23000); + nameToTicks.put("dawn", 23000); + + nameToTicks.put("daystart", 0); + nameToTicks.put("day", 0); + + nameToTicks.put("morning", 1000); + + nameToTicks.put("midday", 6000); + nameToTicks.put("noon", 6000); + + nameToTicks.put("afternoon", 9000); + + nameToTicks.put("sunset", 12000); + nameToTicks.put("dusk", 12000); + nameToTicks.put("sundown", 12000); + nameToTicks.put("nightfall", 12000); + + nameToTicks.put("nightstart", 14000); + nameToTicks.put("night", 14000); + + nameToTicks.put("midnight", 18000); + + resetAliases.add("reset"); + resetAliases.add("normal"); + resetAliases.add("default"); + } + + // ============================================ + public static long parse(String desc) throws NumberFormatException + { + // Only look at alphanumeric and lowercase and : for 24:00 + desc = desc.toLowerCase(Locale.ENGLISH).replaceAll("[^A-Za-z0-9:]", ""); + + // Detect ticks format + try + { + return parseTicks(desc); + } + catch (NumberFormatException e) + { + } + + // Detect 24-hour format + try + { + return parse24(desc); + } + catch (NumberFormatException e) + { + } + + // Detect 12-hour format + try + { + return parse12(desc); + } + catch (NumberFormatException e) + { + } + + // Detect aliases + try + { + return parseAlias(desc); + } + catch (NumberFormatException e) + { + } + + // Well we failed to understand... + throw new NumberFormatException(); + } + public static long parseTicks(String desc) throws NumberFormatException + { + if (!desc.matches("^[0-9]+ti?c?k?s?$")) + { + throw new NumberFormatException(); + } + + desc = desc.replaceAll("[^0-9]", ""); + + return Long.parseLong(desc) % 24000; + } + + public static long parse24(String desc) throws NumberFormatException + { + if (!desc.matches("^[0-9]{2}[^0-9]?[0-9]{2}$")) + { + throw new NumberFormatException(); + } + + desc = desc.toLowerCase(Locale.ENGLISH).replaceAll("[^0-9]", ""); + + if (desc.length() != 4) + { + throw new NumberFormatException(); + } + + final int hours = Integer.parseInt(desc.substring(0, 2)); + final int minutes = Integer.parseInt(desc.substring(2, 4)); + + return hoursMinutesToTicks(hours, minutes); + } + + public static long parse12(String desc) throws NumberFormatException + { + if (!desc.matches("^[0-9]{1,2}([^0-9]?[0-9]{2})?(pm|am)$")) + { + throw new NumberFormatException(); + } + + int hours = 0; + int minutes = 0; + + desc = desc.toLowerCase(Locale.ENGLISH); + String parsetime = desc.replaceAll("[^0-9]", ""); + + if (parsetime.length() > 4) + { + throw new NumberFormatException(); + } + + if (parsetime.length() == 4) + { + hours += Integer.parseInt(parsetime.substring(0, 2)); + minutes += Integer.parseInt(parsetime.substring(2, 4)); + } + else if (parsetime.length() == 3) + { + hours += Integer.parseInt(parsetime.substring(0, 1)); + minutes += Integer.parseInt(parsetime.substring(1, 3)); + } + else if (parsetime.length() == 2) + { + hours += Integer.parseInt(parsetime.substring(0, 2)); + } + else if (parsetime.length() == 1) + { + hours += Integer.parseInt(parsetime.substring(0, 1)); + } + else + { + throw new NumberFormatException(); + } + + if (desc.endsWith("pm") && hours != 12) + { + hours += 12; + } + + if (desc.endsWith("am") && hours == 12) + { + hours -= 12; + } + + return hoursMinutesToTicks(hours, minutes); + } + + public static long hoursMinutesToTicks(final int hours, final int minutes) + { + long ret = ticksAtMidnight; + ret += (hours) * ticksPerHour; + + ret += (minutes / 60.0) * ticksPerHour; + + ret %= ticksPerDay; + return ret; + } + + public static long parseAlias(final String desc) throws NumberFormatException + { + final Integer ret = nameToTicks.get(desc); + if (ret == null) + { + throw new NumberFormatException(); + } + + return ret; + } + + public static boolean meansReset(final String desc) + { + return resetAliases.contains(desc); + } + + // ============================================ + public static String format(final long ticks) + { + return tl("timeFormat", format24(ticks), format12(ticks), formatTicks(ticks)); + } + public static String formatTicks(final long ticks) + { + return (ticks % ticksPerDay) + "ticks"; + } + + public static String format24(final long ticks) + { + synchronized (SDFTwentyFour) + { + return formatDateFormat(ticks, SDFTwentyFour); + } + } + + public static String format12(final long ticks) + { + synchronized (SDFTwelve) + { + return formatDateFormat(ticks, SDFTwelve); + } + } + + public static String formatDateFormat(final long ticks, final SimpleDateFormat format) + { + final Date date = ticksToDate(ticks); + return format.format(date); + } + + public static Date ticksToDate(long ticks) + { + // Assume the server time starts at 0. It would start on a day. + // But we will simulate that the server started with 0 at midnight. + ticks = ticks - ticksAtMidnight + ticksPerDay; + + // How many ingame days have passed since the server start? + final long days = ticks / ticksPerDay; + ticks -= days * ticksPerDay; + + // How many hours on the last day? + final long hours = ticks / ticksPerHour; + ticks -= hours * ticksPerHour; + + // How many minutes on the last day? + final long minutes = (long)Math.floor(ticks / ticksPerMinute); + final double dticks = ticks - minutes * ticksPerMinute; + + // How many seconds on the last day? + final long seconds = (long)Math.floor(dticks / ticksPerSecond); + + // Now we create an english GMT calendar (We wan't no daylight savings) + final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"), Locale.ENGLISH); + cal.setLenient(true); + + // And we set the time to 0! And append the time that passed! + cal.set(0, Calendar.JANUARY, 1, 0, 0, 0); + cal.add(Calendar.DAY_OF_YEAR, (int)days); + cal.add(Calendar.HOUR_OF_DAY, (int)hours); + cal.add(Calendar.MINUTE, (int)minutes); + cal.add(Calendar.SECOND, (int)seconds + 1); // To solve rounding errors. + + return cal.getTime(); + } + + private DescParseTickFormat() + { + } +} diff --git a/Essentials/src/com/earth2me/essentials/utils/FormatUtil.java b/Essentials/src/com/earth2me/essentials/utils/FormatUtil.java new file mode 100644 index 0000000000..8c68d746b0 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/utils/FormatUtil.java @@ -0,0 +1,152 @@ +package com.earth2me.essentials.utils; + +import java.util.regex.Pattern; +import net.ess3.api.IUser; + + +public class FormatUtil +{ + //Vanilla patterns used to strip existing formats + static final transient Pattern VANILLA_PATTERN = Pattern.compile("\u00a7+[0-9A-FK-ORa-fk-or]?"); + static final transient Pattern VANILLA_COLOR_PATTERN = Pattern.compile("\u00a7+[0-9A-Fa-f]"); + static final transient Pattern VANILLA_MAGIC_PATTERN = Pattern.compile("\u00a7+[Kk]"); + static final transient Pattern VANILLA_FORMAT_PATTERN = Pattern.compile("\u00a7+[L-ORl-or]"); + //Essentials '&' convention colour codes + static final transient Pattern REPLACE_ALL_PATTERN = Pattern.compile("(? HOLLOW_MATERIALS = new HashSet(); + private static final HashSet TRANSPARENT_MATERIALS = new HashSet(); + + static + { + HOLLOW_MATERIALS.add(Material.AIR.getId()); + HOLLOW_MATERIALS.add(Material.SAPLING.getId()); + HOLLOW_MATERIALS.add(Material.POWERED_RAIL.getId()); + HOLLOW_MATERIALS.add(Material.DETECTOR_RAIL.getId()); + HOLLOW_MATERIALS.add(Material.LONG_GRASS.getId()); + HOLLOW_MATERIALS.add(Material.DEAD_BUSH.getId()); + HOLLOW_MATERIALS.add(Material.YELLOW_FLOWER.getId()); + HOLLOW_MATERIALS.add(Material.RED_ROSE.getId()); + HOLLOW_MATERIALS.add(Material.BROWN_MUSHROOM.getId()); + HOLLOW_MATERIALS.add(Material.RED_MUSHROOM.getId()); + HOLLOW_MATERIALS.add(Material.TORCH.getId()); + HOLLOW_MATERIALS.add(Material.REDSTONE_WIRE.getId()); + HOLLOW_MATERIALS.add(Material.SEEDS.getId()); + HOLLOW_MATERIALS.add(Material.SIGN_POST.getId()); + HOLLOW_MATERIALS.add(Material.WOODEN_DOOR.getId()); + HOLLOW_MATERIALS.add(Material.LADDER.getId()); + HOLLOW_MATERIALS.add(Material.RAILS.getId()); + HOLLOW_MATERIALS.add(Material.WALL_SIGN.getId()); + HOLLOW_MATERIALS.add(Material.LEVER.getId()); + HOLLOW_MATERIALS.add(Material.STONE_PLATE.getId()); + HOLLOW_MATERIALS.add(Material.IRON_DOOR_BLOCK.getId()); + HOLLOW_MATERIALS.add(Material.WOOD_PLATE.getId()); + HOLLOW_MATERIALS.add(Material.REDSTONE_TORCH_OFF.getId()); + HOLLOW_MATERIALS.add(Material.REDSTONE_TORCH_ON.getId()); + HOLLOW_MATERIALS.add(Material.STONE_BUTTON.getId()); + HOLLOW_MATERIALS.add(Material.SNOW.getId()); + HOLLOW_MATERIALS.add(Material.SUGAR_CANE_BLOCK.getId()); + HOLLOW_MATERIALS.add(Material.DIODE_BLOCK_OFF.getId()); + HOLLOW_MATERIALS.add(Material.DIODE_BLOCK_ON.getId()); + HOLLOW_MATERIALS.add(Material.PUMPKIN_STEM.getId()); + HOLLOW_MATERIALS.add(Material.MELON_STEM.getId()); + HOLLOW_MATERIALS.add(Material.VINE.getId()); + HOLLOW_MATERIALS.add(Material.FENCE_GATE.getId()); + HOLLOW_MATERIALS.add(Material.WATER_LILY.getId()); + HOLLOW_MATERIALS.add(Material.NETHER_WARTS.getId()); + HOLLOW_MATERIALS.add(Material.CARPET.getId()); + + for (Integer integer : HOLLOW_MATERIALS) + { + TRANSPARENT_MATERIALS.add(integer.byteValue()); + } + TRANSPARENT_MATERIALS.add((byte)Material.WATER.getId()); + TRANSPARENT_MATERIALS.add((byte)Material.STATIONARY_WATER.getId()); + } + public static final int RADIUS = 3; + public static final Vector3D[] VOLUME; + + public static ItemStack convertBlockToItem(final Block block) + { + final ItemStack is = new ItemStack(block.getType(), 1, (short)0, block.getData()); + switch (is.getType()) + { + case WOODEN_DOOR: + is.setType(Material.WOOD_DOOR); + is.setDurability((short)0); + break; + case IRON_DOOR_BLOCK: + is.setType(Material.IRON_DOOR); + is.setDurability((short)0); + break; + case SIGN_POST: + case WALL_SIGN: + is.setType(Material.SIGN); + is.setDurability((short)0); + break; + case CROPS: + is.setType(Material.SEEDS); + is.setDurability((short)0); + break; + case CAKE_BLOCK: + is.setType(Material.CAKE); + is.setDurability((short)0); + break; + case BED_BLOCK: + is.setType(Material.BED); + is.setDurability((short)0); + break; + case REDSTONE_WIRE: + is.setType(Material.REDSTONE); + is.setDurability((short)0); + break; + case REDSTONE_TORCH_OFF: + case REDSTONE_TORCH_ON: + is.setType(Material.REDSTONE_TORCH_ON); + is.setDurability((short)0); + break; + case DIODE_BLOCK_OFF: + case DIODE_BLOCK_ON: + is.setType(Material.DIODE); + is.setDurability((short)0); + break; + case DOUBLE_STEP: + is.setType(Material.STEP); + break; + case TORCH: + case RAILS: + case LADDER: + case WOOD_STAIRS: + case COBBLESTONE_STAIRS: + case LEVER: + case STONE_BUTTON: + case FURNACE: + case DISPENSER: + case PUMPKIN: + case JACK_O_LANTERN: + case WOOD_PLATE: + case STONE_PLATE: + case PISTON_STICKY_BASE: + case PISTON_BASE: + case IRON_FENCE: + case THIN_GLASS: + case TRAP_DOOR: + case FENCE: + case FENCE_GATE: + case NETHER_FENCE: + is.setDurability((short)0); + break; + case FIRE: + return null; + case PUMPKIN_STEM: + is.setType(Material.PUMPKIN_SEEDS); + break; + case MELON_STEM: + is.setType(Material.MELON_SEEDS); + break; + } + return is; + } + + + public static class Vector3D + { + public int x; + public int y; + public int z; + + public Vector3D(int x, int y, int z) + { + this.x = x; + this.y = y; + this.z = z; + } + } + + static + { + List pos = new ArrayList(); + for (int x = -RADIUS; x <= RADIUS; x++) + { + for (int y = -RADIUS; y <= RADIUS; y++) + { + for (int z = -RADIUS; z <= RADIUS; z++) + { + pos.add(new Vector3D(x, y, z)); + } + } + } + Collections.sort( + pos, new Comparator() + { + @Override + public int compare(Vector3D a, Vector3D b) + { + return (a.x * a.x + a.y * a.y + a.z * a.z) - (b.x * b.x + b.y * b.y + b.z * b.z); + } + }); + VOLUME = pos.toArray(new Vector3D[0]); + } + + public static Location getTarget(final LivingEntity entity) throws Exception + { + final Block block = entity.getTargetBlock(TRANSPARENT_MATERIALS, 300); + if (block == null) + { + throw new Exception("Not targeting a block"); + } + return block.getLocation(); + } + + static boolean isBlockAboveAir(final World world, final int x, final int y, final int z) + { + if (y > world.getMaxHeight()) + { + return true; + } + return HOLLOW_MATERIALS.contains(world.getBlockAt(x, y - 1, z).getType().getId()); + } + + public static boolean isBlockUnsafeForUser(final IUser user, final World world, final int x, final int y, final int z) + { + if (user.getBase().isOnline() && world.equals(user.getBase().getWorld()) + && (user.getBase().getGameMode() == GameMode.CREATIVE || user.isGodModeEnabled()) + && user.getBase().getAllowFlight()) + { + return false; + } + + if (isBlockDamaging(world, x, y, z)) + { + return true; + } + return isBlockAboveAir(world, x, y, z); + } + + public static boolean isBlockUnsafe(final World world, final int x, final int y, final int z) + { + if (isBlockDamaging(world, x, y, z)) + { + return true; + } + return isBlockAboveAir(world, x, y, z); + } + + public static boolean isBlockDamaging(final World world, final int x, final int y, final int z) + { + final Block below = world.getBlockAt(x, y - 1, z); + if (below.getType() == Material.LAVA || below.getType() == Material.STATIONARY_LAVA) + { + return true; + } + if (below.getType() == Material.FIRE) + { + return true; + } + if (below.getType() == Material.BED_BLOCK) + { + return true; + } + if ((!HOLLOW_MATERIALS.contains(world.getBlockAt(x, y, z).getType().getId())) || (!HOLLOW_MATERIALS.contains(world.getBlockAt(x, y + 1, z).getType().getId()))) + { + return true; + } + return false; + } + + // Not needed if using getSafeDestination(loc) + public static Location getRoundedDestination(final Location loc) + { + final World world = loc.getWorld(); + int x = loc.getBlockX(); + int y = (int)Math.round(loc.getY()); + int z = loc.getBlockZ(); + return new Location(world, x + 0.5, y, z + 0.5, loc.getYaw(), loc.getPitch()); + } + + public static Location getSafeDestination(final IUser user, final Location loc) throws Exception + { + if (user.getBase().isOnline() && loc.getWorld().equals(user.getBase().getWorld()) + && (user.getBase().getGameMode() == GameMode.CREATIVE || user.isGodModeEnabled()) + && user.getBase().getAllowFlight()) + { + if (shouldFly(loc)) + { + user.getBase().setFlying(true); + } + return getRoundedDestination(loc); + } + return getSafeDestination(loc); + } + + public static Location getSafeDestination(final Location loc) throws Exception + { + if (loc == null || loc.getWorld() == null) + { + throw new Exception(tl("destinationNotSet")); + } + final World world = loc.getWorld(); + int x = loc.getBlockX(); + int y = (int)Math.round(loc.getY()); + int z = loc.getBlockZ(); + final int origX = x; + final int origY = y; + final int origZ = z; + while (isBlockAboveAir(world, x, y, z)) + { + y -= 1; + if (y < 0) + { + y = origY; + break; + } + } + if (isBlockUnsafe(world, x, y, z)) + { + x = Math.round(loc.getX()) == origX ? x - 1 : x + 1; + z = Math.round(loc.getZ()) == origZ ? z - 1 : z + 1; + } + int i = 0; + while (isBlockUnsafe(world, x, y, z)) + { + i++; + if (i >= VOLUME.length) + { + x = origX; + y = origY + RADIUS; + z = origZ; + break; + } + x = origX + VOLUME[i].x; + y = origY + VOLUME[i].y; + z = origZ + VOLUME[i].z; + } + while (isBlockUnsafe(world, x, y, z)) + { + y += 1; + if (y >= world.getMaxHeight()) + { + x += 1; + break; + } + } + while (isBlockUnsafe(world, x, y, z)) + { + y -= 1; + if (y <= 1) + { + x += 1; + y = world.getHighestBlockYAt(x, z); + if (x - 48 > loc.getBlockX()) + { + throw new Exception(tl("holeInFloor")); + } + } + } + return new Location(world, x + 0.5, y, z + 0.5, loc.getYaw(), loc.getPitch()); + } + + public static boolean shouldFly(Location loc) + { + final World world = loc.getWorld(); + final int x = loc.getBlockX(); + int y = (int)Math.round(loc.getY()); + final int z = loc.getBlockZ(); + int count = 0; + while (LocationUtil.isBlockUnsafe(world, x, y, z) && y > -1) + { + y--; + count++; + if (count > 2) + { + return true; + } + } + + return y < 0 ? true : false; + } +} diff --git a/Essentials/src/com/earth2me/essentials/utils/NumberUtil.java b/Essentials/src/com/earth2me/essentials/utils/NumberUtil.java new file mode 100644 index 0000000000..2c03d33da4 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/utils/NumberUtil.java @@ -0,0 +1,56 @@ +package com.earth2me.essentials.utils; + +import static com.earth2me.essentials.I18n.tl; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; +import net.ess3.api.IEssentials; + + +public class NumberUtil +{ + static DecimalFormat twoDPlaces = new DecimalFormat("#,###.##"); + static DecimalFormat currencyFormat = new DecimalFormat("#0.00", DecimalFormatSymbols.getInstance(Locale.US)); + + public static String shortCurrency(final BigDecimal value, final IEssentials ess) + { + return ess.getSettings().getCurrencySymbol() + formatAsCurrency(value); + } + + public static String formatDouble(final double value) + { + twoDPlaces.setRoundingMode(RoundingMode.HALF_UP); + return twoDPlaces.format(value); + } + + public static String formatAsCurrency(final BigDecimal value) + { + currencyFormat.setRoundingMode(RoundingMode.FLOOR); + String str = currencyFormat.format(value); + if (str.endsWith(".00")) + { + str = str.substring(0, str.length() - 3); + } + return str; + } + + public static String displayCurrency(final BigDecimal value, final IEssentials ess) + { + return tl("currency", ess.getSettings().getCurrencySymbol(), formatAsCurrency(value)); + } + + public static boolean isInt(final String sInt) + { + try + { + Integer.parseInt(sInt); + } + catch (NumberFormatException e) + { + return false; + } + return true; + } +} diff --git a/Essentials/src/com/earth2me/essentials/utils/StringUtil.java b/Essentials/src/com/earth2me/essentials/utils/StringUtil.java new file mode 100644 index 0000000000..6bb91313e3 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/utils/StringUtil.java @@ -0,0 +1,101 @@ +package com.earth2me.essentials.utils; + +import java.util.*; +import java.util.regex.Pattern; + + +public class StringUtil +{ + private static final Pattern INVALIDFILECHARS = Pattern.compile("[^a-z0-9-]"); + private static final Pattern STRICTINVALIDCHARS = Pattern.compile("[^a-z0-9]"); + private static final Pattern INVALIDCHARS = Pattern.compile("[^\t\n\r\u0020-\u007E\u0085\u00A0-\uD7FF\uE000-\uFFFC]"); + + //Used to clean file names before saving to disk + public static String sanitizeFileName(final String name) + { + return INVALIDFILECHARS.matcher(name.toLowerCase(Locale.ENGLISH)).replaceAll("_"); + } + + //Used to clean strings/names before saving as filenames/permissions + public static String safeString(final String string) + { + return STRICTINVALIDCHARS.matcher(string.toLowerCase(Locale.ENGLISH)).replaceAll("_"); + } + + //Less restrictive string sanitizing, when not used as perm or filename + public static String sanitizeString(final String string) + { + return INVALIDCHARS.matcher(string).replaceAll(""); + } + + public static String joinList(Object... list) + { + return joinList(", ", list); + } + + public static String joinList(String seperator, Object... list) + { + StringBuilder buf = new StringBuilder(); + for (Object each : list) + { + if (buf.length() > 0) + { + buf.append(seperator); + } + + if (each instanceof Collection) + { + buf.append(joinList(seperator, ((Collection)each).toArray())); + } + else + { + try + { + buf.append(each.toString()); + } + catch (Exception e) + { + buf.append(each.toString()); + } + } + } + return buf.toString(); + } + + public static String joinListSkip(String seperator, String skip, Object... list) + { + StringBuilder buf = new StringBuilder(); + for (Object each : list) + { + if (each.toString().equalsIgnoreCase(skip)) { + continue; + } + + if (buf.length() > 0) + { + buf.append(seperator); + } + + if (each instanceof Collection) + { + buf.append(joinListSkip(seperator, skip, ((Collection)each).toArray())); + } + else + { + try + { + buf.append(each.toString()); + } + catch (Exception e) + { + buf.append(each.toString()); + } + } + } + return buf.toString(); + } + + private StringUtil() + { + } +} diff --git a/Essentials/src/config.yml b/Essentials/src/config.yml new file mode 100644 index 0000000000..69bd4f9847 --- /dev/null +++ b/Essentials/src/config.yml @@ -0,0 +1,737 @@ +############################################################ +# +------------------------------------------------------+ # +# | Notes | # +# +------------------------------------------------------+ # +############################################################ + +# If you want to use special characters in this document, such as accented letters, you MUST save the file as UTF-8, not ANSI. +# If you receive an error when Essentials loads, ensure that: +# - No tabs are present: YAML only allows spaces +# - Indents are correct: YAML hierarchy is based entirely on indentation +# - You have "escaped" all apostrophes in your text: If you want to write "don't", for example, write "don''t" instead (note the doubled apostrophe) +# - Text with symbols is enclosed in single or double quotation marks + +# If you have problems join the Essentials help support channel: http://tiny.cc/EssentialsChat + +############################################################ +# +------------------------------------------------------+ # +# | Essentials (Global) | # +# +------------------------------------------------------+ # +############################################################ + +# A color code between 0-9 or a-f. Set to 'none' to disable. +ops-name-color: '4' + +# The character(s) to prefix all nicknames, so that you know they are not true usernames. +nickname-prefix: '~' + +# The maximum length allowed in nicknames. The nickname prefix is included in this. +max-nick-length: 15 + +# Disable this if you have any other plugin, that modifies the displayname of a user. +change-displayname: true + +# When this option is enabled, the (tab) player list will be updated with the displayname. +# The value of change-displayname (above) has to be true. +#change-playerlist: true + +# When EssentialsChat.jar isn't used, force essentials to add the prefix and suffix from permission plugins to displayname. +# This setting is ignored if EssentialsChat.jar is used, and defaults to 'true'. +# The value of change-displayname (above) has to be true. +# Do not edit this setting unless you know what you are doing! +#add-prefix-suffix: false + +# If the teleport destination is unsafe, should players be teleported to the nearest safe location? +# If this is set to true, Essentials will attempt to teleport players close to the intended destination. +# If this is set to false, attempted teleports to unsafe locations will be cancelled with a warning. +teleport-safety: true + +# The delay, in seconds, required between /home, /tp, etc. +teleport-cooldown: 0 + +# The delay, in seconds, before a user actually teleports. If the user moves or gets attacked in this timeframe, the teleport never occurs. +teleport-delay: 0 + +# The delay, in seconds, a player can't be attacked by other players after they have been teleported by a command. +# This will also prevent the player attacking other players. +teleport-invulnerability: 4 + +# The delay, in seconds, required between /heal or /feed attempts. +heal-cooldown: 60 + +# What to prevent from /item and /give. +# e.g item-spawn-blacklist: 10,11,46 +item-spawn-blacklist: + +# Set this to true if you want permission based item spawn rules. +# Note: The blacklist above will be ignored then. +# Example permissions (these go in your permissions manager): +# - essentials.itemspawn.item-all +# - essentials.itemspawn.item-[itemname] +# - essentials.itemspawn.item-[itemid] +# - essentials.give.item-all +# - essentials.give.item-[itemname] +# - essentials.give.item-[itemid] +# - essentials.unlimited.item-all +# - essentials.unlimited.item-[itemname] +# - essentials.unlimited.item-[itemid] +# - essentials.unlimited.item-bucket # Unlimited liquid placing +# +# For more information, visit http://wiki.ess3.net/wiki/Command_Reference/ICheat#Item.2FGive +permission-based-item-spawn: false + +# Mob limit on the /spawnmob command per execution. +spawnmob-limit: 10 + +# Shall we notify users when using /lightning? +warn-on-smite: true + +# The motd and rules are now configured in the files motd.txt and rules.txt. + +# When a command conflicts with another plugin, by default, Essentials will try to force the OTHER plugin to take priority. +# Commands in this list, will tell Essentials to 'not give up' the command to other plugins. +# In this state, which plugin 'wins' appears to be almost random. +# +# If you have two plugin with the same command and you wish to force Essentials to take over, you need an alias. +# To force essentials to take 'god' alias 'god' to 'egod'. +# See http://wiki.bukkit.org/Commands.yml#aliases for more information. + +overridden-commands: +# - god +# - info + +# Disabling commands here will prevent Essentials handling the command, this will not affect command conflicts. +# You should not have to disable commands used in other plugins, they will automatically get priority. +# See http://wiki.bukkit.org/Commands.yml#aliases to map commands to other plugins. +disabled-commands: +# - nick +# - clear + +# These commands will be shown to players with socialSpy enabled. +# You can add commands from other plugins you may want to track or +# remove commands that are used for something you dont want to spy on. +# Set - '*' in order to listen on all possible commands. +socialspy-commands: + - msg + - w + - r + - mail + - m + - t + - whisper + - emsg + - tell + - er + - reply + - ereply + - email + - action + - describe + - eme + - eaction + - edescribe + - etell + - ewhisper + - pm + +# If you do not wish to use a permission system, you can define a list of 'player perms' below. +# This list has no effect if you are using a supported permissions system. +# If you are using an unsupported permissions system, simply delete this section. +# Whitelist the commands and permissions you wish to give players by default (everything else is op only). +# These are the permissions without the "essentials." part. +player-commands: + - afk + - afk.auto + - back + - back.ondeath + - balance + - balance.others + - balancetop + - build + - chat.color + - chat.format + - chat.shout + - chat.question + - clearinventory + - compass + - depth + - delhome + - getpos + - geoip.show + - help + - helpop + - home + - home.others + - ignore + - info + - itemdb + - kit + - kits.tools + - list + - mail + - mail.send + - me + - motd + - msg + - msg.color + - nick + - near + - pay + - ping + - protect + - r + - rules + - realname + - seen + - sell + - sethome + - setxmpp + - signs.create.protection + - signs.create.trade + - signs.break.protection + - signs.break.trade + - signs.use.balance + - signs.use.buy + - signs.use.disposal + - signs.use.enchant + - signs.use.free + - signs.use.gamemode + - signs.use.heal + - signs.use.info + - signs.use.kit + - signs.use.mail + - signs.use.protection + - signs.use.repair + - signs.use.sell + - signs.use.time + - signs.use.trade + - signs.use.warp + - signs.use.weather + - spawn + - suicide + - time + - tpa + - tpaccept + - tpahere + - tpdeny + - warp + - warp.list + - world + - worth + - xmpp + +# Note: All items MUST be followed by a quantity! +# All kit names should be lower case, and will be treated as lower in permissions/costs. +# Syntax: - itemID[:DataValue/Durability] Amount [Enchantment:Level].. [itemmeta:value]... +# For Item Meta information visit http://wiki.ess3.net/wiki/Item_Meta +# 'delay' refers to the cooldown between how often you can use each kit, measured in seconds. +# Set delay to -1 for a one time kit. +# For more information, visit http://wiki.ess3.net/wiki/Kits +kits: + tools: + delay: 10 + items: + - 272 1 + - 273 1 + - 274 1 + - 275 1 + dtools: + delay: 600 + items: + - 278 1 efficiency:1 durability:1 fortune:1 name:&4Gigadrill lore:The_drill_that_&npierces|the_heavens + - 277 1 digspeed:3 name:Dwarf lore:Diggy|Diggy|Hole + - 298 1 color:255,255,255 name:Top_Hat lore:Good_day,_Good_day + - 279:780 1 + notch: + delay: 6000 + items: + - 397:3 1 player:Notch + color: + delay: 6000 + items: + - 387 1 title:&4Book_&9o_&6Colors author:KHobbits lore:Ingame_color_codes book:Colors + firework: + delay: 6000 + items: + - 401 1 name:Angry_Creeper color:red fade:green type:creeper power:1 + - 401 1 name:StarryNight color:yellow,orange fade:blue type:star effect:trail,twinkle power:1 + - 401 2 name:SolarWind color:yellow,orange fade:red shape:large effect:twinkle color:yellow,orange fade:red shape:ball effect:trail color:red,purple fade:pink shape:star effect:trail power:1 + +# Essentials Sign Control +# See http://wiki.ess3.net/wiki/Sign_Tutorial for instructions on how to use these. +# To enable signs, remove # symbol. To disable all signs, comment/remove each sign. +# Essentials colored sign support will be enabled when any sign types are enabled. +# Color is not an actual sign, it's for enabling using color codes on signs, when the correct permissions are given. + +enabledSigns: + #- color + #- balance + #- buy + #- sell + #- trade + #- free + #- disposal + #- warp + #- kit + #- mail + #- enchant + #- gamemode + #- heal + #- info + #- spawnmob + #- repair + #- time + #- weather + +# How many times per second can Essentials signs be interacted with per player. +# Values should be between 1-20, 20 being virtually no lag protection. +# Lower numbers will reduce the possibility of lag, but may annoy players. +sign-use-per-second: 4 + +# Backup runs a batch/bash command while saving is disabled. +backup: + # Interval in minutes. + interval: 30 + # Unless you add a valid backup command or script here, this feature will be useless. + # Use 'save-all' to simply force regular world saving without backup. + #command: 'rdiff-backup World1 backups/World1' + +# Set this true to enable permission per warp. +per-warp-permission: false + +# Sort output of /list command by groups. +# You can hide and merge the groups displayed in /list by defining the desired behaviour here. +# Detailed instructions and examples can be found on the wiki: http://wiki.ess3.net/wiki/List +list: + # To merge groups, list the groups you wish to merge + #Staff: owner admin moderator + Admins: owner admin + # To limit groups, set a max user limit + #builder: 20 + # To hide groups, set the group as hidden + #default: hidden + # Uncomment the line below to simply list all players with no grouping + #Players: '*' + +# More output to the console. +debug: false + +# Set the locale for all messages. +# If you don't set this, the default locale of the server will be used. +# For example, to set language to English, set locale to en, to use the file "messages_en.properties". +# Don't forget to remove the # in front of the line. +# For more information, visit http://wiki.ess3.net/wiki/Locale +#locale: en + +# Turn off god mode when people leave the server. +remove-god-on-disconnect: false + +# Auto-AFK +# After this timeout in seconds, the user will be set as AFK. +# This feature requires the player to have essentials.afk.auto node. +# Set to -1 for no timeout. +auto-afk: 300 + +# Auto-AFK Kick +# After this timeout in seconds, the user will be kicked from the server. +# essentials.afk.kickexempt node overrides this feature. +# Set to -1 for no timeout. +auto-afk-kick: -1 + +# Set this to true, if you want to freeze the player, if the player is AFK. +# Other players or monsters can't push the player out of AFK mode then. +# This will also enable temporary god mode for the AFK player. +# The player has to use the command /afk to leave the AFK mode. +freeze-afk-players: false + +# When the player is AFK, should he be able to pickup items? +# Enable this, when you don't want people idling in mob traps. +disable-item-pickup-while-afk: false + +# This setting controls if a player is marked as active on interaction. +# When this setting is false, the player would need to manually un-AFK using the /afk command. +cancel-afk-on-interact: true + +# Should we automatically remove afk status when a player moves? +# Player will be removed from AFK on chat/command regardless of this setting. +# Disable this to reduce server lag. +cancel-afk-on-move: true + +# You can disable the death messages of Minecraft here. +death-messages: true + +# Should players with permissions be able to join and part silently? +# You can control this with essentials.silentjoin and essentials.silentquit permissions if it is enabled. +# In addition, people with essentials.silentjoin.vanish will be vanished on join. +allow-silent-join-quit: false + +# You can set a custom join message here, set to "none" to disable. +# You may use color codes, use {USERNAME} the player's name or {PLAYER} for the player's displayname. +custom-join-message: "none" + +# You can set a custom quit message here, set to "none" to disable. +# You may use color codes, use {USERNAME} the player's name or {PLAYER} for the player's displayname. +custom-quit-message: "none" + +# Add worlds to this list, if you want to automatically disable god mode there. +no-god-in-worlds: +# - world_nether + +# Set to true to enable per-world permissions for teleporting between worlds with essentials commands. +# This applies to /world, /back, /tp[a|o][here|all], but not warps. +# Give someone permission to teleport to a world with essentials.worlds. +# This does not affect the /home command, there is a separate toggle below for this. +world-teleport-permissions: false + +# The number of items given if the quantity parameter is left out in /item or /give. +# If this number is below 1, the maximum stack size size is given. If over-sized stacks. +# are not enabled, any number higher than the maximum stack size results in more than one stack. +default-stack-size: -1 + +# Over-sized stacks are stacks that ignore the normal max stack size. +# They can be obtained using /give and /item, if the player has essentials.oversizedstacks permission. +# How many items should be in an over-sized stack? +oversized-stacksize: 64 + +# Allow repair of enchanted weapons and armor. +# If you set this to false, you can still allow it for certain players using the permission. +# essentials.repair.enchanted +repair-enchanted: true + +# Allow 'unsafe' enchantments in kits and item spawning. +# Warning: Mixing and overleveling some enchantments can cause issues with clients, servers and plugins. +unsafe-enchantments: false + +#Do you want Essentials to keep track of previous location for /back in the teleport listener? +#If you set this to true any plugin that uses teleport will have the previous location registered. +register-back-in-listener: false + +#Delay to wait before people can cause attack damage after logging in. +login-attack-delay: 5 + +#Set the max fly speed, values range from 0.1 to 1.0 +max-fly-speed: 0.8 + +#Set the max walk speed, values range from 0.1 to 1.0 +max-walk-speed: 0.8 + +#Set the maximum amount of mail that can be sent within a minute. +mails-per-minute: 1000 + +# Set the maximum time /tempban can be used for in seconds. +# Set to -1 to disable, and essentials.tempban.unlimited can be used to override. +max-tempban-time: -1 + +############################################################ +# +------------------------------------------------------+ # +# | EssentialsHome | # +# +------------------------------------------------------+ # +############################################################ + +# Allows people to set their bed at daytime. +update-bed-at-daytime: true + +# Set to true to enable per-world permissions for using homes to teleport between worlds. +# This applies to the /home only. +# Give someone permission to teleport to a world with essentials.worlds. +world-home-permissions: false + +# Allow players to have multiple homes. +# Players need essentials.sethome.multiple before they can have more than 1 home. +# You can set the default number of multiple homes using the 'default' rank below. +# To remove the home limit entirely, give people 'essentials.sethome.multiple.unlimited'. +# To grant different home amounts to different people, you need to define a 'home-rank' below. +# Create the 'home-rank' below, and give the matching permission: essentials.sethome.multiple. +# For more information, visit http://wiki.ess3.net/wiki/Multihome +sethome-multiple: + default: 3 + vip: 5 + staff: 10 + +# In this example someone with 'essentials.sethome.multiple' and 'essentials.sethome.multiple.vip' will have 5 homes. +# Remember, they MUST have both permission nodes in order to be able to set multiple homes. + +# Set the timeout, in seconds for players to accept a tpa before the request is cancelled. +# Set to 0 for no timeout. +tpa-accept-cancellation: 120 + +############################################################ +# +------------------------------------------------------+ # +# | EssentialsEco | # +# +------------------------------------------------------+ # +############################################################ + +# For more information, visit http://wiki.ess3.net/wiki/Essentials_Economy + +# Defines the balance with which new players begin. Defaults to 0. +starting-balance: 0 + +# worth-# defines the value of an item when it is sold to the server via /sell. +# These are now defined in worth.yml + +# Defines the cost to use the given commands PER USE. +# Some commands like /repair have sub-costs, check the wiki for more information. +command-costs: + # /example costs $1000 PER USE + #example: 1000 + # /kit tools costs $1500 PER USE + #kit-tools: 1500 + +# Set this to a currency symbol you want to use. +# Remember, if you want to use special characters in this document, +# such as accented letters, you MUST save the file as UTF-8, not ANSI. +currency-symbol: '$' + +# Set the maximum amount of money a player can have. +# The amount is always limited to 10 trillion because of the limitations of a java double. +max-money: 10000000000000 + +# Set the minimum amount of money a player can have (must be above the negative of max-money). +# Setting this to 0, will disable overdrafts/loans completely. Users need 'essentials.eco.loan' perm to go below 0. +min-money: -10000 + +# Enable this to log all interactions with trade/buy/sell signs and sell command. +economy-log-enabled: false + +############################################################ +# +------------------------------------------------------+ # +# | EssentialsHelp | # +# +------------------------------------------------------+ # +############################################################ + +# Show other plugins commands in help. +non-ess-in-help: true + +# Hide plugins which do not give a permission. +# You can override a true value here for a single plugin by adding a permission to a user/group. +# The individual permission is: essentials.help., anyone with essentials.* or '*' will see all help regardless. +# You can use negative permissions to remove access to just a single plugins help if the following is enabled. +hide-permissionless-help: true + +############################################################ +# +------------------------------------------------------+ # +# | EssentialsChat | # +# +------------------------------------------------------+ # +############################################################ + +# This section requires the EssentialsChat.jar to work. + +chat: + + # If EssentialsChat is installed, this will define how far a player's voice travels, in blocks. Set to 0 to make all chat global. + # Note that users with the "essentials.chat.spy" permission will hear everything, regardless of this setting. + # Users with essentials.chat.shout can override this by prefixing text with an exclamation mark (!) + # Users with essentials.chat.question can override this by prefixing text with a question mark (?) + # You can add command costs for shout/question by adding chat-shout and chat-question to the command costs section." + radius: 0 + + # Chat formatting can be done in two ways, you can either define a standard format for all chat. + # Or you can give a group specific chat format, to give some extra variation. + # For more information of chat formatting, check out the wiki: http://wiki.ess3.net/wiki/Chat_Formatting + + format: '<{DISPLAYNAME}> {MESSAGE}' + #format: '&7[{GROUP}]&r {DISPLAYNAME}&7:&r {MESSAGE}' + + group-formats: + # Default: '{WORLDNAME} {DISPLAYNAME}&7:&r {MESSAGE}' + # Admins: '{WORLDNAME} &c[{GROUP}]&r {DISPLAYNAME}&7:&c {MESSAGE}' + + # If you are using group formats make sure to remove the '#' to allow the setting to be read. + +############################################################ +# +------------------------------------------------------+ # +# | EssentialsProtect | # +# +------------------------------------------------------+ # +############################################################ + +# This section requires the EssentialsProtect.jar to work. + +protect: + + # General physics/behavior modifications. + prevent: + lava-flow: false + water-flow: false + water-bucket-flow: false + fire-spread: true + lava-fire-spread: true + flint-fire: false + lightning-fire-spread: true + portal-creation: false + tnt-explosion: false + tnt-playerdamage: false + tnt-minecart-explosion: false + tnt-minecart-playerdamage: false + fireball-explosion: false + fireball-fire: false + fireball-playerdamage: false + witherskull-explosion: false + witherskull-playerdamage: false + wither-spawnexplosion: false + wither-blockreplace: false + creeper-explosion: false + creeper-playerdamage: false + creeper-blockdamage: false + enderdragon-blockdamage: true + enderman-pickup: false + villager-death: false + # Monsters won't follow players. + # permission essentials.protect.entitytarget.bypass disables this. + entitytarget: false + # Prevent the spawning of creatures. + spawn: + creeper: false + skeleton: false + spider: false + giant: false + zombie: false + slime: false + ghast: false + pig_zombie: false + enderman: false + cave_spider: false + silverfish: false + blaze: false + magma_cube: false + ender_dragon: false + pig: false + sheep: false + cow: false + chicken: false + squid: false + wolf: false + mushroom_cow: false + snowman: false + ocelot: false + iron_golem: false + villager: false + wither: false + bat: false + witch: false + horse: false + + # Maximum height the creeper should explode. -1 allows them to explode everywhere. + # Set prevent.creeper-explosion to true, if you want to disable creeper explosions. + creeper: + max-height: -1 + + # Disable various default physics and behaviors. + disable: + # Should fall damage be disabled? + fall: false + + # Users with the essentials.protect.pvp permission will still be able to attack each other if this is set to true. + # They will be unable to attack users without that same permission node. + pvp: false + + # Should drowning damage be disabled? + # (Split into two behaviors; generally, you want both set to the same value.) + drown: false + suffocate: false + + # Should damage via lava be disabled? Items that fall into lava will still burn to a crisp. ;) + lavadmg: false + + # Should arrow damage be disabled? + projectiles: false + + # This will disable damage from touching cacti. + contactdmg: false + + # Burn, baby, burn! Should fire damage be disabled? + firedmg: false + + # Should the damage after hit by a lightning be disabled? + lightning: false + + # Should Wither damage be disabled? + wither: false + + # Disable weather options? + weather: + storm: false + thunder: false + lightning: false + +############################################################ +# +------------------------------------------------------+ # +# | EssentialsAntiBuild | # +# +------------------------------------------------------+ # +############################################################ + + # This section requires the EssentialsAntiBuild.jar to work. + + # Disable various default physics and behaviors + # For more information, visit http://wiki.ess3.net/wiki/AntiBuild + + # Should people with build: false in permissions be allowed to build? + # Set true to disable building for those people. + # Setting to false means EssentialsAntiBuild will never prevent you from building. + build: true + + # Should people with build: false in permissions be allowed to use items? + # Set true to disable using for those people. + # Setting to false means EssentialsAntiBuild will never prevent you from using items. + use: true + + # Should we tell people they are not allowed to build? + warn-on-build-disallow: true + + # For which block types would you like to be alerted? + # You can find a list of IDs in plugins/Essentials/items.csv after loading Essentials for the first time. + # 10 = lava :: 11 = still lava :: 46 = TNT :: 327 = lava bucket + alert: + on-placement: 10,11,46,327 + on-use: 327 + on-break: + + blacklist: + + # Which blocks should people be prevented from placing? + placement: 10,11,46,327 + + # Which items should people be prevented from using? + usage: 327 + + # Which blocks should people be prevented from breaking? + break: + + # Which blocks should not be pushed by pistons? + piston: + + # Which blocks should not be dispensed by dispensers + dispenser: + +############################################################ +# +------------------------------------------------------+ # +# | Essentials Spawn / New Players | # +# +------------------------------------------------------+ # +############################################################ + +# This section requires essentialsspawn.jar to work. + +newbies: + # Should we announce to the server when someone logs in for the first time? + # If so, use this format, replacing {DISPLAYNAME} with the player name. + # If not, set to '' + #announce-format: '' + announce-format: '&dWelcome {DISPLAYNAME}&d to the server!' + + # When we spawn for the first time, which spawnpoint do we use? + # Set to "none" if you want to use the spawn point of the world. + spawnpoint: newbies + + # Do we want to give users anything on first join? Set to '' to disable + # This kit will be given regardless of cost and permissions, and will not trigger the kit delay. + #kit: '' + kit: tools + +# Set this to lowest, if you want Multiverse to handle the respawning. +# Set this to high, if you want EssentialsSpawn to handle the respawning. +# Set this to highest, if you want to force EssentialsSpawn to handle the respawning. +respawn-listener-priority: high + +# When users die, should they respawn at their first home or bed, instead of the spawnpoint? +respawn-at-home: false + +# End of file <-- No seriously, you're done with configuration. diff --git a/Essentials/src/custom.txt b/Essentials/src/custom.txt new file mode 100644 index 0000000000..b765ee315b --- /dev/null +++ b/Essentials/src/custom.txt @@ -0,0 +1,33 @@ +#Customtext +&6This is the custom text commands file. + +&6This file allows you to define custom text commands. + +&6You can create a specific file for a user or a group: +&6Name it custom_username.txt or custom_groupname.txt + +&6You can use multiple pages, for example type: +&c/customtext 2 + +&6To add a custom command you need to do three things: +&e-&9 Add a section below in the custom.txt +&e-&9 Add a line to the commands.yml aliases section +&e-&9 Give players access to 'essentials.customtext' + +To add /vote, add this to commands.yml: + vote: + - customtext vote $1- + +&6The following commands can also be customized: +&c/rules /motd /news /help + +&6These support chapter customization such as:&c /rules grief +&6You can use custom aliases with these commands too. + +#vote +If you add the correct alias to commands.yml +This text here will be shown if you type /vote + +#stafflist,onlinestaff +&6Online Staff: +{PLAYERLIST:MODERATOR} {PLAYERLIST:ADMIN} {PLAYERLIST:OWNER} \ No newline at end of file diff --git a/Essentials/src/info.txt b/Essentials/src/info.txt new file mode 100644 index 0000000000..fabe982a30 --- /dev/null +++ b/Essentials/src/info.txt @@ -0,0 +1,56 @@ +This is the info file. + +This file format works with the following files: +info.txt, motd.txt, help.txt, custom.txt and rules.txt + +You can create a specific file for a user or a group: +Name it info_username.txt or info_groupname.txt + +This also works with the other files. + +Extra pages: +Type /info Colors +Type /info Tags + +If you have problem viewing this file ingame, try using /einfo. +If this works, it means another command is blocking /info. + +It can contain chapters like the Chapter1 below: + +#Chapter1 +Lines starting with # begin a new chapter +The user has to type /info Chapter1 to read this chapter + +If the file starts with a # then the user is shown a chapter selection, +when he does not select a chapter. + +#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 + +#Tags +&6Player's Display name:&r {PLAYER} +&6Player's user name:&r {USERNAME} +&6IP:&r {IP} +&6Address:&r {ADDRESS} +&6Balance:&r {BALANCE} +&6Unread mails:&r {MAILS} +&6Current world:&r {WORLD} +&6Worlds list:&r {WORLDS} +&6Number of online players:&r {ONLINE} +&6Number of unique players who joined the server:&r {UNIQUE} +&6Player list:&r {PLAYERLIST} +&6Time of server:&r {TIME} +&6Date of server:&r {DATE} +&6Time of world PM/AM:&r {WORLDTIME12} +&6Time of world:&r {WORLDTIME24} +&6Date of world:&r {WORLDDATE} +&6Plugin list:&r {PLUGINS} +&6Version of CraftBukkit:&r {VERSION} diff --git a/Essentials/src/items.csv b/Essentials/src/items.csv new file mode 100644 index 0000000000..a5376ae586 --- /dev/null +++ b/Essentials/src/items.csv @@ -0,0 +1,7449 @@ +#version: TeamCity +#If you change this file, it will not be automatically updated after the next release. +#item,id,metadata +stone,1,0 +sstone,1,0 +smoothstone,1,0 +rock,1,0 +grass,2,0 +greendirt,2,0 +greenearth,2,0 +greenland,2,0 +dirt,3,0 +earth,3,0 +land,3,0 +grasslessdirt,3,1 +grasslessearth,3,1 +grasslessland,3,1 +podzol,3,2 +cobblestone,4,0 +cstone,4,0 +cobble,4,0 +wood,5,0 +plank,5,0 +woodenplank,5,0 +woodplank,5,0 +wplank,5,0 +plankwooden,5,0 +plankwood,5,0 +plankw,5,0 +oakplank,5,0 +oakwoodenplank,5,0 +oakwoodplank,5,0 +oakwplank,5,0 +oakplankwooden,5,0 +oakplankwood,5,0 +oakplankw,5,0 +oplank,5,0 +owoodenplank,5,0 +owoodplank,5,0 +owplank,5,0 +oplankwooden,5,0 +oplankwood,5,0 +oplankw,5,0 +pineplank,5,1 +pinewoodenplank,5,1 +pinewoodplank,5,1 +pinewplank,5,1 +pineplankwooden,5,1 +pineplankwood,5,1 +pineplankw,5,1 +pplank,5,1 +pwoodenplank,5,1 +pwoodplank,5,1 +pwplank,5,1 +pplankwooden,5,1 +pplankwood,5,1 +pplankw,5,1 +darkplank,5,1 +darkwoodenplank,5,1 +darkwoodplank,5,1 +darkwplank,5,1 +darkplankwooden,5,1 +darkplankwood,5,1 +darkplankw,5,1 +dplank,5,1 +dwoodenplank,5,1 +dwoodplank,5,1 +dwplank,5,1 +dplankwooden,5,1 +dplankwood,5,1 +dplankw,5,1 +spruceplank,5,1 +sprucewoodenplank,5,1 +sprucewoodplank,5,1 +sprucewplank,5,1 +spruceplankwooden,5,1 +spruceplankwood,5,1 +spruceplankw,5,1 +splank,5,1 +swoodenplank,5,1 +swoodplank,5,1 +swplank,5,1 +splankwooden,5,1 +splankwood,5,1 +splankw,5,1 +birchplank,5,2 +birchwoodenplank,5,2 +birchwoodplank,5,2 +birchwplank,5,2 +birchplankwooden,5,2 +birchplankwood,5,2 +birchplankw,5,2 +bplank,5,2 +bwoodenplank,5,2 +bwoodplank,5,2 +bwplank,5,2 +bplankwooden,5,2 +bplankwood,5,2 +bplankw,5,2 +lightplank,5,2 +lightwoodenplank,5,2 +lightwoodplank,5,2 +lightwplank,5,2 +lightplankwooden,5,2 +lightplankwood,5,2 +lightplankw,5,2 +lplank,5,2 +lwoodenplank,5,2 +lwoodplank,5,2 +lwplank,5,2 +lplankwooden,5,2 +lplankwood,5,2 +lplankw,5,2 +whiteplank,5,2 +whitewoodenplank,5,2 +whitewoodplank,5,2 +whitewplank,5,2 +whiteplankwooden,5,2 +whiteplankwood,5,2 +whiteplankw,5,2 +wwoodenplank,5,2 +wwoodplank,5,2 +wwplank,5,2 +wplankwooden,5,2 +wplankwood,5,2 +wplankw,5,2 +jungleplank,5,3 +junglewoodenplank,5,3 +junglewoodplank,5,3 +junglewplank,5,3 +jungleplankwooden,5,3 +jungleplankwood,5,3 +jungleplankw,5,3 +jplank,5,3 +jwoodenplank,5,3 +jwoodplank,5,3 +jwplank,5,3 +jplankwooden,5,3 +jplankwood,5,3 +jplankw,5,3 +forestplank,5,3 +forestwoodenplank,5,3 +forestwoodplank,5,3 +forestwplank,5,3 +forestplankwooden,5,3 +forestplankwood,5,3 +forestplankw,5,3 +fplank,5,3 +fwoodenplank,5,3 +fwoodplank,5,3 +fwplank,5,3 +fplankwooden,5,3 +fplankwood,5,3 +fplankw,5,3 +acaciaplank,5,4 +acaciawoodenplank,5,4 +acaciawoodplank,5,4 +acaciawplank,5,4 +acaciaplankwooden,5,4 +acaciaplankwood,5,4 +acaciaplankw,5,4 +aplank,5,4 +awoodenplank,5,4 +awoodplank,5,4 +awplank,5,4 +aplankwooden,5,4 +aplankwood,5,4 +aplankw,5,4 +darkoakplank,5,5 +darkoakwoodenplank,5,5 +darkoakwoodplank,5,5 +darkoakwplank,5,5 +darkoakplankwooden,5,5 +darkoakplankwood,5,5 +darkoakplankw,5,5 +doakplank,5,5 +doakwoodenplank,5,5 +doakwoodplank,5,5 +doakwplank,5,5 +doakplankwooden,5,5 +doakplankwood,5,5 +doakplankw,5,5 +doplank,5,5 +dowoodenplank,5,5 +dowoodplank,5,5 +dowplank,5,5 +doplankwooden,5,5 +doplankwood,5,5 +doplankw,5,5 +sapling,6,0 +treesapling,6,0 +logsapling,6,0 +trunksapling,6,0 +woodsapling,6,0 +oaktreesapling,6,0 +oaklogsapling,6,0 +oaktrunksapling,6,0 +oakwoodsapling,6,0 +osapling,6,0 +otreesapling,6,0 +ologsapling,6,0 +otrunksapling,6,0 +owoodsapling,6,0 +darksapling,6,1 +darktreesapling,6,1 +darklogsapling,6,1 +darktrunksapling,6,1 +darkwoodsapling,6,1 +sprucesapling,6,1 +sprucetreesapling,6,1 +sprucelogsapling,6,1 +sprucetrunksapling,6,1 +sprucewoodsapling,6,1 +pinesapling,6,1 +pinetreesapling,6,1 +pinelogsapling,6,1 +pinetrunksapling,6,1 +pinewoodsapling,6,1 +dsapling,6,1 +dtreesapling,6,1 +dlogsapling,6,1 +dtrunksapling,6,1 +dwoodsapling,6,1 +ssapling,6,1 +streesapling,6,1 +slogsapling,6,1 +strunksapling,6,1 +swoodsapling,6,1 +psapling,6,1 +ptreesapling,6,1 +plogsapling,6,1 +ptrunksapling,6,1 +pwoodsapling,6,1 +birchsapling,6,2 +birchtreesapling,6,2 +birchlogsapling,6,2 +birchtrunksapling,6,2 +birchwoodsapling,6,2 +lightsapling,6,2 +lighttreesapling,6,2 +lightlogsapling,6,2 +lighttrunksapling,6,2 +lightwoodsapling,6,2 +whitesapling,6,2 +whitetreesapling,6,2 +whitelogsapling,6,2 +whitetrunksapling,6,2 +whitewoodsapling,6,2 +bsapling,6,2 +btreesapling,6,2 +blogsapling,6,2 +btrunksapling,6,2 +bwoodsapling,6,2 +lsapling,6,2 +ltreesapling,6,2 +llogsapling,6,2 +ltrunksapling,6,2 +lwoodsapling,6,2 +wsapling,6,2 +wtreesapling,6,2 +wlogsapling,6,2 +wtrunksapling,6,2 +wwoodsapling,6,2 +junglesapling,6,3 +jungletreesapling,6,3 +junglelogsapling,6,3 +jungletrunksapling,6,3 +junglewoodsapling,6,3 +forestsapling,6,3 +foresttreesapling,6,3 +forestlogsapling,6,3 +foresttrunksapling,6,3 +forestwoodsapling,6,3 +jsapling,6,3 +jtreesapling,6,3 +jlogsapling,6,3 +jtrunksapling,6,3 +jwoodsapling,6,3 +fsapling,6,3 +ftreesapling,6,3 +flogsapling,6,3 +ftrunksapling,6,3 +fwoodsapling,6,3 +acaciasapling,6,4 +acaciatreesapling,6,4 +acacialogsapling,6,4 +acaciatrunksapling,6,4 +acaciawoodsapling,6,4 +asapling,6,4 +atreesapling,6,4 +alogsapling,6,4 +atrunksapling,6,4 +awoodsapling,6,4 +darkoaksapling,6,5 +darkoaktreesapling,6,5 +darkoaklogsapling,6,5 +darkoaktrunksapling,6,5 +darkoakwoodsapling,6,5 +doaksapling,6,5 +doaktreesapling,6,5 +doaklogsapling,6,5 +doaktrunksapling,6,5 +dosapling,6,5 +dowoodsapling,6,5 +dotreesapling,6,5 +dologsapling,6,5 +dotrunksapling,6,5 +bedrock,7,0 +oprock,7,0 +opblock,7,0 +adminblock,7,0 +adminrock,7,0 +adminium,7,0 +water,8,0 +stationarywater,9,0 +stillwater,9,0 +swater,9,0 +lava,10,0 +stationarylava,11,0 +stilllava,11,0 +slava,11,0 +sand,12,0 +redsand,12,1 +rsand,12,1 +gravel,13,0 +goldore,14,0 +oregold,14,0 +gore,14,0 +oreg,14,0 +ogold,14,0 +goldo,14,0 +ironore,15,0 +oreiron,15,0 +irono,15,0 +oiron,15,0 +steelore,15,0 +oresteel,15,0 +steelo,15,0 +osteel,15,0 +iore,15,0 +orei,15,0 +sore,15,0 +ores,15,0 +coalore,16,0 +orecoal,16,0 +coalo,16,0 +ocoal,16,0 +core,16,0 +tree,17,0 +log,17,0 +trunk,17,0 +oak,17,0 +oaktree,17,0 +oaklog,17,0 +oaktrunk,17,0 +oakwood,17,0 +otree,17,0 +olog,17,0 +otrunk,17,0 +owood,17,0 +pine,17,1 +pinetree,17,1 +pinelog,17,1 +pinetrunk,17,1 +pinewood,17,1 +darktree,17,1 +darklog,17,1 +darktrunk,17,1 +darkwood,17,1 +spruce,17,1 +sprucetree,17,1 +sprucelog,17,1 +sprucetrunk,17,1 +sprucewood,17,1 +dtree,17,1 +dlog,17,1 +dtrunk,17,1 +dwood,17,1 +stree,17,1 +slog,17,1 +strunk,17,1 +swood,17,1 +ptree,17,1 +plog,17,1 +ptrunk,17,1 +pwood,17,1 +birch,17,2 +birchtree,17,2 +birchlog,17,2 +birchtrunk,17,2 +birchwood,17,2 +whitetree,17,2 +whitelog,17,2 +whitetrunk,17,2 +whitewood,17,2 +lighttree,17,2 +lightlog,17,2 +lighttrunk,17,2 +lightwood,17,2 +btree,17,2 +blog,17,2 +btrunk,17,2 +bwood,17,2 +wtree,17,2 +wlog,17,2 +wtrunk,17,2 +wwood,17,2 +ltree,17,2 +llog,17,2 +ltrunk,17,2 +lwood,17,2 +jungletree,17,3 +junglelog,17,3 +jungletrunk,17,3 +junglewood,17,3 +jungle,17,3 +forest,17,3 +foresttree,17,3 +forestlog,17,3 +foresttrunk,17,3 +forestwood,17,3 +jtree,17,3 +jlog,17,3 +jtrunk,17,3 +jwood,17,3 +ftree,17,3 +flog,17,3 +ftrunk,17,3 +fwood,17,3 +leaves,18,0 +leaf,18,0 +treeleaves,18,0 +logleaves,18,0 +trunkleaves,18,0 +woodleaves,18,0 +oakleaves,18,0 +oakleaf,18,0 +oleaves,18,0 +oleaf,18,0 +oaktreeleaves,18,0 +oaklogleaves,18,0 +oaktrunkleaves,18,0 +oakwoodleaves,18,0 +otreeleaves,18,0 +ologleaves,18,0 +otrunkleaves,18,0 +owoodleaves,18,0 +treeleaf,18,0 +logleaf,18,0 +trunkleaf,18,0 +woodleaf,18,0 +oaktreeleaf,18,0 +oaklogleaf,18,0 +oaktrunkleaf,18,0 +oakwoodleaf,18,0 +otreeleaf,18,0 +ologleaf,18,0 +otrunkleaf,18,0 +owoodleaf,18,0 +pineleaves,18,1 +pineleaf,18,1 +pleaves,18,1 +pleaf,18,1 +pinetreeleaves,18,1 +pinelogleaves,18,1 +pinetrunkleaves,18,1 +pinewoodleaves,18,1 +ptreeleaves,18,1 +plogleaves,18,1 +ptrunkleaves,18,1 +pwoodleaves,18,1 +spruceleaves,18,1 +spruceleaf,18,1 +sleaves,18,1 +sleaf,18,1 +sprucetreeleaves,18,1 +sprucelogleaves,18,1 +sprucetrunkleaves,18,1 +sprucewoodleaves,18,1 +streeleaves,18,1 +slogleaves,18,1 +strunkleaves,18,1 +swoodleaves,18,1 +darkleaves,18,1 +darkleaf,18,1 +dleaves,18,1 +dleaf,18,1 +darktreeleaves,18,1 +darklogleaves,18,1 +darktrunkleaves,18,1 +darkwoodleaves,18,1 +dtreeleaves,18,1 +dlogleaves,18,1 +dtrunkleaves,18,1 +dwoodleaves,18,1 +sprucetreeleaf,18,1 +sprucelogleaf,18,1 +sprucetrunkleaf,18,1 +sprucewoodleaf,18,1 +streeleaf,18,1 +slogleaf,18,1 +strunkleaf,18,1 +swoodleaf,18,1 +pinetreeleaf,18,1 +pinelogleaf,18,1 +pinetrunkleaf,18,1 +pinewoodleaf,18,1 +ptreeleaf,18,1 +plogleaf,18,1 +ptrunkleaf,18,1 +pwoodleaf,18,1 +darktreeleaf,18,1 +darklogleaf,18,1 +darktrunkleaf,18,1 +darkwoodleaf,18,1 +dtreeleaf,18,1 +dlogleaf,18,1 +dtrunkleaf,18,1 +dwoodleaf,18,1 +birchleaves,18,2 +birchleaf,18,2 +bleaves,18,2 +bleaf,18,2 +birchtreeleaves,18,2 +birchlogleaves,18,2 +birchtrunkleaves,18,2 +birchwoodleaves,18,2 +btreeleaves,18,2 +blogleaves,18,2 +btrunkleaves,18,2 +bwoodleaves,18,2 +lightleaves,18,2 +lightleaf,18,2 +lleaves,18,2 +lleaf,18,2 +lighttreeleaves,18,2 +lightlogleaves,18,2 +lighttrunkleaves,18,2 +lightwoodleaves,18,2 +ltreeleaves,18,2 +llogleaves,18,2 +ltrunkleaves,18,2 +lwoodleaves,18,2 +whiteleaves,18,2 +whiteleaf,18,2 +wleaves,18,2 +wleaf,18,2 +whitetreeleaves,18,2 +whitelogleaves,18,2 +whitetrunkleaves,18,2 +whitewoodleaves,18,2 +wtreeleaves,18,2 +wlogleaves,18,2 +wtrunkleaves,18,2 +wwoodleaves,18,2 +birchtreeleaf,18,2 +birchlogleaf,18,2 +birchtrunkleaf,18,2 +birchwoodleaf,18,2 +btreeleaf,18,2 +blogleaf,18,2 +btrunkleaf,18,2 +bwoodleaf,18,2 +lighttreeleaf,18,2 +lightlogleaf,18,2 +lighttrunkleaf,18,2 +lightwoodleaf,18,2 +ltreeleaf,18,2 +llogleaf,18,2 +ltrunkleaf,18,2 +lwoodleaf,18,2 +whitetreeleaf,18,2 +whitelogleaf,18,2 +whitetrunkleaf,18,2 +whitewoodleaf,18,2 +wtreeleaf,18,2 +wlogleaf,18,2 +wtrunkleaf,18,2 +wwoodleaf,18,2 +jungleleaves,18,3 +jungleleaf,18,3 +jleaves,18,3 +jleaf,18,3 +jungletreeleaves,18,3 +junglelogleaves,18,3 +jungletrunkleaves,18,3 +junglewoodleaves,18,3 +jtreeleaves,18,3 +jlogleaves,18,3 +jtrunkleaves,18,3 +jwoodleaves,18,3 +forestleaves,18,3 +forestleaf,18,3 +fleaves,18,3 +fleaf,18,3 +foresttreeleaves,18,3 +forestlogleaves,18,3 +foresttrunkleaves,18,3 +forestwoodleaves,18,3 +ftreeleaves,18,3 +flogleaves,18,3 +ftrunkleaves,18,3 +fwoodleaves,18,3 +jungletreeleaf,18,3 +junglelogleaf,18,3 +jungletrunkleaf,18,3 +junglewoodleaf,18,3 +jtreeleaf,18,3 +jlogleaf,18,3 +jtrunkleaf,18,3 +jwoodleaf,18,3 +foresttreeleaf,18,3 +forestlogleaf,18,3 +foresttrunkleaf,18,3 +forestwoodleaf,18,3 +ftreeleaf,18,3 +flogleaf,18,3 +ftrunkleaf,18,3 +fwoodleaf,18,3 +sponge,19,0 +glass,20,0 +blockglass,20,0 +glassblock,20,0 +lapislazuliore,21,0 +lapislazulio,21,0 +orelapislazuli,21,0 +olapislazuli,21,0 +lapisore,21,0 +lapiso,21,0 +orelapis,21,0 +olapis,21,0 +lore,21,0 +orel,21,0 +lapislazuliblock,22,0 +blocklapislazuli,22,0 +lapisblock,22,0 +blocklapis,22,0 +lblock,22,0 +blockl,22,0 +dispenser,23,0 +dispense,23,0 +sandstone,24,0 +sastone,24,0 +creepersandstone,24,1 +creepersastone,24,1 +creepsandstone,24,1 +creepsastone,24,1 +csandstone,24,1 +csastone,24,1 +hieroglyphicsandstone,24,1 +hieroglyphicsastone,24,1 +hieroglyphsandstone,24,1 +hieroglyphsastone,24,1 +hsandstone,24,1 +hsastone,24,1 +pyramidsandstone,24,1 +pyramidsastone,24,1 +psandstone,24,1 +psastone,24,1 +chiseledsandstone,24,1 +chiseledsastone,24,1 +chiselsandstone,24,1 +chiselsastone,24,1 +smoothsandstone,24,2 +smoothsastone,24,2 +ssandstone,24,2 +smsastone,24,2 +ssastone,24,2 +noteblock,25,0 +musicblock,25,0 +nblock,25,0 +mblock,25,0 +poweredtrack,27,0 +poweredrails,27,0 +poweredrail,27,0 +boostertrack,27,0 +boosterrails,27,0 +boosterrail,27,0 +powertrack,27,0 +powerrails,27,0 +powerrail,27,0 +boosttrack,27,0 +boostrails,27,0 +boostrail,27,0 +ptrack,27,0 +prails,27,0 +prail,27,0 +btrack,27,0 +brails,27,0 +brail,27,0 +detectortrack,28,0 +detectorrails,28,0 +detectorrail,28,0 +detectingtrack,28,0 +detectingrails,28,0 +detectingrail,28,0 +detecttrack,28,0 +detectrails,28,0 +detectrail,28,0 +dtrack,28,0 +drails,28,0 +drail,28,0 +stickypistonbase,29,0 +stickypiston,29,0 +stickpistonbase,29,0 +stickpiston,29,0 +stickyp,29,0 +spistonbase,29,0 +spiston,29,0 +pistonstickybase,29,0 +pistonsticky,29,0 +pistonstickbase,29,0 +pistonstick,29,0 +pistonsbase,29,0 +pistons,29,0 +psticky,29,0 +pstick,29,0 +spiderweb,30,0 +cobweb,30,0 +sweb,30,0 +cweb,30,0 +web,30,0 +longgrass,31,1 +tallgrass,31,1 +wildgrass,31,1 +grasslong,31,1 +grasstall,31,1 +grasswild,31,1 +lgrass,31,1 +tgrass,31,1 +wgrass,31,1 +fern,31,2 +bush,31,2 +deadshrub,32,0 +dshrub,32,0 +deadbush,32,0 +dbush,32,0 +deadsapling,32,0 +piston,33,0 +pistonbase,33,0 +pistonblock,33,0 +whitewool,35,0 +whitecloth,35,0 +whitecotton,35,0 +wcloth,35,0 +wwool,35,0 +wcotton,35,0 +cloth,35,0 +wool,35,0 +cotton,35,0 +orangewool,35,1 +orangecloth,35,1 +orangecotton,35,1 +ocloth,35,1 +owool,35,1 +ocotton,35,1 +magentawool,35,2 +magentacloth,35,2 +magentacotton,35,2 +mcloth,35,2 +mwool,35,2 +mcotton,35,2 +lightbluewool,35,3 +lightbluecloth,35,3 +lightbluecotton,35,3 +lbluecloth,35,3 +lbluewool,35,3 +lbluecotton,35,3 +lightblucloth,35,3 +lightbluwool,35,3 +lightblucotton,35,3 +lblucloth,35,3 +lbluwool,35,3 +lblucotton,35,3 +lbcloth,35,3 +lbwool,35,3 +lbcotton,35,3 +yellowwool,35,4 +yellowcloth,35,4 +yellowcotton,35,4 +ycloth,35,4 +ywool,35,4 +ycotton,35,4 +lightgreenwool,35,5 +lightgreencloth,35,5 +lightgreencotton,35,5 +lgreencloth,35,5 +lgreenwool,35,5 +lgreencotton,35,5 +lightgrecloth,35,5 +lightgrewool,35,5 +lightgrecotton,35,5 +lgrecloth,35,5 +lgrewool,35,5 +lgrecotton,35,5 +limecloth,35,5 +limewool,35,5 +limecotton,35,5 +lcloth,35,5 +lwool,35,5 +lcotton,35,5 +pinkwool,35,6 +pinkcloth,35,6 +pinkcotton,35,6 +picloth,35,6 +piwool,35,6 +picotton,35,6 +darkgraywool,35,7 +darkgraycloth,35,7 +darkgraycotton,35,7 +darkgreywool,35,7 +darkgreycloth,35,7 +darkgreycotton,35,7 +dgraycloth,35,7 +dgraywool,35,7 +dgraycotton,35,7 +dgreycloth,35,7 +dgreywool,35,7 +dgreycotton,35,7 +darkgracloth,35,7 +darkgrawool,35,7 +darkgracotton,35,7 +dgracloth,35,7 +dgrawool,35,7 +dgracotton,35,7 +graycloth,35,7 +graywool,35,7 +graycotton,35,7 +greycloth,35,7 +greywool,35,7 +greycotton,35,7 +gracloth,35,7 +grawool,35,7 +gracotton,35,7 +lightgraywool,35,8 +lightgraycloth,35,8 +lightgraycotton,35,8 +lgraycloth,35,8 +lgraywool,35,8 +lgraycotton,35,8 +lightgreywool,35,8 +lightgreycloth,35,8 +lightgreycotton,35,8 +lgreycloth,35,8 +lgreywool,35,8 +lgreycotton,35,8 +lightgracloth,35,8 +lightgrawool,35,8 +lightgracotton,35,8 +lgracloth,35,8 +lgrawool,35,8 +lgracotton,35,8 +silvercloth,35,8 +silverwool,35,8 +silvercotton,35,8 +sicloth,35,8 +siawool,35,8 +siacotton,35,8 +cyanwool,35,9 +cyancloth,35,9 +cyancotton,35,9 +ccloth,35,9 +cwool,35,9 +ccotton,35,9 +purplewool,35,10 +purplecloth,35,10 +purplecotton,35,10 +pucloth,35,10 +puwool,35,10 +pucotton,35,10 +bluewool,35,11 +bluecloth,35,11 +bluecotton,35,11 +blucloth,35,11 +bluwool,35,11 +blucotton,35,11 +brownwool,35,12 +browncloth,35,12 +browncotton,35,12 +brocloth,35,12 +browool,35,12 +brocotton,35,12 +darkgreenwool,35,13 +darkgreencloth,35,13 +darkgreencotton,35,13 +dgreencloth,35,13 +dgreenwool,35,13 +dgreencotton,35,13 +greencloth,35,13 +greenwool,35,13 +greencotton,35,13 +darkgrecloth,35,13 +darkgrewool,35,13 +darkgrecotton,35,13 +dgrecloth,35,13 +dgrewool,35,13 +dgrecotton,35,13 +grecloth,35,13 +grewool,35,13 +grecotton,35,13 +redwool,35,14 +redcloth,35,14 +redcotton,35,14 +rcloth,35,14 +rwool,35,14 +rcotton,35,14 +blackwool,35,15 +blackcloth,35,15 +blackcotton,35,15 +blacloth,35,15 +blawool,35,15 +blacotton,35,15 +dandelion,37,0 +yellowdandelion,37,0 +ydandelion,37,0 +yellowflower,37,0 +yflower,37,0 +flower,37,0 +rose,38,0 +redrose,38,0 +rrose,38,0 +redflower,38,0 +rflower,38,0 +poppy,38,0 +redpoppy,38,0 +blueorchid,38,1 +cyanorchid,38,1 +lightblueorchid,38,1 +lblueorchid,38,1 +orchid,38,1 +allium,38,2 +magentaallium,38,2 +azurebluet,38,3 +whiteazurebluet,38,3 +abluet,38,3 +azureb,38,3 +houstonia,38,3 +redtulip,38,4 +tulipred,38,4 +rtulip,38,4 +tulipr,38,4 +orangetulip,38,5 +tuliporange,38,5 +otulip,38,5 +tulipo,38,5 +whitetulip,38,6 +tulipwhite,38,6 +wtulip,38,6 +tulipw,38,6 +pinktulip,38,7 +tulippink,38,7 +ptulip,38,7 +tulipp,38,7 +oxeye,38,8 +daisy,38,8 +oxeyedaisy,38,8 +daisyoxeye,38,8 +moondaisy,38,8 +daisymoon,38,8 +lightgrayoxeye,38,8 +lgrayoxeye,38,8 +lightgreyoxeye,38,8 +lgreyoxeye,38,8 +brownmushroom,39,0 +brownshroom,39,0 +brownmush,39,0 +bmushroom,39,0 +bshroom,39,0 +bmush,39,0 +redmushroom,40,0 +redshroom,40,0 +redmush,40,0 +rmushroom,40,0 +rshroom,40,0 +rmush,40,0 +goldblock,41,0 +blockgold,41,0 +gblock,41,0 +blockg,41,0 +ironblock,42,0 +steelblock,42,0 +blockiron,42,0 +blocksteel,42,0 +iblock,42,0 +stblock,42,0 +blocki,42,0 +blockst,42,0 +stonedoublestep,43,0 +stonedstep,43,0 +sdoublestep,43,0 +sdstep,43,0 +doublestonestep,43,0 +dstonestep,43,0 +doublesstep,43,0 +doublestep,43,0 +dstep,43,0 +stonedoubleslab,43,0 +stonedslab,43,0 +sdoubleslab,43,0 +sdslab,43,0 +doublestoneslab,43,0 +dstoneslab,43,0 +doublesslab,43,0 +doubleslab,43,0 +dslab,43,0 +stonedoublehalfblock,43,0 +stonedhalfblock,43,0 +sdoublehalfblock,43,0 +sdhalfblock,43,0 +doublestonehalfblock,43,0 +dstonehalfblock,43,0 +doubleshalfblock,43,0 +doublehalfblock,43,0 +dhalfblock,43,0 +sandstonedoublestep,43,1 +sandstonedstep,43,1 +sstonedoublestep,43,1 +sstonedstep,43,1 +ssdoublestep,43,1 +ssdstep,43,1 +doublesandstonestep,43,1 +dsandstonestep,43,1 +doublesstonestep,43,1 +dsstonestep,43,1 +doublessstep,43,1 +dsstep,43,1 +sandstonedoubleslab,43,1 +sandstonedslab,43,1 +sstonedoubleslab,43,1 +sstonedslab,43,1 +ssdoubleslab,43,1 +ssdslab,43,1 +doublesandstoneslab,43,1 +dsandstoneslab,43,1 +doublesstoneslab,43,1 +dsstoneslab,43,1 +doublessslab,43,1 +dsslab,43,1 +sandstonedoublehalfblock,43,1 +sandstonedhalfblock,43,1 +sstonedoublehalfblock,43,1 +sstonedhalfblock,43,1 +ssdoublehalfblock,43,1 +ssdhalfblock,43,1 +doublesandstonehalfblock,43,1 +dsandstonehalfblock,43,1 +doublesstonehalfblock,43,1 +dsstonehalfblock,43,1 +doublesshalfblock,43,1 +dsshalfblock,43,1 +plankstonedoublestep,43,2 +woodenstonedoublestep,43,2 +woodenstonedstep,43,2 +woodstonedoublestep,43,2 +woodstonedstep,43,2 +wstonedoublestep,43,2 +wstonedstep,43,2 +doublewoodenstonestep,43,2 +dwoodenstonestep,43,2 +doublewoodstonestep,43,2 +dwoodstonestep,43,2 +doublewstonestep,43,2 +dwstonestep,43,2 +woodenstonedoubleslab,43,2 +woodenstonedslab,43,2 +woodstonedoubleslab,43,2 +woodstonedslab,43,2 +wstonedoubleslab,43,2 +wstonedslab,43,2 +doublewoodenstoneslab,43,2 +dwoodenstoneslab,43,2 +doublewoodstoneslab,43,2 +dwoodstoneslab,43,2 +doublewstoneslab,43,2 +dwstoneslab,43,2 +woodenstonedoublehalfblock,43,2 +woodenstonedhalfblock,43,2 +woodstonedoublehalfblock,43,2 +woodstonedhalfblock,43,2 +wstonedoublehalfblock,43,2 +wstonedhalfblock,43,2 +doublewoodenstonehalfblock,43,2 +dwoodenstonehalfblock,43,2 +doublewoodstonehalfblock,43,2 +dwoodstonehalfblock,43,2 +doublewstonehalfblock,43,2 +dwstonehalfblock,43,2 +cobblestonedoublestep,43,3 +cobblestonedstep,43,3 +cobbledoublestep,43,3 +cobbledstep,43,3 +cstonedoublestep,43,3 +cstonedstep,43,3 +csdoublestep,43,3 +csdstep,43,3 +doublecobblestonestep,43,3 +dcobblestonestep,43,3 +doublecobblestep,43,3 +dcobblestep,43,3 +doublecstonestep,43,3 +dcstonestep,43,3 +doublecsstep,43,3 +dcsstep,43,3 +cobblestonedoubleslab,43,3 +cobblestonedslab,43,3 +cobbledoubleslab,43,3 +cobbledslab,43,3 +cstonedoubleslab,43,3 +cstonedslab,43,3 +csdoubleslab,43,3 +csdslab,43,3 +doublecobblestoneslab,43,3 +dcobblestoneslab,43,3 +doublecobbleslab,43,3 +dcobbleslab,43,3 +doublecstoneslab,43,3 +dcstoneslab,43,3 +doublecsslab,43,3 +dcsslab,43,3 +cobblestonedoublehalfblock,43,3 +cobblestonedhalfblock,43,3 +cobbledoublehalfblock,43,3 +cobbledhalfblock,43,3 +cstonedoublehalfblock,43,3 +cstonedhalfblock,43,3 +csdoublehalfblock,43,3 +csdhalfblock,43,3 +doublecobblestonehalfblock,43,3 +dcobblestonehalfblock,43,3 +doublecobblehalfblock,43,3 +dcobblehalfblock,43,3 +doublecstonehalfblock,43,3 +dcstonehalfblock,43,3 +doublecshalfblock,43,3 +dcshalfblock,43,3 +brickdoublestep,43,4 +brickdstep,43,4 +bdoublestep,43,4 +bdstep,43,4 +brickdoubleslab,43,4 +brickdslab,43,4 +bdoubleslab,43,4 +bdslab,43,4 +doublebrickstep,43,4 +dbrickstep,43,4 +doublebstep,43,4 +dbstep,43,4 +doublebrickslab,43,4 +dbrickslab,43,4 +doublebslab,43,4 +dbslab,43,4 +brickdoublehalfblock,43,4 +brickdhalfblock,43,4 +bdoublehalfblock,43,4 +bdhalfblock,43,4 +doublebrickhalfblock,43,4 +dbrickhalfblock,43,4 +doublebhalfblock,43,4 +dbhalfblock,43,4 +stonebrickdoublestep,43,5 +stonebrickdstep,43,5 +stonebdoublestep,43,5 +stonebdstep,43,5 +sbrickdoublestep,43,5 +sbrickdstep,43,5 +sbdoublestep,43,5 +sbdstep,43,5 +stonebrickdoubleslab,43,5 +stonebrickdslab,43,5 +stonebdoubleslab,43,5 +stonebdslab,43,5 +sbrickdoubleslab,43,5 +sbrickdslab,43,5 +sbdoubleslab,43,5 +sbdslab,43,5 +doublestonebrickstep,43,5 +dstonebrickstep,43,5 +doublestonebstep,43,5 +dstonebstep,43,5 +doublesbrickstep,43,5 +dsbrickstep,43,5 +doublesbstep,43,5 +dsbstep,43,5 +doublestonebrickslab,43,5 +dstonebrickslab,43,5 +doublestonebslab,43,5 +dstonebslab,43,5 +doublesbrickslab,43,5 +dsbrickdslab,43,5 +doublesbslab,43,5 +dsbslab,43,5 +stonebrickdoublehalfblock,43,5 +stonebrickdhalfblock,43,5 +stonebdoublehalfblock,43,5 +stonebdhalfblock,43,5 +sbrickdoublehalfblock,43,5 +sbrickdhalfblock,43,5 +sbdoublehalfblock,43,5 +sbdhalfblock,43,5 +doublestonebrickhalfblock,43,5 +dstonebrickhalfblock,43,5 +doublestonebhalfblock,43,5 +dstonebhalfblock,43,5 +doublesbrickhalfblock,43,5 +dsbrickhalfblock,43,5 +doublesbhalfblock,43,5 +dsbhalfblock,43,5 +netherbrickdoubleslab,43,6 +hellbrickdoubleslab,43,6 +nbrickdoubleslab,43,6 +hbrickdoubleslab,43,6 +netherdoubleslab,43,6 +helldoubleslab,43,6 +nbdoubleslab,43,6 +hbdoubleslab,43,6 +hdoubleslab,43,6 +ndoubleslab,43,6 +netherbrickdoublestep,43,6 +hellbrickdoublestep,43,6 +nbrickdoublestep,43,6 +hbrickdoublestep,43,6 +netherdoublestep,43,6 +helldoublestep,43,6 +nbdoublestep,43,6 +hbdoublestep,43,6 +ndoublestep,43,6 +hdoublestep,43,6 +netherbrickdoublehalfblock,43,6 +hellbrickdoublehalfblock,43,6 +nbrickdoublehalfblock,43,6 +hbrickdoublehalfblock,43,6 +netherdoublehalfblock,43,6 +helldoublehalfblock,43,6 +nbdoublehalfblock,43,6 +hbdoublehalfblock,43,6 +ndoublehalfblock,43,6 +hdoublehalfblock,43,6 +netherbrickdslab,43,6 +hellbrickdslab,43,6 +nbrickdslab,43,6 +hbrickdslab,43,6 +netherdslab,43,6 +helldslab,43,6 +nbdslab,43,6 +hbdslab,43,6 +hdslab,43,6 +ndslab,43,6 +netherbrickdstep,43,6 +hellbrickdstep,43,6 +nbrickdstep,43,6 +hbrickdstep,43,6 +netherdstep,43,6 +helldstep,43,6 +nbdstep,43,6 +hbdstep,43,6 +ndstep,43,6 +hdstep,43,6 +netherbrickdhalfblock,43,6 +hellbrickdhalfblock,43,6 +nbrickdhalfblock,43,6 +hbrickdhalfblock,43,6 +netherdhalfblock,43,6 +helldhalfblock,43,6 +nbdhalfblock,43,6 +hbdhalfblock,43,6 +ndhalfblock,43,6 +hdhalfblock,43,6 +doublenetherbrickslab,43,6 +doublehellbrickslab,43,6 +doublenbrickslab,43,6 +doublehbrickslab,43,6 +doublenetherslab,43,6 +doublehellslab,43,6 +doublenbslab,43,6 +doublehbslab,43,6 +doublehslab,43,6 +doublenslab,43,6 +doublenetherbrickstep,43,6 +doublehellbrickstep,43,6 +doublenbrickstep,43,6 +doublehbrickstep,43,6 +doublenetherstep,43,6 +doublehellstep,43,6 +doublenbstep,43,6 +doublehbstep,43,6 +doublenstep,43,6 +doublehstep,43,6 +doublenetherbrickhalfblock,43,6 +doublehellbrickhalfblock,43,6 +doublenbrickhalfblock,43,6 +doublehbrickhalfblock,43,6 +doublenetherhalfblock,43,6 +doublehellhalfblock,43,6 +doublenbhalfblock,43,6 +doublehbhalfblock,43,6 +doublenhalfblock,43,6 +doublehhalfblock,43,6 +dnetherbrickslab,43,6 +dhellbrickslab,43,6 +dnbrickslab,43,6 +dhbrickslab,43,6 +dnetherslab,43,6 +dhellslab,43,6 +dnbslab,43,6 +dhbslab,43,6 +dhslab,43,6 +dnslab,43,6 +dnetherbrickstep,43,6 +dhellbrickstep,43,6 +dnbrickstep,43,6 +dhbrickstep,43,6 +dnetherstep,43,6 +dhellstep,43,6 +dnbstep,43,6 +dhbstep,43,6 +dnstep,43,6 +dhstep,43,6 +dnetherbrickhalfblock,43,6 +dhellbrickhalfblock,43,6 +dnbrickhalfblock,43,6 +dhbrickhalfblock,43,6 +dnetherhalfblock,43,6 +dhellhalfblock,43,6 +dnbhalfblock,43,6 +dhbhalfblock,43,6 +dnhalfblock,43,6 +dhhalfblock,43,6 +netherquartzdoublestep,43,7 +hellquartzdoublestep,43,7 +deathquartzdoublestep,43,7 +nquartzdoublestep,43,7 +hquartzdoublestep,43,7 +dquartzdoublestep,43,7 +quartzdoublestep,43,7 +nqdoublestep,43,7 +hqdoublestep,43,7 +dqdoublestep,43,7 +qdoublestep,43,7 +netherquartzdoubleslab,43,7 +hellquartzdoubleslab,43,7 +deathquartzdoubleslab,43,7 +nquartzdoubleslab,43,7 +hquartzdoubleslab,43,7 +dquartzdoubleslab,43,7 +quartzdoubleslab,43,7 +nqdoubleslab,43,7 +hqdoubleslab,43,7 +dqdoubleslab,43,7 +qdoubleslab,43,7 +netherquartzdoublehalfblock,43,7 +hellquartzdoublehalfblock,43,7 +deathquartzdoublehalfblock,43,7 +nquartzdoublehalfblock,43,7 +hquartzdoublehalfblock,43,7 +dquartzdoublehalfblock,43,7 +quartzdoublehalfblock,43,7 +nqdoublehalfblock,43,7 +hqdoublehalfblock,43,7 +dqdoublehalfblock,43,7 +qdoublehalfblock,43,7 +netherquartzdslab,43,7 +hellquartzdslab,43,7 +deathquartzdslab,43,7 +nquartzdslab,43,7 +hquartzdslab,43,7 +dquartzdslab,43,7 +quartzdslab,43,7 +nqdslab,43,7 +hqdslab,43,7 +dqdslab,43,7 +qdslab,43,7 +netherquartzdstep,43,7 +hellquartzdstep,43,7 +deathquartzdstep,43,7 +nquartzdstep,43,7 +hquartzdstep,43,7 +dquartzdstep,43,7 +quartzdstep,43,7 +nqdstep,43,7 +hqdstep,43,7 +dqdstep,43,7 +qdstep,43,7 +netherquartzdhalfblock,43,7 +hellquartzdhalfblock,43,7 +deathquartzdhalfblock,43,7 +nquartzdhalfblock,43,7 +hquartzdhalfblock,43,7 +dquartzdhalfblock,43,7 +quartzdhalfblock,43,7 +nqdhalfblock,43,7 +hqdhalfblock,43,7 +dqdhalfblock,43,7 +qdhalfblock,43,7 +doublenetherquartzslab,43,7 +doublehellquartzslab,43,7 +doubledeathquartzslab,43,7 +doublenquartzslab,43,7 +doublehquartzslab,43,7 +doubledquartzslab,43,7 +doublequartzslab,43,7 +doublenqslab,43,7 +doublehqslab,43,7 +doubledqslab,43,7 +doubleqslab,43,7 +doublenetherquartzstep,43,7 +doublehellquartzstep,43,7 +doubledeathquartzstep,43,7 +doublenquartzstep,43,7 +doublehquartzstep,43,7 +doubledquartzstep,43,7 +doublequartzstep,43,7 +doublenqstep,43,7 +doublehqstep,43,7 +doubledqstep,43,7 +doubleqstep,43,7 +doublenetherquartzhalfblock,43,7 +doublehellquartzhalfblock,43,7 +doubledeathquartzhalfblock,43,7 +doublenquartzhalfblock,43,7 +doublehquartzhalfblock,43,7 +doubledquartzhalfblock,43,7 +doublequartzhalfblock,43,7 +doublenqhalfblock,43,7 +doublehqhalfblock,43,7 +doubledqhalfblock,43,7 +doubleqhalfblock,43,7 +dnetherquartzslab,43,7 +dhellquartzslab,43,7 +ddeathquartzslab,43,7 +dnquartzslab,43,7 +dhquartzslab,43,7 +ddquartzslab,43,7 +dnqslab,43,7 +dhqslab,43,7 +ddqslab,43,7 +dnetherquartzstep,43,7 +dhellquartzstep,43,7 +ddeathquartzstep,43,7 +dnquartzstep,43,7 +dhquartzstep,43,7 +ddquartzstep,43,7 +dnqstep,43,7 +dhqstep,43,7 +ddqstep,43,7 +dnetherquartzhalfblock,43,7 +dhellquartzhalfblock,43,7 +ddeathquartzhalfblock,43,7 +dnquartzhalfblock,43,7 +dhquartzhalfblock,43,7 +ddquartzhalfblock,43,7 +dnqhalfblock,43,7 +dhqhalfblock,43,7 +ddqhalfblock,43,7 +smoothstonedoubleslab,43,8 +smoothstonedoublestep,43,8 +smoothstonedoublehalfblock,43,8 +smoothstonedslab,43,8 +smoothstonedstep,43,8 +smoothstonedhalfblock,43,8 +doublesmoothstoneslab,43,8 +doublesmoothstonestep,43,8 +doublesmoothstonehalfblock,43,8 +dsmoothstoneslab,43,8 +dsmoothstonestep,43,8 +dsmoothstonehalfblock,43,8 +smoothsandstonedoubleslab,43,9 +ssandstonedoubleslab,43,9 +ssstonedoubleslab,43,9 +sssdoubleslab,43,9 +smoothsandstonedoublestep,43,9 +ssandstonedoublestep,43,9 +ssstonedoublestep,43,9 +sssdoublestep,43,9 +smoothsandstonedoublehalfblock,43,9 +ssandstonedoublehalfblock,43,9 +ssstonedoublehalfblock,43,9 +sssdoublehalfblock,43,9 +smoothsandstonedslab,43,9 +ssandstonedslab,43,9 +ssstonedslab,43,9 +sssdslab,43,9 +smoothsandstonedstep,43,9 +ssandstonedstep,43,9 +ssstonedstep,43,9 +sssdstep,43,9 +smoothsandstonedhalfblock,43,9 +ssandstonedhalfblock,43,9 +ssstonedhalfblock,43,9 +sssdhalfblock,43,9 +doublesmoothsandstoneslab,43,9 +doublessandstoneslab,43,9 +doublessstoneslab,43,9 +doublesssslab,43,9 +doublesmoothsandstonestep,43,9 +doublessandstonestep,43,9 +doublessstonestep,43,9 +doublesssstep,43,9 +doublesmoothsandstonehalfblock,43,9 +doublessandstonehalfblock,43,9 +doublessstonehalfblock,43,9 +doublessshalfblock,43,9 +dsmoothsandstoneslab,43,9 +dssandstoneslab,43,9 +dssstoneslab,43,9 +dsssslab,43,9 +dsmoothsandstonestep,43,9 +dssandstonestep,43,9 +dssstonestep,43,9 +dsssstep,43,9 +dsmoothsandstonehalfblock,43,9 +dssandstonehalfblock,43,9 +dssstonehalfblock,43,9 +dssshalfblock,43,9 +smoothstonestep,44,0 +stonestep,44,0 +sstep,44,0 +step,44,0 +smoothstoneslab,44,0 +stoneslab,44,0 +sslab,44,0 +slab,44,0 +smoothstonehalfblock,44,0 +stonehalfblock,44,0 +shalfblock,44,0 +halfblock,44,0 +sandstonestep,44,1 +sstonestep,44,1 +ssstep,44,1 +sandstoneslab,44,1 +sstoneslab,44,1 +ssslab,44,1 +sandstonehalfblock,44,1 +sstonehalfblock,44,1 +sshalfblock,44,1 +woodenstonestep,44,2 +woodstonestep,44,2 +wstonestep,44,2 +woodenstoneslab,44,2 +woodstoneslab,44,2 +wstoneslab,44,2 +woodenstonehalfblock,44,2 +woodstonehalfblock,44,2 +wstonehalfblock,44,2 +cobblestonestep,44,3 +cobblestep,44,3 +cstonestep,44,3 +csstep,44,3 +cobblestoneslab,44,3 +cobbleslab,44,3 +cstoneslab,44,3 +csslab,44,3 +cobblestonehalfblock,44,3 +cobblehalfblock,44,3 +cstonehalfblock,44,3 +cshalfblock,44,3 +brickstep,44,4 +bstep,44,4 +brickslab,44,4 +bslab,44,4 +brickhalfblock,44,4 +bhalfblock,44,4 +stonebrickstep,44,5 +stonebstep,44,5 +sbrickstep,44,5 +sbstep,44,5 +stonebrickslab,44,5 +stonebslab,44,5 +sbrickslab,44,5 +sbslab,44,5 +stonebrickhalfblock,44,5 +stonebhalfblock,44,5 +sbrickhalfblock,44,5 +sbhalfblock,44,5 +netherbrickslab,44,6 +hellbrickslab,44,6 +nbrickslab,44,6 +hbrickslab,44,6 +netherslab,44,6 +hellslab,44,6 +nbslab,44,6 +hbslab,44,6 +hslab,44,6 +nslab,44,6 +netherbrickstep,44,6 +hellbrickstep,44,6 +nbrickstep,44,6 +hbrickstep,44,6 +netherstep,44,6 +hellstep,44,6 +nbstep,44,6 +hbstep,44,6 +nstep,44,6 +hstep,44,6 +netherbrickhalfblock,44,6 +hellbrickhalfblock,44,6 +nbrickhalfblock,44,6 +hbrickhalfblock,44,6 +netherhalfblock,44,6 +hellhalfblock,44,6 +nbhalfblock,44,6 +hbhalfblock,44,6 +nhalfblock,44,6 +hhalfblock,44,6 +netherquartzstep,44,7 +hellquartzstep,44,7 +deathquartzstep,44,7 +nquartzstep,44,7 +hquartzstep,44,7 +dquartzstep,44,7 +quartzstep,44,7 +nqstep,44,7 +hqstep,44,7 +dqstep,44,7 +qstep,44,7 +netherquartzslab,44,7 +hellquartzslab,44,7 +deathquartzslab,44,7 +nquartzslab,44,7 +hquartzslab,44,7 +dquartzslab,44,7 +quartzslab,44,7 +nqslab,44,7 +hqslab,44,7 +dqslab,44,7 +qslab,44,7 +netherquartzhalfblock,44,7 +hellquartzhalfblock,44,7 +deathquartzhalfblock,44,7 +nquartzhalfblock,44,7 +hquartzhalfblock,44,7 +dquartzhalfblock,44,7 +quartzhalfblock,44,7 +nqhalfblock,44,7 +hqhalfblock,44,7 +dqhalfblock,44,7 +qhalfblock,44,7 +brickblock,45,0 +blockbrick,45,0 +bblock,45,0 +blockb,45,0 +tnt,46,0 +tntblock,46,0 +blocktnt,46,0 +bombblock,46,0 +blockbomb,46,0 +dynamiteblock,46,0 +blockdynamite,46,0 +bomb,46,0 +dynamite,46,0 +bookcase,47,0 +casebook,47,0 +bookshelf,47,0 +shelfbook,47,0 +bookblock,47,0 +blockbook,47,0 +mossycobblestone,48,0 +mosscobblestone,48,0 +mcobblestone,48,0 +mossycobble,48,0 +mosscobble,48,0 +mcobble,48,0 +mossstone,48,0 +mossystone,48,0 +mstone,48,0 +obsidian,49,0 +obsi,49,0 +obby,49,0 +torch,50,0 +burningstick,50,0 +burnstick,50,0 +fire,51,0 +flame,51,0 +flames,51,0 +mobspawner,52,0 +mobcage,52,0 +monsterspawner,52,0 +monstercage,52,0 +mspawner,52,0 +mcage,52,0 +spawner,52,0 +cage,52,0 +woodenstairs,53,0 +woodstairs,53,0 +wstairs,53,0 +woodenstair,53,0 +woodstair,53,0 +wstair,53,0 +chest,54,0 +container,54,0 +diamondore,56,0 +crystalore,56,0 +orediamond,56,0 +orecrystal,56,0 +dore,56,0 +ored,56,0 +diamondblock,57,0 +blockdiamond,57,0 +crystalblock,57,0 +blockcrystal,57,0 +dblock,57,0 +blockd,57,0 +workbench,58,0 +craftingbench,58,0 +crafterbench,58,0 +craftbench,58,0 +worktable,58,0 +craftingtable,58,0 +craftertable,58,0 +crafttable,58,0 +wbench,58,0 +cbench,58,0 +soil,60,0 +furnace,61,0 +litfurnace,62,0 +lfurnace,62,0 +burningfurnace,62,0 +burnfurnace,62,0 +bfurnace,62,0 +ladder,65,0 +minecarttrack,66,0 +minecartrails,66,0 +minecartrail,66,0 +mcarttrack,66,0 +mcartrails,66,0 +mcartrail,66,0 +mctrack,66,0 +mcrails,66,0 +mcrail,66,0 +track,66,0 +rails,66,0 +rail,66,0 +cobblestonestairs,67,0 +cstonestairs,67,0 +stonestairs,67,0 +cobblestairs,67,0 +csstairs,67,0 +sstairs,67,0 +cstairs,67,0 +cobblestonestair,67,0 +cstonestair,67,0 +stonestair,67,0 +cobblestair,67,0 +csstair,67,0 +sstair,67,0 +cstair,67,0 +lever,69,0 +stonepressureplate,70,0 +stonepressplate,70,0 +stonepplate,70,0 +stoneplate,70,0 +spressureplate,70,0 +spressplate,70,0 +spplate,70,0 +splate,70,0 +smoothstonepressureplate,70,0 +smoothstonepressplate,70,0 +smoothstonepplate,70,0 +smoothstoneplate,70,0 +sstonepressureplate,70,0 +sstonepressplate,70,0 +sstonepplate,70,0 +sstoneplate,70,0 +woodenpressureplate,72,0 +woodenpressplate,72,0 +woodenpplate,72,0 +woodenplate,72,0 +woodpressureplate,72,0 +woodpressplate,72,0 +woodpplate,72,0 +woodplate,72,0 +wpressureplate,72,0 +wpressplate,72,0 +wpplate,72,0 +wplate,72,0 +redstoneore,73,0 +redsore,73,0 +redore,73,0 +rstoneore,73,0 +rsore,73,0 +rore,73,0 +oreredstone,73,0 +orereds,73,0 +orered,73,0 +orerstone,73,0 +orers,73,0 +orer,73,0 +redstonetorch,76,0 +rstonetorch,76,0 +redstorch,76,0 +redtorch,76,0 +rstorch,76,0 +stonebutton,77,0 +smoothstonebutton,77,0 +sstonebutton,77,0 +sbutton,77,0 +button,77,0 +snowcover,78,0 +snowcovering,78,0 +scover,78,0 +ice,79,0 +frozenwater,79,0 +waterfrozen,79,0 +freezewater,79,0 +waterfreeze,79,0 +snowblock,80,0 +blocksnow,80,0 +sblock,80,0 +blocks,80,0 +cactus,81,0 +cactuses,81,0 +cacti,81,0 +clayblock,82,0 +blockclay,82,0 +cblock,82,0 +blockc,82,0 +jukebox,84,0 +jbox,84,0 +woodenfence,85,0 +fence,85,0 +woodfence,85,0 +wfence,85,0 +fencewooden,85,0 +fencewood,85,0 +fencew,85,0 +pumpkin,86,0 +netherrack,87,0 +netherrock,87,0 +netherstone,87,0 +hellrack,87,0 +hellrock,87,0 +hellstone,87,0 +deathrack,87,0 +deathrock,87,0 +deathstone,87,0 +nrack,87,0 +nrock,87,0 +nstone,87,0 +hrack,87,0 +hrock,87,0 +hstone,87,0 +drack,87,0 +drock,87,0 +dstone,87,0 +soulsand,88,0 +slowsand,88,0 +slowmud,88,0 +ssand,88,0 +smud,88,0 +mud,88,0 +glowstone,89,0 +glowingstoneblock,89,0 +lightstoneblock,89,0 +glowstoneblock,89,0 +blockglowingstone,89,0 +blocklightstone,89,0 +blockglowstone,89,0 +glowingstone,89,0 +lightstone,89,0 +glowingblock,89,0 +lightblock,89,0 +glowblock,89,0 +lstone,89,0 +gstone,89,0 +portal,90,0 +jackolantern,91,0 +pumpkinlantern,91,0 +glowingpumpkin,91,0 +lightpumpkin,91,0 +jpumpkin,91,0 +plantren,91,0 +glowpumpkin,91,0 +gpumpkin,91,0 +lpumpkin,91,0 +lockedchest,95,0 +lockchest,95,0 +jokechest,95,0 +whiteglass,95,0 +whitesglass,95,0 +whitestainedglass,95,0 +wglass,95,0 +wsglass,95,0 +wstainedglass,95,0 +sglass,95,0 +stainedglass,95,0 +orangeglass,95,1 +orangesglass,95,1 +orangestainedglass,95,1 +oglass,95,1 +osglass,95,1 +ostainedglass,95,1 +magentaglass,95,2 +magentasglass,95,2 +magentastainedglass,95,2 +mglass,95,2 +msglass,95,2 +mstainedglass,95,2 +lightblueglass,95,3 +lightbluesglass,95,3 +lightbluestainedglass,95,3 +lblueglass,95,3 +lbluesglass,95,3 +lbluestainedglass,95,3 +lightbluglass,95,3 +lightblusglass,95,3 +lightblustainedglass,95,3 +lbluglass,95,3 +lblusglass,95,3 +lblustainedglass,95,3 +lbglass,95,3 +lbsglass,95,3 +lbstainedglass,95,3 +yellowglass,95,4 +yellowsglass,95,4 +yellowstainedglass,95,4 +yglass,95,4 +ysglass,95,4 +ystainedglass,95,4 +lightgreenglass,95,5 +lightgreensglass,95,5 +lightgreenstainedglass,95,5 +lgreenglass,95,5 +lgreensglass,95,5 +lgreenstainedglass,95,5 +lightgreglass,95,5 +lightgresglass,95,5 +lightgrestainedglass,95,5 +lgreglass,95,5 +lgresglass,95,5 +lgrestainedglass,95,5 +limeglass,95,5 +limesglass,95,5 +limestainedglass,95,5 +lglass,95,5 +lsglass,95,5 +lstainedglass,95,5 +pinkglass,95,6 +pinksglass,95,6 +pinkstainedglass,95,6 +piglass,95,6 +pisglass,95,6 +pistainedglass,95,6 +darkgrayglass,95,7 +darkgraysglass,95,7 +darkgraystainedglass,95,7 +dgrayglass,95,7 +dgraysglass,95,7 +dgraystainedglass,95,7 +darkgreyglass,95,7 +darkgreysglass,95,7 +darkgreystainedglass,95,7 +dgreyglass,95,7 +dgreysglass,95,7 +dgreystainedglass,95,7 +darkgraglass,95,7 +darkgrasglass,95,7 +darkgrastainedglass,95,7 +dgraglass,95,7 +dgrasglass,95,7 +dgrastainedglass,95,7 +grayglass,95,7 +graysglass,95,7 +graystainedglass,95,7 +greyglass,95,7 +greysglass,95,7 +greystainedglass,95,7 +graglass,95,7 +grasglass,95,7 +grastainedglass,95,7 +lightgrayglass,95,8 +lightgraysglass,95,8 +lightgraystainedglass,95,8 +lgrayglass,95,8 +lgraysglass,95,8 +lgraystainedglass,95,8 +lightgreyglass,95,8 +lightgreysglass,95,8 +lightgreystainedglass,95,8 +lgreyglass,95,8 +lgreysglass,95,8 +lgreystainedglass,95,8 +lightgraglass,95,8 +lightgrasglass,95,8 +lightgrastainedglass,95,8 +lgraglass,95,8 +lgrasglass,95,8 +lgrastainedglass,95,8 +silverglass,95,8 +silversglass,95,8 +silverstainedglass,95,8 +siglass,95,8 +siasglass,95,8 +siastainedglass,95,8 +cyanglass,95,9 +cyansglass,95,9 +cyanstainedglass,95,9 +cglass,95,9 +csglass,95,9 +cstainedglass,95,9 +purpleglass,95,10 +purplesglass,95,10 +purplestainedglass,95,10 +puglass,95,10 +pusglass,95,10 +pustainedglass,95,10 +blueglass,95,11 +bluesglass,95,11 +bluestainedglass,95,11 +bluglass,95,11 +blusglass,95,11 +blustainedglass,95,11 +brownglass,95,12 +brownsglass,95,12 +brownstainedglass,95,12 +broglass,95,12 +brosglass,95,12 +brostainedglass,95,12 +darkgreenglass,95,13 +darkgreensglass,95,13 +darkgreenstainedglass,95,13 +dgreenglass,95,13 +dgreensglass,95,13 +dgreenstainedglass,95,13 +greenglass,95,13 +greensglass,95,13 +greenstainedglass,95,13 +darkgreglass,95,13 +darkgresglass,95,13 +darkgrestainedglass,95,13 +dgreglass,95,13 +dgresglass,95,13 +dgrestainedglass,95,13 +greglass,95,13 +gresglass,95,13 +grestainedglass,95,13 +redglass,95,14 +redsglass,95,14 +redstainedglass,95,14 +rglass,95,14 +rsglass,95,14 +rstainedglass,95,14 +blackglass,95,15 +blacksglass,95,15 +blackstainedglass,95,15 +blaglass,95,15 +blasglass,95,15 +blastainedglass,95,15 +trapdoor,96,0 +doortrap,96,0 +hatch,96,0 +tdoor,96,0 +doort,96,0 +trapd,96,0 +dtrap,96,0 +silverfish,97,0 +silverfishsmoothstone,97,0 +silverfishsstone,97,0 +sfishsmoothstone,97,0 +sfishsstone,97,0 +fishsmoothstone,97,0 +fishsstone,97,0 +sfsmoothstone,97,0 +sfsstone,97,0 +trapsmoothstone,97,0 +trapsstone,97,0 +monsteregg,97,0 +monstereggsmoothstone,97,0 +monstereggsstone,97,0 +meggsmoothstone,97,0 +meggsstone,97,0 +mesmoothstone,97,0 +messtone,97,0 +silverfishcobblestone,97,1 +silverfishcstone,97,1 +sfishcobblestone,97,1 +sfishcstone,97,1 +fishcobblestone,97,1 +fishcstone,97,1 +sfcobblestone,97,1 +sfcstone,97,1 +trapcobblestone,97,1 +trapcstone,97,1 +monstereggcobblestone,97,1 +monstereggcstone,97,1 +meggcobblestone,97,1 +meggcstone,97,1 +mecobblestone,97,1 +mecstone,97,1 +silverfishstonebrick,97,2 +silverfishsbrick,97,2 +sfishstonebrick,97,2 +sfishsbrick,97,2 +fishstonebrick,97,2 +fishsbrick,97,2 +sfstonebrick,97,2 +sfsbrick,97,2 +trapstonebrick,97,2 +trapsbrick,97,2 +monstereggstonebrick,97,2 +monstereggsbrick,97,2 +meggstonebrick,97,2 +meggsbrick,97,2 +mestonebrick,97,2 +mesbrick,97,2 +silverfishmossystonebrick,97,3 +silverfishmossstonebrick,97,3 +silverfishmstonebrick,97,3 +silverfishmsbrick,97,3 +sfishmossystonebrick,97,3 +sfishmossstonebrick,97,3 +sfishmstonebrick,97,3 +sfishmsbrick,97,3 +fishmossystonebrick,97,3 +fishmossstonebrick,97,3 +fishmstonebrick,97,3 +fishmsbrick,97,3 +sfmossystonebrick,97,3 +sfmossstonebrick,97,3 +sfmstonebrick,97,3 +sfmsbrick,97,3 +trapmossystonebrick,97,3 +trapmossstonebrick,97,3 +trapmstonebrick,97,3 +trapmsbrick,97,3 +monstereggmossystonebrick,97,3 +monstereggmossstonebrick,97,3 +monstereggmstonebrick,97,3 +monstereggmsbrick,97,3 +meggmossystonebrick,97,3 +meggmossstonebrick,97,3 +meggmstonebrick,97,3 +meggmsbrick,97,3 +memossystonebrick,97,3 +memossstonebrick,97,3 +memstonebrick,97,3 +memsbrick,97,3 +silverfishcrackedstonebrick,97,4 +silverfishcrackstonebrick,97,4 +silverfishcrstonebrick,97,4 +silverfishcrsbrick,97,4 +sfishcrackedstonebrick,97,4 +sfishcrackstonebrick,97,4 +sfishcrstonebrick,97,4 +sfishcrsbrick,97,4 +fishcrackedstonebrick,97,4 +fishcrackstonebrick,97,4 +fishcrstonebrick,97,4 +fishcrsbrick,97,4 +sfcrackedstonebrick,97,4 +sfcrackstonebrick,97,4 +sfcrstonebrick,97,4 +sfcrsbrick,97,4 +trapcrackedstonebrick,97,4 +trapcrackstonebrick,97,4 +trapcrstonebrick,97,4 +trapcrsbrick,97,4 +monstereggcrackedstonebrick,97,4 +monstereggcrackstonebrick,97,4 +monstereggcrstonebrick,97,4 +monstereggcrsbrick,97,4 +meggcrackedstonebrick,97,4 +meggcrackstonebrick,97,4 +meggcrstonebrick,97,4 +meggcrsbrick,97,4 +mecrackedstonebrick,97,4 +mecrackstonebrick,97,4 +mecrstonebrick,97,4 +mecrsbrick,97,4 +silverfishcirclestonebrick,97,5 +silverfishcistonebrick,97,5 +silverfishcisbrick,97,5 +sfishcirclestonebrick,97,5 +sfishcistonebrick,97,5 +sfishcisbrick,97,5 +fishcirclestonebrick,97,5 +fishcistonebrick,97,5 +fishcisbrick,97,5 +sfcirclestonebrick,97,5 +sfcistonebrick,97,5 +sfcisbrick,97,5 +trapcirclestonebrick,97,5 +trapcistonebrick,97,5 +trapcisbrick,97,5 +monstereggcirclestonebrick,97,5 +monstereggcistonebrick,97,5 +monstereggcisbrick,97,5 +meggcirclestonebrick,97,5 +meggcistonebrick,97,5 +meggcisbrick,97,5 +mecirclestonebrick,97,5 +mecistonebrick,97,5 +mecisbrick,97,5 +stonebrick,98,0 +stonebricks,98,0 +stonebrickblock,98,0 +stonebb,98,0 +sbrick,98,0 +mossystonebrick,98,1 +mossystonebricks,98,1 +mossystonebrickblock,98,1 +mossystonebb,98,1 +mossstonebrick,98,1 +mossstonebricks,98,1 +mossstonebrickblock,98,1 +mossstonebb,98,1 +mstonebrick,98,1 +mstonebricks,98,1 +mstonebrickblock,98,1 +mstonebb,98,1 +mosssbrick,98,1 +mosssbricks,98,1 +mosssbrickblock,98,1 +mosssbb,98,1 +msbrick,98,1 +msbricks,98,1 +msbrickblock,98,1 +crackedstone,98,2 +crackedstonebrick,98,2 +crackedstonebricks,98,2 +crackedstonebrickblock,98,2 +crackedstonebb,98,2 +crackstonebrick,98,2 +crackstonebricks,98,2 +crackstonebrickblock,98,2 +crackstonebb,98,2 +crstonebrick,98,2 +crstonebricks,98,2 +crstonebrickblock,98,2 +crstonebb,98,2 +cracksbrick,98,2 +cracksbricks,98,2 +cracksbrickblock,98,2 +cracksbb,98,2 +crsbrick,98,2 +crsbricks,98,2 +crsbrickblock,98,2 +circlestone,98,3 +circlestonebrick,98,3 +circlestonebricks,98,3 +circlestonebrickblock,98,3 +circlestonebb,98,3 +cistonebrick,98,3 +cistonebricks,98,3 +cistonebrickblock,98,3 +cistonebb,98,3 +circlesbrick,98,3 +circlesbricks,98,3 +circlesbrickblock,98,3 +circlesbb,98,3 +cisbrick,98,3 +cisbricks,98,3 +cisbrickblock,98,3 +giantredmushroom,99,0 +hugeredmushroom,99,0 +bigredmushroom,99,0 +gredmushroom,99,0 +hredmushroom,99,0 +bredmushroom,99,0 +giantrmushroom,99,0 +hugermushroom,99,0 +bigrmushroom,99,0 +grmushroom,99,0 +hrmushroom,99,0 +brmushroom,99,0 +giantredmush,99,0 +hugeredmush,99,0 +bigredmush,99,0 +gredmush,99,0 +hredmush,99,0 +bredmush,99,0 +giantrmush,99,0 +hugermush,99,0 +bigrmush,99,0 +grmush,99,0 +hrmush,99,0 +brmush,99,0 +giantbrownmushroom,100,0 +hugebrownmushroom,100,0 +bigbrownmushroom,100,0 +gbrownmushroom,100,0 +hbrownmushroom,100,0 +bbrownmushroom,100,0 +giantbmushroom,100,0 +hugebmushroom,100,0 +bigbmushroom,100,0 +gbmushroom,100,0 +hbmushroom,100,0 +bbmushroom,100,0 +giantbrownmush,100,0 +hugebrownmush,100,0 +bigbrownmush,100,0 +gbrownmush,100,0 +hbrownmush,100,0 +bbrownmush,100,0 +giantbmush,100,0 +hugebmush,100,0 +bigbmush,100,0 +gbmush,100,0 +hbmush,100,0 +bbmush,100,0 +ironbars,101,0 +ironbarsb,101,0 +ironbarsblock,101,0 +ironfence,101,0 +metalbars,101,0 +metalbarsb,101,0 +metalbarsblock,101,0 +metalfence,101,0 +jailbars,101,0 +jailbarsb,101,0 +jailbarsblock,101,0 +jailfence,101,0 +mbars,101,0 +mbarsb,101,0 +mbarsblock,101,0 +mfence,101,0 +jbars,101,0 +jbarsb,101,0 +jbarsblock,101,0 +jfence,101,0 +ibars,101,0 +ibarsb,101,0 +ibarsblock,101,0 +ifence,101,0 +glasspane,102,0 +glassp,102,0 +paneglass,102,0 +pglass,102,0 +flatglass,102,0 +fglass,102,0 +skinnyglass,102,0 +glassflat,102,0 +glassf,102,0 +glassskinny,102,0 +glasss,102,0 +melon,103,0 +watermelon,103,0 +greenmelon,103,0 +melongreen,103,0 +melonblock,103,0 +watermelonblock,103,0 +greenmelonblock,103,0 +vines,106,0 +vine,106,0 +greenvines,106,0 +greenvine,106,0 +gardenvines,106,0 +gardenvine,106,0 +vinesgreen,106,0 +vinegreen,106,0 +vinesgarden,106,0 +vinegarden,106,0 +vinesg,106,0 +vineg,106,0 +gvines,106,0 +gvine,106,0 +woodgate,107,0 +woodenfencegate,107,0 +wfencegate,107,0 +woodfencegate,107,0 +woodengate,107,0 +wgate,107,0 +gate,107,0 +gardengate,107,0 +ggate,107,0 +fencegate,107,0 +fgate,107,0 +brickstairs,108,0 +redbrickstairs,108,0 +redbstairs,108,0 +rbrickstairs,108,0 +bstairs,108,0 +redstairs,108,0 +brickstair,108,0 +redbrickstair,108,0 +redbstair,108,0 +rbrickstair,108,0 +bstair,108,0 +redstair,108,0 +stonebrickstairs,109,0 +stonebstairs,109,0 +sbstairs,109,0 +cementbrickstairs,109,0 +cementstairs,109,0 +cementbstairs,109,0 +cbstairs,109,0 +greybrickstairs,109,0 +greybstairs,109,0 +greystairs,109,0 +mycelium,110,0 +purplegrass,110,0 +pinkgrass,110,0 +mycel,110,0 +swampgrass,110,0 +sgrass,110,0 +mushroomgrass,110,0 +mushgrass,110,0 +lilypad,111,0 +waterlily,111,0 +lily,111,0 +swamppad,111,0 +lpad,111,0 +wlily,111,0 +netherbrickblock,112,0 +hellbrickblock,112,0 +deathbrickblock,112,0 +nbrickblock,112,0 +hbrickblock,112,0 +dbrickblock,112,0 +netherbblock,112,0 +hellbblock,112,0 +deathbblock,112,0 +nbblock,112,0 +hbblock,112,0 +dbblock,112,0 +netherbrickfence,113,0 +hellbrickfence,113,0 +nbrickfence,113,0 +hbrickfence,113,0 +netherbfence,113,0 +hellbfence,113,0 +netherfence,113,0 +hellfence,113,0 +nbfence,113,0 +hbfence,113,0 +nfence,113,0 +hfence,113,0 +netherbrickstairs,114,0 +hellbrickstairs,114,0 +nbrickstairs,114,0 +hbrickstairs,114,0 +netherbstairs,114,0 +hellbstairs,114,0 +netherstairs,114,0 +hellstairs,114,0 +nbstairs,114,0 +hbstairs,114,0 +nstairs,114,0 +hstairs,114,0 +netherbrickstair,114,0 +hellbrickstair,114,0 +nbrickstair,114,0 +hbrickstair,114,0 +netherbstair,114,0 +hellbstair,114,0 +netherstair,114,0 +hellstair,114,0 +nbstair,114,0 +hbstair,114,0 +nstair,114,0 +hstair,114,0 +enchantmenttable,116,0 +enchantingtable,116,0 +enchanttable,116,0 +etable,116,0 +magicaltable,116,0 +magictable,116,0 +mtable,116,0 +enchantmentdesk,116,0 +enchantingdesk,116,0 +enchantdesk,116,0 +edesk,116,0 +magicaldesk,116,0 +magicdesk,116,0 +mdesk,116,0 +booktable,116,0 +bookdesk,116,0 +btable,116,0 +bdesk,116,0 +enderportal,119,0 +endergoo,119,0 +endgoo,119,0 +endportal,119,0 +egoo,119,0 +eportal,119,0 +enderportalframe,120,0 +endportalframe,120,0 +endgooframe,120,0 +endergooframe,120,0 +egooframe,120,0 +eportalframe,120,0 +enderframe,120,0 +endframe,120,0 +enderstone,121,0 +endstone,121,0 +endrock,121,0 +enderrock,121,0 +erock,121,0 +estone,121,0 +enderdragonegg,122,0 +endegg,122,0 +dragonegg,122,0 +degg,122,0 +bossegg,122,0 +begg,122,0 +redstonelamp,123,0 +redlamp,123,0 +rslamp,123,0 +woodendoublestep,125,0 +woodendstep,125,0 +wooddoublestep,125,0 +wooddstep,125,0 +wdoublestep,125,0 +wdstep,125,0 +doublewoodenstep,125,0 +dwoodenstep,125,0 +doublewoodstep,125,0 +dwoodstep,125,0 +doublewstep,125,0 +dwstep,125,0 +woodendoubleslab,125,0 +woodendslab,125,0 +wooddoubleslab,125,0 +wooddslab,125,0 +wdoubleslab,125,0 +wdslab,125,0 +doublewoodenslab,125,0 +dwoodenslab,125,0 +doublewoodslab,125,0 +dwoodslab,125,0 +doublewslab,125,0 +dwslab,125,0 +woodendoublehalfblock,125,0 +woodendhalfblock,125,0 +wooddoublehalfblock,125,0 +wooddhalfblock,125,0 +wdoublehalfblock,125,0 +wdhalfblock,125,0 +doublewoodenhalfblock,125,0 +dwoodenhalfblock,125,0 +doublewoodhalfblock,125,0 +dwoodhalfblock,125,0 +doublewhalfblock,125,0 +dwhalfblock,125,0 +oakwoodendoublehalfblock,125,0 +oakwoodendhalfblock,125,0 +oakwooddoublehalfblock,125,0 +oakwooddhalfblock,125,0 +oakwdoublehalfblock,125,0 +oakwdhalfblock,125,0 +oakdoublewoodenhalfblock,125,0 +oakdwoodenhalfblock,125,0 +oakdoublewoodhalfblock,125,0 +oakdwoodhalfblock,125,0 +oakdoublewhalfblock,125,0 +oakdwhalfblock,125,0 +oakdoublehalfblock,125,0 +oakdhalfblock,125,0 +odhalfblock,125,0 +oakwoodendoublestep,125,0 +oakwoodendstep,125,0 +oakwooddoublestep,125,0 +oakwooddstep,125,0 +oakwdoublestep,125,0 +oakwdstep,125,0 +oakdoublewoodenstep,125,0 +oakdwoodenstep,125,0 +oakdoublewoodstep,125,0 +oakdwoodstep,125,0 +oakdoublewstep,125,0 +oakdwstep,125,0 +oakdoublestep,125,0 +oakdstep,125,0 +odstep,125,0 +oakwoodendoubleslab,125,0 +oakwoodendslab,125,0 +oakwooddoubleslab,125,0 +oakwooddslab,125,0 +oakwdoubleslab,125,0 +oakwdslab,125,0 +oakdoublewoodenslab,125,0 +oakdwoodenslab,125,0 +oakdoublewoodslab,125,0 +oakdwoodslab,125,0 +oakdoublewslab,125,0 +oakdwslab,125,0 +oakdoubleslab,125,0 +oakdslab,125,0 +odslab,125,0 +sprucewoodendoublestep,125,1 +sprucewoodendstep,125,1 +sprucewooddoublestep,125,1 +sprucewooddstep,125,1 +sprucewdoublestep,125,1 +sprucewdstep,125,1 +sprucedoublewoodenstep,125,1 +sprucedwoodenstep,125,1 +sprucedoublewoodstep,125,1 +sprucedwoodstep,125,1 +sprucedoublewstep,125,1 +sprucedwstep,125,1 +sprucedoublestep,125,1 +sprucedstep,125,1 +sprucewoodendoubleslab,125,1 +sprucewoodendslab,125,1 +sprucewooddoubleslab,125,1 +sprucewooddslab,125,1 +sprucewdoubleslab,125,1 +sprucewdslab,125,1 +sprucedoublewoodenslab,125,1 +sprucedwoodenslab,125,1 +sprucedoublewoodslab,125,1 +sprucedwoodslab,125,1 +sprucedoublewslab,125,1 +sprucedwslab,125,1 +sprucedoubleslab,125,1 +sprucedslab,125,1 +sprucewoodendoublehalfblock,125,1 +sprucewoodendhalfblock,125,1 +sprucewooddoublehalfblock,125,1 +sprucewooddhalfblock,125,1 +sprucewdoublehalfblock,125,1 +sprucewdhalfblock,125,1 +sprucedoublewoodenhalfblock,125,1 +sprucedwoodenhalfblock,125,1 +sprucedoublewoodhalfblock,125,1 +sprucedwoodhalfblock,125,1 +sprucedoublewhalfblock,125,1 +sprucedwhalfblock,125,1 +sprucedoublehalfblock,125,1 +sprucedhalfblock,125,1 +darkwoodendoublestep,125,1 +darkwoodendstep,125,1 +darkwooddoublestep,125,1 +darkwooddstep,125,1 +darkwdoublestep,125,1 +darkwdstep,125,1 +darkdoublewoodenstep,125,1 +darkdwoodenstep,125,1 +darkdoublewoodstep,125,1 +darkdwoodstep,125,1 +darkdoublewstep,125,1 +darkdwstep,125,1 +darkdoublestep,125,1 +darkdstep,125,1 +ddstep,125,1 +darkwoodendoubleslab,125,1 +darkwoodendslab,125,1 +darkwooddoubleslab,125,1 +darkwooddslab,125,1 +darkwdoubleslab,125,1 +darkwdslab,125,1 +darkdoublewoodenslab,125,1 +darkdwoodenslab,125,1 +darkdoublewoodslab,125,1 +darkdwoodslab,125,1 +darkdoublewslab,125,1 +darkdwslab,125,1 +darkdoubleslab,125,1 +darkdslab,125,1 +ddslab,125,1 +darkwoodendoublehalfblock,125,1 +darkwoodendhalfblock,125,1 +darkwooddoublehalfblock,125,1 +darkwooddhalfblock,125,1 +darkwdoublehalfblock,125,1 +darkwdhalfblock,125,1 +darkdoublewoodenhalfblock,125,1 +darkdwoodenhalfblock,125,1 +darkdoublewoodhalfblock,125,1 +darkdwoodhalfblock,125,1 +darkdoublewhalfblock,125,1 +darkdwhalfblock,125,1 +darkdoublehalfblock,125,1 +darkdhalfblock,125,1 +ddhalfblock,125,1 +birchwoodendoublestep,125,2 +birchwoodendstep,125,2 +birchwooddoublestep,125,2 +birchwooddstep,125,2 +birchwdoublestep,125,2 +birchwdstep,125,2 +birchdoublewoodenstep,125,2 +birchdwoodenstep,125,2 +birchdoublewoodstep,125,2 +birchdwoodstep,125,2 +birchdoublewstep,125,2 +birchdwstep,125,2 +birchdoublestep,125,2 +birchdstep,125,2 +birchwoodendoubleslab,125,2 +birchwoodendslab,125,2 +birchwooddoubleslab,125,2 +birchwooddslab,125,2 +birchwdoubleslab,125,2 +birchwdslab,125,2 +birchdoublewoodenslab,125,2 +birchdwoodenslab,125,2 +birchdoublewoodslab,125,2 +birchdwoodslab,125,2 +birchdoublewslab,125,2 +birchdwslab,125,2 +birchdoubleslab,125,2 +birchdslab,125,2 +birchwoodendoublehalfblock,125,2 +birchwoodendhalfblock,125,2 +birchwooddoublehalfblock,125,2 +birchwooddhalfblock,125,2 +birchwdoublehalfblock,125,2 +birchwdhalfblock,125,2 +birchdoublewoodenhalfblock,125,2 +birchdwoodenhalfblock,125,2 +birchdoublewoodhalfblock,125,2 +birchdwoodhalfblock,125,2 +birchdoublewhalfblock,125,2 +birchdwhalfblock,125,2 +birchdoublehalfblock,125,2 +birchdhalfblock,125,2 +lightwoodendoublehalfblock,125,2 +lightwoodendhalfblock,125,2 +lightwooddoublehalfblock,125,2 +lightwooddhalfblock,125,2 +lightwdoublehalfblock,125,2 +lightwdhalfblock,125,2 +lightdoublewoodenhalfblock,125,2 +lightdwoodenhalfblock,125,2 +lightdoublewoodhalfblock,125,2 +lightdwoodhalfblock,125,2 +lightdoublewhalfblock,125,2 +lightdwhalfblock,125,2 +lightdoublehalfblock,125,2 +lightdhalfblock,125,2 +ldhalfblock,125,2 +lightwoodendoublestep,125,2 +lightwoodendstep,125,2 +lightwooddoublestep,125,2 +lightwooddstep,125,2 +lightwdoublestep,125,2 +lightwdstep,125,2 +lightdoublewoodenstep,125,2 +lightdwoodenstep,125,2 +lightdoublewoodstep,125,2 +lightdwoodstep,125,2 +lightdoublewstep,125,2 +lightdwstep,125,2 +lightdoublestep,125,2 +lightdstep,125,2 +ldstep,125,2 +lightwoodendoubleslab,125,2 +lightwoodendslab,125,2 +lightwooddoubleslab,125,2 +lightwooddslab,125,2 +lightwdoubleslab,125,2 +lightwdslab,125,2 +lightdoublewoodenslab,125,2 +lightdwoodenslab,125,2 +lightdoublewoodslab,125,2 +lightdwoodslab,125,2 +lightdoublewslab,125,2 +lightdwslab,125,2 +lightdoubleslab,125,2 +lightdslab,125,2 +ldslab,125,2 +junglewoodendoublestep,125,3 +junglewoodendstep,125,3 +junglewooddoublestep,125,3 +junglewooddstep,125,3 +junglewdoublestep,125,3 +junglewdstep,125,3 +jungledoublewoodenstep,125,3 +jungledwoodenstep,125,3 +jungledoublewoodstep,125,3 +jungledwoodstep,125,3 +jungledoublewstep,125,3 +jungledwstep,125,3 +jungledoublestep,125,3 +jungledstep,125,3 +jdstep,125,3 +junglewoodendoubleslab,125,3 +junglewoodendslab,125,3 +junglewooddoubleslab,125,3 +junglewooddslab,125,3 +junglewdoubleslab,125,3 +junglewdslab,125,3 +jungledoublewoodenslab,125,3 +jungledwoodenslab,125,3 +jungledoublewoodslab,125,3 +jungledwoodslab,125,3 +jungledoublewslab,125,3 +jungledwslab,125,3 +jungledoubleslab,125,3 +jungledslab,125,3 +jdslab,125,3 +junglewoodendoublehalfblock,125,3 +junglewoodendhalfblock,125,3 +junglewooddoublehalfblock,125,3 +junglewooddhalfblock,125,3 +junglewdoublehalfblock,125,3 +junglewdhalfblock,125,3 +jungledoublewoodenhalfblock,125,3 +jungledwoodenhalfblock,125,3 +jungledoublewoodhalfblock,125,3 +jungledwoodhalfblock,125,3 +jungledoublewhalfblock,125,3 +jungledwhalfblock,125,3 +jungledoublehalfblock,125,3 +jungledhalfblock,125,3 +jdhalfblock,125,3 +forestwoodendoublehalfblock,125,3 +forestwoodendhalfblock,125,3 +forestwooddoublehalfblock,125,3 +forestwooddhalfblock,125,3 +forestwdoublehalfblock,125,3 +forestwdhalfblock,125,3 +forestdoublewoodenhalfblock,125,3 +forestdwoodenhalfblock,125,3 +forestdoublewoodhalfblock,125,3 +forestdwoodhalfblock,125,3 +forestdoublewhalfblock,125,3 +forestdwhalfblock,125,3 +forestdoublehalfblock,125,3 +forestdhalfblock,125,3 +fdhalfblock,125,3 +forestwoodendoublestep,125,3 +forestwoodendstep,125,3 +forestwooddoublestep,125,3 +forestwooddstep,125,3 +forestwdoublestep,125,3 +forestwdstep,125,3 +forestdoublewoodenstep,125,3 +forestdwoodenstep,125,3 +forestdoublewoodstep,125,3 +forestdwoodstep,125,3 +forestdoublewstep,125,3 +forestdwstep,125,3 +forestdoublestep,125,3 +forestdstep,125,3 +fdstep,125,3 +forestwoodendoubleslab,125,3 +forestwoodendslab,125,3 +forestwooddoubleslab,125,3 +forestwooddslab,125,3 +forestwdoubleslab,125,3 +forestwdslab,125,3 +forestdoublewoodenslab,125,3 +forestdwoodenslab,125,3 +forestdoublewoodslab,125,3 +forestdwoodslab,125,3 +forestdoublewslab,125,3 +forestdwslab,125,3 +forestdoubleslab,125,3 +forestdslab,125,3 +fdslab,125,3 +acaciawoodendoublestep,125,4 +acaciawoodendstep,125,4 +acaciawooddoublestep,125,4 +acaciawooddstep,125,4 +acaciawdoublestep,125,4 +acaciawdstep,125,4 +acaciadoublewoodenstep,125,4 +acaciadwoodenstep,125,4 +acaciadoublewoodstep,125,4 +acaciadwoodstep,125,4 +acaciadoublewstep,125,4 +acaciadwstep,125,4 +acaciadoublestep,125,4 +acaciadstep,125,4 +adstep,125,4 +acaciawoodendoubleslab,125,4 +acaciawoodendslab,125,4 +acaciawooddoubleslab,125,4 +acaciawooddslab,125,4 +acaciawdoubleslab,125,4 +acaciawdslab,125,4 +acaciadoublewoodenslab,125,4 +acaciadwoodenslab,125,4 +acaciadoublewoodslab,125,4 +acaciadwoodslab,125,4 +acaciadoublewslab,125,4 +acaciadwslab,125,4 +acaciadoubleslab,125,4 +acaciadslab,125,4 +adslab,125,4 +acaciawoodendoublehalfblock,125,4 +acaciawoodendhalfblock,125,4 +acaciawooddoublehalfblock,125,4 +acaciawooddhalfblock,125,4 +acaciawdoublehalfblock,125,4 +acaciawdhalfblock,125,4 +acaciadoublewoodenhalfblock,125,4 +acaciadwoodenhalfblock,125,4 +acaciadoublewoodhalfblock,125,4 +acaciadwoodhalfblock,125,4 +acaciadoublewhalfblock,125,4 +acaciadwhalfblock,125,4 +acaciadoublehalfblock,125,4 +acaciadhalfblock,125,4 +adhalfblock,125,4 +darkoakwoodendoublehalfblock,125,5 +darkoakwoodendhalfblock,125,5 +darkoakwooddoublehalfblock,125,5 +darkoakwooddhalfblock,125,5 +darkoakwdoublehalfblock,125,5 +darkoakwdhalfblock,125,5 +darkoakdoublewoodenhalfblock,125,5 +darkoakdwoodenhalfblock,125,5 +darkoakdoublewoodhalfblock,125,5 +darkoakdwoodhalfblock,125,5 +darkoakdoublewhalfblock,125,5 +darkoakdwhalfblock,125,5 +darkoakdoublehalfblock,125,5 +darkoakdhalfblock,125,5 +dodhalfblock,125,5 +darkoakwoodendoublestep,125,5 +darkoakwoodendstep,125,5 +darkoakwooddoublestep,125,5 +darkoakwooddstep,125,5 +darkoakwdoublestep,125,5 +darkoakwdstep,125,5 +darkoakdoublewoodenstep,125,5 +darkoakdwoodenstep,125,5 +darkoakdoublewoodstep,125,5 +darkoakdwoodstep,125,5 +darkoakdoublewstep,125,5 +darkoakdwstep,125,5 +darkoakdoublestep,125,5 +darkoakdstep,125,5 +dodstep,125,5 +darkoakwoodendoubleslab,125,5 +darkoakwoodendslab,125,5 +darkoakwooddoubleslab,125,5 +darkoakwooddslab,125,5 +darkoakwdoubleslab,125,5 +darkoakwdslab,125,5 +darkoakdoublewoodenslab,125,5 +darkoakdwoodenslab,125,5 +darkoakdoublewoodslab,125,5 +darkoakdwoodslab,125,5 +darkoakdoublewslab,125,5 +darkoakdwslab,125,5 +darkoakdoubleslab,125,5 +darkoakdslab,125,5 +dodslab,125,5 +woodenstep,126,0 +woodstep,126,0 +wstep,126,0 +woodenslab,126,0 +woodslab,126,0 +wslab,126,0 +woodenhalfblock,126,0 +woodhalfblock,126,0 +whalfblock,126,0 +oakwoodenstep,126,0 +oakwoodstep,126,0 +oakwstep,126,0 +oakstep,126,0 +ostep,126,0 +oakwoodenslab,126,0 +oakwoodslab,126,0 +oakwslab,126,0 +oakslab,126,0 +oslab,126,0 +oakwoodenhalfblock,126,0 +oakwoodhalfblock,126,0 +oakwhalfblock,126,0 +oakhalfblock,126,0 +ohalfblock,126,0 +sprucewoodenstep,126,1 +sprucewoodstep,126,1 +sprucewstep,126,1 +sprucestep,126,1 +sprucewoodenslab,126,1 +sprucewoodslab,126,1 +sprucewslab,126,1 +spruceslab,126,1 +sprucewoodenhalfblock,126,1 +sprucewoodhalfblock,126,1 +sprucewhalfblock,126,1 +sprucehalfblock,126,1 +darkwoodenstep,126,1 +darkwoodstep,126,1 +darkwstep,126,1 +darkstep,126,1 +darkwoodenslab,126,1 +darkwoodslab,126,1 +darkwslab,126,1 +darkslab,126,1 +darkwoodenhalfblock,126,1 +darkwoodhalfblock,126,1 +darkwhalfblock,126,1 +darkhalfblock,126,1 +birchwoodenstep,126,2 +birchwoodstep,126,2 +birchwstep,126,2 +birchstep,126,2 +birchwoodenslab,126,2 +birchwoodslab,126,2 +birchwslab,126,2 +birchslab,126,2 +birchwoodenhalfblock,126,2 +birchwoodhalfblock,126,2 +birchwhalfblock,126,2 +birchhalfblock,126,2 +lightwoodenstep,126,2 +lightwoodstep,126,2 +lightwstep,126,2 +lightstep,126,2 +lstep,126,2 +lightwoodenslab,126,2 +lightwoodslab,126,2 +lightwslab,126,2 +lightslab,126,2 +lslab,126,2 +lightwoodenhalfblock,126,2 +lightwoodhalfblock,126,2 +lightwhalfblock,126,2 +lighthalfblock,126,2 +lhalfblock,126,2 +junglewoodenstep,126,3 +junglewoodstep,126,3 +junglewstep,126,3 +junglestep,126,3 +jstep,126,3 +junglewoodenslab,126,3 +junglewoodslab,126,3 +junglewslab,126,3 +jungleslab,126,3 +jslab,126,3 +junglewoodenhalfblock,126,3 +junglewoodhalfblock,126,3 +junglewhalfblock,126,3 +junglehalfblock,126,3 +jhalfblock,126,3 +forestwoodenstep,126,3 +forestwoodstep,126,3 +forestwstep,126,3 +foreststep,126,3 +fstep,126,3 +forestwoodenslab,126,3 +forestwoodslab,126,3 +forestwslab,126,3 +forestslab,126,3 +fslab,126,3 +forestwoodenhalfblock,126,3 +forestwoodhalfblock,126,3 +forestwhalfblock,126,3 +foresthalfblock,126,3 +fhalfblock,126,3 +acaciawoodenstep,126,4 +acaciawoodstep,126,4 +acaciawstep,126,4 +acaciastep,126,4 +astep,126,4 +acaciawoodenslab,126,4 +acaciawoodslab,126,4 +acaciawslab,126,4 +acaciaslab,126,4 +aslab,126,4 +acaciawoodenhalfblock,126,4 +acaciawoodhalfblock,126,4 +acaciawhalfblock,126,4 +acaciahalfblock,126,4 +ahalfblock,126,4 +darkoakwoodenstep,126,5 +darkoakwoodstep,126,5 +darkoakwstep,126,5 +darkoakstep,126,5 +dostep,126,5 +darkoakwoodenslab,126,5 +darkoakwoodslab,126,5 +darkoakwslab,126,5 +darkoakslab,126,5 +doslab,126,5 +darkoakwoodenhalfblock,126,5 +darkoakwoodhalfblock,126,5 +darkoakwhalfblock,126,5 +darkoakhalfblock,126,5 +dohalfblock,126,5 +cocoaplant,127,0 +cocoplant,127,0 +cplant,127,0 +cocoafruit,127,0 +cocofruit,127,0 +cfruit,127,0 +cocoapod,127,0 +cocopod,127,0 +cpod,127,0 +sandstonestairs,128,0 +sandstairs,128,0 +sandsstairs,128,0 +sstonestairs,128,0 +ssstairs,128,0 +sandstair,128,0 +sandstonestair,128,0 +sandsstair,128,0 +sstonestair,128,0 +ssstair,128,0 +emeraldore,129,0 +eore,129,0 +oreemerald,129,0 +oree,129,0 +enderchest,130,0 +endchest,130,0 +echest,130,0 +chestender,130,0 +chestend,130,0 +cheste,130,0 +endercontainer,130,0 +endcontainer,130,0 +econtainer,130,0 +tripwirehook,131,0 +tripwire,131,0 +trip,131,0 +tripwirelever,131,0 +triphook,131,0 +emeraldblock,133,0 +blockemerald,133,0 +eblock,133,0 +blocke,133,0 +sprucewoodenstairs,134,0 +sprucewoodstairs,134,0 +sprucewstairs,134,0 +sprucestairs,134,0 +darkwoodenstairs,134,0 +darkwoodstairs,134,0 +darkwstairs,134,0 +darkstairs,134,0 +dstairs,134,0 +sprucewoodenstair,134,0 +sprucewoodstair,134,0 +sprucewstair,134,0 +sprucestair,134,0 +darkwoodenstair,134,0 +darkwoodstair,134,0 +darkwstair,134,0 +darkstair,134,0 +dstair,134,0 +birchwoodenstairs,135,0 +birchwoodstairs,135,0 +birchwstairs,135,0 +birchstairs,135,0 +lightwoodenstairs,135,0 +lightwoodstairs,135,0 +lightwstairs,135,0 +lightstairs,135,0 +lstairs,135,0 +birchwoodenstair,135,0 +birchwoodstair,135,0 +birchwstair,135,0 +birchstair,135,0 +lightwoodenstair,135,0 +lightwoodstair,135,0 +lightwstair,135,0 +lightstair,135,0 +lstair,135,0 +junglewoodenstairs,136,0 +junglewoodstairs,136,0 +junglewstairs,136,0 +junglestairs,136,0 +jstairs,136,0 +forestwoodenstairs,136,0 +forestwoodstairs,136,0 +forestwstairs,136,0 +foreststairs,136,0 +fstairs,136,0 +junglewoodenstair,136,0 +junglewoodstair,136,0 +junglewstair,136,0 +junglestair,136,0 +jstair,136,0 +forestwoodenstair,136,0 +forestwoodstair,136,0 +forestwstair,136,0 +foreststair,136,0 +fstair,136,0 +commandblock,137,0 +blockcommand,137,0 +cmdblock,137,0 +blockcmd,137,0 +macroblock,137,0 +blockmacro,137,0 +beacon,138,0 +beaconblock,138,0 +cobblestonewall,139,0 +cstonewall,139,0 +cobblewall,139,0 +cobblestonefence,139,0 +cstonefence,139,0 +cobblefence,139,0 +cswall,139,0 +csfence,139,0 +cwall,139,0 +cfence,139,0 +mosscobblestonewall,139,1 +mosscstonewall,139,1 +mosscobblewall,139,1 +mcobblestonewall,139,1 +mcstonewall,139,1 +mcobblewall,139,1 +mosscobblestonefence,139,1 +mosscstonefence,139,1 +mosscobblefence,139,1 +mcobblestonefence,139,1 +mcstonefence,139,1 +mcobblefence,139,1 +mcswall,139,0 +mcsfence,139,0 +mcwall,139,0 +mcfence,139,0 +plantedcarrot,141,0 +plantcarrot,141,0 +carrots,141,0 +growingcarrot,141,0 +potatoplant,142,0 +potatoes,142,0 +plantedpotato,142,0 +plantpotato,142,0 +growingpotato,142,0 +woodenbutton,143,0 +woodenplankbutton,143,0 +woodplankbutton,143,0 +wplankbutton,143,0 +plankbutton,143,0 +woodbutton,143,0 +wbutton,143,0 +anvil,145,0 +slightlydamagedanvil,145,1 +slightdamageanvil,145,1 +damagedanvil,145,1 +verydamagedanvil,145,2 +trapchest,146,0 +trappedchest,146,0 +chesttrapped,146,0 +chesttrap,146,0 +goldpressureplate,147,0 +weightedgoldpressureplate,147,0 +weightgoldpressureplate,147,0 +wgoldpressureplate,147,0 +weightedgoldpressplate,147,0 +weightgoldpressplate,147,0 +wgoldpressplate,147,0 +goldpressplate,147,0 +weightedgoldpplate,147,0 +weightgoldpplate,147,0 +wgoldpplate,147,0 +goldpplate,147,0 +weightedgoldplate,147,0 +weightgoldplate,147,0 +wgoldplate,147,0 +goldplate,147,0 +weightedgpressureplate,147,0 +weightgpressureplate,147,0 +wgpressureplate,147,0 +gpressureplate,147,0 +weightedgpressplate,147,0 +weightgpressplate,147,0 +wgpressplate,147,0 +gpressplate,147,0 +weightedgpplate,147,0 +weightgpplate,147,0 +wgpplate,147,0 +gpplate,147,0 +weightedgplate,147,0 +weightgplate,147,0 +wgplate,147,0 +gplate,147,0 +ironpressureplate,148,0 +weightedironpressureplate,148,0 +weightironpressureplate,148,0 +wironpressureplate,148,0 +weightedironpressplate,148,0 +weightironpressplate,148,0 +wironpressplate,148,0 +ironpressplate,148,0 +weightedironpplate,148,0 +weightironpplate,148,0 +wironpplate,148,0 +ironpplate,148,0 +weightedironplate,148,0 +weightironplate,148,0 +wironplate,148,0 +ironplate,148,0 +weightedipressureplate,148,0 +weightipressureplate,148,0 +wipressureplate,148,0 +ipressureplate,148,0 +weightedipressplate,148,0 +weightipressplate,148,0 +wipressplate,148,0 +ipressplate,148,0 +weightedipplate,148,0 +weightipplate,148,0 +wipplate,148,0 +ipplate,148,0 +weightediplate,148,0 +weightiplate,148,0 +wiplate,148,0 +iplate,148,0 +daylightsensor,151,0 +daylightsense,151,0 +lightsensor,151,0 +lightsense,151,0 +daysensor,151,0 +daysense,151,0 +timesensor,151,0 +timesense,151,0 +redstoneblock,152,0 +rstoneblock,152,0 +redsblock,152,0 +rsblock,152,0 +blockredstone,152,0 +blockrstone,152,0 +blockreds,152,0 +blockrs,152,0 +netherquartzore,153,0 +hellquartzore,153,0 +deathquartzore,153,0 +nquartzore,153,0 +hquartzore,153,0 +dquartzore,153,0 +quartzore,153,0 +netherqore,153,0 +hellqore,153,0 +deathqore,153,0 +nqore,153,0 +hqore,153,0 +dqore,153,0 +qore,153,0 +hopper,154,0 +chestpuller,154,0 +chestpull,154,0 +cheststorer,154,0 +cheststore,154,0 +itempuller,154,0 +itempull,154,0 +itemstorer,154,0 +itemstore,154,0 +quartzblock,155,0 +netherquartzblock,155,0 +nqblock,155,0 +qblock,155,0 +chiseledquartzblock,155,1 +chiselquartzblock,155,1 +cquartzblock,155,1 +cqblock,155,1 +pillarquartzblock,155,2 +pquartzblock,155,2 +pqblock,155,2 +quartzstairs,156,0 +qstairs,156,0 +quartzstair,156,0 +qstair,156,0 +activatorrails,157,0 +activaterails,157,0 +triggerrails,157,0 +arails,157,0 +trails,157,0 +activatorrail,157,0 +activaterail,157,0 +triggerrail,157,0 +arail,157,0 +trail,157,0 +activatortrack,157,0 +activatetrack,157,0 +triggertrack,157,0 +atrack,157,0 +ttrack,157,0 +dropper,158,0 +drop,158,0 +chestdispenser,158,0 +chestdispense,158,0 +chestdropper,158,0 +chestdrop,158,0 +whiteclay,159,0 +whitesclay,159,0 +whitestainedclay,159,0 +wclay,159,0 +wsclay,159,0 +wstainedclay,159,0 +sclay,159,0 +stainedclay,159,0 +orangeclay,159,1 +orangesclay,159,1 +orangestainedclay,159,1 +oclay,159,1 +osclay,159,1 +ostainedclay,159,1 +magentaclay,159,2 +magentasclay,159,2 +magentastainedclay,159,2 +mclay,159,2 +msclay,159,2 +mstainedclay,159,2 +lightblueclay,159,3 +lightbluesclay,159,3 +lightbluestainedclay,159,3 +lblueclay,159,3 +lbluesclay,159,3 +lbluestainedclay,159,3 +lightbluclay,159,3 +lightblusclay,159,3 +lightblustainedclay,159,3 +lbluclay,159,3 +lblusclay,159,3 +lblustainedclay,159,3 +lbclay,159,3 +lbsclay,159,3 +lbstainedclay,159,3 +yellowclay,159,4 +yellowsclay,159,4 +yellowstainedclay,159,4 +yclay,159,4 +ysclay,159,4 +ystainedclay,159,4 +lightgreenclay,159,5 +lightgreensclay,159,5 +lightgreenstainedclay,159,5 +lgreenclay,159,5 +lgreensclay,159,5 +lgreenstainedclay,159,5 +lightgreclay,159,5 +lightgresclay,159,5 +lightgrestainedclay,159,5 +lgreclay,159,5 +lgresclay,159,5 +lgrestainedclay,159,5 +limeclay,159,5 +limesclay,159,5 +limestainedclay,159,5 +lclay,159,5 +lsclay,159,5 +lstainedclay,159,5 +pinkclay,159,6 +pinksclay,159,6 +pinkstainedclay,159,6 +piclay,159,6 +pisclay,159,6 +pistainedclay,159,6 +darkgrayclay,159,7 +darkgraysclay,159,7 +darkgraystainedclay,159,7 +dgrayclay,159,7 +dgraysclay,159,7 +dgraystainedclay,159,7 +darkgreyclay,159,7 +darkgreeysclay,159,7 +darkgreystainedclay,159,7 +dgreyclay,159,7 +dgreysclay,159,7 +dgreystainedclay,159,7 +darkgraclay,159,7 +darkgrasclay,159,7 +darkgrastainedclay,159,7 +dgraclay,159,7 +dgrasclay,159,7 +dgrastainedclay,159,7 +grayclay,159,7 +graysclay,159,7 +graystainedclay,159,7 +greyclay,159,7 +greysclay,159,7 +greystainedclay,159,7 +graclay,159,7 +grasclay,159,7 +grastainedclay,159,7 +lightgrayclay,159,8 +lightgraysclay,159,8 +lightgraystainedclay,159,8 +lgrayclay,159,8 +lgraysclay,159,8 +lgraystainedclay,159,8 +lightgreyclay,159,8 +lightgreysclay,159,8 +lightgreystainedclay,159,8 +lgreyclay,159,8 +lgreysclay,159,8 +lgreystainedclay,159,8 +lightgraclay,159,8 +lightgrasclay,159,8 +lightgrastainedclay,159,8 +lgraclay,159,8 +lgrasclay,159,8 +lgrastainedclay,159,8 +silverclay,159,8 +silversclay,159,8 +silverstainedclay,159,8 +siclay,159,8 +siasclay,159,8 +siastainedclay,159,8 +cyanclay,159,9 +cyansclay,159,9 +cyanstainedclay,159,9 +cclay,159,9 +csclay,159,9 +cstainedclay,159,9 +purpleclay,159,10 +purplesclay,159,10 +purplestainedclay,159,10 +puclay,159,10 +pusclay,159,10 +pustainedclay,159,10 +blueclay,159,11 +bluesclay,159,11 +bluestainedclay,159,11 +bluclay,159,11 +blusclay,159,11 +blustainedclay,159,11 +brownclay,159,12 +brownsclay,159,12 +brownstainedclay,159,12 +broclay,159,12 +brosclay,159,12 +brostainedclay,159,12 +darkgreenclay,159,13 +darkgreensclay,159,13 +darkgreenstainedclay,159,13 +dgreenclay,159,13 +dgreensclay,159,13 +dgreenstainedclay,159,13 +greenclay,159,13 +greensclay,159,13 +greenstainedclay,159,13 +darkgreclay,159,13 +darkgresclay,159,13 +darkgrestainedclay,159,13 +dgreclay,159,13 +dgresclay,159,13 +dgrestainedclay,159,13 +greclay,159,13 +gresclay,159,13 +grestainedclay,159,13 +redclay,159,14 +redsclay,159,14 +redstainedclay,159,14 +rclay,159,14 +rsclay,159,14 +rstainedclay,159,14 +blackclay,159,15 +blacksclay,159,15 +blackstainedclay,159,15 +blaclay,159,15 +blasclay,159,15 +blastainedclay,159,15 +whiteglasspane,160,0 +whitesglasspane,160,0 +whitestainedglasspane,160,0 +wglasspane,160,0 +wsglasspane,160,0 +wstainedglasspane,160,0 +sglasspane,160,0 +stainedglasspane,160,0 +orangeglasspane,160,1 +orangesglasspane,160,1 +orangestainedglasspane,160,1 +oglasspane,160,1 +osglasspane,160,1 +ostainedglasspane,160,1 +magentaglasspane,160,2 +magentasglasspane,160,2 +magentastainedglasspane,160,2 +mglasspane,160,2 +msglasspane,160,2 +mstainedglasspane,160,2 +lightblueglasspane,160,3 +lightbluesglasspane,160,3 +lightbluestainedglasspane,160,3 +lblueglasspane,160,3 +lbluesglasspane,160,3 +lbluestainedglasspane,160,3 +lightbluglasspane,160,3 +lightblusglasspane,160,3 +lightblustainedglasspane,160,3 +lbluglasspane,160,3 +lblusglasspane,160,3 +lblustainedglasspane,160,3 +lbglasspane,160,3 +lbsglasspane,160,3 +lbstainedglasspane,160,3 +yellowglasspane,160,4 +yellowsglasspane,160,4 +yellowstainedglasspane,160,4 +yglasspane,160,4 +ysglasspane,160,4 +ystainedglasspane,160,4 +lightgreenglasspane,160,5 +lightgreensglasspane,160,5 +lightgreenstainedglasspane,160,5 +lgreenglasspane,160,5 +lgreensglasspane,160,5 +lgreenstainedglasspane,160,5 +lightgreglasspane,160,5 +lightgresglasspane,160,5 +lightgrestainedglasspane,160,5 +lgreglasspane,160,5 +lgresglasspane,160,5 +lgrestainedglasspane,160,5 +limeglasspane,160,5 +limesglasspane,160,5 +limestainedglasspane,160,5 +lglasspane,160,5 +lsglasspane,160,5 +lstainedglasspane,160,5 +pinkglasspane,160,6 +pinksglasspane,160,6 +pinkstainedglasspane,160,6 +piglasspane,160,6 +pisglasspane,160,6 +pistainedglasspane,160,6 +darkgrayglasspane,160,7 +darkgraysglasspane,160,7 +darkgraystainedglasspane,160,7 +dgrayglasspane,160,7 +dgraysglasspane,160,7 +dgraystainedglasspane,160,7 +darkgreyglasspane,160,7 +darkgreysglasspane,160,7 +darkgreystainedglasspane,160,7 +dgreyglasspane,160,7 +dgreysglasspane,160,7 +dgreystainedglasspane,160,7 +darkgraglasspane,160,7 +darkgrasglasspane,160,7 +darkgrastainedglasspane,160,7 +dgraglasspane,160,7 +dgrasglasspane,160,7 +dgrastainedglasspane,160,7 +grayglasspane,160,7 +graysglasspane,160,7 +graystainedglasspane,160,7 +greyglasspane,160,7 +greysglasspane,160,7 +greystainedglasspane,160,7 +graglasspane,160,7 +grasglasspane,160,7 +grastainedglasspane,160,7 +lightgrayglasspane,160,8 +lightgraysglasspane,160,8 +lightgraystainedglasspane,160,8 +lgrayglasspane,160,8 +lgraysglasspane,160,8 +lgraystainedglasspane,160,8 +lightgreyglasspane,160,8 +lightgreysglasspane,160,8 +lightgreystainedglasspane,160,8 +lgreyglasspane,160,8 +lgreysglasspane,160,8 +lgreystainedglasspane,160,8 +lightgraglasspane,160,8 +lightgrasglasspane,160,8 +lightgrastainedglasspane,160,8 +lgraglasspane,160,8 +lgrasglasspane,160,8 +lgrastainedglasspane,160,8 +silverglasspane,160,8 +silversglasspane,160,8 +silverstainedglasspane,160,8 +siglasspane,160,8 +siasglasspane,160,8 +siastainedglasspane,160,8 +cyanglasspane,160,9 +cyansglasspane,160,9 +cyanstainedglasspane,160,9 +cglasspane,160,9 +csglasspane,160,9 +cstainedglasspane,160,9 +purpleglasspane,160,10 +purplesglasspane,160,10 +purplestainedglasspane,160,10 +puglasspane,160,10 +pusglasspane,160,10 +pustainedglasspane,160,10 +blueglasspane,160,11 +bluesglasspane,160,11 +bluestainedglasspane,160,11 +bluglasspane,160,11 +blusglasspane,160,11 +blustainedglasspane,160,11 +brownglasspane,160,12 +brownsglasspane,160,12 +brownstainedglasspane,160,12 +broglasspane,160,12 +brosglasspane,160,12 +brostainedglasspane,160,12 +darkgreenglasspane,160,13 +darkgreensglasspane,160,13 +darkgreenstainedglasspane,160,13 +dgreenglasspane,160,13 +dgreensglasspane,160,13 +dgreenstainedglasspane,160,13 +greenglasspane,160,13 +greensglasspane,160,13 +greenstainedglasspane,160,13 +darkgreglasspane,160,13 +darkgresglasspane,160,13 +darkgrestainedglasspane,160,13 +dgreglasspane,160,13 +dgresglasspane,160,13 +dgrestainedglasspane,160,13 +greglasspane,160,13 +gresglasspane,160,13 +grestainedglasspane,160,13 +redglasspane,160,14 +redsglasspane,160,14 +redstainedglasspane,160,14 +rglasspane,160,14 +rsglasspane,160,14 +rstainedglasspane,160,14 +blackglasspane,160,15 +blacksglasspane,160,15 +blackstainedglasspane,160,15 +blaglasspane,160,15 +blasglasspane,160,15 +blastainedglasspane,160,15 +acacialeaves,161,0 +acaciatreeleaves,161,0 +acacialogleaves,161,0 +acaciatrunkleaves,161,0 +acaciawoodleaves,161,0 +aleaves,161,0 +atreeleaves,161,0 +alogleaves,161,0 +atrunkleaves,161,0 +awoodleaves,161,0 +acacialeave,161,0 +acaciatreeleave,161,0 +acacialogleave,161,0 +acaciatrunkleave,161,0 +acaciawoodleave,161,0 +aleave,161,0 +atreeleave,161,0 +alogleave,161,0 +atrunkleave,161,0 +awoodleave,161,0 +acaciatreeleaf,161,0 +acacialogleaf,161,0 +acaciatrunkleaf,161,0 +acaciawoodleaf,161,0 +aleaf,161,0 +atreeleaf,161,0 +alogleaf,161,0 +atrunkleaf,161,0 +awoodleaf,161,0 +darkoakleaves,161,1 +darkoaktreeleaves,161,1 +darkoaklogleaves,161,1 +darkoaktrunkleaves,161,1 +darkoakwoodleaves,161,1 +doakleaves,161,1 +doaktreeleaves,161,1 +doaklogleaves,161,1 +doaktrunkleaves,161,1 +doakwoodleaves,161,1 +doleaves,161,1 +dotreeleaves,161,1 +dologleaves,161,1 +dotrunkleaves,161,1 +dowoodleaves,161,1 +darkoakleave,161,1 +darkoaktreeleave,161,1 +darkoaklogleave,161,1 +darkoaktrunkleave,161,1 +darkoakwoodleave,161,1 +doakleave,161,1 +doaktreeleave,161,1 +doaklogleave,161,1 +doaktrunkleave,161,1 +doakwoodleave,161,1 +doleave,161,1 +dotreeleave,161,1 +dologleave,161,1 +dotrunkleave,161,1 +dowoodleave,161,1 +darkoaktreeleaf,161,1 +darkoaklogleaf,161,1 +darkoaktrunkleaf,161,1 +darkoakwoodleaf,161,1 +doakleaf,161,1 +doaktreeleaf,161,1 +doaklogleaf,161,1 +doaktrunkleaf,161,1 +doakwoodleaf,161,1 +doleaf,161,1 +dotreeleaf,161,1 +dologleaf,161,1 +dotrunkleaf,161,1 +dowoodleaf,161,1 +acacia,162,0 +acaciatree,162,0 +acacialog,162,0 +acaciatrunk,162,0 +acaciawood,162,0 +atree,162,0 +alog,162,0 +atrunk,162,0 +awood,162,0 +darkoak,162,1 +darkoaktree,162,1 +darkoaklog,162,1 +darkoaktrunk,162,1 +darkoakwood,162,1 +doak,162,1 +doaktree,162,1 +doaklog,162,1 +doaktrunk,162,1 +doakwood,162,1 +dotree,162,1 +dolog,162,1 +dotrunk,162,1 +dowood,162,1 +acaciawoodenstairs,163,0 +acaciawoodstairs,163,0 +acaciawstairs,163,0 +acaciastairs,163,0 +awoodenstairs,163,0 +awoodstairs,163,0 +awstairs,163,0 +astairs,163,0 +acaciawoodenstair,163,0 +acaciawoodstair,163,0 +acaciawstair,163,0 +acaciastair,163,0 +awoodenstair,163,0 +awoodstair,163,0 +awstair,163,0 +astair,163,0 +darkoakwoodenstairs,164,0 +darkoakwoodstairs,164,0 +darkoakwstairs,164,0 +darkoakstairs,164,0 +doakwoodenstairs,164,0 +doakwoodstairs,164,0 +doakwstairs,164,0 +doakstairs,164,0 +dowoodenstairs,164,0 +dowoodstairs,164,0 +dowstairs,164,0 +dostairs,164,0 +darkoakwoodenstair,164,0 +darkoakwoodstair,164,0 +darkoakwstair,164,0 +darkoakstair,164,0 +doakwoodenstair,164,0 +doakwoodstair,164,0 +doakwstair,164,0 +doakstair,164,0 +dowoodenstair,164,0 +dowoodstair,164,0 +dowstair,164,0 +dostair,164,0 +hay,170,0 +hayblock,170,0 +haybale,170,0 +baleofhay,170,0 +hayofbale,170,0 +whitecarpet,171,0 +whitefloor,171,0 +wcarpet,171,0 +wfloor,171,0 +carpet,171,0 +floor,171,0 +orangecarpet,171,1 +orangefloor,171,1 +ocarpet,171,1 +ofloor,171,1 +magentacarpet,171,2 +magentafloor,171,2 +mcarpet,171,2 +mfloor,171,2 +lightbluecarpet,171,3 +lightbluefloor,171,3 +lbluecarpet,171,3 +lbluefloor,171,3 +lbcarpet,171,3 +lbfloor,171,3 +lightblucarpet,171,3 +lightblufloor,171,3 +lblucarpet,171,3 +lblufloor,171,3 +yellowcarpet,171,4 +yellowfloor,171,4 +ycarpet,171,4 +yfloor,171,4 +lightgreencarpet,171,5 +lightgreenfloor,171,5 +lgreencarpet,171,5 +lgreenfloor,171,5 +lightgrecarpet,171,5 +lightgrefloor,171,5 +lgrecarpet,171,5 +lgrefloor,171,5 +limecarpet,171,5 +limefloor,171,5 +lcarpet,171,5 +lfloor,171,5 +pinkcarpet,171,6 +pinkfloor,171,6 +picarpet,171,6 +pifloor,171,6 +darkgraycarpet,171,7 +darkgrayfloor,171,7 +dgraycarpet,171,7 +dgrayfloor,171,7 +darkgreycarpet,171,7 +darkgreyfloor,171,7 +dgreycarpet,171,7 +dgreyfloor,171,7 +darkgracarpet,171,7 +darkgrafloor,171,7 +dgracarpet,171,7 +dgrafloor,171,7 +graycarpet,171,7 +grayfloor,171,7 +greycarpet,171,7 +greyfloor,171,7 +gracarpet,171,7 +grafloor,171,7 +lightgraycarpet,171,8 +lightgrayfloor,171,8 +lgraycarpet,171,8 +lgrayfloor,171,8 +lightgreycarpet,171,8 +lightgreyfloor,171,8 +lgreycarpet,171,8 +lgreyfloor,171,8 +lightgracarpet,171,8 +lightgrafloor,171,8 +lgracarpet,171,8 +lgrafloor,171,8 +silvercarpet,171,8 +silverfloor,171,8 +sicarpet,171,8 +siafloor,171,8 +cyancarpet,171,9 +cyanfloor,171,9 +ccarpet,171,9 +cfloor,171,9 +purplecarpet,171,10 +purplefloor,171,10 +pucarpet,171,10 +pufloor,171,10 +bluecarpet,171,11 +bluefloor,171,11 +blucarpet,171,11 +blufloor,171,11 +browncarpet,171,12 +brownfloor,171,12 +brocarpet,171,12 +brofloor,171,12 +darkgreencarpet,171,13 +darkgreenfloor,171,13 +dgreencarpet,171,13 +dgreenfloor,171,13 +greencarpet,171,13 +greenfloor,171,13 +darkgrecarpet,171,13 +darkgrefloor,171,13 +dgrecarpet,171,13 +dgrefloor,171,13 +grecarpet,171,13 +grefloor,171,13 +redcarpet,171,14 +redfloor,171,14 +rcarpet,171,14 +rfloor,171,14 +blackcarpet,171,15 +blackfloor,171,15 +blacarpet,171,15 +blafloor,171,15 +hardenedclay,172,0 +hardclay,172,0 +hclay,172,0 +coalblock,173,0 +blockcoal,173,0 +coblock,173,0 +blockco,173,0 +coalb,173,0 +bcoal,173,0 +packedice,174,0 +packice,174,0 +solidice,174,0 +sunflower,175,0 +yellowsunflower,175,0 +lilac,175,1 +magentalilac,175,1 +syringa,175,1 +longtallgrass,175,2 +extratallgrass,175,2 +doubletallgrass,175,2 +largetallgrass,175,2 +longtgrass,175,2 +extratgrass,175,2 +doubletgrass,175,2 +largetgrass,175,2 +ltgrass,175,2 +etgrass,175,2 +dtgrass,175,2 +bigfern,175,3 +largefern,175,3 +doublefern,175,3 +bfern,175,3 +lfern,175,3 +dfern,175,3 +rosebush,175,4 +redrosebush,175,4 +peony,175,5 +pinkpeony,175,5 +paeonia,175,5 +ironshovel,256,0 +ironspade,256,0 +ishovel,256,0 +ispade,256,0 +steelshovel,256,0 +steelspade,256,0 +ironpickaxe,257,0 +ironpick,257,0 +steelpickaxe,257,0 +steelpick,257,0 +ipickaxe,257,0 +ipick,257,0 +ironaxe,258,0 +iaxe,258,0 +steelaxe,258,0 +flintandsteel,259,0 +flintandiron,259,0 +flintandtinder,259,0 +flintnsteel,259,0 +flintniron,259,0 +flintntinder,259,0 +flintsteel,259,0 +flintiron,259,0 +flinttinder,259,0 +lighter,259,0 +apple,260,0 +normalapple,260,0 +redapple,260,0 +bow,261,0 +arrow,262,0 +coal,263,0 +charcoal,263,1 +ccoal,263,1 +diamond,264,0 +crystal,264,0 +ironingot,265,0 +ironbar,265,0 +ironi,265,0 +steelingot,265,0 +steelbar,265,0 +steeli,265,0 +iingot,265,0 +ibar,265,0 +ingotiron,265,0 +bariron,265,0 +iiron,265,0 +ingotsteel,265,0 +barsteel,265,0 +isteel,265,0 +ingoti,265,0 +bari,265,0 +goldingot,266,0 +goldbar,266,0 +goldi,266,0 +gingot,266,0 +gbar,266,0 +ingotgold,266,0 +bargold,266,0 +igold,266,0 +ingotg,266,0 +barg,266,0 +ironsword,267,0 +steelsword,267,0 +isword,267,0 +woodensword,268,0 +woodsword,268,0 +wsword,268,0 +woodenshovel,269,0 +woodenspade,269,0 +woodshovel,269,0 +woodspade,269,0 +wshovel,269,0 +wspade,269,0 +woodenpickaxe,270,0 +woodenpick,270,0 +woodpickaxe,270,0 +woodpick,270,0 +wpickaxe,270,0 +wpick,270,0 +woodenaxe,271,0 +woodaxe,271,0 +waxe,271,0 +stonesword,272,0 +cobblestonesword,272,0 +cstonesword,272,0 +cssword,272,0 +ssword,272,0 +stoneshovel,273,0 +cobblestoneshovel,273,0 +cobblestonespade,273,0 +cstoneshovel,273,0 +cstonespade,273,0 +stonespade,273,0 +csshovel,273,0 +csspade,273,0 +sshovel,273,0 +sspade,273,0 +stonepickaxe,274,0 +cobblestonepickaxe,274,0 +cobblestonepick,274,0 +cstonepickaxe,274,0 +cstonepick,274,0 +stonepick,274,0 +cspickaxe,274,0 +cspick,274,0 +spickaxe,274,0 +spick,274,0 +stoneaxe,275,0 +cobblestoneaxe,275,0 +cstoneaxe,275,0 +csaxe,275,0 +saxe,275,0 +diamondsword,276,0 +crystalsword,276,0 +dsword,276,0 +diamondshovel,277,0 +diamondspade,277,0 +crystalshovel,277,0 +crystalspade,277,0 +dshovel,277,0 +dspade,277,0 +diamondpickaxe,278,0 +diamondpick,278,0 +crystalpickaxe,278,0 +crystalpick,278,0 +dpickaxe,278,0 +dpick,278,0 +diamondaxe,279,0 +crystalaxe,279,0 +daxe,279,0 +stick,280,0 +twig,280,0 +branch,280,0 +bowl,281,0 +woodenbowl,281,0 +woodbowl,281,0 +mushroomsoup,282,0 +mrsoup,282,0 +soup,282,0 +goldsword,283,0 +gsword,283,0 +goldshovel,284,0 +goldspade,284,0 +gshovel,284,0 +gspade,284,0 +goldpickaxe,285,0 +goldpick,285,0 +gpickaxe,285,0 +gpick,285,0 +goldaxe,286,0 +gaxe,286,0 +string,287,0 +thread,287,0 +feather,288,0 +gunpowder,289,0 +sulfur,289,0 +woodenhoe,290,0 +woodhoe,290,0 +whoe,290,0 +stonehoe,291,0 +cobblestonehoe,291,0 +cstonehoe,291,0 +cshoe,291,0 +shoe,291,0 +ironhoe,292,0 +steelhoe,292,0 +ihoe,292,0 +diamondhoe,293,0 +crystalhoe,293,0 +dhoe,293,0 +goldhoe,294,0 +ghoe,294,0 +seeds,295,0 +seed,295,0 +wheat,296,0 +crops,296,0 +crop,296,0 +bread,297,0 +leatherhelmet,298,0 +leatherhelm,298,0 +leatherhat,298,0 +leathercoif,298,0 +lhelmet,298,0 +lhelm,298,0 +lhat,298,0 +lcoif,298,0 +leatherchestplate,299,0 +leatherplatebody,299,0 +leatherplate,299,0 +leathershirt,299,0 +leathertunic,299,0 +lchestplate,299,0 +lplatebody,299,0 +lplate,299,0 +lshirt,299,0 +ltunic,299,0 +leatherleggings,300,0 +leatherlegs,300,0 +leatherpants,300,0 +lleggings,300,0 +llegs,300,0 +lpants,300,0 +leatherboots,301,0 +leathershoes,301,0 +lboots,301,0 +lshoes,301,0 +chainmailhelmet,302,0 +chainmailhelm,302,0 +chainmailhat,302,0 +chainmailcoif,302,0 +chainmhelmet,302,0 +chainmhelm,302,0 +chainmhat,302,0 +chainmcoif,302,0 +cmailhelmet,302,0 +cmailhelm,302,0 +cmailhat,302,0 +cmailcoif,302,0 +chainhelmet,302,0 +chainhelm,302,0 +chainhat,302,0 +chaincoif,302,0 +cmhelmet,302,0 +cmhelm,302,0 +cmhat,302,0 +cmcoif,302,0 +chainmailchestplate,303,0 +chainmailplatebody,303,0 +chainmailplate,303,0 +chainmailshirt,303,0 +chainmailtunic,303,0 +chainmchestplate,303,0 +chainmplatebody,303,0 +chainmplate,303,0 +chainmshirt,303,0 +chainmtunic,303,0 +cmailchestplate,303,0 +cmailplatebody,303,0 +cmailplate,303,0 +cmailshirt,303,0 +cmailtunic,303,0 +chainchestplate,303,0 +chainplatebody,303,0 +chainplate,303,0 +chainshirt,303,0 +chaintunic,303,0 +cmchestplate,303,0 +cmplatebody,303,0 +cmplate,303,0 +cmshirt,303,0 +cmtunic,303,0 +chainmailleggings,304,0 +chainmaillegs,304,0 +chainmailpants,304,0 +chainmleggings,304,0 +chainmlegs,304,0 +chainmpants,304,0 +cmailleggings,304,0 +cmaillegs,304,0 +cmailpants,304,0 +chainleggings,304,0 +chainlegs,304,0 +chainpants,304,0 +cmleggings,304,0 +cmlegs,304,0 +cmpants,304,0 +chainmailboots,305,0 +chainmailshoes,305,0 +chainmboots,305,0 +chainmshoes,305,0 +cmailboots,305,0 +cmailshoes,305,0 +chainboots,305,0 +chainshoes,305,0 +cmboots,305,0 +cmshoes,305,0 +ironhelmet,306,0 +ironhelm,306,0 +ironhat,306,0 +ironcoif,306,0 +ihelmet,306,0 +ihelm,306,0 +ihat,306,0 +icoif,306,0 +steelhelmet,306,0 +steelhelm,306,0 +steelhat,306,0 +steelcoif,306,0 +shelmet,306,0 +shelm,306,0 +shat,306,0 +scoif,306,0 +ironchestplate,307,0 +ironplatebody,307,0 +ironshirt,307,0 +irontunic,307,0 +ichestplate,307,0 +iplatebody,307,0 +ishirt,307,0 +itunic,307,0 +steelchestplate,307,0 +steelplatebody,307,0 +steelplate,307,0 +steelshirt,307,0 +steeltunic,307,0 +schestplate,307,0 +splatebody,307,0 +sshirt,307,0 +stunic,307,0 +ironleggings,308,0 +ironlegs,308,0 +ironpants,308,0 +ileggings,308,0 +ilegs,308,0 +ipants,308,0 +steelleggings,308,0 +steellegs,308,0 +steelpants,308,0 +sleggings,308,0 +slegs,308,0 +spants,308,0 +ironboots,309,0 +ironshoes,309,0 +iboots,309,0 +ishoes,309,0 +steelboots,309,0 +steelshoes,309,0 +sboots,309,0 +sshoes,309,0 +diamondhelmet,310,0 +diamondhelm,310,0 +diamondhat,310,0 +diamondcoif,310,0 +dhelmet,310,0 +dhelm,310,0 +dhat,310,0 +dcoif,310,0 +crystalhelmet,310,0 +crystalhelm,310,0 +crystalhat,310,0 +crystalcoif,310,0 +chelmet,310,0 +chelm,310,0 +chat,310,0 +ccoif,310,0 +diamondchestplate,311,0 +diamondplatebody,311,0 +diamondplate,311,0 +diamondshirt,311,0 +diamondtunic,311,0 +dchestplate,311,0 +dplatebody,311,0 +dplate,311,0 +dshirt,311,0 +dtunic,311,0 +crystalchestplate,311,0 +crystalplatebody,311,0 +crystalplate,311,0 +crystalshirt,311,0 +crystaltunic,311,0 +cchestplate,311,0 +cplatebody,311,0 +cplate,311,0 +cshirt,311,0 +ctunic,311,0 +diamondleggings,312,0 +diamondlegs,312,0 +diamondpants,312,0 +dleggings,312,0 +dlegs,312,0 +dpants,312,0 +crystalleggings,312,0 +crystallegs,312,0 +crystalpants,312,0 +cleggings,312,0 +clegs,312,0 +cpants,312,0 +diamondboots,313,0 +diamondshoes,313,0 +dboots,313,0 +dshoes,313,0 +crystalboots,313,0 +crystalshoes,313,0 +cboots,313,0 +cshoes,313,0 +goldhelmet,314,0 +goldhelm,314,0 +goldhat,314,0 +goldcoif,314,0 +ghelmet,314,0 +ghelm,314,0 +ghat,314,0 +gcoif,314,0 +goldchestplate,315,0 +goldplatebody,315,0 +goldshirt,315,0 +goldtunic,315,0 +gchestplate,315,0 +gplatebody,315,0 +gplateplate,315,0 +gshirt,315,0 +gtunic,315,0 +goldleggings,316,0 +goldlegs,316,0 +goldpants,316,0 +gleggings,316,0 +glegs,316,0 +gpants,316,0 +goldboots,317,0 +goldshoes,317,0 +gboots,317,0 +gshoes,317,0 +flint,318,0 +pork,319,0 +porkchop,319,0 +rawpork,319,0 +rpork,319,0 +rawporkchop,319,0 +rporkchop,319,0 +cookedpork,320,0 +grilledpork,320,0 +grillpork,320,0 +gpork,320,0 +cookpork,320,0 +cpork,320,0 +grilledporkchop,320,0 +grillporkchop,320,0 +gporkchop,320,0 +cookedporkchop,320,0 +cookporkchop,320,0 +cporkchop,320,0 +bacon,320,0 +painting,321,0 +picture,321,0 +goldenapple,322,0 +goldapple,322,0 +gapple,322,0 +enchantedgoldenapple,322,1 +enchantedgoldapple,322,1 +enchantedgapple,322,1 +supergoldenapple,322,1 +supergoldapple,322,1 +supergapple,322,1 +magicalgoldenapple,322,1 +magicalgoldapple,322,1 +magicalgapple,322,1 +magicgoldenapple,322,1 +magicgoldapple,322,1 +magicgapple,322,1 +egoldenapple,322,1 +egoldapple,322,1 +egapple,322,1 +sgoldenapple,322,1 +sgoldapple,322,1 +sgapple,322,1 +mgoldenapple,322,1 +mgoldapple,322,1 +mgapple,322,1 +sign,323,0 +woodendoor,324,0 +wooddoor,324,0 +wdoor,324,0 +door,324,0 +bucket,325,0 +bukkit,325,0 +waterbucket,326,0 +waterbukkit,326,0 +wbucket,326,0 +wbukkit,326,0 +magmabucket,327,0 +magmabukkit,327,0 +lavabucket,327,0 +lavabukkit,327,0 +lbucket,327,0 +lbukkit,327,0 +minecart,328,0 +mcart,328,0 +cart,328,0 +saddle,329,0 +irondoor,330,0 +idoor,330,0 +steeldoor,330,0 +sdoor,330,0 +dooriron,330,0 +doori,330,0 +doorsteel,330,0 +doors,330,0 +redstonedust,331,0 +redstone,331,0 +rstonedust,331,0 +rstone,331,0 +redsdust,331,0 +reddust,331,0 +rsdust,331,0 +rdust,331,0 +snow,332,0 +snowball,332,0 +snball,332,0 +sball,332,0 +boat,333,0 +leather,334,0 +cowhide,334,0 +hide,334,0 +milkbucket,335,0 +milkbukkit,335,0 +mbucket,335,0 +mbukkit,335,0 +claybrick,336,0 +brick,336,0 +redbrick,336,0 +rbrick,336,0 +clayball,337,0 +cball,337,0 +clay,337,0 +reeds,338,0 +reed,338,0 +sugarcane,338,0 +scane,338,0 +bamboo,338,0 +paper,339,0 +papyrus,339,0 +book,340,0 +slimeball,341,0 +slball,341,0 +chestminecart,342,0 +storageminecart,342,0 +storagemcart,342,0 +chestmcart,342,0 +storagecart,342,0 +chestcart,342,0 +sminecart,342,0 +cminecart,342,0 +smcart,342,0 +cmcart,342,0 +scart,342,0 +ccart,342,0 +furnaceminecart,343,0 +engineminecart,343,0 +poweredminecart,343,0 +powerminecart,343,0 +enginemcart,343,0 +poweredmcart,343,0 +powermcart,343,0 +furnacemcart,343,0 +enginecart,343,0 +poweredcart,343,0 +powercart,343,0 +furnacecart,343,0 +eminecart,343,0 +pminecart,343,0 +fminecart,343,0 +emcart,343,0 +pmcart,343,0 +fmcart,343,0 +ecart,343,0 +pcart,343,0 +fcart,343,0 +egg,344,0 +compass,345,0 +fishingrod,346,0 +fishrod,346,0 +frod,346,0 +rod,346,0 +watch,347,0 +goldwatch,347,0 +goldclock,347,0 +gwatch,347,0 +gclock,347,0 +clock,347,0 +glowstonedust,348,0 +glowingstonedust,348,0 +lightstonedust,348,0 +lbdust,348,0 +gbdust,348,0 +lsdust,348,0 +gsdust,348,0 +rawfish,349,0 +rafish,349,0 +fish,349,0 +rawsalmonfish,349,1 +rasalmonfish,349,1 +salmonfish,349,1 +rawsalmon,349,1 +rasalmon,349,1 +salmon,349,1 +sfish,349,1 +fishs,349,1 +rawclownfish,349,2 +raclownfish,349,2 +clownfish,349,2 +rawnemo,349,2 +ranemo,349,2 +nemo,349,2 +nemofish,349,2 +fishnemo,349,2 +clfish,349,2 +fishcl,349,2 +nfish,349,2 +fishn,349,2 +rawpufferfish,349,3 +rapufferfish,349,3 +pufferfish,349,3 +pufffish,349,3 +fishpuff,349,3 +pfish,349,3 +fishp,349,3 +cookedfish,350,0 +cookfish,350,0 +cfish,350,0 +grilledfish,350,0 +grillfish,350,0 +gfish,350,0 +roastedfish,350,0 +roastfish,350,0 +rofish,350,0 +cookedsalmonfish,350,1 +cooksalmonfish,350,1 +csalmonfish,350,1 +grilledsalmonfish,350,1 +grillsalmonfish,350,1 +gsalmonfish,350,1 +roastedsalmonfish,350,1 +roastsalmonfish,350,1 +rosalmonfish,350,1 +cookedsalmon,350,1 +cooksalmon,350,1 +csalmon,350,1 +grilledsalmon,350,1 +grillsalmon,350,1 +gsalmon,350,1 +roastedsalmon,350,1 +roastsalmon,350,1 +rosalmon,350,1 +dye,351,0 +inksack,351,0 +inksac,351,0 +isack,351,0 +isac,351,0 +sack,351,0 +sac,351,0 +blackinksack,351,0 +blackinksac,351,0 +blackisack,351,0 +blackisac,351,0 +blacksack,351,0 +blacksac,351,0 +inksackblack,351,0 +inksacblack,351,0 +isackblack,351,0 +isacblack,351,0 +sackblack,351,0 +sacblack,351,0 +blackinksackcolour,351,0 +blackinksaccolour,351,0 +blackisackcolour,351,0 +blackisaccolour,351,0 +blacksackcolour,351,0 +blacksaccolour,351,0 +inksackblackcolour,351,0 +inksacblackcolour,351,0 +isackblackcolour,351,0 +isacclackcolour,351,0 +sackblackcolour,351,0 +sacblackcolour,351,0 +blackinksackcolor,351,0 +blackinksaccolor,351,0 +blackisackcolor,351,0 +blackisaccolor,351,0 +blacksackcolor,351,0 +blacksaccolor,351,0 +inksackblackcolor,351,0 +inksacblackcolor,351,0 +isackblackcolor,351,0 +isacblackcolor,351,0 +sackblackcolor,351,0 +sacblackcolor,351,0 +blackinksackdye,351,0 +blackinksacdye,351,0 +blackisackdye,351,0 +blackisacdye,351,0 +blacksackdye,351,0 +blacksacdye,351,0 +inksackblackdye,351,0 +inksacblackdye,351,0 +isackblackdye,351,0 +isacclackdye,351,0 +sackblackdye,351,0 +sacblackdye,351,0 +blackcolor,351,0 +blackdye,351,0 +rosered,351,1 +roseredcolor,351,1 +roseredcolour,351,1 +rosereddye,351,1 +redrosecolor,351,1 +redrosecolour,351,1 +redrosedye,351,1 +redr,351,1 +redrcolor,351,1 +redrcolour,351,1 +redrdye,351,1 +redcolor,351,1 +redcolour,351,1 +reddye,351,1 +cactusgreen,351,2 +greencactus,351,2 +cactusgreencolour,351,2 +greencactuscolour,351,2 +cactusgreencolor,351,2 +greencactuscolor,351,2 +cactusgreendye,351,2 +greencactusdye,351,2 +greencolour,351,2 +greencolor,351,2 +greendye,351,2 +cocoabeans,351,3 +cocoabean,351,3 +cocobeans,351,3 +cocobean,351,3 +cbeans,351,3 +cbean,351,3 +beans,351,3 +bean,351,3 +browncocoabeans,351,3 +browncocoabean,351,3 +browncocobeans,351,3 +browncocobean,351,3 +browncbeans,351,3 +browncbean,351,3 +brownbeans,351,3 +brownbean,351,3 +brownb,351,3 +cocoabeanscolour,351,3 +cocoabeancolour,351,3 +cocobeanscolour,351,3 +cocobeancolour,351,3 +cbeanscolour,351,3 +cbeancolour,351,3 +beanscolour,351,3 +beancolour,351,3 +browncocoabeanscolour,351,3 +browncocoabeancolour,351,3 +browncocobeanscolour,351,3 +browncocobeancolour,351,3 +browncbeanscolour,351,3 +browncbeancolour,351,3 +brownbeanscolour,351,3 +brownbeancolour,351,3 +brownbcolour,351,3 +cocoabeanscolor,351,3 +cocoabeancolor,351,3 +cocobeanscolor,351,3 +cocobeancolor,351,3 +cbeanscolor,351,3 +cbeancolor,351,3 +beanscolor,351,3 +beancolor,351,3 +browncocoabeanscolor,351,3 +browncocoabeancolor,351,3 +browncocobeanscolor,351,3 +browncocobeancolor,351,3 +browncbeanscolor,351,3 +browncbeancolor,351,3 +brownbeanscolor,351,3 +brownbeancolor,351,3 +brownbcolor,351,3 +cocoabeansdye,351,3 +cocoabeandye,351,3 +cocobeansdye,351,3 +cocobeandye,351,3 +cbeansdye,351,3 +cbeandye,351,3 +beansdye,351,3 +beandye,351,3 +browncocoabeansdye,351,3 +browncocoabeandye,351,3 +browncocobeansdye,351,3 +browncocobeandye,351,3 +browncbeansdye,351,3 +browncbeandye,351,3 +brownbeansdye,351,3 +brownbeandye,351,3 +brownbdye,351,3 +browncolour,351,3 +browncolor,351,3 +browndye,351,3 +lapislazuli,351,4 +bluelapislazuli,351,4 +bluelapisl,351,4 +bluelapis,351,4 +bluel,351,4 +lapislazuliblue,351,4 +lapislblue,351,4 +lapisblue,351,4 +lapisl,351,4 +lapis,351,4 +bluelapislazulicolour,351,4 +bluelapislcolour,351,4 +bluelapiscolour,351,4 +lapislazulibluecolour,351,4 +lapislbluecolour,351,4 +lapisbluecolour,351,4 +lapislazulicolour,351,4 +lapislcolour,351,4 +lapiscolour,351,4 +bluelapislazulicolor,351,4 +bluelapislcolor,351,4 +bluelapiscolor,351,4 +lapislazulibluecolor,351,4 +lapislbluecolor,351,4 +lapisbluecolor,351,4 +lapislazulicolor,351,4 +lapislcolor,351,4 +lapiscolor,351,4 +bluelapislazulidye,351,4 +bluelapisldye,351,4 +bluelapisdye,351,4 +lapislazulibluedye,351,4 +lapislbluedye,351,4 +lapisbluedye,351,4 +lapislazulidye,351,4 +lapisldye,351,4 +lapisdye,351,4 +bluecolour,351,4 +bluecolor,351,4 +bluedye,351,4 +purpledye,351,5 +purplecolour,351,5 +purplecolor,351,5 +cyandye,351,6 +cyancolour,351,6 +cyancolor,351,6 +lightgraydye,351,7 +lightgraycolour,351,7 +lightgraycolor,351,7 +lgraycolour,351,7 +lgraycolor,351,7 +lgraydye,351,7 +lightgreydye,351,7 +lightgreycolour,351,7 +lightgreycolor,351,7 +lgreycolour,351,7 +lgreycolor,351,7 +lgreydye,351,7 +silvercolour,351,7 +silvercolor,351,7 +silverdye,351,7 +darkgraydye,351,8 +darkgraycolour,351,8 +darkgraycolor,351,8 +dgraycolour,351,8 +dgraycolor,351,8 +dgraydye,351,8 +graycolour,351,8 +graycolor,351,8 +graydye,351,8 +darkgreydye,351,8 +darkgreycolour,351,8 +darkgreycolor,351,8 +dgreycolour,351,8 +dgreycolor,351,8 +dgreydye,351,8 +greycolour,351,8 +greycolor,351,8 +greydye,351,8 +pinkdye,351,9 +pinkcolour,351,9 +pinkcolor,351,9 +limedye,351,10 +limecolour,351,10 +limecolor,351,10 +dandelionyellow,351,11 +dandelionyellowcolour,351,11 +dandelionyellowcolor,351,11 +dandelionyellowdye,351,11 +yellowdandelioncolour,351,11 +yellowdandelioncolor,351,11 +yellowdandeliondye,351,11 +yellowd,351,11 +yellowdcolour,351,11 +yellowdcolor,351,11 +yellowddye,351,11 +dyellow,351,11 +dyellowcolour,351,11 +dyellowcolor,351,11 +dyellowdye,351,11 +yellowcolour,351,11 +yellowcolor,351,11 +yellowdye,351,11 +lightbluecolour,351,12 +lightbluecolor,351,12 +lightbluedye,351,12 +lbluecolour,351,12 +lbluecolor,351,12 +lbluedye,351,12 +magentacolour,351,13 +magentacolor,351,13 +magentadye,351,13 +orangecolour,351,14 +orangecolor,351,14 +orangedye,351,14 +bonemeal,351,15 +whitebonemeal,351,15 +whitebonemealcolour,351,15 +whitebonemealcolor,351,15 +whitebonemealdye,351,15 +bonemealwhite,351,15 +bonemealwhitecolour,351,15 +bonemealwhitecolor,351,15 +bonemealwhitedye,351,15 +whitebonem,351,15 +whitebonemcolour,351,15 +whitebonemcolor,351,15 +whitebonemdye,351,15 +bonemwhite,351,15 +bonemwhitecolour,351,15 +bonemwhitecolor,351,15 +bonemwhitedye,351,15 +bonemealcolour,351,15 +bonemealcolor,351,15 +bonemealdye,351,15 +bonem,351,15 +bonemcolour,351,15 +bonemcolor,351,15 +bonemdye,351,15 +whitecolour,351,15 +whitecolor,351,15 +whitedye,351,15 +bone,352,0 +sugar,353,0 +whitedust,353,0 +cake,354,0 +bed,355,0 +redstonerepeater,356,0 +redstonerepeat,356,0 +redstonedelayer,356,0 +redstonedelay,356,0 +redstonedioder,356,0 +redstonediode,356,0 +rstonerepeater,356,0 +rstonerepeat,356,0 +rstonedelayer,356,0 +rstonedelay,356,0 +rstonedioder,356,0 +rstonediode,356,0 +redsrepeater,356,0 +redsrepeat,356,0 +redsdelayer,356,0 +redsdelay,356,0 +redsdioder,356,0 +redsdiode,356,0 +rsrepeater,356,0 +rsrepeat,356,0 +rsdelayer,356,0 +rsdelay,356,0 +rsdioder,356,0 +rsdiode,356,0 +repeater,356,0 +repeat,356,0 +delayer,356,0 +delay,356,0 +dioder,356,0 +diode,356,0 +cookie,357,0 +chart,358,0 +map0,358,0 +map1,358,1 +map2,358,2 +map3,358,3 +map4,358,4 +map5,358,5 +map6,358,6 +map7,358,7 +map8,358,8 +map9,358,9 +map10,358,10 +map11,358,11 +map12,358,12 +map13,358,13 +map14,358,14 +map15,358,15 +shears,359,0 +shear,359,0 +sheers,359,0 +sheer,359,0 +woolcutters,359,0 +woolcutter,359,0 +cutterswool,359,0 +cutterwool,359,0 +melonslice,360,0 +mslice,360,0 +slicemelon,360,0 +watermelonslice,360,0 +greenmelonslice,360,0 +melongreenslice,360,0 +pumpkinseeds,361,0 +pseeds,361,0 +seedsp,361,0 +seedspumpkin,361,0 +pumpseeds,361,0 +seedspump,361,0 +melonseeds,362,0 +mseeds,362,0 +watermelonseeds,362,0 +greenmelonseeds,362,0 +gmelonseeds,362,0 +seedsmelon,362,0 +seedswatermelon,362,0 +rawbeef,363,0 +rawsteak,363,0 +uncookedbeef,363,0 +uncookedsteak,363,0 +cowmeat,363,0 +plainbeef,363,0 +beef,364,0 +steak,364,0 +cookedbeef,364,0 +grilledbeef,364,0 +cookedsteak,364,0 +grilledsteak,364,0 +cookedcowmeat,364,0 +rawchicken,365,0 +uncookedchicken,365,0 +plainchicken,365,0 +chickenplain,365,0 +chickenuncooked,365,0 +chickenraw,365,0 +cookedchicken,366,0 +grilledchicken,366,0 +toastedchicken,366,0 +gchicken,366,0 +bbqchicken,366,0 +friedchicken,366,0 +cchicken,366,0 +rottenflesh,367,0 +zombieflesh,367,0 +rottenmeat,367,0 +zombiemeat,367,0 +badflesh,367,0 +poisonflesh,367,0 +zombieremains,367,0 +enderpearl,368,0 +endpearl,368,0 +pearl,368,0 +epearl,368,0 +bluepearl,368,0 +endergem,368,0 +blazerod,369,0 +goldenrod,369,0 +goldrod,369,0 +blazestick,369,0 +goldstick,369,0 +brod,369,0 +grod,369,0 +bstick,369,0 +gstick,369,0 +ghasttear,370,0 +ghastdrop,370,0 +ghosttear,370,0 +ghostdrop,370,0 +gtear,370,0 +gdrop,370,0 +tear,370,0 +goldnugget,371,0 +gnugget,371,0 +goldpebble,371,0 +gpebble,371,0 +goldball,371,0 +gball,371,0 +netherstalk,372,0 +deathstalk,372,0 +hellstalk,372,0 +nstalk,372,0 +dstalk,372,0 +hstalk,372,0 +netherwarts,372,0 +netherwart,372,0 +netherplant,372,0 +nethercrop,372,0 +hellwarts,372,0 +hellwart,372,0 +hellplant,372,0 +hellcrop,372,0 +deathwarts,372,0 +deathwart,372,0 +deathplant,372,0 +deathcrop,372,0 +nwarts,372,0 +nwart,372,0 +ncrop,372,0 +nplant,372,0 +hwarts,372,0 +hwart,372,0 +hplant,372,0 +hcrop,372,0 +dwarts,372,0 +dwart,372,0 +dplant,372,0 +dcrop,372,0 +potion,373,0 +mixture,373,0 +potions,373,0 +waterbottle,373,0 +fullbottle,373,0 +watervase,373,0 +fullvase,373,0 +clearpotion,373,6 +clearpot,373,6 +clearextendedpotion,373,7 +clearexpotion,373,7 +clear2potion,373,7 +clearextendedpot,373,7 +clearexpot,373,7 +clear2pot,373,7 +diffusepotion,373,11 +diffusepot,373,11 +artlesspotion,373,13 +artlesspot,373,13 +thinpotion,373,14 +thinpot,373,14 +thinextendedpotion,373,15 +thinexpotion,373,15 +thin2potion,373,15 +thinextendedpot,373,15 +thinexpot,373,15 +thin2pot,373,15 +awkwardpotion,373,16 +awkwardpot,373,16 +bunglingpotion,373,22 +bunglingpot,373,22 +bunglingextendedpotion,373,23 +bunglingexpotion,373,23 +bungling2potion,373,23 +bunglingextendedpot,373,23 +bunglingexpot,373,23 +bungling2pot,373,23 +smoothpotion,373,27 +smoothpot,373,27 +suavepotion,373,29 +suavepot,373,29 +debonairpotion,373,30 +debonairpot,373,30 +debonairextendedpotion,373,31 +debonairexpotion,373,31 +debonair2potion,373,31 +debonairextendedpot,373,31 +debonairexpot,373,31 +debonair2pot,373,31 +thickpotion,373,32 +thickpot,373,32 +charmingpotion,373,38 +charmingpot,373,38 +charmingextendedpotion,373,39 +charmingexpotion,373,39 +charming2potion,373,39 +charmingextendedpot,373,39 +charmingexpot,373,39 +charming2pot,373,39 +refinedpotion,373,43 +refinedpot,373,43 +cordialpotion,373,45 +cordialpot,373,45 +sparklingpotion,373,46 +sparklingpot,373,46 +sparklingextendedpotion,373,47 +sparklingexpotion,373,47 +sparkling2potion,373,47 +sparklingextendedpot,373,47 +sparklingexpot,373,47 +sparkling2pot,373,47 +potentpotion,373,48 +potentpot,373,48 +rankpotion,373,54 +rankpot,373,54 +rankextendedpotion,373,55 +rankexpotion,373,55 +rank2potion,373,55 +rankextendedpot,373,55 +rankexpot,373,55 +rank2pot,373,55 +acridpotion,373,59 +acridpot,373,59 +grosspotion,373,61 +grosspot,373,61 +stinkypotion,373,62 +stinkypot,373,62 +stinkyextendedpotion,373,63 +stinkyexpotion,373,63 +stinky2potion,373,63 +stinkyextendedpot,373,63 +stinkyexpot,373,63 +stinky2pot,373,63 +mundaneextendedpotion,373,64 +mundaneexpotion,373,64 +mundane2potion,373,64 +mundaneextendedpot,373,64 +mundaneexpot,373,64 +mundane2pot,373,64 +mundanepotion,373,8192 +mundanepot,373,8192 +regenerationpotion,373,8193 +regeneratepotion,373,8193 +regenpotion,373,8193 +regenerationpot,373,8193 +regeneratepot,373,8193 +regenpot,373,8193 +rpot,373,8193 +swiftnesspotion,373,8194 +swiftpotion,373,8194 +speedpotion,373,8194 +swiftnesspot,373,8194 +swiftpot,373,8194 +speedpot,373,8194 +swpot,373,8194 +fireresistancepotion,373,8195 +fireresistpotion,373,8195 +firerespotion,373,8195 +fireresistancepot,373,8195 +fireresistpot,373,8195 +firerespot,373,8195 +fpot,373,8195 +poisonpotion,373,8196 +acidpotion,373,8196 +poisonpot,373,8196 +acidpot,373,8196 +ppot,373,8196 +healingpotion,373,8197 +healpotion,373,8197 +lifepotion,373,8197 +healingpot,373,8197 +healpot,373,8197 +lifepot,373,8197 +hpot,373,8197 +nightvisionpotion,373,8198 +nvisionpotion,373,8198 +nightvpotion,373,8198 +darkvisionpotion,373,8198 +dvisionpotion,373,8198 +darkvpotion,373,8198 +nightvisionpot,373,8198 +nvisionpot,373,8198 +nightvpot,373,8198 +darkvisionpot,373,8198 +dvisionpot,373,8198 +darkvpot,373,8198 +npot,373,8198 +weaknesspotion,373,8200 +weakpotion,373,8200 +weaknesspot,373,8200 +weakpot,373,8200 +wpot,373,8200 +strengthpotion,373,8201 +strongpotion,373,8201 +strpotion,373,8201 +strengthpot,373,8201 +strongpot,373,8201 +strpot,373,8201 +stpot,373,8201 +slownesspotion,373,8202 +slowpotion,373,8202 +slownesspot,373,8202 +slowpot,373,8202 +slpot,373,8202 +harmingpotion,373,8204 +damagepotion,373,8204 +dmgpotion,373,8204 +harmingpot,373,8204 +damagepot,373,8204 +dmgpot,373,8204 +dpot,373,8204 +waterbreathingpotion,373,8205 +waterbreathpotion,373,8205 +breathingpotion,373,8205 +breathpotion,373,8205 +waterbreathingpot,373,8205 +waterbreathpot,373,8205 +breathingpot,373,8205 +breathpot,373,8205 +wbpot,373,8205 +invisibilitypotion,373,8206 +invisiblepotion,373,8206 +invpotion,373,8206 +invisibilitypot,373,8206 +invisiblepot,373,8206 +invpot,373,8206 +ipot,373,8206 +regenerationleveliipotion,373,8225 +regenerateleveliipotion,373,8225 +regenleveliipotion,373,8225 +regenerationlevel2potion,373,8225 +regeneratelevel2potion,373,8225 +regenlevel2potion,373,8225 +regenerationiipotion,373,8225 +regenerateiipotion,373,8225 +regeniipotion,373,8225 +regenerationleveliipot,373,8225 +regenerateleveliipot,373,8225 +regenleveliipot,373,8225 +regenerationlevel2pot,373,8225 +regeneratelevel2pot,373,8225 +regenlevel2pot,373,8225 +regenerationiipot,373,8225 +regenerateiipot,373,8225 +regeniipot,373,8225 +r2pot,373,8225 +swiftnessleveliipotion,373,8226 +swiftleveliipotion,373,8226 +speedleveliipotion,373,8226 +swiftnesslevel2potion,373,8226 +swiftlevel2potion,373,8226 +speedlevel2potion,373,8226 +swiftnessiipotion,373,8226 +swiftiipotion,373,8226 +speediipotion,373,8226 +swiftnessleveliipot,373,8226 +swiftleveliipot,373,8226 +speedleveliipot,373,8226 +swiftnesslevel2pot,373,8226 +swiftlevel2pot,373,8226 +speedlevel2pot,373,8226 +swiftnessiipot,373,8226 +swiftiipot,373,8226 +speediipot,373,8226 +sw2pot,373,8226 +poisonleveliipotion,373,8228 +acidleveliipotion,373,8228 +poisonlevel2potion,373,8228 +acidlevel2potion,373,8228 +poisoniipotion,373,8228 +acidiipotion,373,8228 +poisonleveliipot,373,8228 +acidleveliipot,373,8228 +poisonlevel2pot,373,8228 +acidlevel2pot,373,8228 +poisoniipot,373,8228 +acidiipot,373,8228 +p2pot,373,8228 +healingleveliipotion,373,8229 +healleveliipotion,373,8229 +healinglevel2potion,373,8229 +heallevel2potion,373,8229 +healingiipotion,373,8229 +healiipotion,373,8229 +healingleveliipot,373,8229 +healleveliipot,373,8229 +healinglevel2pot,373,8229 +heallevel2pot,373,8229 +healingiipot,373,8229 +healiipot,373,8229 +h2pot,373,8229 +strengthleveliipotion,373,8233 +strongleveliipotion,373,8233 +strleveliipotion,373,8233 +strengthlevel2potion,373,8233 +stronglevel2potion,373,8233 +strlevel2potion,373,8233 +strengthiipotion,373,8233 +strongiipotion,373,8233 +striipotion,373,8233 +strengthleveliipot,373,8233 +strongleveliipot,373,8233 +strleveliipot,373,8233 +strengthlevel2pot,373,8233 +stronglevel2pot,373,8233 +strlevel2pot,373,8233 +strengthiipot,373,8233 +strongiipot,373,8233 +striipot,373,8233 +st2pot,373,8233 +harmingleveliipotion,373,8236 +damageleveliipotion,373,8236 +dmgleveliipotion,373,8236 +harminglevel2potion,373,8236 +damagelevel2potion,373,8236 +dmglevel2potion,373,8236 +harmingiipotion,373,8236 +damageiipotion,373,8236 +dmgiipotion,373,8236 +harmingleveliipot,373,8236 +damageleveliipot,373,8236 +dmgleveliipot,373,8236 +harminglevel2pot,373,8236 +damagelevel2pot,373,8236 +dmglevel2pot,373,8236 +harmingiipot,373,8236 +damageiipot,373,8236 +dmgiipot,373,8236 +d2pot,373,8236 +regenerationextendedpotion,373,8257 +regenerateextendedpotion,373,8257 +regenextendepotion,373,8257 +regenerationexpotion,373,8257 +regenerateexpotion,373,8257 +regenexpotion,373,8257 +regenerationextendedpot,373,8257 +regenerateextendedpot,373,8257 +regenextendepot,373,8257 +regenerationexpot,373,8257 +regenerateexpot,373,8257 +regenexpot,373,8257 +repot,373,8257 +swiftnessextendedpotion,373,8258 +swiftextendedpotion,373,8258 +speedextendedpotion,373,8258 +swiftnessexpotion,373,8258 +swiftexpotion,373,8258 +speedexpotion,373,8258 +swiftnessextendedpot,373,8258 +swiftextendedpot,373,8258 +speedextendedpot,373,8258 +swiftnessexpot,373,8258 +swiftexpot,373,8258 +speedexpot,373,8258 +swepot,373,8258 +fireresistanceextendedpotion,373,8259 +fireresistextendedpotion,373,8259 +fireresextendedpotion,373,8259 +fireresistanceexpotion,373,8259 +fireresistexpotion,373,8259 +fireresexpotion,373,8259 +fireresistanceextendedpot,373,8259 +fireresistextendedpot,373,8259 +fireresextendedpot,373,8259 +fireresistanceexpot,373,8259 +fireresistexpot,373,8259 +fireresexpot,373,8259 +fepot,373,8259 +poisonextendedpotion,373,8260 +acidextendedpotion,373,8260 +poisonexpotion,373,8260 +acidexpotion,373,8260 +poisonextendedpot,373,8260 +acidextendedpot,373,8260 +poisonexpot,373,8260 +acidexpot,373,8260 +pepot,373,8260 +nightvisionextendedpotion,373,8262 +nvisionextendedpotion,373,8262 +nightvextendedpotion,373,8262 +darkvisionextendedpotion,373,8262 +dvisionextendedpotion,373,8262 +darkvextendedpotion,373,8262 +nightvisionexpotion,373,8262 +nvisionexpotion,373,8262 +nightvexpotion,373,8262 +darkvisionexpotion,373,8262 +dvisionexpotion,373,8262 +darkvexpotion,373,8262 +nightvisionextendedpot,373,8262 +nvisionextendedpot,373,8262 +nightvextendedpot,373,8262 +darkvisionextendedpot,373,8262 +dvisionextendedpot,373,8262 +darkvextendedpot,373,8262 +nightvisionexpot,373,8262 +nvisionexpot,373,8262 +nightvexpot,373,8262 +darkvisionexpot,373,8262 +dvisionexpot,373,8262 +darkvexpot,373,8262 +nepot,373,8262 +weaknessextendedpotion,373,8264 +weakextendedpotion,373,8264 +weaknessexpotion,373,8264 +weakexpotion,373,8264 +weaknessextendedpot,373,8264 +weakextendedpot,373,8264 +weaknessexpot,373,8264 +weakexpot,373,8264 +wepot,373,8264 +strengthextendedpotion,373,8265 +strongextendedpotion,373,8265 +strextendedpotion,373,8265 +strengthexpotion,373,8265 +strongexpotion,373,8265 +strexpotion,373,8265 +strengthextendedpot,373,8265 +strongextendedpot,373,8265 +strextendedpot,373,8265 +strengthexpot,373,8265 +strongexpot,373,8265 +strexpot,373,8265 +stepot,373,8265 +slownessextendedpotion,373,8266 +slowextenedpotion,373,8266 +slownessexpotion,373,8266 +slowexpotion,373,8266 +slownessextendedpot,373,8266 +slowextenedpot,373,8266 +slownessexpot,373,8266 +slowexpot,373,8266 +slepot,373,8266 +waterbreathingextendedpotion,373,8269 +waterbreathextendedpotion,373,8269 +breathingextendedpotion,373,8269 +breathextendedpotion,373,8269 +waterbreathingextendedpot,373,8269 +waterbreathextendedpot,373,8269 +breathingextendedpot,373,8269 +breathextendedpot,373,8269 +waterbreathingexpotion,373,8269 +waterbreathexpotion,373,8269 +breathingexpotion,373,8269 +breathexpotion,373,8269 +waterbreathingexpot,373,8269 +waterbreathexpot,373,8269 +breathingexpot,373,8269 +breathexpot,373,8269 +wbepot,373,8269 +invisibilityextendedpotion,373,8270 +invisibleextendedpotion,373,8270 +invextendedpotion,373,8270 +invisibilityexpotion,373,8270 +invisibleexpotion,373,8270 +invexpotion,373,8270 +invisibilityextendedpot,373,8270 +invisibleextendedpot,373,8270 +invextendedpot,373,8270 +invisibilityexpot,373,8270 +invisibleexpot,373,8270 +invexpot,373,8270 +iepot,373,8270 +regenerationdualbitpotion,373,8289 +regeneratedualbitpotion,373,8289 +regendualbitpotion,373,8289 +regenerationdbpotion,373,8289 +regeneratedbpotion,373,8289 +regendbpotion,373,8289 +regenerationdualbitpot,373,8289 +regeneratedualbitpot,373,8289 +regendualbitpot,373,8289 +regenerationdbpot,373,8289 +regeneratedbpot,373,8289 +regendbpot,373,8289 +rdbpot,373,8289 +swiftnessdualbitpotion,373,8290 +swiftdualbitpotion,373,8290 +speeddualbitpotion,373,8290 +swiftnessdualbitpot,373,8290 +swiftdualbitpot,373,8290 +speeddualbitpot,373,8290 +swiftnessdbpotion,373,8290 +swiftdbpotion,373,8290 +speeddbpotion,373,8290 +swiftnessdbpot,373,8290 +swiftdbpot,373,8290 +speeddbpot,373,8290 +swdbpot,373,8290 +poisondualbitpotion,373,8292 +aciddualbitpotion,373,8292 +poisondualbitpot,373,8292 +aciddualbitpot,373,8292 +poisondbpotion,373,8292 +aciddbpotion,373,8292 +poisondbpot,373,8292 +aciddbpot,373,8292 +pdbpot,373,8292 +strengthdualbitpotion,373,8297 +strongdualbitpotion,373,8297 +strdualbitpotion,373,8297 +strengthdualbitpot,373,8297 +strongdualbitpot,373,8297 +strdualbitpot,373,8297 +strengthdbpotion,373,8297 +strongdbpotion,373,8297 +strdbpotion,373,8297 +strengthdbpot,373,8297 +strongdbpot,373,8297 +strdbpot,373,8297 +stdbpot,373,8297 +splashmundanepotion,373,16384 +splmundanepotion,373,16384 +splashregenerationpotion,373,16385 +splashregeneratepotion,373,16385 +splashregenpotion,373,16385 +splashregenerationpot,373,16385 +splashregeneratepot,373,16385 +splashregenpot,373,16385 +regenerationsplashpotion,373,16385 +regeneratesplashpotion,373,16385 +regensplashpotion,373,16385 +splregenerationpotion,373,16385 +splregeneratepotion,373,16385 +splregenpotion,373,16385 +splregenerationpot,373,16385 +splregeneratepot,373,16385 +splregenpot,373,16385 +sprpot,373,16385 +splashswiftnesspotion,373,16386 +splashswiftpotion,373,16386 +splashspeedpotion,373,16386 +splashswiftnesspot,373,16386 +splashswiftpot,373,16386 +splashspeedpot,373,16386 +splswiftnesspotion,373,16386 +splswiftpotion,373,16386 +splspeedpotion,373,16386 +splswiftnesspot,373,16386 +splswiftpot,373,16386 +splspeedpot,373,16386 +spswpot,373,16386 +splashfireresistancepotion,373,16387 +splashfireresistpotion,373,16387 +splashfirerespotion,373,16387 +splashfireresistancepot,373,16387 +splashfireresistpot,373,16387 +splashfirerespot,373,16387 +splfireresistancepotion,373,16387 +splfireresistpotion,373,16387 +splfirerespotion,373,16387 +splfireresistancepot,373,16387 +splfireresistpot,373,16387 +splfirerespot,373,16387 +spfpot,373,16387 +splashpoisonpotion,373,16388 +splashacidpotion,373,16388 +splashpoisonpot,373,16388 +splashacidpot,373,16388 +splpoisonpotion,373,16388 +splacidpotion,373,16388 +splpoisonpot,373,16388 +splacidpot,373,16388 +spppot,373,16388 +splashhealingpotion,373,16389 +splashhealpotion,373,16389 +splashlifepotion,373,16389 +splashhealingpot,373,16389 +splashhealpot,373,16389 +splashlifepot,373,16389 +splhealingpotion,373,16389 +splhealpotion,373,16389 +spllifepotion,373,16389 +splhealingpot,373,16389 +splhealpot,373,16389 +spllifepot,373,16389 +sphpot,373,16389 +splashclearpotion,373,16390 +splashclearpot,373,16390 +splclearpotion,373,16390 +splclearpot,373,16390 +splashnightvisionpotion,373,16390 +splashnvisionpotion,373,16390 +splashnightvpotion,373,16390 +splashdarkvisionpotion,373,16390 +splashdvisionpotion,373,16390 +splashdarkvpotion,373,16390 +splashnightvisionpot,373,16390 +splashnvisionpot,373,16390 +splashnightvpot,373,16390 +splashdarkvisionpot,373,16390 +splashdvisionpot,373,16390 +splashdarkvpot,373,16390 +splnightvisionpotion,373,16390 +splnvisionpotion,373,16390 +splnightvpotion,373,16390 +spldarkvisionpotion,373,16390 +spldvisionpotion,373,16390 +spldarkvpotion,373,16390 +splnightvisionpot,373,16390 +splnvisionpot,373,16390 +splnightvpot,373,16390 +spldarkvisionpot,373,16390 +spldvisionpot,373,16390 +spldarkvpot,373,16390 +spnpot,373,16390 +splashclearextendedpotion,373,16391 +splashclearexpotion,373,16391 +splashclear2potion,373,16391 +splashclearextendedpot,373,16391 +splashclearexpot,373,16391 +splashclear2pot,373,16391 +splclearextendedpotion,373,16391 +splclearexpotion,373,16391 +splclear2potion,373,16391 +splclearextendedpot,373,16391 +splclearexpot,373,16391 +splclear2pot,373,16391 +splashweaknesspotion,373,16392 +splashweakpotion,373,16392 +splashweaknesspot,373,16392 +splashweakpot,373,16392 +splweaknesspotion,373,16392 +splweakpotion,373,16392 +splweaknesspot,373,16392 +splweakpot,373,16392 +spwpot,373,16392 +splashstrengthpotion,373,16393 +splashstrongpotion,373,16393 +splashstrpotion,373,16393 +splashstrengthpot,373,16393 +splashstrongpot,373,16393 +splashstrpot,373,16393 +splstrengthpotion,373,16393 +splstrongpotion,373,16393 +splstrpotion,373,16393 +splstrengthpot,373,16393 +splstrongpot,373,16393 +splstrpot,373,16393 +spstpot,373,16393 +splashslownesspotion,373,16394 +splashslowpotion,373,16394 +splashslownesspot,373,16394 +splashslowpot,373,16394 +splslownesspotion,373,16394 +splslowpotion,373,16394 +splslownesspot,373,16394 +splslowpot,373,16394 +spslpot,373,16394 +splashdiffusepotion,373,16395 +splashdiffusepot,373,16395 +spldiffusepotion,373,16395 +spldiffusepot,373,16395 +splashharmingpotion,373,16396 +splashdamagepotion,373,16396 +splashdmgpotion,373,16396 +splashharmingpot,373,16396 +splashdamagepot,373,16396 +splashdmgpot,373,16396 +splharmingpotion,373,16396 +spldamagepotion,373,16396 +spldmgpotion,373,16396 +splharmingpot,373,16396 +spldamagepot,373,16396 +spldmgpot,373,16396 +spdpot,373,16396 +splashartlesspotion,373,16397 +splashartlesspot,373,16397 +splartlesspotion,373,16397 +splartlesspot,373,16397 +splashwaterbreathingpotion,373,16397 +splashwaterbreathpotion,373,16397 +splashbreathingpotion,373,16397 +splashbreathpotion,373,16397 +splashwaterbreathingpot,373,16397 +splashwaterbreathpot,373,16397 +splashbreathingpot,373,16397 +splashbreathpot,373,16397 +splwaterbreathingpotion,373,16397 +splwaterbreathpotion,373,16397 +splbreathingpotion,373,16397 +splbreathpotion,373,16397 +splwaterbreathingpot,373,16397 +splwaterbreathpot,373,16397 +splbreathingpot,373,16397 +splbreathpot,373,16397 +spwbpot,373,16397 +splashthinpotion,373,16398 +splashthinpot,373,16398 +splthinpotion,373,16398 +splthinpot,373,16398 +splashinvisibilitypotion,373,16398 +splashinvisiblepotion,373,16398 +splashinvpotion,373,16398 +splashinvisibilitypot,373,16398 +splashinvisiblepot,373,16398 +splashinvpot,373,16398 +splinvisibilitypotion,373,16398 +splinvisiblepotion,373,16398 +splinvpotion,373,16398 +splinvisibilitypot,373,16398 +splinvisiblepot,373,16398 +splinvpot,373,16398 +spipot,373,16398 +splashthinextendedpotion,373,16399 +splashthinexpotion,373,16399 +splashthin2potion,373,16399 +splashthinextendedpot,373,16399 +splashthinexpot,373,16399 +splashthin2pot,373,16399 +splthinextendedpotion,373,16399 +splthinexpotion,373,16399 +splthin2potion,373,16399 +splthinextendedpot,373,16399 +splthinexpot,373,16399 +splthin2pot,373,16399 +splashawkwardpotion,373,16400 +splashawkwardpot,373,16400 +splawkwardpotion,373,16400 +splawkwardpot,373,16400 +splashbunglingpotion,373,16406 +splashbunglingpot,373,16406 +splbunglingpotion,373,16406 +splbunglingpot,373,16406 +splashbunglingextendedpotion,373,16407 +splashbunglingexpotion,373,16407 +splashbungling2potion,373,16407 +splashbunglingextendedpot,373,16407 +splashbunglingexpot,373,16407 +splashbungling2pot,373,16407 +splbunglingextendedpotion,373,16407 +splbunglingexpotion,373,16407 +splbungling2potion,373,16407 +splbunglingextendedpot,373,16407 +splbunglingexpot,373,16407 +splbungling2pot,373,16407 +splashsmoothpotion,373,16411 +splashsmoothpot,373,16411 +splsmoothpotion,373,16411 +splsmoothpot,373,16411 +splashsuavepotion,373,16413 +splashsuavepot,373,16413 +splsuavepotion,373,16413 +splsuavepot,373,16413 +splashdebonairpotion,373,16414 +splashdebonairpot,373,16414 +spldebonairpotion,373,16414 +spldebonairpot,373,16414 +splashdebonairextendedpotion,373,16415 +splashdebonairexpotion,373,16415 +splashdebonair2potion,373,16415 +splashdebonairextendedpot,373,16415 +splashdebonairexpot,373,16415 +splashdebonair2pot,373,16415 +spldebonairextendedpotion,373,16415 +spldebonairexpotion,373,16415 +spldebonair2potion,373,16415 +spldebonairextendedpot,373,16415 +spldebonairexpot,373,16415 +spldebonair2pot,373,16415 +splashthickpotion,373,16416 +splashthickpot,373,16416 +splthickpotion,373,16416 +splthickpot,373,16416 +splashregenerationleveliipotion,373,16417 +splashregenerateleveliipotion,373,16417 +splashregenleveliipotion,373,16417 +splashregenerationlevel2potion,373,16417 +splashregeneratelevel2potion,373,16417 +splashregenlevel2potion,373,16417 +splashregenerationiipotion,373,16417 +splashregenerateiipotion,373,16417 +splashregeniipotion,373,16417 +splashregenerationleveliipot,373,16417 +splashregenerateleveliipot,373,16417 +splashregenleveliipot,373,16417 +splashregenerationlevel2pot,373,16417 +splashregeneratelevel2pot,373,16417 +splashregenlevel2pot,373,16417 +splashregenerationiipot,373,16417 +splashregenerateiipot,373,16417 +splashregeniipot,373,16417 +splregenerationleveliipotion,373,16417 +splregenerateleveliipotion,373,16417 +splregenleveliipotion,373,16417 +splregenerationlevel2potion,373,16417 +splregeneratelevel2potion,373,16417 +splregenlevel2potion,373,16417 +splregenerationiipotion,373,16417 +splregenerateiipotion,373,16417 +splregeniipotion,373,16417 +splregenerationleveliipot,373,16417 +splregenerateleveliipot,373,16417 +splregenleveliipot,373,16417 +splregenerationlevel2pot,373,16417 +splregeneratelevel2pot,373,16417 +splregenlevel2pot,373,16417 +splregenerationiipot,373,16417 +splregenerateiipot,373,16417 +splregeniipot,373,16417 +spr2pot,373,16417 +splashswiftnessleveliipotion,373,16418 +splashswiftleveliipotion,373,16418 +splashspeedleveliipotion,373,16418 +splashswiftnesslevel2potion,373,16418 +splashswiftlevel2potion,373,16418 +splashspeedlevel2potion,373,16418 +splashswiftnessiipotion,373,16418 +splashswiftiipotion,373,16418 +splashspeediipotion,373,16418 +splashswiftnessleveliipot,373,16418 +splashswiftleveliipot,373,16418 +splashspeedleveliipot,373,16418 +splashswiftnesslevel2pot,373,16418 +splashswiftlevel2pot,373,16418 +splashspeedlevel2pot,373,16418 +splashswiftnessiipot,373,16418 +splashswiftiipot,373,16418 +splashspeediipot,373,16418 +splswiftnessleveliipotion,373,16418 +splswiftleveliipotion,373,16418 +splspeedleveliipotion,373,16418 +splswiftnesslevel2potion,373,16418 +splswiftlevel2potion,373,16418 +splspeedlevel2potion,373,16418 +splswiftnessiipotion,373,16418 +splswiftiipotion,373,16418 +splspeediipotion,373,16418 +splswiftnessleveliipot,373,16418 +splswiftleveliipot,373,16418 +splspeedleveliipot,373,16418 +splswiftnesslevel2pot,373,16418 +splswiftlevel2pot,373,16418 +splspeedlevel2pot,373,16418 +splswiftnessiipot,373,16418 +splswiftiipot,373,16418 +splspeediipot,373,16418 +spsw2pot,373,16418 +splashpoisonleveliipotion,373,16420 +splashacidleveliipotion,373,16420 +splashpoisonlevel2potion,373,16420 +splashacidlevel2potion,373,16420 +splashpoisoniipotion,373,16420 +splashacidiipotion,373,16420 +splashpoisonleveliipot,373,16420 +splashacidleveliipot,373,16420 +splashpoisonlevel2pot,373,16420 +splashacidlevel2pot,373,16420 +splashpoisoniipot,373,16420 +splashacidiipot,373,16420 +splpoisonleveliipotion,373,16420 +splacidleveliipotion,373,16420 +splpoisonlevel2potion,373,16420 +splcidlevel2potion,373,16420 +splpoisoniipotion,373,16420 +splacidiipotion,373,16420 +splpoisonleveliipot,373,16420 +splacidleveliipot,373,16420 +splpoisonlevel2pot,373,16420 +splacidlevel2pot,373,16420 +splpoisoniipot,373,16420 +splacidiipot,373,16420 +spp2pot,373,16420 +splashhealingleveliipotion,373,16421 +splashhealleveliipotion,373,16421 +splashhealinglevel2potion,373,16421 +splashheallevel2potion,373,16421 +splashhealingiipotion,373,16421 +splashhealiipotion,373,16421 +splashhealingleveliipot,373,16421 +splashhealleveliipot,373,16421 +splashhealinglevel2pot,373,16421 +splashheallevel2pot,373,16421 +splashhealingiipot,373,16421 +splashhealiipot,373,16421 +splhealingleveliipotion,373,16421 +splhealleveliipotion,373,16421 +splhealinglevel2potion,373,16421 +splheallevel2potion,373,16421 +splhealingiipotion,373,16421 +splhealiipotion,373,16421 +splhealingleveliipot,373,16421 +splhealleveliipot,373,16421 +splhealinglevel2pot,373,16421 +splheallevel2pot,373,16421 +splhealingiipot,373,16421 +splhealiipot,373,16421 +sph2pot,373,16421 +splashcharmingpotion,373,16422 +splashcharmingpot,373,16422 +splcharmingpotion,373,16422 +splcharmingpot,373,16422 +splashcharmingextendedpotion,373,16423 +splashcharmingexpotion,373,16423 +splashcharming2potion,373,16423 +splashcharmingextendedpot,373,16423 +splashcharmingexpot,373,16423 +splashcharming2pot,373,16423 +splcharmingextendedpotion,373,16423 +splcharmingexpotion,373,16423 +splcharming2potion,373,16423 +splcharmingextendedpot,373,16423 +splcharmingexpot,373,16423 +splcharming2pot,373,16423 +splashstrengthleveliipotion,373,16425 +splashstrongleveliipotion,373,16425 +splashstrleveliipotion,373,16425 +splashstrengthlevel2potion,373,16425 +splashstronglevel2potion,373,16425 +splashstrlevel2potion,373,16425 +splashstrengthiipotion,373,16425 +splashstrongiipotion,373,16425 +splashstriipotion,373,16425 +splashstrengthleveliipot,373,16425 +splashstrongleveliipot,373,16425 +splashstrleveliipot,373,16425 +splashstrengthlevel2pot,373,16425 +splashstronglevel2pot,373,16425 +splashstrlevel2pot,373,16425 +splashstrengthiipot,373,16425 +splashstrongiipot,373,16425 +splashstriipot,373,16425 +splstrengthleveliipotion,373,16425 +splstrongleveliipotion,373,16425 +splstrleveliipotion,373,16425 +splstrengthlevel2potion,373,16425 +splstronglevel2potion,373,16425 +splstrlevel2potion,373,16425 +splstrengthiipotion,373,16425 +splstrongiipotion,373,16425 +splstriipotion,373,16425 +splstrengthleveliipot,373,16425 +splstrongleveliipot,373,16425 +splstrleveliipot,373,16425 +splstrengthlevel2pot,373,16425 +splstronglevel2pot,373,16425 +splstrlevel2pot,373,16425 +splstrengthiipot,373,16425 +splstrongiipot,373,16425 +splstriipot,373,16425 +spst2pot,373,16425 +splashrefinedpotion,373,16427 +splashrefinedpot,373,16427 +splrefinedpotion,373,16427 +splrefinedpot,373,16427 +splashharmingleveliipotion,373,16428 +splashdamageleveliipotion,373,16428 +splashdmgleveliipotion,373,16428 +splashharminglevel2potion,373,16428 +splashdamagelevel2potion,373,16428 +splashdmglevel2potion,373,16428 +splashharmingiipotion,373,16428 +splashdamageiipotion,373,16428 +splashdmgiipotion,373,16428 +splashharmingleveliipot,373,16428 +splashdamageleveliipot,373,16428 +splashdmgleveliipot,373,16428 +splashharminglevel2pot,373,16428 +splashdamagelevel2pot,373,16428 +splashdmglevel2pot,373,16428 +splashharmingiipot,373,16428 +splashdamageiipot,373,16428 +splashdmgiipot,373,16428 +splharmingleveliipotion,373,16428 +spldamageleveliipotion,373,16428 +spldmgleveliipotion,373,16428 +splharminglevel2potion,373,16428 +spldamagelevel2potion,373,16428 +spldmglevel2potion,373,16428 +splharmingiipotion,373,16428 +spldamageiipotion,373,16428 +spldmgiipotion,373,16428 +splharmingleveliipot,373,16428 +spldamageleveliipot,373,16428 +spldmgleveliipot,373,16428 +splharminglevel2pot,373,16428 +spldamagelevel2pot,373,16428 +spldmglevel2pot,373,16428 +splharmingiipot,373,16428 +spldamageiipot,373,16428 +spldmgiipot,373,16428 +spd2pot,373,16428 +splashcordialpotion,373,16429 +splashcordialpot,373,16429 +splcordialpotion,373,16429 +splcordialpot,373,16429 +splashsparklingpotion,373,16430 +splashsparklingpot,373,16430 +splsparklingpotion,373,16430 +splsparklingpot,373,16430 +splashsparklingextendedpotion,373,16431 +splashsparklingexpotion,373,16431 +splashsparkling2potion,373,16431 +splashsparklingextendedpot,373,16431 +splashsparklingexpot,373,16431 +splashsparkling2pot,373,16431 +splsparklingextendedpotion,373,16431 +splsparklingexpotion,373,16431 +splsparkling2potion,373,16431 +splsparklingextendedpot,373,16431 +splsparklingexpot,373,16431 +splsparkling2pot,373,16431 +splashpotentpotion,373,16432 +splashpotentpot,373,16432 +splpotentpotion,373,16432 +splpotentpot,373,16432 +splashrankpotion,373,16438 +splashrankpot,373,16438 +splrankpotion,373,16438 +splrankpot,373,16438 +splashrankextendedpotion,373,16439 +splashrankexpotion,373,16439 +splashrank2potion,373,16439 +splashrankextendedpot,373,16439 +splashrankexpot,373,16439 +splashrank2pot,373,16439 +splrankextendedpotion,373,16439 +splrankexpotion,373,16439 +splrank2potion,373,16439 +splrankextendedpot,373,16439 +splrankexpot,373,16439 +splrank2pot,373,16439 +splashacridpotion,373,16443 +splashacridpot,373,16443 +splacridpotion,373,16443 +splacridpot,373,16443 +splashgrosspotion,373,16445 +splashgrosspot,373,16445 +splgrosspotion,373,16445 +splgrosspot,373,16445 +splashstinkypotion,373,16446 +splashstinkypot,373,16446 +splstinkypotion,373,16446 +splstinkypot,373,16446 +splashstinkyextendedpotion,373,16447 +splashstinkyexpotion,373,16447 +splashstinky2potion,373,16447 +splashstinkyextendedpot,373,16447 +splashstinkyexpot,373,16447 +splashstinky2pot,373,16447 +splstinkyextendedpotion,373,16447 +splstinkyexpotion,373,16447 +splstinky2potion,373,16447 +splstinkyextendedpot,373,16447 +splstinkyexpot,373,16447 +splstinky2pot,373,16447 +splashmundaneextendedpotion,373,16448 +splashmundaneexpotion,373,16448 +splashmundane2potion,373,16448 +splashmundaneextendedpot,373,16448 +splashmundaneexpot,373,16448 +splashmundane2pot,373,16448 +splmundaneextendedpotion,373,16448 +splmundaneexpotion,373,16448 +splmundane2potion,373,16448 +splmundaneextendedpot,373,16448 +splmundaneexpot,373,16448 +splmundane2pot,373,16448 +splashregenerationextendedpotion,373,16449 +splashregenerateextendedpotion,373,16449 +splashregenextendepotion,373,16449 +splashregenerationexpotion,373,16449 +splashregenerateexpotion,373,16449 +splashregenexpotion,373,16449 +splashregenerationextendedpot,373,16449 +splashregenerateextendedpot,373,16449 +splashregenextendepot,373,16449 +splashregenerationexpot,373,16449 +splashregenerateexpot,373,16449 +splashregenexpot,373,16449 +splregenerationextendedpotion,373,16449 +splregenerateextendedpotion,373,16449 +splregenextendepotion,373,16449 +splregenerationexpotion,373,16449 +splregenerateexpotion,373,16449 +splregenexpotion,373,16449 +splregenerationextendedpot,373,16449 +splregenerateextendedpot,373,16449 +splregenextendepot,373,16449 +splregenerationexpot,373,16449 +splregenerateexpot,373,16449 +splregenexpot,373,16449 +sprepot,373,16449 +splashswiftnessextendedpotion,373,16450 +splashswiftextendedpotion,373,16450 +splashspeedextendedpotion,373,16450 +splashswiftnessexpotion,373,16450 +splashswiftexpotion,373,16450 +splashspeedexpotion,373,16450 +splashswiftnessextendedpot,373,16450 +splashswiftextendedpot,373,16450 +splashspeedextendedpot,373,16450 +splashswiftnessexpot,373,16450 +splashswiftexpot,373,16450 +splashspeedexpot,373,16450 +splswiftnessextendedpotion,373,16450 +splswiftextendedpotion,373,16450 +splspeedextendedpotion,373,16450 +splswiftnessexpotion,373,16450 +splswiftexpotion,373,16450 +splspeedexpotion,373,16450 +splswiftnessextendedpot,373,16450 +splswiftextendedpot,373,16450 +splspeedextendedpot,373,16450 +splswiftnessexpot,373,16450 +splswiftexpot,373,16450 +splspeedexpot,373,16450 +spswepot,373,16450 +splashfireresistanceextendedpotion,373,16451 +splashfireresistextendedpotion,373,16451 +splashfireresextendedpotion,373,16451 +splashfireresistanceexpotion,373,16451 +splashfireresistexpotion,373,16451 +splashfireresexpotion,373,16451 +splashfireresistanceextendedpot,373,16451 +splashfireresistextendedpot,373,16451 +splashfireresextendedpot,373,16451 +splashfireresistanceexpot,373,16451 +splashfireresistexpot,373,16451 +splashfireresexpot,373,16451 +splfireresistanceextendedpotion,373,16451 +splfireresistextendedpotion,373,16451 +splfireresextendedpotion,373,16451 +splfireresistanceexpotion,373,16451 +splfireresistexpotion,373,16451 +splfireresexpotion,373,16451 +splfireresistanceextendedpot,373,16451 +splfireresistextendedpot,373,16451 +splfireresextendedpot,373,16451 +splfireresistanceexpot,373,16451 +splfireresistexpot,373,16451 +splfireresexpot,373,16451 +spfepot,373,16451 +splashpoisonextendedpotion,373,16452 +splashacidextendedpotion,373,16452 +splashpoisonexpotion,373,16452 +splashacidexpotion,373,16452 +splashpoisonextendedpot,373,16452 +splashacidextendedpot,373,16452 +splashpoisonexpot,373,16452 +splashacidexpot,373,16452 +splpoisonextendedpotion,373,16452 +splacidextendedpotion,373,16452 +splpoisonexpotion,373,16452 +splacidexpotion,373,16452 +splpoisonextendedpot,373,16452 +splacidextendedpot,373,16452 +splpoisonexpot,373,16452 +splacidexpot,373,16452 +sppepot,373,16452 +splashnightvisionextendedpotion,373,16454 +splashnvisionextendedpotion,373,16454 +splashnightvextendedpotion,373,16454 +splashdarkvisionextendedpotion,373,16454 +splashdvisionextendedpotion,373,16454 +splashdarkvextendedpotion,373,16454 +splashnightvisionextendedpot,373,16454 +splashnvisionextendedpot,373,16454 +splashnightvextendedpot,373,16454 +splashdarkvisionextendedpot,373,16454 +splashdvisionextendedpot,373,16454 +splashdarkvextendedpot,373,16454 +splashnightvisionexpotion,373,16454 +splashnvisionexpotion,373,16454 +splashnightvexpotion,373,16454 +splashdarkvisionexpotion,373,16454 +splashdvisionexpotion,373,16454 +splashdarkvexpotion,373,16454 +splashnightvisionexpot,373,16454 +splashnvisionexpot,373,16454 +splashnightvexpot,373,16454 +splashdarkvisionexpot,373,16454 +splashdvisionexpot,373,16454 +splashdarkvexpot,373,16454 +splnightvisionextendedpotion,373,16454 +splnvisionextendedpotion,373,16454 +splnightvextendedpotion,373,16454 +spldarkvisionextendedpotion,373,16454 +spldvisionextendedpotion,373,16454 +spldarkvextendedpotion,373,16454 +splnightvisionextendedpot,373,16454 +splnvisionextendedpot,373,16454 +splnightvextendedpot,373,16454 +spldarkvisionextendedpot,373,16454 +spldvisionextendedpot,373,16454 +spldarkvextendedpot,373,16454 +splnightvisionexpotion,373,16454 +splnvisionexpotion,373,16454 +splnightvexpotion,373,16454 +spldarkvisionexpotion,373,16454 +spldvisionexpotion,373,16454 +spldarkvexpotion,373,16454 +splnightvisionexpot,373,16454 +splnvisionexpot,373,16454 +splnightvexpot,373,16454 +spldarkvisionexpot,373,16454 +spldvisionexpot,373,16454 +spldarkvexpot,373,16454 +spnepot,373,16454 +splashweaknessextendedpotion,373,16456 +splashweakextendedpotion,373,16456 +splashweaknessexpotion,373,16456 +splashweakexpotion,373,16456 +splashweaknessextendedpot,373,16456 +splashweakextendedpot,373,16456 +splashweaknessexpot,373,16456 +splashweakexpot,373,16456 +splweaknessextendedpotion,373,16456 +sphweakextendedpotion,373,16456 +splweaknessexpotion,373,16456 +splweakexpotion,373,16456 +splweaknessextendedpot,373,16456 +splweakextendedpot,373,16456 +splweaknessexpot,373,16456 +splweakexpot,373,16456 +spwepot,373,16456 +splashstrengthextendedpotion,373,16457 +splashstrongextendedpotion,373,16457 +splashstrextendedpotion,373,16457 +splashstrengthexpotion,373,16457 +splashstrongexpotion,373,16457 +splashstrexpotion,373,16457 +splashstrengthextendedpot,373,16457 +splashstrongextendedpot,373,16457 +splashstrextendedpot,373,16457 +splashstrengthexpot,373,16457 +splashstrongexpot,373,16457 +splashstrexpot,373,16457 +splstrengthextendedpotion,373,16457 +splstrongextendedpotion,373,16457 +splstrextendedpotion,373,16457 +splstrengthexpotion,373,16457 +splstrongexpotion,373,16457 +splstrexpotion,373,16457 +splstrengthextendedpot,373,16457 +splstrongextendedpot,373,16457 +splstrextendedpot,373,16457 +splstrengthexpot,373,16457 +splstrongexpot,373,16457 +splstrexpot,373,16457 +spstepot,373,16457 +splashslownessextendedpotion,373,16458 +splashslowextenedpotion,373,16458 +splashslownessexpotion,373,16458 +splashslowexpotion,373,16458 +splashslownessextendedpot,373,16458 +splashslowextenedpot,373,16458 +splashslownessexpot,373,16458 +splashslowexpot,373,16458 +splslownessextendedpotion,373,16458 +splslowextenedpotion,373,16458 +splslownessexpotion,373,16458 +splslowexpotion,373,16458 +splslownessextendedpot,373,16458 +splslowextenedpot,373,16458 +splslownessexpot,373,16458 +splslowexpot,373,16458 +spslepot,373,16458 +splashwaterbreathingextendedpotion,373,16461 +splashwaterbreathextendedpotion,373,16461 +splashbreathingextendedpotion,373,16461 +splashbreathextendedpotion,373,16461 +splashwaterbreathingextendedpot,373,16461 +splashwaterbreathextendedpot,373,16461 +splashbreathingextendedpot,373,16461 +splashbreathextendedpot,373,16461 +splwaterbreathingextendedpotion,373,16461 +splwaterbreathextendedpotion,373,16461 +splbreathingextendedpotion,373,16461 +splbreathextendedpotion,373,16461 +splwaterbreathingextendedpot,373,16461 +splwaterbreathextendedpot,373,16461 +splbreathingextendedpot,373,16461 +splbreathextendedpot,373,16461 +splashwaterbreathingexpotion,373,16461 +splashwaterbreathexpotion,373,16461 +splashbreathingexpotion,373,16461 +splashbreathexpotion,373,16461 +splashwaterbreathingexpot,373,16461 +splashwaterbreathexpot,373,16461 +splashbreathingexpot,373,16461 +splashbreathexpot,373,16461 +splwaterbreathingexpotion,373,16461 +splwaterbreathexpotion,373,16461 +splbreathingexpotion,373,16461 +splbreathexpotion,373,16461 +splwaterbreathingexpot,373,16461 +splwaterbreathexpot,373,16461 +splbreathingexpot,373,16461 +splbreathexpot,373,16461 +spwbepot,373,16461 +splashinvisibilityextendedpotion,373,16462 +splashinvisibleextendedpotion,373,16462 +splashinvextendedpotion,373,16462 +splashinvisibilityextendedpot,373,16462 +splashinvisibleextendedpot,373,16462 +splashinvextendedpot,373,16462 +splashinvisibilityexpotion,373,16462 +splashinvisibleexpotion,373,16462 +splashinvexpotion,373,16462 +splashinvisibilityexpot,373,16462 +splashinvisibleexpot,373,16462 +splashinvexpot,373,16462 +splinvisibilityextendedpotion,373,16462 +splinvisibleextendedpotion,373,16462 +splinvextendedpotion,373,16462 +splinvisibilityextendedpot,373,16462 +splinvisibleextendedpot,373,16462 +splinvextendedpot,373,16462 +splinvisibilityexpotion,373,16462 +splinvisibleexpotion,373,16462 +splinvexpotion,373,16462 +splinvisibilityexpot,373,16462 +splinvisibleexpot,373,16462 +splinvexpot,373,16462 +spiepot,373,16462 +splashregenerationdualbitpotion,373,16481 +splashregeneratedualbitpotion,373,16481 +splashregendualbitpotion,373,16481 +splashregenerationdualbitpot,373,16481 +splashregeneratedualbitpot,373,16481 +splashregendualbitpot,373,16481 +splregenerationdualbitpotion,373,16481 +splregeneratedualbitpotion,373,16481 +splregendualbitpotion,373,16481 +splregenerationdualbitpot,373,16481 +splregeneratedualbitpot,373,16481 +splregendualbitpot,373,16481 +splashregenerationdbpotion,373,16481 +splashregeneratedbpotion,373,16481 +splashregendbpotion,373,16481 +splashregenerationdbpot,373,16481 +splashregeneratedbpot,373,16481 +splashregendbpot,373,16481 +splregenerationdbpotion,373,16481 +splregeneratedbpotion,373,16481 +splregendbpotion,373,16481 +splregenerationdbpot,373,16481 +splregeneratedbpot,373,16481 +splregendbpot,373,16481 +sprdbpot,373,16481 +splashswiftnessdualbitpotion,373,16482 +splashswiftdualbitpotion,373,16482 +splashspeeddualbitpotion,373,16482 +splashswiftnessdualbitpot,373,16482 +splashswiftdualbitpot,373,16482 +splashspeeddualbitpot,373,16482 +splswiftnessdualbitpotion,373,16482 +splswiftdualbitpotion,373,16482 +splspeeddualbitpotion,373,16482 +splswiftnessdualbitpot,373,16482 +splswiftdualbitpot,373,16482 +splspeeddualbitpot,373,16482 +splashswiftnessdbpotion,373,16482 +splashswiftdbpotion,373,16482 +splashspeeddbpotion,373,16482 +splashswiftnessdbpot,373,16482 +splashswiftdbpot,373,16482 +splashspeeddbpot,373,16482 +splswiftnessdbpotion,373,16482 +splswiftdbpotion,373,16482 +splspeeddbpotion,373,16482 +splswiftnessdbpot,373,16482 +splswiftdbpot,373,16482 +splspeeddbpot,373,16482 +spswdbpot,373,16482 +splashpoisondualbitpotion,373,16484 +splashaciddualbitpotion,373,16484 +splashpoisondualbitpot,373,16484 +splashaciddualbitpot,373,16484 +splpoisondualbitpotion,373,16484 +splaciddualbitpotion,373,16484 +splpoisondualbitpot,373,16484 +splaciddualbitpot,373,16484 +splashpoisondbpotion,373,16484 +splashaciddbpotion,373,16484 +splashpoisondbpot,373,16484 +splashaciddbpot,373,16484 +splpoisondbpotion,373,16484 +splaciddbpotion,373,16484 +splpoisondbpot,373,16484 +splaciddbpot,373,16484 +sppdbpot,373,16484 +splashstrengthdualbitpotion,373,16489 +splashstrongdualbitpotion,373,16489 +splashstrdualbitpotion,373,16489 +splashstrengthdualbitpot,373,16489 +splashstrongdualbitpot,373,16489 +splashstrdualbitpot,373,16489 +splstrengthdualbitpotion,373,16489 +splstrongdualbitpotion,373,16489 +splstrdualbitpotion,373,16489 +splstrengthdualbitpot,373,16489 +splstrongdualbitpot,373,16489 +splstrdualbitpot,373,16489 +splashstrengthdbpotion,373,16489 +splashstrongdbpotion,373,16489 +splashstrdbpotion,373,16489 +splashstrengthdbpot,373,16489 +splashstrongdbpot,373,16489 +splashstrdbpot,373,16489 +splstrengthdbpotion,373,16489 +splstrongdbpotion,373,16489 +splstrdbpotion,373,16489 +splstrengthdbpot,373,16489 +splstrongdbpot,373,16489 +splstrdbpot,373,16489 +spstdbpot,373,16489 +glassbottle,374,0 +bottle,374,0 +gbottle,374,0 +gvase,374,0 +vase,374,0 +glassvase,374,0 +emptyglassbottle,374,0 +emptybottle,374,0 +emptygbottle,374,0 +emptygvase,374,0 +emptyvase,374,0 +emptyglassvase,374,0 +eglassbottle,374,0 +ebottle,374,0 +egbottle,374,0 +egvase,374,0 +evase,374,0 +eglassvase,374,0 +spidereye,375,0 +eyeofspider,375,0 +seye,375,0 +fermentedspidereye,376,0 +craftedspidereye,376,0 +fspidereye,376,0 +cspidereye,376,0 +fermentedeyeofspider,376,0 +craftedeyeofspider,376,0 +feyeofspider,376,0 +ceyeofspider,376,0 +fermentedseye,376,0 +craftedseye,376,0 +fseye,376,0 +cseye,376,0 +blazepowder,377,0 +blazedust,377,0 +goldpowder,377,0 +golddust,377,0 +gdust,377,0 +gpowder,377,0 +bpowder,377,0 +bdust,377,0 +magmacream,378,0 +goldcream,378,0 +blazecream,378,0 +mcream,378,0 +gcream,378,0 +bcream,378,0 +combinedcream,378,0 +ccream,378,0 +bstand,379,0 +pstand,379,0 +brewingstand,379,0 +potionstand,379,0 +cauldron,380,0 +steelcauldron,380,0 +ironcauldron,380,0 +icauldron,380,0 +scauldron,380,0 +potioncauldron,380,0 +pcauldron,380,0 +eyeofender,381,0 +endereye,381,0 +endeye,381,0 +evilendereye,381,0 +evileyeofender,381,0 +evilenderpearl,381,0 +eeye,381,0 +eofender,381,0 +glisteringmelon,382,0 +speckledmelon,382,0 +goldmelon,382,0 +sparklymelon,382,0 +shiningmelon,382,0 +gmelon,382,0 +smelon,382,0 +creeperegg,383,50 +eggcreeper,383,50 +skeletonegg,383,51 +eggskeleton,383,51 +spideregg,383,52 +eggspider,383,52 +giantegg,383,53 +egggiant,383,53 +zombieegg,383,54 +eggzombie,383,54 +slimeegg,383,55 +eggslime,383,55 +ghastegg,383,56 +eggghast,383,56 +zombiepigmanegg,383,57 +zpigmanegg,383,57 +pigmanegg,383,57 +zombiepmanegg,383,57 +zpmanegg,383,57 +zombiepigmegg,383,57 +zpigmegg,383,57 +zombiepigegg,383,57 +zpigegg,383,57 +zombiepmegg,383,57 +zombiepegg,383,57 +eggzombiepigman,383,57 +eggzpigman,383,57 +eggpigman,383,57 +eggzombiepman,383,57 +eggzpman,383,57 +eggzombiepigm,383,57 +eggzpigm,383,57 +eggzombiepig,383,57 +eggzpig,383,57 +eggzombiepm,383,57 +eggzombiep,383,57 +endermanegg,383,58 +eggenderman,383,58 +eggcavespider,383,59 +cavespideregg,383,59 +silverfishegg,383,60 +eggsilverfish,383,60 +blazeegg,383,61 +eggblaze,383,61 +lavaslimeegg,383,62 +lavacubeegg,383,62 +magmacubeegg,383,62 +magmaslimeegg,383,62 +egglavaslime,383,62 +egglavacube,383,62 +eggmagmacube,383,62 +eggmagmaslime,383,62 +bategg,383,65 +eggbat,383,65 +witchegg,383,66 +eggwitch,383,66 +pigegg,383,90 +eggpig,383,90 +sheepegg,383,91 +eggsheep,383,91 +cowegg,383,92 +eggcow,383,92 +chickenegg,383,93 +eggchicken,383,93 +squidegg,383,94 +eggsquid,383,94 +wolfegg,383,95 +eggwolf,383,95 +mooshroomegg,383,96 +mushroomcowegg,383,96 +eggmooshroom,383,96 +eggmushroomcow,383,96 +snowgolemegg,383,97 +sgolemegg,383,97 +eggsnowgolem,383,97 +eggsgolem,383,97 +ocelotegg,383,98 +eggocelot,383,98 +irongolemegg,383,99 +igolemegg,383,99 +eggirongolem,383,99 +eggigolem,383,99 +egghorse,383,100 +horseegg,383,100 +villageregg,383,120 +eggvillager,383,120 +bottleofenchanting,384,0 +enchantingbottle,384,0 +expbottle,384,0 +xpbottle,384,0 +bottleexp,384,0 +bottlexp,384,0 +enchantbottle,384,0 +bottleenchanting,384,0 +bottleenchant,384,0 +bottleoenchanting,384,0 +firecharge,385,0 +fireball,385,0 +grenade,385,0 +bookandquill,386,0 +booknquill,386,0 +bookandfeather,386,0 +booknfeather,386,0 +writeablebook,386,0 +writtenbook,387,0 +readablebook,387,0 +sealedbook,387,0 +diary,387,0 +ownedbook,387,0 +emerald,388,0 +itemframe,389,0 +pictureframe,389,0 +iframe,389,0 +pframe,389,0 +flowerpot,390,0 +pot,390,0 +carrot,391,0 +potato,392,0 +rawpotato,392,0 +bakedpotato,393,0 +roastedpotato,393,0 +cookedpotato,393,0 +bakepotato,393,0 +roastpotato,393,0 +cookpotato,393,0 +bpotato,393,0 +rpotato,393,0 +cpotato,393,0 +poisonouspotato,394,0 +poisonpotato,394,0 +ppotato,394,0 +emptymap,395,0 +map,395,0 +goldencarrot,396,0 +goldcarrot,396,0 +gcarrot,396,0 +head,397,0 +skull,397,0 +skeletonhead,397,0 +headskeleton,397,0 +skeletonskull,397,0 +skullskeleton,397,0 +witherhead,397,1 +witherskeletonhead,397,1 +wskeletionhead,397,1 +headwither,397,1 +headwitherskeleton,397,1 +headwskeletion,397,1 +witherskull,397,1 +witherskeletonskull,397,1 +wskeletionskull,397,1 +skullwither,397,1 +skullwitherskeleton,397,1 +skullwskeletion,397,1 +zombiehead,397,2 +headzombie,397,2 +zombieskull,397,2 +skullzombie,397,2 +playerhead,397,3 +humanhead,397,3 +stevehead,397,3 +headplayer,397,3 +headhuman,397,3 +headsteve,397,3 +playerskull,397,3 +humanskull,397,3 +steveskull,397,3 +skullplayer,397,3 +skullhuman,397,3 +skullsteve,397,3 +creeperhead,397,4 +headcreeper,397,4 +creeperskull,397,4 +skullcreeper,397,4 +carrotonastick,398,0 +carrotonstick,398,0 +netherstar,399,0 +hellstar,399,0 +nstar,399,0 +hstar,399,0 +star,399,0 +pumpkinpie,400,0 +pumpkincake,400,0 +ppie,400,0 +pcake,400,0 +pie,400,0 +fireworkrocket,401,0 +fireworkmissle,401,0 +firework,401,0 +fworkrocket,401,0 +fworkmissle,401,0 +fwork,401,0 +fwrocket,401,0 +fwmissle,401,0 +fireworkstar,402,0 +fworkstar,402,0 +fwstar,402,0 +fireworkball,402,0 +fworkball,402,0 +fwball,402,0 +fireworkpowder,402,0 +fworkpowder,402,0 +fwpowder,402,0 +fireworkcharge,402,0 +fworkcharge,402,0 +fwcharge,402,0 +enchantedbook,403,0 +enchantmentbook,403,0 +enchantingbook,403,0 +enchantbook,403,0 +magicalbook,403,0 +magicbook,403,0 +ebook,403,0 +mbook,403,0 +redstonecomparator,404,0 +redstonecomparer,404,0 +redstonecompare,404,0 +rstonecomparator,404,0 +rstonecomparer,404,0 +rstonecompare,404,0 +redscomparator,404,0 +redscomparer,404,0 +redscompare,404,0 +rscomparator,404,0 +rscomparer,404,0 +rscompare,404,0 +comparator,404,0 +comparer,404,0 +compare,404,0 +netherbrick,405,0 +nbrick,405,0 +hellbrick,405,0 +deathbrick,405,0 +dbrick,405,0 +hbrick,405,0 +netherquartz,406,0 +deathquartz,406,0 +hellquartz,406,0 +nquartz,406,0 +dquartz,406,0 +hquartz,406,0 +quartz,406,0 +tntminecart,407,0 +dynamiteminecart,407,0 +dynamitemcart,407,0 +dynamitecart,407,0 +bombminecart,407,0 +bombmcart,407,0 +bombcart,407,0 +tntmcart,407,0 +tntcart,407,0 +dminecart,407,0 +dmcart,407,0 +dcart,407,0 +bminecart,407,0 +bmcart,407,0 +bcart,407,0 +tminecart,407,0 +tmcart,407,0 +tcart,407,0 +hopperminecart,408,0 +hoppermcart,408,0 +hoppercart,408,0 +hopminecart,408,0 +hopmcart,408,0 +hopcart,408,0 +hminecart,408,0 +hmcart,408,0 +hcart,408,0 +ironhorsearmor,417,0 +ironharmor,417,0 +ironarmor,417,0 +ihorsearmor,417,0 +iharmor,417,0 +iarmor,417,0 +steelhorsearmor,417,0 +steelharmor,417,0 +steelarmor,417,0 +shorsearmor,417,0 +sharmor,417,0 +sarmor,417,0 +goldenhorsearmor,418,0 +goldenharmor,418,0 +goldenarmor,418,0 +goldhorsearmor,418,0 +goldharmor,418,0 +goldarmor,418,0 +ghorsearmor,418,0 +gharmor,418,0 +garmor,418,0 +diamondhorsearmor,419,0 +diamondharmor,419,0 +diamondarmor,419,0 +dhorsearmor,419,0 +dharmor,419,0 +darmor,419,0 +crystalhorsearmor,419,0 +crystalharmor,419,0 +crystalarmor,419,0 +chorsearmor,419,0 +charmor,419,0 +carmor,419,0 +lead,420,0 +leash,420,0 +rope,420,0 +nametag,421,0 +tag,421,0 +commandblockminecart,422,0 +cmdblockminecart,422,0 +cblockminecart,422,0 +commandminecart,422,0 +cmdminecart,422,0 +cbminecart,422,0 +commandblockcart,422,0 +cmdblockcart,422,0 +cblockcart,422,0 +commandcart,422,0 +cmdcart,422,0 +cbcart,422,0 +13disc,2256,0 +goldmusicrecord,2256,0 +goldmusicdisk,2256,0 +goldmusicdisc,2256,0 +goldmusiccd,2256,0 +13musicrecord,2256,0 +13musicdisk,2256,0 +13musicdisc,2256,0 +13musiccd,2256,0 +gomusicrecord,2256,0 +gomusicdisk,2256,0 +gomusicdisc,2256,0 +gomusiccd,2256,0 +goldmrecord,2256,0 +goldmdisk,2256,0 +goldmdisc,2256,0 +goldmcd,2256,0 +13mrecord,2256,0 +13mdisk,2256,0 +13mdisc,2256,0 +13mcd,2256,0 +gomrecord,2256,0 +gomdisk,2256,0 +gomdisc,2256,0 +gomcd,2256,0 +goldrecord,2256,0 +golddisk,2256,0 +golddisc,2256,0 +goldcd,2256,0 +13record,2256,0 +13disk,2256,0 +13cd,2256,0 +gorecord,2256,0 +godisk,2256,0 +godisc,2256,0 +gocd,2256,0 +record1,2256,0 +disk1,2256,0 +disc1,2256,0 +cd1,2256,0 +1record,2256,0 +1disk,2256,0 +1disc,2256,0 +1cd,2256,0 +catdisc,2257,0 +greenmusicrecord,2257,0 +greenmusicdisk,2257,0 +greenmusicdisc,2257,0 +greenmusiccd,2257,0 +catmusicrecord,2257,0 +catmusicdisk,2257,0 +catmusicdisc,2257,0 +catmusiccd,2257,0 +grmusicrecord,2257,0 +grmusicdisk,2257,0 +grmusicdisc,2257,0 +grmusiccd,2257,0 +greenmrecord,2257,0 +greenmdisk,2257,0 +greenmdisc,2257,0 +greenmcd,2257,0 +catmrecord,2257,0 +catmdisk,2257,0 +catmdisc,2257,0 +catmcd,2257,0 +grmrecord,2257,0 +grmdisk,2257,0 +grmdisc,2257,0 +grmcd,2257,0 +greenrecord,2257,0 +greendisk,2257,0 +greendisc,2257,0 +greencd,2257,0 +catrecord,2257,0 +catdisk,2257,0 +catcd,2257,0 +grrecord,2257,0 +grdisk,2257,0 +grdisc,2257,0 +grcd,2257,0 +record2,2257,0 +disk2,2257,0 +disc2,2257,0 +cd2,2257,0 +2record,2257,0 +2disk,2257,0 +2disc,2257,0 +2cd,2257,0 +blocksdisc,2258,0 +orangemusicrecord,2258,0 +orangemusicdisk,2258,0 +orangemusicdisc,2258,0 +orangemusiccd,2258,0 +blocksmusicrecord,2258,0 +blocksmusicdisk,2258,0 +blocksmusicdisc,2258,0 +blocksmusiccd,2258,0 +ormusicrecord,2258,0 +ormusicdisk,2258,0 +ormusicdisc,2258,0 +ormusiccd,2258,0 +orangemrecord,2258,0 +orangemdisk,2258,0 +orangemdisc,2258,0 +orangemcd,2258,0 +blocksmrecord,2258,0 +blocksmdisk,2258,0 +blocksmdisc,2258,0 +blocksmcd,2258,0 +ormrecord,2258,0 +ormdisk,2258,0 +ormdisc,2258,0 +ormcd,2258,0 +orangerecord,2258,0 +orangedisk,2258,0 +orangedisc,2258,0 +orangecd,2258,0 +blocksrecord,2258,0 +blocksdisk,2258,0 +blockscd,2258,0 +orrecord,2258,0 +ordisk,2258,0 +ordisc,2258,0 +orcd,2258,0 +record3,2258,0 +disk3,2258,0 +disc3,2258,0 +cd3,2258,0 +3record,2258,0 +3disk,2258,0 +3disc,2258,0 +3cd,2258,0 +chirpdisc,2259,0 +redmusicrecord,2259,0 +redmusicdisk,2259,0 +redmusicdisc,2259,0 +redmusiccd,2259,0 +chirpmusicrecord,2259,0 +chirpmusicdisk,2259,0 +chirpmusicdisc,2259,0 +chirpmusiccd,2259,0 +remusicrecord,2259,0 +remusicdisk,2259,0 +remusicdisc,2259,0 +remusiccd,2259,0 +redmrecord,2259,0 +redmdisk,2259,0 +redmdisc,2259,0 +redmcd,2259,0 +chirpmrecord,2259,0 +chirpmdisk,2259,0 +chirpmdisc,2259,0 +chirpmcd,2259,0 +remrecord,2259,0 +remdisk,2259,0 +remdisc,2259,0 +remcd,2259,0 +redrecord,2259,0 +reddisk,2259,0 +reddisc,2259,0 +redcd,2259,0 +chirprecord,2259,0 +chirpdisk,2259,0 +chirpcd,2259,0 +rerecord,2259,0 +redisk,2259,0 +redisc,2259,0 +recd,2259,0 +record4,2259,0 +disk4,2259,0 +disc4,2259,0 +cd4,2259,0 +4record,2259,0 +4disk,2259,0 +4disc,2259,0 +4cd,2259,0 +fardisc,2260,0 +lightgreenmusicrecord,2260,0 +lightgreenmusicdisk,2260,0 +lightgreenmusicdisc,2260,0 +lightgreenmusiccd,2260,0 +lgreenmusicrecord,2260,0 +lgreenmusicdisk,2260,0 +lgreenmusicdisc,2260,0 +lgreenmusiccd,2260,0 +lightgrmusicrecord,2260,0 +lightgrmusicdisk,2260,0 +lightgrmusicdisc,2260,0 +lightgrmusiccd,2260,0 +farmusicrecord,2260,0 +farmusicdisk,2260,0 +farmusicdisc,2260,0 +farmusiccd,2260,0 +lgrmusicrecord,2260,0 +lgrmusicdisk,2260,0 +lgrmusicdisc,2260,0 +lgrmusiccd,2260,0 +lightgreenmrecord,2260,0 +lightgreenmdisk,2260,0 +lightgreenmdisc,2260,0 +lightgreenmcd,2260,0 +lgreenmrecord,2260,0 +lgreenmdisk,2260,0 +lgreenmdisc,2260,0 +lgreenmcd,2260,0 +lightgrmrecord,2260,0 +lightgrmdisk,2260,0 +lightgrmdisc,2260,0 +lightgrmcd,2260,0 +farmrecord,2260,0 +farmdisk,2260,0 +farmdisc,2260,0 +farmcd,2260,0 +lgrmrecord,2260,0 +lgrmdisk,2260,0 +lgrmdisc,2260,0 +lgrmcd,2260,0 +lightgreenrecord,2260,0 +lightgreendisk,2260,0 +lightgreendisc,2260,0 +lightgreencd,2260,0 +lgreenrecord,2260,0 +lgreendisk,2260,0 +lgreendisc,2260,0 +lgreencd,2260,0 +lightgrrecord,2260,0 +lightgrdisk,2260,0 +lightgrdisc,2260,0 +lightgrcd,2260,0 +farrecord,2260,0 +fardisk,2260,0 +farcd,2260,0 +lgrrecord,2260,0 +lgrdisk,2260,0 +lgrdisc,2260,0 +lgrcd,2260,0 +record5,2260,0 +disk5,2260,0 +disc5,2260,0 +cd5,2260,0 +5record,2260,0 +5disk,2260,0 +5disc,2260,0 +5cd,2260,0 +malldisc,2261,0 +purplemusicrecord,2261,0 +purplemusicdisk,2261,0 +purplemusicdisc,2261,0 +purplemusiccd,2261,0 +mallmusicrecord,2261,0 +mallmusicdisk,2261,0 +mallmusicdisc,2261,0 +mallmusiccd,2261,0 +pumusicrecord,2261,0 +pumusicdisk,2261,0 +pumusicdisc,2261,0 +pumusiccd,2261,0 +purplemrecord,2261,0 +purplemdisk,2261,0 +purplemdisc,2261,0 +purplemcd,2261,0 +mallmrecord,2261,0 +mallmdisk,2261,0 +mallmdisc,2261,0 +mallmcd,2261,0 +pumrecord,2261,0 +pumdisk,2261,0 +pumdisc,2261,0 +pumcd,2261,0 +purplerecord,2261,0 +purpledisk,2261,0 +purpledisc,2261,0 +purplecd,2261,0 +mallrecord,2261,0 +malldisk,2261,0 +mallcd,2261,0 +purecord,2261,0 +pudisk,2261,0 +pudisc,2261,0 +pucd,2261,0 +record6,2261,0 +disk6,2261,0 +disc6,2261,0 +cd6,2261,0 +6record,2261,0 +6disk,2261,0 +6disc,2261,0 +6cd,2261,0 +mellohidisc,2262,0 +pinkmusicrecord,2262,0 +pinkmusicdisk,2262,0 +pinkmusicdisc,2262,0 +pinkmusiccd,2262,0 +mellohimusicrecord,2262,0 +mellohimusicdisk,2262,0 +mellohimusicdisc,2262,0 +mellohimusiccd,2262,0 +pimusicrecord,2262,0 +pimusicdisk,2262,0 +pimusicdisc,2262,0 +pimusiccd,2262,0 +pinkmrecord,2262,0 +pinkmdisk,2262,0 +pinkmdisc,2262,0 +pinkmcd,2262,0 +mellohimrecord,2262,0 +mellohimdisk,2262,0 +mellohimdisc,2262,0 +mellohimcd,2262,0 +pimrecord,2262,0 +pimdisk,2262,0 +pimdisc,2262,0 +pimcd,2262,0 +pinkrecord,2262,0 +pinkdisk,2262,0 +pinkdisc,2262,0 +pinkcd,2262,0 +mellohirecord,2262,0 +mellohidisk,2262,0 +mellohicd,2262,0 +pirecord,2262,0 +pidisk,2262,0 +pidisc,2262,0 +picd,2262,0 +record7,2262,0 +disk7,2262,0 +disc7,2262,0 +cd7,2262,0 +7record,2262,0 +7disk,2262,0 +7disc,2262,0 +7cd,2262,0 +staldisc,2263,0 +blackmusicrecord,2263,0 +blackmusicdisk,2263,0 +blackmusicdisc,2263,0 +blackmusiccd,2263,0 +stalmusicrecord,2263,0 +stalmusicdisk,2263,0 +stalmusicdisc,2263,0 +stalmusiccd,2263,0 +blmusicrecord,2263,0 +blmusicdisk,2263,0 +blmusicdisc,2263,0 +blmusiccd,2263,0 +blackmrecord,2263,0 +blackmdisk,2263,0 +blackmdisc,2263,0 +blackmcd,2263,0 +stalmrecord,2263,0 +stalmdisk,2263,0 +stalmdisc,2263,0 +stalmcd,2263,0 +blmrecord,2263,0 +blmdisk,2263,0 +blmdisc,2263,0 +blmcd,2263,0 +blackrecord,2263,0 +blackdisk,2263,0 +blackdisc,2263,0 +blackcd,2263,0 +stalrecord,2263,0 +staldisk,2263,0 +stalcd,2263,0 +blrecord,2263,0 +bldisk,2263,0 +bldisc,2263,0 +blcd,2263,0 +record8,2263,0 +disk8,2263,0 +disc8,2263,0 +cd8,2263,0 +8record,2263,0 +8disk,2263,0 +8disc,2263,0 +8cd,2263,0 +straddisc,2264,0 +whitemusicrecord,2264,0 +whitemusicdisk,2264,0 +whitemusicdisc,2264,0 +whitemusiccd,2264,0 +stradmusicrecord,2264,0 +stradmusicdisk,2264,0 +stradmusicdisc,2264,0 +stradmusiccd,2264,0 +whmusicrecord,2264,0 +whmusicdisk,2264,0 +whmusicdisc,2264,0 +whmusiccd,2264,0 +whitemrecord,2264,0 +whitemdisk,2264,0 +whitemdisc,2264,0 +whitemcd,2264,0 +stradmrecord,2264,0 +stradmdisk,2264,0 +stradmdisc,2264,0 +stradmcd,2264,0 +whmrecord,2264,0 +whmdisk,2264,0 +whmdisc,2264,0 +whmcd,2264,0 +whiterecord,2264,0 +whitedisk,2264,0 +whitedisc,2264,0 +whitecd,2264,0 +stradrecord,2264,0 +straddisk,2264,0 +stradcd,2264,0 +whrecord,2264,0 +whdisk,2264,0 +whdisc,2264,0 +whcd,2264,0 +record9,2264,0 +disk9,2264,0 +disc9,2264,0 +cd9,2264,0 +9record,2264,0 +9disk,2264,0 +9disc,2264,0 +9cd,2264,0 +warddisc,2265,0 +darkgreenmusicrecord,2265,0 +darkgreenmusicdisk,2265,0 +darkgreenmusicdisc,2265,0 +darkgreenmusiccd,2265,0 +dgreenmusicrecord,2265,0 +dgreenmusicdisk,2265,0 +dgreenmusicdisc,2265,0 +dgreenmusiccd,2265,0 +darkgrmusicrecord,2265,0 +darkgrmusicdisk,2265,0 +darkgrmusicdisc,2265,0 +darkgrmusiccd,2265,0 +wardmusicrecord,2265,0 +wardmusicdisk,2265,0 +wardmusicdisc,2265,0 +wardmusiccd,2265,0 +dgrmusicrecord,2265,0 +dgrmusicdisk,2265,0 +dgrmusicdisc,2265,0 +dgrmusiccd,2265,0 +darkgreenmrecord,2265,0 +darkgreenmdisk,2265,0 +darkgreenmdisc,2265,0 +darkgreenmcd,2265,0 +dgreenmrecord,2265,0 +dgreenmdisk,2265,0 +dgreenmdisc,2265,0 +dgreenmcd,2265,0 +darkgrmrecord,2265,0 +darkgrmdisk,2265,0 +darkgrmdisc,2265,0 +darkgrmcd,2265,0 +wardmrecord,2265,0 +wardmdisk,2265,0 +wardmdisc,2265,0 +wardmcd,2265,0 +dgrmrecord,2265,0 +dgrmdisk,2265,0 +dgrmdisc,2265,0 +dgrmcd,2265,0 +darkgreenrecord,2265,0 +darkgreendisk,2265,0 +darkgreendisc,2265,0 +darkgreencd,2265,0 +dgreenrecord,2265,0 +dgreendisk,2265,0 +dgreendisc,2265,0 +dgreencd,2265,0 +darkgrrecord,2265,0 +darkgrdisk,2265,0 +darkgrdisc,2265,0 +darkgrcd,2265,0 +wardrecord,2265,0 +warddisk,2265,0 +wardcd,2265,0 +dgrrecord,2265,0 +dgrdisk,2265,0 +dgrdisc,2265,0 +dgrcd,2265,0 +record10,2265,0 +disk10,2265,0 +disc10,2265,0 +cd10,2265,0 +10record,2265,0 +10disk,2265,0 +10disc,2265,0 +10cd,2265,0 +11disc,2266,0 +crackedmusicrecord,2266,0 +crackedmusicdisk,2266,0 +crackedmusicdisc,2266,0 +crackedmusiccd,2266,0 +crackmusicrecord,2266,0 +crackmusicdisk,2266,0 +crackmusicdisc,2266,0 +crackmusiccd,2266,0 +11musicrecord,2266,0 +11musicdisk,2266,0 +11musicdisc,2266,0 +11musiccd,2266,0 +cmusicrecord,2266,0 +cmusicdisk,2266,0 +cmusicdisc,2266,0 +cmusiccd,2266,0 +crackedmrecord,2266,0 +crackedmdisk,2266,0 +crackedmdisc,2266,0 +crackedmcd,2266,0 +crackmrecord,2266,0 +crackmdisk,2266,0 +crackmdisc,2266,0 +crackmcd,2266,0 +11mrecord,2266,0 +11mdisk,2266,0 +11mdisc,2266,0 +11mcd,2266,0 +cmrecord,2266,0 +cmdisk,2266,0 +cmdisc,2266,0 +cmcd,2266,0 +crackedrecord,2266,0 +crackeddisk,2266,0 +crackeddisc,2266,0 +crackedcd,2266,0 +crackrecord,2266,0 +crackdisk,2266,0 +crackdisc,2266,0 +crackcd,2266,0 +crecord,2266,0 +cdisk,2266,0 +cdisc,2266,0 +ccd,2266,0 +record11,2266,0 +disk11,2266,0 +disc11,2266,0 +cd11,2266,0 +11record,2266,0 +11disk,2266,0 +11cd,2266,0 +waitdisc,2267,0 +waitmusicrecord,2267,0 +waitmusicdisk,2267,0 +waitmusicdisc,2267,0 +waitmusiccd,2267,0 +bluemusicrecord,2267,0 +bluemusicdisk,2267,0 +bluemusicdisc,2267,0 +bluemusiccd,2267,0 +12musicrecord,2267,0 +12musicdisk,2267,0 +12musicdisc,2267,0 +12musiccd,2267,0 +cyanmusicrecord,2267,0 +cyanmusicdisk,2267,0 +cyanmusicdisc,2267,0 +cyanmusiccd,2267,0 +waitmrecord,2267,0 +waitmdisk,2267,0 +waitmdisc,2267,0 +waitmcd,2267,0 +bluemrecord,2267,0 +bluemdisk,2267,0 +bluemdisc,2267,0 +bluemcd,2267,0 +12mrecord,2267,0 +12mdisk,2267,0 +12mdisc,2267,0 +12mcd,2267,0 +cyanmrecord,2267,0 +cyanmdisk,2267,0 +cyanmdisc,2267,0 +cyanmcd,2267,0 +waitrecord,2267,0 +waitdisk,2267,0 +waitcd,2267,0 +bluerecord,2267,0 +bluedisk,2267,0 +bluedisc,2267,0 +bluecd,2267,0 +cyanrecord,2267,0 +cyandisk,2267,0 +cyandisc,2267,0 +cyancd,2267,0 +record12,2267,0 +disk12,2267,0 +disc12,2267,0 +cd12,2267,0 +12record,2267,0 +12disk,2267,0 +12disc,2267,0 +12cd,2267,0 diff --git a/Essentials/src/messages.properties b/Essentials/src/messages.properties new file mode 100644 index 0000000000..2d438cf3f1 --- /dev/null +++ b/Essentials/src/messages.properties @@ -0,0 +1,557 @@ +#X-Generator: crowdin.net +#version: TeamCity +# Single quotes have to be doubled: '' +# Translations start here +# by: +action=\u00a75* {0} \u00a75{1} +addedToAccount=\u00a7a{0} has been added to your account. +addedToOthersAccount=\u00a7a{0} added to {1}\u00a7a account. New balance\: {2} +adventure=adventure +alertBroke=broke\: +alertFormat=\u00a73[{0}] \u00a7r {1} \u00a76 {2} at\: {3} +alertPlaced=placed\: +alertUsed=used\: +antiBuildBreak=\u00a74You are not permitted to break\u00a7c {0} \u00a74blocks here. +antiBuildCraft=\u00a74You are not permitted to create\u00a7c {0}\u00a74. +antiBuildDrop=\u00a74You are not permitted to drop\u00a7c {0}\u00a74. +antiBuildInteract=\u00a74You are not permitted to interact with\u00a7c {0}\u00a74. +antiBuildPlace=\u00a74You are not permitted to place\u00a7c {0} \u00a74here. +antiBuildUse=\u00a74You are not permitted to use\u00a7c {0}\u00a74. +autoAfkKickReason=You have been kicked for idling more than {0} minutes. +backAfterDeath=\u00a76Use the /back command to return to your death point. +backUsageMsg=\u00a76Returning to previous location. +backupDisabled=\u00a74An external backup script has not been configured. +backupFinished=\u00a76Backup finished. +backupStarted=\u00a76Backup started. +balance=\u00a7aBalance\:\u00a7c {0} +balanceOther=\u00a7aBalance of {0}\u00a7a\:\u00a7c {1} +balanceTop=\u00a76Top balances ({0}) +banExempt=\u00a74You cannot ban that player. +banFormat=\u00a7cYou have been banned\:\n\u00a7r{0} +bed=\u00a7obed\u00a7r +bedMissing=\u00a74Your bed is either unset, missing or blocked. +bedNull=\u00a7mbed\u00a7r +bedSet=\u00a76Bed spawn set\! +bigTreeFailure=\u00a74Big tree generation failure. Try again on grass or dirt. +bigTreeSuccess=\u00a76Big tree spawned. +blockList=\u00a76Essentials relayed the following commands to another plugin\: +bookAuthorSet=\u00a76Author of the book set to {0}. +bookLocked=\u00a76This book is now locked. +bookTitleSet=\u00a76Title of the book set to {0}. +broadcast=\u00a7r\u00a76[\u00a74Broadcast\u00a76]\u00a7a {0} +buildAlert=\u00a74You are not permitted to build. +bukkitFormatChanged=Bukkit version format changed. Version not checked. +burnMsg=\u00a76You set\u00a7c {0} \u00a76on fire for\u00a7c {1} seconds\u00a76. +canTalkAgain=\u00a76You can now talk again. +cannotStackMob=\u00a74You do not have permission to stack multiple mobs. +cantFindGeoIpDB=Can''t find GeoIP database\! +cantReadGeoIpDB=Failed to read GeoIP database\! +cantSpawnItem=\u00a74You are not allowed to spawn the item\u00a7c {0}\u00a74. +chatTypeAdmin=[A] +chatTypeLocal=[L] +chatTypeSpy=[Spy] +cleaned=Userfiles Cleaned. +cleaning=Cleaning userfiles. +commandFailed=Command {0} failed\: +commandHelpFailedForPlugin=Error getting help for plugin\: {0} +commandNotLoaded=\u00a74Command {0} is improperly loaded. +compassBearing=\u00a76Bearing\: {0} ({1} degrees). +configFileMoveError=Failed to move config.yml to backup location. +configFileRenameError=Failed to rename temp file to config.yml. +connectedPlayers=\u00a76Connected players\u00a7r +connectionFailed=Failed to open connection. +cooldownWithMessage=\u00a74Cooldown\: {0} +corruptNodeInConfig=\u00a74Notice\: Your configuration file has a corrupt {0} node. +couldNotFindTemplate=\u00a74Could not find template {0} +creatingConfigFromTemplate=Creating config from template\: {0} +creatingEmptyConfig=Creating empty config\: {0} +creative=creative +currency={0}{1} +currentWorld=\u00a76Current World\:\u00a7c {0} +day=day +days=days +defaultBanReason=The Ban Hammer has spoken\! +deleteFileError=Could not delete file\: {0} +deleteHome=\u00a76Home\u00a7c {0} \u00a76has been removed. +deleteJail=\u00a76Jail\u00a7c {0} \u00a76has been removed. +deleteWarp=\u00a76Warp\u00a7c {0} \u00a76has been removed. +deniedAccessCommand=\u00a7c{0} \u00a74was denied access to command. +denyBookEdit=\u00a74You cannot unlock this book. +denyChangeAuthor=\u00a74You cannot change the author of this book. +denyChangeTitle=\u00a74You cannot change the title of this book. +depth=\u00a76You are at sea level. +depthAboveSea=\u00a76You are\u00a7c {0} \u00a76block(s) above sea level. +depthBelowSea=\u00a76You are\u00a7c {0} \u00a76block(s) below sea level. +destinationNotSet=Destination not set\! +disableUnlimited=\u00a76Disabled unlimited placing of\u00a7c {0} \u00a76for {1}. +disabled=disabled +disabledToSpawnMob=\u00a74Spawning this mob was disabled in the config file. +distance=\u00a76Distance\: {0} +dontMoveMessage=\u00a76Teleportation will commence in\u00a7c {0}\u00a76. Don''t move. +downloadingGeoIp=Downloading GeoIP database... this might take a while (country\: 0.6 MB, city\: 20MB) +duplicatedUserdata=Duplicated userdata\: {0} and {1}. +durability=\u00a76This tool has \u00a7c{0}\u00a76 uses left. +editBookContents=\u00a7eYou may now edit the contents of this book. +enableUnlimited=\u00a76Giving unlimited amount of\u00a7c {0} \u00a76to \u00a7c{1}\u00a76. +enabled=enabled +enchantmentApplied=\u00a76The enchantment\u00a7c {0} \u00a76has been applied to your item in hand. +enchantmentNotFound=\u00a74Enchantment not found\! +enchantmentPerm=\u00a74You do not have the permission for\u00a7c {0}\u00a74. +enchantmentRemoved=\u00a76The enchantment\u00a7c {0} \u00a76has been removed from your item in hand. +enchantments=\u00a76Enchantments\:\u00a7r {0} +errorCallingCommand=Error calling the command /{0} +errorWithMessage=\u00a7cError\:\u00a74 {0} +essentialsHelp1=The file is broken and Essentials can''t open it. Essentials is now disabled. If you can''t fix the file yourself, go to http\://tiny.cc/EssentialsChat +essentialsHelp2=The file is broken and Essentials can''t open it. Essentials is now disabled. If you can''t fix the file yourself, either type /essentialshelp in game or go to http\://tiny.cc/EssentialsChat +essentialsReload=\u00a76Essentials reloaded\u00a7c {0}. +exp=\u00a7c{0} \u00a76has\u00a7c {1} \u00a76exp (level\u00a7c {2}\u00a76) and needs\u00a7c {3} \u00a76more exp to level up. +expSet=\u00a7c{0} \u00a76now has\u00a7c {1} \u00a76exp. +extinguish=\u00a76You extinguished yourself. +extinguishOthers=\u00a76You extinguished {0}\u00a76. +failedToCloseConfig=Failed to close config {0}. +failedToCreateConfig=Failed to create config {0}. +failedToWriteConfig=Failed to write config {0}. +false=\u00a74false\u00a7r +feed=\u00a76Your appetite was sated. +feedOther=\u00a76You satiated the appetite of \u00a7c{0}\u00a76. +fileRenameError=Renaming file {0} failed\! +fireworkColor=\u00a74Invalid firework charge parameters inserted, must set a color first. +fireworkEffectsCleared=\u00a76Removed all effects from held stack. +fireworkSyntax=\u00a76Firework parameters\:\u00a7c color\: [fade\:] [shape\:] [effect\:]\n\u00a76To use multiple colors/effects, separate values with commas\: \u00a7cred,blue,pink\n\u00a76Shapes\:\u00a7c star, ball, large, creeper, burst \u00a76Effects\:\u00a7c trail, twinkle. +flyMode=\u00a76Set fly mode\u00a7c {0} \u00a76for {1}\u00a76. +flying=flying +foreverAlone=\u00a74You have nobody to whom you can reply. +fullStack=\u00a74You already have a full stack. +gameMode=\u00a76Set game mode\u00a7c {0} \u00a76for \u00a7c{1}\u00a76. +gcWorld=\u00a76{0} "\u00a7c{1}\u00a76"\: \u00a7c{2}\u00a76 chunks, \u00a7c{3}\u00a76 entities, \u00a7c{4}\u00a76 tiles. +gcfree=\u00a76Free memory\:\u00a7c {0} MB. +gcmax=\u00a76Maximum memory\:\u00a7c {0} MB. +gctotal=\u00a76Allocated memory\:\u00a7c {0} MB. +geoIpUrlEmpty=GeoIP download url is empty. +geoIpUrlInvalid=GeoIP download url is invalid. +geoipJoinFormat=\u00a76Player \u00a7c{0} \u00a76comes from \u00a7c{1}\u00a76. +giveSpawn=\u00a76Giving\u00a7c {0} \u00a76of\u00a7c {1} to\u00a7c {2}\u00a76. +godDisabledFor=\u00a7cdisabled\u00a76 for\u00a7c {0} +godEnabledFor=\u00a7aenabled\u00a76 for\u00a7c {0} +godMode=\u00a76God mode\u00a7c {0}\u00a76. +groupDoesNotExist=\u00a74There''s no one online in this group\! +groupNumber=\u00a7c{0}\u00a7f online, for the full list\:\u00a7c /{1} {2} +hatArmor=\u00a74You cannot use this item as a hat\! +hatEmpty=\u00a74You are not wearing a hat. +hatFail=\u00a74You must have something to wear in your hand. +hatPlaced=\u00a76Enjoy your new hat\! +hatRemoved=\u00a76Your hat has been removed. +haveBeenReleased=\u00a76You have been released. +heal=\u00a76You have been healed. +healDead=\u00a74You cannot heal someone who is dead\! +healOther=\u00a76Healed\u00a7c {0}\u00a76. +helpConsole=To view help from the console, type ?. +helpFrom=\u00a76Commands from {0}\: +helpLine=\u00a76/{0}\u00a7r\: {1} +helpMatching=\u00a76Commands matching "\u00a7c{0}\u00a76"\: +helpOp=\u00a74[HelpOp]\u00a7r \u00a76{0}\:\u00a7r {1} +helpPlugin=\u00a74{0}\u00a7r\: Plugin Help\: /help {1} +holdBook=\u00a74You are not holding a writable book. +holdFirework=\u00a74You must be holding a firework to add effects. +holdPotion=\u00a74You must be holding a potion to apply effects to it. +holeInFloor=\u00a74Hole in floor\! +homeSet=\u00a76Home set to current location. +homes=\u00a76Homes\:\u00a7r {0} +hour=hour +hours=hours +ignoredList=\u00a76Ignored\:\u00a7r {0} +ignorePlayer=\u00a76You ignore player\u00a7c {0} \u00a76from now on. +illegalDate=Illegal date format. +infoChapter=\u00a76Select chapter\: +infoChapterPages=\u00a7e ---- \u00a76{0} \u00a7e--\u00a76 Page \u00a7c{1}\u00a76 of \u00a7c{2} \u00a7e---- +infoPages=\u00a7e ---- \u00a76{2} \u00a7e--\u00a76 Page \u00a7c{0}\u00a76/\u00a7c{1} \u00a7e---- +infoUnknownChapter=\u00a74Unknown chapter. +insufficientFunds=\u00a74Insufficient funds available. +invalidCharge=\u00a74Invalid charge. +invalidFireworkFormat=\u00a74The option \u00a7c{0} \u00a74is not a valid value for \u00a7c{1}\u00a74. +invalidHome=\u00a74Home\u00a7c {0} \u00a74doesn''t exist\! +invalidHomeName=\u00a74Invalid home name\! +invalidMob=\u00a74Invalid mob type. +invalidNumber=Invalid Number. +invalidPotion=\u00a74Invalid Potion. +invalidPotionMeta=\u00a74Invalid potion meta\: \u00a7c{0}\u00a74. +invalidSignLine=\u00a74Line\u00a7c {0} \u00a74on sign is invalid. +invalidWarpName=\u00a74Invalid warp name\! +invalidWorld=\u00a74Invalid world. +is=is +itemCannotBeSold=\u00a74That item cannot be sold to the server. +itemMustBeStacked=\u00a74Item must be traded in stacks. A quantity of 2s would be two stacks, etc. +itemNames=\u00a76Item short names\:\u00a7r {0} +itemNotEnough1=\u00a74You do not have enough of that item to sell. +itemNotEnough2=\u00a76If you meant to sell all of your items of that type, use /sell itemname. +itemNotEnough3=\u00a76/sell itemname -1 will sell all but one item, etc. +itemSellAir=You really tried to sell Air? Put an item in your hand. +itemSold=\u00a7aSold for \u00a7c{0} \u00a7a({1} {2} at {3} each). +itemSoldConsole=\u00a7a{0} \u00a7asold {1} for \u00a7a{2} \u00a7a({3} items at {4} each). +itemSpawn=\u00a76Giving\u00a7c {0} \u00a76of\u00a7c {1} +itemType=\u00a76Item\:\u00a7c {0} \u00a76-\u00a7c {1} +itemsCsvNotLoaded=Could not load items.csv\! +jailAlreadyIncarcerated=\u00a74Person is already in jail\:\u00a7c {0} +jailMessage=\u00a74You do the crime, you do the time. +jailNotExist=\u00a74That jail does not exist. +jailReleased=\u00a76Player \u00a7c{0}\u00a76 unjailed. +jailReleasedPlayerNotify=\u00a76You have been released\! +jailSentenceExtended=\u00a76Jail time extended to \u00a7c{0}\u00a76. +jailSet=\u00a76Jail\u00a7c {0} \u00a76has been set. +jumpError=\u00a74That would hurt your computer''s brain. +kickDefault=Kicked from server. +kickExempt=\u00a74You cannot kick that person. +kickedAll=\u00a74Kicked all players from server. +kill=\u00a76Killed\u00a7c {0}\u00a76. +killExempt=\u00a74You cannot kill \u00a7c{0}\u00a74. +kitCost=\ \u00a77\u00a7o({0})\u00a7r +kitError2=\u00a74That kit is improperly defined. Contact an administrator. +kitError=\u00a74There are no valid kits. +kitGiveTo=\u00a76Giving kit\u00a7c {0}\u00a76 to \u00a7c{1}\u00a76. +kitInvFull=\u00a74Your inventory was full, placing kit on the floor. +kitNotFound=\u00a74That kit does not exist. +kitOnce=\u00a74You can''t use that kit again. +kitReceive=\u00a76Received kit\u00a7c {0}\u00a76. +kitTimed=\u00a74You can''t use that kit again for another\u00a7c {0}\u00a74. +kits=\u00a76Kits\:\u00a7r {0} +leatherSyntax=\u00a76Leather color syntax\: color\:,, eg\: color\:255,0,0. +lightningSmited=\u00a76Thou hast been smitten\! +lightningUse=\u00a76Smiting\u00a7c {0} +listAfkTag=\u00a77[AFK]\u00a7r +listAmount=\u00a76There are \u00a7c{0}\u00a76 out of maximum \u00a7c{1}\u00a76 players online. +listAmountHidden=\u00a76There are \u00a7c{0}\u00a76/{1}\u00a76 out of maximum \u00a7c{2}\u00a76 players online. +listGroupTag=\u00a76{0}\u00a7r\: \u00a7r +listHiddenTag=\u00a77[HIDDEN]\u00a7r +loadWarpError=\u00a74Failed to load warp {0}. +localFormat=[L]<{0}> {1} +mailClear=\u00a76To mark your mail as read, type\u00a7c /mail clear\u00a76. +mailCleared=\u00a76Mail cleared\! +mailSent=\u00a76Mail sent\! +markMailAsRead=\u00a76To mark your mail as read, type\u00a7c /mail clear\u00a76. +markedAsAway=\u00a76You are now marked as away. +markedAsNotAway=\u00a76You are no longer marked as away. +matchingIPAddress=\u00a76The following players previously logged in from that IP address\: +maxHomes=\u00a74You cannot set more than\u00a7c {0} \u00a74homes. +mayNotJail=\u00a74You may not jail that person\! +me=me +minute=minute +minutes=minutes +missingItems=\u00a74You do not have \u00a7c{0}x {1}\u00a74. +mobSpawnError=\u00a74Error while changing mob spawner. +mobSpawnLimit=Mob quantity limited to server limit. +mobSpawnTarget=\u00a74Target block must be a mob spawner. +mobsAvailable=\u00a76Mobs\:\u00a7r {0} +moneyRecievedFrom=\u00a7a{0} has been received from {1}. +moneySentTo=\u00a7a{0} has been sent to {1}. +month=month +months=months +moreThanZero=\u00a74Quantities must be greater than 0. +moveSpeed=\u00a76Set {0} speed to\u00a7c {1} \u00a76for \u00a7c{2}\u00a76. +msgFormat=\u00a76[\u00a7c{0}\u00a76 -> \u00a7c{1}\u00a76] \u00a7r{2} +multipleCharges=\u00a74You cannot apply more than one charge to this firework. +multiplePotionEffects=\u00a74You cannot apply more than one effect to this potion. +muteExempt=\u00a74You may not mute that player. +muteNotify=\u00a7c{0} \u00a76has muted player \u00a7c{1}\u00a76. +mutedPlayer=\u00a76Player\u00a7c {0} \u00a76muted. +mutedPlayerFor=\u00a76Player\u00a7c {0} \u00a76muted for\u00a7c {1}\u00a76. +mutedUserSpeaks={0} tried to speak, but is muted. +nearbyPlayers=\u00a76Players nearby\:\u00a7r {0} +negativeBalanceError=\u00a74User is not allowed to have a negative balance. +nickChanged=\u00a76Nickname changed. +nickDisplayName=\u00a74You have to enable change-displayname in Essentials config. +nickInUse=\u00a74That name is already in use. +nickNamesAlpha=\u00a74Nicknames must be alphanumeric. +nickNoMore=\u00a76You no longer have a nickname. +nickSet=\u00a76Your nickname is now \u00a7c{0}\u00a76. +nickTooLong=\u00a74That nickname is too long. +noAccessCommand=\u00a74You do not have access to that command. +noAccessPermission=\u00a74You do not have permission to access that \u00a7c{0}\u00a74. +noBreakBedrock=\u00a74You are not allowed to destroy bedrock. +noDestroyPermission=\u00a74You do not have permission to destroy that \u00a7c{0}\u00a74. +noDurability=\u00a74This item does not have a durability. +noGodWorldWarning=\u00a74Warning\! God mode in this world disabled. +noHelpFound=\u00a74No matching commands. +noHomeSetPlayer=\u00a76Player has not set a home. +noIgnored=\u00a76You are not ignoring anyone. +noKitPermission=\u00a74You need the \u00a7c{0}\u00a74 permission to use that kit. +noKits=\u00a76There are no kits available yet. +noMail=\u00a76You do not have any mail. +noMatchingPlayers=\u00a76No matching players found. +noMetaFirework=\u00a74You do not have permission to apply firework meta. +noMetaPerm=\u00a74You do not have permission to apply \u00a7c{0}\u00a74 meta to this item. +noNewMail=\u00a76You have no new mail. +noPendingRequest=\u00a74You do not have a pending request. +noPerm=\u00a74You do not have the \u00a7c{0}\u00a74 permission. +noPermToSpawnMob=\u00a74You don''t have permission to spawn this mob. +noPlacePermission=\u00a74You do not have permission to place a block near that sign. +noPotionEffectPerm=\u00a74You do not have permission to apply potion effect \u00a7c{0} \u00a74to this potion. +noPowerTools=\u00a76You have no power tools assigned. +noWarpsDefined=\u00a76No warps defined. +none=none +notAllowedToQuestion=\u00a74You are not authorized to use question. +notAllowedToShout=\u00a74You are not authorized to shout. +notEnoughExperience=\u00a74You do not have enough experience. +notEnoughMoney=\u00a74You do not have sufficient funds. +notFlying=not flying +notRecommendedBukkit=\u00a74* \! * Bukkit version is not the recommended build for Essentials. +notSupportedYet=Not supported yet. +nothingInHand=\u00a74You have nothing in your hand. +now=now +nuke=\u00a75May death rain upon them. +numberRequired=A number goes there, silly. +onlyDayNight=/time only supports day/night. +onlyPlayerSkulls=\u00a74You can only set the owner of player skulls (\u00a7c397\:3\u00a74). +onlyPlayers=\u00a74Only in-game players can use \u00a7c{0}\u00a74. +onlySunStorm=\u00a74/weather only supports sun/storm. +orderBalances=\u00a76Ordering balances of\u00a7c {0} \u00a76users, please wait... +oversizedTempban=\u00a74You may not ban a player for this period of time. +pTimeCurrent=\u00a7c{0}\u00a76''s time is\u00a7c {1}\u00a76. +pTimeCurrentFixed=\u00a7c{0}\u00a76''s time is fixed to\u00a7c {1}\u00a76. +pTimeNormal=\u00a7c{0}\u00a76''s time is normal and matches the server. +pTimeOthersPermission=\u00a74You are not authorized to set other players'' time. +pTimePlayers=\u00a76These players have their own time\:\u00a7r +pTimeReset=\u00a76Player time has been reset for\: \u00a7c{0} +pTimeSet=\u00a76Player time is set to \u00a7c{0}\u00a76 for\: \u00a7c{1}. +pTimeSetFixed=\u00a76Player time is fixed to \u00a7c{0}\u00a76 for\: \u00a7c{1}. +pWeatherCurrent=\u00a7c{0}\u00a76''s weather is\u00a7c {1}\u00a76. +pWeatherInvalidAlias=\u00a74Invalid weather type +pWeatherNormal=\u00a7c{0}\u00a76''s weather is normal and matches the server. +pWeatherOthersPermission=\u00a74You are not authorized to set other players'' weather. +pWeatherPlayers=\u00a76These players have their own weather\:\u00a7r +pWeatherReset=\u00a76Player weather has been reset for\: \u00a7c{0} +pWeatherSet=\u00a76Player weather is set to \u00a7c{0}\u00a76 for\: \u00a7c{1}. +pendingTeleportCancelled=\u00a74Pending teleportation request cancelled. +playerBanIpAddress=\u00a76Player\u00a7c {0} \u00a76banned IP address\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerBanned=\u00a76Player\u00a7c {0} \u00a76banned\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerInJail=\u00a74Player is already in jail\u00a7c {0}\u00a74. +playerJailed=\u00a76Player\u00a7c {0} \u00a76jailed. +playerJailedFor=\u00a76Player\u00a7c {0} \u00a76jailed for {1}. +playerKicked=\u00a76Player\u00a7c {0} \u00a76kicked {1} for {2}. +playerMuted=\u00a76You have been muted\! +playerMutedFor=\u00a76You have been muted for\u00a7c {0}. +playerNeverOnServer=\u00a74Player\u00a7c {0} \u00a74was never on this server. +playerNotFound=\u00a74Player not found. +playerUnbanIpAddress=\u00a76Player\u00a7c {0} \u00a76unbanned IP\: {1}. +playerUnbanned=\u00a76Player\u00a7c {0} \u00a76unbanned\u00a7c {1}. +playerUnmuted=\u00a76You have been unmuted. +pong=Pong\! +posPitch=\u00a76Pitch\: {0} (Head angle) +posX=\u00a76X\: {0} (+East <-> -West) +posY=\u00a76Y\: {0} (+Up <-> -Down) +posYaw=\u00a76Yaw\: {0} (Rotation) +posZ=\u00a76Z\: {0} (+South <-> -North) +possibleWorlds=\u00a76Possible worlds are the numbers \u00a7c0\u00a76 through \u00a7c{0}\u00a76. +potions=\u00a76Potions\:\u00a7r {0}\u00a76. +powerToolAir=\u00a74Command can''t be attached to air. +powerToolAlreadySet=\u00a74Command \u00a7c{0}\u00a74 is already assigned to \u00a7c{1}\u00a74. +powerToolAttach=\u00a7c{0}\u00a76 command assigned to {1}. +powerToolClearAll=\u00a76All powertool commands have been cleared. +powerToolList=\u00a76Item \u00a7c{1} \u00a76has the following commands\: \u00a7c{0}\u00a76. +powerToolListEmpty=\u00a74Item \u00a7c{0} \u00a74has no commands assigned. +powerToolNoSuchCommandAssigned=\u00a74Command \u00a7c{0}\u00a74 has not been assigned to \u00a7c{1}\u00a74. +powerToolRemove=\u00a76Command \u00a7c{0}\u00a76 removed from \u00a7c{1}\u00a76. +powerToolRemoveAll=\u00a76All commands removed from \u00a7c{0}\u00a76. +powerToolsDisabled=\u00a76All of your power tools have been disabled. +powerToolsEnabled=\u00a76All of your power tools have been enabled. +questionFormat=\u00a72[Question]\u00a7r {0} +readNextPage=\u00a76Type\u00a7c /{0} {1} \u00a76to read the next page. +recipe=\u00a76Recipe for \u00a7c{0}\u00a76 (\u00a7c{1}\u00a76 of \u00a7c{2}\u00a76) +recipeBadIndex=There is no recipe by that number. +recipeFurnace=\u00a76Smelt\: \u00a7c{0}\u00a76. +recipeGrid=\u00a7c{0}X \u00a76| \u00a7{1}X \u00a76| \u00a7{2}X +recipeGridItem=\u00a7c{0}X \u00a76is \u00a7c{1} +recipeMore=\u00a76Type /{0} \u00a7c{1}\u00a76 to see other recipes for \u00a7c{2}\u00a76. +recipeNone=No recipes exist for {0}. +recipeNothing=nothing +recipeShapeless=\u00a76Combine \u00a7c{0} +recipeWhere=\u00a76Where\: {0} +removed=\u00a76Removed\u00a7c {0} \u00a76entities. +repair=\u00a76You have successfully repaired your\: \u00a7c{0}\u00a76. +repairAlreadyFixed=\u00a74This item does not need repairing. +repairEnchanted=\u00a74You are not allowed to repair enchanted items. +repairInvalidType=\u00a74This item cannot be repaired. +repairNone=\u00a74There were no items that needed repairing. +requestAccepted=\u00a76Teleport request accepted. +requestAcceptedFrom=\u00a7c{0} \u00a76accepted your teleport request. +requestDenied=\u00a76Teleport request denied. +requestDeniedFrom=\u00a7c{0} \u00a76denied your teleport request. +requestSent=\u00a76Request sent to\u00a7c {0}\u00a76. +requestTimedOut=\u00a74Teleport request has timed out. +requiredBukkit=\u00a76* \! * You need at least build {0} of CraftBukkit, download it from http\://dl.bukkit.org/downloads/craftbukkit/ +resetBal=\u00a76Balance has been reset to \u00a7c{0} \u00a76for all online players. +resetBalAll=\u00a76Balance has been reset to \u00a7c{0} \u00a76for all players. +returnPlayerToJailError=\u00a74Error occurred when trying to return player\u00a7c {0} \u00a74to jail\: \u00a7c{1}\u00a74\! +runningPlayerMatch=\u00a76Running search for players matching ''\u00a7c{0}\u00a76'' (this could take a little while). +second=second +seconds=seconds +seenOffline=\u00a76Player\u00a7c {0} \u00a76has been \u00a74offline\u00a76 since \u00a7c{1}\u00a76. +seenOnline=\u00a76Player\u00a7c {0} \u00a76has been \u00a7aonline\u00a76 since \u00a7c{1}\u00a76. +serverFull=Server is full\! +serverTotal=\u00a76Server Total\:\u00a7c {0} +setBal=\u00a7aYour balance was set to {0}. +setBalOthers=\u00a7aYou set {0}\u00a7a''s balance to {1}. +setSpawner=\u00a76Changed spawner type to\u00a7c {0}\u00a76. +sheepMalformedColor=\u00a74Malformed color. +shoutFormat=\u00a76[Shout]\u00a7r {0} +signFormatFail=\u00a74[{0}] +signFormatSuccess=\u00a71[{0}] +signFormatTemplate=[{0}] +signProtectInvalidLocation=\u00a74You are not allowed to create sign here. +similarWarpExist=\u00a74A warp with a similar name already exists. +slimeMalformedSize=\u00a74Malformed size. +socialSpy=\u00a76SocialSpy for \u00a7c{0}\u00a76\: \u00a7c{1} +soloMob=\u00a74That mob likes to be alone. +spawnSet=\u00a76Spawn location set for group\u00a7c {0}\u00a76. +spawned=spawned +sudoExempt=\u00a74You cannot sudo this user. +sudoRun=\u00a76Forcing\u00a7c {0} \u00a76to run\:\u00a7r /{1} +suicideMessage=\u00a76Goodbye cruel world... +suicideSuccess=\u00a76Player \u00a7c{0} \u00a76took their own life. +survival=survival +takenFromAccount=\u00a7a{0} has been taken from your account. +takenFromOthersAccount=\u00a7a{0} taken from {1}\u00a7a account. New balance\: {2}. +teleportAAll=\u00a76Teleport request sent to all players... +teleportAll=\u00a76Teleporting all players... +teleportAtoB=\u00a7c{0}\u00a76 teleported you to \u00a7c{1}\u00a76. +teleportDisabled=\u00a7c{0} \u00a74has teleportation disabled. +teleportHereRequest=\u00a7c{0}\u00a76 has requested that you teleport to them. +teleportNewPlayerError=\u00a74Failed to teleport new player\! +teleportRequest=\u00a7c{0}\u00a76 has requested to teleport to you. +teleportRequestTimeoutInfo=\u00a76This request will timeout after\u00a7c {0} seconds\u00a76. +teleportTop=\u00a76Teleporting to top. +teleportationCommencing=\u00a76Teleportation commencing... +teleportationDisabled=\u00a76Teleportation \u00a7cdisabled\u00a76. +teleportationDisabledFor=\u00a76Teleportation \u00a7cdisabled \u00a76for \u00a7c{0}\u00a76. +teleportationEnabled=\u00a76Teleportation \u00a7cenabled\u00a76. +teleportationEnabledFor=\u00a76Teleportation \u00a7cenabled \u00a76for \u00a7c{0}\u00a76. +teleporting=\u00a76Teleporting... +teleportToPlayer=\u00a76Teleporting to \u00a7c{0}\u00a76. +tempBanned=\u00a7cYou have been temporarily banned for {0}\:\n\u00a7r{2} +tempbanExempt=\u00a74You may not tempban that player. +thunder=\u00a76You\u00a7c {0} \u00a76thunder in your world. +thunderDuration=\u00a76You\u00a7c {0} \u00a76thunder in your world for\u00a7c {1} \u00a76seconds. +timeBeforeHeal=\u00a74Time before next heal\:\u00a7c {0}\u00a76. +timeBeforeTeleport=\u00a74Time before next teleport\:\u00a7c {0}\u00a76. +timeFormat=\u00a7c{0}\u00a76 or \u00a7c{1}\u00a76 or \u00a7c{2}\u00a76 +timeSetPermission=\u00a74You are not authorized to set the time. +timeWorldCurrent=\u00a76The current time in\u00a7c {0} \u00a76is \u00a7c{1}\u00a76. +timeWorldSet=\u00a76The time was set to\u00a7c {0} \u00a76in\: \u00a7c{1}\u00a76. +totalWorthAll=\u00a7aSold all items and blocks for a total worth of \u00a7c{1}\u00a7a. +totalWorthBlocks=\u00a7aSold all blocks for a total worth of \u00a7c{1}\u00a7a. +tps=\u00a76Current TPS \= {0} +tradeSignEmpty=\u00a74The trade sign has nothing available for you. +tradeSignEmptyOwner=\u00a74There is nothing to collect from this trade sign. +treeFailure=\u00a74Tree generation failure. Try again on grass or dirt. +treeSpawned=\u00a76Tree spawned. +true=\u00a7atrue\u00a7r +typeTpaccept=\u00a76To teleport, type \u00a7c/tpaccept\u00a76. +typeTpdeny=\u00a76To deny this request, type \u00a7c/tpdeny\u00a76. +typeWorldName=\u00a76You can also type the name of a specific world. +unableToSpawnMob=\u00a74Unable to spawn mob. +unignorePlayer=\u00a76You are not ignoring player\u00a7c {0} \u00a76anymore. +unknownItemId=\u00a74Unknown item id\:\u00a7r {0}\u00a74. +unknownItemInList=\u00a74Unknown item {0} in {1} list. +unknownItemName=\u00a74Unknown item name\: {0}. +unlimitedItemPermission=\u00a74No permission for unlimited item \u00a7c{0}\u00a74. +unlimitedItems=\u00a76Unlimited items\:\u00a7r +unmutedPlayer=\u00a76Player\u00a7c {0} \u00a76unmuted. +unvanishedReload=\u00a74A reload has forced you to become visible. +upgradingFilesError=Error while upgrading the files. +uptime=\u00a76Uptime\:\u00a7c {0} +userAFK=\u00a77{0} \u00a75is currently AFK and may not respond. +userDoesNotExist=\u00a74The user\u00a7c {0} \u00a74does not exist. +userIsAway=\u00a77* {0} \u00a77is now AFK. +userIsNotAway=\u00a77* {0} \u00a77is no longer AFK. +userJailed=\u00a76You have been jailed\! +userUnknown=\u00a74Warning\: The user ''\u00a7c{0}\u00a74'' has never joined this server. +userdataMoveBackError=Failed to move userdata/{0}.tmp to userdata/{1}\! +userdataMoveError=Failed to move userdata/{0} to userdata/{1}.tmp\! +usingTempFolderForTesting=Using temp folder for testing\: +vanished=\u00a76You are now completely invisible to normal users, and hidden from in-game commands. +versionMismatch=\u00a74Version mismatch\! Please update {0} to the same version. +versionMismatchAll=\u00a74Version mismatch\! Please update all Essentials jars to the same version. +voiceSilenced=\u00a76Your voice has been silenced\! +walking=walking +warpDeleteError=\u00a74Problem deleting the warp file. +warpList={0} +warpListPermission=\u00a74You do not have permission to list warps. +warpNotExist=\u00a74That warp does not exist. +warpOverwrite=\u00a74You cannot overwrite that warp. +warpSet=\u00a76Warp\u00a7c {0} \u00a76set. +warpUsePermission=\u00a74You do not have permission to use that warp. +warpingTo=\u00a76Warping to\u00a7c {0}\u00a76. +warps=\u00a76Warps\:\u00a7r {0} +warpsCount=\u00a76There are\u00a7c {0} \u00a76warps. Showing page \u00a7c{1} \u00a76of \u00a7c{2}\u00a76. +weatherStorm=\u00a76You set the weather to \u00a7cstorm\u00a76 in\u00a7c {0}\u00a76. +weatherStormFor=\u00a76You set the weather to \u00a7cstorm\u00a76 in\u00a7c {0} \u00a76for {1} seconds. +weatherSun=\u00a76You set the weather to \u00a7csun\u00a76 in\u00a7c {0}\u00a76. +weatherSunFor=\u00a76You set the weather to \u00a7csun\u00a76 in\u00a7c {0} \u00a76for {1} seconds. +whoisAFK=\u00a76 - AFK\:\u00a7r {0} +whoisBanned=\u00a76 - Banned\:\u00a7r {0} +whoisExp=\u00a76 - Exp\:\u00a7r {0} (Level {1}) +whoisFly=\u00a76 - Fly mode\:\u00a7r {0} ({1}) +whoisGamemode=\u00a76 - Gamemode\:\u00a7r {0} +whoisGeoLocation=\u00a76 - Location\:\u00a7r {0} +whoisGod=\u00a76 - God mode\:\u00a7r {0} +whoisHealth=\u00a76 - Health\:\u00a7r {0}/20 +whoisIPAddress=\u00a76 - IP Address\:\u00a7r {0} +whoisJail=\u00a76 - Jail\:\u00a7r {0} +whoisLocation=\u00a76 - Location\:\u00a7r ({0}, {1}, {2}, {3}) +whoisMoney=\u00a76 - Money\:\u00a7r {0} +whoisMuted=\u00a76 - Muted\:\u00a7r {0} +whoisNick=\u00a76 - Nick\:\u00a7r {0} +whoisOp=\u00a76 - OP\:\u00a7r {0} +whoisTop=\u00a76 \=\=\=\=\=\= WhoIs\:\u00a7c {0} \u00a76\=\=\=\=\=\= +worth=\u00a7aStack of {0} worth \u00a7c{1}\u00a7a ({2} item(s) at {3} each) +worthMeta=\u00a7aStack of {0} with metadata of {1} worth \u00a7c{2}\u00a7a ({3} item(s) at {4} each) +worthSet=\u00a76Worth value set +year=year +years=years +youAreHealed=\u00a76You have been healed. +youHaveNewMail=\u00a76You have\u00a7c {0} \u00a76messages\! Type \u00a7c/mail read\u00a76 to view your mail. +whoisHunger=\u00a76 - Hunger\:\u00a7r {0}/20 (+{1} saturation) +kitDelay=\u00a7m{0}\u00a7r +giveSpawnFailure=\u00a74Not enough space, \u00a7c{0} \u00a7c{1} \u00a74was lost. +noKitGroup=\u00a74You do not have access to this kit. +inventoryClearingFromAll=\u00a76Clearing the inventory of all users... +inventoryClearingAllItems=\u00a76Cleared all inventory items from {0}\u00a76. +inventoryClearingAllArmor=\u00a76Cleared all inventory items and armor from {0}\u00a76. +inventoryClearingAllStack=\u00a76Cleared all\u00a7c {0} \u00a76from {1}\u00a76. +inventoryClearingStack=\u00a76Removed\u00a7c {0} \u00a76of\u00a7c {1} \u00a76from {2}\u00a76. +inventoryClearFail=\u00a74Player {0} \u00a74does not have\u00a7c {1} \u00a74of\u00a7c {2}\u00a74. +localNoOne= +totalSellableAll=\u00a7aThe total worth of all sellable items and blocks is \u00a7c{1}\u00a7a. +totalSellableBlocks=\u00a7aThe total worth of all sellable blocks is \u00a7c{1}\u00a7a. +radiusTooBig=\u00a74Radius is too big\! Maximum radius is {0}. +isIpBanned=\u00a76IP \u00a7c{0} \u00a76is banned. +mobDataList=\u00a76Valid mob data\:\u00a7r {0} +vanish=\u00a76Vanish for {0}\u00a76\: {1} +noLocationFound=\u00a74No valid location found. +coordsKeyword={0}, {1}, {2} +banExemptOffline=\u00a74You may not ban offline players. +tempbanExemptOffline=\u00a74You may not tempban offline players. +mayNotJailOffline=\u00a74You may not jail offline players. +muteExemptOffline=\u00a74You may not mute offline players. +ignoreExempt=\u00a74You may not ignore that player. +unsafeTeleportDestination=\u00a74The teleport destination is unsafe and teleport-safety is disabled. +noMetaJson=JSON Metadata is not supported in this version of Bukkit. +maxMoney=\u00a74This transaction would exceed the balance limit for this account. +skullChanged=\u00a76Skull changed to \u00a7c{0}\u00a76. +alphaNames=\u00a74Player names can only contain letters, numbers and underscores. +givenSkull=\u00a76You have been given the skull of \u00a7c{0}\u00a76. +noPermissionSkull=\u00a74You do not have permission to modify that skull. +teleportInvalidLocation=Value of coordinates cannot be over 30000000 +invalidSkull=\u00a74Please hold a player skull. +weatherInvalidWorld=World named {0} not found\! +gameModeInvalid=\u00a74You need to specify a valid player/mode. +mailTooLong=\u00a74Mail message too long. Try to keep it below 1000 characters. +mailDelay=Too many mails have been sent within the last minute. Maximum\: {0} +seenAccounts=\u00a76Player has also been known as\:\u00a7c {0} +unableToSpawnItem=\u00a74Cannot spawn \u00a7c{0}\u00a74, this is not a spawnable item. +itemsConverted=\u00a76Converted all items into blocks. +itemsNotConverted=\u00a74You have no items that can be converted into blocks. +mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\: +mailMessage={0} +whoisTempBanned=\u00a76 - Ban expires:\u00a7r {0} +playerTempBanned=\u00a76Player \u00a7c{0}\u00a76 temporarily banned \u00a7c{1}\u00a76 for \u00a7c{2}\u00a76: \u00a7c{3}\u00a76. +mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1} diff --git a/Essentials/src/messages_cs.properties b/Essentials/src/messages_cs.properties new file mode 100644 index 0000000000..26c3e6fa4f --- /dev/null +++ b/Essentials/src/messages_cs.properties @@ -0,0 +1,558 @@ +#X-Generator: crowdin.net +#version: TeamCity +# Single quotes have to be doubled: '' +# Translations start here +# by: +action=\u00a75* {0} \u00a75{1} +addedToAccount=\u00a7a{0} bylo pripsano na tvuj ucet. +addedToOthersAccount=\u00a7a{0} bylo pripsano na {1}\u00a7a ucet. Nova hodnota\: {2} +adventure=Adventure +alertBroke=zniceno\: +alertFormat=\u00a73[{0}] \u00a7f {1} \u00a76 {2} v\: {3} +alertPlaced=polozeno\: +alertUsed=pouzito\: +antiBuildBreak=\u00a74Zde nemas dovoleno nicit {0}. +antiBuildCraft=\u00a74Nemas dovoleno vytvaret\u00a7c {0}\u00a74. +antiBuildDrop=\u00a74Nemas dovoleno vyhazovat\u00a7c {0}\u00a74. +antiBuildInteract=\u00a74Nemas dovoleno pouzit {0}. +antiBuildPlace=\u00a74Zde nemas dovoleno pokladat {0}. +antiBuildUse=\u00a74Nemas dovoleno pouzit {0}. +autoAfkKickReason=Byl jsi vyhozen za neaktivitu delsi nez {0} minut. +backAfterDeath=\u00a77Pouzij /back, aby ses vratil na misto sve smrti. +backUsageMsg=\u00a77Vracis se na svou minulou pozici. +backupDisabled=Externi zalohovaci script neni nastaven. +backupFinished=Zaloha dokoncena +backupStarted=Probiha zaloha +balance=\u00a77Ucet\: {0} +balanceOther=\u00a7aUcet hrace {0}\u00a7a\:\u00a7c {1} +balanceTop=\u00a77Nejbohatsi hraci ({0}) +banExempt=\u00a7cNemuzes zabanovat tohoto hrace. +banFormat=\u00a74Banned\: \u00a7r{0} +bed=&opostel&r +bedMissing=\u00a74Tvoje postel bud neni nastavena, nebo je ztracena, nebo zablokovana. +bedNull=\u00a7mpostel\u00a7r +bedSet=&6 Postel nastavena \! +bigTreeFailure=\u00a7cProblem pri vytvareni velkeho stromu. Zkuste znovu na trave nebo hline. +bigTreeSuccess=\u00a77Velky strom vytvoren. +blockList=Essentials prenechal nasledujici prikazy jinemu pluginu\: +bookAuthorSet=\u00a76{0} byl nastaven jako autor knihy. +bookLocked=\u00a76Tato kniha je nyni uzamcena. +bookTitleSet=\u00a76Nazev knihy nastaven na {0}. +broadcast=[\u00a7cSdeleni\u00a7f]\u00a7a {0} +buildAlert=\u00a7cNemas dovoleno stavet. +bukkitFormatChanged=Format kontroly verze Bukkitu zmenen. Verze nebyla zkontrolovana. +burnMsg=\u00a77Zapalil jsi {0} na dobu {1} sekund. +canTalkAgain=\u00a77Muzes opet mluvit. +cannotStackMob=\u00a74Nemas opravneni na stackovani vice mobu. +cantFindGeoIpDB=Nemohu najit GeoIP databazi\! +cantReadGeoIpDB=Nemohu precist GeoIP databazi\! +cantSpawnItem=\u00a7cNejsi dovoleny spawnout item\: {0} +chatTypeAdmin=[A] +chatTypeLocal=[L] +chatTypeSpy=[Spy] +cleaned=Uzivatelske zaznamy vycisteny. +cleaning=Cistim uzivatelske zaznamy. +commandFailed=Prikaz {0} selhal. +commandHelpFailedForPlugin=Chyba pri ziskavani pomoci\: {0} +commandNotLoaded=\u00a7cPrikaz {0} je nespravne nacteny. +compassBearing=\u00a77Zmena orientace\: {0} ({1} stupnu). +configFileMoveError=Chyba pri presouvani config.yml do slozky se zalohou. +configFileRenameError=Chyba pri pokusu o prejmenovani docasneho souboru na config.yml +connectedPlayers=Pripojeni hraci\: +connectionFailed=Pokus o otevreni spojeni selhal. +cooldownWithMessage=\u00a7cOdpocet\: {0} +corruptNodeInConfig=\u00a74Pozor\: Vas konfiguracni soubor ma chybnou {0} poznamku. +couldNotFindTemplate=Nemohu naleznout sablonu\: {0} +creatingConfigFromTemplate=Vytvarim config ze sablony\: {0} +creatingEmptyConfig=Vytvarim prazdny config\: {0} +creative=Creative +currency={0}{1} +currentWorld=Soucasny svet\: {0} +day=den +days=dny +defaultBanReason=Banovaci kladivo promluvilo\! +deleteFileError=Nemohu smazat soubor\: {0} +deleteHome=\u00a77Domov {0} byl uspesne odstranen. +deleteJail=\u00a77Jail {0} byl uspesne odstranen. +deleteWarp=\u00a77Warp {0} byl uspesne odstranen. +deniedAccessCommand=Hraci {0} byl zablokovan prikaz. +denyBookEdit=\u00a74Nemuzes odemknout tuto knihu. +denyChangeAuthor=\u00a74Nemuzes zmenit autora teto knihy. +denyChangeTitle=\u00a74Nemuzes zmenit nazev teto knihy. +depth=\u00a77Jsi na urovni more. +depthAboveSea=\u00a77Jsi {0} kostek nad urovni more. +depthBelowSea=\u00a77Jsi {0} kostek pod urovni more. +destinationNotSet=Destinace neni nastavena. +disableUnlimited=\u00a77Zablokovano neomezene pokladani {0} hraci {1}. +disabled=zablokovano +disabledToSpawnMob=Spawnuti tohoto moba je zakazno v configuracnim souboru. +distance=\u00a76Vzdalenost\: {0} +dontMoveMessage=\u00a77Teleport bude zahajen za {0}. Nehybej se. +downloadingGeoIp=Stahuji GeoIP databazi ... muze to chvilku trvat (staty\: 0.6 MB, mesta\: 20MB) +duplicatedUserdata=Duplikovane data hrace\: {0} and {1} +durability=\u00a77Tomuto nastroji zbyva \u00a7c{0}\u00a77 pouziti. +editBookContents=\u00a7eNyni muzes upravovat obsah teto knihy. +enableUnlimited=\u00a76D\u00e1t neomezen\u00e9 mno\u017estv\u00ed\u00a7c {0} \u00a76na \u00a7c{1}\u00a76. +enabled=povoleno +enchantmentApplied=\u00a77Enchant {0} byl aplikovan na tvuj nastroj v ruce. +enchantmentNotFound=\u00a7cTento enchant neexistuje +enchantmentPerm=\u00a7cNemas opravneni na enchant\: {0} +enchantmentRemoved=\u00a77Enchant {0} byl odstranen z tveho nastroje v ruce. +enchantments=\u00a77Enchantmenty\: {0} +errorCallingCommand=Chyba pri volani prikazu /{0} +errorWithMessage=\u00a7cChyba\: {0} +essentialsHelp1=Soubor je poskozen a Essentials jej nemuze otevrit. Essentials jsou zablokovany. Pokud nemuzete soubor opravit sami, navstivte http\://tiny.cc/EssentialsChat +essentialsHelp2=Soubor je poskozen a Essentials jej nemuze otevrit. Essentials jsou zablokovany. Pokud nemuzete soubor opravit sami, pak napiste /essentialshelp ve hre nebo navstivte http\://tiny.cc/EssentialsChat +essentialsReload=\u00a76Essentials restartovan\u00fd\u00a7c {0}. +exp=\u00a7c{0} \u00a77ma\u00a7c {1} \u00a77exp (level\u00a7c {2}\u00a77) a potrebuje\u00a7c {3} \u00a77 exp aby dosahl dalsiho levelu. +expSet=\u00a7c{0} \u00a77ma nyni\u00a7c {1} \u00a77exp. +extinguish=\u00a77Uhasil ses. +extinguishOthers=\u00a77Uhasil jsi hrace {0}. +failedToCloseConfig=Chyba pri uzavreni configu {0} +failedToCreateConfig=Chyba pri vytvoreni configu {0} +failedToWriteConfig=Chyba pri zapisovani do configu {0} +false=\u00a74Ne\u00a7f +feed=\u00a77Nasytil jsi se. +feedOther=\u00a76Nasytil jsi hrace \u00a7c{0}\u00a76. +fileRenameError=Prejmenovani souboru {0} selhalo. +fireworkColor=\u00a74Vlozeny neplatne parametry, nejprve musis nastavit barvu. +fireworkEffectsCleared=\u00a76Vsechny efekty byly odstraneny. +fireworkSyntax=Parametry ohnostroje\:\u00a7c color\: [fade\:] [shape\:] [effect\:]\n\u00a76Pro multi barvy/efekty, oddel polozky carkou\: \u00a7cred,blue,pink\n\u00a76Tvary\:\u00a7c star, ball, large, creeper, burst \u00a76Efekty\:\u00a7c trail, twinkle. +flyMode=\u00a77Povolil jsi letani hraci {0} hraci {1}. +flying=letani +foreverAlone=\u00a7cNemas komu odepsat. +fullStack=\u00a74Jiz mas cely stack. +gameMode=\u00a76Herni mod hrace \u00a7c{1} \u00a76byl nastaven na \u00a7c {0}\u00a76. +gcWorld=\u00a76{0} "\u00a7c{1}\u00a76"\: \u00a7c{2}\u00a76 chunku, \u00a7c{3}\u00a76 entit, \u00a7c{4}\u00a76 tile-entit. +gcfree=Volna pamet\: {0} MB +gcmax=Dostupna pamet\: {0} MB +gctotal=Vyuzita pamet\: {0} MB +geoIpUrlEmpty=Odkaz na stazeni GeoIP je prazdny. +geoIpUrlInvalid=Odkaz na stazeni GeoIP je chybny. +geoipJoinFormat=Hrac {0} prichazi z {1} +giveSpawn=\u00a76Dal jsi\u00a7c {0} \u00a76\u00a7c {1} hraci\u00a7c {2}\u00a76. +godDisabledFor=\u00a7cvypnuto\u00a76 pro\u00a7c {0} +godEnabledFor=povolen pro {0} +godMode=\u00a76Nesmrtelnost\u00a7c {0}\u00a76. +groupDoesNotExist=\u00a74Nikdo z teto skupiny neni online\! +groupNumber=\u00a7c{0}\u00a7f online, pro kompletni seznam\:\u00a7c /{1} {2} +hatArmor=\u00a7cChyba, tento predmet nemuzes pouzit jako pokryvku hlavy\! +hatEmpty=\u00a7cMomentalne nemas zadnou pokryvku hlavy. +hatFail=\u00a7cMusis mit to, co chces mit na hlave v ruce. +hatPlaced=\u00a7eUzij si svou novou pokryvku hlavy\! +hatRemoved=\u00a7eOdstralil jsi svou pokryvku hlavy. +haveBeenReleased=\u00a77Byl jsi uvolnen +heal=\u00a77Byl jsi uzdraven. +healDead=\u00a74Nemuzes lecit nekoho, kdo je uz po smrti\! +healOther=\u00a77Uzdravil jsi hrace {0}. +helpConsole=Pokud chces videt napovedu z konzole, napis ?. +helpFrom=\u00a77Prikazy od{0}\: +helpLine=\u00a76/{0}\u00a7r\: {1} +helpMatching=\u00a77Prikazy odpovidajici "{0}"\: +helpOp=\u00a7c[HelpOp]\u00a7f \u00a77{0}\:\u00a7f {1} +helpPlugin=\u00a74{0}\u00a7f\: Napoveda pluginu\: /help {1} +holdBook=\u00a74Nemas v ruce knihu, do ktere lze psat. +holdFirework=\u00a74Pro pridani efektu musis drzet ohnostroj v ruce. +holdPotion=\u00a74Pro nastaveni lektvaru ho musis drzet v ruce. +holeInFloor=Dira v podlaze +homeSet=\u00a77Domov nastaven. +homes=Domovy\: {0} +hour=hodina +hours=hodiny +ignoredList=\u00a76Ignorovani hraci\:\u00a7r {0} +ignorePlayer=Zacal jsi ignorovat hrace {0}. +illegalDate=Nespravny format data. +infoChapter=\u00a76Vyberte kapitolu\: +infoChapterPages=\u00a7e ---- \u00a76{0} \u00a7e--\u00a76 Stranka \u00a7c{1}\u00a76 ze \u00a7c{2} \u00a7e---- +infoPages=\u00a7e ---- \u00a76{2} \u00a7e--\u00a76 Strana \u00a74{0}\u00a76/\u00a74{1} \u00a7e---- +infoUnknownChapter=\u00a74Neznama kapitola. +insufficientFunds=\u00a74Nemas k dispozici dostatek hotovosti. +invalidCharge=\u00a7cNeplatny poplatek. +invalidFireworkFormat=\u00a74Nastaveni \u00a7c{0} \u00a74neni platna hodnota pro \u00a7c{1}\u00a74. +invalidHome=Domov {0} neexistuje. +invalidHomeName=\u00a74Spatny nazev domova +invalidMob=\u00a74Neplatny druh moba +invalidNumber=Neplatne cislo. +invalidPotion=\u00a74Nespravny lektvar. +invalidPotionMeta=\u00a74Nespravna metadata lektvaru\: \u00a7c{0}\u00a74. +invalidSignLine=Radek {0} je chybne vyplnen. +invalidWarpName=\u00a74Spatny nazev warpu +invalidWorld=\u00a7cNespravny svet\! +is=je +itemCannotBeSold=Tento predmet nelze prodat serveru. +itemMustBeStacked=Predmety musi byt vymeneny ve stacku. +itemNames=Zkracene nazvy predmetu\: {0} +itemNotEnough1=\u00a7cNemas dostatek tohoto itemu, aby jsi jej mohl prodat. +itemNotEnough2=\u00a77Pokud jsi chtel prodat vsechny itemy tohoto typu, pouzij /sell nazevitemu +itemNotEnough3=\u00a77/sell nazevnitemu -1 proda vse ale pouze jeden item atd. +itemSellAir=Vazne jsi se pokusil prodat Vzduch? Vezmi si neco do ruky. +itemSold=\u00a77Prodano za \u00a7c{0} \u00a77({1} {2} za cenu {3} kus) +itemSoldConsole={0} Prodano {1} za \u00a77{2} \u00a77({3} za cenu {4} kus) +itemSpawn=\u00a77Davam {0} {1} +itemType=\u00a76Item\:\u00a7c {0} \u00a76-\u00a7c {1} +itemsCsvNotLoaded=Nelze nacist soubor items.csv. +jailAlreadyIncarcerated=\u00a7cTento hrace ja jiz uveznen\: {0} +jailMessage=\u00a7cPorusil jsi pravidla, ted si to odsedis\! +jailNotExist=Toto vezeni neexistuje. +jailReleased=\u00a77Hrac \u00a7e{0}\u00a77 byl propusten na svobodu. +jailReleasedPlayerNotify=\u00a77Byl jsi propusten na svobodu\! +jailSentenceExtended=Cas ve vezeni prodlouzen na\: {0} +jailSet=\u00a77Vezeni {0} bylo vytvoreno. +jumpError=Tohle by tvuj procesor nemusel rozdychat. +kickDefault=Vyhozen ze serveru +kickExempt=\u00a7cNemuzes vyhodit tuhle osobu. +kickedAll=\u00a74Vykopl jsi vsechny hrace ze serveru. +kill=\u00a77Zabit {0}. +killExempt=\u00a74Nemuzes zabit hrace \u00a7c{0}\u00a74. +kitCost=\ \u00a77\u00a7o({0})\u00a7r +kitError2=\u00a7cTento kit neexistuje, nebo je chybne definovan. +kitError=\u00a7cNejsou zadne validni kity. +kitGiveTo=\u00a76Davam kit \u00a7c {0}\u00a76 hraci \u00a7c{1}\u00a76. +kitInvFull=\u00a7cMel jsi plny inventar, obsah kitu je na zemi. +kitNotFound=\u00a74Tento kit neexistuje. +kitOnce=\u00a74Jiz nemuzes tento kit pouzivat. +kitReceive=\u00a76Obdrzel jsi kit\u00a7c {0}\u00a76. +kitTimed=\u00a7cNemuzes pouzit tento kit po dalsich {0}. +kits=\u00a77Kity\: {0} +leatherSyntax=\u00a76Syntaxe barvy kuze\: color\:,, napr\: color\:255,0,0. +lightningSmited=\u00a77Byl jsi zasazen bleskem. +lightningUse=\u00a77Zasadil jsi bleskem hrace {0} +listAfkTag=\u00a77[AFK]\u00a7f +listAmount=\u00a79Je zde \u00a7c{0}\u00a79 z maxima \u00a7c{1}\u00a79 hracu online. +listAmountHidden=\u00a79Je zde \u00a7c{0}\u00a77/{1}\u00a79 z maxima \u00a7c{2}\u00a79 hracu online. +listGroupTag=\u00a76{0}\u00a7r\: \u00a7r +listHiddenTag=\u00a77[SKRYTY]\u00a7f +loadWarpError=Chyba pri nacitani warpu\: {0} +localFormat=[L]<{0}> {1} +mailClear=\u00a76Pokud chces vymazat mail, napis\u00a7c /mail clear\u00a76. +mailCleared=\u00a77Mail vymazan\! +mailSent=\u00a77Mail odeslan\! +markMailAsRead=\u00a76Pokud chces vymazat mail, napis\u00a7c /mail clear\u00a76. +markedAsAway=\u00a77Jsi oznacen jako "AFK". +markedAsNotAway=\u00a77Jiz nejsi oznacen jako "AFK". +matchingIPAddress=\u00a76Nasledujici hraci byli prihlaseni z teto IP\: +maxHomes=Nemuzes si nastavit vice nez {0} domovu. +mayNotJail=\u00a7cNesmis uveznit tuto postavu +me=ja +minute=minuta +minutes=minuty +missingItems=\u00a74Nemas \u00a7c{0}x {1}\u00a74. +mobSpawnError=Chyba pri pokusu o zmenu mob spawneru. +mobSpawnLimit=Pocet mobu limitovan serverem. +mobSpawnTarget=Musis se divat na spawner. +mobsAvailable=\u00a77Mobove\: {0} +moneyRecievedFrom=\u00a7a{0} jsi obdrzel od hrace {1} +moneySentTo=\u00a7a{0} bylo odeslano hraci\: {1} +month=mesic +months=mesice +moreThanZero=Mnozstvi musi byt vetsi nez 0. +moveSpeed=\u00a76Nastavena \u00a7c{0} \u00a76rychlost hrace \u00a7c{2} \u00a76na \u00a7c{1}\u00a76. +msgFormat=\u00a76[\u00a7c{0}\u00a76 -> \u00a7c{1}\u00a76] \u00a7r{2} +multipleCharges=\u00a74Nelze pouzit vice jak jeden naboj pro tento ohnostroj. +multiplePotionEffects=\u00a74Nelze pouzit vice jak jeden efekt na tento lektvar. +muteExempt=\u00a7cTohoto hrace nemuzes umlcet. +muteNotify=\u00a76Admin \u00a7c{0} \u00a76umlcel hrace \u00a7c{1}\u00a76. +mutedPlayer=\u00a76Hrac\u00a7c {0} \u00a76byl umlcen. +mutedPlayerFor=\u00a76Hrac\u00a7c {0} \u00a76byl umlcen za\u00a7c {1}\u00a76. +mutedUserSpeaks={0} se pokusil promluvit, ale je umlcen. +nearbyPlayers=Hraci v okoli\: {0} +negativeBalanceError=Hrac nemuze mit zapornou hodnotu uctu. +nickChanged=Nickname zmenen. +nickDisplayName=\u00a77Musis nejdrive povolit change-displayname v Essentials configu. +nickInUse=\u00a7cTento nick jiz nekdo ma. +nickNamesAlpha=\u00a7cNick musi byt alfanumericky. +nickNoMore=\u00a77Uz nemas zadny nick. +nickSet=\u00a76Tvuj nick je nyni \u00a7c{0}\u00a76. +nickTooLong=\u00a74Tento nick je prilis dlouhy. +noAccessCommand=\u00a7cNemas povoleni na tento prikaz. +noAccessPermission=\u00a74Nem\u00e1\u0161 opr\u00e1vn\u011bn\u00ed k tomuto \u00a7c{0}\u00a74. +noBreakBedrock=Nemas opravneni nicit bedrock. +noDestroyPermission=\u00a74Ty nem\u016f\u017ee\u0161 ni\u010dit \u00a7c{0}\u00a74. +noDurability=\u00a7cTento predmet nema zadnou vydrz. +noGodWorldWarning=\u00a7cVarovani\! God-mode je v tomto svete zakazan. +noHelpFound=\u00a7cZadne shodujici prikazy. +noHomeSetPlayer=Hrac nema nastaveny zadny domov. +noIgnored=\u00a76Nikoho neignoruje\u0161. +noKitPermission=\u00a7cPotrebujes \u00a7c{0}\u00a7c permission, aby jsi mohl pouzit tento kit. +noKits=\u00a77Nejsou zadne dostupne kity. +noMail=Nemas zadny mail. +noMatchingPlayers=\u00a76Zadni odpovidajici hraci nebyli nalezeni. +noMetaFirework=\u00a74Nemas opravneni pro nastaveni metadat ohnostroje. +noMetaPerm=\u00a74Nemas opravneni na nastaveni metadat \u00a7c{0}\u00a74 tohoto itemu. +noNewMail=\u00a77Nemas zadny novy mail. +noPendingRequest=Nemas zadne neuzavrene zadosti. +noPerm=\u00a7cNemas \u00a7f{0}\u00a7c permici. +noPermToSpawnMob=\u00a7cNemas povoleni k spawnovani mobu. +noPlacePermission=\u00a7cNemas povoleni pokladat nebo nicit cokoliv blizko teto cedule. +noPotionEffectPerm=\u00a74Nemas opravneni k nastaveni efektu \u00a7c{0} \u00a74tohoto lektvaru. +noPowerTools=Nemas zadny mocny nastroj. +noWarpsDefined=Nejsou nastaveny zadne warpy. +none=zadny +notAllowedToQuestion=\u00a7cNejsi opravnen pouzit otazku. +notAllowedToShout=\u00a7cNejsi opravnen pouzit kriceni. +notEnoughExperience=Nemas dostatek zkusenosti. +notEnoughMoney=Nemas dostatecny financni obnos. +notFlying=neleta +notRecommendedBukkit=* \! * Verze bukkitu neni doporucena pro Essentials. +notSupportedYet=Jeste neni podporovano. +nothingInHand=\u00a7cNedrzis nic v ruce. +now=nyni +nuke=Prsi na tebe smrt \:) +numberRequired=Hlupaku, musis vyplnit cislo. +onlyDayNight=/time podporuje pouze day/night. +onlyPlayerSkulls=\u00a74M\u016f\u017ee nastavit pouze majitel hlavy hr\u00e1\u010de (\u00a7c397\:3\u00a74). +onlyPlayers=\u00a74Jen hraci ve hre muzou pouzit \u00a7c{0}\u00a74. +onlySunStorm=/weather podporuje pouze sun/storm. +orderBalances=Usporadavam bohatstvi {0} hracu, prosim vydrz ... +oversizedTempban=\u00a74Nemuzes potrestat hrace ne tak dlouhou dobu. +pTimeCurrent=\u00a7eCas hrace u00a7f je {1}. //??? +pTimeCurrentFixed=\u00a7eCas hrace {0} u00a7f je nastaven na {1}. +pTimeNormal=\u00a7eCas hrace {0}\u00a7f je normalni a souhlasi s casem serveru. +pTimeOthersPermission=\u00a7cNejsi opravnen menit cizim hracum cas. +pTimePlayers=Tihle hraci maji nastaveny svuj cas\: +pTimeReset=Cas hrace byl obnoven za\: \u00a7e{0} +pTimeSet=Cas hrace je nastaven na \u00a73{0}\u00a7f za\: \u00a7e{1} +pTimeSetFixed=Cas hrace je fixne nastaven na \u00a73{0}\u00a7f za\: \u00a7e{1} +pWeatherCurrent=Pocasi hrace \u00a7c{0} \u00a76bylo nastaveno na\u00a7c {1}\u00a76. +pWeatherInvalidAlias=&4Neplatny typ pocasi +pWeatherNormal=Pocasi hrace \u00a7c{0} \u00a76bylo nastaveno synchronne se serverem. +pWeatherOthersPermission=\u00a74Nemas opravneni nastavovat pocasi ostatnim hracum. +pWeatherPlayers=\u00a76Tito hraci maji sve vlastni pocasi\:\u00a7r +pWeatherReset=\u00a76Hracovo pocasi bylo resetovano na\: \u00a7c{0} +pWeatherSet=\u00a76Pocasi pro hrace \u00a7c{1}\u00a76 bylo nastaveno na\: \u00a7c{0}. +pendingTeleportCancelled=\u00a7cNevyresena zadost o teleportaci byla zrusena. +playerBanIpAddress=\u00a76Player\u00a7c {0} \u00a76banned IP address\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerBanned=\u00a76Hr\u00e1\u010d\u00a7c {0} \u00a76byl potrest\u00e1n\u00a7c {1} \u00a76za \u00a7c{2}\u00a76. +playerInJail=\u00a74Hr\u00e1\u010d u\u017e je ve v\u011bzen\u00ed\u00a7c {0}\u00a74. +playerJailed=\u00a77Hrac {0} byl uveznen. +playerJailedFor=\u00a77Hrac {0} uveznen za {1}. +playerKicked=\u00a7cAdmin {0} vyhodil {1} za {2} +playerMuted=\u00a77Byl jsi umlcen. +playerMutedFor=\u00a77Byl jsi umlcen za {0} +playerNeverOnServer=\u00a7cHrac {0} nebyl nikdy na serveru. +playerNotFound=\u00a7cHrac nenalezen. +playerUnbanIpAddress=\u00a76Hraci\u00a7c {0} \u00a76byla odbanovana IP adresa\: {1}. +playerUnbanned=\u00a76Hrac\u00a7c {0} \u00a76byl odbanovan {1}. +playerUnmuted=\u00a77Byl jsi odmlcen. +pong=Pong\! +posPitch=\u00a76Obzor\: {0} (Roztec vyhledu) +posX=\u00a76X\: {0} (+Vychod <-> -Zapad) +posY=\u00a76Y\: {0} (+Nahoru <-> -Dolu) +posYaw=\u00a76Odchylka\: {0} +posZ=\u00a76Z\: {0} (+Jih <-> -Sever) +possibleWorlds=\u00a76Mozne svety jsou cisla v rozmezi \u00a7c0\u00a76 - \u00a7c{0}\u00a76. +potions=\u00a7 6 \u00a76Lektvary\:\u00a7r {0}. +powerToolAir=Prikaz nemuze byt spojen se vzduchem. +powerToolAlreadySet=\u00a74Prikaz \u00a7c{0}\u00a74 jiz je prirazen \u00a7c{1}\u00a74. +powerToolAttach=\u00a7c{0}\u00a7f prikaz pripsan k {1}. +powerToolClearAll=Vsechny mocne nastroje byli smazany. +powerToolList=Hrac {1} ma tyto prikazy\: \u00a7c{0}\u00a7f. +powerToolListEmpty={0} nema pripsany zadne prikazy. +powerToolNoSuchCommandAssigned=\u00a74Prikaz \u00a7c{0}\u00a74 neni prirazen \u00a7c{1}\u00a74. +powerToolRemove=\u00a76Prikaz \u00a7c{0}\u00a76 odstranen z \u00a7c{1}\u00a76. +powerToolRemoveAll=\u00a76Vsechny prikazy byly odstraneny z \u00a7c{0}\u00a76. +powerToolsDisabled=Vsechny tve mocne nastroje byli zablokovany. +powerToolsEnabled=Vsechny tve mocne nastroje byli povoleny. +questionFormat=\u00a77[Otazka]\u00a7f {0} +readNextPage=Napis /{0} {1} pro precteni dalsi stranky. +recipe=\u00a76Vypis receptu \u00a7c{0}\u00a76 (\u00a7c{1}\u00a76 z \u00a7c{2}\u00a76) +recipeBadIndex=Pro toto cislo neexistuje zadny recept. +recipeFurnace=\u00a76Prepal\: \u00a7 6 \u00a7c {0}. +recipeGrid=\u00a7c{0}X \u00a76| \u00a7{1}X \u00a76| \u00a7{2}X +recipeGridItem=\u00a7c X \u00a76je \u00a7c {0} {1} +recipeMore=\u00a76Pouzij /{0} \u00a7c{1}\u00a76 pro zobrazeni dalsich receptu pro \u00a7c{2}\u00a76. +recipeNone=Zadny recept na {0} neexistuje +recipeNothing=neni +recipeShapeless=\u00a76Zkombinuj \u00a7c{0} +recipeWhere=\u00a76Kde\: {0} +removed=\u00a77Odstraneno {0} entitit. +repair=\u00a76Uspesne jsi opravil tvoji \u00a7c{0}\u00a76. +repairAlreadyFixed=\u00a77Tento item nepotrebuje opravu. +repairEnchanted=\u00a77Nemas opravneni opravovat enchantovane itemy. +repairInvalidType=\u00a7cTento item nemuze byt opraven. +repairNone=\u00a74Nemas zadne itemy, ktere potrebuji opravit. +requestAccepted=\u00a77Zadost o teleport prijata. +requestAcceptedFrom=\u00a77{0} prijal tvou zadost o teleport. +requestDenied=\u00a77Zadost o teleport zamitnuta. +requestDeniedFrom=\u00a77{0} odmitl tvou zadost o teleport. +requestSent=\u00a77Zadost odeslana hraci {0}\u00a77. +requestTimedOut=\u00a7cZadost o teleportaci vyprsela. +requiredBukkit=* \! * Potrebujete minimalne verzi {0} Bukkitu, stahnete si ji z http\://dl.bukkit.org/downloads/craftbukkit/ +resetBal=\u00a76Hotovost vsech online hracu byla resetovana na \u00a7c{0}\u00a76. +resetBalAll=\u00a76Hotovost vsech hracu byla resetovana na \u00a7c{0}\u00a76. +returnPlayerToJailError=\u00a74Nastala chyba pri pokusu navratit hrace \u00a7c{0}\u00a74 do vezeni\: \u00a7c{1}\u00a74\! +runningPlayerMatch=\u00a76Zahajeno hledani odpovidajicich hracu ''\u00a7c{0}\u00a76'' (..muze to chvilku trvat...) +second=sekunda +seconds=sekundy +seenOffline=\u00a76Hrac \u00a7c{0} \u00a76je \u00a74offline\u00a76 od \u00a7c{1}\u00a76. +seenOnline=\u00a76Hrac \u00a7c{0} \u00a76je \u00a7aonline\u00a76 od \u00a7c{1}\u00a76. +serverFull=Server je plny +serverTotal=Maximum serveru\: {0} +setBal=\u00a7aTva hotovost byla nastavena na {0}. +setBalOthers=\u00a7aHotovost hrace {0}\u00a7a nastavena na {1}. +setSpawner=\u00a76Typ spawneru zmenen na\u00a7c {0}\u00a76. +sheepMalformedColor=Deformovana barva. +shoutFormat=\u00a77[Shout]\u00a7f {0} +signFormatFail=\u00a74[{0}] +signFormatSuccess=\u00a71[{0}] +signFormatTemplate=[{0}] +signProtectInvalidLocation=\u00a74Nemas opravneni zde vytvaret cedule. +similarWarpExist=Warp s podobnym nebo stejnym jmenem jiz existuje. +slimeMalformedSize=Zdeformovana velikost. +socialSpy=\u00a76SocialSpy hrace \u00a7c{0}\u00a76\: \u00a7c{1} +soloMob=Tento mob ma rad, kdyz je sam. +spawnSet=\u00a77Spawn-lokace nastavena pro skupinu\: {0}. +spawned=spawnut +sudoExempt=Nemuzes ovladat tohoto hrace +sudoRun=\u00a76Forcing\u00a7c {0} \u00a76to run\:\u00a7r /{1} +suicideMessage=\u00a77Sbohem kruty svete... +suicideSuccess=\u00a77{0} si vzal svuj zivot +survival=Survival +takenFromAccount=\u00a7c{0} bylo odecteno z tveho uctu. +takenFromOthersAccount=\u00a7c{0} bylo odebrano z {1}\u00a7c uctu. Nova hodnota\: {2} +teleportAAll=\u00a77Zadost o teleportaci odeslana vsem hracum... +teleportAll=\u00a77Teleportuji v\u00c5\u00a1echny hrace... +teleportAtoB=\u00a7c{0} \u00a76te teleportoval k hraci \u00a7c{1}\u00a76. +teleportDisabled={0} mas teleportaci zablokovanou. +teleportHereRequest=\u00a7c{0}\u00a7c vas pozadal aby jste se warpnul k nemu. +teleportNewPlayerError=Teleportace noveho hrace selhala +teleportRequest=\u00a7c{0}\u00a7c se chce teleportovat k tobe. +teleportRequestTimeoutInfo=\u00a77Tato zadost vyprsi za {0} sekund. +teleportTop=\u00a77Teleportuji na vrch. +teleportationCommencing=\u00a77Teleportace zahajena... +teleportationDisabled=\u00a76Teleportace \u00a74vypnuta\u00a76. +teleportationDisabledFor=\u00a76Teleportace \u00a74vypnuta\u00a76 hraci \u00a7c{0}\u00a76. +teleportationEnabled=\u00a76Teleportace \u00a7azapnuta\u00a76. +teleportationEnabledFor=\u00a76Teleportace \u00a7azapnuta\u00a76 hraci \u00a7c{0}\u00a76. +teleporting=\u00a77Teleportuji... +teleportToPlayer=\u00a76Teleportuji k hraci \u00a7c{0}\u00a76. +tempBanned=\u00a7cYou have been temporarily banned for {0}\:\n\u00a7r{2} +tempbanExempt=\u00a77Nemel by jsi docasne zabanovat tohoto hrace. +thunder=Nastavil jsi {0} bouri ve tvem svete. +thunderDuration=Nastavil jsi {0} bouri ve svete po {1} sekund. +timeBeforeHeal=Potrebny cas pro dalsi uzdraveni\: {0} +timeBeforeTeleport=Potrebny cas pro dalsi teleport\: {0} +timeFormat=\u00a7c{0}\u00a76 nebo \u00a7c{1}\u00a76 nebo \u00a7c{2}\u00a76 +timeSetPermission=\u00a7cNejsi autorizovany ke zmene casu. +timeWorldCurrent=Ve svete {0} je prave \u00a73{1} +timeWorldSet=Cas byl nastaven na {0} ve\: \u00a7c{1} +totalWorthAll=\u00a7aProdal jsi vsechny veci a kostky ve svem inventari za celkovou cenu {1}. +totalWorthBlocks=\u00a7aProdal jsi vsechny kostky ve svem inventari za celkovou cenu {1}. +tps=Momentalni TPS \= {0} +tradeSignEmpty=Tato cedule jiz nema dostupny material na vymenu. +tradeSignEmptyOwner=Na teto ceduli dosel material. +treeFailure=\u00a7cNepodarilo se vytvorit strom. Zkus to znovu na trave nebo hline. +treeSpawned=\u00a77Strom vytvoren. +true=\u00a72Ano\u00a7f +typeTpaccept=\u00a77Pro prijmuti zadosti napis \u00a7c/tpaccept\u00a77. +typeTpdeny=\u00a77Pokud chces odmitnout zadost napis \u00a7c/tpdeny\u00a77. +typeWorldName=\u00a77Muzes take napsat specificky nazev sveta. +unableToSpawnMob=Nemozne spawnout moba. +unignorePlayer=Prestal jsi ignorovat hrace {0}. +unknownItemId=Nezname ID itemu\: {0} +unknownItemInList=Neznamy item {0} v {1} seznamu. +unknownItemName=Neznamy nazev itemu\: {0} +unlimitedItemPermission=\u00a74Nemas prava mit neomezeny item \u00a7c{0}\u00a74. +unlimitedItems=Neomezene itemy\: +unmutedPlayer=Hrac {0} byl umlcen. +unvanishedReload=\u00a74Probehl reload serveru; jsi zase viditelny. +upgradingFilesError=Chyba pri updatovani souboru. +uptime=\u00a76Server je online\:\u00a7c {0} +userAFK=\u00a77{0} \u00a75je nyni AFK a mozna nebude reagovat. +userDoesNotExist=Uzivatel {0} neexistuje. +userIsAway={0} je AFK. +userIsNotAway={0} se vratil. +userJailed=\u00a77Byl jsi uveznen. +userUnknown=\u00a74Pozor\: Hrac ''\u00a7c{0}\u00a74'' se jeste nikdy nepripojil na tento server. +userdataMoveBackError=Chyba pri pokusu o presun userdata/{0}.tmp do userdata/{1} +userdataMoveError=Chyba pri pokusu o presun userdata/{0} do userdata/{1}.tmp +usingTempFolderForTesting=Pouzivam docasnou slozku pro testovani\: +vanished=\u00a7aZneviditil jsi se. +versionMismatch=Chyba verzi\! Prosim updatuj {0} na stejnou verzi. +versionMismatchAll=Chyba verzi\! Prosim, updatuj vsechny Essentials .jar na stejnou verzi. +voiceSilenced=\u00a77Byl jsi ztisen. +walking=chuze +warpDeleteError=Vyskytl se problem pri mazani warpu. +warpList={0} +warpListPermission=\u00a7cNemas opravneni listovat warpami. +warpNotExist=Tento warp neexistuje. +warpOverwrite=\u00a7cNemuzes prepsat tento warp. +warpSet=\u00a77Warp {0} vytvoren. +warpUsePermission=\u00a7cNemas opravneni pouzit tento warp. +warpingTo=\u00a77Warpuji te do {0}. +warps=Warpy\: {0} +warpsCount=\u00a76Je zde \u00a7c{0} \u00a76warpu. Zobrazuji stranku \u00a7c{1} \u00a76of \u00a7c{2}\u00a76. +weatherStorm=\u00a77Nastavil jsi bourku v {0} +weatherStormFor=\u00a77Nastavil jsi bourku v {0} na {1} sekund. +weatherSun=\u00a77Nastavil jsi slunecne pocasi v {0} +weatherSunFor=\u00a77Nastavil jsi slunecne pocasi v {0} na {1} sekund +whoisAFK=\u00a76 - AFK\:\u00a7f {0} +whoisBanned=\u00a76 - Zabanovan\:\u00a7f {0} +whoisExp=\u00a76 - Exp\:\u00a7f {0} (Uroven {1}) +whoisFly=\u00a76 - Letani\:\u00a7f {0} ({1}) +whoisGamemode=\u00a76 - Herni mod\:\u00a7f {0} +whoisGeoLocation=\u00a76 - Puvod\:\u00a7f {0} +whoisGod=\u00a76 - God mode\:\u00a7f {0} +whoisHealth=\u00a76 - Zdravi\:\u00a7f {0}/20 +whoisIPAddress=\u00a76 - IP Adresa\:\u00a7f {0} +whoisJail=\u00a76 - Jail\:\u00a7f {0} +whoisLocation=\u00a76 - Pozice\:\u00a7f ({0}, {1}, {2}, {3}) +whoisMoney=\u00a76 - Penize\:\u00a7f {0} +whoisMuted=\u00a76 - Umlcen\:\u00a7f {0} +whoisNick=\u00a76 - Nick\:\u00a7f {0} +whoisOp=\u00a76 - OP\:\u00a7f {0} +whoisTop=\u00a76 \=\=\=\=\=\= WhoIs\:\u00a7c {0} \u00a76\=\=\=\=\=\= +worth=\u00a77Stack {0} ceny \u00a7c{1}\u00a77 ({2} kus(u) za {3} kus) +worthMeta=\u00a77Stack {0} s metadaty {1} ceny \u00a7c{2}\u00a77 ({3} kus(u) za {4} kus) +worthSet=Hodnota ceny nastavena +year=rok +years=roky +youAreHealed=\u00a77Byl jsi uzdraven. +youHaveNewMail=\u00a7cMas {0} zprav\!\u00a7f Napis \u00a77/mail read\u00a7f aby jsi si precetl sve zpravy. +whoisHunger=\u00a76 - Hlad\:\u00a7r {0}/20 (+{1} saturation) +kitDelay=\u00a7m{0}\u00a7r +giveSpawnFailure=\u00a74neni dost mista, \u00a7c{0} \u00a7c{1} \u00a74bylo ztraceno. +noKitGroup=\u00a74Nemas opravneni na tento kit. +inventoryClearingFromAll=\u00a76Cistim inventare vsech harcu... +inventoryClearingAllItems=\u00a76Ze vsech inventaru byl odebran item {0}\u00a76. +inventoryClearingAllArmor=\u00a76Odebrany vsechny polozky inventare a brnerni {0}\u00a76. +inventoryClearingAllStack=\u00a76Odebrano vse\u00a7c {0} \u00a76z {1}\u00a76. +inventoryClearingStack=\u00a76Odstraneno\u00a7c {0}\u00a7cz {1} \u00a76od {2}\u00a76. +inventoryClearFail=\u00a74Hrac {0} \u00a74nema\u00a7c {1} \u00a74z\u00a7c {2}\u00a74. +localNoOne= +totalSellableAll=\u00a7aCelkova cena vsech prodejnych itemu a bloku je \u00a7c{1}\u00a7a. +totalSellableBlocks=\u00a7aCelkova cena vsech prodejnych bloku je \u00a7c{1}\u00a7a. +radiusTooBig=\u00a74Polomer je prilis velky. Maximalni mozny polomer je {0} bloku. +isIpBanned=\u00a76IP \u00a7c{0} \u00a76je zabanovana. +mobDataList=\u00a76Spravny nazev mobu\:\u00a7r {0} +vanish=\u00a76Vanish pro hrace {0} je\u00a76\: {1} +noLocationFound=\u00a74Nebylo nalezeno platne umisteni. +coordsKeyword={0}, {1}, {2} +banExemptOffline=\u00a74Nemuzes zabanovat hrace ktery neni ve hre. +tempbanExemptOffline=\u00a74Nemuzes docasne zabanovat hrace ktery neni ve hre. +mayNotJailOffline=\u00a7Nemuzes uveznit hrace, kteri nejsou pripojeni. +muteExemptOffline=\u00a7Nemuzes umlcet hrace ktery neni ve hre. +ignoreExempt=\u00a74Nemuzes ignorovat tohoto hrace. +unsafeTeleportDestination=\u00a74Teleportace zde je nebezpecna a nastaveni teleport-safety je vypnuto. +noMetaJson=JSON Metadata nejsou podporovana v teto verzi Bukkitu. +maxMoney=\u00a74Tato transakce by prekrocila financni limit tohoto uctu. +skullChanged=\u00a76Hlava zmenena na \u00a7c{0}\u00a76. +alphaNames=\u00a74Nick muze obsahovat pouze pismena, cisla a podtrzitka +givenSkull=\u00a76Ziskal si hlavu hrace \u00a7c{0}\u00a76. +noPermissionSkull=\u00a74Nemas prava na upravu teto hlavy. +teleportInvalidLocation=Souradnice nemohou prekrocit 30 000 000 +invalidSkull=\u00a74Vem si hlavu nejprve do ruky. +weatherInvalidWorld=Svet s nazvem {0} nebyl nalezen\! +gameModeInvalid=\u00a74Chybny nick hrace nebo herni mod. +mailTooLong=\u00a74Mailov\u00e1 zpr\u00e1va je velmi dlouh\u00e1. Limit je pod 1000 znak\u016f. +mailDelay=Bylo odeslano prilis mnoho mailu. Pockej minutu. Maximum\: {0} +seenAccounts=\u00a76Hrac je take znamy jako\:\u00a7c {0} +unableToSpawnItem=\u00a74Nepodarilo se spawnout \u00a7c{0}\u00a74, nejedna se o item, ktery jde spawnout. +itemsConverted=\u00a76Converted all items into blocks. +itemsNotConverted=\u00a74You have no items that can be converted into blocks. +mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\: +mailMessage={0} + +whoisTempBanned=\u00a76 - Ban expires:\u00a7r {0} +playerTempBanned=\u00a76Player \u00a7c{0}\u00a76 temporarily banned \u00a7c{1}\u00a76 for \u00a7c{2}\u00a76: \u00a7c{3}\u00a76. +mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1} diff --git a/Essentials/src/messages_da.properties b/Essentials/src/messages_da.properties new file mode 100644 index 0000000000..86a5ef345c --- /dev/null +++ b/Essentials/src/messages_da.properties @@ -0,0 +1,558 @@ +#X-Generator: crowdin.net +#version: TeamCity +# Single quotes have to be doubled: '' +# Translations start here +# by: +action=\u00a75* {0} \u00a75{1} +addedToAccount=\u00a7a{0} er blevet tilf\u00f8jet til din konto. +addedToOthersAccount=\u00a7a{0} tilf\u00f8jet til {1}\u00a7a konto. Ny saldo\: {2} +adventure=eventyr +alertBroke=\u00f8delagde\: +alertFormat=\u00a73[{0}] \u00a7r {1} \u00a76 {2} ved\: {3} +alertPlaced=placerede\: +alertUsed=brugte\: +antiBuildBreak=\u00a74Du har ikke tilladelse til at s\u00e6tte\u00a7c {0} \u00a74blocks her. +antiBuildCraft=\u00a74Du har ikke tilladelse til at lave\u00a7c {0}\u00a74. +antiBuildDrop=\u00a74Du har ikke tilladelse til at smide\u00a7c {0}\u00a74. +antiBuildInteract=\u00a74Du har ikke tilladelse til at interagere med\u00a7c {0}\u00a74. +antiBuildPlace=\u00a74Du har ikke tilladelse til at s\u00e6tte\u00a7c {0} \u00a74her. +antiBuildUse=\u00a74Du har ikke tilladelse til at bruge\u00a7c {0}\u00a74. +autoAfkKickReason=Du er blevet smidt ud, fordi du har v\u00e6ret inaktiv i mere end {0} minutter. +backAfterDeath=\u00a76Brug /back kommandoen for at vende tilbage til der hvor du d\u00f8de. +backUsageMsg=\u00a76Retunerer til tidligere lokation. +backupDisabled=\u00a74Et eksternt backup-script er ikke konfigureret. +backupFinished=\u00a76Backup afsluttet. +backupStarted=\u00a76Backup startet. +balance=\u00a7aSaldo\:\u00a7c {0} +balanceOther=\u00a7aSaldo for {0}\u00a7a\:\u00a7c {1} +balanceTop=\u00a76Top saldi ({0}) +banExempt=\u00a74Du kan ikke bandlyse den spiller. +banFormat=\u00a74Bandlyst\:\n\u00a7r{0} +bed=\u00a7obed\u00a7r +bedMissing=\u00a74Din seng er enten ikke sat, mangler eller ogs\u00e5 er den blokeret. +bedNull=\u00a7mbed\u00a7r +bedSet=\u00a76Seng-spawn er sat\! +bigTreeFailure=\u00a74Fejl under generering af stort tr\u00e6. Pr\u00f8v igen p\u00e5 gr\u00e6s eller jord. +bigTreeSuccess=\u00a76Stort tr\u00e6 spawnet. +blockList=\u00a76Essentials videregav de f\u00f8lgende kommandoer til et andet plugin\: +bookAuthorSet=\u00a76Bogens forfatter er \u00e6ndret til {0}. +bookLocked=\u00a76Denne bog er nu l\u00e5st. +bookTitleSet=\u00a76Bogens titel er \u00e6ndret til {0}. +broadcast=\u00a7r\u00a76[\u00a74Meddelelse\u00a76]\u00a7a {0} +buildAlert=\u00a74Du har ikke rettigheder til at bygge. +bukkitFormatChanged=Bukkit versionsformat er \u00e6ndret. Versionen er ikke checket. +burnMsg=\u00a76Du satte ild til\u00a7c {0} \u00a76 i \u00a7c {1} sekunder\u00a76. +canTalkAgain=\u00a76Du kan nu tale igen. +cannotStackMob=\u00a74Du har ikke tilladelse til at stable flere mobs. +cantFindGeoIpDB=Kan ikke finde GeoIP databasen\! +cantReadGeoIpDB=Fejl ved l\u00e6sning af GeoIP databasen\! +cantSpawnItem=\u00a74Du har ikke tilladelse til at spawne denne ting\u00a7c {0}\u00a74. +chatTypeAdmin=[A] +chatTypeLocal=[L] +chatTypeSpy=[Spion] +cleaned=Brugerfiler blev renset. +cleaning=Renser brugerfiler. +commandFailed=Kommando {0} fejlede\: +commandHelpFailedForPlugin=Fejl ved hentning af hj\u00e6lp til pluginnet\: {0} +commandNotLoaded=\u00a74Kommandoen {0} er indl\u00e6st forkert. +compassBearing=\u00a76Pejling\: {0} ({1} grader). +configFileMoveError=Kunne ikke flytte config.yml til backup-lokation. +configFileRenameError=Kunne ikke omd\u00f8be midlertidig fil til config.yml. +connectedPlayers=\u00a76Tilsluttede spillere\u00a7r +connectionFailed=Kunne ikke \u00e5bne forbindelse. +cooldownWithMessage=\u00a74Cooldown\: {0} +corruptNodeInConfig=\u00a74Notice\: Din konfigurationsfil har en korrupt {0} node. +couldNotFindTemplate=\u00a74Kunne ikke finde skabelon {0} +creatingConfigFromTemplate=Opretter konfig fra skabelon\: {0} +creatingEmptyConfig=Opretter tom konfig\: {0} +creative=kreativ +currency={0}{1} +currentWorld=\u00a76Nuv\u00e6rende Verden\:\u00a7c {0} +day=dag +days=dage +defaultBanReason=Banhammeren har talt\! +deleteFileError=Kunne ikke slette filen\: {0} +deleteHome=\u00a76Hjemmet\u00a7c {0} \u00a76er blevet fjernet. +deleteJail=\u00a76F\u00e6ngslet\u00a7c {0} \u00a76er blevet fjernet. +deleteWarp=\u00a76Warp\u00a7c {0} \u00a76er blevet fjernet. +deniedAccessCommand=\u00a7c{0} \u00a74blev n\u00e6gtet adgang til kommandoen. +denyBookEdit=\u00a74Du kan ikke l\u00e5se denne bog op. +denyChangeAuthor=\u00a74Du kan ikke \u00e6ndre denne bogs forfatter. +denyChangeTitle=\u00a74Du kan ikke \u00e6ndre denne bogs titel. +depth=\u00a76Du er ved havets overflade. +depthAboveSea=\u00a76Du er\u00a7c {0} \u00a76blok(ke) over havets overflade. +depthBelowSea=\u00a76Du er\u00a7c {0} \u00a76blok(ke) under havets overflade. +destinationNotSet=Destination er ikke sat\! +disableUnlimited=\u00a76Deaktiverede ubegr\u00e6nset placering af\u00a7c {0} \u00a76i {1}. +disabled=deaktiveret +disabledToSpawnMob=\u00a74Spawning af dette mob er deaktiveret i konfigurationsfilen. +distance=\u00a76Afstand\: {0} +dontMoveMessage=\u00a76Teleportering vil begynde om\u00a7c {0}\u00a76. Bliv st\u00e5ende. +downloadingGeoIp=Downloader GeoIP database... dette tager m\u00e5ske noget tid (land\: 0.6 MB, by\: 20MB) +duplicatedUserdata=Duplikerede brugerdata\: {0} og {1}. +durability=\u00a76Dette v\u00e6rkt\u00f8j har \u00a7c{0}\u00a76 anvendelser tilbage. +editBookContents=\u00a7eDu kan nu \u00e6ndre denne bogs indhold. +enableUnlimited=\u00a76Giver et ubegr\u00e6nset antal af\u00a7c {0} \u00a76til \u00a7c{1}\u00a76. +enabled=aktiveret +enchantmentApplied=\u00a76Fortryllelsen\u00a7c {0} \u00a76er blevet anvendt til elementet i din h\u00e5nd. +enchantmentNotFound=\u00a74Fortryllelsen blev ikke fundet\! +enchantmentPerm=\u00a74Du har ikke tilladelse til\u00a7c {0}\u00a74. +enchantmentRemoved=\u00a76Fortryllelsen\u00a7c {0} \u00a76er blevet fjernet fra elementet i din h\u00e5nd. +enchantments=\u00a76Fortryllelser\:\u00a7r {0} +errorCallingCommand=Kunne ikke finde kommandoen /{0} +errorWithMessage=\u00a7cFejl\:\u00a74 {0} +essentialsHelp1=Filen er \u00f8delagt, og Essentials kan ikke \u00e5bne den. Essentials er nu deaktiveret. Hvis du ikke selv kan fikse fejlen, s\u00e5 bes\u00f8g http\://tiny.cc/EssentialsChat +essentialsHelp2=Filen er \u00f8delagt, og Essentials kan ikke \u00e5bne den. Essentials er nu deaktiveret. Hvis du ikke selv kan fikse fejlen, s\u00e5 skriv enten /essentialshelp i spillet eller bes\u00f8g http\://tiny.cc/EssentialsChat +essentialsReload=\u00a76Essentials blev genindl\u00e6st\u00a7c {0}. +exp=\u00a7c{0} \u00a76har\u00a7c {1} \u00a76exp (level\u00a7c {2}\u00a76) og beh\u00f8ver\u00a7c {3} \u00a76mere exp for at stige i level. +expSet=\u00a7c{0} \u00a76har nu\u00a7c {1} \u00a76exp. +extinguish=\u00a76Du slukkede selv. +extinguishOthers=\u00a76Du slukkede {0}\u00a76. +failedToCloseConfig=Kunne ikke lukke konfig {0}. +failedToCreateConfig=Kunne ikke oprette konfig {0}. +failedToWriteConfig=Kunne ikke skrive konfig {0}. +false=\u00a74falsk\u00a7r +feed=\u00a76Din appetit blev m\u00e6ttet. +feedOther=\u00a76Du tilfredsstillede \u00a7c{0}s appetit\u00a76. +fileRenameError=Omd\u00f8bning af filen {0} fejlede\! +fireworkColor=\u00a74Ugyldig fyrv\u00e6rkeriladningsparametre indsat. Der skal s\u00e6ttes en farve f\u00f8rst. +fireworkEffectsCleared=\u00a76Fjernede alle effekter fra den holdte stak. +fireworkSyntax=\u00a76Fyrv\u00e6rkeri-parametre\:\u00a7c color\: [fade\:] [shape\:
] [effect\:]\n\u00a76For at bruge flere farver/effekter, separate da v\u00e6rdierne med kommaer\: \u00a7cred,blue,pink\n\u00a76Former\:\u00a7c star, ball, large, creeper, burst \u00a76Effekter\:\u00a7c trail, twinkle. +flyMode=\u00a76Set flytilstand \u00a7c {0} \u00a76for {1}\u00a76. +flying=flyve +foreverAlone=\u00a74Der er ingen, du kan sende et svar til. +fullStack=\u00a74Du har allerede en fuld stak. +gameMode=\u00a76\u00c6ndrede spiltilstand til\u00a7c {0} \u00a76for \u00a7c{1}\u00a76. +gcWorld=\u00a76{0} "\u00a7c{1}\u00a76"\: \u00a7c{2}\u00a76 chunks, \u00a7c{3}\u00a76 enheder, \u00a7c{4}\u00a76 tiles. +gcfree=\u00a76Fri hukommelse\:\u00a7c {0} MB. +gcmax=\u00a76Maksimum hukommelse\:\u00a7c {0} MB. +gctotal=\u00a76Allokeret hukommelse\:\u00a7c {0} MB. +geoIpUrlEmpty=GeoIP download url er tom. +geoIpUrlInvalid=GeoIP download url er ugyldig. +geoipJoinFormat=\u00a76Spilleren \u00a7c{0} \u00a76kommer fra \u00a7c{1}\u00a76. +giveSpawn=\u00a76Giver\u00a7c {0} \u00a76af\u00a7c {1} til\u00a7c {2}\u00a76. +godDisabledFor=\u00a7cdeaktiveret\u00a76 for\u00a7c {0} +godEnabledFor=\u00a7aaktiveret\u00a76 for\u00a7c {0} +godMode=\u00a76Gudetilstand\u00a7c {0}\u00a76. +groupDoesNotExist=\u00a74Der er ingen online i denne gruppe\! +groupNumber=\u00a7c{0}\u00a7f online, for at se komplet liste\:\u00a7c /{1} {2} +hatArmor=\u00a74Du kan ikke bruge dette element som hat\! +hatEmpty=\u00a74Du b\u00e6rer ikke en hat. +hatFail=\u00a74Du skal have noget at b\u00e6re i din h\u00e5nd. +hatPlaced=\u00a76Nyd din nye hat\! +hatRemoved=\u00a76Din hat er blevet fjernet. +haveBeenReleased=\u00a76Du er blevet frigjort. +heal=\u00a76Du er blevet helbredt. +healDead=\u00a74Du kan ikke helbrede nogen, som er d\u00f8d\! +healOther=\u00a76Helbredt\u00a7c {0}\u00a76. +helpConsole=For at se hj\u00e6lp fra konsollen, skriv ?. +helpFrom=\u00a76Kommandoer fra {0}\: +helpLine=\u00a76/{0}\u00a7r\: {1} +helpMatching=\u00a76Kommandoer, der matcher "\u00a7c{0}\u00a76"\: +helpOp=\u00a74[Hj\u00e6lpeOp]\u00a7r \u00a76{0}\:\u00a7r {1} +helpPlugin=\u00a74{0}\u00a7r\: Pluginhj\u00e6lp\: /help {1} +holdBook=\u00a74Du holder ikke en skrivbar bog. +holdFirework=\u00a74Du skal have noget fyrv\u00e6rkeri i din h\u00e5nd for at tilf\u00f8je effekter til det. +holdPotion=\u00a74Du skal have en eliksir i din h\u00e5nd for at tilf\u00f8je effekter til den. +holeInFloor=\u00a74Hul i gulvet\! +homeSet=\u00a76Dit hjem blev sat. +homes=\u00a76Dine hjem\:\u00a7r {0} +hour=time +hours=timer +ignoredList=\u00a76Ignorerede\:\u00a7r {0} +ignorePlayer=\u00a76Du ignorerer spilleren\u00a7c {0} \u00a76fra nu af. +illegalDate=Illegalt datoformat. +infoChapter=\u00a76V\u00e6lg kapitel\: +infoChapterPages=\u00a7e ---- \u00a76{0} \u00a7e--\u00a76 Side \u00a7c{1}\u00a76 af \u00a7c{2} \u00a7e---- +infoPages=\u00a7e ---- \u00a76{2} \u00a7e--\u00a76 Side \u00a7c{0}\u00a76/\u00a7c{1} \u00a7e---- +infoUnknownChapter=\u00a74Ukendt kapitel. +insufficientFunds=\u00a74Ikke tilstr\u00e6kkelige midler. +invalidCharge=\u00a74Ugyldig ladning. +invalidFireworkFormat=\u00a74Muligheden \u00a7c{0} \u00a74er ikke en gyldig v\u00e6rdi til \u00a7c{1}\u00a74. +invalidHome=\u00a74Hjemmet\u00a7c {0} \u00a74eksisterer ikke\! +invalidHomeName=\u00a74Ugyldigt navn til dit hjem. +invalidMob=\u00a74Ugyldig mob type. +invalidNumber=Ugyldigt nummer. +invalidPotion=\u00a74Ugyldig eliksir. +invalidPotionMeta=\u00a74Ugyldig eliksir meta\: \u00a7c{0}\u00a74. +invalidSignLine=\u00a74Linje\u00a7c {0} \u00a74p\u00e5 skiltet er ugyldig. +invalidWarpName=\u00a74Ugyldigt warp navn. +invalidWorld=\u00a74Ugyldig verden. +is=er +itemCannotBeSold=\u00a74Det element kan ikke s\u00e6lges til serveren. +itemMustBeStacked=\u00a74Elementet skal forhandles i form at stakke. En m\u00e6ngde af 2s vil v\u00e6re 2 stakke, osv. +itemNames=\u00a76Elementforkortelser\:\u00a7r {0} +itemNotEnough1=\u00a74Du har ikke nok af det element til at s\u00e6lge det. +itemNotEnough2=\u00a76Hvis du vil s\u00e6lge alle dine elementer af den type, s\u00e5 skriv /sell elementnavn. +itemNotEnough3=\u00a76/sell elementnavn -1 vil s\u00e6lge alle elementer med undtagelse af \u00e9n, osv. +itemSellAir=Pr\u00f8vede du virkeligt at s\u00e6lge luft? L\u00e6g et element i din h\u00e5nd. +itemSold=\u00a7aSolgt for \u00a7c{0} \u00a7a({1} {2} for {3} hver). +itemSoldConsole=\u00a7a{0} \u00a7asolgt {1} for \u00a7a{2} \u00a7a({3} elementer for {4} hver). +itemSpawn=\u00a76Giver\u00a7c {0} \u00a76af\u00a7c {1} +itemType=\u00a76Element\:\u00a7c {0} \u00a76-\u00a7c {1} +itemsCsvNotLoaded=Kunne ikke l\u00e6se items.csv\! +jailAlreadyIncarcerated=\u00a74Spilleren er allerede i f\u00e6ngsel\:\u00a7c {0} +jailMessage=\u00a7cDu bryder reglerne, du tager straffen. +jailNotExist=\u00a74Det f\u00e6ngsel eksisterer ikke. +jailReleased=\u00a76Spilleren \u00a7c{0}\u00a76 er fjernet fra f\u00e6ngslet. +jailReleasedPlayerNotify=\u00a76Du er blevet frigjort\! +jailSentenceExtended=\u00a76F\u00e6ndselstid forl\u00e6nges til\: {0} +jailSet=\u00a76F\u00e6ngslet\u00a7c {0} \u00a76er sat. +jumpError=\u00a74Det ville s\u00e5re din computers hjerne. +kickDefault=Smidt ud fra serveren. +kickExempt=\u00a74Du kan ikke smide den person ud. +kickedAll=\u00a74Smed alle ud fra serveren. +kill=\u00a76Dr\u00e6bte\u00a7c {0}\u00a76. +killExempt=\u00a74Du kan ikke dr\u00e6be \u00a7c{0}\u00a74. +kitCost=\ \u00a77\u00a7o({0})\u00a7r +kitError2=\u00a74Det kit er ikke defineret korrekt. Kontakt en administrator. +kitError=\u00a74Der er ingen gyldige kits. +kitGiveTo=\u00a76Giver kit\u00a7c {0}\u00a76 til \u00a7c{1}\u00a76. +kitInvFull=\u00a7cDin inventory er fuld, placerer kit p\u00e5 gulvet. +kitNotFound=\u00a74Det kit eksisterer ikke. +kitOnce=\u00a74Du kan ikke benytte dig af det kit igen. +kitReceive=\u00a76Modtog kittet\u00a7c {0}\u00a76. +kitTimed=\u00a74Du kan ikke benytte dig af det kit igen f\u00f8r om\u00a7c {0}\u00a74. +kits=\u00a76Kits\:\u00a7r {0} +leatherSyntax=\u00a76L\u00e6derfarve Syntaks\: color\:,, Eksempel\: color\:255,0,0. +lightningSmited=\u00a76Thi er blevet ramt af lynet\! +lightningUse=\u00a76Rammer\u00a7c {0} \u00a76med lyn. +listAfkTag=\u00a77[AFK]\u00a7r +listAmount=\u00a76Der er \u00a7c{0}\u00a76 ud af maksimum \u00a7c{1}\u00a76 spillere online. +listAmountHidden=\u00a76Der er \u00a7c{0}\u00a76/{1}\u00a76 ud af maksimum \u00a7c{2}\u00a76 spillere online. +listGroupTag=\u00a76{0}\u00a7r\: \u00a7r +listHiddenTag=\u00a77[SKJULT]\u00a7r +loadWarpError=\u00a74Kunne ikke indl\u00e6se warp {0}. +localFormat=[L]<{0}> {1} +mailClear=\u00a76For at markere alt post som l\u00e6st, skriv\u00a7c /mail clear\u00a76. +mailCleared=\u00a76Mail Ryddet\! +mailSent=\u00a76Mail sendt\! +markMailAsRead=\u00a76For at markere alt post som l\u00e6st, skriv\u00a7c /mail clear\u00a76. +markedAsAway=\u00a76Du er nu markeret som v\u00e6rende v\u00e6k. +markedAsNotAway=\u00a76Du er ikke l\u00e6ngere markeret som v\u00e6rende v\u00e6k. +matchingIPAddress=\u00a76De f\u00f8lgende spillere er tidligere logget ind fra den IP adresse\: +maxHomes=\u00a74Du kan ikke lave mere end\u00a7c {0} \u00a74hjem. +mayNotJail=\u00a74Du kan ikke s\u00e6tte den person i f\u00e6ngsel\! +me=mig +minute=minut +minutes=minutter +missingItems=\u00a74Du har ikke \u00a7c{0}x {1}\u00a74. +mobSpawnError=\u00a74Fejl under \u00e6ndring af mob spawner. +mobSpawnLimit=Mob m\u00e6ngde begr\u00e6nset til serverens gr\u00e6nse. +mobSpawnTarget=\u00a74M\u00e5lblokken skal v\u00e6re en mob spawner. +mobsAvailable=\u00a76Mobs\:\u00a7r {0} +moneyRecievedFrom=\u00a7a{0} er modtaget fra {1}. +moneySentTo=\u00a7a{0} er blevet sendt til {1}. +month=m\u00e5ned +months=m\u00e5neder +moreThanZero=\u00a74M\u00e6ngder skal v\u00e6re st\u00f8rre end 0. +moveSpeed=\u00a76Satte {0} hastighed til\u00a7c {1} \u00a76for \u00a7c{2}\u00a76. +msgFormat=\u00a76[\u00a7c{0}\u00a76 -> \u00a7c{1}\u00a76] \u00a7r{2} +multipleCharges=\u00a74Du kan ikke tilf\u00f8je mere end \u00e9n ladning til dette fyrv\u00e6rkeri. +multiplePotionEffects=\u00a74Du kan ikke tilf\u00f8je mere end \u00e9n effekt til denne eliksir. +muteExempt=\u00a74Du kan ikke g\u00f8re den spiller tavs. +muteNotify=\u00a7c{0} \u00a76har gjort \u00a7c{1}\u00a76 tavs. +mutedPlayer=\u00a76Spilleren\u00a7c {0} \u00a76 er gjort tavs. +mutedPlayerFor=\u00a76Spilleren\u00a7c {0} \u00a76blev gjort tavs i\u00a7c {1}\u00a76. +mutedUserSpeaks={0} pr\u00f8vede at tale, men er gjort tavs. +nearbyPlayers=\u00a76Spillere i n\u00e6rheden\:\u00a7r {0} +negativeBalanceError=\u00a74Brugeren er ikke tilladt at have en negativ saldo. +nickChanged=\u00a76Kaldenavn \u00e6ndret. +nickDisplayName=\u00a74Du skal aktivere change-displayname i Essentials-konfiggen. +nickInUse=\u00a74Det navn bruges allerede. +nickNamesAlpha=\u00a74Kaldenavne skal v\u00e6re alfanumeriske. +nickNoMore=\u00a76Du har ikke l\u00e6ngere et kaldenavn. +nickSet=\u00a76Dit kaldenavn er nu \u00a7c{0}\u00a76. +nickTooLong=\u00a74Det kaldenavn er for langt. +noAccessCommand=\u00a74Du har ikke adgang til den kommando. +noAccessPermission=\u00a74Du har ikke tilladelse til at bruge den \u00a7c{0}\u00a74. +noBreakBedrock=\u00a74Du er ikke tilladt at \u00f8del\u00e6gge bedrock. +noDestroyPermission=\u00a74Du har ikke tilladelse til at \u00f8del\u00e6gge den \u00a7c{0}\u00a74. +noDurability=\u00a74Dette element har ingen holdbarhed. +noGodWorldWarning=\u00a74Advarsel\! Gud-tilstand er deaktiveret i denne verden. +noHelpFound=\u00a74Ingen matchende kommandoer. +noHomeSetPlayer=\u00a76Spilleren har ikke sat et hjem. +noIgnored=\u00a76Du ignorerer ingen. +noKitPermission=\u00a74Du mangler f\u00f8lgende tilladelse for at bruge det kit\: \u00a7c{0}\u00a74 +noKits=\u00a76Der er ingen tilg\u00e6ngelige kits endnu. +noMail=\u00a76Du har ingen beskeder. +noMatchingPlayers=\u00a76Ingen matchende spillere fundet. +noMetaFirework=\u00a74Du har ikke tilladelse til at anvende fyrv\u00e6rkeri meta. +noMetaPerm=\u00a74Du har ikke tilladelse til at tilf\u00f8je \u00a7c{0}\u00a74 meta til dette element. +noNewMail=\u00a76Du har ingen nye beskeder. +noPendingRequest=\u00a74Du har ingen afventende anmodning. +noPerm=\u00a74Du har ikke tilladelsen\: \u00a7c{0}\u00a74 +noPermToSpawnMob=\u00a74Du har ikke tilladelse til at spawne det mob. +noPlacePermission=\u00a74Du har ikke tilladelse til at placere en blok i n\u00e6rheden af det skilt. +noPotionEffectPerm=\u00a74Du har ikke tilladelse til at tilf\u00f8je effekten \u00a7c{0} \u00a74til denne eliksir. +noPowerTools=\u00a76Du har ingen magtv\u00e6rkt\u00f8jer tildelt. +noWarpsDefined=\u00a76Ingen warps defineret. +none=ingen +notAllowedToQuestion=\u00a74Du er ikke autoriseret til at bruge sp\u00f8rgsm\u00e5l. +notAllowedToShout=\u00a74Du er ikke autoriseret til at r\u00e5be. +notEnoughExperience=\u00a74Du har ikke nok experience. +notEnoughMoney=\u00a74Du har ikke tilstr\u00e6kkelige midler. +notFlying=flyver ikke +notRecommendedBukkit=\u00a74* \! * Bukkit version er ikke det anbefalede build til Essentials. +notSupportedYet=Ikke underst\u00f8ttet endnu. +nothingInHand=\u00a74Du har intet i din h\u00e5nd. +now=nu +nuke=\u00a75Lad d\u00f8den regne over dem. +numberRequired=Der skal v\u00e6re et tal, dit fjollehoved. +onlyDayNight=/time underst\u00f8tter kun day/night. +onlyPlayerSkulls=\u00a74Du kan kun indstille ejeren af spillerkranier (\u00a7c397\:3\u00a74). +onlyPlayers=\u00a74Kun spillere p\u00e5 serveren kan bruge \u00a7c{0}\u00a74. +onlySunStorm=\u00a74/weather underst\u00f8tter kun sun/storm. +orderBalances=\u00a76Tjekker saldi af\u00a7c {0} \u00a76brugere. Vent venligst... +oversizedTempban=\u00a74Du kan ikke bandlyse den spiller i det tidsrum. +pTimeCurrent=\u00a7c{0}\u00a76''s tid er\u00a7c {1}\u00a76. +pTimeCurrentFixed=\u00a7c{0}\u00a76''s tid er fastsat til\u00a7c {1}\u00a76. +pTimeNormal=\u00a7c{0}\u00a76''s tid er normal og matcher serverens tid. +pTimeOthersPermission=\u00a74Du er ikke autoriseret til at \u00e6ndre andre spilleres tid. +pTimePlayers=\u00a76Disse spillere har en brugerdefineret tid\:\u00a7r +pTimeReset=\u00a76Spillertiden er blevet nulstillet for\: \u00a7c{0} +pTimeSet=\u00a76Spillertid er \u00e6ndret til \u00a7c{0}\u00a76 for\: \u00a7c{1}. +pTimeSetFixed=\u00a76Spillertid er fastsat til \u00a7c{0}\u00a76 for\: \u00a7c{1}. +pWeatherCurrent=\u00a7c{0}\u00a76''s vejr er\u00a7c {1}\u00a76. +pWeatherInvalidAlias=\u00a74Ugyldig vejrtype +pWeatherNormal=\u00a7c{0}\u00a76''s vejr er normalt og matcher serveren. +pWeatherOthersPermission=\u00a74Du er ikke autoriseret til at \u00e6ndre andre spilleres vejr. +pWeatherPlayers=\u00a76Disse spillere har brugerdefineret vejr\:\u00a7r +pWeatherReset=\u00a76Spillervejret blev nulstillet for\: \u00a7c{0} +pWeatherSet=\u00a76Spillervejret blev \u00e6ndret til \u00a7c{0}\u00a76 for\: \u00a7c{1}. +pendingTeleportCancelled=\u00a74Afventende teleporteringsanmodning afvist. +playerBanIpAddress=\u00a76Player\u00a7c {0} \u00a76banned IP address\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerBanned=\u00a76Spilleren\u00a7c {0} blev \u00a76bandlyst\u00a7c {1} \u00a76i \u00a7c{2}\u00a76. +playerInJail=\u00a74Spilleren er allerede i f\u00e6ngsel\u00a7c {0}\u00a74. +playerJailed=\u00a76Spilleren\u00a7c {0} \u00a76blev f\u00e6ngslet. +playerJailedFor=\u00a76Spilleren\u00a7c {0} \u00a76blev f\u00e6ngslet i {1}. +playerKicked=\u00a76Spilleren\u00a7c {0} \u00a76smed {1} ud med grunden\: {2}. +playerMuted=\u00a76Du er blevet gjort tavs\! +playerMutedFor=\u00a76Du er blevet gjort tavs med grunden\:\u00a7c {0}. +playerNeverOnServer=\u00a74Spilleren\u00a7c {0} \u00a74har aldrig v\u00e6ret p\u00e5 serveren. +playerNotFound=\u00a74Spilleren blev ikke fundet. +playerUnbanIpAddress=\u00a76Spilleren\u00a7c {0} \u00a76unbannede IP''''en\: {1}. +playerUnbanned=\u00a76Spilleren\u00a7c {0} \u00a76unbannede {1}. +playerUnmuted=\u00a76Du er har f\u00e5et din stemme tilbage. +pong=Pong\! +posPitch=\u00a76Pitch\: {0} (Hovedretning) +posX=\u00a76X\: {0} (+\u00d8st <-> -Vest) +posY=\u00a76Y\: {0} (+Op <-> -Ned) +posYaw=\u00a76Yaw\: {0} (Rotation) +posZ=\u00a76Z\: {0} (+Syd <-> -Nord) +possibleWorlds=\u00a76Mulige verdener er tal fra \u00a7c0\u00a76 til \u00a7c{0}\u00a76. +potions=\u00a76Eliksirer\:\u00a7r {0}\u00a76. +powerToolAir=\u00a74Kommandoen kan ikke fastg\u00f8res til luft. +powerToolAlreadySet=\u00a74Kommandoen \u00a7c{0}\u00a74 er allerede tildelt til \u00a7c{1}\u00a74. +powerToolAttach=\u00a7c{0}\u00a76 kommando fastgjort til {1}. +powerToolClearAll=\u00a76Alle magtv\u00e6rkt\u00f8jskommandoer er blevet ryddet. +powerToolList=\u00a76Element \u00a7c{1} \u00a76har de f\u00f8lgende kommandoer\: \u00a7c{0}\u00a76. +powerToolListEmpty=\u00a74Element \u00a7c{0} \u00a74har ingen kommandoer tildelt. +powerToolNoSuchCommandAssigned=\u00a74Kommandoen \u00a7c{0}\u00a74 er ikke blevet tildelt \u00a7c{1}\u00a74. +powerToolRemove=\u00a76Kommando \u00a7c{0}\u00a76 fjernet fra \u00a7c{1}\u00a76. +powerToolRemoveAll=\u00a76Alle kommandoer fjernet fra \u00a7c{0}\u00a76. +powerToolsDisabled=\u00a76Alle dine magtv\u00e6rkt\u00f8jer er deaktiveret. +powerToolsEnabled=\u00a76Alle dine magtv\u00e6rkt\u00f8jer er aktiveret. +questionFormat=\u00a72[Sp\u00f8rgsm\u00e5l]\u00a7r {0} +readNextPage=\u00a76Skriv\u00a7c /{0} {1} \u00a76for at l\u00e6se den n\u00e6ste side. +recipe=\u00a76Opskrivt for \u00a7c{0}\u00a76 (\u00a7c{1}\u00a76 af \u00a7c{2}\u00a76) +recipeBadIndex=Der er ingen opskrift af det nummer. +recipeFurnace=\u00a76Smelt\: \u00a7c{0}\u00a76. +recipeGrid=\u00a7c{0}X \u00a76| \u00a7{1}X \u00a76| \u00a7{2}X +recipeGridItem=\u00a7c{0}X \u00a76er \u00a7c{1} +recipeMore=\u00a76Skriv /{0} \u00a7c{1}\u00a76 for at \u00e6ndre andre opskrifter for \u00a7c{2}\u00a76. +recipeNone=Ingen opskrift eksisterer for {0} +recipeNothing=intet +recipeShapeless=\u00a76Kombiner \u00a7c{0} +recipeWhere=\u00a76Hvor\: {0} +removed=\u00a76Fjernede\u00a7c {0} \u00a76enheder. +repair=\u00a76Du har succesfuldt repareret din\: \u00a7c{0}\u00a76. +repairAlreadyFixed=\u00a74Dette element beh\u00f8ver ikke reparation. +repairEnchanted=\u00a74Du har ikke tilladelse til at reparere fortryllede elementer. +repairInvalidType=\u00a74Dette element kan ikke repareres. +repairNone=\u00a74Der var ingen elementer, der beh\u00f8vede reparation. +requestAccepted=\u00a76Teleporteringsanmodning accepteret. +requestAcceptedFrom=\u00a7c{0} \u00a76accepterede din teleporteringsanmodning. +requestDenied=\u00a76Teleporterings-anmodning fejlede. +requestDeniedFrom=\u00a7c{0} \u00a76afviste din teleporteringsanmodning. +requestSent=\u00a76Anmodning sendt til\u00a7c {0}\u00a76. +requestTimedOut=\u00a74Teleporteringsanmoding udl\u00f8b. +requiredBukkit=\u00a76* \! * Du skal minimum bruge build {0} af CraftBukkit. Download det fra http\://dl.bukkit.org/downloads/craftbukkit/ +resetBal=\u00a76Saldo er blevet nulstillet til \u00a7c{0} \u00a76for alle online spillere. +resetBalAll=\u00a76Saldo er blevet nulstillet til \u00a7c{0} \u00a76for alle spillere. +returnPlayerToJailError=\u00a74Der opstod en fejl under fors\u00f8get p\u00e5 at returnere spilleren\u00a7c {0} \u00a74til f\u00e6ngsel\: \u00a7c{1}\u00a74\! +runningPlayerMatch=\u00a76S\u00f8ger efter spillere, der matcher ''\u00a7c{0}\u00a76'' (dette kan tage lidt tid) +second=sekund +seconds=sekunder +seenOffline=\u00a76Spilleren\u00a7c {0} \u00a76har v\u00e6ret \u00a74offline\u00a76 siden \u00a7c{1}\u00a76. +seenOnline=\u00a76Spilleren\u00a7c {0} \u00a76har v\u00e6ret \u00a7aonline\u00a76 siden \u00a7c{1}\u00a76. +serverFull=Serveren er fyldt op\! +serverTotal=\u00a76Server Total\:\u00a7c {0} +setBal=\u00a7aDin saldo blev \u00e6ndret til {0}. +setBalOthers=\u00a7aDu \u00e6ndrede {0}\u00a7a''s saldo til {1}. +setSpawner=\u00a76\u00c6ndrede spawner type til\u00a7c {0}\u00a76. +sheepMalformedColor=\u00a74Forkert udformet farve. +shoutFormat=\u00a76[R\u00e5b]\u00a7r {0} +signFormatFail=\u00a74[{0}] +signFormatSuccess=\u00a71[{0}] +signFormatTemplate=[{0}] +signProtectInvalidLocation=\u00a74Du har ikke tilladelse til at lave et skilt her. +similarWarpExist=\u00a74Et warp med et lignende navn eksisterer allerede. +slimeMalformedSize=\u00a74Forkert udformet st\u00f8rrelse. +socialSpy=\u00a76SocialSpy for \u00a7c{0}\u00a76\: \u00a7c{1} +soloMob=\u00a74Det mob kan lide at v\u00e6re alene. +spawnSet=\u00a76Spawn lokation \u00e6ndret for gruppen\u00a7c {0}\u00a76. +spawned=spawnede +sudoExempt=\u00a74Du kan ikke sudo denne spiller. +sudoRun=\u00a76Forcing\u00a7c {0} \u00a76to run\:\u00a7r /{1} +suicideMessage=\u00a76Farvel, grusomme verden... +suicideSuccess=\u00a76{0} \u00a76tog sit eget liv. +survival=overlevelse +takenFromAccount=\u00a7a{0} er blevet taget fra din konto. +takenFromOthersAccount=\u00a7a{0} taget fra {1}\u00a7a konto. Ny saldo\: {2}. +teleportAAll=\u00a76Teleporteringsanmodning sendt til alle spillere... +teleportAll=\u00a76Teleporterer alle spillere... +teleportAtoB=\u00a7c{0}\u00a76 teleporterede dig til \u00a7c{1}\u00a76. +teleportDisabled=\u00a7c{0} \u00a74har deaktiveret teleportering. +teleportHereRequest=\u00a7c{0}\u00a76 har anmodet om, at du teleporterer til spilleren. +teleportNewPlayerError=\u00a74Kunne ikke teleportere ny spiller\! +teleportRequest=\u00a7c{0}\u00a76 har anmodet om at teleportere til dig. +teleportRequestTimeoutInfo=\u00a76Denne anmodning vil udl\u00f8be efter\u00a7c {0} sekunder\u00a76. +teleportTop=\u00a76Teleporterer til toppen. +teleportationCommencing=\u00a76Teleportering begynder... +teleportationDisabled=\u00a76Teleportering \u00a7cdeaktiveret\u00a76. +teleportationDisabledFor=\u00a76Teleportering \u00a7cdeaktiveret \u00a76for \u00a7c{0}\u00a76. +teleportationEnabled=\u00a76Teleportering \u00a7caktiveret\u00a76. +teleportationEnabledFor=\u00a76Teleportering \u00a7caktiveret \u00a76for \u00a7c{0}\u00a76. +teleporting=\u00a76Teleporterer... +teleportToPlayer=\u00a76Teleporterer til \u00a7c{0}\u00a76. +tempBanned=\u00a7cYou have been temporarily banned for {0}\:\n\u00a7r{2} +tempbanExempt=\u00a74Du kan ikke tempbanne den spiller. +thunder=\u00a76Du har\u00a7c {0} \u00a76torden i din verden. +thunderDuration=\u00a76Du har\u00a7c {0} \u00a76torden i din verden i\u00a7c {1} \u00a76sekunder. +timeBeforeHeal=\u00a74Tid inden n\u00e6ste helbredelse\:\u00a7c {0}\u00a76. +timeBeforeTeleport=\u00a74Tid inden n\u00e6ste teleport\:\u00a7c {0}\u00a76. +timeFormat=\u00a7c{0}\u00a76 eller \u00a7c{1}\u00a76 eller \u00a7c{2}\u00a76 +timeSetPermission=\u00a74Du er ikke autoriseret til at \u00e6ndre tiden. +timeWorldCurrent=\u00a76Den nuv\u00e6rende tid i\u00a7c {0} \u00a76er \u00a7c{1}\u00a76. +timeWorldSet=\u00a76Tiden blev \u00e6ndret til\u00a7c {0} \u00a76i\: \u00a7c{1}\u00a76. +totalWorthAll=\u00a7aSolgte alle elementer og blokke for en total v\u00e6rdi af \u00a7c{1}\u00a7a. +totalWorthBlocks=\u00a7aSolgte alle blokke for en total v\u00e6rdi af \u00a7c{1}\u00a7a. +tps=\u00a76Nuv\u00e6rende TPS \= {0} +tradeSignEmpty=\u00a74Handelsskiltet har ikke noget tilg\u00e6ngeligt til dig. +tradeSignEmptyOwner=\u00a74Der er ikke noget at hente fra dette handelsskilt. +treeFailure=\u00a74Fejl ved generering af tr\u00e6. Pr\u00f8v igen p\u00e5 gr\u00e6s eller jord. +treeSpawned=\u00a76Tr\u00e6 spawnet. +true=\u00a7asandt\u00a7r +typeTpaccept=\u00a76For et teleportere, skriv \u00a7c/tpaccept\u00a76. +typeTpdeny=\u00a76For at afvise denne anmodning, skriv \u00a7c/tpdeny\u00a76. +typeWorldName=\u00a76Du kan ogs\u00e5 skrive navnet p\u00e5 en specifikke verden. +unableToSpawnMob=\u00a74Kan ikke spawne mob. +unignorePlayer=\u00a76Du ignorerer ikke spilleren\u00a7c {0} \u00a76mere. +unknownItemId=\u00a74Ukendt element ID\:\u00a7r {0}\u00a74. +unknownItemInList=\u00a74Ukendt element {0} i {1} list. +unknownItemName=\u00a74Ukendt elementnavn\: {0}. +unlimitedItemPermission=\u00a74Ingen tilladelse til ubegr\u00e6nset element \u00a7c{0}\u00a74. +unlimitedItems=\u00a76Ubegr\u00e6nsede ting\:\u00a7r +unmutedPlayer=\u00a76Spilleren\u00a7c {0} \u00a76har f\u00e5et sin stemme tilbage. +unvanishedReload=\u00a74En reload har tvunget dig til at blive synlig. +upgradingFilesError=Der opstod en fejl under opgraderingen af filerne. +uptime=\u00a76Oppetid\:\u00a7c {0} +userAFK=\u00a75{0} \u00a75er pt. AFK og svarer m\u00e5ske ikke. +userDoesNotExist=\u00a74Brugeren\u00a7c {0} \u00a74eksisterer ikke. +userIsAway=\u00a75{0} \u00a75er nu AFK. +userIsNotAway=\u00a75{0} \u00a75er ikke l\u00e6ngere AFK. +userJailed=\u00a76Du er blevet f\u00e6ngslet\! +userUnknown=\u00a74Advarsel\: Brugerem ''\u00a7c{0}\u00a74'' har aldrig spillet p\u00e5 serveren. +userdataMoveBackError=Kunne ikke flytte userdata/{0}.tmp til userdata/{1}\! +userdataMoveError=Kunne ikke flytte userdata/{0} til userdata/{1}.tmp\! +usingTempFolderForTesting=Bruger temp mappe til testning\: +vanished=\u00a76Du er nu helt usynlig over for normale spillere, og er skjult fra in-game kommandoer. +versionMismatch=\u00a74Version-uoverenstemmelse\! Opdater {0} til den samme version. +versionMismatchAll=\u00a74Version-uoverenstemmelse\! Opdater alle Essentials jar-filer til den samme version. +voiceSilenced=\u00a76Du er blevet gjort tavs\! +walking=g\u00e5 +warpDeleteError=\u00a74Der var et problem med at slette warp-filen. +warpList={0} +warpListPermission=\u00a74Du har ikke tilladelse til at se warps. +warpNotExist=\u00a74Det warp eksisterer ikke. +warpOverwrite=\u00a74Du kan ikke overskrive det warp. +warpSet=\u00a76Warp\u00a7c {0} \u00a76blev sat. +warpUsePermission=\u00a74Du har ikke tilladelse til at bruge det warp. +warpingTo=\u00a76Warper til\u00a7c {0}\u00a76. +warps=\u00a76Warps\:\u00a7r {0} +warpsCount=\u00a76Der er\u00a7c {0} \u00a76warps. Viser side \u00a7c{1} \u00a76af \u00a7c{2}\u00a76. +weatherStorm=\u00a76Du \u00e6ndrede vejret til \u00a7cstorm\u00a76 i\u00a7c {0}\u00a76. +weatherStormFor=\u00a76Du \u00e6ndrede vejret til \u00a7cstorm\u00a76 i\u00a7c {0} \u00a76i {1} sekunder. +weatherSun=\u00a76Du \u00e6ndrede vejret til \u00a7csolrigt\u00a76 i\u00a7c {0}\u00a76. +weatherSunFor=\u00a76Du \u00e6ndrede vejret til \u00a7csolrigt\u00a76 i\u00a7c {0} \u00a76i {1} sekunder. +whoisAFK=\u00a76 - AFK\:\u00a7r {0} +whoisBanned=\u00a76 - Banlyst\:\u00a7r {0} +whoisExp=\u00a76 - Exp\:\u00a7r {0} (Level {1}) +whoisFly=\u00a76 - Flyvetilstand\:\u00a7r {0} ({1}) +whoisGamemode=\u00a76 - Spiltilstand\:\u00a7r {0} +whoisGeoLocation=\u00a76 - Lokation\:\u00a7r {0} +whoisGod=\u00a76 - Gud-tilstand\:\u00a7r {0} +whoisHealth=\u00a76 - Helbred\:\u00a7r {0}/20 +whoisIPAddress=\u00a76 - IP Adresse\:\u00a7r {0} +whoisJail=\u00a76 - F\u00e6ngsel\:\u00a7r {0} +whoisLocation=\u00a76 - Lokation\:\u00a7r ({0}, {1}, {2}, {3}) +whoisMoney=\u00a76 - Penge\:\u00a7r {0} +whoisMuted=\u00a76 - Gjort tavs\:\u00a7r {0} +whoisNick=\u00a76 - Nick\:\u00a7r {0} +whoisOp=\u00a76 - OP\:\u00a7r {0} +whoisTop=\u00a76 \=\=\=\=\=\= WhoIs\:\u00a7c {0} \u00a76\=\=\=\=\=\= +worth=\u00a7aStak af {0} med en v\u00e6rdi af \u00a7c{1}\u00a7a ({2} ting \u00e1 {3} hver) +worthMeta=\u00a7aStak af {0} med metadata af {1} med en v\u00e6rdi af \u00a7c{2}\u00a7a ({3} element(er) \u00e1 {4} hver) +worthSet=\u00a76V\u00e6rdi \u00e6ndret +year=\u00e5r +years=\u00e5r +youAreHealed=\u00a76Du er blevet helbredt. +youHaveNewMail=\u00a76Du har\u00a7c {0} \u00a76beskeder\! Skriv \u00a7c/mail read\u00a76 for at l\u00e6se dine beskeder. +whoisHunger=\u00a76 - Sult\:\u00a7r {0}/20 (+{1} m\u00e6tning) +kitDelay=\u00a7m{0}\u00a7r +giveSpawnFailure=\u00a74Ikke nok plads, \u00a7c{0} \u00a7c{1} \u00a74blev tabt. +noKitGroup=\u00a74Du har ikke adgang til dette kit. +inventoryClearingFromAll=\u00a76Rydder alle spilleres inventar... +inventoryClearingAllItems=\u00a76Ryddede alle inventar-elementer fra {0}\u00a76. +inventoryClearingAllArmor=\u00a76Rydede alle inventar-elementer og armor fra{0}\u00a76. +inventoryClearingAllStack=\u00a76Ryddede alle\u00a7c {0} \u00a76fra {1}\u00a76. +inventoryClearingStack=\u00a76Fjernede\u00a7c {0} \u00a76af\u00a7c {1} \u00a76fra {2}\u00a76. +inventoryClearFail=\u00a74Spilleren {0} \u00a74har ikke\u00a7c {1} \u00a74af\u00a7c {2}\u00a74. +localNoOne= +totalSellableAll=\u00a7aDen totale v\u00e6rdi af alle salgbare elementer og blocks er \u00a7c{1}\u00a7a. +totalSellableBlocks=\u00a7aDen totale v\u00e6rdi af alle salgbare blocks er \u00a7c{1}\u00a7a. +radiusTooBig=\u00a74Raduisen er for stor\! Maksimal radius er {0}. +isIpBanned=\u00a76IP \u00a7c{0} \u00a76er banlyst. +mobDataList=\u00a76Gyldig mob data\:\u00a7r {0} +vanish=\u00a76Vanish for {0}\u00a76\: {1} +noLocationFound=\u00a74Ingen gyldig placering fundet. +coordsKeyword={0}, {1}, {2} +banExemptOffline=\u00a74Du kan ikke bandlyse offline spillere. +tempbanExemptOffline=\u00a74Du kan ikke midlertidigt bandlyse offline spillere. +mayNotJailOffline=\u00a74Du kan ikke s\u00e6tte offline spillere i f\u00e6ngsel. +muteExemptOffline=\u00a74Du kan ikke g\u00f8re offline spillere tavse. +ignoreExempt=\u00a74Du kan ikke ignorere den spiller. +unsafeTeleportDestination=\u00a74Teleport destinationen er usikker og teleport-safety er deaktiveret. +noMetaJson=JSON Metadata er ikke underst\u00f8ttet i denne version af Bukkit. +maxMoney=\u00a74Denne transaktion vil overstige saldoen af denne konto. +skullChanged=\u00a76Kranie \u00e6ndret til \u00a7c{0}\u00a76. +alphaNames=\u00a74Spillernavne kan kun indeholde bogstaver, tal og underscores. +givenSkull=\u00a76Du er blevet givet \u00a7c{0}\u00a76s kranie. +noPermissionSkull=\u00a74Du har ikke tilladelse til at modificere det kranie. +teleportInvalidLocation=V\u00e6rdi af koordinater kan ikke overstige 30000000 +invalidSkull=\u00a74Hold venligst et spillerkranie. +weatherInvalidWorld=En verden kaldet {0} blev ikke fundet\! +gameModeInvalid=\u00a74Du skal angive en gyldig spiller/tilstand. +mailTooLong=\u00a74Mailbeskeden er for lang. Pr\u00f8v at holde den under 1000 tegn. +mailDelay=For mange mails er blevet sendt inden for det sidste minut. Maksimum\: {0} +seenAccounts=\u00a76Spilleren er ogs\u00e5 kendt som\:\u00a7c {0} +unableToSpawnItem=\u00a74Kan ikke spawne \u00a7c{0}\u00a74, da det ikke er spawnbart element. +itemsConverted=\u00a76Converted all items into blocks. +itemsNotConverted=\u00a74You have no items that can be converted into blocks. +mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\: +mailMessage={0} + +whoisTempBanned=\u00a76 - Ban expires:\u00a7r {0} +playerTempBanned=\u00a76Player \u00a7c{0}\u00a76 temporarily banned \u00a7c{1}\u00a76 for \u00a7c{2}\u00a76: \u00a7c{3}\u00a76. +mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1} diff --git a/Essentials/src/messages_de.properties b/Essentials/src/messages_de.properties new file mode 100644 index 0000000000..fa4742ae63 --- /dev/null +++ b/Essentials/src/messages_de.properties @@ -0,0 +1,558 @@ +#X-Generator: crowdin.net +#version: TeamCity +# Single quotes have to be doubled: '' +# Translations start here +# by: +action=\u00a75* {0} \u00a75{1} +addedToAccount=\u00a7a{0} wurde zu deinem Konto hinzugef\u00fcgt. +addedToOthersAccount=\u00a7a{0} wurde dem Konto von {1} \u00a7agutgeschrieben. Aktueller Kontostand\: {2} +adventure=Abenteuer +alertBroke=zerst\u00f6rt\: +alertFormat=\u00a73[{0}] \u00a7r {1} \u00a76 {2} bei\: {3} +alertPlaced=platziert\: +alertUsed=benutzt\: +antiBuildBreak=\u00a74Du darfst hier keine\u00a7c {0} \u00a74Bl\u00f6cke abbauen. +antiBuildCraft=\u00a74Du darfst\u00a7c {0}\u00a74 nicht erstellen. +antiBuildDrop=\u00a74Du darfst \u00a7c {0}\u00a74 nicht wegwerfen. +antiBuildInteract=\u00a74Du darfst mit\u00a7c {0}\u00a74 nicht interagieren. +antiBuildPlace=\u00a74Du darfst\u00a7c {0} \u00a74hier nicht platzieren. +antiBuildUse=\u00a74Du darfst\u00a7c {0}\u00a74nicht benutzen. +autoAfkKickReason=Du wurdest rausgeworfen, weil du f\u00fcr {0} Minuten inaktiv warst. +backAfterDeath=\u00a76Benutze den Befehl /back um zu deinem Todespunkt zur\u00fcck zu kehren. +backUsageMsg=\u00a76Kehre zur letzten Position zur\u00fcck. +backupDisabled=\u00a74Ein externes Backup-Skript wurde nicht konfiguriert. +backupFinished=\u00a76Backup beendet. +backupStarted=\u00a76Backup gestartet. +balance=\u00a7aKontostand\:\u00a7c {0} +balanceOther=\u00a7aKontostand von {0}\u00a7a\:\u00a7c {1} +balanceTop=\u00a76Die h\u00f6chsten Kontost\u00e4nde ({0}) +banExempt=\u00a74Du kannst diesen Spieler nicht sperren. +banFormat=\u00a74Gesperrt\: \u00a7r{0} +bed=\u00a7oBett\u00a7r +bedMissing=\u00a74Dein Bett ist entweder nicht gesetzt, fehlt oder ist blockiert. +bedNull=\u00a7mBett\u00a7r +bedSet=\u00a76Bett-Spawn gesetzt\! +bigTreeFailure=\u00a74Fehler beim Pflanzen eines grossen Baums. Versuch es auf Gras oder Dreck. +bigTreeSuccess=\u00a76Grosser Baum gepflanzt. +blockList=\u00a76Essentials hat die folgenden Befehle an ein anderes Plugin weiter gegeben\: +bookAuthorSet=\u00a76Autor des Buchs auf {0} ge\u00e4ndert. +bookLocked=\u00a76Dieses Buch ist jetzt versiegelt. +bookTitleSet=\u00a76Buchtitel auf {0} ge\u00e4ndert. +broadcast=\u00a7r\u00a76[\u00a74Rundruf\u00a76]\u00a7a {0} +buildAlert=\u00a74Du hast keine Rechte zum Bauen. +bukkitFormatChanged=Bukkit-Versionsformat hat sich ge\u00e4ndert. Version nicht kontrolliert. +burnMsg=\u00a76Du hast {0} f\u00fcr {1} Sekunden in Brand gesetzt. +canTalkAgain=\u00a76Du kannst wieder sprechen. +cannotStackMob=\u00a74Du hast nicht das Recht, mehrere Mobs zu stapeln. +cantFindGeoIpDB=Kann GeoIP-Datenbank nicht finden\! +cantReadGeoIpDB=Fehler beim Einlesen der GeoIP-Datenbank\! +cantSpawnItem=\u00a74Du darfst Gegenstand\u00a7c {0}\u00a74 nicht erzeugen. +chatTypeAdmin=[A] +chatTypeLocal=[L] +chatTypeSpy=[Spion] +cleaned=Spielerdateien geleert. +cleaning=S\u00e4ubere Spielerdateien. +commandFailed=Befehl {0} scheiterte\: +commandHelpFailedForPlugin=Fehler beim Abrufen der Hilfe f\u00fcr\: {0} +commandNotLoaded=\u00a74Befehl {0} ist nicht richtig geladen. +compassBearing=\u00a76Peilung\: {0} ({1} Grad). +configFileMoveError=Fehler beim Verschieben der config.yml in das Backupverzeichnis. +configFileRenameError=Verschieben einer tempor\u00e4ren Datei nach config.yml gescheitert. +connectedPlayers=\u00a76Verbundene Spieler\u00a7r +connectionFailed=Fehler beim Verbindungsaufbau. +cooldownWithMessage=\u00a74Cooldown\: {0} +corruptNodeInConfig=\u00a74Hinweis\: Deine Konfigurationsdatei hat einen ung\u00fcltigen Knoten {0}. +couldNotFindTemplate=\u00a74Vorlage {0} konnte nicht gefunden werden. +creatingConfigFromTemplate=Erstelle Konfiguration aus Vorlage\: {0} +creatingEmptyConfig=Erstelle leere Konfiguration\: {0} +creative=Kreativ +currency={0}{1} +currentWorld=\u00a76Aktuelle Welt\:\u00a7c {0} +day=Tag +days=Tage +defaultBanReason=Der Bann-Hammer hat gesprochen\! +deleteFileError=Konnte Datei nicht l\u00f6schen\: {0} +deleteHome=\u00a76Zuhause\u00a7c {0} \u00a76wurde gel\u00f6scht. +deleteJail=\u00a76Gef\u00e4ngnis\u00a7c {0} \u00a76wurde gel\u00f6scht. +deleteWarp=\u00a76Warp-Punkt \u00a7c{0} \u00a76wurde gel\u00f6scht. +deniedAccessCommand=\u00a7c{0} \u00a74hat keinen Zugriff auf diesen Befehl. +denyBookEdit=\u00a74Du kannst dieses Buch nicht entsiegeln. +denyChangeAuthor=\u00a74Du kannst den Autor dieses Buches nicht \u00e4ndern. +denyChangeTitle=\u00a74Du kannst den Titel dieses Buches nicht \u00e4ndern. +depth=\u00a76Du bist auf Meeresh\u00f6he. +depthAboveSea=\u00a76Du bist\u00a7c {0} \u00a76Bl\u00f6cke \u00fcber Meeresh\u00f6he. +depthBelowSea=\u00a76Du bist\u00a7c {0} \u00a76Bl\u00f6cke unter Meeresh\u00f6he. +destinationNotSet=Ziel nicht gesetzt\! +disableUnlimited=\u00a76Deaktiviere unbegrenztes Platzieren von\u00a7c {0} \u00a76f\u00fcr {1}. +disabled=deaktiviert +disabledToSpawnMob=\u00a74Das Spawnen dieses Mobs wurde in der Konfigurationsdatei deaktiviert. +distance=\u00a76Entfernung\: {0} +dontMoveMessage=\u00a76Teleportvorgang startet in {0}. Bewege dich nicht. +downloadingGeoIp=Lade GeoIP-Datenbank ... dies kann etwas dauern (country\: 0.6 MB, city\: 20MB) +duplicatedUserdata=Doppelte Datei in userdata\: {0} und {1}. +durability=\u00a76Dieses Werkzeug kann noch \u00a7c{0}\u00a76 mal benutzt werden. +editBookContents=\u00a7eDu darfst jetzt den Inhalt dieses Buches bearbeiten. +enableUnlimited=\u00a76Gebe \u00a7c{1}\u00a76. unendlichen einen Stack\u00a7c {0} \u00a76. +enabled=aktiviert +enchantmentApplied=\u00a76Der Gegenstand in deiner Hand wurde mit\u00a7c {0} \u00a76verzaubert. +enchantmentNotFound=\u00a74Verzauberung nicht gefunden\! +enchantmentPerm=\u00a74Du hast keine Rechte f\u00fcr\u00a7c {0}\u00a74. +enchantmentRemoved=\u00a76Dem Gegenstand in deiner Hand wurde die Verzauberung\u00a7c {0} \u00a76entfernt. +enchantments=\u00a76Verzauberungen\:\u00a7r {0} +errorCallingCommand=Fehler beim Aufrufen des Befehls /{0} +errorWithMessage=\u00a7cFehler\:\u00a74 {0} +essentialsHelp1=Die Datei ist besch\u00e4digt und Essentials kann sie nicht \u00f6ffnen. Essentials ist jetzt deaktiviert. Wenn du die Datei selbst nicht reparieren kannst, gehe auf http\://tiny.cc/EssentialsChat +essentialsHelp2=Die Datei ist besch\u00e4digt und Essentials kann sie nicht \u00f6ffnen. Essentials ist jetzt deaktiviert. Wenn du die Datei selbst nicht reparieren kannst, versuche /essentialshelp oder gehe auf http\://tiny.cc/EssentialsChat +essentialsReload=\u00a76Essentials neu geladen\u00a7c {0}. +exp=\u00a7c{0} \u00a76hat\u00a7c {1} \u00a76Exp (Level\u00a7c {2}\u00a76) und braucht\u00a7c {3} \u00a76Punkte f\u00fcr den n\u00e4chsten Level. +expSet=\u00a7c{0} \u00a76hat jetzt\u00a7c {1} \u00a76Exp. +extinguish=\u00a76Du hast dich selbst gel\u00f6scht. +extinguishOthers=\u00a76Du hast {0}\u00a76 gel\u00f6scht. +failedToCloseConfig=Fehler beim Schliessen der Konfiguration {0}. +failedToCreateConfig=Fehler beim Erstellen der Konfiguration {0}. +failedToWriteConfig=Fehler beim Schreiben der Konfiguration {0}. +false=\u00a74nein\u00a7r +feed=\u00a76Dein Hunger wurde gestillt. +feedOther=\u00a76Du hast dein Hunger von \u00a7c{0}\u00a76gestillt. +fileRenameError=Umbenennen von {0} gescheitert\! +fireworkColor=\u00a74Ung\u00fcltige Feuerwerksparameter angegeben, setze zuerst eine Farbe. +fireworkEffectsCleared=\u00a76Alle Effekte vom Stapel in der Hand entfernt. +fireworkSyntax=\u00a76Feuerwerk-Parameter\:\u00a7c color\: [fade\:] [shape\:] [effect\:]\n\u00a76Um mehrere Farben/Effekte zu benutzen, mit Komma trennen\: \u00a7cred,blue,pink\n\u00a76Formen\:\u00a7c star, ball, large, creeper, burst \u00a76Effekte\:\u00a7c trail, twinkle. +flyMode=\u00a76Flugmodus\u00a7c {0} \u00a76f\u00fcr {1} \u00a76gesetzt. +flying=fliegt +foreverAlone=\u00a7cDu hast niemanden, dem du antworten kannst. +fullStack=\u00a74Du hast bereits einen vollen Stapel. +gameMode=\u00a76Spielmodus\u00a7c {0} \u00a76f\u00fcr {1} \u00a76gesetzt. +gcWorld=\u00a76 {0} "\u00a7c {1} \u00a76"\: \u00a7c {2} \u00a76 Chunks, \u00a7c {3} 6 Einheiten, \u00a7c {4} \u00a76 Tiles. +gcfree=\u00a76Freier Speicher\:\u00a7c {0} MB +gcmax=\u00a76Maximaler Speicher\:\u00a7c {0} MB +gctotal=\u00a76Reservierter Speicher\:\u00a7c {0} MB +geoIpUrlEmpty=GeoIP Download-URL ist leer. +geoIpUrlInvalid=GeoIP Download-URL ist ung\u00fcltig. +geoipJoinFormat=\u00a76Spieler \u00a7c{0} \u00a76kommt aus \u00a7c{1}\u00a76. +giveSpawn=\u00a76Gebe \u00a7c{2} {0}\u00a76x\u00a7c {1}\u00a76. +godDisabledFor=\u00a7cdeaktiviert\u00a76 f\u00fcr\u00a7c {0} +godEnabledFor=\u00a7aaktiviert\u00a76 f\u00fcr\u00a7c {0} +godMode=\u00a76Unsterblichkeit\u00a7c {0}\u00a76. +groupDoesNotExist=\u00a74Kein Mitglied dieser Gruppe ist online\! +groupNumber=\u00a7c{0}\u00a7f online, f\u00fcr die ganze Liste\:\u00a7c /{1} {2} +hatArmor=\u00a74Du kannst diesen Gegenstand nicht als Hut nutzen\! +hatEmpty=\u00a74Du tr\u00e4gst keinen Hut. +hatFail=\u00a74Du musst einen Gegenstand in der Hand halten. +hatPlaced=\u00a76Viel Spa\u00df mit deinem neuen Hut\! +hatRemoved=\u00a76Dein Hut wurde entfernt. +haveBeenReleased=\u00a76Du wurdest frei gelassen. +heal=\u00a76Du wurdest geheilt. +healDead=\u00a74Du kannst Tote nicht heilen\! +healOther=\u00a7c{0}\u00a76 geheilt. +helpConsole=Um die Hilfe der Konsole zu sehen, schreibe ?. +helpFrom=\u00a76Befehle von {0}\: +helpLine=\u00a76/{0}\u00a7r\: {1} +helpMatching=\u00a76Befehle \u00e4hnlich zu "\u00a7c{0}\u00a76"\: +helpOp=\u00a74[Hilfe]\u00a7r \u00a76{0}\:\u00a7r {1} +helpPlugin=\u00a74{0}\u00a7r\: Plugin-Hilfe\: /help {1} +holdBook=\u00a74Du hast kein beschreibbares Buch in deiner Hand. +holdFirework=\u00a74Du musst Feuerwerk in deiner Hand halten um einen Effekt hinzuzuf\u00fcgen. +holdPotion=\u00a74Du musst einen Trank in der Hand haben, um ihm Effekte zu geben. +holeInFloor=\u00a74Loch im Boden\! +homeSet=\u00a76Zuhause gesetzt. +homes=\u00a76Heime\:\u00a7r {0} +hour=Stunde +hours=Stunden +ignoredList=\u00a76Ignoriert\:\u00a7r {0} +ignorePlayer=\u00a76Du ignorierst ab jetzt Spieler\u00a7c {0}\u00a76. +illegalDate=Ung\u00fcltiges Datumsformat. +infoChapter=\u00a76Kapitel ausw\u00e4hlen\: +infoChapterPages=\u00a7e---\u00a76 {0} \u00a7e--\u00a76 Seite \u00a7c{1}\u00a76 von \u00a7c{2} \u00a7e--- +infoPages=\u00a7e ---- \u00a76{2} \u00a7e--\u00a76 Seite \u00a7c{0}\u00a76/\u00a7c{1} \u00a7e---- +infoUnknownChapter=\u00a74Unbekanntes Kapitel. +insufficientFunds=\u00a74Nicht genug Guthaben. +invalidCharge=\u00a74Ung\u00fcltige Kosten. +invalidFireworkFormat=\u00a76Die Option \u00a74{0} \u00a76ist kein g\u00fcltiger Wert f\u00fcr \u00a74{1}\u00a76. +invalidHome=\u00a74Zuhause\u00a7c {0} \u00a74existiert nicht\! +invalidHomeName=\u00a74Ung\u00fcltiger Name\! +invalidMob=\u00a74Unbekannter Mob-Typ. +invalidNumber=Ung\u00fcltige Nummer. +invalidPotion=\u00a74Ung\u00fcltiger Zaubertrank. +invalidPotionMeta=\u00a74Ung\u00fcltige Zaubertrank-Eigenschaft\: \u00a7c{0}\u00a74. +invalidSignLine=\u00a74Die Zeile\u00a7c {0} \u00a74auf dem Schild ist ung\u00fcltig. +invalidWarpName=\u00a74Ung\u00fcltiger Warp-Punkt-Name\! +invalidWorld=\u00a74Ung\u00fcltige Welt. +is=ist +itemCannotBeSold=\u00a74Dieser Gegenstand kann nicht verkauft werden. +itemMustBeStacked=\u00a74Gegenstand muss als Stapel verkauft werden. Eine Anzahl von 2s verkauft 2 Stapel, usw. +itemNames=\u00a76Kurze Gegenstandsnamen\:\u00a7r {0} +itemNotEnough1=\u00a74Du hast nicht genug Gegenst\u00e4nde zum Verkaufen. +itemNotEnough2=\u00a76Wenn du alles von dieser Art verkaufen m\u00f6chtest, nutze /sell itemname. +itemNotEnough3=\u00a76/sell itemname -1 verkauft alles bis auf eins, usw. +itemSellAir=Du versuchst Luft zu verkaufen? Nimm einen Gegenstand in die Hand. +itemSold=\u00a7aVerkauft f\u00fcr \u00a7c{0}\u00a7a ({1} {2} Einheiten je {3}) +itemSoldConsole=\u00a7a{0} $averkauft {1} f\u00fcr \u00a7a{2} \u00a7a({3} Einheiten je {4}) +itemSpawn=\u00a76Gebe\u00a7c {0}\u00a76x\u00a7c {1} +itemType=\u00a76Gegenstand\:\u00a7c {0} \u00a76-\u00a7c {1} +itemsCsvNotLoaded=Konnte items.csv nicht laden\! +jailAlreadyIncarcerated=\u00a74Spieler ist bereits im Gef\u00e4ngnis\:\u00a7c {0} +jailMessage=\u00a74Du hast ein Verbrechen begangen, also musst du deine Zeit absitzen. +jailNotExist=\u00a74Dieses Gef\u00e4ngnis existiert nicht. +jailReleased=\u00a76Spieler \u00a7c{0}\u00a76 wurde freigelassen. +jailReleasedPlayerNotify=\u00a76Du wurdest freigelassen\! +jailSentenceExtended=\u00a76Gef\u00e4ngniszeit erweitert auf\: {0} +jailSet=\u00a76Gef\u00e4ngnis\u00a7c {0} \u00a76wurde erstellt. +jumpError=\u00a74Das w\u00fcrde deinen Computer \u00fcberlasten. +kickDefault=Vom Server geworfen. +kickExempt=\u00a74Du kannst diesen Spieler nicht rauswerfen. +kickedAll=\u00a74Alle Spieler vom Server geworfen. +kill=\u00a7c{0} \u00a76get\u00f6tet. +killExempt=\u00a74Du kannst \u00a7c{0}\u00a74 nicht t\u00f6ten. +kitCost=\ \u00a77\u00a7o({0})\u00a7r +kitError2=\u00a74Diese Ausr\u00fcstung ist nicht korrekt definiert. Kontaktiere einen Administrator. +kitError=\u00a74Es gibt keine g\u00fcltigen Ausr\u00fcstungen. +kitGiveTo=\u00a76Gebe \u00a7c{1}\u00a76 Kit \u00a7c {0}\u00a76 . +kitInvFull=\u00a74Dein Inventar ist voll, lege Ausr\u00fcstung auf den Boden. +kitNotFound=\u00a74Diese Ausr\u00fcstung gibt es nicht. +kitOnce=\u00a74Du kannst diese Ausr\u00fcstung nicht nochmals bekommen. +kitReceive=\u00a7c{0}\u00a76-Ausr\u00fcstung erhalten. +kitTimed=\u00a74Du kannst diese Ausr\u00fcstung nicht innerhalb von\u00a7c {0}\u00a74 anfordern. +kits=\u00a76Ausr\u00fcstungen\: \u00a7r{0} +leatherSyntax=\u00a76Leder-Farbdefinition\: color\:,, z.B.\: color\:255,0,0. +lightningSmited=\u00a76Du wurdest gepeinigt. +lightningUse=\u00a76Peinige {0} +listAfkTag=\u00a77[Abwesend]\u00a7r +listAmount=\u00a76Es sind \u00a7c{0}\u00a76 von maximal \u00a7c{1}\u00a76 Spielern online. +listAmountHidden=\u00a76Es sind \u00a7c{0}\u00a76/{1}\u00a76 von maximal \u00a7c{2}\u00a76 Spielern online. +listGroupTag=\u00a76{0}\u00a7r\:\u00a7r +listHiddenTag=\u00a77[Versteckt]\u00a7r +loadWarpError=\u00a74Fehler beim Laden von Warp-Punkt {0}. +localFormat=[L]<{0}> {1} +mailClear=\u00a76Um deine Nachrichten zu l\u00f6schen, schreibe\u00a7c /mail clear. +mailCleared=\u00a76Nachrichten gel\u00f6scht\! +mailSent=\u00a76Nachricht gesendet\! +markMailAsRead=\u00a76Um deine Nachrichten zu l\u00f6schen, schreibe\u00a7c /mail clear. +markedAsAway=\u00a76Du wirst als abwesend angezeigt. +markedAsNotAway=\u00a76Du wirst nicht mehr als abwesend angezeigt. +matchingIPAddress=\u00a76Die folgenden Spieler haben sich vorher schonmal mit der IP-Adresse eingeloggt\: +maxHomes=\u00a74Du kannst nicht mehr als\u00a7c {0} \u00a74Heime setzen. +mayNotJail=\u00a74Du kannst diese Person nicht einsperren. +me=mir +minute=Minute +minutes=Minuten +missingItems=\u00a74Du hast nicht \u00a7c{0}x {1}\u00a74. +mobSpawnError=\u00a74Fehler beim \u00c4ndern des Monster-Spawner. +mobSpawnLimit=Anzahl an Monster auf Serverlimit beschr\u00e4nkt. +mobSpawnTarget=\u00a74Zielblock muss ein Monster-Spawner sein. +mobsAvailable=\u00a76Mobs\:\u00a7r {0} +moneyRecievedFrom=\u00a7a{1} \u00a7ahat dir {0} gegeben. +moneySentTo=\u00a7aDu hast {1}\u00a7a {0} gegeben. +month=Monat +months=Monate +moreThanZero=\u00a74Anzahl muss gr\u00f6sser als 0 sein. +moveSpeed=\u00a76Setze {0}-Geschwindigkeit f\u00fcr \u00a7c{2} \u00a76auf \u00a7c{1}. +msgFormat=\u00a76[\u00a7c{0}\u00a76 -> \u00a7c{1}\u00a76] \u00a7r{2} +multipleCharges=\u00a74Du kannst einem Feuerwerk nur einen Feuerwerksstern geben. +multiplePotionEffects=\u00a74Du kannst diesem Trank nur einen Effekt geben. +muteExempt=\u00a74Du darfst diesen Spieler nicht stumm machen. +muteNotify=\u00a7c{0} \u00a76hat Spieler \u00a7c{1}\u00a76 stumm geschaltet. +mutedPlayer=\u00a76Spieler\u00a7c {0}\u00a76 ist nicht mehr stumm. +mutedPlayerFor=\u00a76Spieler\u00a7c {0} \u00a76ist nun stumm f\u00fcr\u00a7c {1} \u00a76. +mutedUserSpeaks={0} versuchte zu sprechen, aber ist stumm geschaltet. +nearbyPlayers=\u00a76Spieler in der N\u00e4he\:\u00a7r {0} +negativeBalanceError=\u00a74Spieler darf keine Schulden machen. +nickChanged=\u00a76Spitzname ge\u00e4ndert. +nickDisplayName=\u00a74Du musst change-displayname in der Essentials-Konfiguration aktivieren. +nickInUse=\u00a74Dieser Name wird bereits verwendet. +nickNamesAlpha=\u00a74Nicknamen d\u00fcrfen nur alphanumerische Zeichen enthalten. +nickNoMore=\u00a76Du hast keinen Spitznamen mehr. +nickSet=\u00a76Dein Spitzname ist nun \u00a7c{0}. +nickTooLong=\u00a74Dieser Spitzname ist zu lang. +noAccessCommand=\u00a74Du hast keinen Zugriff auf diesen Befehl. +noAccessPermission=\u00a74Du hast keine Rechte dies zu betreten \u00a7c{0}\u00a74. +noBreakBedrock=\u00a74Du darfst Grundgestein nicht zerst\u00f6ren. +noDestroyPermission=\u00a74Du hast keine Rechte dies zu zerst\u00f6ren \u00a7c{0}\u00a74. +noDurability=\u00a74Dieser Gegenstand hat keine Haltbarkeit. +noGodWorldWarning=\u00a74Warnung\! Unsterblichkeitsmodus ist in dieser Welt deaktiviert. +noHelpFound=\u00a74Keine \u00fcbereinstimmenden Befehle. +noHomeSetPlayer=\u00a76Spieler hat kein Zuhause gesetzt. +noIgnored=\u00a76Du ignorierst niemanden. +noKitPermission=\u00a74Du brauchst die Berechtigung \u00a7c{0}\u00a74 um diese Ausr\u00fcstung anzufordern. +noKits=\u00a76Es sind keine Ausr\u00fcstungen verf\u00fcgbar. +noMail=\u00a76Du hast keine Nachrichten. +noMatchingPlayers=\u00a76Keine \u00fcbereinstimmenden Spieler gefunden. +noMetaFirework=\u00a74Du darfst keine Berechtigung Feuerwerk-Metadaten zu bearbeiten. +noMetaPerm=\u00a74Du darfst dem Gegenstand \u00a7c{0}\u00a74 keine Metadaten geben. +noNewMail=\u00a76Du hast keine neue Nachrichten. +noPendingRequest=\u00a74Du hast keine Teleportierungsanfragen. +noPerm=\u00a74Du hast die Berechtigung \u00a7c{0}\u00a74 nicht. +noPermToSpawnMob=\u00a74Du bis nicht berechtigt, diesen Mob zu spawnen. +noPlacePermission=\u00a7cDu hast keine Rechte, einen Block in der N\u00e4he des Schildes zu platzieren. +noPotionEffectPerm=\u00a74Du darfst den Zaubertrankeffekt \u00a7c{0} \u00a74diesem Trank nicht hinzuf\u00fcgen. +noPowerTools=\u00a76Du hast keine Powertools zugewiesen. +noWarpsDefined=\u00a76Keine Warp-Punkte erstellt. +none=keine +notAllowedToQuestion=\u00a74Du bist nicht berechtigt zu fragen. +notAllowedToShout=\u00a74Du bist nicht berechtigt zu schreien. +notEnoughExperience=\u00a74Du hast nicht genug Erfahrung. +notEnoughMoney=\u00a74Du hast nicht genug Guthaben. +notFlying=fliegt nicht +notRecommendedBukkit=\u00a74* \! * Die verwendete Bukkit-Version ist nicht f\u00fcr Essentials empfohlen. +notSupportedYet=Noch nicht verf\u00fcgbar. +nothingInHand=\u00a74Du hast nichts in der Hand. +now=jetzt +nuke=\u00a75M\u00f6ge der Tod auf Sie hernieder prasseln\! +numberRequired=Ein Zahl wird ben\u00f6tigt. +onlyDayNight=/time unterst\u00fctzt nur day und night. +onlyPlayerSkulls=\u00a74Du kannst nur den Besitzer von Spielerk\u00f6pfen (\u00a7c397\:3\u00a74) \u00e4ndern. +onlyPlayers=\u00a74Nur in-Game-Spieler k\u00f6nnen \u00a7c{0} \u00a74benutzen. +onlySunStorm=\u00a74/weather unterst\u00fctzt nur sun und storm. +orderBalances=\u00a76Ordne die Kontost\u00e4nde von\u00a7c {0} \u00a76Benutzern, bitte warten ... +oversizedTempban=\u00a74Du darfst einen Spieler nicht f\u00fcr so eine lange Zeit sperren. +pTimeCurrent=\u00a76Die Zeit f\u00fcr\u00a7c {0} \u00a76ist\u00a7c {1}\u00a76. +pTimeCurrentFixed=\u00a76Die Zeit f\u00fcr \u00a7c{0}\u00a76 wurde auf \u00a7c{1}\u00a76 gesetzt. +pTimeNormal=\u00a76Die Zeit f\u00fcr \u00a7c{0}\u00a76 ist normal und entspricht der Serverzeit. +pTimeOthersPermission=\u00a74Du hast keine Berechtigung die Zeit von anderen Spielern zu \u00e4ndern. +pTimePlayers=\u00a76Diese Spieler haben ihre eigene Zeit\:\u00a7r +pTimeReset=\u00a76Zeit wurde zur\u00fcckgesetzt f\u00fcr\: \u00a7c{0} +pTimeSet=\u00a76Zeit wurde f\u00fcr \u00a7c{1}\u00a76 auf \u00a7c{0}\u00a76 gesetzt. +pTimeSetFixed=\u00a76Spielerzeit ist festgesetzt auf \u00a7c{0}\u00a76 f\u00fcr\: \u00a7c{1} +pWeatherCurrent=\u00a76Das Wetter von\u00a7c {0} \u00a76ist\u00a7c {1}\u00a76. +pWeatherInvalidAlias=\u00a74Ung\u00fcltiger Wettertyp +pWeatherNormal=\u00a7cDas Wetter von \u00a7c{0}\u00a76 ist normal, wie auf dem Server. +pWeatherOthersPermission=\u00a74Du darfst keinem Spieler das Wetter ver\u00e4ndern. +pWeatherPlayers=\u00a76Diese Spieler haben ihr eigenes Wetter\:\u00a7r +pWeatherReset=\u00a76Das Spielerwetter wurde zur\u00fcckgesetzt f\u00fcr\: \u00a7c{0} +pWeatherSet=\u00a76Spielerwetter gesetzt auf \u00a7c{0}\u00a76 f\u00fcr\: \u00a7c{1}. +pendingTeleportCancelled=\u00a74Laufende Teleportierung abgebrochen. +playerBanIpAddress=\u00a76Player\u00a7c {0} \u00a76banned IP address\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerBanned=\u00a76Spieler\u00a7c {0} \u00a76wurde gebannt\u00a7c {1} \u00a76f\u00fcr \u00a7c{2}\u00a76. +playerInJail=\u00a74Spieler ist bereits in Gef\u00e4ngnis\u00a7c {0}\u00a76. +playerJailed=\u00a76Spieler\u00a7c {0} \u00a76eingesperrt. +playerJailedFor=\u00a76Spieler\u00a7c {0} \u00a76eingesperrt f\u00fcr {1}. +playerKicked=\u00a76Spieler\u00a7c {0} \u00a76rausgeworfen\: {1} f\u00fcr {2}. +playerMuted=\u00a76Du bist jetzt stumm\! +playerMutedFor=\u00a76Du bist jetzt stumm f\u00fcr\u00a7c {0}. +playerNeverOnServer=\u00a74Spieler\u00a7c {0} \u00a74war niemals auf diesem Server. +playerNotFound=\u00a74Spieler nicht gefunden. +playerUnbanIpAddress=\u00a76Spieler\u00a7c {0} \u00a76hat die IP Adresse {1} \u00a76entsperrt. +playerUnbanned=\u00a76Spieler\u00a7c {0} \u00a76hat {1}\u00a76 entsperrt. +playerUnmuted=\u00a76Du bist nicht mehr stumm. +pong=Pong\! +posPitch=\u00a76Pitch\: {0} (Neigewinkel) +posX=\u00a76X\: {0} (+Ost <-> -West) +posY=\u00a76Y\: {0} (+Hoch <-> -Runter) +posYaw=\u00a76Yaw\: {0} (Drehung) +posZ=\u00a76Z\: {0} (+S\u00fcd <-> -Nord) +possibleWorlds=\u00a76M\u00f6gliche Welten sind die Nummern \u00a7c0\u00a76 bis \u00a7c{0}\u00a76. +potions=\u00a76Zaubertr\u00e4nke\:\u00a7r {0}\u00a76. +powerToolAir=\u00a74Befehl kann nicht mit Luft verbunden werden. +powerToolAlreadySet=\u00a74Der Command \u00a7c{0}\u00a74 ist bereits \u00a7c{c{1}\u00a74 zugewiesen. +powerToolAttach=\u00a76Befehl \u00a7c{0}\u00a7f erfolgreich an {1} gebunden. +powerToolClearAll=\u00a76Alle Powertoolbefehle wurden entfernt. +powerToolList=\u00a76Gegenstand \u00a7c{1} \u00a76hat die folgenden Befehle\: \u00a7c{0}\u00a76. +powerToolListEmpty=\u00a74Gegenstand \u00a7c{0} $4hat keinen Befehl. +powerToolNoSuchCommandAssigned=\u00a74Command \u00a7c{0}\u00a74 has not been assigned to \u00a7c{1}\u00a74. +powerToolRemove=\u00a76Command \u00a7c{0}\u00a76 removed from \u00a7c{1}\u00a76. +powerToolRemoveAll=\u00a76All commands removed from \u00a7c{0}\u00a76. +powerToolsDisabled=\u00a76Alle deine Powertools wurden deaktiviert. +powerToolsEnabled=\u00a76Alle deine Powertools wurden aktiviert. +questionFormat=\u00a72[Frage]\u00a7r {0} +readNextPage=\u00a76Tippe\u00a7c /{0} {1} \u00a76f\u00fcr die n\u00e4chste Seite. +recipe=\u00a76Recipe for \u00a7c{0}\u00a76 (\u00a7c{1}\u00a76 of \u00a7c{2}\u00a76) +recipeBadIndex=Es gibt kein Rezept mit dieser Nummer. +recipeFurnace=\u00a76Smelt\: \u00a7c{0}\u00a76. +recipeGrid=\u00a7c{0}X \u00a76| \u00a7{1}X \u00a76| \u00a7{2}X +recipeGridItem=\u00a7c{0}X \u00a76ist \u00a7c{1} +recipeMore=\u00a76Tippe /{0} \u00a7c{1}\u00a76 um andere Rezepte f\u00fcr \u00a7c{2}\u00a76 anzuschauen. +recipeNone=Keine Rezepte f\u00fcr {0} +recipeNothing=nichts +recipeShapeless=\u00a76Kombiniere \u00a7c{0} +recipeWhere=\u00a76Wo\: {0} +removed=\u00a7c{0} \u00a76Einheiten entfernt. +repair=\u00a76Dein \u00a7c{0}\u00a76wurde erfolgreich repariert. +repairAlreadyFixed=\u00a74Dieser Gegenstand ben\u00f6tigt keine Reparatur. +repairEnchanted=\u00a74Du darfst keine verzauberten Gegenst\u00e4nde reparieren. +repairInvalidType=\u00a74Dieser Gegenstand kann nicht repariert werden. +repairNone=\u00a74Es sind keine Gegenst\u00e4nde vorhanden, die repariert werden k\u00f6nnen. +requestAccepted=\u00a77Teleportierungsanfrage akzeptiert. +requestAcceptedFrom=\u00a7c{0} \u00a76hat deine Teleportierungsanfrage angenommen. +requestDenied=\u00a76Teleportierungsanfrage verweigert. +requestDeniedFrom=\u00a7c{0} \u00a76hat deine Teleportierungsanfrage abgelehnt. +requestSent=\u00a76Anfrage gesendet an\u00a7c {0}\u00a76. +requestTimedOut=\u00a74Teleportierungsanfrage ist abgelaufen. +requiredBukkit=\u00a76* \! * Du brauchst mindestens CraftBukkit Build \#{0}, lade es von http\://dl.bukkit.org/downloads/craftbukkit/ +resetBal=\u00a76Kontostand aller Spieler auf dem Server auf \u00a7a{0} \u00a76gesetzt. +resetBalAll=\u00a76Balance has been reset to \u00a7c{0} \u00a76for all players. +returnPlayerToJailError=\u00a74Fehler beim Zur\u00fcckversetzen von\u00a7c {0} \u00a74in Gef\u00e4ngis\: {1}\! +runningPlayerMatch=\u00a76Suche nach Spielern mit ''\u00a7c{0}\u00a76'' im Namen (das kann etwas dauern) +second=Sekunde +seconds=Sekunden +seenOffline=\u00a76SSpieler\u00a7c {0} \u00a76ist \u00a74offline\u00a76 seit \u00a7c{1}\u00a76. +seenOnline=\u00a76SSpieler\u00a7c {0} \u00a76ist \u00a74online\u00a76 seit \u00a7c{1}\u00a76. +serverFull=Server ist voll +serverTotal=\u00a76Server insgesamt\:\u00a7c {0} +setBal=\u00a7aDein Kontostand wurde auf {0} gesetzt. +setBalOthers=\u00a7aDu hast den Kontostand von {0}\u00a7a auf {1} gesetzt. +setSpawner=\u00a76Mob-Spawner-Typ zu \u00a7c{0}\u00a76 ge\u00e4ndert. +sheepMalformedColor=\u00a74Ung\u00fcltige Farbe. +shoutFormat=\u00a76[Schrei]\u00a7r {0} +signFormatFail=\u00a74[{0}] +signFormatSuccess=\u00a71[{0}] +signFormatTemplate=[{0}] +signProtectInvalidLocation=\u00a74Du hast keine Rechte ein Schild hier zu setzen. +similarWarpExist=\u00a74Ein Warp-Punkt mit einem \u00e4hnlichen Namen existiert bereits. +slimeMalformedSize=\u00a74Ung\u00fcltige Gr\u00f6sse. +socialSpy=\u00a76SocialSpy f\u00fcr \u00a7c {0} \u00a7 6\: \u00a7c {1} +soloMob=\u00a74Das Monster m\u00f6chte allein sein. +spawnSet=\u00a76Spawn-Punkt gesetzt f\u00fcr Gruppe \u00a7c{0}\u00a76. +spawned=erzeugt +sudoExempt=\u00a74Du kannst f\u00fcr diesen Spieler kein sudo-Kommando ausf\u00fchren. +sudoRun=\u00a76Forcing\u00a7c {0} \u00a76to run\:\u00a7r /{1} +suicideMessage=\u00a76Ad\u00e9, du schn\u00f6de Welt... +suicideSuccess=\u00a76{0} \u00a76hat sich das Leben genommen. +survival=\u00dcberleben +takenFromAccount=\u00a7a{0} wurden von deinem Konto abgezogen. +takenFromOthersAccount=\u00a7a{0} genommen von {1}\u00a7a. Neuer Kontostand\: {2}. +teleportAAll=\u00a76Teleportierungsanfrage zu allen Spielern gesendet... +teleportAll=\u00a76Teleportiere alle Spieler... +teleportAtoB=\u00a7c{0}\u00a76 teleportiert dich zu {1}\u00a76. +teleportDisabled=\u00a7c{0} \u00a74verweigert die Teleportierung. +teleportHereRequest=\u00a7c{0}\u00a76 fragt, ob du dich zu ihm teleportierst. +teleportNewPlayerError=\u00a74Fehler beim Teleportieren eines neuen Spielers\! +teleportRequest=\u00a7c{0}\u00a76 fragt, ob er sich zu dir teleportieren darf. +teleportRequestTimeoutInfo=\u00a76Diese Anfrage wird nach\u00a7c {0} Sekunden\u00a76 ung\u00fcltig. +teleportTop=\u00a76Teleportiere nach oben. +teleportationCommencing=\u00a76Teleportierung gestartet... +teleportationDisabled=\u00a76Teleportation \u00a7cdeaktiviert\u00a76. +teleportationDisabledFor=\u00a76Teleportation \u00a7cdisabled \u00a76for \u00a7c{0}\u00a76. +teleportationEnabled=\u00a76Teleportation \u00a7cenabled\u00a76. +teleportationEnabledFor=\u00a76Teleportation \u00a7cenabled \u00a76for \u00a7c{0}\u00a76. +teleporting=\u00a76Teleportiere... +teleportToPlayer=\u00a76teleportieren zu \u00a7c{0}\u00a76. +tempBanned=\u00a7cYou have been temporarily banned for {0}\:\n\u00a7r{2} +tempbanExempt=\u00a74Du kannst diesen Spieler nicht zeitlich sperren. +thunder=\u00a76Es donnert nun in deiner Welt \u00a7c{0}\u00a76. +thunderDuration=\u00a76Es donnert nun f\u00fcr\u00a7c {1} \u00a76Sekunden in deiner Welt\u00a7c {0}\u00a76. +timeBeforeHeal=\u00a74Zeit bis zur n\u00e4chsten Heilung\:\u00a7c {0}\u00a76. +timeBeforeTeleport=\u00a74Zeit bis zum n\u00e4chsten Teleport\:\u00a7c {0} +timeFormat=\u00a7c{0}\u00a76 or \u00a7c{1}\u00a76 or \u00a7c{2}\u00a76 +timeSetPermission=\u00a74Du hast keine Berechtigung die Zeit zu \u00e4ndern. +timeWorldCurrent=\u00a76Die aktuelle Zeit in\u00a7c {0} \u00a76ist \u00a7c{1} +timeWorldSet=Die Zeit in \u00a7c{1}\u00a7f wurde zu {0} gesetzt. +totalWorthAll=\u00a7aAlle Gegenst\u00e4nde und Bl\u00f6cke f\u00fcr einen Gesamtwert von \u00a7c{1}\u00a7a verkauft. +totalWorthBlocks=\u00a7aAlle Bl\u00f6cke f\u00fcr einen Gesamtwert von \u00a7c{1}\u00a7a verkauft. +tps=\u00a76Aktuelle TPS \= {0} +tradeSignEmpty=Der Bestand des Trade-Schild ist aufgebraucht. +tradeSignEmptyOwner=Es gibt nichts mehr zu Sammeln von diesem Trade-Schild. +treeFailure=\u00a74Baumpflanzung gescheitert. Versuche es nochmal auf Gras oder Erde. +treeSpawned=\u00a76Baum gepflanzt. +true=\u00a7aja\u00a7r +typeTpaccept=\u00a76Um zu teleportieren, schreibe \u00a7c/tpaccept\u00a76. +typeTpdeny=\u00a76Um diese Anfrage abzulehnen, schreibe \u00a7c/tpdeny\u00a76. +typeWorldName=\u00a76Du kannst auch den Namen der Welt eingeben. +unableToSpawnMob=\u00a74Fehler beim Erzeugen des Monsters. +unignorePlayer=\u00a76Du ignorierst Spieler\u00a7c {0} \u00a76nicht mehr. +unknownItemId=\u00a74Unbekannte Gegenstandsnummer\:\u00a7r {0}\u00a74. +unknownItemInList=\u00a74Unbekannter Gegenstand {0} in Liste {1}. +unknownItemName=\u00a74Unbekannter Gegenstand\: {0}. +unlimitedItemPermission=\u00a74No permission for unlimited item \u00a7c{0}\u00a74. +unlimitedItems=\u00a76Unendliche Objekte\:\u00a7r +unmutedPlayer=\u00a76Spieler\u00a7c {0}\u00a76 ist nicht mehr stumm. +unvanishedReload=\u00a74Ein Neuladen des Servers hat dich sichtbar gemacht. +upgradingFilesError=Fehler beim Aktualisieren der Dateien +uptime=\u00a76Laufzeit\:\u00a7c {0} +userAFK=\u00a77{0} \u00a75ist gerade nicht da und antwortet wahrscheinlich nicht. +userDoesNotExist=\u00a74Spieler\u00a7c {0} \u00a74existiert nicht. +userIsAway=\u00a77* {0} \u00a77ist nun abwesend. +userIsNotAway=\u00a77* {0} \u00a77ist wieder da. +userJailed=\u00a76Du wurdest eingesperrt. +userUnknown=\u00a74Warnung\: Der Spieler ''\u00a7c{0}\u00a74'' war nie auf diesem Server. +userdataMoveBackError=Verschieben von userdata/{0}.tmp nach userdata/{1} gescheitert. +userdataMoveError=Verschieben von userdata/{0} nach userdata/{1}.tmp gescheitert. +usingTempFolderForTesting=Benutze tempor\u00e4ren Ordner zum Testen\: +vanished=\u00a76Du bist nun vollst\u00e4ndig unsichtbar f\u00fcr normale Benutzer, auch f\u00fcr deren Kommandos. +versionMismatch=\u00a74Versionen nicht identisch\! Bitte aktualisiere {0}. +versionMismatchAll=\u00a74Versionen ungleich\! Bitte aktualisiere alle Essentials jars auf die gleiche Version. +voiceSilenced=\u00a76Du bist nun stumm\! +walking=Bewegungs +warpDeleteError=\u00a74Fehler beim L\u00f6schen der Warp-Datei. +warpList={0} +warpListPermission=\u00a74Du hast keine Berechtigung, die Warp-Punkte anzuzeigen. +warpNotExist=\u00a74Warp-Punkt existiert nicht. +warpOverwrite=\u00a74Du kannst diesen Warp-Punkt nicht ersetzen. +warpSet=\u00a76Warp-Punkt\u00a7c {0} \u00a76wurde erstellt. +warpUsePermission=\u00a74Du hast keinen Zugriff f\u00fcr diesen Warp-Punkt. +warpingTo=\u00a76Teleportiere zu Warp-Punkt\u00a7c {0}\u00a76. +warps=\u00a76Warp-Punkte\:\u00a7r {0} +warpsCount=\u00a76There are\u00a7c {0} \u00a76warps. Showing page \u00a7c{1} \u00a76of \u00a7c{2}\u00a76. +weatherStorm=\u00a76In \u00a7c{0} \u00a76st\u00fcrmt es nun. +weatherStormFor=\u00a76In \u00a7c{0} \u00a76st\u00fcrmt es nun f\u00fcr {1} Sekunden. +weatherSun=\u00a76In \u00a7c{0}\u00a76 scheint nun die \u00a7cSonne\u00a76. +weatherSunFor=\u00a76In \u00a7c{0} \u00a76scheint nun f\u00fcr {1} Sekunden die \u00a7cSonne\u00a76. +whoisAFK=\u00a76 - Abwesend\:\u00a7r {0} +whoisBanned=\u00a76 - Gebannt\:\u00a7r {0} +whoisExp=\u00a76 - Exp\:\u00a7r {0} (Level {1}) +whoisFly=\u00a76 - Flugmodus\:\u00a7r {0} ({1}) +whoisGamemode=\u00a76 - Spielmodus\:\u00a7r {0} +whoisGeoLocation=\u00a76 - Herkunft\:\u00a7f {0} +whoisGod=\u00a76 - Unsterblichkeitsmodus\:\u00a7r {0} +whoisHealth=\u00a76 - Gesundheit\:\u00a7f {0}/20 +whoisIPAddress=\u00a76 - IP-Adresse\:\u00a7r {0} +whoisJail=\u00a76 - Gef\u00e4ngnis\:\u00a7r {0} +whoisLocation=\u00a76 - Position\:\u00a7r ({0}, {1}, {2}, {3}) +whoisMoney=\u00a76 - Kontostand\:\u00a7r {0} +whoisMuted=\u00a76 - Stumm\:\u00a7r {0} +whoisNick=\u00a76 - Spitzname\:\u00a7r {0} +whoisOp=\u00a76 - OP\:\u00a7r {0} +whoisTop=\u00a76 \=\=\=\=\=\= WhoIs\:\u00a7c {0} \u00a76\=\=\=\=\=\= +worth=\u00a7aEin Stapel {0} ist \u00a7c{1}\u00a7a wert ({2} Einheiten je {3}) +worthMeta=\u00a7aEin Stapel von {0} mit Metadaten {1} ist \u00a7c{2}\u00a7a wert. ({3} Einheiten je {4}) +worthSet=\u00a76Wert des Gegenstands gesetzt. +year=Jahr +years=Jahre +youAreHealed=\u00a76Du wurdest geheilt. +youHaveNewMail=\u00a76Du hast \u00a7c{0} \u00a76Nachrichten\! Schreibe \u00a7c/mail read\u00a76 um deine Nachrichten anzuzeigen. +whoisHunger=\u00a76 - Hunger\:\u00a7r {0}/20 (+{1} S\u00e4ttigung) +kitDelay=\u00a7m{0}\u00a7r +giveSpawnFailure=\u00a74Nicht genug Platz, \u00a7c{0} \u00a7c{1} \u00a74verloren. +noKitGroup=\u00a74Du hast auf diese Ausr\u00fcstung keinen Zugriff. +inventoryClearingFromAll=\u00a76Leere das Inventar aller Spieler... +inventoryClearingAllItems=\u00a76Alle Gegenst\u00e4nde im Inventar von {0} \u00a76entfernt. +inventoryClearingAllArmor=\u00a76Alle Gegenst\u00e4nde im Inventar und R\u00fcstung von {0} \u00a76entfernt. +inventoryClearingAllStack=\u00a76Alle\u00a7c {0} \u00a76von {1} \u00a76entfernt. +inventoryClearingStack=\u00a7c {0} {1} \u00a76von {2} \u00a76entfernt. +inventoryClearFail=\u00a74Spieler {0} \u00a74hat keine\u00a7c {1} {2}\u00a74. +localNoOne= +totalSellableAll=\u00a7aDer Gesamtwert von allen Bl\u00f6cken und Items ist \u00a7c{1}\u00a7a. +totalSellableBlocks=\u00a7aDer Gesamtwert der verkaufbaren Bl\u00f6cke ist \u00a7c{1}\u00a7a. +radiusTooBig=\u00a74Radius ist zu gro\u00df\! Maximaler Radius ist {0}. +isIpBanned=\u00a76IP \u00a7c{0} \u00a76wurde gebannt. +mobDataList=\u00a76G\u00fcltige Mob Daten\:\u00a7r {0} +vanish=\u00a76Unsichtbar f\u00fcr {0} \u00a76\: {1} +noLocationFound=\u00a74Keine g\u00fcltige Position gefunden. +coordsKeyword={0}, {1}, {2} +banExemptOffline=\u00a74Du darfst abgemeldete Spieler nicht bannen. +tempbanExemptOffline=\u00a74Du darfst abgemeldete Spieler nicht tempor\u00e4r bannen. +mayNotJailOffline=\u00a74Du darfst abgemeldete Spieler nicht einsperren. +muteExemptOffline=\u00a74Du darfst abgemeldete Spieler nicht stummschalten. +ignoreExempt=\u00a74Du kannst diesen Spieler nicht ignorieren. +unsafeTeleportDestination=\u00a74Das Teleport-Ziel ist nicht sicher und der Teleportschutz ist nicht aktiv. +noMetaJson=JSON MetaDaten werden in dieser Bukkit-Version nicht unterst\u00fctzt. +maxMoney=\u00a74Diese \u00dcberweisung \u00fcberschreitet das Limit des Empf\u00e4ngers. +skullChanged=\u00a76Skull changed to \u00a7c{0}\u00a76. +alphaNames=\u00a74Spieler Namen k\u00f6nnen nur Buchstaben, Zahlen und Unterstriche enthalten. +givenSkull=\u00a76Dir wurde der Kopf von \u00a7c{0}\u00a76 gegeben. +noPermissionSkull=$4Du hast nicht die Berechtigung diesen Kopf zu \u00e4ndern. +teleportInvalidLocation=Der Wert der angegebenen Koordinaten darf nicht \u00fcber 30000000 sein +invalidSkull=\u00a74Bitte halte einen Spielerkopf in der Hand. +weatherInvalidWorld=Welt mit dem Namen {0} wurde nicht gefunden\! +gameModeInvalid=\u00a74Sie m\u00fcssen einen g\u00fcltigen Spieler/Modus angeben. +mailTooLong=\u00a74Nachricht zu lang. Schreibe nicht mehr als 1000 Zeichen. +mailDelay=In der letzten Minute wurden zu viele Mails gesendet. Maximum\: {0} +seenAccounts=\u00a76Player has also been known as\:\u00a7c {0} +unableToSpawnItem=\u00a74Cannot spawn \u00a7c{0}\u00a74, this is not a spawnable item. +itemsConverted=\u00a76Converted all items into blocks. +itemsNotConverted=\u00a74You have no items that can be converted into blocks. +mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\: +mailMessage={0} + +whoisTempBanned=\u00a76 - Ban expires:\u00a7r {0} +playerTempBanned=\u00a76Player \u00a7c{0}\u00a76 temporarily banned \u00a7c{1}\u00a76 for \u00a7c{2}\u00a76: \u00a7c{3}\u00a76. +mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1} diff --git a/Essentials/src/messages_en.properties b/Essentials/src/messages_en.properties new file mode 100644 index 0000000000..2d438cf3f1 --- /dev/null +++ b/Essentials/src/messages_en.properties @@ -0,0 +1,557 @@ +#X-Generator: crowdin.net +#version: TeamCity +# Single quotes have to be doubled: '' +# Translations start here +# by: +action=\u00a75* {0} \u00a75{1} +addedToAccount=\u00a7a{0} has been added to your account. +addedToOthersAccount=\u00a7a{0} added to {1}\u00a7a account. New balance\: {2} +adventure=adventure +alertBroke=broke\: +alertFormat=\u00a73[{0}] \u00a7r {1} \u00a76 {2} at\: {3} +alertPlaced=placed\: +alertUsed=used\: +antiBuildBreak=\u00a74You are not permitted to break\u00a7c {0} \u00a74blocks here. +antiBuildCraft=\u00a74You are not permitted to create\u00a7c {0}\u00a74. +antiBuildDrop=\u00a74You are not permitted to drop\u00a7c {0}\u00a74. +antiBuildInteract=\u00a74You are not permitted to interact with\u00a7c {0}\u00a74. +antiBuildPlace=\u00a74You are not permitted to place\u00a7c {0} \u00a74here. +antiBuildUse=\u00a74You are not permitted to use\u00a7c {0}\u00a74. +autoAfkKickReason=You have been kicked for idling more than {0} minutes. +backAfterDeath=\u00a76Use the /back command to return to your death point. +backUsageMsg=\u00a76Returning to previous location. +backupDisabled=\u00a74An external backup script has not been configured. +backupFinished=\u00a76Backup finished. +backupStarted=\u00a76Backup started. +balance=\u00a7aBalance\:\u00a7c {0} +balanceOther=\u00a7aBalance of {0}\u00a7a\:\u00a7c {1} +balanceTop=\u00a76Top balances ({0}) +banExempt=\u00a74You cannot ban that player. +banFormat=\u00a7cYou have been banned\:\n\u00a7r{0} +bed=\u00a7obed\u00a7r +bedMissing=\u00a74Your bed is either unset, missing or blocked. +bedNull=\u00a7mbed\u00a7r +bedSet=\u00a76Bed spawn set\! +bigTreeFailure=\u00a74Big tree generation failure. Try again on grass or dirt. +bigTreeSuccess=\u00a76Big tree spawned. +blockList=\u00a76Essentials relayed the following commands to another plugin\: +bookAuthorSet=\u00a76Author of the book set to {0}. +bookLocked=\u00a76This book is now locked. +bookTitleSet=\u00a76Title of the book set to {0}. +broadcast=\u00a7r\u00a76[\u00a74Broadcast\u00a76]\u00a7a {0} +buildAlert=\u00a74You are not permitted to build. +bukkitFormatChanged=Bukkit version format changed. Version not checked. +burnMsg=\u00a76You set\u00a7c {0} \u00a76on fire for\u00a7c {1} seconds\u00a76. +canTalkAgain=\u00a76You can now talk again. +cannotStackMob=\u00a74You do not have permission to stack multiple mobs. +cantFindGeoIpDB=Can''t find GeoIP database\! +cantReadGeoIpDB=Failed to read GeoIP database\! +cantSpawnItem=\u00a74You are not allowed to spawn the item\u00a7c {0}\u00a74. +chatTypeAdmin=[A] +chatTypeLocal=[L] +chatTypeSpy=[Spy] +cleaned=Userfiles Cleaned. +cleaning=Cleaning userfiles. +commandFailed=Command {0} failed\: +commandHelpFailedForPlugin=Error getting help for plugin\: {0} +commandNotLoaded=\u00a74Command {0} is improperly loaded. +compassBearing=\u00a76Bearing\: {0} ({1} degrees). +configFileMoveError=Failed to move config.yml to backup location. +configFileRenameError=Failed to rename temp file to config.yml. +connectedPlayers=\u00a76Connected players\u00a7r +connectionFailed=Failed to open connection. +cooldownWithMessage=\u00a74Cooldown\: {0} +corruptNodeInConfig=\u00a74Notice\: Your configuration file has a corrupt {0} node. +couldNotFindTemplate=\u00a74Could not find template {0} +creatingConfigFromTemplate=Creating config from template\: {0} +creatingEmptyConfig=Creating empty config\: {0} +creative=creative +currency={0}{1} +currentWorld=\u00a76Current World\:\u00a7c {0} +day=day +days=days +defaultBanReason=The Ban Hammer has spoken\! +deleteFileError=Could not delete file\: {0} +deleteHome=\u00a76Home\u00a7c {0} \u00a76has been removed. +deleteJail=\u00a76Jail\u00a7c {0} \u00a76has been removed. +deleteWarp=\u00a76Warp\u00a7c {0} \u00a76has been removed. +deniedAccessCommand=\u00a7c{0} \u00a74was denied access to command. +denyBookEdit=\u00a74You cannot unlock this book. +denyChangeAuthor=\u00a74You cannot change the author of this book. +denyChangeTitle=\u00a74You cannot change the title of this book. +depth=\u00a76You are at sea level. +depthAboveSea=\u00a76You are\u00a7c {0} \u00a76block(s) above sea level. +depthBelowSea=\u00a76You are\u00a7c {0} \u00a76block(s) below sea level. +destinationNotSet=Destination not set\! +disableUnlimited=\u00a76Disabled unlimited placing of\u00a7c {0} \u00a76for {1}. +disabled=disabled +disabledToSpawnMob=\u00a74Spawning this mob was disabled in the config file. +distance=\u00a76Distance\: {0} +dontMoveMessage=\u00a76Teleportation will commence in\u00a7c {0}\u00a76. Don''t move. +downloadingGeoIp=Downloading GeoIP database... this might take a while (country\: 0.6 MB, city\: 20MB) +duplicatedUserdata=Duplicated userdata\: {0} and {1}. +durability=\u00a76This tool has \u00a7c{0}\u00a76 uses left. +editBookContents=\u00a7eYou may now edit the contents of this book. +enableUnlimited=\u00a76Giving unlimited amount of\u00a7c {0} \u00a76to \u00a7c{1}\u00a76. +enabled=enabled +enchantmentApplied=\u00a76The enchantment\u00a7c {0} \u00a76has been applied to your item in hand. +enchantmentNotFound=\u00a74Enchantment not found\! +enchantmentPerm=\u00a74You do not have the permission for\u00a7c {0}\u00a74. +enchantmentRemoved=\u00a76The enchantment\u00a7c {0} \u00a76has been removed from your item in hand. +enchantments=\u00a76Enchantments\:\u00a7r {0} +errorCallingCommand=Error calling the command /{0} +errorWithMessage=\u00a7cError\:\u00a74 {0} +essentialsHelp1=The file is broken and Essentials can''t open it. Essentials is now disabled. If you can''t fix the file yourself, go to http\://tiny.cc/EssentialsChat +essentialsHelp2=The file is broken and Essentials can''t open it. Essentials is now disabled. If you can''t fix the file yourself, either type /essentialshelp in game or go to http\://tiny.cc/EssentialsChat +essentialsReload=\u00a76Essentials reloaded\u00a7c {0}. +exp=\u00a7c{0} \u00a76has\u00a7c {1} \u00a76exp (level\u00a7c {2}\u00a76) and needs\u00a7c {3} \u00a76more exp to level up. +expSet=\u00a7c{0} \u00a76now has\u00a7c {1} \u00a76exp. +extinguish=\u00a76You extinguished yourself. +extinguishOthers=\u00a76You extinguished {0}\u00a76. +failedToCloseConfig=Failed to close config {0}. +failedToCreateConfig=Failed to create config {0}. +failedToWriteConfig=Failed to write config {0}. +false=\u00a74false\u00a7r +feed=\u00a76Your appetite was sated. +feedOther=\u00a76You satiated the appetite of \u00a7c{0}\u00a76. +fileRenameError=Renaming file {0} failed\! +fireworkColor=\u00a74Invalid firework charge parameters inserted, must set a color first. +fireworkEffectsCleared=\u00a76Removed all effects from held stack. +fireworkSyntax=\u00a76Firework parameters\:\u00a7c color\: [fade\:] [shape\:] [effect\:]\n\u00a76To use multiple colors/effects, separate values with commas\: \u00a7cred,blue,pink\n\u00a76Shapes\:\u00a7c star, ball, large, creeper, burst \u00a76Effects\:\u00a7c trail, twinkle. +flyMode=\u00a76Set fly mode\u00a7c {0} \u00a76for {1}\u00a76. +flying=flying +foreverAlone=\u00a74You have nobody to whom you can reply. +fullStack=\u00a74You already have a full stack. +gameMode=\u00a76Set game mode\u00a7c {0} \u00a76for \u00a7c{1}\u00a76. +gcWorld=\u00a76{0} "\u00a7c{1}\u00a76"\: \u00a7c{2}\u00a76 chunks, \u00a7c{3}\u00a76 entities, \u00a7c{4}\u00a76 tiles. +gcfree=\u00a76Free memory\:\u00a7c {0} MB. +gcmax=\u00a76Maximum memory\:\u00a7c {0} MB. +gctotal=\u00a76Allocated memory\:\u00a7c {0} MB. +geoIpUrlEmpty=GeoIP download url is empty. +geoIpUrlInvalid=GeoIP download url is invalid. +geoipJoinFormat=\u00a76Player \u00a7c{0} \u00a76comes from \u00a7c{1}\u00a76. +giveSpawn=\u00a76Giving\u00a7c {0} \u00a76of\u00a7c {1} to\u00a7c {2}\u00a76. +godDisabledFor=\u00a7cdisabled\u00a76 for\u00a7c {0} +godEnabledFor=\u00a7aenabled\u00a76 for\u00a7c {0} +godMode=\u00a76God mode\u00a7c {0}\u00a76. +groupDoesNotExist=\u00a74There''s no one online in this group\! +groupNumber=\u00a7c{0}\u00a7f online, for the full list\:\u00a7c /{1} {2} +hatArmor=\u00a74You cannot use this item as a hat\! +hatEmpty=\u00a74You are not wearing a hat. +hatFail=\u00a74You must have something to wear in your hand. +hatPlaced=\u00a76Enjoy your new hat\! +hatRemoved=\u00a76Your hat has been removed. +haveBeenReleased=\u00a76You have been released. +heal=\u00a76You have been healed. +healDead=\u00a74You cannot heal someone who is dead\! +healOther=\u00a76Healed\u00a7c {0}\u00a76. +helpConsole=To view help from the console, type ?. +helpFrom=\u00a76Commands from {0}\: +helpLine=\u00a76/{0}\u00a7r\: {1} +helpMatching=\u00a76Commands matching "\u00a7c{0}\u00a76"\: +helpOp=\u00a74[HelpOp]\u00a7r \u00a76{0}\:\u00a7r {1} +helpPlugin=\u00a74{0}\u00a7r\: Plugin Help\: /help {1} +holdBook=\u00a74You are not holding a writable book. +holdFirework=\u00a74You must be holding a firework to add effects. +holdPotion=\u00a74You must be holding a potion to apply effects to it. +holeInFloor=\u00a74Hole in floor\! +homeSet=\u00a76Home set to current location. +homes=\u00a76Homes\:\u00a7r {0} +hour=hour +hours=hours +ignoredList=\u00a76Ignored\:\u00a7r {0} +ignorePlayer=\u00a76You ignore player\u00a7c {0} \u00a76from now on. +illegalDate=Illegal date format. +infoChapter=\u00a76Select chapter\: +infoChapterPages=\u00a7e ---- \u00a76{0} \u00a7e--\u00a76 Page \u00a7c{1}\u00a76 of \u00a7c{2} \u00a7e---- +infoPages=\u00a7e ---- \u00a76{2} \u00a7e--\u00a76 Page \u00a7c{0}\u00a76/\u00a7c{1} \u00a7e---- +infoUnknownChapter=\u00a74Unknown chapter. +insufficientFunds=\u00a74Insufficient funds available. +invalidCharge=\u00a74Invalid charge. +invalidFireworkFormat=\u00a74The option \u00a7c{0} \u00a74is not a valid value for \u00a7c{1}\u00a74. +invalidHome=\u00a74Home\u00a7c {0} \u00a74doesn''t exist\! +invalidHomeName=\u00a74Invalid home name\! +invalidMob=\u00a74Invalid mob type. +invalidNumber=Invalid Number. +invalidPotion=\u00a74Invalid Potion. +invalidPotionMeta=\u00a74Invalid potion meta\: \u00a7c{0}\u00a74. +invalidSignLine=\u00a74Line\u00a7c {0} \u00a74on sign is invalid. +invalidWarpName=\u00a74Invalid warp name\! +invalidWorld=\u00a74Invalid world. +is=is +itemCannotBeSold=\u00a74That item cannot be sold to the server. +itemMustBeStacked=\u00a74Item must be traded in stacks. A quantity of 2s would be two stacks, etc. +itemNames=\u00a76Item short names\:\u00a7r {0} +itemNotEnough1=\u00a74You do not have enough of that item to sell. +itemNotEnough2=\u00a76If you meant to sell all of your items of that type, use /sell itemname. +itemNotEnough3=\u00a76/sell itemname -1 will sell all but one item, etc. +itemSellAir=You really tried to sell Air? Put an item in your hand. +itemSold=\u00a7aSold for \u00a7c{0} \u00a7a({1} {2} at {3} each). +itemSoldConsole=\u00a7a{0} \u00a7asold {1} for \u00a7a{2} \u00a7a({3} items at {4} each). +itemSpawn=\u00a76Giving\u00a7c {0} \u00a76of\u00a7c {1} +itemType=\u00a76Item\:\u00a7c {0} \u00a76-\u00a7c {1} +itemsCsvNotLoaded=Could not load items.csv\! +jailAlreadyIncarcerated=\u00a74Person is already in jail\:\u00a7c {0} +jailMessage=\u00a74You do the crime, you do the time. +jailNotExist=\u00a74That jail does not exist. +jailReleased=\u00a76Player \u00a7c{0}\u00a76 unjailed. +jailReleasedPlayerNotify=\u00a76You have been released\! +jailSentenceExtended=\u00a76Jail time extended to \u00a7c{0}\u00a76. +jailSet=\u00a76Jail\u00a7c {0} \u00a76has been set. +jumpError=\u00a74That would hurt your computer''s brain. +kickDefault=Kicked from server. +kickExempt=\u00a74You cannot kick that person. +kickedAll=\u00a74Kicked all players from server. +kill=\u00a76Killed\u00a7c {0}\u00a76. +killExempt=\u00a74You cannot kill \u00a7c{0}\u00a74. +kitCost=\ \u00a77\u00a7o({0})\u00a7r +kitError2=\u00a74That kit is improperly defined. Contact an administrator. +kitError=\u00a74There are no valid kits. +kitGiveTo=\u00a76Giving kit\u00a7c {0}\u00a76 to \u00a7c{1}\u00a76. +kitInvFull=\u00a74Your inventory was full, placing kit on the floor. +kitNotFound=\u00a74That kit does not exist. +kitOnce=\u00a74You can''t use that kit again. +kitReceive=\u00a76Received kit\u00a7c {0}\u00a76. +kitTimed=\u00a74You can''t use that kit again for another\u00a7c {0}\u00a74. +kits=\u00a76Kits\:\u00a7r {0} +leatherSyntax=\u00a76Leather color syntax\: color\:,, eg\: color\:255,0,0. +lightningSmited=\u00a76Thou hast been smitten\! +lightningUse=\u00a76Smiting\u00a7c {0} +listAfkTag=\u00a77[AFK]\u00a7r +listAmount=\u00a76There are \u00a7c{0}\u00a76 out of maximum \u00a7c{1}\u00a76 players online. +listAmountHidden=\u00a76There are \u00a7c{0}\u00a76/{1}\u00a76 out of maximum \u00a7c{2}\u00a76 players online. +listGroupTag=\u00a76{0}\u00a7r\: \u00a7r +listHiddenTag=\u00a77[HIDDEN]\u00a7r +loadWarpError=\u00a74Failed to load warp {0}. +localFormat=[L]<{0}> {1} +mailClear=\u00a76To mark your mail as read, type\u00a7c /mail clear\u00a76. +mailCleared=\u00a76Mail cleared\! +mailSent=\u00a76Mail sent\! +markMailAsRead=\u00a76To mark your mail as read, type\u00a7c /mail clear\u00a76. +markedAsAway=\u00a76You are now marked as away. +markedAsNotAway=\u00a76You are no longer marked as away. +matchingIPAddress=\u00a76The following players previously logged in from that IP address\: +maxHomes=\u00a74You cannot set more than\u00a7c {0} \u00a74homes. +mayNotJail=\u00a74You may not jail that person\! +me=me +minute=minute +minutes=minutes +missingItems=\u00a74You do not have \u00a7c{0}x {1}\u00a74. +mobSpawnError=\u00a74Error while changing mob spawner. +mobSpawnLimit=Mob quantity limited to server limit. +mobSpawnTarget=\u00a74Target block must be a mob spawner. +mobsAvailable=\u00a76Mobs\:\u00a7r {0} +moneyRecievedFrom=\u00a7a{0} has been received from {1}. +moneySentTo=\u00a7a{0} has been sent to {1}. +month=month +months=months +moreThanZero=\u00a74Quantities must be greater than 0. +moveSpeed=\u00a76Set {0} speed to\u00a7c {1} \u00a76for \u00a7c{2}\u00a76. +msgFormat=\u00a76[\u00a7c{0}\u00a76 -> \u00a7c{1}\u00a76] \u00a7r{2} +multipleCharges=\u00a74You cannot apply more than one charge to this firework. +multiplePotionEffects=\u00a74You cannot apply more than one effect to this potion. +muteExempt=\u00a74You may not mute that player. +muteNotify=\u00a7c{0} \u00a76has muted player \u00a7c{1}\u00a76. +mutedPlayer=\u00a76Player\u00a7c {0} \u00a76muted. +mutedPlayerFor=\u00a76Player\u00a7c {0} \u00a76muted for\u00a7c {1}\u00a76. +mutedUserSpeaks={0} tried to speak, but is muted. +nearbyPlayers=\u00a76Players nearby\:\u00a7r {0} +negativeBalanceError=\u00a74User is not allowed to have a negative balance. +nickChanged=\u00a76Nickname changed. +nickDisplayName=\u00a74You have to enable change-displayname in Essentials config. +nickInUse=\u00a74That name is already in use. +nickNamesAlpha=\u00a74Nicknames must be alphanumeric. +nickNoMore=\u00a76You no longer have a nickname. +nickSet=\u00a76Your nickname is now \u00a7c{0}\u00a76. +nickTooLong=\u00a74That nickname is too long. +noAccessCommand=\u00a74You do not have access to that command. +noAccessPermission=\u00a74You do not have permission to access that \u00a7c{0}\u00a74. +noBreakBedrock=\u00a74You are not allowed to destroy bedrock. +noDestroyPermission=\u00a74You do not have permission to destroy that \u00a7c{0}\u00a74. +noDurability=\u00a74This item does not have a durability. +noGodWorldWarning=\u00a74Warning\! God mode in this world disabled. +noHelpFound=\u00a74No matching commands. +noHomeSetPlayer=\u00a76Player has not set a home. +noIgnored=\u00a76You are not ignoring anyone. +noKitPermission=\u00a74You need the \u00a7c{0}\u00a74 permission to use that kit. +noKits=\u00a76There are no kits available yet. +noMail=\u00a76You do not have any mail. +noMatchingPlayers=\u00a76No matching players found. +noMetaFirework=\u00a74You do not have permission to apply firework meta. +noMetaPerm=\u00a74You do not have permission to apply \u00a7c{0}\u00a74 meta to this item. +noNewMail=\u00a76You have no new mail. +noPendingRequest=\u00a74You do not have a pending request. +noPerm=\u00a74You do not have the \u00a7c{0}\u00a74 permission. +noPermToSpawnMob=\u00a74You don''t have permission to spawn this mob. +noPlacePermission=\u00a74You do not have permission to place a block near that sign. +noPotionEffectPerm=\u00a74You do not have permission to apply potion effect \u00a7c{0} \u00a74to this potion. +noPowerTools=\u00a76You have no power tools assigned. +noWarpsDefined=\u00a76No warps defined. +none=none +notAllowedToQuestion=\u00a74You are not authorized to use question. +notAllowedToShout=\u00a74You are not authorized to shout. +notEnoughExperience=\u00a74You do not have enough experience. +notEnoughMoney=\u00a74You do not have sufficient funds. +notFlying=not flying +notRecommendedBukkit=\u00a74* \! * Bukkit version is not the recommended build for Essentials. +notSupportedYet=Not supported yet. +nothingInHand=\u00a74You have nothing in your hand. +now=now +nuke=\u00a75May death rain upon them. +numberRequired=A number goes there, silly. +onlyDayNight=/time only supports day/night. +onlyPlayerSkulls=\u00a74You can only set the owner of player skulls (\u00a7c397\:3\u00a74). +onlyPlayers=\u00a74Only in-game players can use \u00a7c{0}\u00a74. +onlySunStorm=\u00a74/weather only supports sun/storm. +orderBalances=\u00a76Ordering balances of\u00a7c {0} \u00a76users, please wait... +oversizedTempban=\u00a74You may not ban a player for this period of time. +pTimeCurrent=\u00a7c{0}\u00a76''s time is\u00a7c {1}\u00a76. +pTimeCurrentFixed=\u00a7c{0}\u00a76''s time is fixed to\u00a7c {1}\u00a76. +pTimeNormal=\u00a7c{0}\u00a76''s time is normal and matches the server. +pTimeOthersPermission=\u00a74You are not authorized to set other players'' time. +pTimePlayers=\u00a76These players have their own time\:\u00a7r +pTimeReset=\u00a76Player time has been reset for\: \u00a7c{0} +pTimeSet=\u00a76Player time is set to \u00a7c{0}\u00a76 for\: \u00a7c{1}. +pTimeSetFixed=\u00a76Player time is fixed to \u00a7c{0}\u00a76 for\: \u00a7c{1}. +pWeatherCurrent=\u00a7c{0}\u00a76''s weather is\u00a7c {1}\u00a76. +pWeatherInvalidAlias=\u00a74Invalid weather type +pWeatherNormal=\u00a7c{0}\u00a76''s weather is normal and matches the server. +pWeatherOthersPermission=\u00a74You are not authorized to set other players'' weather. +pWeatherPlayers=\u00a76These players have their own weather\:\u00a7r +pWeatherReset=\u00a76Player weather has been reset for\: \u00a7c{0} +pWeatherSet=\u00a76Player weather is set to \u00a7c{0}\u00a76 for\: \u00a7c{1}. +pendingTeleportCancelled=\u00a74Pending teleportation request cancelled. +playerBanIpAddress=\u00a76Player\u00a7c {0} \u00a76banned IP address\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerBanned=\u00a76Player\u00a7c {0} \u00a76banned\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerInJail=\u00a74Player is already in jail\u00a7c {0}\u00a74. +playerJailed=\u00a76Player\u00a7c {0} \u00a76jailed. +playerJailedFor=\u00a76Player\u00a7c {0} \u00a76jailed for {1}. +playerKicked=\u00a76Player\u00a7c {0} \u00a76kicked {1} for {2}. +playerMuted=\u00a76You have been muted\! +playerMutedFor=\u00a76You have been muted for\u00a7c {0}. +playerNeverOnServer=\u00a74Player\u00a7c {0} \u00a74was never on this server. +playerNotFound=\u00a74Player not found. +playerUnbanIpAddress=\u00a76Player\u00a7c {0} \u00a76unbanned IP\: {1}. +playerUnbanned=\u00a76Player\u00a7c {0} \u00a76unbanned\u00a7c {1}. +playerUnmuted=\u00a76You have been unmuted. +pong=Pong\! +posPitch=\u00a76Pitch\: {0} (Head angle) +posX=\u00a76X\: {0} (+East <-> -West) +posY=\u00a76Y\: {0} (+Up <-> -Down) +posYaw=\u00a76Yaw\: {0} (Rotation) +posZ=\u00a76Z\: {0} (+South <-> -North) +possibleWorlds=\u00a76Possible worlds are the numbers \u00a7c0\u00a76 through \u00a7c{0}\u00a76. +potions=\u00a76Potions\:\u00a7r {0}\u00a76. +powerToolAir=\u00a74Command can''t be attached to air. +powerToolAlreadySet=\u00a74Command \u00a7c{0}\u00a74 is already assigned to \u00a7c{1}\u00a74. +powerToolAttach=\u00a7c{0}\u00a76 command assigned to {1}. +powerToolClearAll=\u00a76All powertool commands have been cleared. +powerToolList=\u00a76Item \u00a7c{1} \u00a76has the following commands\: \u00a7c{0}\u00a76. +powerToolListEmpty=\u00a74Item \u00a7c{0} \u00a74has no commands assigned. +powerToolNoSuchCommandAssigned=\u00a74Command \u00a7c{0}\u00a74 has not been assigned to \u00a7c{1}\u00a74. +powerToolRemove=\u00a76Command \u00a7c{0}\u00a76 removed from \u00a7c{1}\u00a76. +powerToolRemoveAll=\u00a76All commands removed from \u00a7c{0}\u00a76. +powerToolsDisabled=\u00a76All of your power tools have been disabled. +powerToolsEnabled=\u00a76All of your power tools have been enabled. +questionFormat=\u00a72[Question]\u00a7r {0} +readNextPage=\u00a76Type\u00a7c /{0} {1} \u00a76to read the next page. +recipe=\u00a76Recipe for \u00a7c{0}\u00a76 (\u00a7c{1}\u00a76 of \u00a7c{2}\u00a76) +recipeBadIndex=There is no recipe by that number. +recipeFurnace=\u00a76Smelt\: \u00a7c{0}\u00a76. +recipeGrid=\u00a7c{0}X \u00a76| \u00a7{1}X \u00a76| \u00a7{2}X +recipeGridItem=\u00a7c{0}X \u00a76is \u00a7c{1} +recipeMore=\u00a76Type /{0} \u00a7c{1}\u00a76 to see other recipes for \u00a7c{2}\u00a76. +recipeNone=No recipes exist for {0}. +recipeNothing=nothing +recipeShapeless=\u00a76Combine \u00a7c{0} +recipeWhere=\u00a76Where\: {0} +removed=\u00a76Removed\u00a7c {0} \u00a76entities. +repair=\u00a76You have successfully repaired your\: \u00a7c{0}\u00a76. +repairAlreadyFixed=\u00a74This item does not need repairing. +repairEnchanted=\u00a74You are not allowed to repair enchanted items. +repairInvalidType=\u00a74This item cannot be repaired. +repairNone=\u00a74There were no items that needed repairing. +requestAccepted=\u00a76Teleport request accepted. +requestAcceptedFrom=\u00a7c{0} \u00a76accepted your teleport request. +requestDenied=\u00a76Teleport request denied. +requestDeniedFrom=\u00a7c{0} \u00a76denied your teleport request. +requestSent=\u00a76Request sent to\u00a7c {0}\u00a76. +requestTimedOut=\u00a74Teleport request has timed out. +requiredBukkit=\u00a76* \! * You need at least build {0} of CraftBukkit, download it from http\://dl.bukkit.org/downloads/craftbukkit/ +resetBal=\u00a76Balance has been reset to \u00a7c{0} \u00a76for all online players. +resetBalAll=\u00a76Balance has been reset to \u00a7c{0} \u00a76for all players. +returnPlayerToJailError=\u00a74Error occurred when trying to return player\u00a7c {0} \u00a74to jail\: \u00a7c{1}\u00a74\! +runningPlayerMatch=\u00a76Running search for players matching ''\u00a7c{0}\u00a76'' (this could take a little while). +second=second +seconds=seconds +seenOffline=\u00a76Player\u00a7c {0} \u00a76has been \u00a74offline\u00a76 since \u00a7c{1}\u00a76. +seenOnline=\u00a76Player\u00a7c {0} \u00a76has been \u00a7aonline\u00a76 since \u00a7c{1}\u00a76. +serverFull=Server is full\! +serverTotal=\u00a76Server Total\:\u00a7c {0} +setBal=\u00a7aYour balance was set to {0}. +setBalOthers=\u00a7aYou set {0}\u00a7a''s balance to {1}. +setSpawner=\u00a76Changed spawner type to\u00a7c {0}\u00a76. +sheepMalformedColor=\u00a74Malformed color. +shoutFormat=\u00a76[Shout]\u00a7r {0} +signFormatFail=\u00a74[{0}] +signFormatSuccess=\u00a71[{0}] +signFormatTemplate=[{0}] +signProtectInvalidLocation=\u00a74You are not allowed to create sign here. +similarWarpExist=\u00a74A warp with a similar name already exists. +slimeMalformedSize=\u00a74Malformed size. +socialSpy=\u00a76SocialSpy for \u00a7c{0}\u00a76\: \u00a7c{1} +soloMob=\u00a74That mob likes to be alone. +spawnSet=\u00a76Spawn location set for group\u00a7c {0}\u00a76. +spawned=spawned +sudoExempt=\u00a74You cannot sudo this user. +sudoRun=\u00a76Forcing\u00a7c {0} \u00a76to run\:\u00a7r /{1} +suicideMessage=\u00a76Goodbye cruel world... +suicideSuccess=\u00a76Player \u00a7c{0} \u00a76took their own life. +survival=survival +takenFromAccount=\u00a7a{0} has been taken from your account. +takenFromOthersAccount=\u00a7a{0} taken from {1}\u00a7a account. New balance\: {2}. +teleportAAll=\u00a76Teleport request sent to all players... +teleportAll=\u00a76Teleporting all players... +teleportAtoB=\u00a7c{0}\u00a76 teleported you to \u00a7c{1}\u00a76. +teleportDisabled=\u00a7c{0} \u00a74has teleportation disabled. +teleportHereRequest=\u00a7c{0}\u00a76 has requested that you teleport to them. +teleportNewPlayerError=\u00a74Failed to teleport new player\! +teleportRequest=\u00a7c{0}\u00a76 has requested to teleport to you. +teleportRequestTimeoutInfo=\u00a76This request will timeout after\u00a7c {0} seconds\u00a76. +teleportTop=\u00a76Teleporting to top. +teleportationCommencing=\u00a76Teleportation commencing... +teleportationDisabled=\u00a76Teleportation \u00a7cdisabled\u00a76. +teleportationDisabledFor=\u00a76Teleportation \u00a7cdisabled \u00a76for \u00a7c{0}\u00a76. +teleportationEnabled=\u00a76Teleportation \u00a7cenabled\u00a76. +teleportationEnabledFor=\u00a76Teleportation \u00a7cenabled \u00a76for \u00a7c{0}\u00a76. +teleporting=\u00a76Teleporting... +teleportToPlayer=\u00a76Teleporting to \u00a7c{0}\u00a76. +tempBanned=\u00a7cYou have been temporarily banned for {0}\:\n\u00a7r{2} +tempbanExempt=\u00a74You may not tempban that player. +thunder=\u00a76You\u00a7c {0} \u00a76thunder in your world. +thunderDuration=\u00a76You\u00a7c {0} \u00a76thunder in your world for\u00a7c {1} \u00a76seconds. +timeBeforeHeal=\u00a74Time before next heal\:\u00a7c {0}\u00a76. +timeBeforeTeleport=\u00a74Time before next teleport\:\u00a7c {0}\u00a76. +timeFormat=\u00a7c{0}\u00a76 or \u00a7c{1}\u00a76 or \u00a7c{2}\u00a76 +timeSetPermission=\u00a74You are not authorized to set the time. +timeWorldCurrent=\u00a76The current time in\u00a7c {0} \u00a76is \u00a7c{1}\u00a76. +timeWorldSet=\u00a76The time was set to\u00a7c {0} \u00a76in\: \u00a7c{1}\u00a76. +totalWorthAll=\u00a7aSold all items and blocks for a total worth of \u00a7c{1}\u00a7a. +totalWorthBlocks=\u00a7aSold all blocks for a total worth of \u00a7c{1}\u00a7a. +tps=\u00a76Current TPS \= {0} +tradeSignEmpty=\u00a74The trade sign has nothing available for you. +tradeSignEmptyOwner=\u00a74There is nothing to collect from this trade sign. +treeFailure=\u00a74Tree generation failure. Try again on grass or dirt. +treeSpawned=\u00a76Tree spawned. +true=\u00a7atrue\u00a7r +typeTpaccept=\u00a76To teleport, type \u00a7c/tpaccept\u00a76. +typeTpdeny=\u00a76To deny this request, type \u00a7c/tpdeny\u00a76. +typeWorldName=\u00a76You can also type the name of a specific world. +unableToSpawnMob=\u00a74Unable to spawn mob. +unignorePlayer=\u00a76You are not ignoring player\u00a7c {0} \u00a76anymore. +unknownItemId=\u00a74Unknown item id\:\u00a7r {0}\u00a74. +unknownItemInList=\u00a74Unknown item {0} in {1} list. +unknownItemName=\u00a74Unknown item name\: {0}. +unlimitedItemPermission=\u00a74No permission for unlimited item \u00a7c{0}\u00a74. +unlimitedItems=\u00a76Unlimited items\:\u00a7r +unmutedPlayer=\u00a76Player\u00a7c {0} \u00a76unmuted. +unvanishedReload=\u00a74A reload has forced you to become visible. +upgradingFilesError=Error while upgrading the files. +uptime=\u00a76Uptime\:\u00a7c {0} +userAFK=\u00a77{0} \u00a75is currently AFK and may not respond. +userDoesNotExist=\u00a74The user\u00a7c {0} \u00a74does not exist. +userIsAway=\u00a77* {0} \u00a77is now AFK. +userIsNotAway=\u00a77* {0} \u00a77is no longer AFK. +userJailed=\u00a76You have been jailed\! +userUnknown=\u00a74Warning\: The user ''\u00a7c{0}\u00a74'' has never joined this server. +userdataMoveBackError=Failed to move userdata/{0}.tmp to userdata/{1}\! +userdataMoveError=Failed to move userdata/{0} to userdata/{1}.tmp\! +usingTempFolderForTesting=Using temp folder for testing\: +vanished=\u00a76You are now completely invisible to normal users, and hidden from in-game commands. +versionMismatch=\u00a74Version mismatch\! Please update {0} to the same version. +versionMismatchAll=\u00a74Version mismatch\! Please update all Essentials jars to the same version. +voiceSilenced=\u00a76Your voice has been silenced\! +walking=walking +warpDeleteError=\u00a74Problem deleting the warp file. +warpList={0} +warpListPermission=\u00a74You do not have permission to list warps. +warpNotExist=\u00a74That warp does not exist. +warpOverwrite=\u00a74You cannot overwrite that warp. +warpSet=\u00a76Warp\u00a7c {0} \u00a76set. +warpUsePermission=\u00a74You do not have permission to use that warp. +warpingTo=\u00a76Warping to\u00a7c {0}\u00a76. +warps=\u00a76Warps\:\u00a7r {0} +warpsCount=\u00a76There are\u00a7c {0} \u00a76warps. Showing page \u00a7c{1} \u00a76of \u00a7c{2}\u00a76. +weatherStorm=\u00a76You set the weather to \u00a7cstorm\u00a76 in\u00a7c {0}\u00a76. +weatherStormFor=\u00a76You set the weather to \u00a7cstorm\u00a76 in\u00a7c {0} \u00a76for {1} seconds. +weatherSun=\u00a76You set the weather to \u00a7csun\u00a76 in\u00a7c {0}\u00a76. +weatherSunFor=\u00a76You set the weather to \u00a7csun\u00a76 in\u00a7c {0} \u00a76for {1} seconds. +whoisAFK=\u00a76 - AFK\:\u00a7r {0} +whoisBanned=\u00a76 - Banned\:\u00a7r {0} +whoisExp=\u00a76 - Exp\:\u00a7r {0} (Level {1}) +whoisFly=\u00a76 - Fly mode\:\u00a7r {0} ({1}) +whoisGamemode=\u00a76 - Gamemode\:\u00a7r {0} +whoisGeoLocation=\u00a76 - Location\:\u00a7r {0} +whoisGod=\u00a76 - God mode\:\u00a7r {0} +whoisHealth=\u00a76 - Health\:\u00a7r {0}/20 +whoisIPAddress=\u00a76 - IP Address\:\u00a7r {0} +whoisJail=\u00a76 - Jail\:\u00a7r {0} +whoisLocation=\u00a76 - Location\:\u00a7r ({0}, {1}, {2}, {3}) +whoisMoney=\u00a76 - Money\:\u00a7r {0} +whoisMuted=\u00a76 - Muted\:\u00a7r {0} +whoisNick=\u00a76 - Nick\:\u00a7r {0} +whoisOp=\u00a76 - OP\:\u00a7r {0} +whoisTop=\u00a76 \=\=\=\=\=\= WhoIs\:\u00a7c {0} \u00a76\=\=\=\=\=\= +worth=\u00a7aStack of {0} worth \u00a7c{1}\u00a7a ({2} item(s) at {3} each) +worthMeta=\u00a7aStack of {0} with metadata of {1} worth \u00a7c{2}\u00a7a ({3} item(s) at {4} each) +worthSet=\u00a76Worth value set +year=year +years=years +youAreHealed=\u00a76You have been healed. +youHaveNewMail=\u00a76You have\u00a7c {0} \u00a76messages\! Type \u00a7c/mail read\u00a76 to view your mail. +whoisHunger=\u00a76 - Hunger\:\u00a7r {0}/20 (+{1} saturation) +kitDelay=\u00a7m{0}\u00a7r +giveSpawnFailure=\u00a74Not enough space, \u00a7c{0} \u00a7c{1} \u00a74was lost. +noKitGroup=\u00a74You do not have access to this kit. +inventoryClearingFromAll=\u00a76Clearing the inventory of all users... +inventoryClearingAllItems=\u00a76Cleared all inventory items from {0}\u00a76. +inventoryClearingAllArmor=\u00a76Cleared all inventory items and armor from {0}\u00a76. +inventoryClearingAllStack=\u00a76Cleared all\u00a7c {0} \u00a76from {1}\u00a76. +inventoryClearingStack=\u00a76Removed\u00a7c {0} \u00a76of\u00a7c {1} \u00a76from {2}\u00a76. +inventoryClearFail=\u00a74Player {0} \u00a74does not have\u00a7c {1} \u00a74of\u00a7c {2}\u00a74. +localNoOne= +totalSellableAll=\u00a7aThe total worth of all sellable items and blocks is \u00a7c{1}\u00a7a. +totalSellableBlocks=\u00a7aThe total worth of all sellable blocks is \u00a7c{1}\u00a7a. +radiusTooBig=\u00a74Radius is too big\! Maximum radius is {0}. +isIpBanned=\u00a76IP \u00a7c{0} \u00a76is banned. +mobDataList=\u00a76Valid mob data\:\u00a7r {0} +vanish=\u00a76Vanish for {0}\u00a76\: {1} +noLocationFound=\u00a74No valid location found. +coordsKeyword={0}, {1}, {2} +banExemptOffline=\u00a74You may not ban offline players. +tempbanExemptOffline=\u00a74You may not tempban offline players. +mayNotJailOffline=\u00a74You may not jail offline players. +muteExemptOffline=\u00a74You may not mute offline players. +ignoreExempt=\u00a74You may not ignore that player. +unsafeTeleportDestination=\u00a74The teleport destination is unsafe and teleport-safety is disabled. +noMetaJson=JSON Metadata is not supported in this version of Bukkit. +maxMoney=\u00a74This transaction would exceed the balance limit for this account. +skullChanged=\u00a76Skull changed to \u00a7c{0}\u00a76. +alphaNames=\u00a74Player names can only contain letters, numbers and underscores. +givenSkull=\u00a76You have been given the skull of \u00a7c{0}\u00a76. +noPermissionSkull=\u00a74You do not have permission to modify that skull. +teleportInvalidLocation=Value of coordinates cannot be over 30000000 +invalidSkull=\u00a74Please hold a player skull. +weatherInvalidWorld=World named {0} not found\! +gameModeInvalid=\u00a74You need to specify a valid player/mode. +mailTooLong=\u00a74Mail message too long. Try to keep it below 1000 characters. +mailDelay=Too many mails have been sent within the last minute. Maximum\: {0} +seenAccounts=\u00a76Player has also been known as\:\u00a7c {0} +unableToSpawnItem=\u00a74Cannot spawn \u00a7c{0}\u00a74, this is not a spawnable item. +itemsConverted=\u00a76Converted all items into blocks. +itemsNotConverted=\u00a74You have no items that can be converted into blocks. +mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\: +mailMessage={0} +whoisTempBanned=\u00a76 - Ban expires:\u00a7r {0} +playerTempBanned=\u00a76Player \u00a7c{0}\u00a76 temporarily banned \u00a7c{1}\u00a76 for \u00a7c{2}\u00a76: \u00a7c{3}\u00a76. +mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1} diff --git a/Essentials/src/messages_es.properties b/Essentials/src/messages_es.properties new file mode 100644 index 0000000000..74992540f1 --- /dev/null +++ b/Essentials/src/messages_es.properties @@ -0,0 +1,558 @@ +#X-Generator: crowdin.net +#version: TeamCity +# Single quotes have to be doubled: '' +# Translations start here +# by: +action=\u00a75* {0} \u00a75{1} +addedToAccount=\u00a7a{0} han sido agregados a tu cuenta. +addedToOthersAccount=\u00a7a{0} han sidos agregados a la cuenta de {1}\u00a7a. Nuevo presupuesto\: {2} +adventure=aventura +alertBroke=rompi\u00f3\: +alertFormat=\u00a73[{0}] \u00a7f {1} \u00a76 {2} en\: {3} +alertPlaced=colocado\: +alertUsed=usado\: +antiBuildBreak=\u00a74No puedes romper\u00a7c {0} \u00a74bloques aqu\u00ed. +antiBuildCraft=\n\n\u00a74No tienes permiso para crear\u00a7c {0}\u00a74. +antiBuildDrop=\u00a74No puedes tirar \u00a7c {0}\u00a74. +antiBuildInteract=\u00a74No puedes interactuar con\u00a7c {0}\u00a74. +antiBuildPlace=\u00a74No puedes colocar \u00a7c{0} \u00a74aqu\u00ed. +antiBuildUse=\u00a74No puedes usar \u00a7c{0}\u00a74. +autoAfkKickReason=Has sido echado por estar inactivo m\u00e1s de {0} minuto/s. +backAfterDeath=\u00a76Usa el comando \u00a7c/back \u00a76para volver al lugar de tu muerte. +backUsageMsg=\u00a76Volviendo a la ubicaci\u00f3n anterior. +backupDisabled=\u00a74No se ha configurado un c\u00f3digo externo de copias de seguridad. +backupFinished=Copia de seguridad completada. +backupStarted=\u00a76Copia de seguridad empezada. +balance=\u00a7aDinero\:\u00a7c {0} +balanceOther=\u00a7aDinero de {0} \u00a7a\:\u00a7c {1} +balanceTop=\u00a76Ranking de econom\u00edas ({0}) +banExempt=\u00a74No puedes banear a ese jugador. +banFormat=\u00a74Baneado\: \u00a7r {0} +bed=\u00a7ocama\u00a7r +bedMissing=\u00a7cTu cama no esta, se encuentra obstru\u00edda o no esta segura +bedNull=\u00a7mcama\u00a7r +bedSet=\u00a76Cama establecida como lugar de aparicion\! +bigTreeFailure=\u00a7cError al generar el \u00e1rbol grande. Prueba de nuevo en tierra, tierra h\u00fameda o hierba. +bigTreeSuccess=\u00a76\u00c1rbol grande generado. +blockList=\u00a76Essentials ha cedido los siguientes comandos a otros plugins\: +bookAuthorSet=\u00a76Ahora el autor de este libro es {0}. +bookLocked=\u00a76El libro ha sido bloqueado. +bookTitleSet=\u00a76Ahora el t\u00edtulo del libro es {0}. +broadcast=\u00a7r\u00a76[\u00a74Difundido\u00a76]\u00a7a {0} +buildAlert=\u00a74No tienes permisos para construir. +bukkitFormatChanged=Formato de la versi\u00f3n de Bukkit cambiado. Versi\u00f3n no comprobada. +burnMsg=\u00a77Has puesto {0} en fuego durante {1} segundos. +canTalkAgain=\u00a77Ya puedes hablar de nuevo. +cannotStackMob=\u00a74No tienes permiso para apilar tantos mobs. +cantFindGeoIpDB=No se puede encontrar la base de datos del Geo IP. +cantReadGeoIpDB=\u00a1Error al leer la base de datos de GeoIP\! +cantSpawnItem=\u00a74No tienes acceso para producir el \u00edtem\u00a7c {0}\u00a74. +chatTypeAdmin=[A] +chatTypeLocal=[L] +chatTypeSpy=[Esp\u00eda] +cleaned=Archivos de usuarios limpiados. +cleaning=Limpiando archivos de usuario. +commandFailed=Comando {0} fallido\: +commandHelpFailedForPlugin=Error al obtener ayuda para el plugin\: {0} +commandNotLoaded=\u00a74El comando {0} no est\u00e1 cargado correctamente. +compassBearing=\u00a76Transporte\: {0} ({1} grados). +configFileMoveError=Error al mover config.yml a la carpeta de la copia de seguridad. +configFileRenameError=Error al renombrar archivo temp a config.yml. +connectedPlayers=\u00a76Jugadores conectados\u00a7r +connectionFailed=No se ha podido abrir la conexion. +cooldownWithMessage=\u00a74Tiempo restante\:\u00a76 {0} +corruptNodeInConfig=\u00a74Advertencia\: Tu archivo de configuraci\u00f3n tiene un nodo {0} incorrecto. +couldNotFindTemplate=\u00a74No se puede encontrar la plantilla\u00a76 {0} +creatingConfigFromTemplate=Creando configuraci\u00f3n desde la plantilla\: {0} +creatingEmptyConfig=Creando configuraci\u00f3n vac\u00eda\: {0} +creative=creativo +currency={0}{1} +currentWorld=\u00a77Mundo actual\: {0} +day=d\u00eda +days=d\u00edas +defaultBanReason=\u00a1Baneado por mal comportamiento\! +deleteFileError=No se puede eliminar archivo\: {0} +deleteHome=\u00a77El hogar\u00a7c {0} \u00a77ha sido eliminado. +deleteJail=\u00a77La c\u00e1rcel {0} \u00a77ha sido eliminada. +deleteWarp=\u00a76El warp\u00a7c {0} \u00a76ha sido borrado. +deniedAccessCommand=\u00a7c{0} \u00a74ha denegado el acceso al comando. +denyBookEdit=\u00a74No puedes desbloquear este libro. +denyChangeAuthor=\u00a74No puedes cambiar el autor de este libro. +denyChangeTitle=\u00a74No puedes cambiar el t\u00edtulo de este libro. +depth=\u00a77Te encuentras en el nivel del mar. +depthAboveSea=\u00a76Est\u00e1s\u00a7c {0} \u00a76bloque(s) por encima del mar. +depthBelowSea=\u00a76Est\u00e1s a\u00a7c {0} \u00a76bloque(s) por debajo del nivel del mar. +destinationNotSet=\u00a1Destino no establecido\! +disableUnlimited=\u00a76La colocaci\u00f3n ilimitada de \u00a7c{0} \u00a76ha sido desactivada para {1}\u00a76. +disabled=desactivado +disabledToSpawnMob=\u00a74El spawn de este mob est\u00e1 deshabilitado en la configuraci\u00f3n. +distance=\u00a76Distancia\: {0} +dontMoveMessage=\u00a76El teletransporte comenzar\u00e1 en\u00a7c {0}\u00a76. Por favor, no te muevas. +downloadingGeoIp=Descargando base de datos de GeoIP... Puede tardar unos minutos (pa\u00edses\: 0.6 MB, ciudades\: 20 MB) +duplicatedUserdata=Datos de usuario duplicados\: {0} y {1} +durability=\u00a77Esta herramienta tiene \u00a7c{0}\u00a77 usos restantes. +editBookContents=\u00a7eAhora puedes editar los contenidos de este libro. +enableUnlimited=\u00a76Dando cantidad ilimitada de\u00a7c {0} \u00a76a \u00a7c{1}\u00a76. +enabled=activado +enchantmentApplied=\u00a76El encantamiento\u00a7c {0} \u00a76fue aplicado al objeto de tu mano. +enchantmentNotFound=\u00a74\u00a1No se ha encontrado \u00e9ste encantamiento\! +enchantmentPerm=\u00a74No tienes permisos suficientes para\u00a7c {0}\u00a74. +enchantmentRemoved=\u00a77El encantamiento {0} \u00a77ha sido eliminado del objeto de tu mano. +enchantments=\u00a77Encantamientos\: {0} +errorCallingCommand=Error al ejecutar el comando /{0} +errorWithMessage=\u00a7cError\:\u00a74 {0} +essentialsHelp1=Archivo corrupto, no es posible abrirlo. Essentials est\u00e1 ahora desactivado. Si no puedes arreglar el archivo, ve a http\://tiny.cc/EssentialsChat +essentialsHelp2=Archivo corrupto, no es posible abrirlo. Essentials est\u00e1 ahora desactivado. Si no puedes arreglar el archivo, escribe /essentialshelp dentro del juego o ve a http\://tiny.cc/EssentialsChat +essentialsReload=\u00a76Essentials ha sido recargado. La versi\u00f3n es\u00a7c {0}. +exp=\u00a7c{0} \u00a76tiene\u00a7c {1} \u00a76 de exp. (nivel\u00a7c {2}\u00a76) y necesita\u00a7c {3} \u00a76de exp para subir su nivel. +expSet=\u00a7c{0} \u00a76ahora tiene\u00a7c {1} \u00a76de exp. +extinguish=\u00a76Te has suicidado. +extinguishOthers=\u00a77Has matado a {0}. +failedToCloseConfig=Error al cerrar configuraci\u00f3n {0}. +failedToCreateConfig=Error al crear configuraci\u00f3n {0}. +failedToWriteConfig=Error al escribir configuraci\u00f3n {0}. +false=\u00a74no\u00a7r +feed=\u00a76Tu apetito est\u00e1 satisfecho. +feedOther=\u00a76Satisficiste el apetito de \u00a7c{0}\u00a76. +fileRenameError=Error al renombrar el archivo {0} +fireworkColor=\u00a74Par\u00e1metros inv\u00e1lidos. Inserta primero el color. +fireworkEffectsCleared=\u00a77Borrados todos los efectos. +fireworkSyntax=\u00a77Uso del cohete\:\u00a7c color\: [color\:] [forma\:] [efecto de explosi\u00f3n\:]\n\u00a77Para usar m\u00faltiples colores/efectos, separa los nombres mediante comas\: \u00a7cred,blue,pink\n\u00a77Formas\:\u00a7c star, ball, large, creeper, burst \u00a76Efectos\:\u00a7c trail, twinkle. +flyMode=\u00a76Modo de vuelo\u00a7c {0} \u00a76para\u00a7c {1}\u00a76. +flying=volando +foreverAlone=\u00a7cNo tienes nadie a quien puedas responder. +fullStack=\u00a74Ya tienes el stack completo. +gameMode=\u00a76El modo de juego de\u00a7c {1} \u00a76ha sido cambiado a\u00a7c {0}\u00a76. +gcWorld=\u00a76{0} "\u00a7c{1}\u00a76"\: \u00a7c{2}\u00a76 chunks, \u00a7c{3}\u00a76 entidades, \u00a7c{4}\u00a76 tiles. +gcfree=\u00a76Memoria libre\:\u00a7c {0} MB. +gcmax=\u00a76Memoria m\u00e1xima\:\u00a7c {0} MB. +gctotal=\u00a76Memoria asignada\:\u00a7c {0} MB. +geoIpUrlEmpty=El link para descargar GeoIP esta vacio. +geoIpUrlInvalid=El link para descargar GeoIP es inv\u00e1lido. +geoipJoinFormat=\u00a76El jugador \u00a7c{0} \u00a76viene de \u00a7c{1}\u00a76. +giveSpawn=\u00a77Se ha dado\u00a7c {0} \u00a76de\u00a7c {1} a\u00a7c {2}\u00a76. +godDisabledFor=\u00a7cdeshabilitado\u00a76 para\u00a7c {0} +godEnabledFor=\u00a7aactivado\u00a76 para\u00a7c {0} +godMode=\u00a77Modo de dios \u00a7c{0}\u00a77. +groupDoesNotExist=\u00a74Nadie conectado en este grupo\! +groupNumber=\u00a7c{0}\u00a7f conectados, para ver la lista completa\:\u00a7c /{1} {2} +hatArmor=\u00a7c\u00a1No puedes usar este \u00edtem como sombrero\! +hatEmpty=\u00a74No est\u00e1s usando sombrero. +hatFail=\u00a74Necesitas tener un \u00edtem en tu mano para poder usarlo de sombrero. +hatPlaced=\u00a7eDisfruta de tu nuevo sombrero\! +hatRemoved=\u00a7eTu sombrero ha sido borrado. +haveBeenReleased=\u00a77Has sido liberado. +heal=\u00a76Has sido curado. +healDead=\u00a74\u00a1Est\u00e1 muerto, no puedes curarlo\! +healOther=\u00a77Has curado a {0}. +helpConsole=Para obtener ayuda de la consola, escribe ?. +helpFrom=\u00a76Comandos de {0}\: +helpLine=\u00a76/{0}\u00a7r\: {1} +helpMatching=\u00a77Comandos que coinciden con "{0}"\: +helpOp=\u00a74[Ayuda de Op]\u00a7r \u00a76{0}\:\u00a7r {1} +helpPlugin=\u00a74{0}\u00a7r\: Ayuda para el plugin\: /help {1} +holdBook=\u00a74No tienes un libro para escribir. +holdFirework=\u00a74No tienes algun cohete al que agregar efectos. +holdPotion=\u00a74No tienes pociones a las que agregar efectos. +holeInFloor=\u00a74\u00a1No hay suelo en el punto de aparici\u00f3n\! +homeSet=\u00a77Hogar establecido. +homes=\u00a76Hogares\:\u00a7r {0} +hour=hora +hours=horas +ignoredList=\u00a76Ignorado\:\u00a7r {0} +ignorePlayer=A partir de ahora ignoras al jugador {0}. +illegalDate=Formato de fecha ilegal. +infoChapter=\u00a76Seleccionar cap\u00edtulo\: +infoChapterPages=\u00a7e ---- \u00a77{0} \u00a7e--\u00a77 P\u00e1gina \u00a7c{1}\u00a77 de \u00a7c{2} \u00a7e---- +infoPages=\u00a7e ---- \u00a77{2} \u00a7e--\u00a77 P\u00e1gina \u00a74{0}\u00a77/\u00a74{1} \u00a7e---- +infoUnknownChapter=\u00a74Desconocido. +insufficientFunds=\u00a74Te falta dinero. +invalidCharge=\u00a74Carga no v\u00e1lida. +invalidFireworkFormat=\u00a74La opci\u00f3n \u00a7c{0} \u00a74no es un valor v\u00e1lido para \u00a7c{1}\u00a74. +invalidHome=\u00a74\u00a1El hogar\u00a7c {0} \u00a74no existe\! +invalidHomeName=\u00a74\u00a1Nombre de hogar inv\u00e1lido\! +invalidMob=\u00a74Tipo de mob inv\u00e1lido. +invalidNumber=N\u00famero inv\u00e1lido. +invalidPotion=\u00a74Poci\u00f3n inv\u00e1lida. +invalidPotionMeta=\u00a74Opciones de poci\u00f3n inv\u00e1lidas\: \u00a7c{0}\u00a74. +invalidSignLine=La l\u00ednea {0} en el cartel no es v\u00e1lida. +invalidWarpName=\u00a74\u00a1Nombre del Warp no reconocido\! +invalidWorld=\u00a74Mundo erroneo o no cargado. +is=es +itemCannotBeSold=\u00a74\u00a1Ese objeto no puede ser vendido al servidor\! +itemMustBeStacked=El objeto tiene que ser intercambiado en montones. Una cantidad de 2s ser\u00edan dos montones, etc. +itemNames=\u00a76Nombre corto del \u00edtem\:\u00a7r {0} +itemNotEnough1=\u00a74No tienes la suficiente cantidad del \u00edtem para venderlo. +itemNotEnough2=\u00a76Si quieres vender todos tus \u00edtems que sean como ese, escribe /sell nombre_del_\u00edtem (en ingl\u00e9s). +itemNotEnough3=\u00a77/sell nombredeobjeto -1 vendera todos excepto un objeto, etc. +itemSellAir=\u00bf\u00bf\u00bfRealmente intentas vender AIRE??? \u00a1\u00a1\u00a1Pon un objeto en tu mano\!\!\! +itemSold=\u00a77Vendido por \u00a7c {0} \u00a77 ({1} {2} a {3} cada uno). +itemSoldConsole={0} Vendido {1} para\u00a77 {2} \u00a77({3} objetos a {4} cada uno) +itemSpawn=\u00a76Dando {0} de {1} +itemType=\u00a76Objeto\:\u00a7c {0} \u00a76-\u00a7c {1} +itemsCsvNotLoaded=\u00a1No se ha podido cargar el archivo items.csv\! +jailAlreadyIncarcerated=\u00a74Ese jugador ya est\u00e1 en la c\u00e1rcel\:\u00a7c {0} +jailMessage=\u00a7c\u00a1Por el crimen hacer, a la c\u00e1rcel ir\u00e1s\! +jailNotExist=\u00a74Esa c\u00e1rcel no existe. +jailReleased=\u00a76El jugador \u00a7c{0}\u00a76 ha salido de la c\u00e1rcel. +jailReleasedPlayerNotify=\u00a77\u00a1Has sido liberado\! +jailSentenceExtended=Tiempo en la c\u00e1rcel extendido a {0} +jailSet=\u00a76La c\u00e1rcel {0} ha sido creada. +jumpError=\u00a74Eso da\u00f1ar\u00eda el cerebro de tu ordenador. +kickDefault=Has sido expulsado del servidor\! Nota\: Revisa tu comportamiento +kickExempt=\u00a74No puedes expulsar a ese jugador. +kickedAll=\u00a74Todos los jugadores han sido expulsados. +kill=\u00a77Has matado a\u00a7c {0}\u00a77. +killExempt=\u00a74No puedes matar a \u00a7c{0}\u00a74. +kitCost=\ \u00a77\u00a7o({0})\u00a7r +kitError2=\u00a74Este kit est\u00e1 mal creado. Por favor, contacta con un administrador. +kitError=\u00a7cNo hay ning\u00fan kit v\u00e1lido. +kitGiveTo=\u00a76Dando kit\u00a7c {0}\u00a76 a \u00a7c{1}\u00a76. +kitInvFull=\u00a74Tu preciado inventario no tiene hueco para este kit. El kit se lanzar\u00e1 al suelo. +kitNotFound=\u00a74Ese kit no existe. +kitOnce=\u00a74No puedes volver a usar este kit. +kitReceive=\u00a76Kit\u00a7c {0}\u00a76 recibido. +kitTimed=\u00a7c No puedes usar ese kit de nuevo para otro {0}. +kits=\u00a77Kits disponibles\: {0} +leatherSyntax=\u00a76Color sintax\: color\:,, ejemplo\: color\:255,0,0. +lightningSmited=\u00a76\u00a1Has sido golpeado m\u00e1gicamente\! +lightningUse=\u00a76Golpeando al jugador\u00a7c {0} +listAfkTag=\u00a78[Ausente]\u00a7r +listAmount=\u00a79Hay \u00a7c{0}\u00a79 jugadores de un m\u00e1ximo de \u00a7c{1}\u00a79 jugadores \u00a72en linea\u00a79. +listAmountHidden=\u00a76Hay \u00a7c{0}\u00a76/{1}\u00a76 jugadores de un m\u00e1ximo de \u00a7c{2}\u00a76 jugadores conectados. +listGroupTag=\u00a76{0}\u00a7r\: \u00a7r +listHiddenTag=\u00a78[Oculto]\u00a7r +loadWarpError=\u00a74Error al cargar el Warp {0}. +localFormat=[L]<{0}> {1} +mailClear=\u00a76Para marcar tu correo como le\u00eddo, escribe\u00a7c /mail clear\u00a76. +mailCleared=\u00a76\u00a1El correo ha sido limpiado\! +mailSent=\u00a76\u00a1El correo ha sido enviado\! +markMailAsRead=\u00a76Para marcar tu correo como le\u00eddo, escribe\u00a7c /mail clear\u00a76. +markedAsAway=\u00a77Has sido anunciado como AFK (Away-From-Keyboard/Ausente o Lejos del teclado). +markedAsNotAway=\u00a77Ya no estas AFK. +matchingIPAddress=\u00a76Los siguientes jugadores entraron previamente con la IP\: +maxHomes=\u00a74No puedes tener m\u00e1s de\u00a7c {0} \u00a74hogares. +mayNotJail=\u00a7cNo puedes encarcelar a esa persona. +me=yo +minute=minuto +minutes=minutos +missingItems=\u00a74No tienes \u00a7c{0}x {1}\u00a74. +mobSpawnError=Error al cambiar la localizaci\u00f3n para el nacimiento de los mobs. +mobSpawnLimit=Cantidad de criaturas (mobs) limitadas por el l\u00edmite del servidor. +mobSpawnTarget=El bloque seleccionado ser\u00e1 el lugar donde van a aparecer los mobs. +mobsAvailable=\u00a76Mobs\:\u00a7r {0} +moneyRecievedFrom=\u00a7a{0} ha sido recibido de {1} +moneySentTo=\u00a7a{0} ha sido enviado a {1} +month=mes +months=meses +moreThanZero=Las cantidades han de ser mayores que 0. +moveSpeed=\u00a76Establecida velocidad de {0} a\u00a7c {1} \u00a76durante \u00a7c{2}\u00a76. +msgFormat=\u00a76[\u00a7c{0}\u00a76 -> \u00a7c{1}\u00a76] \u00a7r{2} +multipleCharges=\u00a74Solo puedes aplicar una carga a este cohete. +multiplePotionEffects=\u00a74No puedes aplicarle m\u00e1s de un efecto a esta poci\u00f3n. +muteExempt=\u00a7cNo puedes silenciar a ese jugador. +muteNotify=\u00a7c{0} \u00a76ha silenciado a \u00a7c{1}\u00a76. +mutedPlayer=\u00a76El jugador\u00a7c {0} \u00a76est\u00e1 silenciado. +mutedPlayerFor=\u00a76Jugador\u00a7c {0} \u00a76silenciado por\u00a7c {1}\u00a76. +mutedUserSpeaks={0} intent\u00f3 hablar, pero est\u00e1 silenciado. +nearbyPlayers=\u00a76Jugadores cercanos\:\u00a7r {0} +negativeBalanceError=\u00a74El jugador no tiene permitido tener dinero por debajo de 0$. +nickChanged=\u00a76Nick cambiado. +nickDisplayName=\u00a74Tienes que activar el cambio de nick en la configuraci\u00f3n del plugin Essentials. +nickInUse=\u00a74Ese nick ya est\u00e1 en uso. Prueba a usar otro. +nickNamesAlpha=\u00a74No puedes usar s\u00edmbolos raros. +nickNoMore=\u00a76Ya no tienes un nombre personalizado. VUELVES A SER TU. +nickSet=\u00a76Tu seud\u00f3nimo ahora es \u00a7c{0}\u00a76. +nickTooLong=\u00a74Ese nick es demasiado largo. +noAccessCommand=\u00a74No tienes permiso para ejecutar ese comando. +noAccessPermission=\u00a74No tienes permiso para interactuar con \u00a7c{0}\u00a74. +noBreakBedrock=No puedes romper piedra base. +noDestroyPermission=\u00a74No tienes permiso para destruir ese \u00a7c{0}\u00a74. +noDurability=\u00a74Este \u00edtem no tiene durabilidad. +noGodWorldWarning=\u00a74\u00a1Advertencia\! El modo de dios ha sido desactivado en este mundo. +noHelpFound=\u00a74No hay comandos relacionados. +noHomeSetPlayer=\u00a76El jugador no ha establecido hogares. +noIgnored=\u00a76No est\u00e1s ignorando a nadie. +noKitPermission=\u00a7cNecesitas el permiso \u00a74{0}\u00a7c para usar ese kit. +noKits=\u00a77No hay kits disponibles a\u00fan. +noMail=\u00a76No tienes correo nuevo. +noMatchingPlayers=\u00a76No se encontr\u00f3 al jugador buscado. +noMetaFirework=\u00a74No tienes permiso para usar los efectos de los fuegos artificiales. +noMetaPerm=\u00a74No tienes permiso para aplicar \u00a7c{0}\u00a74 efectos a este \u00edtem. +noNewMail=\u00a77No tienes correo nuevo. +noPendingRequest=\u00a74No tienes peticiones pendientes. +noPerm=\u00a74No tienes el permiso \u00a7c{0}\u00a74. +noPermToSpawnMob=\u00a74No tienes permiso para generar esa criatura. +noPlacePermission=\u00a74No tienes permiso para colocar un bloque junto a eso. +noPotionEffectPerm=\u00a74No tienes permiso para aplicar el efecto\u00a7c {0} \u00a74a esta poci\u00f3n. +noPowerTools=\u00a76No tienes ninguna herramienta el\u00e9ctrica asignada. +noWarpsDefined=\u00a76No hay warps disponibles. +none=ninguno +notAllowedToQuestion=\u00a74No est\u00e1s autorizado para hacer una pregunta. +notAllowedToShout=\u00a74No est\u00e1s autorizado para gritar. +notEnoughExperience=\u00a74No tienes la experiencia necesaria. +notEnoughMoney=\u00a74No tienes dinero suficiente. +notFlying=no esta volando +notRecommendedBukkit=\u00a74* \! * La versi\u00f3n de bukkit no es la recomendada para esta versi\u00f3n del plugin Essentials. +notSupportedYet=No soportado por el momento. +nothingInHand=\u00a7cNo tienes nada en tu mano. +now=ahora +nuke=\u00a75Que la muerta afecte al que no despierte. +numberRequired=Es necesario un n\u00famero, amigo. +onlyDayNight=\u00a76/time \u00a74\u00fanicamente funciona con los valores \u00a76Day\u00a74 o \u00a76Night\u00a74 (d\u00eda/noche). +onlyPlayerSkulls=\u00a74Solo puedes indicar el propietario de las calaveras de jugadores (\u00a7c397\:3\u00a74). +onlyPlayers=\u00a74Solo jugadores dentro del juego pueden usar \u00a7c{0}\u00a74. +onlySunStorm=\u00a7c/weather \u00a74solo acepta los valores \u00a7csun \u00a74o \u00a7cstorm \u00a74(\u00a76sol\u00a74/\u00a76tormenta\u00a74). +orderBalances=Creando un ranking de {0} usuarios segun su presupuesto, espera... +oversizedTempban=\u00a74No puedes banear por ese periodo de tiempo. +pTimeCurrent=\u00a76La hora de \u00a7c{0} es\u00a7c {1}\u00a76. +pTimeCurrentFixed=\u00a7c{0}\u00a76 la hora ha sido corregida a\u00a7c {1}\u00a76. +pTimeNormal=\u00a7c{0} \u00a77\: el tiempo es normal (coincide con el del servidor). +pTimeOthersPermission=\u00a74No tienes permitido cambiar la hora de otros jugadores. +pTimePlayers=\u00a77Estos jugadores tienen establecida su propia hora\:\u00a7r +pTimeReset=La hora del usuario ha sido reiniciada a las\: \u00a7e{0} +pTimeSet=La hora del jugador ha sido cambiada a\: \u00a73{0}\u00a7f for\: \u00a7e{1}. +pTimeSetFixed=La hora del jugador ha sido fijada a las\: \u00a73{0}\u00a7f for\: \u00a7e{1}. +pWeatherCurrent=\u00a76El clima de\u00a7c {0}\u00a76 es\u00a7c {1}\u00a76. +pWeatherInvalidAlias=\u00a74Tipo de clima inv\u00e1lido +pWeatherNormal=\u00a76El clima de \u00a7c{0} \u00a76es normal y coincide con el servidor. +pWeatherOthersPermission=\u00a74No est\u00e1s autorizado para cambiar el clima de otros jugadores. +pWeatherPlayers=\u00a77Jugadores que tienen su propio clima\: \u00a7r +pWeatherReset=\u00a76Clima reseteado para\: \u00a7c{0} +pWeatherSet=\u00a76Clima establecido en \u00a7c{0}\u00a76 para\: \u00a7c{1}. +pendingTeleportCancelled=\u00a74Petici\u00f3n de teletransporte cancelada. +playerBanIpAddress=\u00a76Player\u00a7c {0} \u00a76banned IP address\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerBanned=\u00a7c{0} \u00a76 ha sido baneado\:\u00a7c {1} \u00a76por \u00a7c{2}\u00a76. +playerInJail=\u00a74El jugador\u00a7c {0}\u00a74 ya est\u00e1 en la c\u00e1rcel. +playerJailed=\u00a77Jugador {0} encarcelado. +playerJailedFor=\u00a77El jugador {0} ha sido encarcelado durante {1}. +playerKicked=\u00a7c\u00a1El jugador {0} ha echado a {1}\u00a7c\! \u00a77Motivo\: &r{2}\u00a77. +playerMuted=\u00a77Has sido silenciado. +playerMutedFor=\u00a77Has sido silenciado durante {0}. +playerNeverOnServer=\u00a74\u00a1El jugador \u00a7c{0} \u00a74nunca ha entrado al servidor\! +playerNotFound=\u00a74Jugador no encontrado. +playerUnbanIpAddress=\u00a76La IP {1} ha sido desbaneada por\u00a7c {0}. +playerUnbanned=\u00a7c{1} \u00a76ha sido desbaneado por\u00a7c {0}\u00a76. +playerUnmuted=\u00a76Ya no est\u00e1s silenciado. +pong=\u00a1PONG\! +posPitch=\u00a77Giro\: {0} (\u00c1ngulo de cabeza) +posX=\u00a77X\: {0} (+Este <-> -Oeste) +posY=\u00a77Y\: {0} (+Arriba <-> -abajo) +posYaw=\u00a77Yaw\: {0} (Rotaci\u00f3n) +posZ=\u00a77Z\: {0} (+Sur <-> -Norte) +possibleWorlds=\u00a76Posibles mundos son los n\u00fameros desde el \u00a7c0\u00a76 hasta el \u00a7c{0}\u00a76. +potions=\u00a77Pociones\:\u00a7r {0}\u00a76. +powerToolAir=El comando no se puede ejecutar en el aire. +powerToolAlreadySet=\u00a74El comando \u00a7c{0}\u00a74 ya est\u00e1 asignado a \u00a7c{1}\u00a74. +powerToolAttach=\u00a77El comando \u00a7c{0}\u00a77 ha sido asignado a {1}\u00a77. +powerToolClearAll=\u00a77Todos los comandos de la herramienta el\u00e9ctrica han sido eliminados. +powerToolList=\u00a76El \u00edtem \u00a7c{1} \u00a76tiene asignados los comandos\: \u00a7c{0}\u00a76. +powerToolListEmpty=\u00a74El \u00edtem\u00a7c {0} \u00a74no tiene comandos asignados. +powerToolNoSuchCommandAssigned=\u00a74El comando \u00a7c{0}\u00a74 no ha sido asignado a \u00a7c{1}\u00a74. +powerToolRemove=\u00a76Comando \u00a7c{0}\u00a76 borrado de \u00a7c{1}\u00a76. +powerToolRemoveAll=\u00a76Todos los comandos borrados de \u00a7c{0}\u00a76. +powerToolsDisabled=\u00a77Todas tus herramientas de poder han sido desactivadas. +powerToolsEnabled=\u00a77Todas tus herramientas de poder han sido activadas. +questionFormat=\u00a72[Pregunta]\u00a7r {0} +readNextPage=\u00a77Escribe\u00a7c /{0} {1} \u00a77para leer la p\u00e1gina siguiente. +recipe=\u00a76Receta para \u00a7c{0}\u00a76 (\u00a7c{1}\u00a76 de \u00a7c{2}\u00a76) +recipeBadIndex=No hay ning\u00fan crafteo con ese n\u00famero. +recipeFurnace=\u00a76Fundir\: \u00a7c{0}\u00a76. +recipeGrid=\u00a7c{0}X \u00a76| \u00a7{1}X \u00a76| \u00a7{2}X +recipeGridItem=\u00a7c{0}X \u00a76es \u00a7c{1} +recipeMore=\u00a76Escribe /{0} \u00a7c{1}\u00a76 para ver otros crafteos de \u00a7c{2}\u00a76. +recipeNone=No existen crafteos para {0} +recipeNothing=nada +recipeShapeless=\u00a77Combinar \u00a7c{0} +recipeWhere=\u00a77Donde\: {0} +removed=\u00a76Eliminadas\u00a7c {0} \u00a76entidades. +repair=\u00a76Has reparado exit\u00f3samente tu\: \u00a7c{0}\u00a76. +repairAlreadyFixed=\u00a74Este \u00edtem no necesita reparaci\u00f3n. +repairEnchanted=\u00a74No tienes permiso para reparar un \u00edtem encantado. +repairInvalidType=\u00a74Ese \u00edtem no puede ser reparado. +repairNone=\u00a74No hay \u00edtems que necesiten ser reparados. +requestAccepted=\u00a76Petici\u00f3n de teletransporte aceptada. +requestAcceptedFrom=\u00a7c{0} \u00a76ha aceptado tu teletransportaci\u00f3n. +requestDenied=\u00a76Petici\u00f3n de teletransporte denegada. +requestDeniedFrom=\u00a7c{0} \u00a76ha denegado tu teletransportaci\u00f3n. +requestSent=\u00a76La petici\u00f3n ha sido enviada a\u00a7c {0}\u00a76. +requestTimedOut=\u00a74El tiempo de la solicitud de teletransporte se ha agotado. +requiredBukkit=\u00a75* \! * \u00a7cNecesitas al menos el build {0} de CraftBukkit, descargalo desde \u00a7bhttp\://dl.bukkit.org/downloads/craftbukkit/ +resetBal=\u00a76Dinero reestablecido a \u00a7c{0} \u00a76a todos los jugadores conectados. +resetBalAll=\u00a76Dinero reestablecido a \u00a7c{0} \u00a76a todos los jugadores. +returnPlayerToJailError=\u00a74\u00a1Ha ocurrido un error al intentar enviar al jugador\u00a7c {0} \u00a74a la c\u00e1rcel\: \u00a7c{1}\u00a74\! +runningPlayerMatch=\u00a77Ejecutando busqueda de jugadores ''\u00a7c{0}\u00a77'' (puede tardar) +second=segundo +seconds=segundos +seenOffline=\u00a76El jugador\u00a7c {0} \u00a76ha estado \u00a74desconectado\u00a76 desde \u00a7c{1}\u00a76. +seenOnline=\u00a76El jugador\u00a7c {0} \u00a76ha estado \u00a7aconectado\u00a76 desde \u00a7c{1}\u00a76. +serverFull=\u00a1El servidor est\u00e1 lleno\! +serverTotal=\u00a76Total\:\u00a7c {0} +setBal=\u00a7aEconom\u00eda personal establecida en {0}. +setBalOthers=\u00a7aLa economia de {0}\u00a7a ha sido establecida a {1}. +setSpawner=\u00a7Cambiado tipo de generador a\u00a7c {0}\u00a76. +sheepMalformedColor=\u00a74Color malformado. +shoutFormat=\u00a76[Mundo]\u00a7r {0} +signFormatFail=\u00a74[{0}] +signFormatSuccess=\u00a71[{0}] +signFormatTemplate=[{0}] +signProtectInvalidLocation=\u00a74No puedes poner carteles en este sitio. +similarWarpExist=\u00a74Ya existe un warp con ese nombre. +slimeMalformedSize=\u00a74Medidas malformadas. +socialSpy=\u00a76Esp\u00eda de chat para \u00a7c{0}\u00a76\: \u00a7c{1} +soloMob=\u00a74A este mob le gusta estar solo. +spawnSet=\u00a76El lugar de aparici\u00f3n o el sitio del comando /spawn ha sido colocado para el grupo\u00a7c {0}\u00a76. +spawned=nacido +sudoExempt=\u00a74No puedes usar el comando sudo con este jugador. +sudoRun=\u00a76Forcing\u00a7c {0} \u00a76to run\:\u00a7r /{1} +suicideMessage=\u00a76Adi\u00f3s mundo cruel... +suicideSuccess=\u00a76{0} \u00a7cse ha suicidado... +survival=supervivencia +takenFromAccount=\u00a7a{0} han sido sacados de tu cuenta econ\u00f3mica. +takenFromOthersAccount=\u00a7a{0} han sido sacados de la cuenta de {1}\u00a7a. \u00a72Nuevo balance\: {2}. +teleportAAll=\u00a77Peticion de teletransporte enviada a todos los jugadores... +teleportAll=\u00a77Teletransportando a todos los jugadores... +teleportAtoB=\u00a7c{0}\u00a76 te ha teletransportado a \u00a7c{1}\u00a76. +teleportDisabled=\u00a7c{0} \u00a74tiene la teletransportaci\u00f3n desactivada. +teleportHereRequest=\u00a7c{0}\u00a76te ha pedido que te teletransportes hasta \u00e9l. +teleportNewPlayerError=\u00a74\u00a1Ha ocurrido un error al teletransportar al nuevo jugador\! +teleportRequest=\u00a7c{0}\u00a76 te ha pedido teletransportarse hasta ti. +teleportRequestTimeoutInfo=\u00a76La solicitud ser\u00e1 autom\u00e1ticamente cancelada despu\u00e9s de\u00a7c {0} segundos\u00a76. +teleportTop=\u00a76Teletransportandote hasta la cima. +teleportationCommencing=\u00a76Teletransportando... +teleportationDisabled=\u00a76Teletransporte \u00a7cdeshabilitado\u00a76. +teleportationDisabledFor=\u00a76Teletransporte \u00a7cdeshabilitado \u00a76para \u00a7c{0}\u00a76. +teleportationEnabled=\u00a76Teletransporte \u00a7chabilitado\u00a76. +teleportationEnabledFor=\u00a76Teletransporte \u00a7chabilitado \u00a76para \u00a7c{0}\u00a76. +teleporting=\u00a76Teletransportando... +teleportToPlayer=\u00a76Teletransport\u00e1ndose a \u00a7c{0}\u00a76. +tempBanned=\u00a7cYou have been temporarily banned for {0}\:\n\u00a7r{2} +tempbanExempt=\u00a74Ese jugador no puede recibir un baneo temporal tuyo. +thunder=\u00a76Has cambiado los truenos a\u00a7c {0} \u00a76en tu mundo. +thunderDuration=\u00a76Has\u00a7c {0} \u00a76una tormenta en tu mundo durante\u00a7c {1} \u00a76segundos. +timeBeforeHeal=Tiempo antes de la siguiente curacion\: {0} +timeBeforeTeleport=\u00a74Tiempo antes del pr\u00f3ximo teletransporte\:\u00a7c {0}\u00a74. +timeFormat=\u00a7c{0}\u00a76 o \u00a7c{1}\u00a76 o \u00a7c{2}\u00a76 +timeSetPermission=\u00a74No tienes permitido cambiar la hora. +timeWorldCurrent=\u00a76La hora actual en\u00a7c {0} \u00a76es \u00a7c{1}\u00a76. +timeWorldSet=\u00a76La hora ha sido establecida a\u00a7c {0} \u00a76en el mundo\: \u00a7c{1}\u00a76. +totalWorthAll=\u00a7aVendidos todos los objetos por un valor total de \u00a7c {1}\u00a7a. +totalWorthBlocks=\u00a7aVendidos todos los bloques por un total de \u00a7c{1}\u00a7a. +tps=\u00a76Ticks por segundo \= {0} +tradeSignEmpty=Esta tienda no tiene nada disponible para ti. +tradeSignEmptyOwner=No hay nada que recojer de esta tienda. +treeFailure=\u00a7cError al generar el \u00e1rbol. Prueba de nuevo en tierra, tierra h\u00fameda o hierba. +treeSpawned=\u00a77\u00c1rbol generado. +true=\u00a7as\u00ed\u00a7f +typeTpaccept=\u00a76Escribe \u00a7c/tpaccept \u00a76para aceptar el teletransporte. +typeTpdeny=\u00a76Para denegar la teletransportaci\u00f3n, escribe \u00a7c/tpdeny\u00a76. +typeWorldName=\u00a76T\u00fa tambi\u00e9n puedes escribir el nombre de un mundo espec\u00edfico. +unableToSpawnMob=\u00a74No puedes generar criaturas. +unignorePlayer=\u00a76Ya no ignoras al jugador\u00a7c {0}\u00a76. +unknownItemId=\u00a74ID de \u00edtem desconocida\:\u00a7r {0}\u00a74. +unknownItemInList=\u00a74\u00cdtem desconocido {0} en {1} lista. +unknownItemName=\u00a74Nombre de \u00edtem desconocido\: {0}. +unlimitedItemPermission=\u00a74Sin permiso para art\u00edculo ilimitado \u00a7c{0}\u00a74. +unlimitedItems=\u00a76\u00cdtems ilimitados\:\u00a7r +unmutedPlayer=\u00a76El jugador\u00a7c {0} \u00a76ya no est\u00e1 silenciado. +unvanishedReload=\u00a74Un reinicio o una recarga del servidor te ha forzado a perder la invisibilidad. +upgradingFilesError=Error mientras se actualizaban los archivos +uptime=\u00a76Tiempo encendido\:\u00a7c {0} +userAFK=\u00a77{0} \u00a75se encuentra ausente y es probable que no responda. +userDoesNotExist=El usuario {0} no existe +userIsAway=\u00a77{0} \u00a77\u00a1est\u00e1 ausente\! +userIsNotAway=\u00a77{0} \u00a77\u00a1ya no est\u00e1 ausente\! +userJailed=\u00a76\u00a1Has sido encarcelado\! +userUnknown=\u00a74Aviso\: \u00a7cel jugador \u00a74{0} \u00a7cnunca ha visitado el servidor\! +userdataMoveBackError=Error al mover userdata/{0}.tmp a userdata/{1} +userdataMoveError=Error al mover userdata/{0} a userdata/{1}.tmp +usingTempFolderForTesting=Usando carpeta temporal para pruebas\: +vanished=\u00a76Ahora eres invisible para los usuarios normales, ellos no podr\u00e1n detectarte ni con comandos. +versionMismatch=La version no coincide\! Por favor actualiza {0} a la misma version. +versionMismatchAll=La version no coincide\! Por favor actualiza todos los jars de Essentials a la misma version. +voiceSilenced=\u00a77Tu voz ha sido silenciada +walking=caminando +warpDeleteError=Problema al borrar el archivo de teletransporte. +warpList={0} +warpListPermission=\u00a7cNo tienes permiso para listar esos teletransportes. +warpNotExist=\u00a74Ese Warp no existe. +warpOverwrite=\u00a74No puedes sobrescribir ese Warp. +warpSet=\u00a76El Warp\u00a7c {0} \u00a76ha sido establecido. +warpUsePermission=\u00a74No tienes permisos para usar ese Warp. +warpingTo=\u00a76Teletransportadote a\u00a7c {0}\u00a76... +warps=\u00a76Warps\:\u00a7r {0} +warpsCount=\u00a76Hay\u00a7c {0} \u00a76puntos de teletransporte. Mostrando p\u00e1gina \u00a7c{1} \u00a76de \u00a7c{2}\u00a76. +weatherStorm=\u00a77Has establecido el tiempo como tormenta en este mundo. +weatherStormFor=\u00a77Has establecido el tiempo como tormenta en este {1} durante {0} segundos. +weatherSun=\u00a77Has establecido el tiempo como sol en este mundo. +weatherSunFor=\u00a77Has establecido el tiempo como sol en este {1} durante {0} segundos. +whoisAFK=\u00a77 - Ausente\:\u00a7r {0} +whoisBanned=\u00a77 - Baneado\:\u00a7f {0} +whoisExp=\u00a77 - Exp\:\u00a7f {0} (Nivel {1}) +whoisFly=\u00a77 - Modo volar\:\u00a7f {0} ({1}) +whoisGamemode=\u00a77 - Modo de juego\:\u00a7f {0} +whoisGeoLocation=\u00a77 - Ubicaci\u00f3n\:\u00a7f {0} +whoisGod=\u00a77 - Modo de dios\:\u00a7f {0} +whoisHealth=\u00a77 - Salud\:\u00a7f {0}/20 +whoisIPAddress=\u00a77 - Direcci\u00f3n IP\:\u00a7f {0} +whoisJail=\u00a77 - C\u00e1rcel\:\u00a7r {0} +whoisLocation=\u00a77 - Ubicaci\u00f3n\:\u00a7f ({0}, {1}, {2}, {3}) +whoisMoney=\u00a77 - Dinero\:\u00a7f {0} +whoisMuted=\u00a77 - Silenciado\:\u00a7f {0} +whoisNick=\u00a77 - Nick\:\u00a7f {0} +whoisOp=\u00a77 - OP\:\u00a7f {0} +whoisTop=\u00a76 \=\=\= Acerca de\:\u00a7c {0} \u00a76 \=\=\= +worth=\u00a77Pila de {0} con valor de \u00a7c{1}\u00a77 ({2} objeto(s) a {3} cada uno) +worthMeta=\u00a77Pila de {0} con metadata de {1} , con valor de \u00a7c{2}\u00a77 ({3} objeto(s) a {4} cada uno) +worthSet=Establecer el valor de un valor +year=a\u00f1o +years=a\u00f1os +youAreHealed=\u00a77Has sido curado. +youHaveNewMail=\u00a76\u00a1Tienes\u00a7c {0} \u00a76mensajes\! Escribe \u00a7c/mail read\u00a76 para ver los correos que no has le\u00eddo. +whoisHunger=\u00a77 - Hambre\:\u00a7r {0}/20 (+{1} saturaci\u00f3n) +kitDelay=\u00a7m{0}\u00a7r +giveSpawnFailure=\u00a74Espacio insuficiente, \u00a7c{0} \u00a7c{1} \u00a74se ha perdido. +noKitGroup=\u00a74No tienes acceso a este kit. +inventoryClearingFromAll=\u00a77Limpiando el inventario de todos los usuarios... +inventoryClearingAllItems=\u00a76Limpiado todos los objetos del inventario a\u00a76 {0}. +inventoryClearingAllArmor=\u00a7eLimpiado objetos y armaduras de\u00a7a {0}\u00a7e. +inventoryClearingAllStack=\u00a76Inventario limpiado completamente a \u00a7c {0} \u00a76de {1}\u00a76. +inventoryClearingStack=\u00a76Eliminado\u00a7c {0} \u00a76de\u00a7c {1} \u00a76de {2}\u00a76. +inventoryClearFail=\u00a74El jugador {0} \u00a74no tiene\u00a7c {1} \u00a74de\u00a7c {2}\u00a74. +localNoOne= +totalSellableAll=\u00a7aEl precio total de todos los objetos vendibles es de \u00a7c {1}. +totalSellableBlocks=\u00a7aEl valor total de la venta de todos tus bloques es \u00a7c{1}\u00a7a. +radiusTooBig=\u00a74\u00a1Radio demasiado grande\! Lo m\u00e1ximo es {0}. +isIpBanned=\u00a76IP \u00a7c{0} \u00a76est\u00e1 baneada. +mobDataList=\u00a77Datos de mobs v\u00e1lidos\:\u00a7r {0} +vanish=\u00a76Invisibilidad m\u00e1gica para {0}\u00a76\:\u00a7c {1} +noLocationFound=\u00a74Localizaci\u00f3n inv\u00e1lida. +coordsKeyword={0}, {1}, {2} +banExemptOffline=\u00a74No puedes banear a jugadores que no est\u00e1n conectados. +tempbanExemptOffline=\u00a74No puedes banear temporalmente a jugadores que no est\u00e1n conectados. +mayNotJailOffline=\u00a74No puedes encarcelar a jugadores que no est\u00e1n conectados. +muteExemptOffline=\u00a74No puedes silenciar a jugadores que no est\u00e1n conectados. +ignoreExempt=\u00a74No puedes ignorar a este jugador. +unsafeTeleportDestination=\u00a74El destino es inseguro y el teletransporte seguro est\u00e1 desactivado. +noMetaJson=El formato JSON Metadata no esta soportado para esta versi\u00f3n de bukkit. +maxMoney=\u00a74Esta transacci\u00f3n supera el l\u00edmite del dinero para esta cuenta. +skullChanged=\u00a76Calavera cambiada a \u00a7c{0}\u00a76. +alphaNames=\u00a74Los nombres de jugadores s\u00f3lo pueden contener letras, n\u00fameros y gui\u00f3n bajo. +givenSkull=\u00a76Se te ha dado el cr\u00e1neo de \u00a7c{0}\u00a76. +noPermissionSkull=\u00a74No tienes permiso de modificar ese cr\u00e1neo. +teleportInvalidLocation=El valor de las coordenadas no puede ser mayor a 30000000 +invalidSkull=\u00a74Por favor sost\u00e9n un cr\u00e1neo de un jugador. +weatherInvalidWorld=\u00a1No se ha podido encontrar el mundo llamado "{0}"\! +gameModeInvalid=\u00a74Necesitas especificar un jugador/modo v\u00e1lido. +mailTooLong=\u00a74Mensaje muy largo. Intenta mantenerte debajo de 1000 caracteres. +mailDelay=Demasiados correos han sido enviados en el \u00faltimo minuto. M\u00e1ximo\: {0} +seenAccounts=\u00a76El jugador ha sido tambi\u00e9n conocido como\:\u00a7c {0} +unableToSpawnItem=\u00a74No se puede generar \u00a7c{0}\u00a74, no es un objeto generable. +itemsConverted=\u00a76Converted all items into blocks. +itemsNotConverted=\u00a74You have no items that can be converted into blocks. +mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\: +mailMessage={0} + +whoisTempBanned=\u00a76 - Ban expires:\u00a7r {0} +playerTempBanned=\u00a76Player \u00a7c{0}\u00a76 temporarily banned \u00a7c{1}\u00a76 for \u00a7c{2}\u00a76: \u00a7c{3}\u00a76. +mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1} diff --git a/Essentials/src/messages_et.properties b/Essentials/src/messages_et.properties new file mode 100644 index 0000000000..ac9e9864d8 --- /dev/null +++ b/Essentials/src/messages_et.properties @@ -0,0 +1,558 @@ +#X-Generator: crowdin.net +#version: TeamCity +# Single quotes have to be doubled: '' +# Translations start here +# by: +action=\u00a75* {0} \u00a75{1} +addedToAccount=\u00a7a{0} on lisatud teie kontole. +addedToOthersAccount=\u00a7a{0} lisatud {1}\u00a7a kontole. Uus summa\: {2} +adventure=seiklus +alertBroke=l\u00f5hkus\: +alertFormat=\u00a73[{0}] \u00a7r {1} \u00a76 {2} asukohas\: {3} +alertPlaced=asetas\: +alertUsed=kasutas\: +antiBuildBreak=\u00a74Teil ei ole siin luba lammutada\u00a7c {0} \u00a74plokke. +antiBuildCraft=\u00a74Teil ei ole luba valmistada\u00a7c {0}\u00a74. +antiBuildDrop=\u00a74Teil ei ole luba maha visata\u00a7c {0}\u00a74. +antiBuildInteract=\u00a74Teil ei ole luba suhelda\u00a7c {0}\u00a74''iga. +antiBuildPlace=\u00a74Teil ei ole luba siia asetada\u00a7c {0} \u00a74. +antiBuildUse=\u00a74Teil ei ole luba kasutada\u00a7c {0}\u00a74. +autoAfkKickReason=Teid kickiti, sest olite eemal rohkem kui {0} minutit. +backAfterDeath=\u00a76Kasuta k\u00e4sku /back, et oma surmapaigale naasta. +backUsageMsg=\u00a76Tagasi viimine eelmisesse asukohta. +backupDisabled=\u00a74V\u00e4line backup skript ei ole konfigureeritud. +backupFinished=\u00a76Varukoopia on valmis. +backupStarted=\u00a76Varukoopia tegemine alustatud. +balance=\u00a7aRaha\:\u00a7c {0} +balanceOther=\u00a7aM\u00e4ngijal {0}\u00a7a on raha\:\u00a7c {1} +balanceTop=\u00a76Top rikkaimad({0}) +banExempt=\u00a74Sa ei saa blokeerida seda m\u00e4ngijat. +banFormat=\u00a74Blokeeritud\:\n\u00a7r{0} +bed=\u00a7ovoodi\u00a7r +bedMissing=\u00a74Sinu voodi on kas m\u00e4\u00e4ramata, kadunud v\u00f5i takistatud. +bedNull=\u00a7mvoodi\u00a7r +bedSet=\u00a76Voodikoht m\u00e4\u00e4ratud\! +bigTreeFailure=\u00a74Suure puu generatsiooni viga. Proovige uuesti muru v\u00f5i mulla peal. +bigTreeSuccess=\u00a76Suur puu on tekitatud. +blockList=\u00a76Essentials lootis j\u00e4rgnevad k\u00e4sud teisele pluginale\: +bookAuthorSet=\u00a76Raamatu autoriks on m\u00e4\u00e4ratud {0}. +bookLocked=\u00a76See raamat on n\u00fc\u00fcd lukus. +bookTitleSet=\u00a76Raamatu pealkirjaks on m\u00e4\u00e4ratud "{0}". +broadcast=\u00a7r\u00a76[\u00a74Teade\u00a76]\u00a7a {0} +buildAlert=\u00a74Teil ei ole luba ehitada. +bukkitFormatChanged=Bukkit versiooni formaat muudetud. Versioon ei ole kontrollitud. +burnMsg=\u00a76S\u00fc\u00fctasid m\u00e4ngija\u00a7c {0} \u00a76p\u00f5lema\u00a7c {1} sekundiks\u00a76. +canTalkAgain=\u00a76Sa saad j\u00e4lle r\u00e4\u00e4kida. +cannotStackMob=\u00a74Sul ei ole luba kihistada mitmeid elukaid. +cantFindGeoIpDB=Ei leia GeoIP andmebaasi\! +cantReadGeoIpDB=Tekkis viga lugedes GeoIP andmebaasi\! +cantSpawnItem=\u00a74Sul ei ole luba tekitada eset\u00a7c {0}\u00a74. +chatTypeAdmin=[A] +chatTypeLocal=[L] +chatTypeSpy=[Spioon] +cleaned=Kasutajafailid puhastatud. +cleaning=Kasutajafailide puhastus. +commandFailed=K\u00e4sk {0} eba\u00f5nnestus\: +commandHelpFailedForPlugin=Viga saades abi pluginale\: {0} +commandNotLoaded=\u00a74K\u00e4sk {0} on ebakoheselt laetud. +compassBearing=\u00a76Suund\: {0} ({1} kraadi). +configFileMoveError=Viga liigutades config.yml backup asukohta. +configFileRenameError=Viga temp faili \u00fcmber nimetamisega config.yml-ks. +connectedPlayers=\u00a76\u00dchendatud m\u00e4ngijad\u00a7r +connectionFailed=\u00dchenduse avamine eba\u00f5nnestus. +cooldownWithMessage=\u00a74Maha jahtumine\: {0} +corruptNodeInConfig=\u00a74Teade\: Sinu konfiguratsioonifailis on vigane {0} node. +couldNotFindTemplate=\u00a74Ei leidnud \u0161ablooni {0} +creatingConfigFromTemplate=Seadete loomine \u0161abloonist\: {0} +creatingEmptyConfig=Loon t\u00fchja konfiguratsiooni\: {0} +creative=loominguline +currency={0}{1} +currentWorld=\u00a76Praegune maailm\:\u00a7c {0} +day=p\u00e4ev +days=p\u00e4eva +defaultBanReason=Blokeerimishaamer on r\u00e4\u00e4kinud\! +deleteFileError=Faili {0} ei saanud kustutada +deleteHome=\u00a76Kodu\u00a7c {0} \u00a76on eemaldatud. +deleteJail=\u00a76Vangla\u00a7c {0} \u00a76on eemaldatud. +deleteWarp=\u00a76L\u00f5im\u00a7c {0} \u00a76on eemaldatud. +deniedAccessCommand=\u00a74M\u00e4ngijal \u00a7c{0} \u00a74keelati ligip\u00e4\u00e4s k\u00e4sule. +denyBookEdit=\u00a74Sa ei saa avada seda raamatut. +denyChangeAuthor=\u00a74Sa ei saa muuta selle raamatu autorit. +denyChangeTitle=\u00a74Sa ei saa muuta selle raamatu pealkirja. +depth=\u00a76Sa oled merepinnal. +depthAboveSea=\u00a76Sa oled\u00a7c {0} \u00a76plokk(i) merepinnast k\u00f5rgemal. +depthBelowSea=\u00a76Sa oled\u00a7c {0} \u00a76plokk(i) merepinnast madalamal. +destinationNotSet=Sihtpaik ei ole m\u00e4\u00e4ratud\! +disableUnlimited=\u00a76Peatatud l\u00f5pmatu plokki asetamine \u00a7c {0} \u00a76m\u00e4ngijale {1}. +disabled=keelatud +disabledToSpawnMob=\u00a74Selle eluka tekitamine on konfiguratsioonis keelatud. +distance=\u00a76Kaugus\: {0} +dontMoveMessage=\u00a76Teleportatsioon algab\u00a7c {0}\u00a76 p\u00e4rast. \u00c4ra liigu. +downloadingGeoIp=GeoIP andmebaasi allalaadimine... see v\u00f5ib v\u00f5tta aega (riik\: 0.6 MB, linn\: 20MB) +duplicatedUserdata=Topelt kasutaja andmed\: {0} ja {1}. +durability=\u00a76Sellel esemel on \u00a7c{0}\u00a76 kasutust j\u00e4rel +editBookContents=\u00a7eSa v\u00f5id n\u00fc\u00fcd muuta selle raamatu sisu. +enableUnlimited=\u00a76Annan piiramatus koguses\u00a7c {0} \u00a76m\u00e4ngijale \u00a7c{1}\u00a76. +enabled=lubatud +enchantmentApplied=\u00a76Loits\u00a7c {0} \u00a76on lisatud k\u00e4esolevale esemele. +enchantmentNotFound=\u00a74Loitsu ei leitud\! +enchantmentPerm=\u00a74Sul ei ole luba j\u00e4rgnevaks\:\u00a7c {0}\u00a74. +enchantmentRemoved=\u00a76Loits\u00a7c {0} \u00a76on eemaldatud k\u00e4esolevalt esemelt. +enchantments=\u00a76Loitsud\:\u00a7r {0} +errorCallingCommand=Viga kutsudes k\u00e4sku /{0} +errorWithMessage=\u00a7cViga\:\u00a74 {0} +essentialsHelp1=Fail on katki/vigane ja Essentials ei saa seda avada. Essentials on n\u00fc\u00fcd suletud. Kui te ei suuda faili ise korda teha, siis k\u00fclastage http\://tiny.cc/EssentialsChat +essentialsHelp2=Fail on katki/vigane ja Essentials ei saa seda avada. Essentials on n\u00fc\u00fcd suletud. Kui te ei suuda faili ise korda teha, siis kas kirjutage /essentialshelp m\u00e4ngus v\u00f5i k\u00fclastage http\://tiny.cc/EssentialsChat +essentialsReload=\u00a76Essentials taaslaetud\u00a7c {0}. +exp=\u00a7c{0}\u00a76''il on\u00a7c {1} \u00a76exp (level\u00a7c {2}\u00a76) ja vajab veel\u00a7c {3} \u00a76exp j\u00e4rgmiseks leveliks. +expSet=\u00a7c{0}\u00a76''il on n\u00fc\u00fcd\u00a7c {1} \u00a76exp. +extinguish=\u00a76Te kustutasite end. +extinguishOthers=\u00a76Kustutasite m\u00e4ngija {0}\u00a76. +failedToCloseConfig=Esines viga konfiguratsiooni {0} sulgemisega. +failedToCreateConfig=Esines viga konfiguratsiooni {0} loomisel. +failedToWriteConfig=Esines viga kirjutamisega konfiguratsiooni {0}. +false=\u00a74false\u00a7r +feed=\u00a76Teie isu on kadunud. +feedOther=\u00a76Rahuldasid \u00a7c{0}\u00a76 isu. +fileRenameError=Faili {0} \u00fcmbernimetamine eba\u00f5nnestus\! +fireworkColor=\u00a74Vigsed ilutulestiku parameetrid sisestatud, peate esmalt v\u00e4rvi paika panema. +fireworkEffectsCleared=\u00a76K\u00f5ik effektid eemaldatud k\u00e4esoleval esemel. +fireworkSyntax=\u00a76Ilutulestiku parameetrid\:\u00a7c v\u00e4rv\: [hajutus\:] [kuju\:] [effekt\:]\n\u00a76Et kasutada mitmeid effekte/v\u00e4rve korraga, eralda nad \u00fcksteisest komaga\: \u00a7cred,blue,pink\n\u00a76Kujud\:\u00a7c star, ball, large, creeper, burst \u00a76Effektid\:\u00a7c trail, twinkle. +flyMode=\u00a76Lubasid lendamise\u00a7c {0} \u00a76m\u00e4ngijale {1}\u00a76. +flying=lendab +foreverAlone=\u00a74Sul ei ole mitte kellelegi vastata. +fullStack=\u00a74Sul on juba t\u00e4is kuhi. +gameMode=\u00a7c{1} \u00a76m\u00e4ngure\u017eiimiks on seatud \u00a7c{0}\u00a76. +gcWorld=\u00a76{0} "\u00a7c{1}\u00a76"\: \u00a7c{2}\u00a76 t\u00fckki, \u00a7c{3}\u00a76 \u00fcksust, \u00a7c{4}\u00a76 plaati. +gcfree=\u00a76Vaba m\u00e4lu\:\u00a7c {0} MB. +gcmax=\u00a76Maksimaalne m\u00e4lu\:\u00a7c {0} MB. +gctotal=\u00a76M\u00e4\u00e4ratud m\u00e4lu\:\u00a7c {0} MB. +geoIpUrlEmpty=GeoIP allalaadimise url on t\u00fchi. +geoIpUrlInvalid=GeoIP allalaadimise url on vigane. +geoipJoinFormat=\u00a76M\u00e4ngija \u00a7c{0} \u00a76tuleb asukohast \u00a7c{1}\u00a76. +giveSpawn=\u00a76Annan\u00a7c {0} \u00a7c {1}\u00a76''i\u00a7c m\u00e4ngijale\u00a7c {2}\u00a76. +godDisabledFor=\u00a7ckeelatud\u00a76 m\u00e4ngijale\u00a7c {0} +godEnabledFor=\u00a7alubatud\u00a76 m\u00e4ngijal\u00a7c {0} +godMode=\u00a76Jumalare\u017eiim\u00a7c {0}\u00a76. +groupDoesNotExist=\u00a74Selles grupis ei ole mitte kedagi v\u00f5rgus\! +groupNumber=\u00a7c{0}\u00a7f v\u00f5rgus, terve nimekiri\:\u00a7c /{1} {2} +hatArmor=\u00a74K\u00e4esolevat eset ei saa m\u00fctsina kasutada\! +hatEmpty=\u00a74Sa ei kanna m\u00fctsi. +hatFail=\u00a74Teil peab olema k\u00e4es olema midagi mida kanda. +hatPlaced=\u00a76Naudi oma uut m\u00fctsi\! +hatRemoved=\u00a76Teie m\u00fcts on eemaldatud. +haveBeenReleased=\u00a76Sind on vabastatud. +heal=\u00a76Sind on tervendatud. +healDead=\u00a74Sa ei saa surnuid tervendada\! +healOther=\u00a76Tervendasid\u00a7c {0}\u00a76. +helpConsole=Et vaadata abi konsoolist, kirjuta ?. +helpFrom=\u00a76K\u00e4sud m\u00e4ngijalt {0}\: +helpLine=\u00a76/{0}\u00a7r\: {1} +helpMatching=\u00a76K\u00e4sud klapivad "\u00a7c{0}\u00a76"\: +helpOp=\u00a74[HelpOp]\u00a7r \u00a76{0}\:\u00a7r {1} +helpPlugin=\u00a74{0}\u00a7r\: Plugina Abi\: /help {1} +holdBook=\u00a74Te ei hoia k\u00e4es raamatut kuhu saaks kirjutada. +holdFirework=\u00a74Te peate k\u00e4es hoidma ilutulestikku, et lisada effekte. +holdPotion=\u00a74Te peate k\u00e4es hoidma n\u00f5iajooki, et sellele lisada effekte. +holeInFloor=\u00a74P\u00f5randas on auk\! +homeSet=\u00a76Kodu m\u00e4\u00e4ratud. +homes=\u00a76Kodud\:\u00a7r {0} +hour=tund +hours=tundi +ignoredList=\u00a76Ignoreerid\:\u00a7r {0} +ignorePlayer=\u00a76Te ignoreerite m\u00e4ngijat\u00a7c {0}\u00a76. +illegalDate=Vigane kuup\u00e4eva vorming. +infoChapter=\u00a76Vali peat\u00fckk\: +infoChapterPages=\u00a7e ---- \u00a76{0} \u00a7e--\u00a76 Leht \u00a7c{1}\u00a76/\u00a7c{2} \u00a7e---- +infoPages=\u00a7e ---- \u00a76{2} \u00a7e--\u00a76 Leht \u00a7c{0}\u00a76/\u00a7c{1} \u00a7e---- +infoUnknownChapter=\u00a74Tundmatu peat\u00fckk. +insufficientFunds=\u00a74Ebapiisavas koguses raha. +invalidCharge=\u00a74Vigane tasu. +invalidFireworkFormat=\u00a74Valik \u00a7c{0} \u00a74ei ole sobiv v\u00e4\u00e4rtus \u00a7c{1}\u00a74 jaoks. +invalidHome=\u00a74Kodu\u00a7c {0} \u00a74ei ole m\u00e4\u00e4ratud\! +invalidHomeName=\u00a74Vigane kodu nimi\! +invalidMob=\u00a74Kehtetu eluka liik. +invalidNumber=Vigane Number. +invalidPotion=\u00a74Vigane n\u00f5iajook. +invalidPotionMeta=\u00a74Vigane n\u00f5iajoogi meta\: \u00a7c{0}\u00a74. +invalidSignLine=\u00a74Rida\u00a7c {0} \u00a74m\u00e4rgil on vigane. +invalidWarpName=\u00a74Vigane l\u00f5imu nimi\! +invalidWorld=\u00a74Vigane maailm. +is=on +itemCannotBeSold=\u00a74K\u00e4esolevat eset ei saa serverile m\u00fc\u00fca. +itemMustBeStacked=\u00a74Eset saad vahetada stackina. Kogus 2s oleks kaks stacki, jne. +itemNames=\u00a76Eseme l\u00fchendid\:\u00a7r {0} +itemNotEnough1=\u00a74Sul pole k\u00e4es piisavat hulka eset, et seda m\u00fc\u00fca. +itemNotEnough2=\u00a76Kui teil oli plaanis m\u00fc\u00fca k\u00f5ik oma esemed sellest t\u00fc\u00fcbist, siis kasutage /sell esemenimi. +itemNotEnough3=\u00a76/sell esemenimi -1 m\u00fc\u00fcb k\u00f5ik peale \u00fche, jne. +itemSellAir=Te t\u00f5esti proovisite m\u00fc\u00fca \u00d5hku? V\u00f5tke ese endale k\u00e4tte. +itemSold=\u00a7aM\u00fc\u00fcs hinnaga \u00a7c{0} \u00a7a({1} {2} asukohas {3} \u00fche eest). +itemSoldConsole=\u00a7a{0} \u00a7am\u00fc\u00fcs {1} hinnaga \u00a7a{2} \u00a7a({3} eset asukohas {4} \u00fche eest). +itemSpawn=\u00a76Annan\u00a7c {0}\u00a7c {1}\u00a76-i +itemType=\u00a76Ese\:\u00a7c {0} \u00a76-\u00a7c {1} +itemsCsvNotLoaded=Viga laadimisel items.csv\! +jailAlreadyIncarcerated=\u00a74M\u00e4ngija on juba vanglas\:\u00a7c {0} +jailMessage=\u00a74Sooritad kuriteo, oled vangis ka. +jailNotExist=\u00a74Selline vangla ei ole olemas. +jailReleased=\u00a76M\u00e4ngija \u00a7c{0}\u00a76 vabastatud. +jailReleasedPlayerNotify=\u00a76Teid on vabastatud\! +jailSentenceExtended=\u00a76Vangi aega pikendati j\u00e4rgnevalt\: {0} +jailSet=\u00a76Vangla\u00a7c {0} \u00a76on m\u00e4\u00e4ratud. +jumpError=\u00a74See teeks teie arvuti ajule haiget. +kickDefault=Serverist v\u00e4lja visatud. +kickExempt=\u00a74Sa ei saa seda m\u00e4ngijat m\u00e4ngust v\u00e4lja visata. +kickedAll=\u00a74K\u00f5ik m\u00e4ngijad on serverist v\u00e4lja visatud. +kill=\u00a76Tapsid\u00a7c {0}\u00a76-i. +killExempt=\u00a74Sa ei saa tappa \u00a7c{0}\u00a74. +kitCost=\ \u00a77\u00a7o({0})\u00a7r +kitError2=\u00a74See abipakk on ebakorrektselt seadistatud. Kontakteeru omanikuga. +kitError=\u00a74Ei leitud \u00fchtegi abipakki. +kitGiveTo=\u00a76Annan abipaki\u00a7c {0}\u00a76 m\u00e4ngijale \u00a7c{1}\u00a76. +kitInvFull=\u00a74Sinu seljakott on t\u00e4is, panime abipaki maha. +kitNotFound=\u00a74Antud abipakki ei ole olemas. +kitOnce=\u00a74Te ei saa seda abipakki uuesti kasutada. +kitReceive=\u00a76Said abipaki\u00a7c {0}\u00a76. +kitTimed=\u00a74Sa saad seda abipakki kasutada peale\u00a7c {0}\u00a74. +kits=\u00a76Abipakid\:\u00a7r {0} +leatherSyntax=\u00a76Nahav\u00e4rvi s\u00fcntaks\: color\:,, eg\: color\:255,0,0. +lightningSmited=\u00a76Pikne on teid l\u00f6\u00f6nud\! +lightningUse=\u00a76Viskad pikse noole m\u00e4ngijale\u00a7c {0} +listAfkTag=\u00a77[Eemal]\u00a7r +listAmount=\u00a76V\u00f5rgus on \u00a7c{0}\u00a76/\u00a7c{1}\u00a76 m\u00e4ngijat. +listAmountHidden=\u00a76V\u00f5rgus on \u00a7c{0}\u00a76 (\u00a7c{1}\u00a76)/\u00a7c{2}\u00a76 m\u00e4ngijat. +listGroupTag=\u00a76{0}\u00a7r\: \u00a7r +listHiddenTag=\u00a77[PEIDETUD]\u00a7r +loadWarpError=\u00a74L\u00f5imu {0} laadimisel tekkis viga. +localFormat=[L]<{0}> {1} +mailClear=\u00a76Et m\u00e4rkida kirjad loetuks, kirjuta\u00a7c /mail clear\u00a76. +mailCleared=\u00a76Kirjad on puhastatud\! +mailSent=\u00a76Kiri saadetud\! +markMailAsRead=\u00a76Et m\u00e4rkida kirjad loetuks, kirjuta\u00a7c /mail clear\u00a76. +markedAsAway=\u00a76Teid on m\u00e4rgitud kui eemal. +markedAsNotAway=\u00a76Te ei ole enam m\u00e4rgitud kui eemal. +matchingIPAddress=\u00a76J\u00e4rgnevad m\u00e4ngijad on eelnevalt sisse loginud sellelt IP aadressilt\: +maxHomes=\u00a74Sa ei saa m\u00e4\u00e4rata rohkem kui\u00a7c {0} \u00a74kodu. +mayNotJail=\u00a74Sa ei tohi antud m\u00e4ngijat vangistada\! +me=mina +minute=minut +minutes=minutit +missingItems=\u00a74Sul ei ole \u00a7c{0}x {1}\u00a74. +mobSpawnError=\u00a74Elukatekitaja vahetamisel tekkis viga. +mobSpawnLimit=Elukate hulk piiratud serveri limiidile. +mobSpawnTarget=\u00a74Sihitud plokk peab olema elukatekitaja. +mobsAvailable=\u00a76Elukad\:\u00a7r {0} +moneyRecievedFrom=\u00a7a{0} on saadud kasutajalt {1}. +moneySentTo=\u00a7a{0} on saadetud m\u00e4ngijale {1}. +month=kuu +months=kuud +moreThanZero=\u00a74Kogused peavad olema suuremad kui 0. +moveSpeed=\u00a7c{1} \u00a76{0}kiiruseks on seatud \u00a7c{2}\u00a76. +msgFormat=\u00a76[\u00a7c{0}\u00a76 -> \u00a7c{1}\u00a76] \u00a7r{2} +multipleCharges=\u00a74Te ei saa lisada rohkem kui \u00fche laadimise k\u00e4esolevale ilutulestikule. +multiplePotionEffects=\u00a74Te ei saa lisada rohkem kui \u00fche effekti k\u00e4esolevale n\u00f5iajoogile. +muteExempt=\u00a74Sa ei tohi vaigistada antud m\u00e4ngijat. +muteNotify=\u00a7c{0} \u00a76vaigistas m\u00e4ngija \u00a7c{1}\u00a76. +mutedPlayer=\u00a76M\u00e4ngija\u00a7c {0} \u00a76on vaigistatud. +mutedPlayerFor=\u00a76M\u00e4ngija\u00a7c {0} \u00a76on vaigistatud\u00a7c {1}\u00a76. +mutedUserSpeaks={0} \u00fcritas r\u00e4\u00e4kida, aga on vaigistatud. +nearbyPlayers=\u00a76M\u00e4ngijad l\u00e4heduses\:\u00a7r {0} +negativeBalanceError=\u00a74Kasutajal ei ole tohi olla negatiivne rahasumma. +nickChanged=\u00a76H\u00fc\u00fcdnimi muudetud. +nickDisplayName=\u00a74Te peate lubama change-displayname Essentials configus. +nickInUse=\u00a74Antud nimi on juba kasutusel. +nickNamesAlpha=\u00a74H\u00fc\u00fcdnimed peavad olema t\u00e4ht-numbrilised. +nickNoMore=\u00a76Teilt eemaldati h\u00fc\u00fcdnimi. +nickSet=\u00a76Sinu h\u00fc\u00fcdnimi on n\u00fc\u00fcd \u00a7c{0}\u00a76. +nickTooLong=\u00a74Antud h\u00fc\u00fcdnimi on liiga pikk. +noAccessCommand=\u00a74Teil ei ole sellele k\u00e4sule juurdep\u00e4\u00e4su. +noAccessPermission=\u00a74Sul pole \u00f5igust \u00a7c{0}\u00a74 avamiseks. +noBreakBedrock=\u00a74Teil ei ole lubatud purustada aluskivi. +noDestroyPermission=\u00a74Sul pole \u00f5igust \u00a7c{0}\u00a74 l\u00f5hkumiseks. +noDurability=\u00a74K\u00e4esoleval esemel puudub vastupidavus. +noGodWorldWarning=\u00a74Hoiatus\! Jumalare\u017eiim ei ole selles maailmas lubatud. +noHelpFound=\u00a74Klappivaid k\u00e4ske ei ole. +noHomeSetPlayer=\u00a76M\u00e4ngija ei ole m\u00e4\u00e4ranud kodu. +noIgnored=\u00a76Te ei ignoreeri mitte kedagi. +noKitPermission=\u00a74Te vajate \u00a7c{0}\u00a74 luba, et kasutada seda abipakki. +noKits=\u00a76\u00dchtegi abipakki ei ole hetkel saadaval. +noMail=\u00a76Teil ei ole \u00fchtegi kirja. +noMatchingPlayers=\u00a76Klappivaid m\u00e4ngijaid ei leitud. +noMetaFirework=\u00a74Teil ei ole luba, et m\u00e4\u00e4rata ilutulestiku effekte. +noMetaPerm=\u00a74Teil ei ole luba lisada \u00a7c{0}\u00a74 effekte k\u00e4esolevale esemele. +noNewMail=\u00a76Teil ei ole \u00fchtegi uut kirja. +noPendingRequest=\u00a74Teil ei ole ootel taotlust. +noPerm=\u00a74Teil ei ole \u00a7c{0}\u00a74 permissionit. +noPermToSpawnMob=\u00a74Sul ei ole luba tekitada antud elukat. +noPlacePermission=\u00a74Teil ei ole luba asetada plokki selle m\u00e4rgi l\u00e4heduses. +noPotionEffectPerm=\u00a74Teil ei ole luba, et lisada n\u00f5iajoogi effekti \u00a7c{0} \u00a74k\u00e4esolevale n\u00f5iajoogile. +noPowerTools=\u00a76Teil ei ole power tool-e m\u00e4\u00e4ratud. +noWarpsDefined=\u00a76L\u00f5ime ei ole m\u00e4\u00e4ratud. +none=mitte \u00fckski +notAllowedToQuestion=\u00a74Te ei ole autoriseeritud, et kasutada k\u00fcsimust. +notAllowedToShout=\u00a74Te ei ole autoriseeritud, et karjuda. +notEnoughExperience=\u00a74Teil ei ole piisavalt exp-d. +notEnoughMoney=\u00a74Teil pole piisavalt raha. +notFlying=ei lenda +notRecommendedBukkit=\u00a74* \! * Bukkit''i versioon ei ole soovitatud build Essentials''ile. +notSupportedYet=Ei ole veel toetatud. +nothingInHand=\u00a74Teil ei ole mitte midagi k\u00e4es. +now=n\u00fc\u00fcd +nuke=\u00a75Las surm sajab neile peale. +numberRequired=Number l\u00e4heb sinna, rumaluke. +onlyDayNight=/time toetab ainult day/night. +onlyPlayerSkulls=\u00a74Sa saad m\u00e4\u00e4rata ainult m\u00e4ngija kolju (\u00a7c397\:3\u00a74) omaniku. +onlyPlayers=\u00a74K\u00e4sku \u00a7c{0}\u00a74 saab kasutada ainult m\u00e4ngusiseselt. +onlySunStorm=\u00a74/weather toetab ainult sun/storm. +orderBalances=\u00a76J\u00e4rjestan\u00a7c {0} \u00a76m\u00e4ngija raha, palun oota... +oversizedTempban=\u00a74Sa ei saa blokeerida m\u00e4ngijat nii pikaks ajaks. +pTimeCurrent=\u00a7c{0}\u00a76''i aeg on\u00a7c {1}\u00a76. +pTimeCurrentFixed=\u00a7c{0}\u00a76''i aeg on peatatud\u00a7c {1}\u00a76. +pTimeNormal=\u00a7c{0}\u00a76''i aeg on normaalne ja kattub serveriga. +pTimeOthersPermission=\u00a74Te ei ole autoriseeritud, et m\u00e4\u00e4rata teiste m\u00e4ngijate aega. +pTimePlayers=\u00a76Nendel m\u00e4ngijatel on oma aeg\:\u00a7r +pTimeReset=\u00a76M\u00e4ngija aeg on taastatud m\u00e4ngijale\: \u00a7c{0} +pTimeSet=\u00a76M\u00e4ngija aeg on m\u00e4\u00e4ratud \u00a7c{0}\u00a76 m\u00e4ngijale\: \u00a7c{1}. +pTimeSetFixed=\u00a76M\u00e4ngija aeg on fikseeritud \u00a7c{0}\u00a76 m\u00e4ngijale\: \u00a7c{1}. +pWeatherCurrent=\u00a7c{0}\u00a76''i ilm on\u00a7c {1}\u00a76. +pWeatherInvalidAlias=\u00a74Vigane ilma t\u00fc\u00fcp +pWeatherNormal=\u00a7c{0}\u00a76''i ilm on normaalne ja kattub serveri omaga. +pWeatherOthersPermission=\u00a74Teil ei ole \u00f5igust m\u00e4\u00e4rata teiste m\u00e4ngijate ilma. +pWeatherPlayers=\u00a76Nendel m\u00e4ngijatel on oma ilm\:\u00a7r +pWeatherReset=\u00a76M\u00e4ngija ilm on taastatud m\u00e4ngjale\: \u00a7c{0} +pWeatherSet=\u00a76M\u00e4ngija ilm on seatud \u00a7c{0}\u00a76 m\u00e4ngijale\: \u00a7c{1}. +pendingTeleportCancelled=\u00a74Ootel teleport kutse h\u00fcljatud. +playerBanIpAddress=\u00a76Player\u00a7c {0} \u00a76banned IP address\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerBanned=\u00a76M\u00e4ngija\u00a7c {0} \u00a76blokeeris\u00a7c {1} \u00a76p\u00f5hjusega \u00a7c{2}\u00a76. +playerInJail=\u00a74M\u00e4ngija on juba vangis\u00a7c {0}\u00a74. +playerJailed=\u00a76M\u00e4ngija\u00a7c {0} \u00a76vangistatud. +playerJailedFor=\u00a76M\u00e4ngija\u00a7c {0} \u00a76vangistatud p\u00f5hjusega {1}. +playerKicked=\u00a76M\u00e4ngija\u00a7c {0} \u00a76viskas {1} v\u00e4lja p\u00f5hjusega {2}. +playerMuted=\u00a76Sa oled vaigistatud\! +playerMutedFor=\u00a76Sind on vaigistatud m\u00e4\u00e4ratud ajaks\:\u00a7c {0}. +playerNeverOnServer=\u00a74M\u00e4ngija\u00a7c {0} \u00a74ei ole kunagi siin m\u00e4nginud. +playerNotFound=\u00a74M\u00e4ngijat ei leitud. +playerUnbanIpAddress=\u00a76M\u00e4ngija\u00a7c {0} \u00a76eemaldas IP {1} blokeeringu. +playerUnbanned=\u00a76M\u00e4ngija\u00a7c {0} \u00a76eemaldas\u00a7c {1} \u00a76blokeeringu. +playerUnmuted=\u00a76Sinu vaigistus on eemaldatud. +pong=Pong\! +posPitch=\u00a76Pitch\: {0} (pea nurk) +posX=\u00a76X\: {0} (+Ida <-> -L\u00e4\u00e4s) +posY=\u00a76Y\: {0} (+\u00dcles <-> -Alla) +posYaw=\u00a76Yaw\: {0} (P\u00f6\u00f6re) +posZ=\u00a76Z\: {0} (+L\u00f5una <-> -P\u00f5hi) +possibleWorlds=\u00a76V\u00f5imalikud maailmad on numbrite \u00a7c0\u00a76 kuni \u00a7c{0}\u00a76 vahel. +potions=\u00a76N\u00f5iajoogid\:\u00a7r {0}\u00a76. +powerToolAir=\u00a74K\u00e4sku ei saa m\u00e4\u00e4rata \u00f5hule. +powerToolAlreadySet=\u00a74K\u00e4sk \u00a7c{0}\u00a74 on juba lisatud esemele \u00a7c{1}\u00a74. +powerToolAttach=\u00a7c{0}\u00a76 k\u00e4sk m\u00e4\u00e4ratud esemele {1}. +powerToolClearAll=\u00a76K\u00f5ik powertool k\u00e4sud puhastatud. +powerToolList=\u00a76Esemel \u00a7c{1} \u00a76on j\u00e4rgnevad k\u00e4sud\: \u00a7c{0}\u00a76. +powerToolListEmpty=\u00a74Esemel \u00a7c{0} \u00a74ei ole m\u00e4\u00e4ratud k\u00e4ske. +powerToolNoSuchCommandAssigned=\u00a74K\u00e4sk \u00a7c{0}\u00a74 ei ole lisatud esemele \u00a7c{1}\u00a74. +powerToolRemove=\u00a76K\u00e4sk \u00a7c{0}\u00a76 eemaldatud esemelt \u00a7c{1}\u00a76. +powerToolRemoveAll=\u00a76K\u00f5ik k\u00e4sud eemaldatud esemelt \u00a7c{0}\u00a76. +powerToolsDisabled=\u00a76K\u00f5ik su power tool-id on disabled. +powerToolsEnabled=\u00a76K\u00f5ik su power tool-id on lubatud. +questionFormat=\u00a72[K\u00fcsimus]\u00a7r {0} +readNextPage=\u00a76Kirjuta\u00a7c /{0} {1}\u00a76, et lugeda j\u00e4rgmist lehte. +recipe=\u00a76Retsept esemele \u00a7c{0}\u00a76 (\u00a7c{1}\u00a76 koguses \u00a7c{2}\u00a76) +recipeBadIndex=Ei leidunud restepti antud numbriga. +recipeFurnace=\u00a76Sulata\: \u00a7c{0}\u00a76. +recipeGrid=\u00a7c{0}X \u00a76| \u00a7{1}X \u00a76| \u00a7{2}X +recipeGridItem=\u00a7c{0}X \u00a76on \u00a7c{1} +recipeMore=\u00a76Kirjuta /{0} \u00a7c{1}\u00a76 , et n\u00e4ha \u00a7c{2}\u00a76 retsepti. +recipeNone=Mitte \u00fchtegi retsepti ei ole olemas j\u00e4rgnevale esemele\: {0} +recipeNothing=mitte midagi +recipeShapeless=\u00a76Kombineeri \u00a7c{0} +recipeWhere=\u00a76Kus\: {0} +removed=\u00a76Eemaldatud\u00a7c {0} \u00a76\u00fcksust. +repair=\u00a76Te olete edukalt parandanud oma\: \u00a7c{0}\u00a76. +repairAlreadyFixed=\u00a74Antud ese ei tarvi parandamist. +repairEnchanted=\u00a74Teil ei ole lubatud parandada loitsitud esemeid. +repairInvalidType=\u00a74K\u00e4esolevat eset ei saa parandada. +repairNone=\u00a74Ei ole \u00fchtegi eset mis vajaksid parandamist. +requestAccepted=\u00a76Teleport kutse vastu v\u00f5etud. +requestAcceptedFrom=\u00a7c{0} \u00a76v\u00f5ttis teie teleport kutse vastu. +requestDenied=\u00a76Teleport kutse h\u00fcljatud. +requestDeniedFrom=\u00a7c{0} \u00a76h\u00fclgas teie teleport kutse. +requestSent=\u00a76Kutse saadetud m\u00e4ngijale\u00a7c {0}\u00a76. +requestTimedOut=\u00a74Teleport kutse aegus. +requiredBukkit=\u00a76* \! * Teil on vaja v\u00e4hemalt build {0} CraftBukkit''it, laadige see alla aadressilt http\://dl.bukkit.org/downloads/craftbukkit/ +resetBal=\u00a76Raha on taastatud summaks \u00a7c{0} \u00a76k\u00f5ikidel online m\u00e4ngijatel. +resetBalAll=\u00a76Raha on taastatud summaks \u00a7c{0} \u00a76k\u00f5ikidel m\u00e4ngijatel. +returnPlayerToJailError=\u00a74Tekkis viga tagastades m\u00e4ngija\u00a7c {0} \u00a74vanglasse\: \u00a7c{1}\u00a74\! +runningPlayerMatch=\u00a76Jooksutan otsingu m\u00e4ngjatele ''\u00a7c{0}\u00a76'' (see v\u00f5ib v\u00f5tta aega) +second=sekund +seconds=sekundit +seenOffline=\u00a76M\u00e4ngija\u00a7c {0} \u00a76on olnud \u00a74v\u00f5rgust v\u00e4ljas\u00a76 alates \u00a7c{1}\u00a76. +seenOnline=\u00a76M\u00e4ngija\u00a7c {0} \u00a76on olnud \u00a7av\u00f5rgus\u00a76 alates \u00a7c{1}\u00a76. +serverFull=Server on t\u00e4is\! +serverTotal=\u00a76Serveril kokku\:\u00a7c {0} +setBal=\u00a7aTeie raha m\u00e4\u00e4rati j\u00e4rgnevaks\: {0}. +setBalOthers=\u00a7aM\u00e4\u00e4rasite {0}\u00a7a''i raha j\u00e4rgnevaks\: {1}. +setSpawner=\u00a76Muutsid elukatekitaja t\u00fc\u00fcbi j\u00e4rgnevaks\:\u00a7c {0}\u00a76. +sheepMalformedColor=\u00a74Moondunud v\u00e4rv. +shoutFormat=\u00a76[H\u00fc\u00fcd]\u00a7r {0} +signFormatFail=\u00a74[{0}] +signFormatSuccess=\u00a71[{0}] +signFormatTemplate=[{0}] +signProtectInvalidLocation=\u00a74Teil ei ole lubatud siia m\u00e4rki teha. +similarWarpExist=\u00a74L\u00f5im sarnase nimiga on juba olemas. +slimeMalformedSize=\u00a74Moondunud suurus. +socialSpy=\u00a76SocialSpy on \u00a7c{1}\u00a76 m\u00e4ngijale \u00a7c{0} +soloMob=\u00a74Antud elukale meeldib olla \u00fcksi. +spawnSet=\u00a76Spawn asukoht m\u00e4\u00e4ratud gruppile\u00a7c {0}\u00a76. +spawned=tekkis +sudoExempt=\u00a74Te ei saa sudo-da antud kasutajat. +sudoRun=\u00a76Forcing\u00a7c {0} \u00a76to run\:\u00a7r /{1} +suicideMessage=\u00a76Headaega julm maailm... +suicideSuccess=\u00a76{0} \u00a76v\u00f5ttis endalt elu. +survival=elluj\u00e4\u00e4mine +takenFromAccount=\u00a7a{0} on v\u00f5etud teie kontolt. +takenFromOthersAccount=\u00a7a{0} v\u00f5etud m\u00e4ngija {1}\u00a7a kontolt. Uus raha summa\: {2}. +teleportAAll=\u00a76Teleporteerumise kutse saadetud k\u00f5igile... +teleportAll=\u00a76Teleporteerun k\u00f5ik m\u00e4ngijad... +teleportAtoB=\u00a7c{0}\u00a76 teleportis su \u00a7c{1}\u00a76 juurde. +teleportDisabled=\u00a7c{0}\u00a74-il on teleportimine disabled. +teleportHereRequest=\u00a7c{0}\u00a76 saatis teile kutse, et telepordiksid nende juurde. +teleportNewPlayerError=\u00a74Viga teleportimisel uut m\u00e4ngijat\! +teleportRequest=\u00a7c{0}\u00a76 soovib teie juurde teleportida. +teleportRequestTimeoutInfo=\u00a76See kutse aegub peale\u00a7c {0} sekundit\u00a76. +teleportTop=\u00a76Teleporteerud \u00fcles. +teleportationCommencing=\u00a76Teleporteerumine algab... +teleportationDisabled=\u00a76Teleportimine \u00a7ckeelatud\u00a76. +teleportationDisabledFor=\u00a76Teleporimine \u00a7ckeelatud \u00a76m\u00e4ngijale \u00a7c{0}\u00a76. +teleportationEnabled=\u00a76Teleportimine \u00a7clubatud\u00a76. +teleportationEnabledFor=\u00a76Teleporimine \u00a7clubatud \u00a76m\u00e4ngijale \u00a7c{0}\u00a76. +teleporting=\u00a76Teleportimine... +teleportToPlayer=\u00a76Telepordin \u00a7c{0}\u00a76 juurde. +tempBanned=\u00a7cYou have been temporarily banned for {0}\:\n\u00a7r{2} +tempbanExempt=\u00a74Sa ei v\u00f5i seda m\u00e4ngijat ajutiselt blokeerida. +thunder=\u00a76Sa\u00a7c {0} \u00a76\u00e4ikeseliseks oma maailmas. +thunderDuration=\u00a76Sa\u00a7c {0} \u00a76\u00e4ikeliseks oma maailmas\u00a7c {1} \u00a76sekundiks. +timeBeforeHeal=\u00a74Aeg enne j\u00e4rgmist elustamist\:\u00a7c {0}\u00a76. +timeBeforeTeleport=\u00a74Aeg enne j\u00e4rgmist teleportimist\:\u00a7c {0}\u00a76. +timeFormat=\u00a7c{0}\u00a76, \u00a7c{1}\u00a76 v\u00f5i \u00a7c{2}\u00a76 +timeSetPermission=\u00a74Teil ei ole lubatud aega muuta. +timeWorldCurrent=\u00a76Praegune aeg maailmas\u00a7c {0} \u00a76on \u00a7c{1}\u00a76. +timeWorldSet=\u00a76Aeg on m\u00e4\u00e4ratud j\u00e4rgnevaks\:\u00a7c {0} \u00a76maailmas\: \u00a7c{1}\u00a76. +totalWorthAll=\u00a7aM\u00fc\u00fcsite k\u00f5ik esemed ja plokkid kogusummaga \u00a7c{1}\u00a7a. +totalWorthBlocks=\u00a7aM\u00fc\u00fcsite k\u00f5ik plokkid kogusummaga \u00a7c{1}\u00a7a. +tps=\u00a76Praegune TPS \= {0} +tradeSignEmpty=\u00a74Vahetus m\u00e4rgil ei ole mitte midagi saadaval teile. +tradeSignEmptyOwner=\u00a74Ei ole mitte midagi mida korjata sellelt vahetus m\u00e4rgilt. +treeFailure=\u00a74Puidu generatsiooni viga. Proovi uuesti muru v\u00f5i mulla peal. +treeSpawned=\u00a76Puu on tekitatud. +true=\u00a7atrue\u00a7r +typeTpaccept=\u00a76Et teleportida, kirjuta \u00a7c/tpaccept\u00a76. +typeTpdeny=\u00a76Et h\u00fcljata seda kutset, kirjuta \u00a7c/tpdeny\u00a76. +typeWorldName=\u00a76V\u00f5ite kirjutada ka teatud maailma nime. +unableToSpawnMob=\u00a74Eluka tekitamisel tekkis viga. +unignorePlayer=\u00a76Sa ei ignoreeri enam m\u00e4ngijat\u00a7c {0}\u00a76. +unknownItemId=\u00a74Tundmatu eseme id\:\u00a7r {0}\u00a74. +unknownItemInList=\u00a74Tundmatu ese {0} {1} listis. +unknownItemName=\u00a74Tundmatu eseme nimi\: {0}. +unlimitedItemPermission=\u00a74Puuduvad \u00f5igused l\u00f5pmatu eseme \u00a7c{0}\u00a74 jaoks. +unlimitedItems=\u00a76L\u00f5pmatud esemed\:\u00a7r +unmutedPlayer=\u00a76M\u00e4ngija\u00a7c {0} \u00a76vaigistus eemaldatud. +unvanishedReload=\u00a74Taaslaadimine sundis sind muutuma n\u00e4htavaks. +upgradingFilesError=Viga uuendades faile. +uptime=\u00a76Uptime\:\u00a7c {0} +userAFK=\u00a77{0} \u00a75on hetkel eemal ja ei pruugi vastata. +userDoesNotExist=\u00a74Kasutaja\u00a7c {0} \u00a74ei ole olemas. +userIsAway=\u00a77* {0} \u00a77on n\u00fc\u00fcd eemal. +userIsNotAway=\u00a77* {0} \u00a77on tagasi. +userJailed=\u00a76Teid on vangistatud\! +userUnknown=\u00a74Hoiatus\: Kasutaja ''\u00a7c{0}\u00a74'' ei ole kunagi selle serveriga liitunud. +userdataMoveBackError=Viga \u00fcritades liigutada userdata/{0}.tmp asukohta userdata/{1}\! +userdataMoveError=Viga \u00fcritades liigutada userdata/{0} asukohta userdata/{1}.tmp\! +usingTempFolderForTesting=Kasutan temp kausta testimiseks\: +vanished=\u00a76Olete n\u00fc\u00fcd t\u00e4iesti n\u00e4htamatu tavakasutajatele, ja peidetud m\u00e4ngusisestest k\u00e4skudest. +versionMismatch=\u00a74Versioon ei kattu\! Palun uuenda {0} samale versioonile. +versionMismatchAll=\u00a74Versioon ei kattu\! Palun uuenda k\u00f5ik Essentials''si jarid samale versioonile. +voiceSilenced=\u00a76Su h\u00e4\u00e4l on vaigistatud\! +walking=k\u00f5nnib +warpDeleteError=\u00a74Probleem l\u00f5imu faili kustutamisega. +warpList={0} +warpListPermission=\u00a74Teil ei ole \u00d5igust, et n\u00e4ha warp listi. +warpNotExist=\u00a74Antud l\u00f5imu ei ole olemas. +warpOverwrite=\u00a74Te ei saa seda warpi \u00fcle kirjutada. +warpSet=\u00a76L\u00f5im\u00a7c {0} \u00a76m\u00e4\u00e4ratud. +warpUsePermission=\u00a74Teil ei ole \u00d5igust, et seda l\u00f5imu kasutada. +warpingTo=\u00a76Kasutate l\u00f5imu, et liikuda asukohta\:\u00a7c {0}\u00a76. +warps=\u00a76L\u00f5imud\:\u00a7r {0} +warpsCount=\u00a76Kokku on\u00a7c {0} \u00a76l\u00f5imu. N\u00e4itan lehte \u00a7c{1}\u00a76/\u00a7c{2}\u00a76. +weatherStorm=\u00a76Te m\u00e4\u00e4rasite ilma \u00a7ctormiseks\u00a76 maailmas\u00a7c {0}\u00a76. +weatherStormFor=\u00a76M\u00e4\u00e4rasite ilma \u00a7ctormiseks\u00a76 maailmas\u00a7c {0}\u00a76 {1} sekundiks. +weatherSun=\u00a76M\u00e4\u00e4rasite ilma \u00a7cp\u00e4ikeselisek\u00a76 maailmas\u00a7c {0}\u00a76. +weatherSunFor=\u00a76M\u00e4\u00e4rasite ilma \u00a7cp\u00e4ikeliseks\u00a76 maailmas\u00a7c {0}\u00a76 {1} sekundiks. +whoisAFK=\u00a76 - Eemal\:\u00a7r {0} +whoisBanned=\u00a76 - Blokeeritud\:\u00a7r {0} +whoisExp=\u00a76 - Exp\:\u00a7r {0} (Level {1}) +whoisFly=\u00a76 - Lennure\u017eiim\:\u00a7r {0} ({1}) +whoisGamemode=\u00a76 - M\u00e4ngure\u017eiim\:\u00a7r {0} +whoisGeoLocation=\u00a76 - Asukoht\:\u00a7r {0} +whoisGod=\u00a76 - Jumalare\u017eiim\:\u00a7r {0} +whoisHealth=\u00a76 - Tervis\:\u00a7r {0}/20 +whoisIPAddress=\u00a76 - IP Aadress\:\u00a7r {0} +whoisJail=\u00a76 - Vangis\:\u00a7r {0} +whoisLocation=\u00a76 - Asukoht\:\u00a7r ({0}, {1}, {2}, {3}) +whoisMoney=\u00a76 - Raha\:\u00a7r {0} +whoisMuted=\u00a76 - Vaigistatud\:\u00a7r {0} +whoisNick=\u00a76 - H\u00fc\u00fcdnimi\:\u00a7r {0} +whoisOp=\u00a76 - OP\:\u00a7r {0} +whoisTop=\u00a76 \=\=\=\=\=\= WhoIs\:\u00a7c {0} \u00a76\=\=\=\=\=\= +worth=\u00a7aStack {0}''i on v\u00e4\u00e4rt \u00a7c{1}\u00a7a ({2} ese(t)(s) asukohas {3} \u00fcks) +worthMeta=\u00a7aStack {0}''i metadataga {1} v\u00e4\u00e4rt \u00a7c{2}\u00a7a ({3} ese(t) asukohas {4} \u00fcks) +worthSet=\u00a76V\u00e4\u00e4rtus m\u00e4\u00e4ratud +year=aasta +years=aastat +youAreHealed=\u00a76Sind on tervendatud. +youHaveNewMail=\u00a76Teil on\u00a7c {0} \u00a76lugemata s\u00f5numit\! Kirjutage \u00a7c/mail read\u00a76, et lugeda enda kirju. +whoisHunger=\u00a76 - N\u00e4lg\:\u00a7r {0}/20 (+{1} k\u00fcllastus) +kitDelay=\u00a7m{0}\u00a7r +giveSpawnFailure=\u00a74Pole piisavalt ruumi, \u00a7c{0} \u00a7c{1} \u00a74j\u00e4i saamata. +noKitGroup=\u00a74Sul ei ole juurdep\u00e4\u00e4su sellele abipakile. +inventoryClearingFromAll=\u00a76T\u00fchjendan k\u00f5ikide m\u00e4ngijate seljakoti... +inventoryClearingAllItems=\u00a76Puhastati k\u00f5ik seljakoti esemed\: {0}\u00a76. +inventoryClearingAllArmor=\u00a76Puhastati k\u00f5ik seljakoti esemed ja armor\: {0}\u00a76. +inventoryClearingAllStack=\u00a76Eemaldati k\u00f5ik\u00a7c {0} \u00a76m\u00e4ngijalt {1}\u00a76. +inventoryClearingStack=\u00a76Eemaldati\u00a7c {0} \u00a76eset\u00a7c {1} \u00a76m\u00e4ngijalt {2}\u00a76. +inventoryClearFail=\u00a74M\u00e4ngijal {0} \u00a74ei ole\u00a7c {1} \u00a74eset\u00a7c {2}\u00a74. +localNoOne= +totalSellableAll=\u00a7aKogusumma k\u00f5ikide m\u00fc\u00fcvate esemete ja plokkide v\u00e4\u00e4rtus on \u00a7c{1}\u00a7a. +totalSellableBlocks=\u00a7aKogusumma k\u00f5ikide m\u00fc\u00fcdavate plokkide v\u00e4\u00e4rtus on \u00a7c{1}\u00a7a. +radiusTooBig=\u00a74Raadius on liiga suur\! Maksimaalne raadius on {0}. +isIpBanned=\u00a76IP \u00a7c{0} \u00a76on blokeeritud. +mobDataList=\u00a76Kehtiv mob data\:\u00a7r {0} +vanish=\u00a76Haihtumine\u00a76 {1} \u00a76 m\u00e4ngijale {0} +noLocationFound=\u00a74Ei leidnud sobivat asukohta. +coordsKeyword={0}, {1}, {2} +banExemptOffline=\u00a74Te ei v\u00f5i bannida m\u00e4ngijaid kes ei ole serveris sees. +tempbanExemptOffline=\u00a74Sa ei tohi ajutiselt blokeerida v\u00f5rgust v\u00e4ljas olevaid m\u00e4ngijaid. +mayNotJailOffline=\u00a74Sa ei tohi vangistada v\u00f5rgust v\u00e4ljas olevaid m\u00e4ngijaid. +muteExemptOffline=\u00a74Sa ei tohi vaigistada v\u00f5rgust v\u00e4ljas olevaid m\u00e4ngijaid. +ignoreExempt=\u00a74Te ei saa seda m\u00e4ngijat ignoreerida. +unsafeTeleportDestination=\u00a75Teleportimise sihtpunkt on ohtlik ja teleportimise-ohutus on maha v\u00f5etud. +noMetaJson=See Bukkiti versioon ei toeta JSON metaandmeid. +maxMoney=\u00a74See tehing \u00fcletab selle konto liimiti. +skullChanged=\u00a76Kolju muudetud\: \u00a7c{0}\u00a76. +alphaNames=\u00a74H\u00fc\u00fcdnimed nimed v\u00f5ivad sisaldada ainult t\u00e4hti, numbreid ning allkriipse. +givenSkull=\u00a76Sulle anti \u00a7c{0} kolju\u00a76. +noPermissionSkull=\u00a74Sul ei ole luba muuta seda koljut. +teleportInvalidLocation=Koordinaatide v\u00e4\u00e4rtus ei saa olla \u00fcle 30000000 +invalidSkull=\u00a74Palun hoia k\u00e4es m\u00e4ngija koljut. +weatherInvalidWorld=Maailma nimega {0} ei leitud\! +gameModeInvalid=\u00a74Sa pead m\u00e4\u00e4rama kehtiva m\u00e4ngija/re\u017eiimi. +mailTooLong=\u00a74Kiri on liiga pikk. P\u00fc\u00fcdke hoida kirja alla 1000 t\u00e4hem\u00e4rgi. +mailDelay=Saatsid liiga palju kirju viimase minuti jooskul. Maksimaalne kirjade saatmise arv\: {0} +seenAccounts=\u00a76M\u00e4ngija on tuntud ka kui\:\u00a7c {0} +unableToSpawnItem=\u00a74Ei saa tekitada \u00a7c{0}\u00a74, see ei ole tekitatav ese. +itemsConverted=\u00a76Converted all items into blocks. +itemsNotConverted=\u00a74You have no items that can be converted into blocks. +mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\: +mailMessage={0} + +whoisTempBanned=\u00a76 - Ban expires:\u00a7r {0} +playerTempBanned=\u00a76Player \u00a7c{0}\u00a76 temporarily banned \u00a7c{1}\u00a76 for \u00a7c{2}\u00a76: \u00a7c{3}\u00a76. +mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1} diff --git a/Essentials/src/messages_fi.properties b/Essentials/src/messages_fi.properties new file mode 100644 index 0000000000..da5451d0da --- /dev/null +++ b/Essentials/src/messages_fi.properties @@ -0,0 +1,558 @@ +#X-Generator: crowdin.net +#version: TeamCity +# Single quotes have to be doubled: '' +# Translations start here +# by: +action=\u00a75* {0} \u00a75{1} +addedToAccount=\u00a7a{0} on lis\u00e4tty sinun tilillesi. +addedToOthersAccount=\u00a7a{0} lis\u00e4tty {1}\u00a7a tilille. Uusi rahatilanne\: {2} +adventure=seikkailu +alertBroke=rikkoi\: +alertFormat=\u00a73[{0}] \u00a7f {1} \u00a76 {2} sijainnissa\: {3} +alertPlaced=laittoi\: +alertUsed=k\u00e4ytti\: +antiBuildBreak=\u00a74Sinulla ei ole oikeuksia rikkoa\u00a7c {0} \u00a74palikoita t\u00e4\u00e4ll\u00e4. +antiBuildCraft=\u00a74Sinulla ei ole oikeuksia tehd\u00e4\u00a7c {0}\u00a74. +antiBuildDrop=\u00a74Sinulla ei ole oikeuksia tiputtaa\u00a7c {0}\u00a74. +antiBuildInteract=\u00a74Sin\u00e4 et saa olla tekemisiss\u00e4\u00a7c {0}\u00a74kanssa. +antiBuildPlace=\u00a74Sinulla ei ole oikeuksia laittaa\u00a7c {0} \u00a74t\u00e4h\u00e4n. +antiBuildUse=\u00a74Sinulla ei ole oikeuksia k\u00e4ytt\u00e4\u00e4\u00a7c {0}\u00a74. +autoAfkKickReason=Sinut on potkittu, koska olit tekem\u00e4tt\u00e4 mit\u00e4\u00e4n {0} minuuttia. +backAfterDeath=\u00a77K\u00e4yt\u00e4 /back komentoa p\u00e4\u00e4st\u00e4ksesi takaisin sijaintiin, jossa kuolit. +backUsageMsg=\u00a77Palautetaan \u00e4skeiseen sijaintiin. +backupDisabled=Ulkoista varmuuskopio koodia ei ole konfiguroitu. +backupFinished=Varmuuskopiointi suoritettu +backupStarted=Varmuuskopiointi aloitettu +balance=\u00a77Rahatilanne\: {0} +balanceOther=\u00a7aSaldo {0}\u00a7a\:\u00a7c {1} +balanceTop=\u00a77Top rahatilanteet ({0}) +banExempt=\u00a7cEt voi bannia pelaajaa. +banFormat=\u00a74Porttikiellot\:\n\u00a7r{0} +bed=\u00a7os\u00e4nky\u00a7r +bedMissing=\u00a74S\u00e4nkysi puuttui, se on kadoksissa tai tukittu. +bedNull=\u00a7ms\u00e4nky\u00a7r +bedSet=S\u00e4nky spawni asetettu\! +bigTreeFailure=\u00a7cIson puun luominen ep\u00e4onnistui. Yrit\u00e4 uudelleen nurmikolla tai mullalla. +bigTreeSuccess=\u00a77Iso puu luotu. +blockList=Essentials siirsi seuraavat komennot muihin plugineihin\: +bookAuthorSet=\u00a76Kirjan tekij\u00e4 on nyt {0}. +bookLocked=\u00a76T\u00e4m\u00e4 kirja on nyt lukittu. +bookTitleSet=\u00a76Kirjan titteli on nyt {0}. +broadcast=[\u00a7cIlmoitus\u00a7f]\u00a7a {0} +buildAlert=\u00a7cSinulla ei ole oikeuksia rakentaa +bukkitFormatChanged=Bukkitin versiomuoto muuttui. Versiota ei ole tarkistettu. +burnMsg=\u00a77Asetit pelaajan {0} tuleen {1} sekunniksi. +canTalkAgain=\u00a77Voit taas puhua +cannotStackMob=\u00a74Sinulla ei ole oikeutta pinota montaa mobia. +cantFindGeoIpDB=Ei l\u00f6ydetty GeoIP tietokantaa\! +cantReadGeoIpDB=Ei pystytty lukemaan GeoIP tietokantaa\! +cantSpawnItem=\u00a7cSinulla ei ole oikeutta luoda tavaraa {0} +chatTypeAdmin=[A] +chatTypeLocal=[L] +chatTypeSpy=[Vakoilla] +cleaned=K\u00e4ytt\u00e4j\u00e4tiedot on poistettu. +cleaning=Poistetaan k\u00e4ytt\u00e4j\u00e4tietoja. +commandFailed=Komento {0} ep\u00e4onnistui\: +commandHelpFailedForPlugin=Virhe haettaessa apua komennoista\: {0} +commandNotLoaded=\u00a7cKomento {0} on v\u00e4\u00e4rin ladattu. +compassBearing=\u00a77Osoittaa\: {0} ({1} astetta). +configFileMoveError=Virhe siirrett\u00e4ess\u00e4 tiedostoa config.yml varmuuskopio sijaintiin. +configFileRenameError=Virhe nimett\u00e4ess\u00e4 tiedostoa temp tiedostoon config.yml +connectedPlayers=\u00a77Liittyneet pelaajat\u00a77r +connectionFailed=Virhe avattaessa yhteytt\u00e4. +cooldownWithMessage=\u00a7cJ\u00e4\u00e4htyminen\: {0} +corruptNodeInConfig=\u00a74Huom\: Sinun konfigurointi tiedostossa on virhe {0}. +couldNotFindTemplate=Ei l\u00f6ydetty mallia {0} +creatingConfigFromTemplate=Luodaan config tiedostoa mallista\: {0} +creatingEmptyConfig=Luodaan tyhj\u00e4\u00e4 config tiedostoa\: {0} +creative=luova +currency={0}{1} +currentWorld=T\u00e4m\u00e4nhetkinen maailma\: {0} +day=p\u00e4iv\u00e4 +days=p\u00e4iv\u00e4\u00e4 +defaultBanReason=Ban Nuija on puhunut\! +deleteFileError=Ei voida poistaa tiedostoa\: {0} +deleteHome=\u00a77Koti {0} on poistettu. +deleteJail=\u00a77Vankila {0} on poistettu. +deleteWarp=\u00a77Warp {0} on poistettu. +deniedAccessCommand={0} p\u00e4\u00e4sy komentoon ev\u00e4ttiin. +denyBookEdit=Et voi avata t\u00e4t\u00e4 kirjaa. +denyChangeAuthor=\u00a74You cannot change the author of this book +denyChangeTitle=\u00a74Et voi vaihtaa t\u00e4m\u00e4n kirjan titteli\u00e4. +depth=\u00a77Olet merenpinnan tasolla. +depthAboveSea=\u00a77Olet {0} palikkaa meritason yl\u00e4puolella. +depthBelowSea=\u00a77Olet {0} palikkaa meritason alapuolella. +destinationNotSet=Sijaintia ei ole m\u00e4\u00e4ritetty +disableUnlimited=\u00a77Poistettu k\u00e4yt\u00f6st\u00e4 loputon laittaminen tavaralta "{0}", pelaajalta {1}. +disabled=poissa k\u00e4yt\u00f6st\u00e4 +disabledToSpawnMob=T\u00e4m\u00e4n mobin luominen on poistettu k\u00e4yt\u00f6st\u00e4 config tiedostossa. +distance=\u00a76Et\u00e4isyys\: {0} +dontMoveMessage=\u00a77Teleportataan {0} kuluttua. \u00c4l\u00e4 liiku. +downloadingGeoIp=Ladataan GeoIP tietokantaa ... t\u00e4m\u00e4 voi vied\u00e4 hetken (maa\: 0.6 MB, kaupunki\: 20MB) +duplicatedUserdata=Kopioitu k\u00e4ytt\u00e4j\u00e4n tiedot\: {0} ja {1} +durability=\u00a77T\u00e4ll\u00e4 ty\u00f6kalulla on \u00a7c{0}\u00a77 k\u00e4ytt\u00f6kertaa j\u00e4ljell\u00e4 +editBookContents=\u00a7eVoit nyt muokata t\u00e4m\u00e4n kirjan sis\u00e4lt\u00f6\u00e4. +enableUnlimited=\u00a76Giving unlimited amount of\u00a7c {0} \u00a76to \u00a7c{1}\u00a76. +enabled=k\u00e4yt\u00f6ss\u00e4 +enchantmentApplied=\u00a77Parannus "{0}" on lis\u00e4tty tavaraan k\u00e4dess\u00e4si. +enchantmentNotFound=\u00a7cParannusta ei l\u00f6ydetty +enchantmentPerm=\u00a7cSinulla ei ole oikeutta {0} +enchantmentRemoved=\u00a77Parannus {0} on poistettu tavarasta k\u00e4dess\u00e4si. +enchantments=\u00a77Parannukset\: {0} +errorCallingCommand=Virhe kutsuttaessa komentoa /{0} +errorWithMessage=\u00a7cVirhe\: {0} +essentialsHelp1=Tiedosto on viallinen ja Essentials ei voi avata sit\u00e4. Essentials on nyt poistettu k\u00e4yt\u00f6st\u00e4. Jos et voi korjata tiedostoa itse, mene osoitteeseen http\://tiny.cc/EssentialsChat +essentialsHelp2=Tiedosto on viallinen ja Essentials ei voi avata sit\u00e4. Essentials on nyt poistettu k\u00e4yt\u00f6st\u00e4. Jos et voi korjata tiedostoa itse, kirjoita /essentialshelp peliss\u00e4 tai mene osoitteeseen http\://tiny.cc/EssentialsChat +essentialsReload=\u00a76Essentials reloaded\u00a7c {0}. +exp=Pelaajalla \u00a7c{0} \u00a77on\u00a7c {1} \u00a77expi\u00e4 (taso\u00a7c {2}\u00a77) ja tarvitsee\u00a7c {3} \u00a77lis\u00e4\u00e4 expi\u00e4 seuravaan tasoon. +expSet=Pelaajalla\u00a7c{0} \u00a77on nyt\u00a7c {1} \u00a77expi\u00e4. +extinguish=\u00a77Sammutit itsesi. +extinguishOthers=\u00a77Sammutit pelaajan {0}. +failedToCloseConfig=Virhe suljettaessa tiedostoa config {0} +failedToCreateConfig=Virhe luotaessa tiedostoa config {0} +failedToWriteConfig=Virhe muokattaessa tiedostoa config {0} +false=v\u00e4\u00e4r\u00e4 +feed=\u00a77Ruokahalusi on tyydytetty. +feedOther=\u00a76You satiated the appetite of \u00a7c{0}\u00a76. +fileRenameError={0} uudelleen nime\u00e4minen ep\u00e4onnistui +fireworkColor=\u00a74V\u00e4\u00e4r\u00e4nlaiset ilotulitteen parametrit, v\u00e4ri t\u00e4ytyy valita ensin. +fireworkEffectsCleared=\u00a76Kaikki vaikutukset poistettu k\u00e4dess\u00e4si olevasta tavarasta. +fireworkSyntax=\u00a76Ilotulitteen parametrit\:\u00a7c v\u00e4ri\: [h\u00e4ivytys\: ] [muoto\:] [effekti\:]\n\u00a76K\u00e4ytt\u00e4\u00e4ksesi montaa v\u00e4ri\u00e4/effekti\u00e4, erota arvot pilkulla\: \u00a7cred,blue,pink\n\u00a76Muotoja\:\u00a7c star, ball, large, creeper, burst \u00a76Effektit\:\u00a7c trail, twinkle. +flyMode=\u00a77Lento {0} pelaajalla {1}. +flying=lent\u00e4v\u00e4 +foreverAlone=\u00a7cSinulla ei ole ket\u00e4\u00e4n kenelle vastata. +fullStack=\u00a74Sinulla on jo t\u00e4ysi pino. +gameMode=\u00a76Set game mode\u00a7c {0} \u00a76for \u00a7c{1}\u00a76. +gcWorld=\u00a76{0} "\u00a7c{1}\u00a76"\: \u00a7c{2}\u00a76 chunks, \u00a7c{3}\u00a76 entities, \u00a7c{4}\u00a76 tiles. +gcfree=Vapaa muisti\: {0} MB +gcmax=Maksimi muisti\: {0} MB +gctotal=Sallittu muisti\: {0} MB +geoIpUrlEmpty=GeoIP latausosoite on tyhj\u00e4. +geoIpUrlInvalid=GeoIP latausosoite on viallinen. +geoipJoinFormat=\u00a76Pelaaja \u00a7c{0} \u00a76tulee maasta \u00a7c{1}\u00a76. +giveSpawn=\u00a76Annetaan\u00a7c {0} \u00a7c {1} \u00a76pelaajalle\u00a7c {2}\u00a76. +godDisabledFor=\u00a7cdisabled\u00a76 for\u00a7c {0} +godEnabledFor=laitettu pelaajalle {0} +godMode=\u00a77God muoto {0}. +groupDoesNotExist=\u00a74Kukaan ei ole paikalla t\u00e4st\u00e4 ryhm\u00e4st\u00e4\! +groupNumber=\u00a7c{0}\u00a7f paikalla, n\u00e4hd\u00e4ksesi kokolistan\:\u00a7c /{1} {2} +hatArmor=\u00a7cVirhe, et voi k\u00e4ytt\u00e4\u00e4 t\u00e4t\u00e4 tavaraa hattuna\! +hatEmpty=\u00a7cYou are not wearing a hat. +hatFail=\u00a7cSinulla tulee olla jotain k\u00e4dess\u00e4si, mit\u00e4 k\u00e4ytt\u00e4\u00e4 hattuna. +hatPlaced=\u00a7eNauti uudesta hatustasi\! +hatRemoved=\u00a76Hattusi on poistettu. +haveBeenReleased=\u00a77Sinut on vapautettu +heal=\u00a77Sinut on parannettu. +healDead=\u00a74Et voi parantaa pelaajaa, joka on kuollut\! +healOther=\u00a77Paransit pelaajan {0}. +helpConsole=Katsoaksesi apua konsolista, kirjoita ?. +helpFrom=\u00a77Komennot {0}\: +helpLine=\u00a76/{0}\u00a7r\: {1} +helpMatching=\u00a77Komennot "{0}"\: +helpOp=\u00a7c[HelpOp]\u00a7f \u00a77{0}\:\u00a7f {1} +helpPlugin=\u00a74{0}\u00a7f\: Plugin apu\: /help {1} +holdBook=\u00a74Et pid\u00e4 k\u00e4dess\u00e4si kirjoitettavaa kirjaa. +holdFirework=\u00a74Sinul\u00f6a t\u00e4ytyy olla k\u00e4dess\u00e4si ilotulite lis\u00e4t\u00e4ksesi effektej\u00e4. +holdPotion=\u00a74Sinul\u00f6a t\u00e4ytyy olla taikajuoma k\u00e4dess\u00e4si lis\u00e4t\u00e4ksesi siihen effektej\u00e4. +holeInFloor=Reik\u00e4 lattiassa +homeSet=\u00a77Koti asetettu. +homes=Kodit\: {0} +hour=tunti +hours=tunnit +ignoredList=\u00a76Huomiotta\:\u00a7r {0} +ignorePlayer=J\u00e4tit huomiotta pelaajan {0}. +illegalDate=Laiton p\u00e4iv\u00e4m\u00e4\u00e4r\u00e4n muoto. +infoChapter=\u00a76Valitse luku\: +infoChapterPages=\u00a7e ---- \u00a76{0} \u00a7e--\u00a76 Sivu \u00a7c{1}\u00a76 kirjasta \u00a7c{2} \u00a7e---- +infoPages=\u00a7e ---- \u00a76{2} \u00a7e--\u00a76 Sivu \u00a74{0}\u00a76/\u00a74{1} \u00a7e---- +infoUnknownChapter=\u00a74Tuntematon luku. +insufficientFunds=\u00a74Insufficient funds available. +invalidCharge=\u00a7cMit\u00e4t\u00f6n m\u00e4\u00e4r\u00e4ys. +invalidFireworkFormat=\u00a74The option \u00a7c{0} \u00a74is not a valid value for \u00a7c{1}\u00a74. +invalidHome=Kotia {0} ei ole olemassa +invalidHomeName=\u00a74Invalid home name\! +invalidMob=\u00a74Invalid mob type. +invalidNumber=Virheellinen numero. +invalidPotion=\u00a74Invalid Potion. +invalidPotionMeta=\u00a74Invalid potion meta\: \u00a7c{0}\u00a74. +invalidSignLine=Kyltin rivi {0} on viallinen. +invalidWarpName=\u00a74Invalid warp name\! +invalidWorld=\u00a7cKelvoton maailma. +is=on +itemCannotBeSold=Tuota tavaraa ei voi myyd\u00e4 t\u00e4ll\u00e4 palvelimella. +itemMustBeStacked=Tavara pit\u00e4\u00e4 vaihtaa pakattuina. M\u00e4\u00e4r\u00e4 2s olisi kaksi pakettia, jne. +itemNames=\u00a76Item short names\:\u00a7r {0} +itemNotEnough1=\u00a7cSinulla ei ole tarpeeksi tavaraa jota myyd\u00e4. +itemNotEnough2=\u00a77Jos haluat myyd\u00e4 kaikki tuon tyypin tavarat, k\u00e4yt\u00e4 /sell tavarannimi +itemNotEnough3=\u00a77/sell itemname -1 myy kaiken paitsi yhden, jne. +itemSellAir=Yritit myyd\u00e4 ilmaa? Laita tavara k\u00e4teesi ja yrit\u00e4 uudelleen. +itemSold=\u00a77Myy \u00a7c{0} \u00a77({1} {2} hintaan {3} kpl) +itemSoldConsole={0} sold {1} for \u00a77{2} \u00a77({3} items at {4} each) +itemSpawn=\u00a77Annetaan {0} kpl {1} +itemType=\u00a76Item\:\u00a7c {0} \u00a76-\u00a7c {1} +itemsCsvNotLoaded=Ei voida ladata tiedostoa items.csv. +jailAlreadyIncarcerated=\u00a7cPelaaja on jo vankilassa\: {0} +jailMessage=\u00a7cSin\u00e4 teet rikoksen, istut my\u00f6s sen mukaan. +jailNotExist=Tuota vankilaa ei ole olemassa. +jailReleased=\u00a77Pelaaja \u00a7e{0}\u00a77 vapautettu. +jailReleasedPlayerNotify=\u00a77Sinut on vapautettu\! +jailSentenceExtended=Vankila aika pidennetty\: {0} +jailSet=\u00a77Vankila {0} on asetettu +jumpError=Tuo vahingoittaisi koneesi aivoja. +kickDefault=Potkittu palvelimelta +kickExempt=\u00a7cEt voi potkia h\u00e4nt\u00e4. +kickedAll=\u00a7cPotkittu kaikki pelaajat palvelimelta +kill=\u00a77Tappoi {0}. +killExempt=\u00a74You cannot kill \u00a7c{0}\u00a74. +kitCost=\ \u00a77\u00a7o({0})\u00a7r +kitError2=\u00a74That kit is improperly defined. Contact an administrator. +kitError=\u00a7cEi ole sopivia pakkauksia. +kitGiveTo=\u00a76Giving kit\u00a7c {0}\u00a76 to \u00a7c{1}\u00a76. +kitInvFull=\u00a7cSinun reppusi on t\u00e4ynn\u00e4, laitetaan tavarat maahan +kitNotFound=Tuota Kitti\u00e4 ei ole olemassa. +kitOnce=\u00a74You can''t use that kit again. +kitReceive=\u00a76Received kit\u00a7c {0}\u00a76. +kitTimed=\u00a7cAika, jota ennen et voi k\u00e4ytt\u00e4\u00e4 t\u00e4t\u00e4 pakkausta uudelleen\: {0}. +kits=\u00a77Pakkaukset\: {0} +leatherSyntax=\u00a76Leather color syntax\: color\:,, eg\: color\:255,0,0. +lightningSmited=\u00a77Sinut on salamoitu +lightningUse=\u00a77Salamoidaan {0} +listAfkTag=\u00a77[AFK]\u00a7f +listAmount=\u00a79Pelaajia palvelimella \u00a7c{0}\u00a79 / \u00a7c{1}\u00a79. +listAmountHidden=\u00a79Pelaajia palvelimella \u00a7c{0}\u00a77/{1}\u00a79 / \u00a7c{2}\u00a79. +listGroupTag=\u00a76{0}\u00a7r\: \u00a7r +listHiddenTag=\u00a77[HIDDEN]\u00a7f +loadWarpError=Virhe ladattaessa warppia {0} +localFormat=[L]<{0}> {1} +mailClear=\u00a76To mark your mail as read, type\u00a7c /mail clear\u00a76. +mailCleared=\u00a77Viestit poistettu\! +mailSent=\u00a77Viesti l\u00e4hetetty\! +markMailAsRead=\u00a76To mark your mail as read, type\u00a7c /mail clear\u00a76. +markedAsAway=\u00a77Sinut on laitettu poissaolevaksi. +markedAsNotAway=\u00a77Sinua ei ole en\u00e4\u00e4 laitettu poissaolevaksi. +matchingIPAddress=\u00a76The following players previously logged in from that IP address\: +maxHomes=Voit asettaa maksimissaan {0} kotia. +mayNotJail=\u00a7cEt voi laittaa tuota pelaajaa vankilaan +me=min\u00e4 +minute=minuutti +minutes=minuuttia +missingItems=\u00a74You do not have \u00a7c{0}x {1}\u00a74. +mobSpawnError=Virhe vaihdettaessa mob-luojan tyyppi\u00e4. +mobSpawnLimit=Mobien m\u00e4\u00e4r\u00e4 rajoitettu palvelimen maksimim\u00e4\u00e4r\u00e4\u00e4n +mobSpawnTarget=Kohteen pit\u00e4\u00e4 olla mob-luoja palikka. +mobsAvailable=\u00a77Mobit\: {0} +moneyRecievedFrom=\u00a7a{0} on vastaanotettu pelaajalta {1} +moneySentTo=\u00a7a{0} on l\u00e4hetetty pelaajalle {1} +month=kuukausi +months=kuukaudet +moreThanZero=M\u00e4\u00e4r\u00e4n pit\u00e4\u00e4 olla enemm\u00e4n kuin 0. +moveSpeed=\u00a76Set {0} speed to\u00a7c {1} \u00a76for \u00a7c{2}\u00a76. +msgFormat=\u00a76[\u00a7c{0}\u00a76 -> \u00a7c{1}\u00a76] \u00a7r{2} +multipleCharges=\u00a74You cannot apply more than one charge to this firework. +multiplePotionEffects=\u00a74You cannot apply more than one effect to this potion. +muteExempt=\u00a7cEt voi hiljent\u00e4\u00e4 tuota pelaajaa. +muteNotify=\u00a7c {0} \u00a76Mykisti Pelaaja \u00a7c {1} \u00a76. +mutedPlayer=Pelaaja {0} voi taas puhua. +mutedPlayerFor=\u00a76Player\u00a7c {0} \u00a76muted for\u00a7c {1}\u00a76. +mutedUserSpeaks={0} yritti puhua, mutta oli hiljennetty. +nearbyPlayers=Pelaajat l\u00e4hell\u00e4\: {0} +negativeBalanceError=Pelaajalla ei ole mahdollista olla negatiivist\u00e4 m\u00e4\u00e4r\u00e4\u00e4 rahaa. +nickChanged=Lempinimi vaihdettu. +nickDisplayName=\u00a77Sinun tulee ottaa k\u00e4ytt\u00f6\u00f6n change-displayname Essentialsin config-tiedostosta. +nickInUse=\u00a7cSe nimi on jo k\u00e4yt\u00f6ss\u00e4. +nickNamesAlpha=\u00a7cLempinimen pit\u00e4\u00e4 olla aakkosista. +nickNoMore=\u00a77Sinulla ei ole en\u00e4\u00e4 lempinime\u00e4. +nickSet=\u00a77Lempinimesi on nyt \u00a7c{0}. +nickTooLong=\u00a74Tuo lempinimi on liian pitk\u00e4. +noAccessCommand=\u00a7cSinulla ei ole oikeutta tuohon komentoon. +noAccessPermission=\u00a74Sinulla ei ole oikeutta Tuohon \u00a7c {0} \u00a74. +noBreakBedrock=Sinulla ei ole lupaa tuhota bedrock-palikoita. +noDestroyPermission=\u00a74You do not have permission to destroy that \u00a7c{0}\u00a74. +noDurability=\u00a7cT\u00e4ll\u00e4 tavaralla ei ole kestoa. +noGodWorldWarning=\u00a7cVaroitus\! God muoto ei ole k\u00e4yt\u00f6ss\u00e4 t\u00e4ss\u00e4 maailmassa. +noHelpFound=\u00a7cEi komentoja. +noHomeSetPlayer=Pelaaja ei ole asettanut kotia. +noIgnored=\u00a76You are not ignoring anyone. +noKitPermission=\u00a7cTarvitset \u00a7c{0}\u00a7c oikeuden, jotta voit k\u00e4ytt\u00e4\u00e4 tuota pakkausta. +noKits=\u00a77Ei pakkauksia saatavilla viel\u00e4 +noMail=Ei uusia viestej\u00e4 +noMatchingPlayers=\u00a76No matching players found. +noMetaFirework=\u00a74You do not have permission to apply firework meta. +noMetaPerm=\u00a74You do not have permission to apply \u00a7c{0}\u00a74 meta to this item. +noNewMail=\u00a77Ei viestej\u00e4. +noPendingRequest=Sinulla ei ole odottavia pyynt\u00f6j\u00e4. +noPerm=\u00a7cSinulla ei ole \u00a7f{0}\u00a7c oikeuksia. +noPermToSpawnMob=\u00a7cSinulla ei ole lupaa luoda t\u00e4t\u00e4 mobia. +noPlacePermission=\u00a7cSinulla ei ole lupaa laittaa palikoita l\u00e4helle tuota kyltti\u00e4. +noPotionEffectPerm=\u00a74You do not have permission to apply potion effect \u00a7c{0} \u00a74to this potion. +noPowerTools=Ei voimaty\u00f6kaluja laitettu. +noWarpsDefined=Ei warppeja +none=ei mit\u00e4\u00e4n +notAllowedToQuestion=\u00a7cSinulla ei ole lupaa k\u00e4ytt\u00e4\u00e4 kysymyst\u00e4. +notAllowedToShout=\u00a7cSinulla ei ole lupaa huutaa. +notEnoughExperience=Sinulla ei ole tarpeeksi kokemusta. +notEnoughMoney=Sinulla ei ole riitt\u00e4v\u00e4sti rahaa. +notFlying=not flying +notRecommendedBukkit=* \! * Bukkit versio ei ole suositeltu t\u00e4m\u00e4n Essentials version kanssa. +notSupportedYet=Ei tueta viel\u00e4. +nothingInHand=\u00a7cSinulla ei ole mit\u00e4\u00e4n k\u00e4dess\u00e4si. +now=nyt +nuke=Antaa kuoleman sateen kohdata heid\u00e4t +numberRequired=Numero menee tuohon, h\u00f6lm\u00f6. +onlyDayNight=/time tukee vain day/night. +onlyPlayerSkulls=\u00a74You can only set the owner of player skulls (\u00a7c397\:3\u00a74). +onlyPlayers=\u00a74Only in-game players can use \u00a7c{0}\u00a74. +onlySunStorm=/weather tukee vain sun/storm. +orderBalances=J\u00e4rjestet\u00e4\u00e4n rahatilanteita {0}, odota... +oversizedTempban=\u00a74You may not ban a player for this period of time. +pTimeCurrent=Pelaajan \u00a7e{0}\u00a7f aika on {1}. +pTimeCurrentFixed=Pelaajan \u00a7e{0}\u00a7f aika on korjattu {1}. +pTimeNormal=Pelaajan \u00a7e{0}\u00a7f aika on normaali ja vastaa palvelimen aikaa. +pTimeOthersPermission=\u00a7cSinulla ei ole lupaa muokata muiden pelaajien aikaa. +pTimePlayers=N\u00e4ill\u00e4 pelaajilla on k\u00e4yt\u00f6ss\u00e4 heid\u00e4n oma aika\: +pTimeReset=Pelaajan aika on resetoitu\: \u00a7e{0} +pTimeSet=Pelaajan aika on asetettu \u00a73{0}\u00a7f koska\: \u00a7e{1} +pTimeSetFixed=Pelaajan aika on korjattu \u00a73{0}\u00a7f koska\: \u00a7e{1} +pWeatherCurrent=\u00a7c{0}\u00a76''s weather is\u00a7c {1}\u00a76. +pWeatherInvalidAlias=\u00a74Tota s\u00e4\u00e4n tyyppi\u00e4 ei ole olemassa +pWeatherNormal=\u00a7c{0}\u00a76''s weather is normal and matches the server. +pWeatherOthersPermission=\u00a74You are not authorized to set other players'' weather. +pWeatherPlayers=\u00a76These players have their own weather\:\u00a7r +pWeatherReset=\u00a76Player weather has been reset for\: \u00a7c{0} +pWeatherSet=\u00a76Player weather is set to \u00a7c{0}\u00a76 for\: \u00a7c{1}. +pendingTeleportCancelled=\u00a7cOdottava teleporttipyynt\u00f6 peruttu. +playerBanIpAddress=\u00a76Player\u00a7c {0} \u00a76banned IP address\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerBanned=\u00a76Player\u00a7c {0} \u00a76banned\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerInJail=\u00a74Player is already in jail\u00a7c {0}\u00a74. +playerJailed=\u00a77Pelaaja {0} laitettu vankilaan. +playerJailedFor=\u00a77Pelaaja {0} laitettu vankilaan, koska {1}. +playerKicked=\u00a7cPelaaja {0} potki pelaajan {1} koska {2} +playerMuted=\u00a77Sinut on hiljennetty +playerMutedFor=\u00a77Sinut on hiljennetty, koska {0} +playerNeverOnServer=\u00a7cPelaaja {0} ei ole koskaan ollut t\u00e4ll\u00e4 palvelimella. +playerNotFound=\u00a7cPelaajaa ei l\u00f6ydetty. +playerUnbanIpAddress=\u00a76Player\u00a7c {0} \u00a76unbanned IP\: {1}. +playerUnbanned=\u00a76Player\u00a7c {0} \u00a76Poisti pelaajan \u00a7c {1} karkoituksen. +playerUnmuted=\u00a77Sin\u00e4 voit taas puhua +pong=Pong\! +posPitch=\u00a76Pitch\: {0} (Head angle) +posX=\u00a76X\: {0} (+East <-> -West) +posY=\u00a76Y\: {0} (+Up <-> -Down) +posYaw=\u00a76Yaw\: {0} (Rotation) +posZ=\u00a76Z\: {0} (+South <-> -North) +possibleWorlds=\u00a76Possible worlds are the numbers \u00a7c0\u00a76 through \u00a7c{0}\u00a76. +potions=\u00a76Potions\:\u00a7r {0}\u00a76. +powerToolAir=Komentoa ei voi liitt\u00e4\u00e4 k\u00e4teen. +powerToolAlreadySet=\u00a74Command \u00a7c{0}\u00a74 is already assigned to \u00a7c{1}\u00a74. +powerToolAttach=\u00a7c{0}\u00a7f komento liitetty kohteeseen {1}. +powerToolClearAll=Kaikki voimaty\u00f6kalun komennot on poistettu. +powerToolList={1} omistaa seuraavat komennot\: \u00a7c{0}\u00a7f. +powerToolListEmpty={0} ei ole komentoja liitetty. +powerToolNoSuchCommandAssigned=\u00a74Command \u00a7c{0}\u00a74 has not been assigned to \u00a7c{1}\u00a74. +powerToolRemove=\u00a76Command \u00a7c{0}\u00a76 removed from \u00a7c{1}\u00a76. +powerToolRemoveAll=\u00a76All commands removed from \u00a7c{0}\u00a76. +powerToolsDisabled=Kaikki voimaty\u00f6kalut on poistettu k\u00e4yt\u00f6st\u00e4. +powerToolsEnabled=Kaikki voimaty\u00f6alut on otettu k\u00e4ytt\u00f6\u00f6n. +questionFormat=\u00a77[Question]\u00a7f {0} +readNextPage=Kirjoita /{0} {1} lukeaksesi seuraavan sivun +recipe=\u00a76Recipe for \u00a7c{0}\u00a76 (\u00a7c{1}\u00a76 of \u00a7c{2}\u00a76) +recipeBadIndex=There is no recipe by that number. +recipeFurnace=\u00a76Smelt\: \u00a7c{0}\u00a76. +recipeGrid=\u00a7c{0}X \u00a76| \u00a7{1}X \u00a76| \u00a7{2}X +recipeGridItem=\u00a7c{0}X \u00a76is \u00a7c{1} +recipeMore=\u00a76Type /{0} \u00a7c{1}\u00a76 to see other recipes for \u00a7c{2}\u00a76. +recipeNone=No recipes exist for {0}. +recipeNothing=nothing +recipeShapeless=\u00a76Combine \u00a7c{0} +recipeWhere=\u00a76Where\: {0} +removed=\u00a77Poistettu {0} kokonaisuutta. +repair=Onnistuneesti korjasit ty\u00f6kalun\: \u00a7e{0}. +repairAlreadyFixed=\u00a77T\u00e4m\u00e4 tavara ei kaipaa korjaamista. +repairEnchanted=\u00a77Sinulla ei ole lupaa korjata kehitettyj\u00e4 tavaroita. +repairInvalidType=\u00a7cT\u00e4t\u00e4 tavaraa ei voi korjata. +repairNone=Ei ollut tavaroita, jotka olivat korjauksen tarpeessa. +requestAccepted=\u00a77Teleporttaus pyynt\u00f6 hyv\u00e4ksytty. +requestAcceptedFrom=\u00a77{0} hyv\u00e4ksyi sinun teleportti pyynn\u00f6n. +requestDenied=\u00a77Teleporttaus pyynt\u00f6 kielletty. +requestDeniedFrom=\u00a77{0} kielt\u00e4ytyi sinun teleportti pyynn\u00f6st\u00e4. +requestSent=\u00a77Pyynt\u00f6 l\u00e4hetetty pelaajalle {0}\u00a77. +requestTimedOut=\u00a7cTeleportti pyynt\u00f6 aikakatkaistiin +requiredBukkit=* \! * Tarvitset v\u00e4hint\u00e4\u00e4n {0} version CraftBukkitista, lataa se osoitteesta http\://dl.bukkit.org/downloads/craftbukkit/ +resetBal=\u00a76Balance has been reset to \u00a7c{0} \u00a76for all online players. +resetBalAll=\u00a76Balance has been reset to \u00a7c{0} \u00a76for all players. +returnPlayerToJailError=\u00a74Error occurred when trying to return player\u00a7c {0} \u00a74to jail\: \u00a7c{1}\u00a74\! +runningPlayerMatch=\u00a76Running search for players matching ''\u00a7c{0}\u00a76'' (this could take a little while). +second=sekunti +seconds=sekuntia +seenOffline=\u00a76Player\u00a7c {0} \u00a76has been \u00a74offline\u00a76 since \u00a7c{1}\u00a76. +seenOnline=\u00a76Player\u00a7c {0} \u00a76has been \u00a7aonline\u00a76 since \u00a7c{1}\u00a76. +serverFull=Palvelin on t\u00e4ynn\u00e4 +serverTotal=Palvelimen kokonaism\u00e4\u00e4r\u00e4m\u00e4\u00e4r\u00e4\: {0} +setBal=\u00a7aSinun rahatilanne on asetettu {0}. +setBalOthers=\u00a7aYou set {0}\u00a7a''s balance to {1}. +setSpawner=\u00a76Changed spawner type to\u00a7c {0}\u00a76. +sheepMalformedColor=Viallinen v\u00e4ri. +shoutFormat=\u00a77[Huuto]\u00a7f {0} +signFormatFail=\u00a74[{0}] +signFormatSuccess=\u00a71[{0}] +signFormatTemplate=[{0}] +signProtectInvalidLocation=\u00a74Sinulla ei ole lupaa laittaa kyltti\u00e4 t\u00e4h\u00e4n. +similarWarpExist=Tuon niminen warp on jo olemassa. +slimeMalformedSize=Viallinen koko. +socialSpy=\u00a76SocialSpy for \u00a7c{0}\u00a76\: \u00a7c{1} +soloMob=Tuo mob tykk\u00e4\u00e4 olevan yksin +spawnSet=\u00a77Spawn sijainti m\u00e4\u00e4ritetty ryhm\u00e4lle {0}. +spawned=luotu +sudoExempt=Et voi sudoa t\u00e4t\u00e4 pelaajaa +sudoRun=\u00a76Forcing\u00a7c {0} \u00a76to run\:\u00a7r /{1} +suicideMessage=\u00a77Hyv\u00e4sti julma maailma... +suicideSuccess=\u00a77{0} riisti oman henkens\u00e4 +survival=selviytyminen +takenFromAccount=\u00a7c{0} on veloitettu tililt\u00e4si. +takenFromOthersAccount=\u00a7c{0} veloitettu pelaajan {1}\u00a7c tililt\u00e4. Uusi rahatilanne\: {2} +teleportAAll=\u00a77Teleporttaus pyynt\u00f6 l\u00e4hetetty kaikille pelaajille... +teleportAll=\u00a77Teleportataan kaikki pelaajat... +teleportAtoB=\u00a77{0}\u00a77 teleporttasi sinun luokse {1}\u00a77. +teleportDisabled=Pelaajalla {0} on teleporttaus poissa k\u00e4yt\u00f6st\u00e4. +teleportHereRequest=\u00a7c{0}\u00a7c on pyyt\u00e4nyt, ett\u00e4 sin\u00e4 teleporttaat heid\u00e4n luokseen. +teleportNewPlayerError=Virhe teleportattaessa uutta pelaajaa +teleportRequest=\u00a7c{0}\u00a7c on pyyt\u00e4nyt lupaa sinun luokse teleporttaamiseen. +teleportRequestTimeoutInfo=\u00a77T\u00e4m\u00e4 pyynt\u00f6 aikakatkaistaan {0} sekunnin kuluttua. +teleportTop=\u00a77Teleportataan p\u00e4\u00e4lle. +teleportationCommencing=\u00a77Teleportataan... +teleportationDisabled=\u00a76Teleportation \u00a7cdisabled\u00a76. +teleportationDisabledFor=\u00a76Teleportation \u00a7cdisabled \u00a76for \u00a7c{0}\u00a76. +teleportationEnabled=\u00a76Teleportation \u00a7cenabled\u00a76. +teleportationEnabledFor=\u00a76Teleportation \u00a7cenabled \u00a76for \u00a7c{0}\u00a76. +teleporting=\u00a77Teleportataan... +teleportToPlayer=\u00a76Teleportataan \u00a7c {0} \u00a76. +tempBanned=\u00a7cYou have been temporarily banned for {0}\:\n\u00a7r{2} +tempbanExempt=\u00a77Et voi bannia tuota pelaajaa +thunder=Myrsky {0} maailmassasi +thunderDuration=Myrsky {0} maailmassasi {1} sekuntia. +timeBeforeHeal=Aika ennen seuraavaa parannusta\: {0} +timeBeforeTeleport=Aika ennen seuraavaa teleporttausta\: {0} +timeFormat=\u00a7c{0}\u00a76 or \u00a7c{1}\u00a76 or \u00a7c{2}\u00a76 +timeSetPermission=\u00a7cSinulla ei ole lupaa vaihtaa aikaa. +timeWorldCurrent=T\u00e4m\u00e4nhetkinen aika maailmassa {0} on \u00a73{1} +timeWorldSet=Aika vaihdettiin {0} maailmassa\: \u00a7c{1} +totalWorthAll=\u00a7aSold all items and blocks for a total worth of \u00a7c{1}\u00a7a. +totalWorthBlocks=\u00a7aSold all blocks for a total worth of \u00a7c{1}\u00a7a. +tps=T\u00e4m\u00e4nhetkinen TPS \= {0} +tradeSignEmpty=Vaihtokyltill\u00e4 ei ole mit\u00e4\u00e4n tarjolla sinulle. +tradeSignEmptyOwner=Ei ole mit\u00e4\u00e4n mit\u00e4 ker\u00e4t\u00e4 t\u00e4st\u00e4 vaihtokyltist\u00e4. +treeFailure=\u00a7cPuun luominen ep\u00e4onnistui. Yrit\u00e4 uudelleen nurmikolla tai mullalla. +treeSpawned=\u00a77Puu luotu. +true=totta +typeTpaccept=\u00a77Hyv\u00e4ksy\u00e4ksesi, kirjoita \u00a7c/tpaccept\u00a77. +typeTpdeny=\u00a77Kielt\u00e4\u00e4ksesi, kirjoita \u00a7c/tpdeny\u00a77. +typeWorldName=\u00a77Voit my\u00f6s laittaa maailman nimen. +unableToSpawnMob=Ei voida luoda mobia. +unignorePlayer=Otat taas huomioon pelaajan {0}. +unknownItemId=Tuntematon tavaran ID\: {0} +unknownItemInList=Tuntematon tavara {0} listassa {1}. +unknownItemName=Tuntematon tavaran nimi\: {0} +unlimitedItemPermission=\u00a74No permission for unlimited item \u00a7c{0}\u00a74. +unlimitedItems=Loputtomat tavarat\: +unmutedPlayer=Pelaajat {0} voi taas puhua. +unvanishedReload=\u00a7cSinut on pakotettu taas n\u00e4kyv\u00e4ksi uudelleen latauksen vuoksi. +upgradingFilesError=Virhe p\u00e4ivitett\u00e4ess\u00e4 tiedostoja +uptime=\u00a76Uptime\:\u00a7c {0} +userAFK=\u00a77{0} \u00a75is currently AFK and may not respond. +userDoesNotExist=Pelaajaa {0} ei ole olemassa. +userIsAway={0} on nyt AFK +userIsNotAway={0} ei ole en\u00e4\u00e4 AFK +userJailed=\u00a77Sinut on laitettu vankilaan +userUnknown=\u00a74Warning\: The user ''\u00a7c{0}\u00a74'' has never joined this server. +userdataMoveBackError=Virhe siirrett\u00e4ess\u00e4 k\u00e4ytt\u00e4j\u00e4n tietoja/{0}.tmp k\u00e4ytt\u00e4j\u00e4n tietoihin/{1} +userdataMoveError=Virhe siirrett\u00e4ess\u00e4 k\u00e4ytt\u00e4j\u00e4n tietoja/{0} k\u00e4ytt\u00e4j\u00e4n tietoihin/{1}.tmp +usingTempFolderForTesting=K\u00e4ytet\u00e4\u00e4n v\u00e4liaikaista kansiota testaukseen\: +vanished=\u00a7aOlet n\u00e4kym\u00e4t\u00f6n. +versionMismatch=Versiot eiv\u00e4t t\u00e4sm\u00e4\u00e4\! P\u00e4ivit\u00e4 {0} samaan versioon. +versionMismatchAll=Versiot eiv\u00e4t t\u00e4sm\u00e4\u00e4\! P\u00e4ivit\u00e4 kaikki Essentialsin jar tiedostot samaan versioon. +voiceSilenced=\u00a77Sinun \u00e4\u00e4ni on hiljennetty +walking=walking +warpDeleteError=Virhe poistettaessa warp tiedostoa. +warpList={0} +warpListPermission=\u00a7cSinulla ei ole oikeuksia n\u00e4hd\u00e4 warp-listaa. +warpNotExist=Tuota warppia ei ole olemassa. +warpOverwrite=\u00a7cEt voi korvata tuota warppia. +warpSet=\u00a77Warp {0} asetettu. +warpUsePermission=\u00a7cSinulla ei ole oikeutta k\u00e4ytt\u00e4\u00e4 tuota warppia. +warpingTo=\u00a77Sinut warpataan pian kohteeseen {0}. +warps=Warpit\: {0} +warpsCount=\u00a76There are\u00a7c {0} \u00a76warps. Showing page \u00a7c{1} \u00a76of \u00a7c{2}\u00a76. +weatherStorm=\u00a77Laitoit myrskyn maailmaan {0} +weatherStormFor=\u00a77Laitoit myrskyn maailmaan {0} {1} sekunniksi +weatherSun=\u00a77Laitoit auringon paistamaan maailmaan {0} +weatherSunFor=\u00a77Laitoit auringon paistamaan maailmaan {0} {1} sekunniksi +whoisAFK=\u00a76 - AFK\:\u00a7f {0} +whoisBanned=\u00a76 - Banned\:\u00a7f {0} +whoisExp=\u00a76 - Exp\:\u00a7f {0} (Level {1}) +whoisFly=\u00a76 - Fly mode\:\u00a7f {0} ({1}) +whoisGamemode=\u00a76 - Gamemode\:\u00a7f {0} +whoisGeoLocation=\u00a76 - Location\:\u00a7f {0} +whoisGod=\u00a76 - God mode\:\u00a7f {0} +whoisHealth=\u00a76 - Health\:\u00a7f {0}/20 +whoisIPAddress=\u00a76 - IP Address\:\u00a7f {0} +whoisJail=\u00a76 - Jail\:\u00a7f {0} +whoisLocation=\u00a76 - Location\:\u00a7f ({0}, {1}, {2}, {3}) +whoisMoney=\u00a76 - Money\:\u00a7f {0} +whoisMuted=\u00a76 - Muted\:\u00a7f {0} +whoisNick=\u00a76 - Nick\:\u00a7f {0} +whoisOp=\u00a76 - OP\:\u00a7f {0} +whoisTop=\u00a76 \=\=\=\=\=\= WhoIs\:\u00a7c {0} \u00a76\=\=\=\=\=\= +worth=\u00a77Pino tavaraa "{0}" on arvoltaan \u00a7c{1}\u00a77 ({2} tavara(a) \= {3} kappale) +worthMeta=\u00a77Pino tavaraa "{0}" metadatan kanssa {1} on arvoltaan \u00a7c{2}\u00a77 ({3} tavara(a) \= {4} kappale) +worthSet=Arvo asetettu +year=vuosi +years=vuosia +youAreHealed=\u00a77Sinut on parannettu. +youHaveNewMail=\u00a7cSinulla on {0} viesti(\u00e4)\!\u00a7f Kirjoita \u00a77/mail read\u00a7f lukeaksesi viestit. +whoisHunger=\u00a76 - Hunger\:\u00a7r {0}/20 (+{1} saturation) +kitDelay=\u00a7m{0}\u00a7r +giveSpawnFailure=\u00a74Not enough space, \u00a7c{0} \u00a7c{1} \u00a74was lost. +noKitGroup=\u00a74You do not have access to this kit. +inventoryClearingFromAll=\u00a76Clearing the inventory of all users... +inventoryClearingAllItems=\u00a76Cleared all inventory items from {0}\u00a76. +inventoryClearingAllArmor=\u00a76Cleared all inventory items and armor from {0}\u00a76. +inventoryClearingAllStack=\u00a76Cleared all\u00a7c {0} \u00a76from {1}\u00a76. +inventoryClearingStack=\u00a76Removed\u00a7c {0} \u00a76of\u00a7c {1} \u00a76from {2}\u00a76. +inventoryClearFail=\u00a74Player {0} \u00a74does not have\u00a7c {1} \u00a74of\u00a7c {2}\u00a74. +localNoOne= +totalSellableAll=\u00a7aThe total worth of all sellable items and blocks is \u00a7c{1}\u00a7a. +totalSellableBlocks=\u00a7aThe total worth of all sellable blocks is \u00a7c{1}\u00a7a. +radiusTooBig=\u00a74Radius is too big\! Maximum radius is {0}. +isIpBanned=\u00a76IP \u00a7c {0} \u00a76On karkoitettu. +mobDataList=\u00a76Valid mob data\:\u00a7r {0} +vanish=\u00a76Vanish for {0}\u00a76\: {1} +noLocationFound=\u00a74No valid location found. +coordsKeyword={0}, {1}, {2} +banExemptOffline=\u00a74You may not ban offline players. +tempbanExemptOffline=\u00a74You may not tempban offline players. +mayNotJailOffline=\u00a74You may not jail offline players. +muteExemptOffline=\u00a74You may not mute offline players. +ignoreExempt=\u00a74You may not ignore that player. +unsafeTeleportDestination=\u00a74The teleport destination is unsafe and teleport-safety is disabled. +noMetaJson=JSON Metadata is not supported in this version of Bukkit. +maxMoney=\u00a74This transaction would exceed the balance limit for this account. +skullChanged=\u00a76Skull changed to \u00a7c{0}\u00a76. +alphaNames=\u00a74Player names can only contain letters, numbers and underscores. +givenSkull=\u00a76You have been given the skull of \u00a7c{0}\u00a76. +noPermissionSkull=\u00a74You do not have permission to modify that skull. +teleportInvalidLocation=Value of coordinates cannot be over 30000000 +invalidSkull=\u00a74Please hold a player skull. +weatherInvalidWorld=World named {0} not found\! +gameModeInvalid=\u00a74You need to specify a valid player/mode. +mailTooLong=\u00a74Mail message too long. Try to keep it below 1000 characters. +mailDelay=Too many mails have been sent within the last minute. Maximum\: {0} +seenAccounts=\u00a76Player has also been known as\:\u00a7c {0} +unableToSpawnItem=\u00a74Cannot spawn \u00a7c{0}\u00a74, this is not a spawnable item. +itemsConverted=\u00a76Converted all items into blocks. +itemsNotConverted=\u00a74You have no items that can be converted into blocks. +mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\: +mailMessage={0} + +whoisTempBanned=\u00a76 - Ban expires:\u00a7r {0} +playerTempBanned=\u00a76Player \u00a7c{0}\u00a76 temporarily banned \u00a7c{1}\u00a76 for \u00a7c{2}\u00a76: \u00a7c{3}\u00a76. +mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1} diff --git a/Essentials/src/messages_fr.properties b/Essentials/src/messages_fr.properties new file mode 100644 index 0000000000..a557fa3663 --- /dev/null +++ b/Essentials/src/messages_fr.properties @@ -0,0 +1,558 @@ +#X-Generator: crowdin.net +#version: TeamCity +# Single quotes have to be doubled: '' +# Translations start here +# by: +action=\u00a75* {0} \u00a75{1} +addedToAccount=\u00a7a{0} ont \u00e9t\u00e9 ajout\u00e9s \u00e0 votre compte. +addedToOthersAccount=\u00a7a{0} ajout\u00e9s au compte de {1}\u00a7a. Nouveau solde \: {2} +adventure=aventure +alertBroke=a cass\u00e9 \: +alertFormat=\u00a73[{0}] \u00a7f {1} \u00a76 {2} \u00e0\:{3} +alertPlaced=a plac\u00e9 \: +alertUsed=a utilis\u00e9 \: +antiBuildBreak=\u00a74Vous n''\u00eates pas autoris\u00e9 \u00e0 casser des blocs de {0} ici. +antiBuildCraft=\u00a74Vous n''\u00eates pas autoris\u00e9 \u00e0 cr\u00e9er\u00a7c {0}\u00a74. +antiBuildDrop=\u00a74Vous n''\u00eates pas autoris\u00e9 \u00e0 jeter\u00a7c {0}\u00a74. +antiBuildInteract=\u00a74Vous n''\u00eates pas autoris\u00e9 \u00e0 interagir avec {0}. +antiBuildPlace=\u00a74Vous n''\u00eates pas autoris\u00e9 \u00e0 placer\u00a7c {0} \u00a74ici. +antiBuildUse=\u00a74Vous n''\u00eates pas autoris\u00e9 \u00e0 utiliser\u00a7c {0}\u00a74. +autoAfkKickReason=Vous avez \u00e9t\u00e9 expuls\u00e9 pour inactivit\u00e9 sup\u00e9rieure \u00e0 {0} minutes. +backAfterDeath=\u00a77Utilisez la commande /back pour retourner \u00e0 l''endroit ou vous \u00eates mort. +backUsageMsg=\u00a77Retour \u00e0 votre emplacement pr\u00e9c\u00e9dent. +backupDisabled=Aucun script de backup externe n''a \u00e9t\u00e9 configur\u00e9. +backupFinished=\u00a76Sauvegarde termin\u00e9e. +backupStarted=D\u00e9but de la sauvegarde... +balance=\u00a77Solde \: {0} +balanceOther=\u00a7aSolde de {0}\u00a7a \:\u00a7c {1} +balanceTop=\u00a77Meilleurs soldes au ({0}) +banExempt=\u00a77Vous ne pouvez pas bannir ce joueur. +banFormat=Banni \: {0} +bed=\u00a7olit\u00a7r +bedMissing=\u00a74Votre lit est soit non d\u00e9fini, soit manquant, soit bloqu\u00e9. +bedNull=\u00a7mlit\u00a7r +bedSet=\u00a76Spawn de lit d\u00e9fini \! +bigTreeFailure=\u00a7c\u00c9chec de la g\u00e9n\u00e9ration du gros arbre. Essayez de nouveau sur de la terre ou de l''herbe. +bigTreeSuccess=\u00a77Gros arbre cr\u00e9\u00e9. +blockList=Essentials a relay\u00e9 les commandes suivantes \u00e0 un autre plugin \: +bookAuthorSet=\u00a76L''auteur du livre est maintenant {0}. +bookLocked=\u00a7cCe livre est maintenant sign\u00e9. +bookTitleSet=\u00a76Le titre du livre est maintenant {0}. +broadcast=[\u00a7cMessage\u00a7f]\u00a7a {0} +buildAlert=\u00a7cVous n''avez pas la permission de construire. +bukkitFormatChanged=Le format de la version de Bukkit a \u00e9t\u00e9 chang\u00e9. La version n''a pas \u00e9t\u00e9 v\u00e9rifi\u00e9e. +burnMsg=\u00a77Vous avez enflamm\u00e9 {0} pour {1} seconde(s). +canTalkAgain=\u00a77Vous pouvez de nouveau parler. +cannotStackMob=\u00a74Vous n''avez pas la permission d''empiler plusieurs mobs. +cantFindGeoIpDB=La base de donn\u00e9es GeoIP est introuvable \! +cantReadGeoIpDB=\u00c9chec de la lecture de la base de donn\u00e9es GeoIP \! +cantSpawnItem=\u00a74Vous n''\u00eates pas autoris\u00e9 \u00e0 faire appara\u00eetre l''item\u00a7c {0}\u00a74. +chatTypeAdmin=[A] +chatTypeLocal=[L] +chatTypeSpy=[Espion] +cleaned=Fichiers joueurs nettoy\u00e9s. +cleaning=Nettoyage des fichiers joueurs... +commandFailed=\u00c9chec de la commande {0} \: +commandHelpFailedForPlugin=Erreur d''obtention d''aide pour \: {0} +commandNotLoaded=\u00a7cLa commande {0} a \u00e9t\u00e9 mal charg\u00e9e. +compassBearing=\u00a77Orientation \: {0} ({1} degr\u00e9s). +configFileMoveError=\u00c9chec du d\u00e9placement de config.yml vers l''emplacement de sauvegarde. +configFileRenameError=Impossible de renommer le fichier temporaire en config.yml. +connectedPlayers=\u00a77Joueurs connect\u00e9s\u00a7r +connectionFailed=\u00c9chec de la connexion. +cooldownWithMessage=\u00a7cR\u00e9utilisation \: {0} +corruptNodeInConfig=\u00a74Annonce \: votre fichier de configuration a un {0} n\u0153ud corrompu. +couldNotFindTemplate=Le mod\u00e8le {0} est introuvable +creatingConfigFromTemplate=Cr\u00e9ation de la configuration \u00e0 partir du mod\u00e8le \: {0} +creatingEmptyConfig=Cr\u00e9ation d''une configuration vierge \: {0} +creative=cr\u00e9atif +currency={0}{1} +currentWorld=Monde actuel \: {0} +day=jour +days=jours +defaultBanReason=Le marteau du bannissement a frapp\u00e9 \! +deleteFileError=Le fichier {0} n''a pas pu \u00eatre supprim\u00e9 +deleteHome=\u00a77La r\u00e9sidence {0} a \u00e9t\u00e9 supprim\u00e9e. +deleteJail=\u00a77La prison {0} a \u00e9t\u00e9 supprim\u00e9e. +deleteWarp=\u00a77Warp {0} supprim\u00e9. +deniedAccessCommand=L''acc\u00e8s \u00e0 la commande a \u00e9t\u00e9 refus\u00e9 pour {0}. +denyBookEdit=\u00a74Vous ne pouvez pas \u00e9diter ce livre. +denyChangeAuthor=\u00a74Vous ne pouvez pas changer l''auteur de ce livre. +denyChangeTitle=\u00a74Vous ne pouvez pas changer le titre de ce livre. +depth=\u00a77Vous \u00eates au niveau de la mer. +depthAboveSea=\u00a77Vous \u00eates \u00e0 {0} bloc(s) au dessus du niveau de la mer. +depthBelowSea=\u00a77Vous \u00eates \u00e0 {0} bloc(s) en dessous du niveau de la mer. +destinationNotSet=Destination non d\u00e9finie \! +disableUnlimited=\u00a77D\u00e9sactivation du placement illimit\u00e9 de {0} pour {1}. +disabled=d\u00e9sactiv\u00e9 +disabledToSpawnMob=L''invocation de ce monstre a \u00e9t\u00e9 d\u00e9sactiv\u00e9e dans le fichier de configuration. +distance=\u00a76Distance \: {0} +dontMoveMessage=\u00a77La t\u00e9l\u00e9portation commence dans {0}. Ne bougez pas. +downloadingGeoIp=T\u00e9l\u00e9chargement de la base de donn\u00e9es GeoIP... Cela peut prendre un moment (pays \: 0.6 Mo, villes \: 20 Mo) +duplicatedUserdata=Donn\u00e9es utilisateurs dupliqu\u00e9es \: {0} et {1} +durability=\u00a77Cet outil a \u00a7c{0}\u00a77 usage(s) restant(s). +editBookContents=\u00a7eVous pouvez maintenant \u00e9diter le contenu de ce livre. +enableUnlimited=&6Don d''une quantit\u00e9 illimit\u00e9e de\u00a7c {0} \u00a76\u00e0 \u00a7c{1}\u00a76. +enabled=activ\u00e9 +enchantmentApplied=\u00a77L''enchantement {0} a \u00e9t\u00e9 appliqu\u00e9 \u00e0 l''objet dans votre main. +enchantmentNotFound=\u00a7cEnchantement non trouv\u00e9 \! +enchantmentPerm=\u00a7cVous n''avez pas les droits pour {0}. +enchantmentRemoved=\u00a77L''enchantement {0} de l''item dans votre main a \u00e9t\u00e9 supprim\u00e9. +enchantments=\u00a76Enchantements \:\u00a7r {0} +errorCallingCommand=Erreur en appelant la commande /{0} +errorWithMessage=\u00a7cErreur \: {0} +essentialsHelp1=Le fichier est corrompu et Essentials ne peut l''ouvrir. Essentials est maintenant d\u00e9sactiv\u00e9. Si vous ne pouvez corriger vous-m\u00eame, allez sur \u00e0 http\://tiny.cc/EssentialsChat +essentialsHelp2=Le fichier est corrompu et Essentials ne peut l''ouvrir. Essentials est maintenant d\u00e9sactiv\u00e9. Si vous ne pouvez corriger vous-m\u00eame, tapez /help ou allez sur \u00e0 http\://tiny.cc/EssentialsChat +essentialsReload=\u00a76Essentials\u00a7c {0} \u00a76a \u00e9t\u00e9 recharg\u00e9. +exp=\u00a7c{0} \u00a77a\u00a7c {1} \u00a77exp (niveau\u00a7c {2}\u00a77) et a besoin de\u00a7c {3} \u00a77pour monter d''un niveau. +expSet=\u00a7c{0} \u00a77a maintenant\u00a7c {1} \u00a77exp. +extinguish=\u00a77Vous cessez de br\u00fbler. +extinguishOthers=\u00a77Vous avez \u00e9teint le feu sur {0}. +failedToCloseConfig=\u00c9chec de la fermeture de la configuration {0}. +failedToCreateConfig=\u00c9chec de la cr\u00e9ation de la configuration {0}. +failedToWriteConfig=\u00c9chec de l''\u00e9criture de la configuration {0}. +false=\u00a74faux\u00a7f +feed=\u00a77Vous avez \u00e9t\u00e9 rassasi\u00e9. +feedOther=\u00a76Vous avez rassasi\u00e9 \u00a7c{0}\u00a76. +fileRenameError=\u00c9chec du changement de nom de {0}. +fireworkColor=\u00a74Vous devez ajouter une couleur au feu d''artifice pour pouvoir lui ajouter un effet. +fireworkEffectsCleared=\u00a76Les effets ont \u00e9t\u00e9 retir\u00e9s. +fireworkSyntax=\u00a76Param\u00e8tres du feu d''artifice \:\u00a7c color\: [fade\:] [shape\:] [effect\:]\n\u00a76Pour utiliser plusieurs couleurs/effets, s\u00e9parez les valeurs avec des virgules \: \u00a7cred,blue,pink\n\u00a76Shapes \:\u00a7c star, ball, large, creeper, burst \u00a76Effects \:\u00a7c trail, twinkle +flyMode=\u00a77Fly mode {0} pour {1} d\u00e9fini. +flying=volant +foreverAlone=\u00a7cVous n''avez personne \u00e0 qui r\u00e9pondre. +fullStack=\u00a74Vous avez d\u00e9j\u00e0 un stack complet. +gameMode=\u00a76Mode de jeu\u00a7c {0} \u00a76pour \u00a7c{1}\u00a76. +gcWorld=\u00a76{0} "\u00a7c{1}\u00a76"\: \u00a7c{2}\u00a76 chunks, \u00a7c{3}\u00a76 entit\u00e9s, \u00a7c{4}\u00a76 tiles. +gcfree=\u00a76M\u00e9moire libre \: \u00a7c{0} \u00a76Mo +gcmax=\u00a76M\u00e9moire maximale \: \u00a7c{0} \u00a76Mo +gctotal=\u00a76M\u00e9moire utilis\u00e9e \: \u00a7c{0} \u00a76Mo +geoIpUrlEmpty=L''URL de t\u00e9l\u00e9chargement de GeoIP est vide. +geoIpUrlInvalid=L''URL de t\u00e9l\u00e9chargement de GeoIP est invalide. +geoipJoinFormat=\u00a76Joueur \u00a7c{0} \u00a76vient de \u00a7c{1}\u00a76. +giveSpawn=\u00a76Donne\u00a7c {0} \u00a76de\u00a7c {1} \u00a76\u00e0\u00a7c {2}\u00a76. +godDisabledFor=\u00a7cd\u00e9sactiv\u00e9\u00a76 pour\u00a7c {0} +godEnabledFor=activ\u00e9 pour {0} +godMode=\u00a77Mode Dieu {0}. +groupDoesNotExist=\u00a74Il n''y a personne en ligne dans ce groupe \! +groupNumber={0} en ligne, pour la liste compl\u00e8te, tapez /{1} {2} +hatArmor=\u00a7cErreur, vous ne pouvez pas utiliser cet item comme chapeau \! +hatEmpty=\u00a7cVous ne portez pas de chapeau. +hatFail=\u00a7cVous devez avoir quelque chose \u00e0 porter dans votre main. +hatPlaced=\u00a7eProfitez bien de votre nouveau chapeau \! +hatRemoved=\u00a7eVotre chapeau a \u00e9t\u00e9 retir\u00e9. +haveBeenReleased=\u00a77Vous avez \u00e9t\u00e9 lib\u00e9r\u00e9. +heal=\u00a77Vous avez \u00e9t\u00e9 soign\u00e9. +healDead=\u00a74Vous ne pouvez pas soigner quelqu''un qui est mort \! +healOther=\u00a77{0} a \u00e9t\u00e9 soign\u00e9. +helpConsole=Pour voir l''aide tapez ? +helpFrom=\u00a77Commandes de {0}\: +helpLine=\u00a76/{0}\u00a7r\: {1} +helpMatching=\u00a77Commandes correspondant \u00e0 "{0}" \: +helpOp=\u00a7c[Aide Admin]\u00a7f \u00a77{0} \: \u00a7f {1} +helpPlugin=\u00a74{0}\u00a7f \: Aide Plugin \: /help {1} +holdBook=\u00a74Vous ne tenez pas un livre dans lequel on peut \u00e9crire. +holdFirework=\u00a74Vous devez tenir un feu d''artifice pour lui ajouter des effets. +holdPotion=\u00a74Vous devez tenir une potion pour lui ajouter des effets. +holeInFloor=Trou dans le sol. +homeSet=\u00a77R\u00e9sidence d\u00e9finie. +homes=R\u00e9sidences \: {0} +hour=heure +hours=heures +ignoredList=\u00a76Ignor\u00e9(s) \:\u00a7r {0} +ignorePlayer=Vous ignorez d\u00e9sormais {0}. +illegalDate=Format de date invalide. +infoChapter=\u00a76S\u00e9lectionnez le chapitre \: +infoChapterPages=\u00a7e ---- \u00a76{0} \u00a7e--\u00a76 Page \u00a7c{1}\u00a76 sur \u00a7c{2} \u00a7e---- +infoPages=\u00a7e ---- \u00a76{2} \u00a7e--\u00a76 Page \u00a74{0}\u00a76/\u00a74{1} \u00a7e---- +infoUnknownChapter=\u00a74Chapitre inconnu. +insufficientFunds=\u00a74Fonds insuffisants. +invalidCharge=\u00a7cCharge invalide. +invalidFireworkFormat=\u00a74L''option \u00a7c{0} \u00a74n''est pas une valeur valide pour \u00a7c{1}\u00a74. +invalidHome=La r\u00e9sidence {0} n''existe pas +invalidHomeName=\u00a74Nom de r\u00e9sindence invalide. +invalidMob=\u00a74Mauvais type de mob. +invalidNumber=\u00a74Nombre invalide. +invalidPotion=\u00a74Potion invalide. +invalidPotionMeta=\u00a74M\u00e9tadata de potion invalide \: \u00a7c{0}\u00a74. +invalidSignLine=\u00a74La ligne {0} du panneau est invalide. +invalidWarpName=\u00a74Nom de warp invalide. +invalidWorld=\u00a7cMonde invalide. +is=est +itemCannotBeSold=Cet objet ne peut \u00eatre vendu au serveur. +itemMustBeStacked=Cet objet doit \u00eatre vendu par 64. Une quantit\u00e9 de 2 serait deux fois 64. +itemNames=Noms d''item courts \: {0} +itemNotEnough1=\u00a7cVous n''avez pas assez de cet objet pour le vendre. +itemNotEnough2=\u00a77Si vous voulez vendre l''int\u00e9gralit\u00e9 de vos objets de ce type l\u00e0, utilisez /sell nomObjet +itemNotEnough3=\u00a77/sell nomObjet -1 vendra tout sauf un objet, etc. +itemSellAir=Vouliez-vous vraiment vendre de l''air ? Mettez un objet dans votre main. +itemSold=\u00a77Vendu pour \u00a7c{0} \u00a77({1} {2} \u00e0 {3} chacun) +itemSoldConsole={0} vendu {1} pour \u00a77{2} \u00a77({3} objet(s) \u00e0 {4} chacun) +itemSpawn=\u00a77Donne {0} de {1} +itemType=\u00a76Item \:\u00a7c {0} \u00a76-\u00a7c {1} +itemsCsvNotLoaded=Essentials n''a pas pu charger items.csv. +jailAlreadyIncarcerated=\u00a7cJoueur d\u00e9j\u00e0 emprisonn\u00e9 \: {0} +jailMessage=\u00a7cVous avez commis un crime, vous en payez le prix. +jailNotExist=Cette prison n''existe pas. +jailReleased=\u00a77Joueur \u00a7e{0}\u00a77 lib\u00e9r\u00e9. +jailReleasedPlayerNotify=\u00a77Vous avez \u00e9t\u00e9 lib\u00e9r\u00e9 \! +jailSentenceExtended=Dur\u00e9e d''emprisonnement rallong\u00e9e de \: {0} +jailSet=\u00a77La prison {0} a \u00e9t\u00e9 cr\u00e9\u00e9e. +jumpError=\u00c7a aurait pu faire mal au cerveau de votre ordinateur. +kickDefault=\u00c9ject\u00e9 du serveur. +kickExempt=\u00a77Vous ne pouvez pas \u00e9jecter ce joueur. +kickedAll=\u00a7cTous les joueurs ont \u00e9t\u00e9 \u00e9ject\u00e9s. +kill=\u00a77{0} a \u00e9t\u00e9 tu\u00e9. +killExempt=\u00a74Vous ne pouvez pas tuer \u00a7c{0}\u00a74. +kitCost=\ \u00a77\u00a7o({0})\u00a7r +kitError2=\u00a74Ce kit est mal d\u00e9fini. Contactez un administrateur. +kitError=\u00a7cIl n''y a pas de kits valides. +kitGiveTo=\u00a76Don du kit\u00a7c {0}\u00a76 \u00e0 \u00a7c{1}\u00a76. +kitInvFull=\u00a7cVotre inventaire \u00e9tait plein, le kit est par terre. +kitNotFound=\u00a74Ce kit n''existe pas. +kitOnce=\u00a74Vous ne pouvez pas utiliser ce kit de nouveau. +kitReceive=\u00a76Kit\u00a7c {0}\u00a76 re\u00e7u. +kitTimed=\u00a7cVous ne pouvez pas utiliser ce kit pendant encore {0}. +kits=\u00a76Kits \:\u00a7r {0} +leatherSyntax=\u00a76Syntaxe de la couleur du cuir \: color\:,, exemple \: color\:255,0,0. +lightningSmited=\u00a77Vous venez d''\u00eatre foudroy\u00e9. +lightningUse=\u00a77{0} \u00a76a \u00e9t\u00e9 foudroy\u00e9. +listAfkTag=\u00a77[AFK]\u00a7r +listAmount=\u00a79Il y a \u00a7c{0}\u00a79 joueurs en ligne sur \u00a7c{1}\u00a79 au total. +listAmountHidden=\u00a79Il y a \u00a7c{0}\u00a77/{1}\u00a79 sur un maximum de \u00a7c{2}\u00a79 joueurs en ligne. +listGroupTag=\u00a76{0}\u00a7r \: \u00a7r +listHiddenTag=\u00a77[MASQU\u00c9]\u00a7f +loadWarpError=\u00c9chec du chargement du warp {0}. +localFormat=[L]<{0}> {1} +mailClear=\u00a76Pour marquer votre courrier comme lu, tapez\u00a7c /mail clear\u00a76. +mailCleared=\u00a77Courrier supprim\u00e9 \! +mailSent=\u00a77Courrier envoy\u00e9 \! +markMailAsRead=\u00a76Pour marquer votre courrier comme lu, tapez\u00a7c /mail clear\u00a76. +markedAsAway=\u00a77Vous \u00eates d\u00e9sormais absent/AFK. +markedAsNotAway=\u00a77Vous n''\u00eates plus absent/AFK. +matchingIPAddress=\u00a76Les joueurs suivant ce sont d\u00e9j\u00e0 connect\u00e9s avec cette adresse \: +maxHomes=Vous ne pouvez pas cr\u00e9er plus de {0} r\u00e9sidences. +mayNotJail=\u00a7cVous ne pouvez pas emprisonner cette personne. +me=moi +minute=minute +minutes=minutes +missingItems=\u00a74Vous n''avez pas \u00a7c{0}x {1}\u00a74. +mobSpawnError=Erreur lors du changement du g\u00e9n\u00e9rateur de cr\u00e9atures. +mobSpawnLimit=Quantit\u00e9 de cr\u00e9atures limit\u00e9 \u00e0 au maximum du serveur. +mobSpawnTarget=Le bloc cible doit \u00eatre un g\u00e9n\u00e9rateur de cr\u00e9atures. +mobsAvailable=\u00a77cr\u00e9atures \: {0} +moneyRecievedFrom=\u00a7a{0} a \u00e9t\u00e9 re\u00e7u de {1}. +moneySentTo=\u00a7a{0} ont \u00e9t\u00e9 envoy\u00e9s \u00e0 {1}. +month=mois +months=mois +moreThanZero=Les quantit\u00e9s doivent \u00eatre sup\u00e9rieures \u00e0 z\u00e9ro. +moveSpeed=\u00a76Vitesse de {0} d\u00e9finie \u00e0\u00a7c {1} \u00a76pour \u00a7c{2}\u00a76. +msgFormat=\u00a76[\u00a7c{0}\u00a76 -> \u00a7c{1}\u00a76] \u00a7r{2} +multipleCharges=\u00a74Vous ne pouvez pas appliquer plus d''une charge \u00e0 ce feu d''artifice. +multiplePotionEffects=\u00a74Vous ne pouvez pas appliquer plus d''un effet \u00e0 cette potion. +muteExempt=\u00a7cVous ne pouvez pas r\u00e9duire ce joueur au silence. +muteNotify=\u00a7c{0} \u00a76a rendu muet \u00a7c{1}\u00a76. +mutedPlayer=\u00a76Le joueur\u00a7c {0} \u00a76est muet. +mutedPlayerFor=\u00a7c{0} \u00a76est muet pour\u00a7c {1}\u00a76. +mutedUserSpeaks={0} a essay\u00e9 de parler mais est muet. +nearbyPlayers=Joueurs dans les environs \: {0} +negativeBalanceError=L''utilisateur n''est pas autoris\u00e9 \u00e0 avoir un solde n\u00e9gatif. +nickChanged=surnom modifi\u00e9. +nickDisplayName=\u00a77Vous devez activer change-displayname dans la configuration Essentials. +nickInUse=\u00a7cCe nom est d\u00e9j\u00e0 utilis\u00e9. +nickNamesAlpha=\u00a7cLes surnoms doivent \u00eatre alphanum\u00e9riques. +nickNoMore=\u00a7 Vous n''avez plus de surnom. +nickSet=\u00a76Votre surnom est maintenant \u00a7c{0}\u00a76. +nickTooLong=\u00a74Ce surnom est trop long. +noAccessCommand=\u00a7cVous n''avez pas acc\u00e8s \u00e0 cette commande. +noAccessPermission=\u00a74Vous n''avez pas la permission d\u2019acc\u00e9der \u00e0 cette \u00a7c{0}\u00a74. +noBreakBedrock=Vous n''\u00eates pas autoris\u00e9s \u00e0 d\u00e9truire la bedrock. +noDestroyPermission=\u00a74Vous n''avez pas la permission de d\u00e9truire ce/cette \u00a7c{0}\u00a74. +noDurability=\u00a7cCet item n''a pas de durabilit\u00e9. +noGodWorldWarning=\u00a7cAttention \! Le mode dieu est d\u00e9sactiv\u00e9 dans ce monde. +noHelpFound=\u00a7cAucune commande correspondante. +noHomeSetPlayer=Le joueur n''a pas d\u00e9fini sa r\u00e9sidence. +noIgnored=\u00a76Vous n''ignorez personne. +noKitPermission=\u00a7cVous avez besoin de la permission \u00a7c{0}\u00a7c pour utiliser ce kit. +noKits=\u00a77Il n''y a pas encore de kits disponibles. +noMail=Vous n''avez pas de courrier +noMatchingPlayers=\u00a76Aucun joueur correspondant. +noMetaFirework=\u00a74Vous n''avez pas la permission d''appliquer des m\u00e9tadatas aux feux d''artifice. +noMetaPerm=\u00a74Vous n''avez pas la permission d''appliquer la m\u00e9tadata \u00a7c{0}\u00a74 \u00e0 cet item. +noNewMail=\u00a77Vous n''avez pas de courrier. +noPendingRequest=Vous n''avez pas de requ\u00eate non lue. +noPerm=\u00a7cVous n''avez pas la permission \u00a7f{0}\u00a7c. +noPermToSpawnMob=\u00a7cVous n''avez pas la permission d''invoquer cette cr\u00e9ature. +noPlacePermission=\u00a7cVous n''avez pas la permission de placer un bloc pr\u00e8s de cette pancarte. +noPotionEffectPerm=\u00a74Vous n''avez pas la permission d''appliquer l''effet \u00a7c{0} \u00a74\u00e0 cette potion. +noPowerTools=Vous n''avez pas d''outil macro associ\u00e9. +noWarpsDefined=Aucun warp d\u00e9fini. +none=aucun +notAllowedToQuestion=\u00a7cVous n''\u00eates pas autoris\u00e9 \u00e0 poser des questions. +notAllowedToShout=\u00a7cVous n''\u00eates pas autoris\u00e9 \u00e0 crier. +notEnoughExperience=Vous n''avez pas assez d''exp\u00e9rience. +notEnoughMoney=Vous n''avez pas les fonds n\u00e9cessaires. +notFlying=ne volant pas +notRecommendedBukkit=* \! * Cette version de Bukkit n''est pas recommand\u00e9 pour cette version de Essentials. +notSupportedYet=Pas encore pris en charge. +nothingInHand=\u00a7cVous n''avez rien en main. +now=maintenant +nuke=Que la mort s''abatte sur eux \! +numberRequired=Un nombre est requis ici. +onlyDayNight=/time ne supporte que day/night (jour/nuit). +onlyPlayerSkulls=\u00a74Vous ne pouvez d\u00e9finir que le propri\u00e9taire des t\u00eates de joueurs (\u00a7c397\:3\u00a74). +onlyPlayers=\u00a74Seul les joueurs en jeu peuvent utiliser \u00a7c{0}\u00a74. +onlySunStorm=/weather ne supporte que (soleil) sun/storm (temp\u00eate). +orderBalances=Classement des soldes des {0} joueurs, patientez... +oversizedTempban=\u00a74Vous ne pouvez pas bannir un joueur pour cette p\u00e9riode. +pTimeCurrent=Pour \u00a7e{0}\u00a7f l''heure est {1}. +pTimeCurrentFixed=L''heure de \u00a7e{0}\u00a7f est fix\u00e9e \u00e0 {1}. +pTimeNormal=\u00a7fPour \u00a7e{0}\u00a7f l''heure est normale et correspond au serveur. +pTimeOthersPermission=\u00a7cVous n''\u00eates pas autoris\u00e9 \u00e0 changer l''heure des autres joueurs. +pTimePlayers=Ces joueurs ont leur propre horaire \: +pTimeReset=L''heure a \u00e9t\u00e9 r\u00e9initialis\u00e9e \u00e0 \: \u00a7e{0} +pTimeSet=L''heure du joueur a \u00e9t\u00e9 r\u00e9gl\u00e9e \u00e0 \u00a73{0}\u00a7f pour \: \u00a7e{1} +pTimeSetFixed=L''heure du joueur a \u00e9t\u00e9 fix\u00e9e \u00e0 \: \u00a7e{1} +pWeatherCurrent=Pour \u00a7e{0}\u00a7f la m\u00e9t\u00e9o est {1}. +pWeatherInvalidAlias=\u00a74Type de m\u00e9t\u00e9o invalide. +pWeatherNormal=\u00a7fPour \u00a7e{0}\u00a7f la m\u00e9t\u00e9o est normale et correspond au serveur. +pWeatherOthersPermission=\u00a7cVous n''\u00eates pas autoris\u00e9 \u00e0 changer la m\u00e9t\u00e9o des autres joueurs. +pWeatherPlayers=Ces joueurs ont leur propre m\u00e9t\u00e9o \: +pWeatherReset=La m\u00e9t\u00e9o a \u00e9t\u00e9 r\u00e9initialis\u00e9e \u00e0 \: \u00a7e{0} +pWeatherSet=La m\u00e9t\u00e9o du joueur a \u00e9t\u00e9 r\u00e9gl\u00e9e \u00e0 \u00a73{0}\u00a7f pour \: \u00a7e{1} +pendingTeleportCancelled=\u00a7cRequete de t\u00e9l\u00e9portation annul\u00e9e. +playerBanIpAddress=\u00a76Player\u00a7c {0} \u00a76banned IP address\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerBanned=\u00a76Le joueur\u00a7c {0} \u00a76a banni\u00a7c {1} \u00a76pour \u00a7c{2}\u00a76. +playerInJail=\u00a74Le joueur est d\u00e9j\u00e0 en prison(\u00a7c {0}\u00a74). +playerJailed=\u00a77Le joueur {0} a \u00e9t\u00e9 emprisonn\u00e9. +playerJailedFor=\u00a77{0} a \u00e9t\u00e9 emprisonn\u00e9 pour {1}. +playerKicked=\u00a7c{0} a \u00e9t\u00e9 \u00e9ject\u00e9 {1} pour {2}. +playerMuted=\u00a77Vous avez \u00e9t\u00e9 r\u00e9duit au silence. +playerMutedFor=\u00a77Vous avez \u00e9t\u00e9 r\u00e9duit au silence pour {0} +playerNeverOnServer=\u00a7cLe joueur {0} n''a jamais \u00e9t\u00e9 sur le serveur. +playerNotFound=\u00a7cLe joueur est introuvable. +playerUnbanIpAddress=\u00a7c{0} \u00a76a d\u00e9banni l''IP {1}. +playerUnbanned=\u00a76Le joueur\u00a7c {0} \u00a76a d\u00e9banni\u00a7c {1}. +playerUnmuted=\u00a77Vous avez de nouveau la parole. +pong=Pong \! +posPitch=\u00a76Pitch \: {0} (Angle de t\u00eate) +posX=\u00a76X\: {0} (+Est <-> -Ouest) +posY=\u00a76Y\: {0} (+Haut <-> -Bas) +posYaw=\u00a76Yaw \: {0} (Rotation) +posZ=\u00a76Z\: {0} (+Sud <-> -Nord) +possibleWorlds=\u00a76Les mondes possibles sont les nombres de \u00a7c0\u00a76 \u00e0 \u00a7c{0}\u00a76. +potions=\u00a76Potions \:\u00a7r {0}\u00a76. +powerToolAir=La commande ne peut pas \u00eatre assign\u00e9e \u00e0 l''air. +powerToolAlreadySet=\u00a74La commande \u00a7c{0}\u00a74 est d\u00e9j\u00e0 assign\u00e9e \u00e0 \u00a7c{1}\u00a74. +powerToolAttach=Commande \u00a7c{0}\u00a7f assign\u00e9e \u00e0 {1}. +powerToolClearAll=Toutes les commandes assign\u00e9es ont \u00e9t\u00e9 retir\u00e9es. +powerToolList={1} assign\u00e9s aux commandes \: \u00a7c{0}\u00a7f. +powerToolListEmpty={0} n''a pas de commande assign\u00e9e. +powerToolNoSuchCommandAssigned=\u00a74La commande \u00a7c{0}\u00a74 n''a pas \u00e9t\u00e9 assign\u00e9e \u00e0 \u00a7c{1}\u00a74. +powerToolRemove=\u00a76La commande \u00a7c{0}\u00a76 a \u00e9t\u00e9 retir\u00e9e de \u00a7c{1}\u00a76. +powerToolRemoveAll=\u00a76Toutes les commandes ont \u00e9t\u00e9 retir\u00e9es de \u00a7c{0}\u00a76. +powerToolsDisabled=Toutes vos commandes assign\u00e9es ont \u00e9t\u00e9 d\u00e9sactiv\u00e9es. +powerToolsEnabled=Toutes vos commandes assign\u00e9es ont \u00e9t\u00e9 activ\u00e9es. +questionFormat=\u00a72[Question]\u00a7r {0} +readNextPage=Utilisez /{0} {1} pour lire la page suivante. +recipe=\u00a76Recette pour \u00a7c{0}\u00a76 (\u00a7c{1}\u00a76 sur \u00a7c{2}\u00a76) +recipeBadIndex=Il n''y a pas de rec\u00eate pour ce num\u00e9ro. +recipeFurnace=\u00a76Faire fondre \: \u00a7c{0}\u00a76. +recipeGrid=\u00a7c{0}X \u00a76| \u00a7{1}X \u00a76| \u00a7{2}X +recipeGridItem=\u00a7c{0}X \u00a76est \u00a7c{1} +recipeMore=\u00a76Tapez /{0} \u00a7c{1}\u00a76 pour voir les autres rec\u00eates pour \u00a7c{2} +recipeNone=Aucune rec\u00eate n''existe pour {0}. +recipeNothing=rien +recipeShapeless=\u00a76Combiner \u00a7c{0} +recipeWhere=\u00a76O\u00f9 \: {0} +removed=\u00a77{0} entit\u00e9s supprim\u00e9es. +repair=\u00a76Vous avez r\u00e9par\u00e9 avec succ\u00e8s votre \: \u00a7c{0}\u00a76. +repairAlreadyFixed=\u00a77Cet objet n''a pas besoin de r\u00e9paration. +repairEnchanted=\u00a77Vous n''\u00eates pas autoris\u00e9 \u00e0 r\u00e9parer les objets enchant\u00e9s. +repairInvalidType=\u00a7cCet objet ne peut \u00eatre r\u00e9par\u00e9. +repairNone=\u00a74Il n''y avait pas d''objets ayant besoin de r\u00e9paration. +requestAccepted=\u00a77Demande de t\u00e9l\u00e9portation accept\u00e9e. +requestAcceptedFrom=\u00a77{0} a accept\u00e9 votre demande de t\u00e9l\u00e9portation. +requestDenied=\u00a77Demande de t\u00e9l\u00e9portation refus\u00e9e. +requestDeniedFrom=\u00a77{0} a refus\u00e9 votre demande de t\u00e9l\u00e9portation. +requestSent=\u00a77Requ\u00eate envoy\u00e9e \u00e0 {0}\u00a77. +requestTimedOut=\u00a7cLa demande de t\u00e9l\u00e9portation a expir\u00e9. +requiredBukkit=* \! * Vous avez au moins besoin de la version {0} de CraftBukkit. T\u00e9l\u00e9chargez-la ici http\://dl.bukkit.org/downloads/craftbukkit/ +resetBal=\u00a76Le solde a \u00e9t\u00e9 r\u00e9initialis\u00e9 \u00e0 \u00a7c{0} \u00a76pour tous les joueurs en ligne. +resetBalAll=\u00a76Le solde a \u00e9t\u00e9 r\u00e9initialis\u00e9 \u00e0 \u00a7c{0} \u00a76pour tous les joueurs. +returnPlayerToJailError=\u00a74Une erreur est survenue en essayant de remettre le joueur\u00a7c {0} \u00a74dans la prison \: \u00a7c{1}\u00a74 \! +runningPlayerMatch=\u00a76Recherche en cours des joueurs ayant utilis\u00e9 l''IP ''\u00a7c{0}\u00a76'' (cette op\u00e9ration peut prendre un certain temps) +second=seconde +seconds=secondes +seenOffline=\u00a76Le joueur\u00a7c {0} \u00a76est \u00a74hors-ligne\u00a76 depuis \u00a7c{1}\u00a76. +seenOnline=\u00a76Le joueur\u00a7c {0} \u00a76est \u00a74en ligne\u00a76 depuis \u00a7c{1}\u00a76. +serverFull=Le serveur est plein. +serverTotal=Total du serveur \: {0} +setBal=\u00a7aVotre solde a \u00e9t\u00e9 modifi\u00e9 \u00e0 {0}. +setBalOthers=\u00a7aVous avez modifi\u00e0 le solde de {0} \u00e0 {1}. +setSpawner=\u00a76Type de spawner chang\u00e9 en\u00a7c {0}\u00a76. +sheepMalformedColor=Couleur incorrecte. +shoutFormat=\u00a77[Crie]\u00a7f {0} +signFormatFail=\u00a74[{0}] +signFormatSuccess=\u00a71[{0}] +signFormatTemplate=[{0}] +signProtectInvalidLocation=\u00a74Vous n''avez pas l''autorisation de cr\u00e9er une pancarte ici. +similarWarpExist=Un warp avec un nom similaire existe d\u00e9j\u00e0. +slimeMalformedSize=Taille incorrecte. +socialSpy=\u00a76SocialSpy pour \u00a7c{0}\u00a76 \: \u00a7c{1} +soloMob=Cette cr\u00e9ature pr\u00e9f\u00e8re \u00eatre seule. +spawnSet=\u00a77Le point de d\u00e9part a \u00e9t\u00e9 d\u00e9fini pour le groupe {0}. +spawned=invoqu\u00e9(s) +sudoExempt=Vous ne pouvez pas ex\u00e9cuter une commande de force \u00e0 la place de ce joueur. +sudoRun=\u00a76Forcing\u00a7c {0} \u00a76to run\:\u00a7r /{1} +suicideMessage=\u00a77Au revoir monde cruel... +suicideSuccess=\u00a77{0} s''est suicid\u00e9. +survival=survie +takenFromAccount=\u00a7c{0} ont \u00e9t\u00e9 retir\u00e9s de votre compte. +takenFromOthersAccount=\u00a7c{0} retir\u00e9s du compte de {1}\u00a7c. Nouveau solde \: {2} +teleportAAll=\u00a77Demande de t\u00e9l\u00e9portation envoy\u00e9e \u00e0 tous les joueurs... +teleportAll=\u00a77T\u00e9l\u00e9portation de tous les joueurs. +teleportAtoB=\u00a7c{0}\u00a76 vous a t\u00e9l\u00e9port\u00e9 \u00e0 \u00a7c{1}\u00a76. +teleportDisabled={0} a la t\u00e9l\u00e9portation d\u00e9sactiv\u00e9. +teleportHereRequest=\u00a7c{0}\u00a7c Vous a demand\u00e9 de vous t\u00e9l\u00e9porter \u00e0 lui/elle. +teleportNewPlayerError=\u00c9chec de la t\u00e9l\u00e9portation du nouveau joueur. +teleportRequest=\u00a7c{0}\u00a7c vous demande s''il peut se t\u00e9l\u00e9porter vers vous. +teleportRequestTimeoutInfo=\u00a77Cette demande de t\u00e9l\u00e9portation expirera dans {0} secondes. +teleportTop=\u00a77T\u00e9l\u00e9portation vers le haut. +teleportationCommencing=\u00a77D\u00e9but de la t\u00e9l\u00e9portation... +teleportationDisabled=\u00a76T\u00e9l\u00e9portation \u00a7cd\u00e9sactiv\u00e9e\u00a76. +teleportationDisabledFor=\u00a76T\u00e9l\u00e9portation \u00a7cd\u00e9sactiv\u00e9e \u00a76pour \u00a7c{0}\u00a76. +teleportationEnabled=\u00a76T\u00e9l\u00e9portation \u00a7cactiv\u00e9e\u00a76. +teleportationEnabledFor=\u00a76T\u00e9l\u00e9portation \u00a7cactiv\u00e9e \u00a76pour \u00a7c{0}\u00a76. +teleporting=\u00a77T\u00e9l\u00e9portation en cours... +teleportToPlayer=\u00a76T\u00e9l\u00e9portation vers \u00a7c{0}\u00a76. +tempBanned=\u00a7cYou have been temporarily banned for {0}\:\n\u00a7r{2} +tempbanExempt=\u00a77Vous ne pouvez pas bannir temporairement ce joueur. +thunder=Vous avez {0} la foudre dans votre monde. +thunderDuration=Vous avez {0} la foudre sur le serveur pendant {1} seconde(s). +timeBeforeHeal=Temps avant le prochain soin \: {0} +timeBeforeTeleport=Temps avant la prochaine t\u00e9l\u00e9portation {0} +timeFormat=\u00a7c{0}\u00a76 ou \u00a7c{1}\u00a76 ou \u00a7c{2}\u00a76 +timeSetPermission=\u00a7cVous n''\u00eates pas autoris\u00e9 \u00e0 r\u00e9gler l''heure. +timeWorldCurrent=Il est \u00a73{1}\u00a77 dans \u00a7c{0}. +timeWorldSet=L''heure a \u00e9t\u00e9 r\u00e9gl\u00e9e \u00e0 {0} dans \: \u00a7c{1} +totalWorthAll=\u00a7aTous les blocs et items ont \u00e9t\u00e9 vendus pour une valeur totale de \u00a7c{1}\u00a7a. +totalWorthBlocks=\u00a7aTous les blocs ont \u00e9t\u00e9 vendus pour une valeur totale de \u00a7c{1}\u00a7a. +tps=TPS actuellement \= {0} +tradeSignEmpty=Le panneau de vente n''a pas encore assez de stock. +tradeSignEmptyOwner=Il n''y a rien \u00e0 collecter de cette pancarte d''\u00e9change commercial. +treeFailure=\u00a7c\u00c9chec de la g\u00e9n\u00e9ration de l''arbre. Essayez de nouveau sur de l''herbe ou de la terre. +treeSpawned=\u00a77Arbre cr\u00e9\u00e9. +true=\u00a72vrai\u00a7f +typeTpaccept=\u00a77Pour le t\u00e9l\u00e9porter, utilisez \u00a7c/tpaccept\u00a77 \u00a77ou \u00a7c/tpyes\u00a77. +typeTpdeny=\u00a77Pour d\u00e9cliner cette demande, utilisez \u00a7c/tpdeny\u00a77 \u00a77ou \u00a7c/tpno\u00a77. +typeWorldName=\u00a77Vous pouvez aussi taper le nom d''un monde sp\u00e9cifique. +unableToSpawnMob=Incapable d''invoquer une cr\u00e9ature. +unignorePlayer=Vous n''ignorez plus {0}. +unknownItemId=Num\u00e9ro d''objet inconnu \: {0} +unknownItemInList=L''objet {0} est inconnu dans la liste {1}. +unknownItemName=Nom d''objet inconnu \: {0} +unlimitedItemPermission=\u00a74Pas de permission pour l''objet illimit\u00e9 \u00a7c{0}\u00a74. +unlimitedItems=Objets illimit\u00e9s \: +unmutedPlayer=Le joueur {0} n''est plus muet. +unvanishedReload=\u00a7cUn reload vous a rendu de nouveau visible. +upgradingFilesError=Erreur durant la mise \u00e0 jour des fichiers. +uptime=\u00a76Dur\u00e9e de fonctionnement \:\u00a7c {0} +userAFK=\u00a75{0} \u00a75est actuellement absent/AFK et peut ne pas r\u00e9pondre. +userDoesNotExist=L''utilisateur {0} n''existe pas. +userIsAway={0} est d\u00e9sormais AFK. +userIsNotAway={0} n''est plus AFK. +userJailed=\u00a77Vous avez \u00e9t\u00e9 emprisonn\u00e9. +userUnknown=\u00a74Attention \: le joueur \u00a7c{0}\u00a74 n''est jamais venu sur ce serveur. +userdataMoveBackError=\u00c9chec du d\u00e9placement de userdata/{0}.tmp vers userdata/{1} +userdataMoveError=\u00c9chec du d\u00e9placement de userdata/{0} vers userdata/{1}.tmp +usingTempFolderForTesting=Utilise un fichier temporaire pour un test. +vanished=\u00a7aVous \u00eates d\u00e9sormais invisible. +versionMismatch=Versions diff\u00e9rentes \! Veuillez mettre {0} \u00e0 la m\u00eame version. +versionMismatchAll=Mauvaise version \! Veuillez mettre des jars Essentials de m\u00eame version. +voiceSilenced=\u00a77Vous avez \u00e9t\u00e9 r\u00e9duit au silence. +walking=en train de marcher +warpDeleteError=Probl\u00e8me concernant la suppression du fichier warp. +warpList={0} +warpListPermission=\u00a7cVous n''avez pas la permission d''afficher la liste des points de t\u00e9l\u00e9portation. +warpNotExist=Ce warp n''existe pas. +warpOverwrite=\u00a7cVous ne pouvez pas \u00e9craser ce warp. +warpSet=\u00a77Le warp {0} a \u00e9t\u00e9 cr\u00e9\u00e9. +warpUsePermission=\u00a7cVous n''avez pas la permission d''utiliser ce warp. +warpingTo=\u00a77T\u00e9l\u00e9portation vers {0}. +warps=\u00a76Warps \:\u00a7r {0} +warpsCount=\u00a76Il y a\u00a7c {0} \u00a76warps. Page \u00a7c{1} \u00a76sur \u00a7c{2}\u00a76. +weatherStorm=\u00a77Vous avez programm\u00e9 l''orage dans {0}. +weatherStormFor=\u00a77Vous avez programm\u00e9 l''orage dans {0} pour {1} seconde(s). +weatherSun=\u00a77Vous avez programm\u00e9 le beau temps dans {0}. +weatherSunFor=\u00a77Vous avez programm\u00e9 le beau temps dans {0} pour {1} seconde(s). +whoisAFK=\u00a76 - AFK/Absent \:\u00a7f {0} +whoisBanned=\u00a76 - Banni \:\u00a7f {0} +whoisExp=\u00a76 - Exp\u00e9rience \:\u00a7f {0} (Niveau {1}) +whoisFly=\u00a76 - Fly mode \:\u00a7f {0} ({1}) +whoisGamemode=\u00a76 - Mode de jeu \:\u00a7f {0} +whoisGeoLocation=\u00a76 - Emplacement \:\u00a7f {0} +whoisGod=\u00a76 - Mode Dieu \:\u00a7f {0} +whoisHealth=\u00a76 - Sant\u00e9 \:\u00a7f {0} / 20 +whoisIPAddress=\u00a76 - Adresse IP \:\u00a7f {0} +whoisJail=\u00a76 - Prison \:\u00a7f {0} +whoisLocation=\u00a76 - Position \:\u00a7f ({0}, {1}, {2}, {3}) +whoisMoney=\u00a76 - Argent \:\u00a7f {0} +whoisMuted=\u00a76 - Muet \:\u00a7f {0} +whoisNick=\u00a76 - Surnom \:\u00a7f {0} +whoisOp=\u00a76 - OP \:\u00a7f {0} +whoisTop=\u00a76 \=\=\=\=\=\= WhoIs\:\u00a7c {0} \u00a76\=\=\=\=\=\= +worth=\u00a77Un stack de {0} vaut \u00a7c{1}\u00a77 ({2} objet(s) \u00e0 {3} chacun) +worthMeta=\u00a77Un stack de {0} de type {1} vaut \u00a7c{2}\u00a77 ({3} objet(s) \u00e0 {4} chacun) +worthSet=Valeur cr\u00e9\u00e9e. +year=ann\u00e9e +years=ann\u00e9es +youAreHealed=\u00a77Vous avez \u00e9t\u00e9 soign\u00e9. +youHaveNewMail=\u00a7cVous avez {0} message(s) \! \u00a7fEntrez \u00a77/mail read\u00a7f pour voir votre courrier. +whoisHunger=\u00a76 - Faim \:\u00a7r {0} / 20 (+{1} saturation) +kitDelay=\u00a7m{0}\u00a7r +giveSpawnFailure=\u00a74Pas assez d''espace dans l''inventaire, \u00a7c{0} \u00a7c{1} \u00a74n''ont pas pu \u00eatre donn\u00e9s. +noKitGroup=\u00a74Vous n''avez pas acc\u00e8 \u00e0 ce kit. +inventoryClearingFromAll=\u00a76Tous les inventaires sont en train d''\u00ea vid\u00e9s... +inventoryClearingAllItems=\u00a76Tous les items de l''inventaire de {0}\u00a76 ont \u00e9t\u00e9 supprim\u00e9s. +inventoryClearingAllArmor=\u00a76Tous les items de l''inventaire et l''armure de {0}\u00a76 ont \u00e9t\u00e9 supprim\u00e9s. +inventoryClearingAllStack=\u00a76Tous les\u00a7c {0} \u00a76de l''inventaire de {1}\u00a76 ont \u00e9t\u00e9 supprim\u00e9s. +inventoryClearingStack=\u00a7c{0} \u00a7c {1} \u00a76ont \u00e9t\u00e9 supprim\u00e9s de l''inventaire de {2}\u00a76. +inventoryClearFail=\u00a74Le joueur {0} \u00a74n''a pas\u00a7c {1}\u00a7c {2}\u00a74 sur lui. +localNoOne= +totalSellableAll=\u00a7aLa valeur totale de tous les items et blocs que vous pouvez vendre est de \u00a7c{1}\u00a7a. +totalSellableBlocks=\u00a7aLa valeur totale de tous les blocs que vous pouvez vendre est \u00a7c{1}\u00a7a. +radiusTooBig=\u00a74Le rayon est trop grand \! Le rayon maximum est {0}. +isIpBanned=\u00a76L''IP \u00a7c{0} \u00a76est bannie. +mobDataList=\u00a76Donn\u00e9es de mob valides \:\u00a7r {0} +vanish=\u00a76Invisibilit\u00e9 pour {0}\u00a76 \: {1} +noLocationFound=\u00a74Aucun emplacement valide n''a \u00e9t\u00e9 trouv\u00e9. +coordsKeyword={0}, {1}, {2} +banExemptOffline=\u00a74Vous ne pouvez bannir les joueurs d\u00e9connect\u00e9s. +tempbanExemptOffline=\u00a74Vous ne pouvez pas bannir temporairement les joueurs d\u00e9connect\u00e9s. +mayNotJailOffline=\u00a74Vous ne pouvez pas emprisonner les joueurs d\u00e9connect\u00e9s. +muteExemptOffline=\u00a74Vous ne pouvez pas rendre muets les joueurs d\u00e9connect\u00e9s. +ignoreExempt=\u00a74Vous ne pouvez pas ignorer ce joueur. +unsafeTeleportDestination=\u00a74La destination est dangereuse et la t\u00e9l\u00e9portation sans risque est d\u00e9sactiv\u00e9e. +noMetaJson=Les m\u00e9tadonn\u00e9es JSON ne sont pas prises en charge dans cette version de Bukkit. +maxMoney=\u00a74Cette transaction d\u00e9passerait la limite du solde de ce compte. +skullChanged=\u00a76T\u00eate chang\u00e9e en celle de \u00a7c{0}.\u00a76. +alphaNames=\u00a74Les pseudos ne peuvent contenir que des lettres, des chiffres et des underscores. +givenSkull=\u00a76Vous avez re\u00e7u la t\u00eate de \u00a7c{0}\u00a76. +noPermissionSkull=\u00a74Vous n''avez pas la permission de modifier cette t\u00eate. +teleportInvalidLocation=La valeur des coordonn\u00e9es ne peut exc\u00e9der 30 000 000 +invalidSkull=\u00a74Vous devez tenir une t\u00eate de joueur. +weatherInvalidWorld=Le monde {0} est introuvable \! +gameModeInvalid=\u00a74Vous devez sp\u00e9cifier un joueur/mode valide. +mailTooLong=\u00a74Votre mail est trop long. Essayez de le garder en dessous de 1000 caract\u00e8res. +mailDelay=Trop de mails ont \u00e9t\u00e9 envoy\u00e9s durant la derni\u00e8re minute. Maximum \: {0} +seenAccounts=\u00a76Le joueur est aussi connu en tant que \:\u00a7c {0} +unableToSpawnItem=\u00a74Impossible de cr\u00e9er \u00a7c{0}\u00a74, ce n''est pas un objet cr\u00e9able. +itemsConverted=\u00a76Converted all items into blocks. +itemsNotConverted=\u00a74You have no items that can be converted into blocks. +mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\: +mailMessage={0} + +whoisTempBanned=\u00a76 - Ban expires:\u00a7r {0} +playerTempBanned=\u00a76Player \u00a7c{0}\u00a76 temporarily banned \u00a7c{1}\u00a76 for \u00a7c{2}\u00a76: \u00a7c{3}\u00a76. +mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1} diff --git a/Essentials/src/messages_hu.properties b/Essentials/src/messages_hu.properties new file mode 100644 index 0000000000..0ecb75fab0 --- /dev/null +++ b/Essentials/src/messages_hu.properties @@ -0,0 +1,558 @@ +#X-Generator: crowdin.net +#version: TeamCity +# Single quotes have to be doubled: '' +# Translations start here +# by: +action=\u00a75* {0} \u00a75{1} +addedToAccount=\u00a7a{0} hozz\u00e1adva az egyenlegedhez. +addedToOthersAccount=\u00a7a{0} hozz\u00e1dva {1}\u00a7a egyenleg\u00e9hez. \u00daj egyenlege\: {2} +adventure=kaland +alertBroke=t\u00f6r\: +alertFormat=\u00a73[{0}] \u00a7r {1} \u00a76 {2} at\: {3} +alertPlaced=letett\: +alertUsed=haszn\u00e1lt\: +antiBuildBreak=\u00a74Nincs jogod, hogy ki\u00fcss egy\u00a7c {0} \u00a74blokkot itt. +antiBuildCraft=\u00a74Nincs jogod, hogy a k\u00f6vetkez\u0151t k\u00e9sz\u00edtsd\:\u00a7c {0}\u00a74. +antiBuildDrop=\u00a74Nincs jogod, hogy eldobd a k\u00f6vetkez\u0151t\:\u00a7c {0}\u00a74. +antiBuildInteract=\u00a74Nincs jogod, hogy interakci\u00f3ba l\u00e9pj a\u00a7c {0}\u00a74-val/vel. +antiBuildPlace=\u00a74Nincs jogod, hogy lehelyezed\u00a7c {0} \u00a74ide. +antiBuildUse=\u00a74NIncs jogod, hogy haszn\u00e1ld a k\u00f6vetkez\u0151t\:\u00a7c {0}\u00a74. +autoAfkKickReason=Kickelve lett\u00e9l {0} perc AFK miatt\! +backAfterDeath=\u00a76Meghalt\u00e1l\! A \u00a74/back\u00a76 parancssal visszajuthatsz hal\u00e1lod sz\u00ednhely\u00e9re. +backUsageMsg=\u00a76Visszat\u00e9r\u00e9s az el\u0151z\u0151 helyre. +backupDisabled=\u00a74A ment\u00e9s nincs k\u00e9sz +backupFinished=\u00a76Biztons\u00e1gi ment\u00e9s k\u00e9sz. +backupStarted=\u00a76Biztons\u00e1gi ment\u00e9s elkezdve. +balance=\u00a7aEgyenleged\:\u00a7c {0} +balanceOther={0}\u00a7a egyenlege\:\u00a7c {1} +balanceTop=\u00a76Legmagasabb egyenlegek ({0}) +banExempt=\u00a74Nem tilthatod ki ezt a j\u00e1t\u00e9kost. +banFormat=\u00a74Kitiltva\:\n\u00a7r{0} +bed=\u00a7o\u00e1gy\u00a7r +bedMissing=\u00a74Az \u00e1gyad nincs be\u00e1ll\u00edtva vagy eltorlaszolt\u00e1k. +bedNull=\u00a7m\u00e1gy\u00a7r +bedSet=\u00a76\u00c1gyi kezd\u00f5hely be\u00e1ll\u00edtva\! +bigTreeFailure=\u00a74Nagy fa gener\u00e1l\u00e1si hiba\! Pr\u00f3b\u00e1ld \u00fajra f\u00fcv\u00f6n vagy f\u00f6ld\u00f6n. +bigTreeSuccess=\u00a76Nagy fa legener\u00e1lva. +blockList=\u00a76Az Essentials \u00e1tengedte a k\u00f6vetkez\u0151 parancsokat egy m\u00e1sik pluginnak\: +bookAuthorSet=\u00a76Mostant\u00f3l a k\u00f6nyv \u00edr\u00f3ja\: {0}. +bookLocked=\u00a76K\u00f6nyv lez\u00e1rva. +bookTitleSet=\u00a76A k\u00f6nyv c\u00edme mostant\u00f3l\: {0}. +broadcast=\u00a7r\u00a76[\u00a74K\u00f6zvet\u00edt\u00e9s\u00a76]\u00a7a {0} +buildAlert=\u00a74Nincs jogod, hogy \u00e9p\u00edts. +bukkitFormatChanged=Bukkit version format changed. Version not checked. +burnMsg=\u00a76Be\u00e1ll\u00edtottad\u00a7c {0}\u00a76-nak/nek a t\u00fczet\u00a7c {1} m\u00e1sodpercre\u00a76. +canTalkAgain=\u00a76Besz\u00e9lhetsz \u00fajra. +cannotStackMob=\u00a74You do not have permission to stack multiple mobs. +cantFindGeoIpDB=A GeoIP adatb\u00e1zisa nem tal\u00e1lhat\u00f3\! +cantReadGeoIpDB=Nem tudom beolvasni a GeoIP adatb\u00e1zist\! +cantSpawnItem=\u00a74Nincs jogod, hogy lek\u00e9rd a k\u00f6vetkez\u0151 cuccot\:\u00a7c {0}\u00a74. +chatTypeAdmin=[A] +chatTypeLocal=[L] +chatTypeSpy=\u00a72[K\u00e9m]\u00a7r +cleaned=J\u00e1t\u00e9kos f\u00e1jlok t\u00f6r\u00f6lve. +cleaning=J\u00e1t\u00e9kos f\u00e1jlok tiszt\u00edt\u00e1sa. +commandFailed=Parancs {0} sikertelen\: +commandHelpFailedForPlugin=Hiba a seg\u00edts\u00e9g lek\u00e9r\u00e9sben a(z) {0} pluginban +commandNotLoaded=\u00a74Parancs {0} nincs bet\u00f6ltve. +compassBearing=\u00a76Ir\u00e1ny\: {0} ({1} fok). +configFileMoveError=Failed to move config.yml to backup location. +configFileRenameError=Failed to rename temp file to config.yml. +connectedPlayers=\u00a76Csatlakozott j\u00e1t\u00e9kosok\u00a7r +connectionFailed=Failed to open connection. +cooldownWithMessage=\u00a74Cooldown\: {0} +corruptNodeInConfig=\u00a74Notice\: Your configuration file has a corrupt {0} node. +couldNotFindTemplate=\u00a74Could not find template {0} +creatingConfigFromTemplate=Creating config from template\: {0} +creatingEmptyConfig=Creating empty config\: {0} +creative=kreat\u00edv +currency={0}{1} +currentWorld=\u00a76Current World\:\u00a7c {0} +day=nap +days=nap +defaultBanReason=Ki lett\u00e9l tiltva\! +deleteFileError=Could not delete file\: {0} +deleteHome=\u00a76Otthon\u00a7c {0} \u00a76sikeresen elt\u00e1vol\u00edtva. +deleteJail=\u00a76B\u00f6rt\u00f6n\u00a7c {0} \u00a76sikeresen elt\u00e1vol\u00edtva. +deleteWarp=\u00a76Warp\u00a7c {0} \u00a76sikeresen elt\u00e1vol\u00edtva. +deniedAccessCommand=\u00a7c{0} \u00a74was denied access to command. +denyBookEdit=\u00a74You cannot unlock this book. +denyChangeAuthor=\u00a74You cannot change the author of this book. +denyChangeTitle=\u00a74You cannot change the title of this book. +depth=\u00a76You are at sea level. +depthAboveSea=\u00a76You are\u00a7c {0} \u00a76block(s) above sea level. +depthBelowSea=\u00a76You are\u00a7c {0} \u00a76block(s) below sea level. +destinationNotSet=Destination not set\! +disableUnlimited=\u00a76Disabled unlimited placing of\u00a7c {0} \u00a76for {1}. +disabled=letiltva +disabledToSpawnMob=\u00a74Ennek a l\u00e9nynek a leh\u00edv\u00e1sa jelenleg le van tiltva a config f\u00e1jlban. +distance=\u00a76T\u00e1vols\u00e1g\: {0} +dontMoveMessage=\u00a76A teleport\u00e1l\u00e1s elkezd\u00f5dik\u00a7c {0}\u00a76 bel\u00fcl. Ne mozogj\! +downloadingGeoIp=GeoIP adatb\u00e1zis let\u00f6lt\u00e9se folyamatban... eltarthat egy kis ideig (country\: 0.6 MB, city\: 20MB) +duplicatedUserdata=Duplik\u00e1lt felhaszn\u00e1l\u00f3i adatok\: {0} \u00e9s {1}. +durability=\u00a76This tool has \u00a7c{0}\u00a76 uses left +editBookContents=\u00a76Mostant\u00f3l tudod szerkeszteni ezt a k\u00f6nyvet. +enableUnlimited=\u00a76Lek\u00e9rve v\u00e9gtelen mennyis\u00e9g\u0171 \u00a7c {0} \u00a76\u00a7c{1}\u00a76-nak/nek. +enabled=bekapcsolva +enchantmentApplied=\u00a76A k\u00f6vetkez\u0151 enchant\:\u00a7c {0} \u00a76sikeresen r\u00e1 lett rakva a kezedbe l\u00e9v\u0151 dologra. +enchantmentNotFound=\u00a74Enchant nem tal\u00e1lhat\u00f3\! +enchantmentPerm=\u00a74Nincs jogod a k\u00f6vetkez\u0151 enchanthoz\:\u00a7c {0}\u00a74. +enchantmentRemoved=\u00a76A k\u00f6vetkez\u0151 enchant\:\u00a7c {0} \u00a76sikeresen le lett v\u00e9ve a kezedbe l\u00e9v\u0151 dologr\u00f3l. +enchantments=\u00a76Enchantok\:\u00a7r {0} +errorCallingCommand=Hiba a parancs h\u00edv\u00e1s\u00e1ban /{0} +errorWithMessage=\u00a7cHiba\:\u00a74 {0} +essentialsHelp1=The file is broken and Essentials can''t open it. Essentials is now disabled. If you can''t fix the file yourself, go to http\://tiny.cc/EssentialsChat +essentialsHelp2=The file is broken and Essentials can''t open it. Essentials is now disabled. If you can''t fix the file yourself, either type /essentialshelp in game or go to http\://tiny.cc/EssentialsChat +essentialsReload=\u00a76Essentials \u00fajrat\u00f6ltve\u00a7c {0}. +exp=\u00a7c{0} \u00a76has\u00a7c {1} \u00a76exp (level\u00a7c {2}\u00a76) and needs\u00a7c {3} \u00a76more exp to level up. +expSet=\u00a7c{0} \u00a76now has\u00a7c {1} \u00a76exp. +extinguish=\u00a76You extinguished yourself. +extinguishOthers=\u00a76Eloltottad {0}\u00a76-t. +failedToCloseConfig=Nem siker\u00fclt bez\u00e1rni a config f\u00e1jlt {0}. +failedToCreateConfig=Nem siker\u00fclt a config f\u00e1ljt l\u00e1trehozni {0}. +failedToWriteConfig=Nem siker\u00fclt a config f\u00e1jlba \u00edrni {0}. +false=\u00a74hamis\u00a7r +feed=\u00a76Meg lett\u00e9l etetve. +feedOther=\u00a76Megetetted {0}\u00a76-t. +fileRenameError=A(z) {0} f\u00e1jlt nem siker\u00fclt \u00e1tnevezni\! +fireworkColor=\u00a74Nem val\u00f3s param\u00e9rtert adt\u00e1l meg a t\u00f6ltetnek, el\u0151sz\u00f6r a sz\u00edn kell. +fireworkEffectsCleared=\u00a76Az \u00f6sszes effekt elt\u00e1vol\u00edtva. +fireworkSyntax=\u00a76T\u00fczij\u00e1t\u00e9k param\u00e9terek\:\u00a7c color\: [fade\:] [shape\:] [effect\:]\n\u00a76Ahhoz, hogy t\u00f6bb adatot adj meg, vessz\u0151vel kell elv\u00e1lasztanod. pl\: \u00a7cred,blue,pink\n\u00a76Alakzatok\:\u00a7c star, ball, large, creeper, burst \u00a76Effektek\:\u00a7c trail, twinkle. +flyMode=\u00a76Rep\u00fcl\u0151 m\u00f3d\u00a7c {0} \u00a76{1} \u00a76j\u00e1t\u00e9kosnak. +flying=rep\u00fcl +foreverAlone=\u00a74Nincs senki, akinek v\u00e1laszolhatn\u00e1l. +fullStack=\u00a74M\u00e1r teljes a stack. +gameMode={1} \u00a76\u00faj j\u00e1t\u00e9km\u00f3dja\: \u00a7e{0}\u00a76. +gcWorld=\u00a76{0} "\u00a7c{1}\u00a76"\: \u00a7c{2}\u00a76 chunk, \u00a7c{3}\u00a76 entit\u00e1s, \u00a7c{4}\u00a76 blokkok. +gcfree=\u00a76Szabad mem\u00f3ria\:\u00a7c {0} MB. +gcmax=\u00a76Maximum mem\u00f3ria\:\u00a7c {0} MB. +gctotal=\u00a76Lefoglalt mem\u00f3ria\:\u00a7c {0} MB. +geoIpUrlEmpty=GeoIP let\u00f6lt\u00e9si URL hi\u00e1nyzik. +geoIpUrlInvalid=GeoIP let\u00f6lt\u00e9si URL \u00e9rv\u00e9nytelen. +geoipJoinFormat=\u00a7c{0} \u00a76\u00a7c{1}\u00a76-b\u00f3l/b\u0151l csatlakozott. +giveSpawn=\u00a7c{0} \u00a76darab\u00a7c {1} adva\u00a7c {2}\u00a76 j\u00e1t\u00e9kosnak. +godDisabledFor=\u00a7cletiltva\u00a76\u00a7c {0}\u00a76-nak/nek +godEnabledFor=\u00a74enged\u00e9lyezve\u00a7c {0}\u00a76-nak/nek +godMode=\u00a76Isten m\u00f3d\u00a7c {0}\u00a76. +groupDoesNotExist=\u00a74Ebb\u0151l a csapatb\u00f3l senki sincs fent. +groupNumber=\u00a7c{0}\u00a7f van fent, teljes lista\:\u00a7c /{1} {2} +hatArmor=\u00a74Ezt nem veheted fel kalapk\u00e9nt\! +hatEmpty=\u00a74Nem viselsz kalapot. +hatFail=\u00a74Nincs semmi a kezedben amit felvehetn\u00e9l. +hatPlaced=\u00a76\u00c9lvezd az \u00faj kalapod\! +hatRemoved=\u00a76Kalapod elt\u00e1vol\u00edtva. +haveBeenReleased=\u00a76Ki engedtek a b\u00f6rt\u00f6nb\u0151l. +heal=\u00a76\u00c9leted felt\u00f6ltve. +healDead=\u00a74Nem t\u00f6lthed fel olyannak az \u00e9let\u00e9t aki halott\! +healOther=\u00a7c{0}\u00a76 \u00e9lete felt\u00f6ltve. +helpConsole=Hogy seg\u00edts\u00e9get k\u00e9rj konzolb\u00f3l, \u00edrd be\: ?. +helpFrom=\u00a76Parancsok {0}-b\u00f3l/b\u0151l\: +helpLine=\u00a76/{0}\u00a7r\: {1} +helpMatching=\u00a76Egyez\u0151 parancsok "\u00a7c{0}\u00a76"\: +helpOp=\u00a74[Seg\u00edts\u00e9g]\u00a7r \u00a76{0}\:\u00a7r {1} +helpPlugin=\u00a74{0}\u00a7r\: Plugin seg\u00edts\u00e9g\: /help {1} +holdBook=\u00a74Nincs a kezedben \u00edrhat\u00f3 k\u00f6nyv. +holdFirework=\u00a74A kezedben kell tartanod a t\u00fczij\u00e1t\u00e9kot, hogy hozz\u00e1add az effekteket. +holdPotion=\u00a74Egy b\u00e1jitalt kell a kezedben tartanod, hogy effekteket adhass hozz\u00e1. +holeInFloor=\u00a74Lyuk a padl\u00f3ban\! +homeSet=\u00a76Otthon be\u00e1ll\u00edtva. +homes=\u00a76Otthonok\:\u00a7r {0} +hour=\u00f3ra +hours=\u00f3ra +ignoredList=\u00a76Mell\u0151zve\:\u00a7r {0} +ignorePlayer=\u00a76You ignore player\u00a7c {0} \u00a76from now on. +illegalDate=Illegal date format. +infoChapter=\u00a76V\u00e1lassz fejezetet\: +infoChapterPages=\u00a7e ---- \u00a76{0} \u00a7e--\u00a76 Oldal \u00a7c{1}\u00a76 \u00a7c{2}-b\u00f3l/b\u0151l \u00a7e---- +infoPages=\u00a7e ---- \u00a76{2} \u00a7e--\u00a76 Oldal \u00a7c{0}\u00a76/\u00a7c{1} \u00a7e---- +infoUnknownChapter=\u00a74Ismeretlen fejezet. +insufficientFunds=\u00a74Insufficient funds available. +invalidCharge=\u00a74Invalid charge. +invalidFireworkFormat=\u00a76Ez az opci\u00f3\: \u00a74{0} \u00a76nem \u00e9rv\u00e9nyes \u00a74{1}\u00a76-ra/re. +invalidHome=\u00a74Home\u00a7c {0} \u00a74doesn''t exist\! +invalidHomeName=\u00a74Invalid home name\! +invalidMob=\u00a74Hat\u00e1rozatlan mob t\u00edpus +invalidNumber=Invalid Number. +invalidPotion=\u00a74Invalid Potion. +invalidPotionMeta=\u00a74Invalid potion meta\: \u00a7c{0}\u00a74. +invalidSignLine=\u00a74Line\u00a7c {0} \u00a74on sign is invalid. +invalidWarpName=\u00a74Nincs ilyen warp\! +invalidWorld=\u00a74Invalid world. +is=is +itemCannotBeSold=\u00a74Ezt nem adhatod el a szerveren. +itemMustBeStacked=\u00a74Item must be traded in stacks. A quantity of 2s would be two stacks, etc. +itemNames=\u00a76T\u00e1rgy r\u00f6vid nevei\:\u00a7r {0} +itemNotEnough1=\u00a74Nincs el\u00e9g eladni val\u00f3 t\u00e1rgyad. +itemNotEnough2=\u00a76Ha elakarod adni az \u00f6sszes ilyen t\u00e1rgyat \u00edrd be /sell t\u00e1rgyn\u00e9v. +itemNotEnough3=\u00a76/sell itemname -1 will sell all but one item, etc. +itemSellAir=T\u00e9nyleg elakartad adni a Leveg\u00f5t? Vegy\u00e9l a kezedbe valami t\u00e1rgyat. +itemSold=\u00a7aSold for \u00a7c{0} \u00a7a({1} {2} at {3} each). +itemSoldConsole=\u00a7a{0} \u00a7asold {1} for \u00a7a{2} \u00a7a({3} items at {4} each). +itemSpawn=\u00a76Lek\u00e9rt\u00e9l\u00a7c {0} \u00a76db \u00a7c {1}-t +itemType=\u00a76T\u00e1rgy\:\u00a7c {0} \u00a76-\u00a7c {1} +itemsCsvNotLoaded=Could not load items.csv\! +jailAlreadyIncarcerated=\u00a74Person is already in jail\:\u00a7c {0} +jailMessage=\u00a74You do the crime, you do the time. +jailNotExist=\u00a74Nincs ilyen b\u00f6rt\u00f6n. +jailReleased=\u00a7c{0}\u00a76 kiengedve a b\u00f6rt\u00f6nb\u00f5l. +jailReleasedPlayerNotify=\u00a76Kiengedtek a b\u00f6rt\u00f6nb\u0151l\! +jailSentenceExtended=\u00a76B\u00f6rt\u00f6n ideje mostant\u00f3l\: {0} +jailSet=\u00a7c{0} \u00a76 b\u00f6rt\u00f6n be\u00e1ll\u00edtva. +jumpError=\u00a74That would hurt your computer''s brain. +kickDefault=Ki lett\u00e9l kickelve. +kickExempt=\u00a74\u00d5t nem kickelheted. +kickedAll=\u00a74\u00d6sszes j\u00e1t\u00e9kos kickelve a szerverr\u00f5l. +kill=\u00a7c{0}\u00a76 meg\u00f6lve. +killExempt=\u00a74Nem \u00f6lheted meg \u00a7c{0}\u00a74-t. +kitCost=\ \u00a77\u00a7o({0})\u00a7r +kitError2=\u00a74That kit is improperly defined. Contact an administrator. +kitError=\u00a74There are no valid kits. +kitGiveTo=\u00a76A(z)\u00a7c {0}\u00a76 csomag lek\u00e9rve \u00a7c{1}\u00a76-nak/nek. +kitInvFull=\u00a74Az eszk\u00f6zt\u00e1rad televan, \u00edgy a f\u00f6ldre kapod meg a csomagot. +kitNotFound=\u00a74Nincs ilyen csomag. +kitOnce=\u00a74You can''t use that kit again. +kitReceive=\u00a76Megkaptad a(z)\u00a7c {0}\u00a76 csomagot. +kitTimed=\u00a74Ezt a csomagot nem haszn\u00e1hatod m\u00e9g\u00a7c {0}\u00a74-ig. +kits=\u00a76Csomagok\:\u00a7r {0} +leatherSyntax=\u00a76Leather Color Syntax\: color\:,, eg\: color\:255,0,0. +lightningSmited=\u00a76A vill\u00e1m les\u00fajtott r\u00e1d\! +lightningUse=\u00a76Vill\u00e1m lesujt\u00e1sa\u00a7c {0}\u00a76-ra/re +listAfkTag=\u00a77[AFK]\u00a7r +listAmount=\u00a76Jelenleg \u00a7c{0}\u00a76 j\u00e1t\u00e9kos van fent a maxim\u00e1lis \u00a7c{1}\u00a76 j\u00e1t\u00e9kosb\u00f3l. +listAmountHidden=\u00a76Jelenleg \u00a7c{0}\u00a76/{1}\u00a76 j\u00e1t\u00e9kos van fent a maxim\u00e1lis \u00a7c{2}\u00a76 j\u00e1t\u00e9kosb\u00f3l. +listGroupTag={0}\u00a7r\: +listHiddenTag=\u00a77[REJTETT]\u00a7r +loadWarpError=\u00a74Failed to load warp {0}. +localFormat=[L]<{0}> {1} +mailClear=\u00a76Hogy megjel\u00f6ld olvasottk\u00e9nt \u00edrd be a\u00a7c /mail clear \u00a76parancsot. +mailCleared=\u00a76\u00dczenetek t\u00f6r\u00f6lve\! +mailSent=\u00a76Lev\u00e9l elk\u00fcldve\! +markMailAsRead=\u00a76Hogy megjel\u00f6ld olvasottk\u00e9nt \u00edrd be a\u00a7c /mail clear \u00a76parancsot. +markedAsAway=\u00a76You are now marked as away. +markedAsNotAway=\u00a76You are no longer marked as away. +matchingIPAddress=\u00a76Az al\u00e1bbi j\u00e1t\u00e9kosok csatlakoztak utolj\u00e1ra err\u0151l az IP c\u00edmr\u0151l\: +maxHomes=\u00a74You cannot set more than\u00a7c {0} \u00a74homes. +mayNotJail=\u00a74\u00d5t nem rakhatod b\u00f6rt\u00f6nbe\! +me=\u00e9n +minute=perc +minutes=perc +missingItems=\u00a74Nincs \u00a7c{0} db {1}\u00a74-od. +mobSpawnError=\u00a74Error while changing mob spawner. +mobSpawnLimit=Mob quantity limited to server limit. +mobSpawnTarget=\u00a74Target block must be a mob spawner. +mobsAvailable=\u00a76Mobok\:\u00a7r {0} +moneyRecievedFrom=\u00a7a{0}-t kapt\u00e1l {1}\u00a7a-t\u00f3l/t\u00f5l. +moneySentTo=\u00a7a{0}-t k\u00fcldt\u00e9l {1}\u00a7a-nak/nek. +month=h\u00f3nap +months=h\u00f3nap +moreThanZero=\u00a74Quantities must be greater than 0. +moveSpeed=\u00a76Sebess\u00e9g tipus\: {0}, Sebess\u00e9g\:\u00a7c {1}\u00a76-re/ra {2}\u00a76-nak/nek. +msgFormat=\u00a76[\u00a7c{0}\u00a76 -> \u00a7c{1}\u00a76] \u00a7r{2} +multipleCharges=\u00a74Nem alkalmazhatsz t\u00f6bb t\u00f6ltetet enn\u00e9l a t\u00fczij\u00e1t\u00e9kn\u00e1l. +multiplePotionEffects=\u00a74You cannot apply more than one effect to this potion. +muteExempt=\u00a74Nem n\u00e9m\u00edthatod \u00f5t. +muteNotify=\u00a7c{0} \u00a76len\u00e9m\u00edtotta \u00a7c{1}\u00a76-t. +mutedPlayer=\u00a76\u00a7c{0} \u00a76len\u00e9m\u00edtva. +mutedPlayerFor=\u00a76\u00a7c{0} \u00a76len\u00e9m\u00edtva\u00a7c {1}\u00a76-ra/re. +mutedUserSpeaks={0} tried to speak, but is muted. +nearbyPlayers=\u00a76J\u00e1t\u00e9kosok k\u00f6zelbe\:\u00a7r {0} +negativeBalanceError=\u00a74User is not allowed to have a negative balance. +nickChanged=\u00a76Nick megv\u00e1ltoztatva. +nickDisplayName=\u00a74You have to enable change-displayname in Essentials config. +nickInUse=\u00a74Ez a n\u00e9v m\u00e1r haszn\u00e1ltban van. +nickNamesAlpha=\u00a74Nicknames must be alphanumeric. +nickNoMore=\u00a76Nincs t\u00f6bb\u00e9 nicked. +nickSet=\u00a76A nicked mostant\u00f3l\: \u00a7c{0}. +nickTooLong=\u00a76Ez a Nickn\u00e9v t\u00fal hossz\u00fa. +noAccessCommand=\u00a74Nincs jogod ehhez\!. +noAccessPermission=\u00a74Nincs jogod a k\u00f6vetkez\u0151h\u00f6z\: \u00a7c{0}\u00a74. +noBreakBedrock=\u00a74You are not allowed to destroy bedrock. +noDestroyPermission=\u00a74Nincs jogod, hogy ki\u00fcsd ezt\: \u00a7c{0}\u00a74. +noDurability=\u00a74This item does not have a durability. +noGodWorldWarning=\u00a74Vigy\u00e1zat\! Az Isten m\u00f3d ebben a vil\u00e1gba le van tiltva\! +noHelpFound=\u00a74No matching commands. +noHomeSetPlayer=\u00a76Player has not set a home. +noIgnored=\u00a76Nem hagysz figyelmen k\u00edv\u00fcl senkit. +noKitPermission=\u00a74You need the \u00a7c{0}\u00a74 permission to use that kit. +noKits=\u00a76There are no kits available yet. +noMail=\u00a76Nincs leveled. +noMatchingPlayers=\u00a76No matching players found. +noMetaFirework=\u00a74Nincs jogod, hogy alkalmazd ezt a t\u00fczij\u00e1t\u00e9k adatot. +noMetaPerm=\u00a74You do not have permission to apply \u00a7c{0}\u00a74 meta to this item. +noNewMail=\u00a76Nincs \u00faj leveled. +noPendingRequest=\u00a74You do not have a pending request. +noPerm=\u00a74You do not have the \u00a7c{0}\u00a74 permission. +noPermToSpawnMob=\u00a74You don''t have permission to spawn this mob. +noPlacePermission=\u00a74You do not have permission to place a block near that sign. +noPotionEffectPerm=\u00a74You do not have permission to apply potion effect \u00a7c{0} \u00a74to this potion. +noPowerTools=\u00a76You have no power tools assigned. +noWarpsDefined=\u00a76Nincs m\u00e9g egy warp se. +none=none +notAllowedToQuestion=\u00a74You are not authorized to use question. +notAllowedToShout=\u00a74You are not authorized to shout. +notEnoughExperience=\u00a74You do not have enough experience. +notEnoughMoney=\u00a74Erre nincs p\u00e9nzed. +notFlying=nem rep\u00fcl +notRecommendedBukkit=\u00a74* \! * Bukkit version is not the recommended build for Essentials. +notSupportedYet=Not supported yet. +nothingInHand=\u00a74Nincs semmi a kezedben. +now=most +nuke=\u00a75May death rain upon them. +numberRequired=A number goes there, silly. +onlyDayNight=/time only supports day/night. +onlyPlayerSkulls=\u00a74Csak j\u00e1t\u00e9kos fejnek tudod be\u00e1ll\u00edtani a tulajdonos\u00e1t (\u00a7c397\:3\u00a74). +onlyPlayers=\u00a74Csak j\u00e1t\u00e9kon bel\u00fcl haszn\u00e1lhat\u00f3 a \u00a7c{0}\u00a74 parancs. +onlySunStorm=\u00a74/weather only supports sun/storm. +orderBalances=\u00a76Egyenlegek \u00f6sszegy\u00fcjt\u00e9se\u00a7c {0} \u00a76j\u00e1t\u00e9kost\u00f3l, k\u00e9rlek v\u00e1rj... +oversizedTempban=\u00a74You may not ban a player for this period of time. +pTimeCurrent=\u00a7c{0}\u00a76''s time is\u00a7c {1}\u00a76. +pTimeCurrentFixed=\u00a7c{0}\u00a76''s time is fixed to\u00a7c {1}\u00a76. +pTimeNormal=\u00a7c{0}\u00a76''s time is normal and matches the server. +pTimeOthersPermission=\u00a74You are not authorized to set other players'' time. +pTimePlayers=\u00a76These players have their own time\:\u00a7r +pTimeReset=\u00a76Player time has been reset for\: \u00a7c{0} +pTimeSet=\u00a76Player time is set to \u00a7c{0}\u00a76 for\: \u00a7c{1}. +pTimeSetFixed=\u00a76Player time is fixed to \u00a7c{0}\u00a76 for\: \u00a7c{1}. +pWeatherCurrent=\u00a7c{0}\u00a76''s weather is\u00a7c {1}\u00a76. +pWeatherInvalidAlias=\u00a74Invalid weather type +pWeatherNormal=\u00a7c{0}\u00a76''s weather is normal and matches the server. +pWeatherOthersPermission=\u00a74You are not authorized to set other players'' weather. +pWeatherPlayers=\u00a76These players have their own weather\:\u00a7r +pWeatherReset=\u00a76Player weather has been reset for\: \u00a7c{0} +pWeatherSet=\u00a76Player weather is set to \u00a7c{0}\u00a76 for\: \u00a7c{1}. +pendingTeleportCancelled=\u00a74Folyamatban l\u00e9v\u0151 teleport\u00e1l\u00e1s megszak\u00edtva. +playerBanIpAddress=\u00a76Player\u00a7c {0} \u00a76banned IP address\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerBanned=\u00a7c{0} \u00a76kitiltotta\u00a7c {1}\u00a76-t Indok\: \u00a7c{2}\u00a76. +playerInJail=\u00a74M\u00e1r bent van a(z)\u00a7c {0}\u00a74 b\u00f6rt\u00f6nbe. +playerJailed=\u00a76\u00a7c{0} \u00a76beb\u00f6tr\u00f6n\u00f6zve. +playerJailedFor=\u00a76\u00a7c{0} \u00a76beb\u00f6rt\u00f6n\u00f6zve {1}-re/ra. +playerKicked=\u00a7c{0} \u00a76 kickelte {1}-t. Indok\: {2}. +playerMuted=\u00a76Ellett\u00e9l n\u00e9m\u00edtva\! +playerMutedFor=\u00a76Le lett\u00e9l n\u00e9m\u00edtva\u00a7c {0}-ra/re. +playerNeverOnServer=\u00a7c{0} \u00a74 m\u00e9g sose j\u00e1rt a szerveren. +playerNotFound=\u00a74Nincs ilyen nev\u00fb j\u00e1t\u00e9kos. +playerUnbanIpAddress=\u00a76\u00a7c{0} \u00a76feloldotta a k\u00f6vetkez\u00f5 IP c\u00edmet\: {1}. +playerUnbanned=\u00a76\u00a7c{0} \u00a76feloldotta {1}\u00a76-t. +playerUnmuted=\u00a76Fel lett oldva a n\u00e9m\u00edt\u00e1sod. +pong=Pong\! +posPitch=\u00a76Sz\u00f6g\: {0} (Fej sz\u00f6ge) +posX=\u00a76X\: {0} (+Kelet <-> -Nyugat) +posY=\u00a76Y\: {0} (+Fel <-> -Le) +posYaw=\u00a76Fordul\u00e1s\: {0} (Forg\u00e1s) +posZ=\u00a76Z\: {0} (+D\u00e9l <-> -\u00c9szak) +possibleWorlds=\u00a76Lehets\u00e9ges vil\u00e1gok a sz\u00e1ma \u00a7c0\u00a76 kereszt\u00fcl \u00a76\u00a7c{0}. +potions=\u00a76Var\u00e1zsitalok\:\u00a7r {0}\u00a76. +powerToolAir=\u00a74Nem csatolhatsz parancsot a leveg\u00f5h\u00f6z. +powerToolAlreadySet=\u00a74A(z)\u00a7c {0}\u00a74 parancs m\u00e1r bevan \u00e1ll\u00edtva \u00a7c{1}\u00a74-hoz/hez. +powerToolAttach=\u00a7c{0}\u00a76 berakva PowerToolnak a(z) {1}-ra/re. +powerToolClearAll=\u00a76\u00d6sszes PowerTool parancs ki\u00fcr\u00edtve. +powerToolList=\u00a76\u00a7c{1}\u00a76-n a k\u00f6vetkez\u0151 parancsok vannak\: \u00a7c{0}\u00a76. +powerToolListEmpty=\u00a74\u00a7c{0}\u00a74-hoz egy parancs sincs csatolva. +powerToolNoSuchCommandAssigned=\u00a74A(z)\u00a7c {0}\u00a74 parancs nincs be\u00e1ll\u00edtva \u00a7c{1}\u00a74-hoz/hez. +powerToolRemove=\u00a74A(z)\u00a7c {0}\u00a74 parancs lelett szedve \u00a7c{1}\u00a74-r\u00f3l/r\u0151l. +powerToolRemoveAll=\u00a76\u00d6sszes parancs elt\u00e1vol\u00edtva \u00a7c{0}\u00a76-r\u00f3l/r\u0151l. +powerToolsDisabled=\u00a76Az \u00f6sszes power tool-os eszk\u00f6z\u00f6d letiltva. +powerToolsEnabled=\u00a76Az \u00f6sszes power tool-os eszk\u00f6z\u00f6d enged\u00e9lyezve. +questionFormat=\u00a72[K\u00e9rd\u00e9s]\u00a7r {0} +readNextPage=\u00a76\u00cdrd be a\u00a7c /{0} {1} \u00a76 parancsot a k\u00f6vetkez\u00f5 oldal elolvas\u00e1s\u00e1hoz. +recipe=\u00a76\u00a7c{0}\u00a76 receptje (\u00a7c{1}\u00a76 az \u00a7c{2}\u00a76-b\u00f3l/b\u0151l) +recipeBadIndex=Nincs recept ennyihez. +recipeFurnace=\u00a76\u00c9gess\: \u00a7c{0}\u00a76-t. +recipeGrid=\u00a7c{0}X \u00a76| \u00a7{1}X \u00a76| \u00a7{2}X +recipeGridItem=\u00a7c{0}X \u00a76is \u00a7c{1} +recipeMore=\u00a76\u00cdrd be a /{0} \u00a7c{1}\u00a76 parancsot, hogy t\u00f6bb receptet l\u00e1thass \u00a7c{2}\u00a76-hoz. +recipeNone={0}-nak/nek nincs receptje. +recipeNothing=semmi +recipeShapeless=\u00a76Egyes\u00edts \u00a7c{0} +recipeWhere=\u00a76Hol\: {0} +removed=\u00a76Elt\u00e1vol\u00edtva\u00a7c {0} \u00a76entit\u00e1s. +repair=\u00a76Sikeresen megjav\u00edtottad a az al\u00e1bbi dolgaidat\: \u00a7c{0}. +repairAlreadyFixed=\u00a74Ezt a t\u00e1rgyat m\u00e9g nem kell jav\u00edtanod. +repairEnchanted=\u00a74Nincs jogod, hogy enchantolt t\u00e1rgyakat jav\u00edts. +repairInvalidType=\u00a74Ez a t\u00e1rgy nem jav\u00edthat\u00f3. +repairNone=\u00a74Nincs olyan eszk\u00f6z\u00f6d/felszerel\u00e9sed amit jav\u00edtani k\u00e9ne. +requestAccepted=\u00a76Teleport\u00e1l\u00e1si k\u00e9relem elfogadva. +requestAcceptedFrom=\u00a7c{0} \u00a76elfogadta a k\u00e9relmed. +requestDenied=\u00a76Teleport\u00e1l\u00e1si k\u00e9relem elutas\u00edtva. +requestDeniedFrom=\u00a7c{0} \u00a76elutas\u00edtotta a k\u00e9relmed. +requestSent=\u00a76K\u00e9r\u00e9s elk\u00fcldve\u00a7c {0}\u00a76-nak/nek. +requestTimedOut=\u00a74Teleport k\u00e9relem kifutott az id\u00f5b\u00f5l. +requiredBukkit=\u00a76* \! * You need atleast build {0} of CraftBukkit, download it from http\://dl.bukkit.org/downloads/craftbukkit/ +resetBal=\u00a76Egyenleg vissza \u00e1ll\u00edtva \u00a7a{0}-ra/re \u00a76minden fentl\u00e9v\u0151 j\u00e1t\u00e9kosnak. +resetBalAll=\u00a76Egyenleg vissza\u00e1ll\u00edtva \u00a7a{0}\u00a76-ra/re az \u00f6sszes j\u00e1t\u00e9kosnak. +returnPlayerToJailError=\u00a74Hiba t\u00f6rt\u00e9nt amikor\u00a7c {0} \u00a74visszapr\u00f3b\u00e1lt t\u00e9rni a(z) \u00a7c{1}\u00a74 b\u00f6rt\u00f6nbe\! +runningPlayerMatch=\u00a76Running search for players matching ''\u00a7c{0}\u00a76'' (this could take a little while) +second=m\u00e1sodperc +seconds=m\u00e1sodperc +seenOffline=\u00a76A \u00a7c{0} \u00a76nev\u0171 j\u00e1t\u00e9kos \u00a74nem el\u00e9rhet\u0151 \u00a76ennyi ideje\: \u00a7c{1}\u00a76. +seenOnline=\u00a76A \u00a7c{0} \u00a76nev\u0171 j\u00e1t\u00e9kos \u00a74el\u00e9rhet\u0151 \u00a76ennyi ideje\: \u00a7c{1}\u00a76. +serverFull=A szerver tele van\! +serverTotal=\u00a76Szerver \u00f6sszesen\:\u00a7c {0} +setBal=\u00a7aEgyenleged be\u00e1ll\u00edtva {0}-ra. +setBalOthers=\u00a7aBe\u00e1ll\u00edtottad {0}\u00a7a egyenleg\u00e9t {1}-ra. +setSpawner=\u00a76Spawner \u00faj tipusa\:\u00a7c {0}. +sheepMalformedColor=\u00a74Malformed color. +shoutFormat=\u00a76[Ki\u00e1lt]\u00a7r {0} +signFormatFail=\u00a74[{0}] +signFormatSuccess=\u00a71[{0}] +signFormatTemplate=[{0}] +signProtectInvalidLocation=\u00a74You are not allowed to create sign here. +similarWarpExist=\u00a74A warp with a similar name already exists. +slimeMalformedSize=\u00a74Malformed size. +socialSpy=\u00a76SocialSpy \u00a7c{0}\u00a76-nak/nek\: \u00a7c{1} +soloMob=\u00a74That mob likes to be alone. +spawnSet=\u00a76Kezd\u00f5pont be\u00e1ll\u00edtva a \u00a7c{0}\u00a76 csoportnak. +spawned=spawnolva +sudoExempt=\u00a74Nem k\u00e9nyszer\u00edtheted \u00f5t. +sudoRun=\u00a76Forcing\u00a7c {0} \u00a76to run\:\u00a7r /{1} +suicideMessage=\u00a76Viszl\u00e1t sz\u00e9p vil\u00e1g... +suicideSuccess=\u00a76{0} \u00a76feladta az \u00e9let\u00e9t. +survival=t\u00fal\u00e9l\u00f5 +takenFromAccount=\u00a7a{0} lev\u00e9ve az egyenlegedr\u00f5l. +takenFromOthersAccount=\u00a7a{0} lev\u00e9ve {1}\u00a7a egyenleg\u00e9r\u00f5l. \u00daj egyenleg\: {2}. +teleportAAll=\u00a76Teleport\u00e1l\u00e1si k\u00e9relem mindenkinek elk\u00fcldve... +teleportAll=\u00a76\u00d6sszes j\u00e1t\u00e9kos teleport\u00e1l\u00e1sa... +teleportAtoB=\u00a7c{0}\u00a76 elteleport\u00e1lt t\u00e9ged {1}\u00a76-hoz/hez. +teleportDisabled=\u00a7c{0} \u00a74letiltotta, hogy r\u00e1 teleport\u00e1ljanak. +teleportHereRequest=\u00a7c{0}\u00a76 szeretn\u00e9, hogy hozz\u00e1 teleport\u00e1lj. +teleportNewPlayerError=\u00a74Failed to teleport new player\! +teleportRequest=\u00a7c{0}\u00a76 hozz\u00e1d szeretne teleport\u00e1lni. +teleportRequestTimeoutInfo=\u00a76\u00a7c{0} m\u00e1sodperced\u00a76 van, hogy ezt elfogadd. +teleportTop=\u00a76Teleport\u00e1l\u00e1s a legmagasabb pontra. +teleportationCommencing=\u00a76Teleport\u00e1l\u00e1s megkezd\u00e9se... +teleportationDisabled=\u00a76Teleport\u00e1l\u00e1s \u00a7cletiltva\u00a76. +teleportationDisabledFor=\u00a76Teleport\u00e1l\u00e1s \u00a7cletiltva \u00a7c{0} \u00a76sz\u00e1m\u00e1ra\u00a76. +teleportationEnabled=\u00a76Teleport\u00e1l\u00e1s \u00a7cenged\u00e9lyezve\u00a76. +teleportationEnabledFor=\u00a76Teleport\u00e1l\u00e1s \u00a7cenged\u00e9lyezve \u00a7c{0} \u00a76sz\u00e1m\u00e1ra\u00a76. +teleporting=\u00a76Teleport\u00e1l\u00e1s... +teleportToPlayer=\u00a76Teleport\u00e1l\u00e1s \u00a7c{0}\u00a76-hoz/hez. +tempBanned=\u00a7cYou have been temporarily banned for {0}\:\n\u00a7r{2} +tempbanExempt=\u00a74Nem tempbannolhatod ezt a szem\u00e9lyt. +thunder=\u00a76You\u00a7c {0} \u00a76thunder in your world. +thunderDuration=\u00a76You\u00a7c {0} \u00a76thunder in your world for\u00a7c {1} \u00a76seconds. +timeBeforeHeal=\u00a74Time before next heal\:\u00a7c {0}\u00a76. +timeBeforeTeleport=\u00a74Time before next teleport\:\u00a7c {0}\u00a76. +timeFormat=\u00a7c{0}\u00a76 vagy \u00a7c{1}\u00a76 vagy \u00a7c{2}\u00a76 +timeSetPermission=\u00a74Nincs jogod, hogy \u00e1ll\u00edtsd az id\u00f5t. +timeWorldCurrent=\u00a76The current time in\u00a7c {0} \u00a76is \u00a7c{1}\u00a76. +timeWorldSet=\u00a76Id\u00f5 be\u00e1ll\u00edtva\u00a7c {0}\u00a76-re a \u00a7c{1}\u00a76 vil\u00e1gban. +totalWorthAll=\u00a7aSold all items and blocks for a total worth of \u00a7c{1}\u00a7a. +totalWorthBlocks=\u00a7aSold all blocks for a total worth of \u00a7c{1}\u00a7a. +tps=\u00a76Jelenlegi TPS \= {0} +tradeSignEmpty=\u00a74A t\u00e1bla nem tud neked adni \u00e1rut. +tradeSignEmptyOwner=\u00a74A t\u00e1bl\u00e1b\u00f3l m\u00e9g nem v\u00e1s\u00e1rolt senki. +treeFailure=\u00a74Tree generation failure. Try again on grass or dirt. +treeSpawned=\u00a76Fa spawnolva. +true=\u00a7aigaz\u00a7r +typeTpaccept=\u00a76Hogy elfogadd \u00edrd be \u00a7c/tpaccept\u00a76. +typeTpdeny=\u00a76Hogy elutas\u00edtsd \u00edrd be \u00a7c/tpdeny\u00a76. +typeWorldName=\u00a76You can also type the name of a specific world. +unableToSpawnMob=\u00a74Unable to spawn mob. +unignorePlayer=\u00a76You are not ignoring player\u00a7c {0} \u00a76anymore. +unknownItemId=\u00a74Ismeretlen t\u00e1rgy ID\:\u00a7r {0}\u00a74. +unknownItemInList=\u00a74Unknown item {0} in {1} list. +unknownItemName=\u00a74Ismeretlen t\u00e1rgy n\u00e9v\: {0}. +unlimitedItemPermission=\u00a74Nincs jogod a v\u00e9gtelens\u00e9gre a k\u00f6vetkez\u0151 t\u00e1rgyn\u00e1l\: \u00a7c{0}\u00a74. +unlimitedItems=\u00a76V\u00e9gtelen t\u00e1rgyak\:\u00a7r +unmutedPlayer=\u00a7c {0}\u00a76-r\u00f3l fellett oldva a n\u00e9m\u00edt\u00e1s. +unvanishedReload=\u00a74A reload k\u00f6vetkezt\u00e9ben mindenki l\u00e1tni fog. +upgradingFilesError=Error while upgrading the files. +uptime=\u00a76M\u00fbk\u00f6d\u00e9si id\u00f5\:\u00a7c {0} +userAFK=\u00a75{0} \u00a75most AFK \u00e9s nem bisztos hogy fog v\u00e1laszolni. +userDoesNotExist=\u00a74The user\u00a7c {0} \u00a74does not exist. +userIsAway=\u00a77* \u00a75{0}\u00a77 elment a g\u00e9pt\u0151l... +userIsNotAway=\u00a77* \u00a75{0} \u00a77visszaj\u00f6tt... +userJailed=\u00a76Beb\u00f6rt\u00f6n\u00f6ztek\! +userUnknown=\u00a74Figyelem\: ''\u00a7c{0}\u00a74'' m\u00e9g sose j\u00e1rt a szerveren. +userdataMoveBackError=Failed to move userdata/{0}.tmp to userdata/{1}\! +userdataMoveError=Failed to move userdata/{0} to userdata/{1}.tmp\! +usingTempFolderForTesting=Using temp folder for testing\: +vanished=\u00a76Sikeresen elt\u00fcnt\u00e9l a norm\u00e1lis j\u00e1t\u00e9kosok el\u00f5l \u00e9s a j\u00e1t\u00e9kbeli parancsokb\u00f3l. +versionMismatch=\u00a74Version mismatch\! Please update {0} to the same version. +versionMismatchAll=\u00a74Version mismatch\! Please update all Essentials jars to the same version. +voiceSilenced=\u00a76El vagy n\u00e9m\u00edtva\! +walking=s\u00e9ta +warpDeleteError=\u00a74Problem deleting the warp file. +warpList={0} +warpListPermission=\u00a74Nincs jogod, hogy ki list\u00e1zd a Warpokat. +warpNotExist=\u00a74Nincs ilyen warp. +warpOverwrite=\u00a74You cannot overwrite that warp. +warpSet=\u00a76Warp\u00a7c {0} \u00a76be\u00e1ll\u00edtva. +warpUsePermission=\u00a74Nincs jogod oda Warpolni. +warpingTo=\u00a76Warpol\u00e1s a(z)\u00a7c {0}\u00a76 helyre. +warps=\u00a76Teleportok\:\u00a7r {0} +warpsCount=\u00a76Van\u00a7c {0} \u00a76warp. Ez az \u00a7c{1}.\u00a76 oldal a \u00a7c{2}\u00a76-b\u00f3l/b\u0151l. +weatherStorm=\u00a76Be\u00e1ll\u00edtottad az id\u00f5t \u00a7ces\u00f5sre\u00a76 a(z)\u00a7c {0}\u00a76 vil\u00e1gban. +weatherStormFor=\u00a76You set the weather to \u00a7cstorm\u00a76 in\u00a7c {0} \u00a76for {1} seconds. +weatherSun=\u00a76Be\u00e1ll\u00edtottad az id\u00f5t \u00a7cnaposra\u00a76 a(z)\u00a7c {0}\u00a76 vil\u00e1gban. +weatherSunFor=\u00a76You set the weather to \u00a7csun\u00a76 in\u00a7c {0} \u00a76for {1} seconds. +whoisAFK=\u00a76 - AFK\:\u00a7r {0} +whoisBanned=\u00a76 - Bannolva\:\u00a7r {0} +whoisExp=\u00a76 - Exp\:\u00a7r {0} (Level {1}) +whoisFly=\u00a76 - Rep\u00fcl\u00e9s\:\u00a7r {0} ({1}) +whoisGamemode=\u00a76 - J\u00e1t\u00e9km\u00f3d\:\u00a7r {0} +whoisGeoLocation=\u00a76 - Helyezked\u00e9s\:\u00a7r {0} +whoisGod=\u00a76 - Isten m\u00f3d\:\u00a7r {0} +whoisHealth=\u00a76 - \u00c9let\:\u00a7r {0}/20 +whoisIPAddress=\u00a76 - IP C\u00edm\:\u00a7r {0} +whoisJail=\u00a76 - B\u00f6rt\u00f6n\:\u00a7r {0} +whoisLocation=\u00a76 - Helye\:\u00a7r ({0}, {1}, {2}, {3}) +whoisMoney=\u00a76 - P\u00e9nz\:\u00a7r {0} +whoisMuted=\u00a76 - N\u00e9m\u00edtva\:\u00a7r {0} +whoisNick=\u00a76 - Nick\:\u00a7r {0} +whoisOp=\u00a76 - OP\:\u00a7r {0} +whoisTop=\u00a76 \=\=\=\=\=\= KiIs\u00d6\:\u00a7c {0} \u00a76\=\=\=\=\=\= +worth=\u00a7aStack of {0} worth \u00a7c{1}\u00a7a ({2} item(s) at {3} each) +worthMeta=\u00a7aStack of {0} with metadata of {1} worth \u00a7c{2}\u00a7a ({3} item(s) at {4} each) +worthSet=\u00a76\u00c1r be\u00e1ll\u00edtva +year=\u00e9v +years=\u00e9v +youAreHealed=\u00a76\u00c9leted felt\u00f6ltve. +youHaveNewMail=\u00a76Van\u00a7c {0} \u00a76\u00fczeneted\! \u00cdrd be a \u00a7c/mail read\u00a76 parancsot, hogy elolvasd \u00f5ket. +whoisHunger=\u00a76 - \u00c9hs\u00e9g\:\u00a7r {0}/20 (+{1} saturation) +kitDelay=\u00a7m{0}\u00a7r +giveSpawnFailure=\u00a74Not enough space, \u00a7c{0} \u00a7c{1} \u00a74was lost. +noKitGroup=\u00a74Nincs jogod ehhez a csomaghoz. +inventoryClearingFromAll=\u00a76\u00d6sszes ember eszk\u00f6zt\u00e1r\u00e1nak \u00fcr\u00edt\u00e9se... +inventoryClearingAllItems=\u00a76Az \u00f6sszes dolog t\u00f6r\u00f6lve lett {0} \u00a76eszk\u00f6zt\u00e1r\u00e1b\u00f3l. +inventoryClearingAllArmor=\u00a76Az \u00f6sszes cucc \u00e9s felszerel\u00e9s t\u00f6r\u00f6lve lett {0}\u00a76 eszk\u00f6zt\u00e1r\u00e1b\u00f3l. +inventoryClearingAllStack=\u00a76T\u00f6r\u00f6lve minden \u00a7c{0} {1}\u00a76 eszk\u00f6zt\u00e1r\u00e1b\u00f3l. +inventoryClearingStack=\u00a76Elt\u00e1vol\u00edtva \u00a7c{0} \u00a76db \u00a7c{1} \u00a76{2}\u00a76 eszk\u00f6zt\u00e1r\u00e1b\u00f3l. +inventoryClearFail=\u00a74{0}-nak/nek nincs \u00a7c{1} \u00a74db \u00a7c{2}\u00a74-ja/je. +localNoOne= +totalSellableAll=\u00a7aAz \u00f6sszes eladhat\u00f3 dolgod\u00e9rt \u00e9s blockjaid\u00e9rt \u00a7c{1}\u00a7a-t kapsz. +totalSellableBlocks=\u00a7aAz \u00f6sszes eladhat\u00f3 blockjaid\u00e9rt \u00a7c{1}\u00a7a-t kapsz. +radiusTooBig=\u00a74Ez a sug\u00e1r t\u00fal nagy\! A maximum\: {0}. +isIpBanned=\u00a76IP \u00a7c{0} \u00a76m\u00e1r ki van bannolva. +mobDataList=\u00a76\u00c9rv\u00e9nyes adatok\:\u00a7r {0} +vanish=\u00a76L\u00e1thatatlans\u00e1g {0}\u00a76-nak/nek\: {1} +noLocationFound=\u00a74Nincs ilyen \u00e9rv\u00e9nyes hely. +coordsKeyword={0}, {1}, {2} +banExemptOffline=\u00a74Nem bannolhatsz Offline j\u00e1t\u00e9kost. +tempbanExemptOffline=\u00a74Nem tempbannolhatsz Offline j\u00e1t\u00e9kost. +mayNotJailOffline=\u00a74Nem b\u00f6rt\u00f6n\u00f6zhetsz be Offline j\u00e1t\u00e9kost. +muteExemptOffline=\u00a74Nem n\u00e9m\u00edthatsz le Offline j\u00e1t\u00e9kost. +ignoreExempt=\u00a74Nem hagyhatod figyelmen k\u00edv\u0171l ezt a j\u00e1t\u00e9kost. +unsafeTeleportDestination=\u00a74Ahova teleport\u00e1lni szeretn\u00e9l nem biztons\u00e1gos \u00e9s a bisztons\u00e1gos teleport kikapcsolva. +noMetaJson=JSON Metadata nem t\u00e1mogatott a Bukkit ezen verzi\u00f3j\u00e1ban. +maxMoney=\u00a74Ez a tranzakci\u00f3 meghaladja a be\u00e1ll\u00edtott maxim\u00e1lis tranzakci\u00f3 hat\u00e1r\u00e9rt\u00e9k\u00e9t. +skullChanged=\u00a76Fej megv\u00e1ltoztatva \u00a7c{0}\u00a76 fej\u00e9re. +alphaNames=\u00a74A j\u00e1t\u00e9kosok nevei csak bet\u0171ket, sz\u00e1mokat \u00e9s al\u00e1h\u00faz\u00e1st tartalmazhat. +givenSkull=\u00a76Megkaptad \u00a7c{0}\u00a76 fej\u00e9t. +noPermissionSkull=\u00a74Nincs jogod megv\u00e1ltoztatni ezt a fejet. +teleportInvalidLocation=A koordin\u00e1t\u00e1k \u00e9rt\u00e9ke nem lehet t\u00f6bb 30000000-n\u00e9l +invalidSkull=\u00a74K\u00e9rlek j\u00e1t\u00e9kos fejet tarts a kezedben. +weatherInvalidWorld=A vil\u00e1g {0} nem tal\u00e1lhat\u00f3\! +gameModeInvalid=\u00a74Meg kell adnod egy \u00e9rv\u00e9nyes j\u00e1t\u00e9kost/m\u00f3dot. +mailTooLong=\u00a74Az \u00fczeneted t\u00fal hossz\u00fa. Pr\u00f3b\u00e1ld 1000 karakter alatt. +mailDelay=T\u00fal sok lev\u00e9l lett elk\u00fcldve az utols\u00f3 percben. Maximum\: {0} +seenAccounts=\u00a76J\u00e1t\u00e9kos ismerhet\u0151\u00a7c {0} \u00a76n\u00e9ven is +unableToSpawnItem=\u00a74Nem lehetett lespawnolni \u00a7c{0}\u00a74-t, mert ez nem spawnolhat\u00f3 t\u00e1rgy. +itemsConverted=\u00a76Converted all items into blocks. +itemsNotConverted=\u00a74You have no items that can be converted into blocks. +mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\: +mailMessage={0} + +whoisTempBanned=\u00a76 - Ban expires:\u00a7r {0} +playerTempBanned=\u00a76Player \u00a7c{0}\u00a76 temporarily banned \u00a7c{1}\u00a76 for \u00a7c{2}\u00a76: \u00a7c{3}\u00a76. +mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1} diff --git a/Essentials/src/messages_it.properties b/Essentials/src/messages_it.properties new file mode 100644 index 0000000000..4441732921 --- /dev/null +++ b/Essentials/src/messages_it.properties @@ -0,0 +1,558 @@ +#X-Generator: crowdin.net +#version: TeamCity +# Single quotes have to be doubled: '' +# Translations start here +# by: +action=\u00a75* {0} \u00a75{1} +addedToAccount=\u00a7a{0} sono stati aggiunti al tuo account. +addedToOthersAccount=\u00a7a{0} sono stati aggiunti all''account {1}\u00a7a. Nuovo bilancio\: {2} +adventure=avventura +alertBroke=rotto\: +alertFormat=\u00a73[{0}] \u00a7f {1} \u00a76 {2} a\: {3} +alertPlaced=piazzato\: +alertUsed=usato\: +antiBuildBreak=\u00a74Non hai il permesso di rompere un blocco di\u00a7c\: {0} \u00a74qui. +antiBuildCraft=\u00a74Non hai il permesso di creare\u00a7c {0}\u00a74. +antiBuildDrop=\u00a74Non hai il permesso di gettare un\u00a7c {0}\u00a74. +antiBuildInteract=\u00a74Non hai il permesso di interagire con\u00a7c {0}\u00a74. +antiBuildPlace=\u00a74\u00a74Non hai il permesso di piazzare un\u00a7c {0} \u00a74qui. +antiBuildUse=\u00a74\u00a74Non hai il permesso di utilizzare un\u00a7c {0}\u00a74. +autoAfkKickReason=Sei stato kickato per inattivita'' oltre i {0} minuti. +backAfterDeath=\u00a77Digita il comando /back per tornare al punto dove sei morto. +backUsageMsg=\u00a77Ritorna alla posizione precedente. +backupDisabled=\u00a74Non e'' stato ancora configurato uno script di backup esterno. +backupFinished=Backup terminato. +backupStarted=Backup iniziato +balance=\u00a7aSoldi\:\u00a7c {0} +balanceOther=\u00a7aSoldi\: {0}\u00a7a\:\u00a7c {1} +balanceTop=\u00a76Migliori bilanci ({0}) +banExempt=\u00a7cNon puoi esiliare questo player. +banFormat=\u00a74Esiliati\:\n\u00a7r{0} +bed=\u00a7oletto\u00a7r +bedMissing=\u00a74Il tuo letto non e'' stato settato, manca o e'' bloccato. +bedNull=\u00a7mletto\u00a7r +bedSet=\u00a76Spawn letto stabilito\! +bigTreeFailure=\u00a74Creazione del albero grande fallita. Riprova sull''erba o sulla terra. +bigTreeSuccess=\u00a76Albero grande generato. +blockList=Essentials ha trasmesso i seguenti comandi ad un altro plugin\: +bookAuthorSet=\u00a76Autore del libro impostato a {0}. +bookLocked=\u00a76Questo libro e'' ora bloccato. +bookTitleSet=\u00a76Titolo del libro settato a {0}. +broadcast=[\u00a7cBroadcast\u00a7f]\u00a7a {0} +buildAlert=\u00a74Non hai il permesso di costruire. +bukkitFormatChanged=Il formato della versione Bukkit e'' cambiato. Versione non controllata. +burnMsg=\u00a77Hai impostato{0} infuocato per {1} secondi. +canTalkAgain=\u00a76Ora puoi nuovamente parlare. +cannotStackMob=\u00a74\u00a74Non hai il permesso di impilare vari mob. +cantFindGeoIpDB=Impossibil trovare database GeoIP\! +cantReadGeoIpDB=Lettura fallita del database GeoIP\! +cantSpawnItem=\u00a74Non hai il permesso di generare l''oggetto\u00a7c {0}\u00a74. +chatTypeAdmin=[A] +chatTypeLocal=[L] +chatTypeSpy=[Spia] +cleaned=File utente puliti. +cleaning=Pulizia dei file utente in corso. +commandFailed=Comando {0} fallito\: +commandHelpFailedForPlugin=Errore nella guida di\: {0} +commandNotLoaded=\u00a74Il comando {0} non e'' stato caricato correttamente. +compassBearing=\u00a76Bussola\: {0} ({1} gradi). +configFileMoveError=Impossibile spostare config.yml nel backup. +configFileRenameError=Impossibile rinominare il file temporaneo config.yml. +connectedPlayers=\u00a76Giocatori connessi\u00a7r +connectionFailed=Connessione fallita. +cooldownWithMessage=\u00a7cTempo di ricarica\: {0} +corruptNodeInConfig=\u00a74Avviso\: Errore nel tuo file di configurazione al nodo {0}. +couldNotFindTemplate=Impossibile trovare il template {0} +creatingConfigFromTemplate=Configurazione dal template\: {0} +creatingEmptyConfig=Creazione configurazione vuota\: {0} +creative=creativa +currency={0}{1} +currentWorld=\u00a76Mondo Attuale\:\u00a7c {0} +day=giorno +days=giorni +defaultBanReason=Sei stato bannato\! +deleteFileError=Impossibile eliminare il file\: {0} +deleteHome=\u00a76La casa\u00a7c {0} \u00a76e'' stata rimossa. +deleteJail=\u00a76La prigione\u00a7c {0} \u00a76e'' stata rimossa. +deleteWarp=\u00a76Il warp\u00a7c {0} \u00a76e'' stato rimosso. +deniedAccessCommand={0} Accesso negato al comando. +denyBookEdit=\u00a74Non puoi sbloccare questo libro. +denyChangeAuthor=\u00a74Non puoi cambiare l''autore di questo libro. +denyChangeTitle=\u00a74Non puoi cambiare il titolo di questo libro. +depth=\u00a77Sei al livello del mare. +depthAboveSea=\u00a76Sei\u00a7c {0} \u00a76blocchi sul livello del mare. +depthBelowSea=\u00a76Sei\u00a7c {0} \u00a76blocchi sotto il livello del mare. +destinationNotSet=Destinazione non impostata\! +disableUnlimited=\u00a76Piazzamento illimitato di\u00a7c {0} \u00a76disabilitato per {1}. +disabled=disabilitato +disabledToSpawnMob=\u00a74La creazione di questo mob e'' stata disabilitata nel file configurazione. +distance=\u00a76Distanza\: {0} +dontMoveMessage=\u00a77Il teletrasporto iniziera'' tra {0}. Attendi. +downloadingGeoIp=Download del database GeoIP... potrebbe richiedere del tempo (nazione\: 0.6 MB, citta''\: 20MB) +duplicatedUserdata=Dati dell''utente duplicati\: {0} e {1} +durability=\u00a76Questo attrezzo ha \u00a7c{0}\u00a76 utilizzi rimasti +editBookContents=\u00a7eOra puoi modificare i contenuti di questo libro. +enableUnlimited=\u00a76Dati illimitati oggetti di\u00a7c {0} \u00a76a \u00a7c{1}\u00a76. +enabled=abilitato +enchantmentApplied=\u00a76L''incantesimo\u00a7c {0} \u00a76e'' stato applicato all''oggetto che hai in mano. +enchantmentNotFound=\u00a74Incantesimo non trovato\! +enchantmentPerm=\u00a74Non hai il permesso per\u00a7c {0}\u00a74. +enchantmentRemoved=\u00a76L''incantesimo\u00a7c {0} \u00a76e'' stato rimosso dall''oggetto che hai in mano. +enchantments=\u00a76Incantesimi\:\u00a7r {0} +errorCallingCommand=Errore nell''esecuzione del comando /{0} +errorWithMessage=\u00a7cErrore\:\u00a74 {0} +essentialsHelp1=Il file e'' corrotto ed Essentials non lo puo'' aprire. Essentials e'' attualmente disabilitato. Se non riesci a riparare il file, vai su http\://tiny.cc/EssentialsChat +essentialsHelp2=Il file e'' corrotto ed Essentials non lo puo'' aprire. Essentials e tuttora disabilitato. Se non riesci a riparare il file, scrivi /essentialshelp in-game o vai su http\://tiny.cc/EssentialsChat +essentialsReload=\u00a76Essentials ricaricato\u00a7c {0}. +exp=\u00a7c{0} \u00a76ha\u00a7c {1} \u00a76esperienza (livello\u00a7c {2}\u00a76) e necessita di altri\u00a7c {3} \u00a76punti esperienza per salire di livello. +expSet=\u00a7c{0} \u00a76ha ora\u00a7c {1} \u00a76esperienza. +extinguish=\u00a76Hai spento le fiamme. +extinguishOthers=\u00a76Hai spento le fiamme di {0}. +failedToCloseConfig=Fallita la chiusura del file di configurazione {0}. +failedToCreateConfig=Fallita creazione del file di configurazione {0}. +failedToWriteConfig=Fallita scrittura del file di configurazione {0}. +false=\u00a74falso\u00a7r +feed=\u00a76Ora sei sazio. +feedOther=\u00a76Hai saziato l''appetito di \u00a7c{0}\u00a76. +fileRenameError=Rinomina del file {0} fallita\! +fireworkColor=\u00a74I parametri di carica fuochi d''artificio inseriti non sono validi, devi prima impostare i colori. +fireworkEffectsCleared=\u00a76Rimossi tutti gli effetti dalla pila attualmente mantenuta. +fireworkSyntax=\u00a76Parametri Fuochi d''Artificio\:\u00a7c color\: [fade\:] [shape\:] [effect\:]\n\u00a76Per utilizzare piu'' di un colore/effetto, separa i valori con una virgola\: \u00a7cred,blue,pink\n\u00a76Shapes\:\u00a7c star, ball, large, creeper, burst \u00a76Effects\:\u00a7c trail, twinkle. +flyMode=\u00a76Modalita'' volo impostata\u00a7c {0} \u00a76per {1}\u00a76. +flying=volando +foreverAlone=\u00a74Non c''e'' nessuno a cui rispondere. +fullStack=\u00a74Hai gia'' una pila intera. +gameMode=\u00a76Modalit\u00e0 di gioco impostata a\u00a7c {0} \u00a76per \u00a7c{1}\u00a76. +gcWorld=\u00a76{0} "\u00a7c{1}\u00a76"\: \u00a7c{2}\u00a76 chunk, \u00a7c{3}\u00a76 entita'', \u00a7c{4}\u00a76 piastrelle. +gcfree=\u00a76Memoria libera\:\u00a7c {0} MB. +gcmax=\u00a76Memoria massima\:\u00a7c {0} MB. +gctotal=\u00a76Memoria allocata\:\u00a7c {0} MB. +geoIpUrlEmpty=L''url per il download del GeoIP e'' vuoto. +geoIpUrlInvalid=L''url per il download del GeoIP non e'' valido. +geoipJoinFormat=\u00a76Il giocatore \u00a7c{0} \u00a76viene da \u00a7c{1}\u00a76. +giveSpawn=\u00a76Sto dando\u00a7c {0} \u00a7c {1} a\u00a7c {2}\u00a76. +godDisabledFor=\u00a7cDisabilitato\u00a76 perr\u00a7c {0} +godEnabledFor=\u00a7aabilitato\u00a76 per\u00a7c {0} +godMode=\u00a76Modalita'' Dio\u00a7c {0}\u00a76. +groupDoesNotExist=\u00a74Non c''e'' nessuno online in questo gruppo\! +groupNumber=\u00a7c{0}\u00a7f online, per la lista completa\:\u00a7c /{1} {2} +hatArmor=\u00a74Non puoi utilizzare questo oggetto come cappello\! +hatEmpty=\u00a7cYou are not wearing a hat. +hatFail=\u00a74Devi avere qualcosa in mano da indossare. +hatPlaced=\u00a76Goditi il tuo nuovo cappello\! +hatRemoved=\u00a76Il tuo cappello \u00e8 stato rimosso. +haveBeenReleased=\u00a77Sei stato scarcerato. +heal=\u00a77Sei stato curato. +healDead=\u00a74Non pu\u00f2 guarire qualcuno che \u00e8 morto\! +healOther=\u00a77{0} e'' stato curato. +helpConsole=Digitare ? per la guida. +helpFrom=\u00a77Comandi da {0}\: +helpLine=\u00a76/{0}\u00a7r\: {1} +helpMatching=\u00a77I comandi corrispondono "{0}"\: +helpOp=\u00a7c[Aiuto]\u00a7f \u00a77{0}\:\u00a7f {1} +helpPlugin=\u00a74{0}\u00a7r\: Aiuto Plugin\: /help {1} +holdBook=\u00a74Non stai mantenendo un libro scrivibile. +holdFirework=\u00a74Devi mantenere un fuoco d''artificio per aggiungerne degli effetti. +holdPotion=\u00a74Devi mantenere un pozione per applicare effetti ad essa. +holeInFloor=Buco nel terreno +homeSet=\u00a77Casa impostata. +homes=Case\: {0} +hour=ora +hours=ore +ignoredList=\u00a76Ignorato/i\:\u00a7r {0} +ignorePlayer=Da ora in poi ignorerai {0}. +illegalDate=Formato data/ora non riconosciuto. +infoChapter=\u00a76Seleziona capitolo\: +infoChapterPages=\u00a7e ---- \u00a76{0} \u00a7e--\u00a76 Pagina \u00a7c{1}\u00a76 di \u00a7c{2} \u00a7e---- +infoPages=\u00a7e ---- \u00a76{2} \u00a7e--\u00a76 Pagina \u00a74{0}\u00a76/\u00a74{1} \u00a7e---- +infoUnknownChapter=\u00a74Capitolo sconosciuto. +insufficientFunds=\u00a74Fondi disponibili insufficienti. +invalidCharge=\u00a7cCosto non corretto. +invalidFireworkFormat=\u00a74L''opzione \u00a7c{0} \u00a74non \u00e8 un valore valido per \u00a7c{1}\u00a74. +invalidHome=La casa {0} non esiste\! +invalidHomeName=\u00a74Nome casa invalido\! +invalidMob=\u00a74Tipo mob non valido. +invalidNumber=Numero non valido. +invalidPotion=\u00a74Pozione non valida. +invalidPotionMeta=\u00a74Dato meta della pozione non valido\: \u00a7c{0}\u00a74. +invalidSignLine=\u00a74Riga\u00a7c {0} \u00a74del cartello non valida. +invalidWarpName=\u00a74Nome portale non valido\! +invalidWorld=\u00a74Mondo incorretto. +is=e'' +itemCannotBeSold=\u00a74Quell''oggetto non puo'' essere venduto al server. +itemMustBeStacked=\u00a74L''oggetto deve essere scambiato in pile. Una quantita'' di 2 oggetti sarebbero due pile, etc. +itemNames=\u00a76Nomi corti oggetti\:\u00a7r {0} +itemNotEnough1=\u00a74Non hai abbastanza di quell''oggetto per vendere. +itemNotEnough2=\u00a76Se intendevi vendere tutti i tuoi oggetti di quel tipo, usa /sell nomeoggetto. +itemNotEnough3=\u00a76/sell nomeoggetto -1 vende tutti gli oggetti tranne uno, ecc. +itemSellAir=Hai davvero cercato di vendere aria? Prendi un oggetto in mano. +itemSold=\u00a7aVenduto per \u00a7c{0} \u00a7a({1} {2} a {3} l''uno). +itemSoldConsole=\u00a7a{0} \u00a7aha venduto {1} per \u00a7a{2} \u00a7a({3} oggetti a {4} l''uno). +itemSpawn=\u00a76Inviati\u00a7c {0} \u00a76di\u00a7c {1} +itemType=\u00a76Oggetto\:\u00a7c {0} \u00a76-\u00a7c {1} +itemsCsvNotLoaded=Impossibile caricare items.csv\! +jailAlreadyIncarcerated=\u00a74Giocatore gia'' in prigione\:\u00a7c {0} +jailMessage=\u00a74Avrai tempo per riflettere... in prigione. +jailNotExist=\u00a74Quella prigione non esiste. +jailReleased=\u00a76Il giocatore \u00a7c{0}\u00a76 e'' stato scarcerato. +jailReleasedPlayerNotify=\u00a76Sei stato scarcerato\! +jailSentenceExtended=\u00a76Tempo di prigionia aumentato a\: {0} +jailSet=\u00a76La prigione\u00a7c {0} \u00a76e'' stata stabilita. +jumpError=\u00a74Cosi'' facendo dannegerai la CPU. +kickDefault=Espulso dal server. +kickExempt=\u00a74Non puoi espulgere questo giocatore. +kickedAll=\u00a74Espulsi tutti i giocatori dal server. +kill=\u00a76Hai ucciso\u00a7c {0}\u00a76. +killExempt=\u00a74Non puoi uccidere \u00a7c{0}\u00a74. +kitCost=\ \u00a77\u00a7o({0})\u00a7r +kitError2=\u00a74Quel kit non \u00e8 definito correttamente. Contatta un amministratore. +kitError=\u00a7cNon ci sono kit validi. +kitGiveTo=\u00a76Kit\u00a7c {0}\u00a76 dato a \u00a7c{1}\u00a76. +kitInvFull=\u00a74Il tuo inventario e'' pieno, il kit verra'' piazzato a terra. +kitNotFound=\u00a74Kit inesistente. +kitOnce=\u00a74Non puoi pi\u00f9 usare quel kit. +kitReceive=\u00a76Ricevuto kit\u00a7c {0}\u00a76. +kitTimed=\u00a74Non potrai usare quel kit per altri\u00a7c {0}\u00a74. +kits=\u00a76Kits\:\u00a7r {0} +leatherSyntax=\u00a76Sintassi colore pelle\: color\:,, esemipo\: color\:255,0,0. +lightningSmited=\u00a76Sei stato folgorato\! +lightningUse=\u00a7c {0} \u00a76 e'' stato folgorato\! +listAfkTag=\u00a77[AFK]\u00a7r +listAmount=\u00a76Ci sono \u00a7c{0}\u00a76 player online su un massimo di \u00a7c{1}\u00a76. +listAmountHidden=\u00a76Ci sono \u00a7c{0}\u00a76/{1}\u00a76 giocatori online su un massimo di \u00a7c{2}\u00a76. +listGroupTag=\u00a76{0}\u00a7r\: \u00a7r +listHiddenTag=\u00a77[NASCOSTO]\u00a7r +loadWarpError=Impossibile caricare il warp {0} +localFormat=[L]<{0}> {1} +mailClear=\u00a76Per cancellare le mail lette, digita\u00a7c /mail clear\u00a76. +mailCleared=\u00a77Mail cancellata\! +mailSent=\u00a77Mail inviata\! +markMailAsRead=\u00a76Per marcare il tuo messaggio come letto, digita\u00a7c /mail clear\u00a76. +markedAsAway=\u00a77Il tuo stato ora e'' "Non al computer". +markedAsNotAway=\u00a77Bentornato\! +matchingIPAddress=\u00a76I seguenti giocatori sono entrati con quell''indirizzo IP\: +maxHomes=Non puoi assegnare piu'' di {0} case. +mayNotJail=\u00a7cNon puoi imprigionare questo player. +me=io +minute=minuto +minutes=minuti +missingItems=\u00a74Non hai \u00a7c{0}x {1}\u00a74. +mobSpawnError=Errore durante il cambiamento del generatore di mob. +mobSpawnLimit=Quantit\u00e0 Mob limitata dal server. +mobSpawnTarget=Il blocco designato deve essere un generatore di mostri. +mobsAvailable=\u00a76Mostri\:\u00a7r {0} +moneyRecievedFrom=\u00a7a{0} sono stati ricevuti da {1} +moneySentTo=\u00a7a{0} sono stati inviati a {1} +month=mese +months=mesi +moreThanZero=La quantit\u00e0 deve essere maggiore di 0. +moveSpeed=\u00a76Impostata {0} velocit\u00e0 a\u00a7c {1} \u00a76per \u00a7c{2}\u00a76. +msgFormat=\u00a76[\u00a7c{0}\u00a76 -> \u00a7c{1}\u00a76] \u00a7r{2} +multipleCharges=\u00a74Non puoi applicare pi\u00f9 di una carica in questo fuoco d''artificio. +multiplePotionEffects=\u00a74Non puoi applicare pi\u00f9 di un effetto in questa pozione. +muteExempt=\u00a7cNon puoi mutare questo player. +muteNotify=\u00a7c{0} \u00a76ha mutato \u00a7c{1}\u00a76. +mutedPlayer=\u00a76Il giocatore\u00a7c {0} \u00a76e'' stato mutato. +mutedPlayerFor=\u00a76Il giocatore\u00a7c {0} \u00a76e'' stato mutato per\u00a7c {1}\u00a76. +mutedUserSpeaks={0} ha provato a parlare, ma e'' mutato. +nearbyPlayers=Giocatori nelle vicinanze\: {0} +negativeBalanceError=\u00a74L''utente non ha il permesso di avere un bilancio negativo. +nickChanged=\u00a76Nickname modificato. +nickDisplayName=\u00a74Devi abilitare change-displayname nel file di configurazione di Essentials. +nickInUse=\u00a74Quel nickname e'' gia'' in uso. +nickNamesAlpha=\u00a74I Nicknames devono essere alfanumerici. +nickNoMore=\u00a76Non disponi piu'' di un nickname. +nickSet=\u00a76Il tuo nome \u00e8 ora \u00a7c{0}\u00a76. +nickTooLong=\u00a74Quel soprannome \u00e8 troppo lungo. +noAccessCommand=\u00a74Non hai accesso a quel comando. +noAccessPermission=\u00a74Non hai il permesso per accedere a questo \u00a7c{0}\u00a74. +noBreakBedrock=\u00a74Non hai il permesso di distruggere la pietra madre. +noDestroyPermission=\u00a74Non hai il permesso di distruggere questo \u00a7c{0}\u00a74. +noDurability=\u00a74Questo oggetto non ha durabilit\u00e0. +noGodWorldWarning=\u00a74Attenzione\! Modalita'' Dio disabilitata in questo mondo. +noHelpFound=\u00a74Nessun comando corrispondente trovato. +noHomeSetPlayer=\u00a76Il player non ha stabilito una casa. +noIgnored=\u00a76Non stai ignorando nessuno. +noKitPermission=\u00a74Hai bisogno del permesso \u00a7c{0}\u00a74 per utilizzare quel kit. +noKits=\u00a76Non e'' ancora disponibile alcun kit. +noMail=\u00a76Non hai ricevuto nessuna mail. +noMatchingPlayers=\u00a76Nessun giocatore corrispondente trovato. +noMetaFirework=\u00a74Non hai il permesso di applicare dati meta ad un fuoco d''artificio. +noMetaPerm=\u00a74Non hai il permesso di applicare \u00a7c{0}\u00a74 meta in questo oggetto. +noNewMail=\u00a76Non hai ricevuto nuove mail. +noPendingRequest=\u00a74Non hai richieste in sospeso. +noPerm=\u00a74Non hai il permesso \u00a7c{0}\u00a74. +noPermToSpawnMob=\u00a74Non hai il permesso di generare questo mob. +noPlacePermission=\u00a74Non hai il permesso di piazzare un blocco accanto a questo cartello. +noPotionEffectPerm=\u00a74Non hai il permesso di applicare questo effetto di pozione \u00a7c{0} \u00a74a questa pozione. +noPowerTools=\u00a76Non hai nessun power tool assegnato. +noWarpsDefined=\u00a76Nessun warp definito. +none=nessun +notAllowedToQuestion=\u00a74Non sei autorizzato a fare domande. +notAllowedToShout=\u00a74Non hai il permesso di gridare. +notEnoughExperience=\u00a74Non hai abbastanza esperienza. +notEnoughMoney=\u00a74Non hai abbastanza soldi. +notFlying=non volando +notRecommendedBukkit=\u00a74* \! * La versione di Bukkit in uso non e'' quella raccomandata per Essentials. +notSupportedYet=Non ancora supportato. +nothingInHand=\u00a74Non hai niente in mano. +now=adesso +nuke=\u00a75Che la morte piova su di te. +numberRequired=Che ne dici di metterci un numero? +onlyDayNight=/time supporta solo day/night. +onlyPlayerSkulls=\u00a74Puoi solo impostare il propetario della testa (\u00a7c397\:3\u00a74). +onlyPlayers=\u00a74Solo in gioco i giocatori possono usare \u00a7c{0}\u00a74. +onlySunStorm=/weather supporta solo sun/storm. +orderBalances=\u00a76Ordinamento bilanci di\u00a7c {0} \u00a76utenti, attendere prego... +oversizedTempban=\u00a74Non potrai esiliare giocatori in questo arco di tempo. +pTimeCurrent=\u00a76L''orario di \u00a7c{0}\u00a76 e''\u00a7c {1}\u00a76. +pTimeCurrentFixed=L''orario di \u00a7e{0}\u00a7f e'' fissato alle {1}. +pTimeNormal=L''orario di \u00a7e{0}\u00a7f e'' normale e corrisponde a quello del server. +pTimeOthersPermission=\u00a7cNon sei autorizzato a definre l''orario degli altri player. +pTimePlayers=Questi player hanno il loro orario\: +pTimeReset=L''orario del Player e'' stato resettato alle\: \u00a7e{0} +pTimeSet=L''orario del Player e'' stato regolato alle \u00a73{0}\u00a7f per le\: \u00a7e{1} +pTimeSetFixed=L''orario del Player e'' stato fissato alle \u00a73{0}\u00a7f per le\: \u00a7e{1} +pWeatherCurrent=\u00a76Il meteo di \u00a7c{0}\u00a76 \u00e8\u00a7c {1}\u00a76. +pWeatherInvalidAlias=\u00a74Tipo meteo non valido +pWeatherNormal=\u00a76Il meteo di \u00a7c{0}\u00a76 \u00e8 normale e corrisponde con il server. +pWeatherOthersPermission=\u00a74Non hai il permesso di impostare il meteo di altri giocatori. +pWeatherPlayers=\u00a76Quei giocatori hanno il loro meteo\:\u00a7r +pWeatherReset=\u00a76Il meteo del giocatore \u00e8 stato reimpostato per\: \u00a7c{0} +pWeatherSet=\u00a76Il meteo del giocatore \u00e8 impostato a \u00a7c{0}\u00a76 per\: \u00a7c{1}. +pendingTeleportCancelled=\u00a7cRichiesta in sospeso di teletrasporto cancellata. +playerBanIpAddress=\u00a76Player\u00a7c {0} \u00a76banned IP address\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerBanned=\u00a76Giocatore\u00a7c {0} \u00a76esiliato\u00a7c {1} \u00a76per \u00a7c{2}\u00a76. +playerInJail=\u00a74Il giocatore \u00e8 gi\u00e0 nella prigione\u00a7c {0}\u00a74. +playerJailed=\u00a77Il giocatore {0} e'' stato messo in prigione. +playerJailedFor=\u00a77Il giocatore {0} e'' in prigione. motivo\: {1}. +playerKicked=\u00a7cIl Player {0} e'' stato kickato {1} motivo\: {2} +playerMuted=\u00a77Sei stato mutato +playerMutedFor=\u00a77Sei stato mutato per {0} +playerNeverOnServer=\u00a7cIl Player {0} non e'' mai stato su questo server. +playerNotFound=\u00a7cPlayer non trovato. +playerUnbanIpAddress=\u00a76Il giocatore\u00a7c {0} \u00a76ha fatto ritornare l'' IP\: {1}. +playerUnbanned=\u00a76Il giocatore\u00a7c {0} \u00a76pu\u00f2 tornare in gioco\u00a7c {1}. +playerUnmuted=\u00a77Sei stato smutato +pong=Pong\! +posPitch=\u00a76Inclinazione\: {0} (Angolo testa) +posX=\u00a76X\: {0} (+Est <-> -Ovest) +posY=\u00a76Y\: {0} (+Sopra <-> -Sotto) +posYaw=\u00a76Straorzata\: {0} (Rotazione) +posZ=\u00a76Z\: {0} (+Sud <-> -Nord) +possibleWorlds=\u00a76Possibile lettere e numeri \u00a7c0\u00a76 tra \u00a7c{0}\u00a76. +potions=\u00a76Pozioni\:\u00a7r {0}\u00a76. +powerToolAir=\u00a74Il comando non puo'' essere collegato all''aria. +powerToolAlreadySet=\u00a74Il comando \u00a7c{0}\u00a74 \u00e8 stato gi\u00e0 assegnato a \u00a7c{1}\u00a74. +powerToolAttach=\u00a76Il comando \u00a7c{0}\u00a76 e'' stato assegnato a {1}. +powerToolClearAll=\u00a76Tutti i comandi per i power tools sono stati cancellati. +powerToolList=\u00a76L''oggetto \u00a7c{1} \u00a76ha i seguenti comandi\: \u00a7c{0}\u00a76. +powerToolListEmpty=\u00a74L''oggetto \u00a7c{0} \u00a74non ha comandi assegnati. +powerToolNoSuchCommandAssigned=\u00a74Il comando \u00a7c{0}\u00a74 non \u00e8 stato assegnato a \u00a7c{1}\u00a74. +powerToolRemove=\u00a76Comando \u00a7c{0}\u00a76 rimosso da \u00a7c{1}\u00a76. +powerToolRemoveAll=\u00a76Tutti i comandi sono stati rimossi da \u00a7c{0}\u00a76. +powerToolsDisabled=\u00a76Tutti i tuoi power tool sono stati disabilitati. +powerToolsEnabled=\u00a76Tutti i tuoi power tool sono stati abilitati. +questionFormat=\u00a72[Domanda]\u00a7r {0} +readNextPage=\u00a76Scrivi\u00a7c /{0} {1} \u00a76per la pagina successiva. +recipe=\u00a76Ricetta per \u00a7c{0}\u00a76 (\u00a7c{1}\u00a76 di \u00a7c{2}\u00a76) +recipeBadIndex=Non c''e'' nessuna ricetta con quel numero. +recipeFurnace=\u00a76Cucinato\: \u00a7c{0}\u00a76. +recipeGrid=\u00a7c{0}X \u00a76| \u00a7{1}X \u00a76| \u00a7{2}X +recipeGridItem=\u00a7c{0}X \u00a76\u00e8 \u00a7c{1} +recipeMore=\u00a76Scrivi /{0} \u00a7c{1}\u00a76 per vedere altre ricette per \u00a7c{2}\u00a76. +recipeNone=Nessuna ricetta esistente per {0} +recipeNothing=niente +recipeShapeless=\u00a76Combina \u00a7c{0} +recipeWhere=\u00a76Dove\: {0} +removed=\u00a76Rimosse\u00a7c {0} \u00a76entita''. +repair=\u00a76Hai riparato il tuo\: \u00a7c{0}\u00a76. +repairAlreadyFixed=\u00a74Questo oggetto non richiede riparazioni. +repairEnchanted=\u00a74Non hai il permesso di riparare oggetti incantati. +repairInvalidType=\u00a74Questo oggetto non puo'' essere riparato. +repairNone=\u00a74Non ci sono oggetti da riparare. +requestAccepted=\u00a76Richiesta di teletrasporto accettata. +requestAcceptedFrom=\u00a7c{0} \u00a76ha accettato la tua richiesta di teletrasporto. +requestDenied=\u00a76Richiesta di teletrasporto rifiutata. +requestDeniedFrom=\u00a7c{0} \u00a76Ha rifiutato la tua richiesta di teletrasporto. +requestSent=\u00a76Richiesta inviata a\u00a7c {0}\u00a76. +requestTimedOut=\u00a74Richiesta di telestrasporto scaduta. +requiredBukkit=\u00a76* \! * E'' necessaria come minimo la versione {0} di CraftBukkit, scaricala da http\://dl.bukkit.org/downloads/craftbukkit/ +resetBal=\u00a76Il bilancio \u00e8 stato resettato a \u00a7c{0} \u00a76per tutti i giocatori in gioco. +resetBalAll=\u00a76Il bilancio \u00e8 stato resettato a \u00a7c{0} \u00a76per tutti i giocatori. +returnPlayerToJailError=\u00a74Riscontrato errore durante il rinvio del giocatore\u00a7c {0} \u00a74nella prigione\: \u00a7c{1}\u00a74\! +runningPlayerMatch=\u00a76Ricerca in corso di giocatori corrispondenti a ''\u00a7c{0}\u00a76'' (potrebbe richiedere un po'' di tempo) +second=secondo +seconds=secondi +seenOffline=\u00a76Il giocatore\u00a7c {0} \u00a76non \u00e8 in \u00a74gioco\u00a76 da \u00a7c{1}\u00a76. +seenOnline=\u00a76Il giocatore\u00a7c {0} \u00a76\u00e8 in \u00a7agioco\u00a76 da \u00a7c{1}\u00a76. +serverFull=Il server e'' pieno\! +serverTotal=\u00a76Totale Server\:\u00a7c {0} +setBal=\u00a7aI tuoi soldi sono stati impostati a {0}. +setBalOthers=\u00a7aHai impostato i soldi di {0}\u00a7 a {1}. +setSpawner=\u00a76Cambiato il tipo di generatore di mostri a\u00a7c {0}\u00a76. +sheepMalformedColor=\u00a74Colore non valido. +shoutFormat=\u00a76[Grido]\u00a7r {0} +signFormatFail=\u00a74[{0}] +signFormatSuccess=\u00a71[{0}] +signFormatTemplate=[{0}] +signProtectInvalidLocation=\u00a74Non hai il permesso per creare segnaposti qui. +similarWarpExist=Il nome del warp e'' stato gia'' utilizzato. +slimeMalformedSize=Dimensione non valida. +socialSpy=\u00a76SocialSpy per \u00a7c{0}\u00a76\: \u00a7c{1} +soloMob=Quel mob sembra essere solo +spawnSet=\u00a77Punto di rigenerazione creato per il gruppo {0}. +spawned=creato +sudoExempt=Impossibile applicare il sudo a questo utente +sudoRun=\u00a76Forcing\u00a7c {0} \u00a76to run\:\u00a7r /{1} +suicideMessage=\u00a77Addio mondo crudele... +suicideSuccess=\u00a77{0} si e'' suicidato.. +survival=sopravvivenza +takenFromAccount=\u00a7c{0} sono stati prelevati dal tuo conto. +takenFromOthersAccount=\u00a7c{0} taken from {1}\u00a7c account. New balance\: {2} +teleportAAll=\u00a77Richiesta di teletrasporto inviata a tutti i players... +teleportAll=\u00a77Sto teletrasportando tutti i players... +teleportAtoB=\u00a7c{0}\u00a76 ti ha teletrasportato a \u00a7c{1}\u00a76. +teleportDisabled={0} ha il teletrasporto disabilitato. +teleportHereRequest=\u00a7c{0}\u00a7c ha richiesto di teletrasportati da loro. +teleportNewPlayerError=Teletrasporto del nuovo player fallito +teleportRequest=\u00a7c{0}\u00a7c ha richiesto di teletrasportati da te. +teleportRequestTimeoutInfo=\u00a77Questa richiesta scadra'' tra {0} secondi. +teleportTop=\u00a77Teletrasporto in cima. +teleportationCommencing=\u00a77Inizio teletrasporto... +teleportationDisabled=\u00a76Teletrasporto \u00a7cdisabilitato\u00a76. +teleportationDisabledFor=\u00a76Teletrasporto \u00a7cdisabilitato \u00a76per \u00a7c{0}\u00a76. +teleportationEnabled=\u00a76Teletrasporto \u00a7cabilitato\u00a76. +teleportationEnabledFor=\u00a76Teletrasporto \u00a7cabilitato\u00a76 \u00a76per \u00a7c{0}\u00a76. +teleporting=\u00a77Teletrasporto in corso... +teleportToPlayer=\u00a76Teletrasportato a \u00a7c{0}\u00a76. +tempBanned=\u00a7cYou have been temporarily banned for {0}\:\n\u00a7r{2} +tempbanExempt=\u00a77Non puoi esiliare questo player. +thunder=Abilita i filmini dal cielo\: {0} +thunderDuration=Abilita i filmini dal cielo\: {0} per {1} secondi. +timeBeforeHeal=Tempo rimanente alla prossima cura\: {0} +timeBeforeTeleport=\u00a74Tempo rimanente prima del prossimo teletrasporto\:\u00a7c {0}\u00a76. +timeFormat=\u00a7c{0}\u00a76 o \u00a7c{1}\u00a76 o \u00a7c{2}\u00a76 +timeSetPermission=\u00a74Non sei autorizzato a regolare l''orario. +timeWorldCurrent=\u00a76L''orario attuale in\u00a7c {0} \u00a76e'' \u00a7c{1}\u00a76. +timeWorldSet=\u00a76L''orario e'' stato regolato alle\u00a7c {0} \u00a76in\: \u00a7c{1}\u00a76. +totalWorthAll=\u00a7aVenduti tutti gli oggetti e blocchi per un valore totale di \u00a7c{1}\u00a7a. +totalWorthBlocks=\u00a7aVenduti tutti i blocchi per un valore totale di \u00a7c{1}\u00a7a. +tps=\u00a76TPS Attuali \= {0} +tradeSignEmpty=\u00a74Il cartello di baratto non dispone di merci da scambiare. +tradeSignEmptyOwner=\u00a74Non c''e'' niente da raccogliere da questo cartello. +treeFailure=\u00a74Creazione dell''albero fallita. Riprova sull''erba o sulla terra. +treeSpawned=\u00a76Albero generato. +true=\u00a7avero\u00a7r +typeTpaccept=\u00a76Per accettare il teletrasporto,digita \u00a7c/tpaccept\u00a76. +typeTpdeny=\u00a76Per rifiutare il teletrasporto, digita \u00a7c/tpdeny\u00a76. +typeWorldName=\u00a76Puoi anche digitare il nome di un mondo. +unableToSpawnMob=\u00a74Impossibile generare il mob. +unignorePlayer=\u00a76Non stai piu'' ignorando il giocatore\u00a7c {0} \u00a76. +unknownItemId=\u00a74ID Oggetto sconosciuto\:\u00a7r {0}\u00a74. +unknownItemInList=\u00a74Oggetto sconosciuto {0} nella lista {1}. +unknownItemName=\u00a74Nome oggetto sconosciuto\: {0}. +unlimitedItemPermission=\u00a74Non ci sono permessi per oggetti infiniti \u00a7c{0}\u00a74. +unlimitedItems=\u00a76Oggetti illimitati\:\u00a7r +unmutedPlayer=\u00a76Il giocatore\u00a7c {0} \u00a76e'' stato smutato. +unvanishedReload=\u00a74Il server e'' stato ricaricato e cio'' ti ha forzato a tornare visibile. +upgradingFilesError=Errore durante l''aggiornamento dei file +uptime=\u00a76Tempo online\:\u00a7c {0} +userAFK=\u00a77{0} \u00a75e'' attualmente AFK e potrebbe non rispondere. +userDoesNotExist=\u00a74L''utente\u00a7c {0} \u00a74non esiste. +userIsAway=\u00a77* {0} \u00a77e'' AFK. +userIsNotAway=\u00a77* {0} \u00a77non e'' piu'' AFK. +userJailed=\u00a76Sei stato incarcerato\! +userUnknown=\u00a74Attenzione\: Il giocatore ''\u00a7c{0}\u00a74'' non e'' mai entrato sul server. +userdataMoveBackError=Errore durante lo spostamento di userdata/{0}.tmp a userdata/{1}\! +userdataMoveError=Errore durante lo spostamento di userdata/{0} a userdata/{1}.tmp\! +usingTempFolderForTesting=Sto usando la cartella temporanea per il test\: +vanished=\u00a76Sei ora completamente invisibile agli utenti normali, e nascosto dai comandi di gioco. +versionMismatch=\u00a74Versione incorretta\! Aggiornare {0} alla stessa versione. +versionMismatchAll=\u00a74Versione incorretta\! Aggiornare tutti i jar Essentials alla stessa versione. +voiceSilenced=\u00a76Sei stato silenziato. +walking=camminando +warpDeleteError=\u00a74Problema durante eliminazione del file di warp. +warpList={0} +warpListPermission=\u00a74Non hai il permesso di consultare la lista dei warps. +warpNotExist=\u00a74Quel warp non esiste. +warpOverwrite=\u00a74Non puoi sovrascrivere quel warp. +warpSet=\u00a76Warp\u00a7c {0} \u00a76definito. +warpUsePermission=\u00a74Non hai il permesso di utilizzare quel warp. +warpingTo=\u00a76Teletrasporto al warp\u00a7c {0}\u00a76. +warps=\u00a76Warps\:\u00a7r {0} +warpsCount=\u00a76Questi sono\u00a7c {0} \u00a76i portali. Mostrando la lista \u00a7c{1} \u00a76di \u00a7c{2}\u00a76. +weatherStorm=\u00a77Hai regolato il tempo in tempesta in {0} +weatherStormFor=\u00a77Hai cambiato il tempo in tempesta in {0} per {1} secondi +weatherSun=\u00a77Hai cambiato il tempo in soleggiato in {0} +weatherSunFor=\u00a77Hai cambiato il tempo in soleggiato in {0} per {1} secondi +whoisAFK=\u00a76 - AFK\:\u00a7f {0} +whoisBanned=\u00a76 - Esiliati\:\u00a7f {0} +whoisExp=\u00a76 - Exp\:\u00a7f {0} (Livello {1}) +whoisFly=\u00a76 - Fly mode\:\u00a7f {0} ({1}) +whoisGamemode=\u00a76 - Gamemode\:\u00a7f {0} +whoisGeoLocation=\u00a76 - Posizione\:\u00a7f {0} +whoisGod=\u00a76 - God mode\:\u00a7f {0} +whoisHealth=\u00a76 - Health\:\u00a7f {0}/20 +whoisIPAddress=\u00a76 - IP Address\:\u00a7f {0} +whoisJail=\u00a76 - Imprigionati\:\u00a7f {0} +whoisLocation=\u00a76 - Posizione\:\u00a7f ({0}, {1}, {2}, {3}) +whoisMoney=\u00a76 - Denaro\:\u00a7f {0} +whoisMuted=\u00a76 - Muted\:\u00a7f {0} +whoisNick=\u00a76 - Nick\:\u00a7f {0} +whoisOp=\u00a76 - OP\:\u00a7f {0} +whoisTop=\u00a76 \=\=\=\=\=\= WhoIs\:\u00a7c {0} \u00a76\=\=\=\=\=\= +worth=\u00a77Pila di {0} valore \u00a7c{1}\u00a77 ({2} oggetto(i) a {3} l''uno) +worthMeta=\u00a77Pila di {0} con metadati di {1} valore \u00a7c{2}\u00a77 ({3} oggetto(i) a {4} l''uno) +worthSet=Valore definito +year=anno +years=anni +youAreHealed=\u00a77Sei stato curato. +youHaveNewMail=\u00a7cHai {0} messaggi\!\u00a7f digita \u00a77/mail read\u00a7f per consultare la tua mail. +whoisHunger=\u00a76 - Fame\:\u00a7r {0}/20 (+{1} saturazione) +kitDelay=\u00a7m{0}\u00a7r +giveSpawnFailure=\u00a74Spazio non sufficiente, \u00a7c{0} \u00a7c{1} \u00a74\u00e8 stato perso. +noKitGroup=\u00a74Non hai accesso a questo kit kit. +inventoryClearingFromAll=\u00a76Cancellamento dell''inventario di tutti gli utenti... +inventoryClearingAllItems=\u00a76Cancellati tutti gli oggetti nell''inventario di {0}\u00a76. +inventoryClearingAllArmor=\u00a76Cancellati tutti gli oggetti e armatura nell''inventario di {0}\u00a76. +inventoryClearingAllStack=\u00a76Cancellati tutti i\u00a7c {0} \u00a76da {1}\u00a76. +inventoryClearingStack=\u00a76Rimossi\u00a7c {0} \u00a76di\u00a7c {1} \u00a76da {2}\u00a76. +inventoryClearFail=\u00a74Il giocatore {0} \u00a74non possiede\u00a7c {1} \u00a74di\u00a7c {2}\u00a74. +localNoOne= +totalSellableAll=\u00a7aIl valore totale di tutti gli oggetti e blocchi vendibili \u00e8 \u00a7c{1}\u00a7a. +totalSellableBlocks=\u00a7aIl valore totale di tutti i blocchi vendibili \u00e8 \u00a7c{1}\u00a7a. +radiusTooBig=\u00a74Il raggio \u00e8 troppo grande\! Il raggio massimo \u00e8 di {0}. +isIpBanned=\u00a76L'' IP \u00a7c{0} \u00a76\u00e8 esiliato. +mobDataList=\u00a76Dati mob validi\:\u00a7r {0} +vanish=\u00a76Invisibilita'' giocatore {0}\u00a76\: {1} +noLocationFound=\u00a74Nessuna posizione valida trovata. +coordsKeyword={0}, {1}, {2} +banExemptOffline=\u00a74Non puoi esiliare un giocatore che e'' offline. +tempbanExemptOffline=\u00a74Non puoi dare un esilio temporaneo ad un giocatore che e'' offline. +mayNotJailOffline=\u00a74Non puoi imprigionare un giocatore che e'' offline. +muteExemptOffline=\u00a74Non puoi silenziare un giocatore che e'' offline. +ignoreExempt=\u00a74Non puoi ignorare quel giocatore. +unsafeTeleportDestination=\u00a74La destinazione del teletrasporto non e'' sicura e la sicurezza nel teletrasporto e'' disabilitata. +noMetaJson=Metadata JSON non supportato in questa versione Bukkit. +maxMoney=\u00a74Questa transazione eccederebbe il limite massimo di soldi per questo account. +skullChanged=\u00a76Testa modificata a \u00a7c{0}\u00a76. +alphaNames=\u00a74I nomi dei giocatori possono contenere soltanto lettere, numeri e _ . +givenSkull=\u00a76Ti e'' stata data la testa di \u00a7c{0}\u00a76. +noPermissionSkull=\u00a74Non hai il permesso di modificare quella testa. +teleportInvalidLocation=Il valore delle coordinate non puo'' eccedere 30000000 +invalidSkull=\u00a74Tieni la testa di un giocatore in mano. +weatherInvalidWorld=Il mondo di nome{0} non e'' stato trovato\! +gameModeInvalid=\u00a74Devi specificare un/a giocatore/modalita'' valida. +mailTooLong=\u00a74Il messaggio \u00e8 troppo lungo. Riprova senza superare i 1000 caratteri. +mailDelay=Hai mandato troppe mail nell''ultimo minuto. Massimo\: {0} +seenAccounts=\u00a76Il giocatore \u00e8 anche conosciuto come\:\u00a7c {0} +unableToSpawnItem=\u00a74Impossibile evocare \u00a7c{0}\u00a74, questo non \u00e8 un oggetto evocabile. +itemsConverted=\u00a76Converted all items into blocks. +itemsNotConverted=\u00a74You have no items that can be converted into blocks. +mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\: +mailMessage={0} + +whoisTempBanned=\u00a76 - Ban expires:\u00a7r {0} +playerTempBanned=\u00a76Player \u00a7c{0}\u00a76 temporarily banned \u00a7c{1}\u00a76 for \u00a7c{2}\u00a76: \u00a7c{3}\u00a76. +mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1} diff --git a/Essentials/src/messages_ko.properties b/Essentials/src/messages_ko.properties new file mode 100644 index 0000000000..8f47f78ed3 --- /dev/null +++ b/Essentials/src/messages_ko.properties @@ -0,0 +1,558 @@ +#X-Generator: crowdin.net +#version: TeamCity +# Single quotes have to be doubled: '' +# Translations start here +# by: +action=\u00a75* {0} \u00a75{1} +addedToAccount=\u00a7a{0}\uac00 \ub2f9\uc2e0\uc758 \uacc4\uc88c\uc5d0 \ucd94\uac00\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +addedToOthersAccount=\u00a7a{0}\uac00 {1}\u00a7a\ub2d8\uc758 \uacc4\uc815\uc5d0 \ucd94\uac00\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \uc0c8 \uc794\uace0\: {2} +adventure=\ubaa8\ud5d8 +alertBroke=\ubd80\uc11c\uc9d0\: +alertFormat=\u00a73[{0}] \u00a7r {1} \u00a76 {2} at\: {3} +alertPlaced=\uc124\uce58\ub428\: +alertUsed=\uc0ac\uc6a9\ub428\: +antiBuildBreak=\uc774 {0} \ube14\ub85d\uc744 \ubd80\uc220 \uad8c\ud55c\uc744 \uac00\uc9c0\uace0 \uc788\uc9c0\uc54a\uc2b5\ub2c8\ub2e4. +antiBuildCraft=\u00a74\ub2f9\uc2e0\uc740 {0}\uc744(\ub97c) \ub9cc\ub4e4 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +antiBuildDrop=\u00a74 \ub2f9\uc2e0\uc740 \u00a7c {0} \u00a74\uc744(\ub97c) \ub5a8\uc5b4\ub728\ub9b4 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +antiBuildInteract=\u00a74\ub2f9\uc2e0\uc5d0\uac8c\ub294 \u00a7c{0}\uacfc \uc0c1\ud638 \uc791\uc6a9\ud560 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +antiBuildPlace=\u00a74\ub2f9\uc2e0\uc740 \uc774\uacf3\uc5d0 \u00a7c {0} \u00a74\uc744(\ub97c) \ub193\uc744 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +antiBuildUse=\u00a74\ub2f9\uc2e0\uc740 \u00a7c {0}\u00a74\uc744 \uc0ac\uc6a9\ud560 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +autoAfkKickReason={0}\ubd84 \uc774\uc0c1\uc758 \uc720\ud734\uc0c1\ud0dc\ub85c \uc788\uc5c8\uae30\uc5d0 \ucd94\ubc29\ub2f9\ud558\uc168\uc2b5\ub2c8\ub2e4. +backAfterDeath=\u00a7c/back \u00a76\uba85\ub839\uc5b4\ub85c \uc0ac\ub9dd\ud55c \uc9c0\uc810\uc73c\ub85c \ud154\ub808\ud3ec\ud2b8 \ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. +backUsageMsg=\u00a76\uc774\uc804 \uc7a5\uc18c\ub85c \ub3cc\uc544\uac00\ub294\uc911.. +backupDisabled=\u00a74\uc678\ubd80 \ubc31\uc5c5 \uc2a4\ud06c\ub9bd\ud2b8\uac00 \uc124\uc815\ub418\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4. +backupFinished=\u00a76\ubc31\uc5c5\uc774 \uc644\ub8cc\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +backupStarted=\u00a76\ubc31\uc5c5\uc744 \uc2dc\uc791\ud569\ub2c8\ub2e4. +balance=\u00a76\uc794\uace0\:\u00a7c {0} +balanceOther=\u00a7a{0}\uc758 \uc794\uace0\u00a7a\:\u00a7c {1} +balanceTop=\u00a76\uc794\uace0 \uc21c\uc704 ({0}) +banExempt=\u00a74\ub2f9\uc2e0\uc740 \uc774 \uc720\uc800\ub97c \ubc34 \ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +banFormat=\u00a74\ucc28\ub2e8\ub428\:\n\u00a7r {0} +bed=\u00a7o\uce68\ub300\u00a7r +bedMissing=\u00a74\ub2f9\uc2e0\uc758 \uce68\ub300\uac00 \ub193\uc5ec\uc9c0\uc9c0 \uc54a\uc558\uac70\ub098 \uc5c6\uc5b4\uc84c\uac70\ub098 \ub9c9\ud600\uc788\uc2b5\ub2c8\ub2e4. +bedNull=\u00a7m\uce68\ub300\u00a7r +bedSet=\u00a76\uce68\ub300 \uc2a4\ud3f0\uc9c0\uc810\uc774 \uc124\uc815\ub418\uc5c8\uc2b5\ub2c8\ub2e4\! +bigTreeFailure=\u00a7c\ud070 \ub098\ubb34 \uc0dd\uc131\uc911 \uc624\ub958\uac00 \ubc1c\uc0dd\ud558\uc600\uc2b5\ub2c8\ub2e4. \uc794\ub514\ub098 \ud759\uc5d0\uc11c \ub2e4\uc2dc \uc2dc\ub3c4\ud558\uc138\uc694. +bigTreeSuccess=\u00a76\ud070 \ub098\ubb34\ub97c \uc131\uacf5\uc801\uc73c\ub85c \uc0dd\uc131\ud558\uc600\uc2b5\ub2c8\ub2e4. +blockList=\u00a76\uc5d0\uc13c\uc15c\uc740 \ub2e4\uc74c \ud50c\ub7ec\uadf8\uc778\uc5d0 \uc758\ud574 \ucee4\ub9e8\ub4dc\uac00 \uad50\uccb4\ub429\ub2c8\ub2e4\: +bookAuthorSet=\u00a76\ucc45\uc758 \uc800\uc790\ub97c \u00a7c{0}\u00a76\uc73c\ub85c \uc124\uc815\ud569\ub2c8\ub2e4. +bookLocked=\u00a76\uc774 \ucc45\uc740 \uc7a0\uae34\uc0c1\ud0dc\ub85c \uc804\ud658\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +bookTitleSet=\u00a76\ucc45\uc758 \uc81c\ubaa9\uc744 \u00a7c{0}\u00a76\uc73c\ub85c \uc124\uc815\ud569\ub2c8\ub2e4. +broadcast=\u00a7r\u00a76[\u00a74\uacf5\uc9c0\u00a7r\u00a76]\u00a7r\u00a7a {0} +buildAlert=\u00a74\uac74\ucd95 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +bukkitFormatChanged=Bukkit\uc758 \ubc84\uc83c \ud3ec\ub9f7\uc774 \ubcc0\uacbd\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \ubc84\uc83c\uc774 \ud655\uc778\ub418\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4. +burnMsg=\u00a76\ub2f9\uc2e0\uc740 \u00a7c{0} \u00a76\ub2d8\uc5d0\uac8c \u00a7c{1} \u00a76\ucd08 \ub9cc\ud07c \ubd88\uc744 \uc9c8\ub800\uc2b5\ub2c8\ub2e4. +canTalkAgain=\u00a77\ub2f9\uc2e0\uc740 \ub2e4\uc2dc \ub300\ud654\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. +cannotStackMob=\u00a74 \ub2f9\uc2e0\uc5d0\uac8c\ub294 \uc5ec\ub7ec \ub9c8\ub9ac\uc758 \ubab9\ub4e4\uc744 \uc18c\ud658\ud560 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +cantFindGeoIpDB=GeoIP \ub370\uc774\ud130\ubca0\uc774\uc2a4\ub97c \ucc3e\uc744 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4\! +cantReadGeoIpDB=GeoIP \ub370\uc774\ud130\ubca0\uc774\uc2a4 \uc77d\uae30\uc5d0 \uc2e4\ud328\ud588\uc2b5\ub2c8\ub2e4\! +cantSpawnItem=\u00a7c\ub2f9\uc2e0\uc740 \uc544\uc774\ud15c {0}\uc744/\ub97c \uc18c\ud658\ud560 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +chatTypeAdmin=[A] +chatTypeLocal=[L] +chatTypeSpy=[\uc2a4\ud30c\uc774] +cleaned=\uc720\uc800 \ud30c\uc77c\uc774 \uc815\ub9ac\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +cleaning=\uc720\uc800 \ud30c\uc77c\uc744 \uc815\ub9ac\ud569\ub2c8\ub2e4. +commandFailed=\uba85\ub839\uc5b4 {0} \uc0ac\uc6a9 \uc2e4\ud328\: +commandHelpFailedForPlugin={0} \ud50c\ub7ec\uadf8\uc778\uc758 \ub3c4\uc6c0\ub9d0\uc744 \ubd88\ub7ec\uc62c \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +commandNotLoaded=\u00a7c \uba85\ub839\uc5b4 {0}\ub97c \uc798\ubabb \ubd88\ub7ec\uc654\uc2b5\ub2c8\ub2e4. +compassBearing=\u00a77\uc88c\ud45c\: {0} (\ubc29\ud5a5\: {1}) +configFileMoveError=config.yml\ub97c \ubc31\uc5c5 \uc704\uce58\ub85c \uc774\ub3d9\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4. +configFileRenameError=\uc784\uc2dc \ud30c\uc77c\uc758 \uc774\ub984\uc744 Config.yml\ub85c \ubcc0\uacbd\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4. +connectedPlayers=\u00a76\uc811\uc18d \uc911\uc778 \ud50c\ub808\uc774\uc5b4\u00a7r +connectionFailed=\uc5f0\uacb0\uc5d0 \uc2e4\ud328\ud558\uc600\uc2b5\ub2c8\ub2e4. +cooldownWithMessage=\u00a7c\uc7ac\uc0ac\uc6a9 \ub300\uae30\: {0} +corruptNodeInConfig=\u00a7c\uc624\ub958\: \u00a74config.yml \ub0b4 {0} \ub178\ub4dc\uc5d0 \uc624\ub958\uac00 \uc788\uc2b5\ub2c8\ub2e4. +couldNotFindTemplate=\ud15c\ud50c\ub9bf {0}\ub97c \ucc3e\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4. +creatingConfigFromTemplate=\ud15c\ud50c\ub9bf\uc744 \uc124\uc815\ud558\uc5ec \ub9cc\ub4ed\ub2c8\ub2e4 \: {0} +creatingEmptyConfig=\ube48 \uc124\uc815 \ud30c\uc77c\uc744 \uc0dd\uc131\uc911\: {0} +creative=\ud06c\ub9ac\uc5d0\uc774\ud2f0\ube0c +currency={0}{1} +currentWorld=\u00a76\ud604\uc7ac \uc6d4\ub4dc\:\u00a7c {0} +day=\uc77c +days=\uc77c +defaultBanReason=\ub2f9\uc2e0\uc740 \uad00\ub9ac\uc790\uc5d0 \uc758\ud574 \uc11c\ubc84\uc5d0\uc11c \ucc28\ub2e8\ub418\uc5c8\uc2b5\ub2c8\ub2e4\! +deleteFileError={0} \ud30c\uc77c\uc774 \uc0ad\uc81c\ub418\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4. +deleteHome=\u00a76\uc9d1\u00a7c {0} \uc774 \uc81c\uac70\uac00 \ub418\uc5c8\uc2b5\ub2c8\ub2e4. +deleteJail=\u00a77{0} \uac10\uc625\uc774 \uc81c\uac70\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +deleteWarp=\u00a76\uc6cc\ud504 {0}\ub294(\uc740) \uc0ad\uc81c\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +deniedAccessCommand=\u00a7c{0}\ub2d8\uc740 \ud574\ub2f9 \uba85\ub839\uc5b4\uc5d0 \uc811\uadfc\ud560 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +denyBookEdit=\u00a74\ub2f9\uc2e0\uc740 \uc774 \ucc45\uc758 \uc7a0\uae08\uc744 \ud574\uc81c\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +denyChangeAuthor=\u00a74\ub2f9\uc2e0\uc740 \uc774 \ucc45\uc758 \uc800\uc790\ub97c \ubcc0\uacbd\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +denyChangeTitle=\u00a74\ub2f9\uc2e0\uc740 \uc774 \ucc45\uc758 \uc81c\ubaa9\uc744 \ubcc0\uacbd\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +depth=\u00a77\ub2f9\uc2e0\uc740 \ud574\uc218\uba74\uc5d0 \uc788\uc2b5\ub2c8\ub2e4. +depthAboveSea=\u00a76\ub2f9\uc2e0\uc740 \ud574\uc218\uba74 {0} \u00a76\ube14\ub85d \uc704\uc5d0 \uc788\uc2b5\ub2c8\ub2e4. +depthBelowSea=\u00a76\ub2f9\uc2e0\uc740 \ud574\uc218\uba74 {0} \u00a76\ube14\ub85d \uc544\ub798\uc5d0 \uc788\uc2b5\ub2c8\ub2e4. +destinationNotSet=\ubaa9\uc801\uc9c0\uac00 \uc124\uc815\ub418\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4. +disableUnlimited=\u00a77{1}\ub85c {0}\uc758 \ubb34\ud55c\ubc30\uce58 \ube44\ud65c\uc131\ud654 +disabled=\ube44\ud65c\uc131\ud654\ub428 +disabledToSpawnMob=\u00a74\uc774 \ubaac\uc2a4\ud130\uc758 \uc2a4\ud3f0\uc740 \uc124\uc815 \ud30c\uc77c\uc5d0\uc11c \ud574\uc81c\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +distance=\u00a76\uac70\ub9ac\: {0} +dontMoveMessage=\u00a76{0}\ucd08 \ub4a4\uc5d0 \uc774\ub3d9\ub429\ub2c8\ub2e4. \uc6c0\uc9c1\uc774\uba74 \uc774\ub3d9\uc774 \ucde8\uc18c\ub429\ub2c8\ub2e4. +downloadingGeoIp=GeoIP \ub370\uc774\ud130\ubca0\uc774\uc2a4\ub97c \ub2e4\uc6b4\ubc1b\ub294 \uc911\uc785\ub2c8\ub2e4.... \uc57d\uac04\uc758 \uc2dc\uac04\uc774 \uac78\ub9b4 \uc218 \uc788\uc2b5\ub2c8\ub2e4. (\uad6d\uac00\: 0.6 MB, \ub3c4\uc2dc\: 20MB) +duplicatedUserdata=\uc911\ubcf5\ub41c \uc720\uc800\ub370\uc774\ud130 \: {0} \uc640/\uacfc {1} +durability=\u00a76\uc774 \ub3c4\uad6c\ub294 \uc0ac\uc6a9 \uac00\ub2a5 \ud69f\uc218\uac00 s \u00a7c{0}\u00a76\ubc88 \ub0a8\uc558\uc2b5\ub2c8\ub2e4 +editBookContents=\u00a7e\uc774\uc81c \uc774 \ucc45\uc758 \ub0b4\uc6a9\uc744 \uc218\uc815\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. +enableUnlimited=\u00a7c{1} \u00a76\uc544\uc774\ud15c\uc744 \u00a7c{0} \u00a76\uc5d0\uac8c \ubb34\uc81c\ud55c\uc73c\ub85c \uc9c0\uae09\ud588\uc2b5\ub2c8\ub2e4. +enabled=\ud65c\uc131\ud654 +enchantmentApplied=\u00a76\uc778\ucc48\ud2b8\u00a7c {0} \u00a76\uac00 \uc190\uc5d0 \ub4e4\uace0\uc788\ub294 \uc544\uc774\ud15c\uc5d0 \uc801\uc6a9\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +enchantmentNotFound=\u00a74\uc778\ucc48\ud2b8\uac00 \ubc1c\uacac\ub418\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4\! +enchantmentPerm=\u00a7c {0}\u00a74\ub97c \uc704\ud55c \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +enchantmentRemoved=\u00a76\uc778\ucc48\ud2b8\u00a7c {0} \u00a76\uac00 \uc190\uc5d0 \ub4e4\uace0\uc788\ub294 \uc544\uc774\ud15c\uc5d0\uc11c \uc81c\uac70\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +enchantments=\u00a76\uc778\ucc48\ud2b8\:\u00a7r {0} +errorCallingCommand=/{0} \uba85\ub839\uc5b4 \uc0ac\uc6a9 \uc911 \uc624\ub958 \ubc1c\uc0dd. +errorWithMessage=\u00a7c\uc624\ub958\:\u00a74 {0} +essentialsHelp1=\ud30c\uc77c\uc774 \ub9dd\uac00\uc838\uc11c Essentials\uc5d0\uc11c \uc5f4 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. Essentials\uc740 \ube44\ud65c\uc131\ud654 \ub418\uc5c8\uc2b5\ub2c8\ub2e4. \ub9cc\uc57d \ud574\uacb0\ud558\uc9c0 \uc5b4\ub824\uc6b0\uc2dc\ub2e4\uba74, \ub2e4\uc74c\uc73c\ub85c \uac00\uc138\uc694 http\://tiny.cc/EssentialsChat +essentialsHelp2=\ud30c\uc77c\uc774 \ub9dd\uac00\uc838\uc11c Essentials\uc5d0\uc11c \uc5f4 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. Essentials\uc740 \ube44\ud65c\uc131\ud654 \ub418\uc5c8\uc2b5\ub2c8\ub2e4. \ub9cc\uc57d \uc2a4\uc2a4\ub85c \ud574\uacb0\ud558\uc9c0 \ubabb\ud558\uaca0\ub2e4\uba74, /essentialshelp \uba85\ub839\uc5b4\ub098 \ub2e4\uc74c\uc73c\ub85c \uac00\uc138\uc694. http\://tiny.cc/EssentialsChat +essentialsReload=\u00a76\uc5d0\uc13c\uc15c\u00a7c {0}\u00a76\ub9ac\ub85c\ub4dc\uac00 \uc644\ub8cc\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +exp=\u00a7c{0} \u00a76\ub294\u00a7c {1} \u00a76\uacbd\ud5d8\uce58 (\ub808\ubca8\u00a7c {2}\u00a76) \uc744 \uac00\uc9c0\uace0 \uc788\uace0,\u00a7c {3} \u00a76\uc758 \uacbd\ud5d8\uce58\uac00 \uc788\uc73c\uba74 \ub808\ubca8 \uc5c5 \ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.. +expSet=\u00a7c{0} \u00a76\uc740 \uc774\uc81c\u00a7c {1} \u00a76\uacbd\ud5d8\uce58 \uc785\ub2c8\ub2e4. +extinguish=\u00a77\ubab8\uc5d0 \ubd99\uc740 \ubd88\uc744 \uaed0\uc2b5\ub2c8\ub2e4. +extinguishOthers=\u00a77\ub2f9\uc2e0\uc740 {0}\uc758 \ubd88\uc744 \uaed0\uc2b5\ub2c8\ub2e4. +failedToCloseConfig={0} \uc124\uc815\uc744 \ub2eb\uc9c0 \ubabb\ud558\uc600\uc2b5\ub2c8\ub2e4. +failedToCreateConfig={0} \uc124\uc815\uc744 \ub9cc\ub4e4\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4. +failedToWriteConfig={0} \uc124\uc815 \ud30c\uc77c\uc5d0 \uc4f0\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4. +false=\u00a74\uc544\ub2c8\uc694.\u00a7r +feed=\u00a76\ubc30\uace0\ud514\uc744 \ubaa8\ub450 \ucc44\uc6e0\uc2b5\ub2c8\ub2e4. +feedOther=\u00a76\ub2f9\uc2e0\uc740 \u00a7c{0} \u00a76\uc5d0\uac8c \ubc30\uace0\ud514\uc744 \ubaa8\ub450 \ucc44\uc6cc\uc92c\uc2b5\ub2c8\ub2e4. +fileRenameError={0} \ud30c\uc77c\uc758 \uc774\ub984 \ubcc0\uacbd\uc744 \uc2e4\ud328\ud558\uc600\uc2b5\ub2c8\ub2e4. +fireworkColor=\u00a74\ubd88\uaf43\ub180\uc774 \ub9e4\uac8c\uc218\uac00 \uc54c\ub9de\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. \ubd88\uaf43\ub180\uc774 \ub9e4\uac8c \ubcc0\uc218 \uc0bd\uc785, \uc0c9\uc0c1\uc744 \uba3c\uc800 \uc124\uc815\ud574\uc8fc\uc138\uc694. +fireworkEffectsCleared=\u00a76Removed all effects from held stack. +fireworkSyntax=\u00a76\ubd88\uaf43\ub180\uc774 \ub9e4\uac1c\ubcc0\uc218\:\u00a7c \uc0c9\uae54\:<\uc0c9\uae54> [\ud398\uc774\ub4dc\:<\uc0c9\uae54>] [\ubaa8\uc591\:<\ubaa8\uc591>] [\ud6a8\uacfc\:<\ud6a8\uacfc>]\n\u00a76\ub2e4\uc911 \uc0c9\uae54/\ud6a8\uacfc, \uc0ac\uc6a9\ud558\uc5ec \uac12\uc744 \uc27c\ud45c\ub85c \uad6c\ubd84\ud558\uc138\uc694 \: \u00a7\uc6b0\ub294\uc0c9,\ud30c\ub780\uc0c9,\ubd84\ud64d\uc0c9\n\u00a76\ubaa8\uc591\:\u00a7c \ubcc4, \uacf5, \ub300\ud615, \ud06c\ub9ac\ud37c, \ubc84\uc2a4\ud2b8 \u00a76\ud6a8\uacfc\:\u00a7c \ud2b8\ub808\uc77c, \ubc18\uc9dd. +flyMode=\u00a76\ud50c\ub808\uc774\uc5b4 {1}\u00a76\uc758 \ube44\ud589 \ubaa8\ub4dc\ub97c \u00a7c{0}\u00a76\uc2dc\ucf30\uc2b5\ub2c8\ub2e4. +flying=\ube44\ud589\uc911 +foreverAlone=\u00a74\ub2f5\uc7a5\ud560 \uc0c1\ub300\uac00 \uc5c6\uc2b5\ub2c8\ub2e4. +fullStack=\u00a74You already have a full stack. +gameMode=\u00a7c{1} \u00a76\uc5d0\uac8c \u00a7c{0} \u00a76 \ubaa8\ub4dc\ub97c \uc801\uc6a9\ud569\ub2c8\ub2e4. +gcWorld=\u00a76{0} "\u00a7c{1}\u00a76"\: \u00a7c{2}\u00a76\uac1c\uc758 \uccad\ud06c, \u00a7c{3}\u00a76\uac1c\uc758 \uc5d4\ud2f0\ud2f0, \u00a7c{4}\u00a76\uac1c\uc758 \ud0c0\uc77c. +gcfree=\u00a76\ub0a8\uc740 \uba54\ubaa8\ub9ac \: \u00a7c{0}MB. +gcmax=\u00a76\ucd5c\ub300 \uba54\ubaa8\ub9ac\:\u00a7c {0} MB. +gctotal=\u00a76\uc0ac\uc6a9\uac00\ub2a5 \uba54\ubaa8\ub9ac\:\u00a7c {0} MB. +geoIpUrlEmpty=GeoIP \ub2e4\uc6b4\ub85c\ub4dc \uc8fc\uc18c\uac00 \ube44\uc5c8\uc2b5\ub2c8\ub2e4. +geoIpUrlInvalid=GeoIP \ub2e4\uc6b4\ub85c\ub4dc \uc8fc\uc18c\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +geoipJoinFormat=\ud50c\ub808\uc774\uc5b4 {0}\ub2d8\uc740 {1}\uc5d0\uc11c \uc654\uc2b5\ub2c8\ub2e4. +giveSpawn=\u00a7c{0}\u00a76\uac1c\uc758 \u00a7c{1}\u00a76\ub97c \u00a7c{2}\u00a76\uc5d0\uac8c \uc92c\uc2b5\ub2c8\ub2e4. +godDisabledFor=\u00a7c{0} \u00a76\ub97c \u00a7c\ube44\ud65c\uc131\ud654 +godEnabledFor={0} \ub85c \ud65c\uc131\ud654 \ub418\uc5c8\uc2b5\ub2c8\ub2e4. +godMode=\u00a76\ubb34\uc801 \ubaa8\ub4dc\u00a7c {0}\u00a76. +groupDoesNotExist=\u00a74\uc774 \uadf8\ub8f9\uc5d0\uc11c \uc628\ub77c\uc778 \uc0c1\ud0dc\uc778 \uc0ac\ub78c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4\! +groupNumber=&bNOS &a \u00a7c{0}\u00a7f online, for the full list\:\u00a7c /{1} {2} +hatArmor=\u00a74\uc774 \uc544\uc774\ud15c\uc744 \ubaa8\uc790\ub85c \uc0ac\uc6a9\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4\! +hatEmpty=\u00a74\ub2f9\uc2e0\uc740 \ubaa8\uc790\ub97c \uc4f0\uace0\uc788\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. +hatFail=\u00a74\ubc18\ub4dc\uc2dc \uba38\ub9ac\uc5d0 \uc4f0\uae30 \uc704\ud574\uc11c\ub294 \ubb34\uc5b8\uac00\ub97c \ub4e4\uace0 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4. +hatPlaced=\uc0c8\ub85c\uc6b4 \ubaa8\uc790\uac00 \ub9d8\uc5d0 \ub4e4\uc5c8\uc73c\uba74 \uc88b\uaca0\uc2b5\ub2c8\ub2e4\! +hatRemoved=\u00a76\ub2f9\uc2e0\uc758 \ubaa8\uc790\ub294 \uc81c\uac70 \ub418\uc5c8\uc2b5\ub2c8\ub2e4. +haveBeenReleased=\u00a76\ub2f9\uc2e0\uc740 \uacf5\uac1c\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +heal=\u00a76\ub2f9\uc2e0\uc740 \ud68c\ubcf5\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +healDead=\uc8fd\uc740 \uc0ac\ub78c\uc744 \ud68c\ubcf5\uc2dc\ud0ac \uc218\ub294 \uc5c6\uc2b5\ub2c8\ub2e4\! +healOther=\u00a76{0}\ub2d8\uc774 \ud68c\ubcf5\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +helpConsole=\ucf58\uc194\uc5d0\uc11c \ub3c4\uc6c0\ub9d0\uc744 \ubcf4\ub824\uba74, ?(\uc744)\ub97c \uccd0\uc8fc\uc138\uc694. +helpFrom=\u00a76\ucee4\uba58\ub4dc\uc5d0\uc11c \uc628\ub9d0 {0}\: +helpLine=\u00a76/{0}\u00a7r\: {1} +helpMatching=\u00a76Commands matching "\u00a7c{0}\u00a76"\: +helpOp=\u00a74[\uac74\uc758]\u00a7f \u00a76{0}\\\:\u00a7r {1} +helpPlugin=\u00a74{0}\u00a7r\: \ud50c\ub7ec\uadf8\uc778 \ub3c4\uc6c0\ub9d0\: /help {1} +holdBook=\u00a74\uc4f8 \uc218 \uc788\ub294 \ucc45\uc744 \uac00\uc9c0\uace0 \uc788\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. +holdFirework=\u00a74\ud6a8\uacfc\ub97c \ucd94\uac00\ud558\uae30 \uc704\ud574\uc11c\ub294 \ud3ed\uc8fd\uc744 \ub4e4\uace0\uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4. +holdPotion=\u00a74You must be holding a potion to apply effects to it. +holeInFloor=\ubc14\ub2e5\uc5d0 \uc544\ubb34 \ube14\ub7ed\uc774 \uc5c6\uc73c\ubbc0\ub85c, \uc774\ub3d9\uc774 \ubd88\uac00\ud569\ub2c8\ub2e4. +homeSet=\u00a76\uc774\uacf3\uc744 \uc9d1\uc73c\ub85c \uc124\uc815\ud558\uc600\uc2b5\ub2c8\ub2e4. +homes=\u00a76\uc9d1\ub4e4\:\u00a7r {0} +hour=\uc2dc\uac04 +hours=\uc2dc(\uc2dc\uac04) +ignoredList=\u00a76Ignored\:\u00a7r {0} +ignorePlayer=\ub2f9\uc2e0\uc740 \uc774\uc81c {0} \ud50c\ub808\uc774\uc5b4\ub97c \ubb34\uc2dc\ud569\ub2c8\ub2e4. +illegalDate=\uc798\ubabb\ub41c \ub0a0\uc9dc \ud615\uc2dd\uc785\ub2c8\ub2e4. +infoChapter=\u00a76\ucc55\ud130 \uc120\ud0dd\: +infoChapterPages=\u00a7e ---- \u00a76{0} \u00a7e--\u00a76 Page \u00a7c{1}\u00a76 of \u00a7c{2} \u00a7e---- +infoPages=\u00a7e ---- \u00a76{2} \u00a7e--\u00a76 \ud398\uc774\uc9c0 \u00a7c{0}\u00a76/\u00a7c{1} \u00a7e---- +infoUnknownChapter=\u00a74\uc54c \uc218 \uc5c6\ub294 \ucc55\ud130. +insufficientFunds=\u00a74Insufficient funds available. +invalidCharge=\u00a74Invalid charge. +invalidFireworkFormat=\u00a7c{0} \u00a74\uc635\uc158\uc740 \u00a7c{1} \u00a74\ub77c\ub294 \uac12\uc774 \uc874\uc7ac\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. +invalidHome=\u00a7c{0}\u00a74 \uc9d1\uc774 \uc874\uc7ac\ud558\uc9c0\uc54a\uc2b5\ub2c8\ub2e4\! +invalidHomeName=\u00a74\uc9d1 \uc774\ub984\uc774 \ub9de\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4\! +invalidMob=\u00a74\uc798\ubabb\ub41c \ubab9 \ud0c0\uc785\uc785\ub2c8\ub2e4. +invalidNumber=\uc798\ubabb\ub41c \uc22b\uc790\uc785\ub2c8\ub2e4. +invalidPotion=\u00a74\uc798\ubabb\ub41c \ud3ec\uc158. +invalidPotionMeta=\u00a74\uc798\ubabb\ub41c \ud3ec\uc158 \uba54\ud0c0 \ub370\uc774\ud130\: \u00a7c{0}\u00a74. +invalidSignLine=\ud45c\uc9c0\ud310\uc758 {0}\ubc88\uc9f8 \uc904\uc774 \uc798\ubabb \ub418\uc5c8\uc2b5\ub2c8\ub2e4. +invalidWarpName=\u00a74\uc798\ubabb\ub41c \uc6cc\ud504 \uc774\ub984\uc785\ub2c8\ub2e4\! +invalidWorld=\u00a7c\uc798\ubabb\ub41c \uc6d4\ub4dc\uc785\ub2c8\ub2e4. +is=\uc740/\ub294 +itemCannotBeSold=\uadf8 \uc544\uc774\ud15c\uc740 \uc11c\ubc84\uc5d0 \ud314 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +itemMustBeStacked=\uc544\uc774\ud15c\uc744 \uac70\ub798\ud558\uae30 \uc704\ud574\uc11c 2\uac1c \uc774\uc0c1\uc758 \uac19\uc740\uc544\uc774\ud15c\uc744 \uac00\uc9c0\uace0\uc788\uc5b4\uc57c\ud569\ub2c8\ub2e4. +itemNames=\u00a76\uc9e7\uc740 \uc544\uc774\ud15c \uc774\ub984\:\u00a7r {0} +itemNotEnough1=\u00a7c\ub2f9\uc2e0\uc740 \ud310\ub9e4\ud558\uae30\uc704\ud55c \uc544\uc774\ud15c\uc744 \ucda9\ubd84\ud788 \uac00\uc9c0\uace0\uc788\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. +itemNotEnough2=\u00a77\ub2f9\uc2e0\uc758 \uc544\uc774\ud15c\uc744 \ud314\uace0\uc2f6\ub2e4\uba74, /sell <\uc544\uc774\ud15c\uc774\ub984>\uc744 \ud1b5\ud558\uc5ec \ud310\ub9e4\uac00 \uac00\ub2a5\ud569\ub2c8\ub2e4. +itemNotEnough3=\u00a77/sell itemname -1 \ub85c \uc544\uc774\ud15c 1\uac1c\ub97c \ud310\ub9e4 \ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. +itemSellAir=\uacf5\uae30\ub97c \ud314\uc544\ubcf4\ub824\uad6c\uc694? \uc544\uc774\ud15c\uc744 \ub4e4\uace0 \ub2e4\uc2dc \uc2dc\ub3c4\ud574\uc8fc\uc138\uc694. +itemSold=\u00a77 \u00a7c {0} \u00a77 {{1} \uc640 {2} \uc758 \uc544\uc774\ud15c\uc774 \ud314\ub9ac\ub2e4.) +itemSoldConsole={0} \ud310\ub9e4 {1} \uc758 \u00a77 {2} \u00a77 ({3} \uc544\uc774\ud15c\uc758 \ud56d\ubaa9 {4} \uac01\uac01\uc758) +itemSpawn=\u00a77\uc544\uc774\ud15c {1}\uc744/\ub97c {0}\uac1c \uc90d\ub2c8\ub2e4. +itemType=\u00a76\uc544\uc774\ud15c\:\u00a7c {0} \u00a76-\u00a7c {1} +itemsCsvNotLoaded=items.csv \ud30c\uc77c\uc744 \ubd88\ub7ec\uc62c \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +jailAlreadyIncarcerated=\u00a74\uc0ac\ub78c\uc774 \uc774\ubbf8 \uac10\uc625\uc5d0 \uc788\uc74c\:\u00a7c {0} +jailMessage=\u00a7c\ub2f9\uc2e0\uc740 \ubc94\uc8c4\ub97c \uc800\uc9c0\ub974\uace0\uc788\uc2b5\ub2c8\ub2e4, \ub2f9\uc2e0\uc740 \uc2dc\uac04\uc774 \ud544\uc694\ud569\ub2c8\ub2e4. +jailNotExist=\u00a74\ud574\ub2f9 \uac10\uc625\uc740 \uc874\uc7ac\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. +jailReleased=\u00a76\uc720\uc800 \u00a7c{0}\u00a76\ub294 \uac10\uc625\uc5d0\uc11c \uc11d\ubc29\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +jailReleasedPlayerNotify=\u00a76\ub2f9\uc2e0\uc740 \uc11d\ubc29\ub418\uc5c8\uc2b5\ub2c8\ub2e4\! +jailSentenceExtended=\u00a76\uac10\uc625 \uc2dc\uac04\uc774 \ub2e4\uc74c\uacfc \uac19\uc774 \uc5f0\uc7a5\ub418\uc5c8\uc2b5\ub2c8\ub2e4.\: {0} +jailSet=\u00a7c{0} \u00a76 \uac10\uc625\uc774 \uc0dd\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +jumpError=\uc774\uac83\uc740 \ub2f9\uc2e0\uc758 \ucef4\ud4e8\ud130\uc5d0 \uc624\ub958\ub97c \uc77c\uc73c\ud0ac \uc218 \uc788\uc2b5\ub2c8\ub2e4. +kickDefault=\uc11c\ubc84\uc5d0\uc11c \ucd94\ubc29\ub418\uc168\uc2b5\ub2c8\ub2e4. +kickExempt=\u00a74\ub2f9\uc2e0\uc740 \ud0a5\uc744 \ud560\uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +kickedAll=\u00a74\ubaa8\ub4e0\uc0ac\ub78c\uc744 \ud0a5\ud588\uc2b5\ub2c8\ub2e4. +kill=\u00a7c{0}\u00a76\ub2d8\uc774 \uc0ac\ub9dd\ud558\uc600\uc2b5\ub2c8\ub2e4. +killExempt=\u00a74\ub2f9\uc2e0\uc740 \u00a7c{0} \u00a74\ub97c \uc8fd\uc77c\uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +kitCost=\ \u00a77\u00a7o({0})\u00a7r +kitError2=\u00a74\ud0b7 \uc815\uc758\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \uad00\ub9ac\uc790\uc5d0\uac8c \ubb38\uc758\ud558\uc138\uc694. +kitError=\u00a7c\uc62c\ubc14\ub978 \ud0b7\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +kitGiveTo=\u00a76\ud0b7\uc744 \u00a7c {0}\u00a76 \uc5d0\uac8c \u00a7c{1} \uc9c0\uae09\ud558\uc600\uc2b5\ub2c8\ub2e4.\u00a76. +kitInvFull=\u00a74\ub2f9\uc2e0\uc758 \uc778\ubca4\ud1a0\ub9ac\uc5d0 \uacf5\uac04\uc774 \uc5c6\uc5b4\uc11c, \uc544\uc774\ud15c\uc774 \ubc14\ub2e5\uc5d0 \ubc84\ub824\uc84c\uc2b5\ub2c8\ub2e4. +kitNotFound=\u00a74\ud0b7\uc774 \uc874\uc7ac\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. +kitOnce=\u00a74\ud0b7\uc744 \ub2e4\uc2dc \uc0ac\uc6a9\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +kitReceive=\u00a7c{0}\u00a76 \ud0a4\ud2b8\ub97c \ubc1b\uc558\uc2b5\ub2c8\ub2e4. +kitTimed=\u00a7c{0}\u00a74\uc774 \uc9c0\ub098\uae30 \uc804\uc5d0\ub294 \ud0b7\uc744 \ubc1b\uc744 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +kits=\u00a76\ud0b7\ub4e4\:\u00a7r {0} +leatherSyntax=\u00a76\uac00\uc8fd \uc0c9 \ubb38\ubc95\: color\:,, \uc608\uc2dc\: color\:255,0,0. +lightningSmited=\u00a76\ubc88\uac1c\ub97c \ub9de\uc558\uc2b5\ub2c8\ub2e4. +lightningUse=\u00a7c{0}\u00a76\uc5d0\uac8c \ubc88\uac1c\ub97c \ub0b4\ub9bd\ub2c8\ub2e4. +listAfkTag=\u00a77[\uc7a0\uc218]\u00a7r +listAmount=\u00a76\ucd5c\ub300 \u00a7c{1}\u00a76\uba85\uc774 \uc811\uc18d \uac00\ub2a5\ud558\uace0, \u00a7c{0}\u00a76\uba85\uc758 \ud50c\ub808\uc774\uc5b4\uac00 \uc811\uc18d\uc911\uc785\ub2c8\ub2e4. +listAmountHidden=\u00a76\ucd5c\ub300 \u00a7c{2} \u00a76\uba85\uc774 \uc811\uc18d \uac00\ub2a5\ud558\uace0,\u00a7c{1}\u00a76 \uba85\uc774 \uc228\uae40 \uc0c1\ud0dc\uc774\uba70, \u00a7c{0}\u00a76 \uba85\uc758 \ud50c\ub808\uc774\uc5b4\uac00 \uc811\uc18d\uc911\uc785\ub2c8\ub2e4. +listGroupTag=\u00a76{0}\u00a7r\: \u00a7r +listHiddenTag=\u00a77[\uc228\uae40]\u00a7r +loadWarpError=\u00a74\uc6cc\ud504 \ub370\uc774\ud130 {0}\ub97c \ubd88\ub7ec\uc624\ub294\ub370 \uc2e4\ud328\ud558\uc600\uc2b5\ub2c8\ub2e4. +localFormat=[L]<{0}> {1} +mailClear=\u00a76\uba54\uc77c\uc744 \uc77d\uc74c\uc73c\ub85c \ud45c\uc2dc\ud558\ub824\uba74, \u00a7c /mail clear\u00a76\ub97c \uc785\ub825\ud558\uc138\uc694. +mailCleared=\u00a76\uba54\uc77c\ud568\uc744 \ube44\uc6e0\uc2b5\ub2c8\ub2e4\! +mailSent=\u00a76\uba54\uc77c\uc744 \ubcf4\ub0c8\uc2b5\ub2c8\ub2e4\! +markMailAsRead=\u00a76\uc774 \uba54\uc77c\uc744 \uc77d\uc73c\uc168\ub2e4\uba74, \u00a7c /mail clear \u00a76\uba85\ub839\uc5b4\ub97c \uc0ac\uc6a9\ud558\uc5ec \uc0ad\uc81c \ud574\uc8fc\uc138\uc694. +markedAsAway=\u00a76\uc790\ub9ac\ube44\uc6c0 \uc0c1\ud0dc\ub85c \ubcc0\uacbd\ud558\uc600\uc2b5\ub2c8\ub2e4. +markedAsNotAway=\u00a76\uc790\ub9ac\ube44\uc6c0 \uc0c1\ud0dc\uac00 \ud574\uc81c\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +matchingIPAddress=\u00a76\ud574\ub2f9 \ud50c\ub808\uc774\uc5b4\ub294 \uc774\uc804\uc5d0 \ub2e4\uc74c IP \uc8fc\uc18c\ub85c\ubd80\ud130 \uc811\uc18d\ud558\uc600\uc2b5\ub2c8\ub2e4\: +maxHomes=\u00a74\uc9d1\uc744 \u00a7c {0} \u00a74\uac1c\uae4c\uc9c0\ub9cc \uac00\uc9c8 \uc218 \uc788\uc2b5\ub2c8\ub2e4. +mayNotJail=\u00a74\uc774 \ud50c\ub808\uc774\uc5b4\ub294 \uac10\uc625\uc5d0 \uac00\ub458 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4\! +me=\ub098 +minute=\ubd84 +minutes=\ubd84 +missingItems=\u00a74\ub2f9\uc2e0\uc740 \u00a7c{0}\ub97c {1}\uac1c \uac00\uc9c0\uace0 \uc788\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.\u00a74. +mobSpawnError=\u00a74\ubab9 \uc2a4\ud3ec\ub108\ub97c \ubcc0\uacbd\ud558\ub294 \uc911 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4. +mobSpawnLimit=\uc11c\ubc84\uc5d0\uc11c \uc218\uc6a9 \ud560 \uc218 \uc788\ub294 \ubaac\uc2a4\ud130\uc758 \uac1c\uccb4 \uc218\ub97c \ucd08\uacfc\ud558\uc600\uc2b5\ub2c8\ub2e4. +mobSpawnTarget=\uc9c0\uc815\ub41c \ube14\ub85d\uc740 \ubb34\uc870\uac74 \ubaac\uc2a4\ud130 \uc2a4\ud3ec\ub108\uc774\uc5ec\uc57c\ud569\ub2c8\ub2e4. +mobsAvailable=\u00a76\ubab9\:\u00a7r {0} +moneyRecievedFrom=\u00a7a{1}\ub2d8\uaed8\uc11c \ubcf4\ub0b8 {0}\uac00 \uc218\uc2e0\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +moneySentTo=\u00a7a{0}\uac00 {1}\uc5d0\uac8c \ubcf4\ub0b4\uc84c\uc2b5\ub2c8\ub2e4. +month=\uc6d4(\ub2ec) +months=\uc6d4(\ub2ec) +moreThanZero=\uc218\ub7c9\uc774 0\ubcf4\ub2e4 \ucee4\uc57c\ud569\ub2c8\ub2e4. +moveSpeed=\u00a76\uc2a4\ud53c\ub4dc\ub97c {0}\u00a76 \ub9cc\ud07c \u00a7c {1} \u00a76\ud50c\ub808\uc774\uc5b4\uc5d0\uac8c \uc9c0\uae09\ud558\uc600\uc2b5\ub2c8\ub2e4. \u00a7c{2}\u00a76. +msgFormat=\u00a76[\u00a7c{0}\u00a76 -> \u00a7c{1}\u00a76] \u00a7r{2} +multipleCharges=\u00a74You cannot apply more than one charge to this firework. +multiplePotionEffects=\u00a74\ud55c\uac00\uc9c0 \ud3ec\uc158\uc5d0 \ud558\ub098\uc758 \ud6a8\uacfc\ub9cc \uc801\uc6a9\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. +muteExempt=\u00a74\uc774 \ud50c\ub808\uc774\uc5b4\ub97c \ubc99\uc5b4\ub9ac\ub85c \ub9cc\ub4e4 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +muteNotify=\u00a7c{0} \u00a76has muted \u00a7c{1}\u00a76. +mutedPlayer=\u00a76\ud50c\ub808\uc774\uc5b4\u00a7c {0}\u00a76\ub2d8\uc774 \ubc99\uc5b4\ub9ac\uac00 \ub418\uc5c8\uc2b5\ub2c8\ub2e4. +mutedPlayerFor=\u00a76Player\u00a7c {0} \u00a76muted for\u00a7c {1}\u00a76. +mutedUserSpeaks={0}\ub2d8\uc740 \ub9d0\ud558\ub824 \ud558\uc600\uc9c0\ub9cc, \ubc99\uc5b4\ub9ac \uc0c1\ud0dc\uc785\ub2c8\ub2e4. +nearbyPlayers=\u00a76\uc8fc\ubcc0 \ud50c\ub808\uc774\uc5b4\:\u00a7r {0} +negativeBalanceError=\u00a74\uc794\uace0\uac00 \uc74c\uc218\uac00 \ub418\uba74 \uc548\ub429\ub2c8\ub2e4. +nickChanged=\u00a76\ub2c9\ub124\uc784\uc774 \ubcc0\uacbd\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +nickDisplayName=\u00a74You have to enable change-displayname in Essentials config. +nickInUse=\u00a74\uc774\ubbf8 \uc0ac\uc6a9\uc911\uc778 \uc774\ub984\uc785\ub2c8\ub2e4. +nickNamesAlpha=\u00a74\ub2c9\ub124\uc784\uc740 \ubc18\ub4dc\uc2dc \uc601\uc22b\uc790\uc758 \uc870\ud569\uc774\uc5b4\uc57c \ud569\ub2c8\ub2e4. +nickNoMore=\u00a76\ub2f9\uc2e0\uc740 \uc774\uc81c \ub2c9\ub124\uc784\uc744 \uc0ac\uc6a9\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. +nickSet=\u00a76\uc774\uc81c \ub2f9\uc2e0\uc758 \ub2c9\ub124\uc784\uc740 \u00a7c{0} \u00a76\uc785\ub2c8\ub2e4. +nickTooLong=\u00a74\ub2c9\ub124\uc784\uc774 \ub108\ubb34 \uae41\ub2c8\ub2e4. +noAccessCommand=\u00a74\ub2f9\uc2e0\uc740 \uc774 \uba85\ub839\uc5b4\ub97c \uc0ac\uc6a9\ud560 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +noAccessPermission=\u00a74\ub2f9\uc2e0\uc740 \u00a7c{0}\u00a74 \ub97c \uc0ac\uc6a9 \ud560 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +noBreakBedrock=\u00a74\uae30\ubc18\uc554\uc744 \ud30c\uad34\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +noDestroyPermission=\u00a74\ub2f9\uc2e0\uc740 \u00a7c{0}\u00a74 \ub97c \ud30c\uad34\ud560 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +noDurability=\u00a74\uc774 \uc544\uc774\ud15c\uc5d0\ub294 \ub0b4\uad6c\ub3c4\uac00 \uc5c6\uc2b5\ub2c8\ub2e4. +noGodWorldWarning=\u00a74\uc8fc\uc758\! \uc774 \uc6d4\ub4dc\uc5d0\uc11c \ubb34\uc801 \ubaa8\ub4dc\ub294 \ube44\ud65c\uc131\ud654\ub429\ub2c8\ub2e4. +noHelpFound=\u00a74\uc77c\uce58\ud558\ub294 \uba85\ub839\uc5b4\uac00 \uc5c6\uc2b5\ub2c8\ub2e4. +noHomeSetPlayer=\ud574\ub2f9 \ud50c\ub808\uc774\uc5b4\ub294 \uc9d1 \uc124\uc815\uc774 \ub418\uc5b4\uc788\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. +noIgnored=\u00a76\ub2f9\uc2e0\uc774 \ubb34\uc2dc\ud558\ub294 \uc720\uc800\uac00 \uc5c6\uc2b5\ub2c8\ub2e4. +noKitPermission=\u00a7c\ud574\ub2f9 \ud0a4\ud2b8\ub97c \uc0ac\uc6a9\ud558\uae30 \uc704\ud574\uc120 \u00a7c{0}\u00a7c \uad8c\ud55c\uc774 \ud544\uc694\ud569\ub2c8\ub2e4. +noKits=\u00a77\uc544\uc9c1 \uc0ac\uc6a9\uac00\ub2a5\ud55c \ud0a4\ud2b8\uac00 \uc5c6\uc2b5\ub2c8\ub2e4. +noMail=\u00a76\ub2f9\uc2e0\uc5d0\uac8c \uc628 \uba54\uc77c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +noMatchingPlayers=\u00a76\uc77c\uce58\ud558\ub294 \ud50c\ub808\uc774\uc5b4\ub97c \ucc3e\uc744 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +noMetaFirework=\u00a74You do not have permission to apply firework meta. +noMetaPerm=\u00a7c{0}\u00a74 \uba54\ud0c0\ub97c \uc774 \uc544\uc774\ud15c\uc5d0 \uc801\uc6a9\uc2dc\ud0ac \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +noNewMail=\u00a76\uc0c8 \uba54\uc77c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +noPendingRequest=\u00a74\ub300\uae30\uc911\uc778 \uc694\uccad\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +noPerm=\u00a74\ub2f9\uc2e0\uc740 \u00a7c{0}\u00a74 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +noPermToSpawnMob=\u00a74\uc774 \ubaac\uc2a4\ud130\ub97c \uc18c\ud658\ud560 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +noPlacePermission=\u00a74\uadf8 \ud45c\uc9c0\ud310 \uadfc\ucc98\uc5d0 \ube14\ub7ed\uc744 \ub193\uc744 \uc218 \uc788\ub294 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +noPotionEffectPerm=\u00a74\ub2f9\uc2e0\uc740 \uc774 \ud3ec\uc158\uc5d0 \u00a7c{0} \u00a74 \ud6a8\uacfc\ub97c \uc801\uc6a9\ud560 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +noPowerTools=\u00a76\ud560\ub2f9\ub41c \ud30c\uc6cc\ud234\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +noWarpsDefined=&6\uc124\uc815\ub41c \uc6cc\ud504\uac00 \uc5c6\uc2b5\ub2c8\ub2e4. +none=\uc5c6\uc74c +notAllowedToQuestion=\u00a74\ub2f9\uc2e0\uc740 \uc9c8\ubb38\uc744 \uc0ac\uc6a9\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +notAllowedToShout=\u00a74\uc678\uce60 \uc218 \uc788\ub294 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +notEnoughExperience=\u00a74\uacbd\ud5d8\uce58\uac00 \ubd80\uc871\ud569\ub2c8\ub2e4. +notEnoughMoney=\u00a74\ub2f9\uc2e0\uc740 \ucda9\ubd84\ud55c \ub3c8\uc744 \uac00\uc9c0\uace0\uc788\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. +notFlying=\ube44\ud589\uc911\uc774 \uc544\ub2d8 +notRecommendedBukkit=\u00a74* \! * \ubc84\ud0b7 \ubc84\uc804\uc774 \uc5d0\uc13c\uc15c\uc5d0\uac8c \uad8c\uc7a5\ub418\uc9c0 \uc54a\ub294 \ube4c\ub4dc\uc785\ub2c8\ub2e4. +notSupportedYet=\uc544\uc9c1 \uc9c0\uc6d0\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. +nothingInHand=\u00a74\uc190\uc5d0 \uc544\ubb34\uac83\ub3c4 \uc5c6\uc2b5\ub2c8\ub2e4. +now=\uc9c0\uae08 +nuke=\u00a75\uc8fd\uc74c\uc758 \ube44\uac00 \ub0b4\ub9bd\ub2c8\ub2e4. +numberRequired=\ubc88\ud638\ub97c \uc785\ub825\ud574 \uc8fc\uc138\uc694, \uba4d\uccad\uc544. +onlyDayNight=\ucee4\ub9e8\ub4dc /time \uc740 \uc2dc\uac04\uc744 \ub0ae, \ubc24\uc73c\ub85c\ub9cc \ubcc0\uacbd\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. +onlyPlayerSkulls=&4\ub2f9\uc2e0\uc740 \ud50c\ub808\uc774\uc5b4 \uba38\ub9ac\uc758 \uc18c\uc720\uc790\ub9cc \uc124\uc815\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4 (&c397\:3&4). +onlyPlayers=\u00a74\ubc84\ud0b7\uc5d0\uc11c\ub294 \u00a7c{0}\u00a74 \ub97c \uc0ac\uc6a9 \ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. \uac8c\uc784\uc5d0 \uc811\uc18d\ud558\uc5ec \uc0ac\uc6a9\ud574\uc8fc\uc138\uc694. +onlySunStorm=\u00a74/\ub0a0\uc528\ub294 \ub9d1\uc74c/\ud750\ub9bc\ub9cc \uc124\uc815\uc774 \uac00\ub2a5\ud569\ub2c8\ub2e4. +orderBalances=\u00a76Ordering balances of\u00a7c {0} \u00a76users, please wait... +oversizedTempban=\u00a74You may not \ucc28\ub2e8 a player for this period of time. +pTimeCurrent=\u00a7c{0}\u00a76''s time is\u00a7c {1}\u00a76. +pTimeCurrentFixed=\u00a7c{0}\u00a76''s time is fixed to\u00a7c {1}\u00a76. +pTimeNormal=\u00a7c{0}\u00a76''s time is normal and matches the server. +pTimeOthersPermission=\u00a74\ub2e4\ub978 \ud50c\ub808\uc774\uc5b4\uc758 \uc2dc\uac04\uc744 \uc124\uc815\ud560 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +pTimePlayers=\u00a76These players have their own time\:\u00a7r +pTimeReset=\ud50c\ub808\uc774\uc5b4\uc758 \uc2dc\uac04\uc774 {0}\uc73c\ub85c \ucd08\uae30\ud654 \ub418\uc5c8\uc2b5\ub2c8\ub2e4. +pTimeSet=\u00a76Player time is set to \u00a7c{0}\u00a76 for\: \u00a7c{1}. +pTimeSetFixed=\u00a76Player time is fixed to \u00a7c{0}\u00a76 for\: \u00a7c{1}. +pWeatherCurrent=\u00a7c{0}\u00a76''s weather is\u00a7c {1}\u00a76. +pWeatherInvalidAlias=\u00a74\uc874\uc7ac\ud574\uc9c0 \uc54a\ub294 \ub0a0\uc528 \uc720\ud615\uc785\ub2c8\ub2e4 +pWeatherNormal=\u00a7c{0}\u00a76''s weather is normal and matches the server. +pWeatherOthersPermission=\ub2e4\ub978 \ud50c\ub808\uc774\uc5b4\uc758 \ub0a0\uc528\ub97c \uc124\uc815 \ud560 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +pWeatherPlayers=\u00a76These players have their own weather\:\u00a7r +pWeatherReset=\ud50c\ub808\uc774\uc5b4\uc758 \ub0a0\uc528\uac00 {0}\uc73c\ub85c \ucd08\uae30\ud654 \ub418\uc5c8\uc2b5\ub2c8\ub2e4. +pWeatherSet=\u00a76Player weather is set to \u00a7c{0}\u00a76 for\: \u00a7c{1}. +pendingTeleportCancelled=\u00a74\uc21c\uac04\uc774\ub3d9 \uc694\uccad\uc774 \ucde8\uc18c\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +playerBanIpAddress=\u00a76Player\u00a7c {0} \u00a76banned IP address\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerBanned=\u00a76\ud50c\ub808\uc774\uc5b4\u00a7c {0} \u00a76\ub2d8\uc774\u00a7c {1} \u00a76\ub2d8\uc744 \ubca4\ud558\uc600\uc2b5\ub2c8\ub2e4. \uc0ac\uc720\: \u00a7c{2}\u00a76. +playerInJail=\u00a74\uadf8 \ud50c\ub808\uc774\uc5b4\ub294 \uc774\ubbf8 {0}\u00a74 \uac10\uc625\uc5d0 \uc218\uac10\ub418\uc5b4\uc788\uc2b5\ub2c8\ub2e4. +playerJailed=\u00a76{0} \ud50c\ub808\uc774\uc5b4\uac00 \uac10\uae08\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +playerJailedFor=\u00a76\ud50c\ub808\uc774\uc5b4 {0}\uc740 {1}\uc5d0 \uac10\uae08\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +playerKicked=\u00a76Player\u00a7c {0} \u00a76kicked {1} for {2}. +playerMuted=\u00a76\ub2f9\uc2e0\uc740 \ubc99\uc5b4\ub9ac\uac00 \ub418\uc5c8\uc2b5\ub2c8\ub2e4\! +playerMutedFor=\u00a76\ub2f9\uc2e0\uc740 \u00a7c{0}\u00a76 \ub3d9\uc548 \ubc99\uc5b4\ub9ac\uac00 \ub418\uc5c8\uc2b5\ub2c8\ub2e4. +playerNeverOnServer=\u00a74{0}\ub2d8\uc740 \ub2e8 \ud55c\ubc88\ub3c4 \uc11c\ubc84\uc5d0 \ubc29\ubb38\ud55c \uc801\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +playerNotFound=\u00a74\ud50c\ub808\uc774\uc5b4\ub97c \ucc3e\uc744 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +playerUnbanIpAddress=\u00a7c{0}\u00a76\ub2d8\uc774 {1} IP\uc758 \ucc28\ub2e8\uc744 \ud574\uc81c\ud588\uc2b5\ub2c8\ub2e4. +playerUnbanned=\u00a7c{0}\u00a76\ub2d8\uc774 \u00a7c{1}\u00a76\uc758 \ucc28\ub2e8\uc744 \ud574\uc81c\ud588\uc2b5\ub2c8\ub2e4. +playerUnmuted=\u00a76\ubba4\ud2b8 \uc0c1\ud0dc\uac00 \ud574\uc81c\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +pong=Pong\! +posPitch=\u00a76Pitch\: {0} (Head angle) +posX=\u00a76X\: {0} (+\ub3d9 <-> -\uc11c) +posY=\u00a76Y\: {0} (+\uc704 <-> -\uc544\ub798) +posYaw=\u00a76Yaw\: {0} (Rotation) +posZ=\u00a76Z\: {0} (+\ub0a8 <-> -\ubd81) +possibleWorlds=\ub9c8\uc778\ud31c \uc11c\ubc84\uc5d0 \uc624\uc2ec? +potions=\u00a76\ud3ec\uc158\:\u00a7r {0}\u00a76. +powerToolAir=\u00a74\uc774 \uba85\ub839\uc5b4\ub294 \uacf5\uc911\uc5d0\uc11c \uc0ac\uc6a9\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +powerToolAlreadySet=\u00a74\ucee4\ub9e8\ub4dc \u00a7c{0}\u00a74 \uc774/\uac00 \uc774\ubbf8 \u00a7c{1}\u00a74 (\uc73c)\ub85c \ud560\ub2f9\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +powerToolAttach={0}\uc5d0 \ud560\ub2f9\ub41c \uba85\ub839\uc5b4 +powerToolClearAll=\u00a76All powertool commands have been cleared. +powerToolList=\u00a76Item \u00a7c{1} \u00a76has the following commands\: \u00a7c{0}\u00a76. +powerToolListEmpty=\u00a74Item \u00a7c{0} \u00a74has no commands assigned. +powerToolNoSuchCommandAssigned=\u00a74\ucee4\ub9e8\ub4dc \u00a7c{0}\u00a74 \uc774/\uac00 \u00a7c{1}\u00a74 (\uc73c)\ub85c \ud560\ub2f9\ub418\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4. +powerToolRemove=\u00a76\ucee4\ub9e8\ub4dc \u00a7c{0}\u00a76 \uc774/\uac00 \u00a7c{1}\u00a76 (\uc73c)\ub85c\ubd80\ud130 \uc81c\uac70\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +powerToolRemoveAll=\u00a7c{0}\u00a76 \uc5d0 \ub300\ud55c \ubaa8\ub4e0 \uba85\ub839\uc5b4\uac00 \uc0ad\uc81c\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +powerToolsDisabled=\u00a76All of your power tools have been disabled. +powerToolsEnabled=\u00a76All of your power tools have been enabled. +questionFormat=\u00a72[\uc9c8\ubb38]\u00a7r {0} +readNextPage=\u00a7c/{0} {1} \u00a76\ub97c \uc785\ub825\ud558\uc5ec \ub2e4\uc74c \ud398\uc774\uc9c0\ub97c \uc77d\uc73c\uc138\uc694. +recipe=\u00a7c{0}\u00a76 (\u00a7c{2}\u00a76\uc758 \u00a7c{1}\u00a76) \uc758 \uc870\ud569\ubc95 +recipeBadIndex=\uadf8 \ubc88\ud638\uc5d0 \ub300\ud55c \ub808\uc2dc\ud53c\uac00 \uc874\uc7ac\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. +recipeFurnace=\u00a76\uc81c\ub828\: \u00a7c{0}\u00a76. +recipeGrid=\u00a7c{0}X \u00a76| \u00a7{1}X \u00a76| \u00a7{2}X +recipeGridItem=\u00a7c{0}X \u00a76\ub294 \u00a7c{1}\uc785\ub2c8\ub2e4 +recipeMore=\u00a76Type /{0} \u00a7c{1}\u00a76 to see other recipes for \u00a7c{2}\u00a76. +recipeNone={0}\uc758 \ub808\uc2dc\ud53c\uac00 \uc874\uc7ac\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. +recipeNothing=nothing +recipeShapeless=\u00a76\uacb0\ud569 \u00a7c{0} +recipeWhere=\u00a76\uc704\uce58\: {0} +removed=\u00a7c{0}\u00a76\uac1c\uc758 \uc5d4\ud2f0\ud2f0\uac00 \uc81c\uac70\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +repair=\u00a7c{0}\u00a76\ub97c \uc131\uacf5\uc801\uc73c\ub85c \uc218\ub9ac\ud558\uc600\uc2b5\ub2c8\ub2e4. +repairAlreadyFixed=\u00a74\uc774 \uc544\uc774\ud15c\uc740 \uc218\ub9ac\uac00 \ud544\uc694\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. +repairEnchanted=\u00a74\ub2f9\uc2e0\uc740 \uc778\ucc48\ud2b8 \ub41c \uc544\uc774\ud15c\uc744 \uc218\ub9ac\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +repairInvalidType=\u00a74\uc774 \uc544\uc774\ud15c\uc740 \uc218\ub9ac\ub420 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +repairNone=\u00a74\uc218\ub9ac\ud558\ub294\ub370 \ud544\uc694\ud55c \uc544\uc774\ud15c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +requestAccepted=\u00a77\ud154\ub808\ud3ec\ud2b8 \uc694\uccad\uc744 \uc218\ub77d\ud558\uc600\uc2b5\ub2c8\ub2e4. +requestAcceptedFrom=\u00a7c{0} \u00a76 \ud154\ub808\ud3ec\ud2b8 \uc694\uccad\uc774 \uc2b9\uc778\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +requestDenied=\u00a76\uc21c\uac04\uc774\ub3d9 \uc694\uccad\uc774 \uac70\ubd80\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +requestDeniedFrom=\u00a7c{0} \u00a76 \ud154\ub808\ud3ec\ud2b8 \uc694\uccad\uc774 \uac70\ubd80\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +requestSent=\u00a7c{0}\u00a76\ub2d8\uc5d0\uac8c \ud154\ub808\ud3ec\ud2b8 \uc694\uccad\uc744 \ubcf4\ub0c5\ub2c8\ub2e4. +requestTimedOut=\u00a74\ud154\ub808\ud3ec\ud2b8 \uc694\uccad\uc774 \ud0c0\uc784\uc544\uc6c3 \ub418\uc5c8\uc2b5\ub2c8\ub2e4. +requiredBukkit=\u00a76* \! * {0} \ubc84\uc804 \uc774\uc0c1\uc758 CraftBukkit\uc744 \uc0ac\uc6a9\ud574\uc57c\ud569\ub2c8\ub2e4. \ub2e4\uc74c \uc8fc\uc18c\uc5d0\uc11c \ub2e4\uc6b4\ub85c\ub4dc \ubc1b\uc73c\uc138\uc694. http\://dl.bukkit.org/downloads/craftbukkit/ +resetBal=\u00a76\ubaa8\ub4e0 \uc628\ub77c\uc778 \ud50c\ub808\uc774\uc5b4\uc758 \uc794\uace0\uac00 \u00a7a{0} \u00a76(\uc73c)\ub85c \ub9ac\uc14b\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +resetBalAll=\u00a76\ubaa8\ub4e0 \ud50c\ub808\uc774\uc5b4\uc758 \uc794\uace0\uac00 \u00a7a{0} \u00a76(\uc73c)\ub85c \ub9ac\uc14b\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +returnPlayerToJailError=\u00a74\ud50c\ub808\uc774\uc5b4 \u00a7c {0} \u00a74\uc744/\ub97c {1} \uac10\uc625\uc73c\ub85c \ubcf4\ub0b4\ub294\ub370 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4. +runningPlayerMatch=\u00a76''\u00a7c{0}\u00a76''\uc640 \uc77c\uce58\ud558\ub294 \ud50c\ub808\uc774\uc5b4\ub97c \ucc3e\ub294 \uc911... (\uc870\uae08 \uc2dc\uac04\uc774 \uac78\ub9b4\uc218 \uc788\uc2b5\ub2c8\ub2e4) +second=\ucd08 +seconds=\ucd08 +seenOffline=\u00a76\ud50c\ub808\uc774\uc5b4\u00a7c {0} \u00a76\uc774/\uac00 \u00a7c{1}\u00a76 \uc804\ubd80\ud130 \u00a74\uc624\ud504\ub77c\uc778\u00a76\uc0c1\ud0dc\uc600\uc2b5\ub2c8\ub2e4. +seenOnline=\u00a76\ud50c\ub808\uc774\uc5b4\u00a7c {0} \u00a76\uc774/\uac00 \u00a7c{1}\u00a76 \uc804\ubd80\ud130 \u00a7a\uc628\ub77c\uc778\u00a76\uc0c1\ud0dc\uc600\uc2b5\ub2c8\ub2e4. +serverFull=\uc11c\ubc84\uac00 \uaf49 \ucc3c\uc2b5\ub2c8\ub2e4\! +serverTotal=\u00a76\uc11c\ubc84 \ucd1d \ud569\uacc4\:\u00a7c {0} +setBal=\u00a7a\uc794\uace0\uac00 {0}\uc73c\ub85c \uc124\uc815\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +setBalOthers=\u00a7a{0}\u00a7a\uc758 \uc794\uace0\ub97c {1}\uc73c\ub85c \uc124\uc815\ud569\ub2c8\ub2e4. +setSpawner=\u00a76\uc2a4\ud3ec\ub108 \ud0c0\uc785\uc744 \u00a7c{0}\u00a76\uc73c\ub85c \ubcc0\uacbd\ud569\ub2c8\ub2e4. +sheepMalformedColor=\u00a74\uc798\ubabb\ub41c \uc0c9\uc0c1\uc785\ub2c8\ub2e4. +shoutFormat=\u00a76[\uc678\uce58\uae30]\u00a7r {0} +signFormatFail=\u00a74[{0}] +signFormatSuccess=\u00a71[{0}] +signFormatTemplate=[{0}] +signProtectInvalidLocation=\u00a74\uc5ec\uae30\uc11c\ub294 \ud45c\uc9c0\ud310\uc744 \ub9cc\ub4e4\uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +similarWarpExist=\uc6cc\ud504\uc758 \uc774\ub984\uc740 \uc774\ubbf8 \ube44\uc2b7\ud55c \uc774\ub984\uc774 \uc874\uc7ac\ud569\ub2c8\ub2e4 +slimeMalformedSize=\uc798\ubabb\ub41c \ud06c\uae30. +socialSpy=\u00a7c{0}\u00a76\: \u00a7c{1}\uc5d0 \ub300\ud55c \u00a76SocialSpy +soloMob=\uadf8 \ubaac\uc2a4\ud130\ub3c4 \uc88b\uc2b5\ub2c8\ub2e4. +spawnSet=\u00a7c{0} \u00a76\uadf8\ub8f9\uc758 \uc2a4\ud3f0\uc7a5\uc18c\uac00 \uc124\uc815\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +spawned=\uc2a4\ud3f0 +sudoExempt=\u00a74You cannot sudo this user. +sudoRun=\u00a76Forcing\u00a7c {0} \u00a76to run\:\u00a7r /{1} +suicideMessage=\u00a76\uc798 \uc788\uac70\ub77c, \uc794\ud639\ud55c \uc138\uc0c1\uc544... +suicideSuccess=\u00a76{0}\u00a76\ub2d8\uc774 \uc790\uc0b4\ud588\uc2b5\ub2c8\ub2e4. +survival=\uc11c\ubc14\uc774\ubc8c +takenFromAccount=\u00a7c{0} \ub9cc\ud07c \uc9c0\ubd88\ud558\uc600\uc2b5\ub2c8\ub2e4. +takenFromOthersAccount=\u00a7a{1}\u00a7a\uc758 \uacc4\uc815\uc5d0\uc11c {0}\u00a7a\uc744 \uac00\uc838\uc640 \uc794\uace0\uac00 {2}\u00a7a\uc774 \ub418\uc5c8\uc2b5\ub2c8\ub2e4. +teleportAAll=\u00a76\ubaa8\ub4e0 \ud50c\ub808\uc774\uc5b4\uc5d0\uac8c \ud154\ub808\ud3ec\ud2b8 \uc694\uccad\uc744 \ubcf4\ub0c8\uc2b5\ub2c8\ub2e4... +teleportAll=\u00a76\ubaa8\ub4e0 \ud50c\ub808\uc774\uc5b4\ub97c \ud154\ub808\ud3ec\ud2b8 \ud558\ub294\uc911.. +teleportAtoB=\u00a7c{0}\u00a76 \uac00 \u00a7c{1}\u00a76 \uc5d0\uac8c \uc774\ub3d9 \ud558\uc600\uc2b5\ub2c8\ub2e4. +teleportDisabled=\u00a7c{0}\u00a74\uc5d0 \ub300\ud55c \ud154\ub808\ud3ec\ud2b8\ub294 \ube44\ud65c\uc131\ud654 \ub41c \uc0c1\ud0dc\uc785\ub2c8\ub2e4, +teleportHereRequest=\u00a7c{0}\u00a7c \ub294 \uc694\uccad\uc744 \ubc1b\uc544\ub4e4\uc600\uc2b5\ub2c8\ub2e4. +teleportNewPlayerError=\u00a74\uc0c8\ub85c\uc6b4 \ud50c\ub808\uc774\uc5b4\ub97c \ud154\ub808\ud3ec\ud2b8 \uc2dc\ud0ac \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +teleportRequest=\u00a7c{0}\u00a76\ub2d8\uaed8\uc11c \ub2f9\uc2e0\uc5d0\uac8c \ud154\ub808\ud3ec\ud2b8 \uc694\uccad\uc744 \ud558\uc600\uc2b5\ub2c8\ub2e4. +teleportRequestTimeoutInfo=\u00a7c{0}\u00a76\ucd08 \ud6c4 \ud154\ub808\ud3ec\ud2b8 \uc694\uccad\uc774 \uc2dc\uac04\ucd08\uacfc\ub429\ub2c8\ub2e4 +teleportTop=\u00a76\uaf2d\ub300\uae30\ub85c \uc62c\ub77c\uc654\uc2b5\ub2c8\ub2e4. +teleportationCommencing=\u00a76\ud154\ub808\ud3ec\ud2b8 \uc911... +teleportationDisabled=\u00a76\ud154\ub808\ud3ec\ud2b8\uac00 \u00a7c\ube44\ud65c\uc131\ud654\u00a76\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +teleportationDisabledFor=\u00a7c{0}\u00a76 \uc5d0 \ub300\ud55c \uc774\ub3d9\uc774 \uc81c\ud55c\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +teleportationEnabled=\u00a76\ud154\ub808\ud3ec\ud2b8\uac00 \u00a7c\ud65c\uc131\ud654\u00a76\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +teleportationEnabledFor=\u00a7c{0}\u00a76 \uc5d0 \ub300\ud55c \uc774\ub3d9\uc774 \ud5c8\uac00\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +teleporting=\u00a76\ud154\ub808\ud3ec\ud2b8 \uc911 \uc785\ub2c8\ub2e4... +teleportToPlayer=\u00a7c{0}\u00a76\ub85c \uc774\ub3d9 \ud569\ub2c8\ub2e4. +tempBanned=\u00a7cYou have been temporarily banned for {0}\:\n\u00a7r{2} +tempbanExempt=\u00a74\ud574\ub2f9 \ud50c\ub808\uc774\uc5b4\ub97c \uc784\uc2dc \ucc28\ub2e8\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +thunder=\u00a76\ub2f9\uc2e0\uc740 \uc774 \uc6d4\ub4dc\uc758 \ucc9c\ub465\uc744 {0} \uc2dc\ucf30\uc2b5\ub2c8\ub2e4. +thunderDuration=\u00a76\ub2f9\uc2e0\uc740 \uc774 \uc6d4\ub4dc\uc758 \ucc9c\ub465\uc744 {1}\ucd08 \ub3d9\uc548 {0} \uc2dc\ucf30\uc2b5\ub2c8\ub2e4. +timeBeforeHeal=\u00a74\ub2e4\uc74c \ud68c\ubcf5\uae4c\uc9c0\uc758 \ud544\uc694\ud55c \uc2dc\uac04\: \u00a7c{0}\u00a76. +timeBeforeTeleport=\u00a74\ub2e4\uc74c \ud154\ub808\ud3ec\ud2b8\uae4c\uc9c0 \ud544\uc694\ud55c \uc2dc\uac04\:\u00a7c {0}\u00a76. +timeFormat=\u00a7c{0}\u00a76 \ub610\ub294 \u00a7c{1}\u00a76 \ub610\ub294 \u00a7c{2}\u00a76 +timeSetPermission=\uc2dc\uac04\uc744 \uc124\uc815\ud560 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +timeWorldCurrent=\u00a76\u00a7c{0}\u00a76\uc758 \ud604\uc7ac \uc2dc\uac04\uc740\u00a7c {1} \u00a76\uc785\ub2c8\ub2e4. +timeWorldSet=\u00a76The time was set to\u00a7c {0} \u00a76in\: \u00a7c{1}\u00a76. +totalWorthAll=\u00a7aSold all items and blocks for a total worth of \u00a7c{1}\u00a7a. +totalWorthBlocks=\u00a7aSold all blocks for a total worth of \u00a7c{1}\u00a7a. +tps=\u00a76\ud604\uc7ac TPS \= {0} +tradeSignEmpty=\ud574\ub2f9\ub41c \ud45c\uc9c0\ud310\uc740 \ucda9\ubd84\ud55c \uacf5\uae09\uc744 \ud558\uc9c0 \ubabb\ud569\ub2c8\ub2e4. +tradeSignEmptyOwner=\u00a74\uac70\ub798 \ud45c\uc9c0\ub85c\ubd80\ud130 \uc544\ubb34\uac83\ub3c4 \ud68d\ub4dd\ud560 \uc218 \uc5c6\uc5c8\uc2b5\ub2c8\ub2e4. +treeFailure=\u00a74\ub098\ubb34 \uc0dd\uc131\uc774 \uc2e4\ud328\ud558\uc600\uc2b5\ub2c8\ub2e4. \uc794\ub514\ub098 \ud759 \uc704\uc5d0\uc11c \ub2e4\uc2dc \uc2dc\ub3c4\ud574\uc8fc\uc138\uc694. +treeSpawned=\u00a76\ub098\ubb34 \uc18c\ud658\ub428. +true=\u00a7a\ucc38\u00a7r +typeTpaccept=\u00a76\uc21c\uac04\uc774\ub3d9 \uc694\uccad\uc744 \uc218\ub77d\ud558\ub824\uba74, \u00a7c/tpaccept\u00a76 \ub97c \uc785\ub825\ud558\uc138\uc694. +typeTpdeny=\u00a77\ud154\ub808\ud3ec\ud2b8 \uc694\uccad\uc744 \uac70\uc808\ud558\ub824\uba74, \u00a7c/tpdeny\u00a77\ub97c \uc785\ub825\ud558\uc138\uc694. +typeWorldName=\u00a76\ub2f9\uc2e0\uc740 \ud2b9\uc815\ud55c \uc138\uacc4\uc758 \uc885\ub958\ub97c \uc9c0\uba85\ud560 \uc218\ub3c4 \uc788\uc2b5\ub2c8\ub2e4. +unableToSpawnMob=\u00a74\ubaac\uc2a4\ud130 \uc18c\ud658\uc744 \ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +unignorePlayer=\u00a76\ub2f9\uc2e0\uc740 \ub354 \uc774\uc0c1 \u00a7c{0} \u00a76\ud50c\ub808\uc774\uc5b4\ub97c \ubb34\uc2dc\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. +unknownItemId=\u00a74\uc54c \uc218 \uc5c6\ub294 \uc544\uc774\ud15c \uace0\uc720\ubc88\ud638\:\u00a7r {0}\u00a74. +unknownItemInList=\uc54c \uc218 \uc5c6\ub294 \uc544\uc774\ud15c {0} \uac00 {1} \ubc88\uc9f8 \ub9ac\uc2a4\ud2b8\uc5d0 \uc874\uc7ac\ud569\ub2c8\ub2e4. +unknownItemName=\u00a74\uc54c \uc218 \uc5c6\ub294 \uc544\uc774\ud15c \uc774\ub984\: {0} +unlimitedItemPermission=\u00a74\ubb34\uc81c\ud55c \uc544\uc774\ud15c \u00a7c{0}\u00a74 \uc5d0 \ub300\ud55c \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +unlimitedItems=\ubb34\uc81c\ud55c \uc544\uc774\ud15c \ubaa9\ub85d\: +unmutedPlayer=\ud50c\ub808\uc774\uc5b4 \u00a7c{0}\u00a76\ub294 \uc774\uc81c \ub9d0\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. +unvanishedReload=\u00a74A reload has forced you to become visible. +upgradingFilesError=\ud30c\uc77c\uc744 \uc5c5\uadf8\ub808\uc774\ub4dc \ud558\ub358 \ub3c4\uc911, \uc624\ub958\uac00 \ubc1c\uc0dd\ud558\uc600\uc2b5\ub2c8\ub2e4. +uptime=\u00a76\uac00\ub3d9 \uc2dc\uac04\:\u00a7c {0} +userAFK=\u00a77{0} \u00a75\uc740 \ud604\uc7ac \uc7a0\uc218 \uc0c1\ud0dc\uc774\ubbc0\ub85c \uc751\ub2f5\ud558\uc9c0 \uc54a\uc744 \uc218 \uc788\uc2b5\ub2c8\ub2e4. +userDoesNotExist={0} \uc720\uc800\ub294 \uc874\uc7ac\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. +userIsAway=\u00a77* {0}\u00a77\ub2d8\uc774 \uc7a0\uc218 \uc0c1\ud0dc \uc785\ub2c8\ub2e4. +userIsNotAway=\u00a77* {0}\u00a77\ub2d8\uc758 \uc7a0\uc218 \uc0c1\ud0dc\uac00 \ub05d\ub0ac\uc2b5\ub2c8\ub2e4. +userJailed=\u00a76\uac10\uc625\uc5d0 \uac10\uae08\ub418\uc5c8\uc2b5\ub2c8\ub2e4\! +userUnknown=\u00a74\uacbd\uace0 \: ''\u00a7c{0}\u00a74'' \ub294 \uc11c\ubc84\uc5d0 \ud55c\ubc88\ub3c4 \uc811\uc18d\ud574\ubcf4\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4\! +userdataMoveBackError=userdata/ {0}.tmp \ub97c userdata/ {1} \ub85c \uc62e\uae30\ub294\ub370 \uc2e4\ud328\ud558\uc600\uc2b5\ub2c8\ub2e4. +userdataMoveError=\uc720\uc800\ub370\uc774\ud130 / {0}\uc744/\ub97c \uc720\uc800\ub370\uc774\ud130 / {1}.tmp\ub85c \uc62e\uae30\ub294\ub370 \uc2e4\ud328\ud558\uc600\uc2b5\ub2c8\ub2e4. +usingTempFolderForTesting=\ud14c\uc2a4\ud2b8\ub97c \uc704\ud574 temp \ud3f4\ub354\ub97c \uc0ac\uc6a9\ud569\ub2c8\ub2e4\: +vanished=\u00a76\ub2f9\uc2e0\uc740 \uc774\uc81c \uc77c\ubc18 \ud50c\ub808\uc774\uc5b4\uc5d0\uac8c \ubcf4\uc774\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4, \uadf8\ub9ac\uace0 \uac8c\uc784 \ub0b4 \uba85\ub839\uc5b4\ub85c\ubd80\ud130 \uc228\uaca8\uc9d1\ub2c8\ub2e4. +versionMismatch=\u00a74\ubc84\uc804 \ubd88\uc77c\uce58\! {0}\uc744 \ub3d9\uc77c\ud55c \ubc84\uc804\uc73c\ub85c \uc5c5\ub370\uc774\ud2b8 \ud574 \uc8fc\uc138\uc694 +versionMismatchAll=\ubc84\uc804\uc774 \ubd88\uc77c\uce58\ud569\ub2c8\ub2e4\! \ubaa8\ub4e0 Essentials jar \ud30c\uc77c\ub4e4\uc758 \ubc84\uc804\uc744 \uac19\uc740 \ubc84\uc804\uc73c\ub85c \uc5c5\ub370\uc774\ud2b8 \ud574 \uc8fc\uc138\uc694. +voiceSilenced=\u00a76\ub2f9\uc2e0\uc758 \ubaa9\uc18c\ub9ac\uac00 \uce68\ubb35\ub418\uc5c8\uc2b5\ub2c8\ub2e4 +walking=\uac77\uae30 +warpDeleteError=\u00a74\uc6cc\ud504 \ud30c\uc77c \uc0ad\uc81c\uc911 \ubb38\uc81c\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4. +warpList={0} +warpListPermission=\u00a74\ub2f9\uc2e0\uc740 \uc6cc\ud504 \ubaa9\ub85d\uc744 \ubcfc \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +warpNotExist=\u00a74\ud574\ub2f9 \uc6cc\ud504\ub294 \uc874\uc7ac\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. +warpOverwrite=\u00a74\ub2f9\uc2e0\uc740 \uc6cc\ud504\ub97c \ub36e\uc5b4 \uc50c\uc6b8 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +warpSet=\u00a76\uc6cc\ud504 {0}\uc774 \ucd94\uac00\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +warpUsePermission=\u00a7c\ub2f9\uc2e0\uc740 \uadf8 \uc6cc\ud504\ub97c \uc0ac\uc6a9\ud560 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +warpingTo=\u00a7c{0}\u00a76\uc73c\ub85c \uc6cc\ud504\ud569\ub2c8\ub2e4. +warps=\u00a76\uc6cc\ud504 \ub9ac\uc2a4\ud2b8\:\u00a7r {0} +warpsCount=\u00a76\ud604\uc7ac\u00a7c {0} \u00a76\uac1c\uc758 \uc6cc\ud504\uac00 \uc788\uc2b5\ub2c8\ub2e4. \ud398\uc774\uc9c0 \u00a7c{1}\u00a76/\u00a7c{2}\u00a76. +weatherStorm=\u00a76{0}\uc758 \ub0a0\uc528\uac00 \ud3ed\ud48d\uc73c\ub85c \uc124\uc815\ub418\uc5c8\uc2b5\ub2c8\ub2e4 +weatherStormFor=\u00a76{0}\u00a76\uc758 \ub0a0\uc528\uac00 {1}\u00a76\ucd08\uac04 \ucc9c\ub465\ubc88\uac1c\ub85c \uc124\uc815\ub429\ub2c8\ub2e4. +weatherSun=\u00a76{0}\u00a76\uc758 \ub0a0\uc528\uac00 \ub9d1\uc74c\uc73c\ub85c \uc124\uc815\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +weatherSunFor=\u00a77{0}\ucd08\uac04 \ub2f9\uc2e0\uc774 \uc788\ub294 \uc6d4\ub4dc\ub294 \ub9d1\uac8c \uc720\uc9c0\ub429\ub2c8\ub2e4. +whoisAFK=\u00a76 - \uc7a0\uc218\:\u00a7r {0} +whoisBanned=\u00a76 - \ucc28\ub2e8\:\u00a7r {0} +whoisExp=\u00a76 - \uacbd\ud5d8\uce58\:\u00a7r {0} (Level {1}) +whoisFly=\u00a76 - \ube44\ud589 \ubaa8\ub4dc\:\u00a7r {0} ({1}) +whoisGamemode=\u00a76 - \uac8c\uc784\ubaa8\ub4dc\:\u00a7r {0} +whoisGeoLocation=\u00a76 - \uc704\uce58\: \u00a7r{0} +whoisGod=\u00a76 - \ubb34\uc801 \ubaa8\ub4dc\:\u00a7r {0} +whoisHealth=\u00a76 - \uccb4\ub825\:\u00a7r {0}/20 +whoisIPAddress=\u00a76 - \uc544\uc774\ud53c\:\u00a7r {0} +whoisJail=\u00a76 - \uac10\uc625\:\u00a7r {0} +whoisLocation=\u00a76 - \uc704\uce58\: \u00a7r({0}, {1}, {2}, {3}) +whoisMoney=\u00a79 - \uc794\uc561\: {0} +whoisMuted=\u00a76 - \ucc44\ud305 \uae08\uc9c0\:\u00a7r {0} +whoisNick=\u00a76 - \ub2c9\ub124\uc784\:\u00a7r {0} +whoisOp=\u00a76 - \uad00\ub9ac\uc790\:\u00a7r {0} +whoisTop=\u00a76 \=\=\=\=\=\= WhoIs\:\u00a7c {0} \u00a76\=\=\=\=\=\= +worth=\u00a7a{0} {2}\uac1c\uc758 \uac00\uaca9\uc740 \u00a7c{1}\u00a7a \uc785\ub2c8\ub2e4. (\uc544\uc774\ud15c 1\uac1c\uc758 \uac00\uaca9\uc740 {3} \uc785\ub2c8\ub2e4.) +worthMeta=\u00a77\uacb9\uccd0\uc9c4 {0}\:{1} \ub294 \u00a7c{2}\uc758 \uac00\uce58\uac00 \uc788\uc501\ub2c8\ub2e4.\u00a77 (\uc544\uc774\ud15c {3}\ub294 \uac01 {4} \ub9cc\ud07c\uc758 \uac00\uce58) +worthSet=\uac00\uce58 \ubc0f \uac12 \uc124\uc815 +year=\ub144(\ub144\ub3c4) +years=\ub144 +youAreHealed=\u00a77\ub2f9\uc2e0\uc740 \uce58\ub8cc\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +youHaveNewMail=\u00a76\ub2f9\uc2e0\uc740 \u00a7c{0}\u00a76\uac1c\uc758 \uba54\uc77c\uc774 \uc788\uc2b5\ub2c8\ub2e4. \u00a7c/mail read\u00a76 \uba85\ub839\uc5b4\ub97c \ud1b5\ud574 \uba54\uc77c\uc744 \ud655\uc778\ud574\uc8fc\uc138\uc694. +whoisHunger=\u00a76 - \ubc30\uace0\ud514\:\u00a7r {0}/20 (+{1} \ucd94\uac00 \uccb4\ub825) +kitDelay=\u00a7m{0}\u00a7r +giveSpawnFailure=\u00a74Not enough space, \u00a7c{0} \u00a7c{1} \u00a74was lost. +noKitGroup=\u00a74\ub2f9\uc2e0\uc740 \uc774 \ud0b7\uc5d0 \ub300\ud558\uc5ec \uc811\uadfc \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +inventoryClearingFromAll=\u00a76\ubaa8\ub4e0 \uc720\uc800\uc758 \uc778\ubca4\ud1a0\ub9ac\uac00 \ucd08\uae30\ud654\ub429\ub2c8\ub2e4. +inventoryClearingAllItems=\u00a76{0}\uc758 \ubaa8\ub4e0 \uc778\ubca4\ud1a0\ub9ac \uc544\uc774\ud15c\uc744 \uc81c\uac70\ud588\uc2b5\ub2c8\ub2e4. +inventoryClearingAllArmor=\u00a76{0}\uc758 \uac11\uc637\uc744 \ud3ec\ud568\ud55c \ubaa8\ub4e0 \uc778\ubca4\ud1a0\ub9ac\uc758 \uc544\uc774\ud15c\uc744 \uc81c\uac70\ud588\uc2b5\ub2c8\ub2e4. +inventoryClearingAllStack=\u00a76{1}\u00a76\uc758 \ubaa8\ub4e0 \u00a7c {0} \u00a76\uc744 \uc81c\uac70\ud588\uc2b5\ub2c8\ub2e4. +inventoryClearingStack=\u00a76Removed\u00a7c {0} \u00a76of\u00a7c {1} \u00a76from {2}\u00a76. +inventoryClearFail=\u00a74Player {0} \u00a74does not have\u00a7c {1} \u00a74of\u00a7c {2}\u00a74. +localNoOne= +totalSellableAll=\u00a7aThe total worth of all sellable items and blocks is \u00a7c{1}\u00a7a. +totalSellableBlocks=\u00a7aThe total worth of all sellable blocks is \u00a7c{1}\u00a7a. +radiusTooBig=\u00a74\ubc94\uc704\uac00 \ub108\ubb34 \ud07d\ub2c8\ub2e4\! \ucd5c\ub300 \ubc94\uc704\ub294 {0}\uc785\ub2c8\ub2e4. +isIpBanned=\u00a76IP \u00a7c{0} \u00a76\ub294 \ucc28\ub2e8 \ub418\uc5c8\uc2b5\ub2c8\ub2e4. +mobDataList=\u00a76Valid mob data\:\u00a7r {0} +vanish=\u00a76{0}\u00a76\ub2d8\uc758 \uc0ac\ub77c\uc9c0\uae30\uac00 {1}. +noLocationFound=\u00a74\uc62c\ubc14\ub978 \uc704\uce58\ub97c \ucc3e\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4. +coordsKeyword={0}, {1}, {2} +banExemptOffline=\u00a74\ub2f9\uc2e0\uc740 \uc811\uc18d\uc911\uc774\uc9c0 \uc54a\uc740 \ud50c\ub808\uc774\uc5b4\ub97c \ucc28\ub2e8\uc2dc\ud0ac \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +tempbanExemptOffline=\u00a74\ub2f9\uc2e0\uc740 \uc811\uc18d\uc911\uc774\uc9c0 \uc54a\uc740 \ud50c\ub808\uc774\uc5b4\ub97c \uc784\uc2dc \ucc28\ub2e8\uc2dc\ud0ac\uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +mayNotJailOffline=\u00a74\ub2f9\uc2e0\uc740 \uc811\uc18d\uc911\uc774\uc9c0 \uc54a\uc740 \ud50c\ub808\uc774\uc5b4\ub97c \uac10\uc625\uc5d0 \ubcf4\ub0bc \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +muteExemptOffline=\u00a74\uc624\ud504\ub77c\uc778 \ud50c\ub808\uc774\uc5b4\ub97c \ubc99\uc5b4\ub9ac\ub85c \ub9cc\ub4e4 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +ignoreExempt=\u00a74\ub2f9\uc2e0\uc740 \uc774 \ud50c\ub808\uc774\uc5b4\ub97c \ubb34\uc2dc\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +unsafeTeleportDestination=\u00a74\ud154\ub808\ud3ec\ud2b8 \ub300\uc0c1\uc774 \uc548\uc804\ud558\uace0 \ud154\ub808\ud3ec\ud2b8\uac00 \uc548\uc804 \ube44\ud65c\uc131\ud654 \ub429\ub2c8\ub2e4. +noMetaJson=JSON \uba54\ud0c0 \ud14c\uc774\ud130\ub294 \uc774 \ubc84\ud0b7 \ubc84\uc804\uc5d0\uc11c \uc9c0\uc6d0\ub418\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. +maxMoney=\u00a74 \uc774 \ud2b8\ub79c\uc7ad\uc158\uc774 \uacc4\uc815\uc5d0 \ub300\ud55c \uade0\ud615 \uc81c\ud55c\uc744 \ucd08\uacfc\ud560 \uac83 \uc785\ub2c8\ub2e4. +skullChanged=\u00a76\uba38\ub9ac\uac00 \u00a7c{0}\u00a76 (\uc73c)\ub85c \ubcc0\uacbd\ub418\uc5c8\uc2b5\ub2c8\ub2e4. +alphaNames=\u00a74\ud50c\ub808\uc774\uc5b4 \uc774\ub984\uc740 \ubb38\uc790, \uc22b\uc790 \ubc0f \ubc11\uc904\uc758 \uc870\ud569\uc73c\ub85c \uc774\ub8e8\uc5b4 \uc838\uc57c\ub9cc \ud569\ub2c8\ub2e4. +givenSkull=\u00a7c{0}\u00a76\uc758 \uba38\ub9ac\ub97c \uc5bb\uc5c8\uc2b5\ub2c8\ub2e4. +noPermissionSkull=\u00a74\ub2f9\uc2e0\uc740 \uc774 \uba38\ub9ac\ub97c \uc218\uc815\ud560 \uc218 \uc788\ub294 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +teleportInvalidLocation=30000000 \uc774\uc0c1\uc758 \uc88c\ud45c\ub294 \ucc3e\uc744 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +invalidSkull=\u00a74\ud50c\ub808\uc774\uc5b4\uc758 \uba38\ub9ac\ub97c \ub4dc\uc138\uc694. +weatherInvalidWorld={0}\uc774\ub77c\ub294 \uc6d4\ub4dc\ub97c \ucc3e\uc744 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +gameModeInvalid=\u00a74\ub2f9\uc2e0\uc740 \u00a7c {0}\u00a74\uc744(\ub97c) \ub5a8\uc5b4\ub728\ub9b4 \uad8c\ud55c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. +mailTooLong=\u00a74\uba54\uc77c \uba54\uc2dc\uc9c0\uac00 \ub108\ubb34 \uae41\ub2c8\ub2e4. \uc601\uc5b4 \uae30\uc900 1000\uc790 \ub97c \ub118\uc9c0 \uc54a\ub3c4\ub85d \ud574\uc8fc\uc138\uc694. +mailDelay=\ub108\ubb34 \ub9ce\uc740 \uc591\uc758 \uc774\uba54\uc77c\uc744 \ubcf4\ub0c8\uc2b5\ub2c8\ub2e4. \ucd5c\ub300\: {0} +seenAccounts=\u00a76\ud50c\ub808\uc774\uc5b4\uac00 \u00a7c{0}&6(\uc73c)\ub85c\ub3c4 \uc54c\ub824\uc838 \uc788\uc2b5\ub2c8\ub2e4. +unableToSpawnItem=\u00a7c{0}\u00a74 \uc744/\ub97c \uc0dd\uc131\uac00\ub2a5\ud55c \uc544\uc774\ud15c\uc774 \uc544\ub2c8\ubbc0\ub85c \uc0dd\uc131\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4. +itemsConverted=\u00a76Converted all items into blocks. +itemsNotConverted=\u00a74You have no items that can be converted into blocks. +mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\: +mailMessage={0} + +whoisTempBanned=\u00a76 - Ban expires:\u00a7r {0} +playerTempBanned=\u00a76Player \u00a7c{0}\u00a76 temporarily banned \u00a7c{1}\u00a76 for \u00a7c{2}\u00a76: \u00a7c{3}\u00a76. +mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1} diff --git a/Essentials/src/messages_lt.properties b/Essentials/src/messages_lt.properties new file mode 100644 index 0000000000..3070b45c36 --- /dev/null +++ b/Essentials/src/messages_lt.properties @@ -0,0 +1,558 @@ +#X-Generator: crowdin.net +#version: TeamCity +# Single quotes have to be doubled: '' +# Translations start here +# by: +action=\u00a75* {0} \u00a75{1} +addedToAccount=\u00a7a{0} buvo prid\u0117ta \u012f j\u016bs\u0173 s\u0105skait\u0105. +addedToOthersAccount=\u00a7a{0} buvo prid\u0117ta \u012f {1}\u00a7a s\u0105skait\u0105. Naujas balansas\: {2} +adventure=nuotyki\u0173 +alertBroke=broke\: +alertFormat=\u00a73[{0}] \u00a7r {1} \u00a76 {2} at\: {3} +alertPlaced=placed\: +alertUsed=used\: +antiBuildBreak=\u00a74Tu neturi leidimo griauti\u00a7c {0} \u00a74blok\u0173 \u010dia. +antiBuildCraft=\u00a74Tu neturi leidimo sukurti\u00a7c {0}\u00a74. +antiBuildDrop=\u00a74Tu neturi leidimo i\u0161mesti\u00a7c {0}\u00a74. +antiBuildInteract=\u00a74Tu neturi leidimo naudotis\u00a7c {0}\u00a74. +antiBuildPlace=\u00a74Tu neturi leidimo pad\u0117ti\u00a7c {0} \u00a74cia. +antiBuildUse=\u00a74Tu neturi leidimo naudoti\u00a7c {0}\u00a74. +autoAfkKickReason=Tu buvai i\u0161mestas u\u017e b\u016bvim\u0105 AFK daugiau, nei {0} minutes. +backAfterDeath=\u00a76Naudok /back komanda, kad gr\u012f\u017etum \u012f mirties viet\u0105. +backUsageMsg=\u00a76Gr\u012f\u017etama \u012f ankstesn\u0119 viet\u0105. +backupDisabled=\u00a74An external backup script has not been configured. +backupFinished=\u00a76Backup finished. +backupStarted=\u00a76Backup started. +balance=\u00a7aBalansas\:\u00a7c {0} +balanceOther=\u00a7a{0} balansas\:\u00a7c {1} +balanceTop=\u00a76Top balansai ({0}) +banExempt=\u00a74Tu negali u\u017eblokuoti \u0161io \u017eaid\u0117jo. +banFormat=\u00a74U\u017eblokuotas\:\n\u00a7r{0} +bed=\u00a7obed\u00a7r +bedMissing=\u00a74Tavo lova yra nenustatyt\u0105, nerasta arba u\u017ed\u0117ta blokais. +bedNull=\u00a7mlova\u00a7r +bedSet=\u00a76Atsiradimo vieta nustatyta\! +bigTreeFailure=\u00a74Nepavyko sukurti didelio med\u017eio. Pabandyk dar kart\u0105 ant \u017eol\u0117s arba \u017eemi\u0173. +bigTreeSuccess=\u00a76Didelis medis sukurtas. +blockList=\u00a76Essentials perduoda \u0161ias komandas \u012f kit\u0105 \u012fskiep\u012f\: +bookAuthorSet=\u00a76Knygos autorius nustatytas \u012f {0}. +bookLocked=\u00a76\u0160i knyga dabar yra u\u017erakinta. +bookTitleSet=\u00a76Knygos pavadinimas nustatytas \u012f {0}. +broadcast=\u00a7r\u00a76[\u00a74Broadcast\u00a76]\u00a7a {0} +buildAlert=\u00a74Tau neleid\u017eiama statyti. +bukkitFormatChanged=Bukkit versijos formatas pakeistas. Versija nepatikrinta. +burnMsg=\u00a76Tu u\u017edegei\u00a7c {0} \u00a76ugnimi\u00a7c {1} sekund\u0117ms\u00a76. +canTalkAgain=\u00a76Tu v\u0117l dabar gali kalb\u0117ti. +cannotStackMob=\u00a74You do not have permission to stack multiple mobs. +cantFindGeoIpDB=Nepavyko surasti GeoIP databazes\! +cantReadGeoIpDB=Nepavyko perskaityti GeoIP databazes\! +cantSpawnItem=\u00a74You are not allowed to spawn the item\u00a7c {0}\u00a74. +chatTypeAdmin=[A] +chatTypeLocal=[L] +chatTypeSpy=[Spy] +cleaned=Userfiles Cleaned. +cleaning=Cleaning userfiles. +commandFailed=Komanda {0} nepavyko\: +commandHelpFailedForPlugin=Error getting help for plugin\: {0} +commandNotLoaded=\u00a74Command {0} is improperly loaded. +compassBearing=\u00a76Bearing\: {0} ({1} degrees). +configFileMoveError=Failed to move config.yml to backup location. +configFileRenameError=Nepavyko pervadinti laikino failo \u012f config.yml. +connectedPlayers=\u00a76Prisijung\u0119 \u017eaid\u0117jai\u00a7r +connectionFailed=Failed to open connection. +cooldownWithMessage=\u00a74Cooldown\: {0} +corruptNodeInConfig=\u00a74Notice\: Your configuration file has a corrupt {0} node. +couldNotFindTemplate=\u00a74Could not find template {0} +creatingConfigFromTemplate=Creating config from template\: {0} +creatingEmptyConfig=Kuriama tuscia konfiguracija\: {0} +creative=k\u016brybinis +currency={0}{1} +currentWorld=\u00a76Dabartinis pasaulis\:\u00a7c {0} +day=diena +days=dienos +defaultBanReason=J\u016bs buvote u\u017eblokuotas\! +deleteFileError=Nepavyksta panaikinti failo\: {0} +deleteHome=\u00a76Namas\u00a7c {0} \u00a76buvo i\u0161trintas. +deleteJail=\u00a76Kal\u0117jimas\u00a7c {0} \u00a76buvo panaikintas. +deleteWarp=\u00a76Warp\u00a7c {0} \u00a76buvo i\u0161trintas. +deniedAccessCommand=\u00a7c{0} \u00a74was denied access to command. +denyBookEdit=\u00a74 Tu negali atrakinti \u0161i\u0105 knyg\u0105. +denyChangeAuthor=\u00a74Tu negali pakeisti \u0161ios knygos autoriaus. +denyChangeTitle=\u00a74Tu negali pakeisti sios knygos pavadinimo. +depth=\u00a76Tu esi juros lygyje. +depthAboveSea=\u00a76Esi\u00a7c {0}\u00a76m vir\u0161 j\u016bros lygio. +depthBelowSea=\u00a76Tu esi\u00a7c {0} \u00a76blokais-(u) zemiau juros lygio. +destinationNotSet=Paskirties vieta nenustatyta\! +disableUnlimited=\u00a76Disabled unlimited placing of\u00a7c {0} \u00a76for {1}. +disabled=i\u0161jungta +disabledToSpawnMob=\u00a74Spawning this mob was disabled in the config file. +distance=\u00a76Distance\: {0} +dontMoveMessage=\u00a76Teleportacija prasid\u0117s po\u00a7c {0}\u00a76. Nejud\u0117kite. +downloadingGeoIp=Siun\u010diama GeoIP databaze... tai gali \u0161iek tiek u\u017etrukti (Kaime\: 0.6 MB, Mieste\: 20MB) +duplicatedUserdata=Duplicated userdata\: {0} and {1}. +durability=\u00a76This tool has \u00a7c{0}\u00a76 uses left +editBookContents=\u00a7eTu dabar gali redaguoti \u0161ios knygos turin\u012f. +enableUnlimited=\u00a76Duodama neribota suma\u00a7c {0} \u00a76\u017eaid\u0117jui \u00a7c{1}\u00a76. +enabled=\u012fjungtas +enchantmentApplied=\u00a76The enchantment\u00a7c {0} \u00a76has been applied to your item in hand. +enchantmentNotFound=\u00a74Enchantment not found\! +enchantmentPerm=\u00a74Tu neturi teis\u0117s\u00a7c {0}\u00a74. +enchantmentRemoved=\u00a76The enchantment\u00a7c {0} \u00a76has been removed from your item in hand. +enchantments=\u00a76Enchantments\:\u00a7r {0} +errorCallingCommand=Error calling command /{0} +errorWithMessage=\u00a7cKlaida\:\u00a74 {0} +essentialsHelp1=The file is broken and Essentials can''t open it. Essentials is now disabled. If you can''t fix the file yourself, go to http\://tiny.cc/EssentialsChat +essentialsHelp2=The file is broken and Essentials can''t open it. Essentials is now disabled. If you can''t fix the file yourself, either type /essentialshelp in game or go to http\://tiny.cc/EssentialsChat +essentialsReload=\u00a76Essentials perkrautas\u00a7c {0}. +exp=\u00a7c{0} \u00a76has\u00a7c {1} \u00a76exp (level\u00a7c {2}\u00a76) and needs\u00a7c {3} \u00a76more exp to level up. +expSet=\u00a7c{0} \u00a76dabar turi\u00a7c {1} \u00a76exp. +extinguish=Tu u\u017egesinai save. +extinguishOthers=\u00a76You extinguished {0}\u00a76. +failedToCloseConfig=Failed to close config {0}. +failedToCreateConfig=Failed to create config {0}. +failedToWriteConfig=Failed to write config {0}. +false=\u00a74false\u00a7r +feed=\u00a76Tavo apetitas buvo pasotintas. +feedOther=\u00a76Tu pasisotinai \u00a7c{0}\u00a76. +fileRenameError=Nepavyko pervadinti {0} failo\! +fireworkColor=\u00a74Invalid firework charge parameters inserted, must set a color first. +fireworkEffectsCleared=\u00a76Removed all effects from held stack. +fireworkSyntax=\u00a76Fejeverk\u0173 parametrai\:\u00a7c spalva\: [nykimas\:] [forma\:] [efektas\:]\n\u00a76Norint naudoti daug spalv\u0173/efekt\u0173, atskirkit\u0117s reiksm\u0117s kableliais\: \u00a7cred,blue,pink ir t.t\n\u00a76Formos\:\u00a7c star, ball, large, creeper, burst \u00a76Efektai\:\u00a7c trail, twinkle. +flyMode=\u00a76Nustatytas fly r\u0117\u017eimas\u00a7c {0} \u00a76 {1}\u00a76. +flying=skrenda +foreverAlone=\u00a74Tu neturi kam atra\u0161yti. +fullStack=\u00a74Tu turi pilna stacka. +gameMode=\u00a76\u017daid\u0117jo \u00a7c{1} \u00a76r\u0117\u017eimas buvo nustatytas \u012f \u00a7c{0}\u00a76. +gcWorld=\u00a76{0} "\u00a7c{1}\u00a76"\: \u00a7c{2}\u00a76 chunks, \u00a7c{3}\u00a76 entities, \u00a7c{4}\u00a76 tiles. +gcfree=\u00a76Free memory\:\u00a7c {0} MB. +gcmax=\u00a76Maximum memory\:\u00a7c {0} MB. +gctotal=\u00a76Allocated memory\:\u00a7c {0} MB. +geoIpUrlEmpty=GeoIP download url is empty. +geoIpUrlInvalid=GeoIP download url is invalid. +geoipJoinFormat=\u00a76Player \u00a7c{0} \u00a76comes from \u00a7c{1}\u00a76. +giveSpawn=\u00a76Giving\u00a7c {0} \u00a76of\u00a7c {1} to\u00a7c {2}\u00a76. +godDisabledFor=\u00a7ci\u0161jungta\u00a76 u\u017e\u00a7c {0} +godEnabledFor=\u00a7aenabled\u00a76 for\u00a7c {0} +godMode=\u00a76Dievo r\u0117\u017eimas\u00a7c {0}\u00a76. +groupDoesNotExist=\u00a74There''s no one online in this group\! +groupNumber=\u00a7c{0}\u00a7f prisijungusi\u0173, pilnas s\u0105ra\u0161as\:\u00a7c /{1} {2} +hatArmor=\u00a74Tu negali naudoti \u0161io daikto kaip kepur\u0117s\! +hatEmpty=\u00a74Tu nedevi kepures. +hatFail=\u00a74Tu turi ka\u017ek\u0105 tur\u0117ti savo rankose. +hatPlaced=\u00a76Megaukis savo nauja kepure\! +hatRemoved=\u00a76Tavo kepure buvo nuimta. +haveBeenReleased=\u00a76Tu buvai paleistas. +heal=\u00a76Tu buvai pagydytas. +healDead=\u00a74Tu negali gydyti negyv\u0173 \u017emoni\u0173\! +healOther=\u00a76Pagydei\u00a7c {0}\u00a76. +helpConsole=Kad matyti pagalba konsoleje, rasykite ?. +helpFrom=\u00a76Komandos i\u0161 {0}\: +helpLine=\u00a76/{0}\u00a7r\: {1} +helpMatching=\u00a76Commands matching "\u00a7c{0}\u00a76"\: +helpOp=\u00a74[HelpOp]\u00a7r \u00a76{0}\:\u00a7r {1} +helpPlugin=\u00a74{0}\u00a7r\: \u012eskiepio pagalba\: /help {1} +holdBook=\u00a74Tu nelaikai rankose knygos, kurioje b\u016bt\u0173 galima ra\u0161yti. +holdFirework=\u00a74Tu turi laikyti fejerverk\u0105, kad suteiktum efekt\u0173. +holdPotion=\u00a74You must be holding a potion to apply effects to it. +holeInFloor=\u00a74Hole in floor\! +homeSet=\u00a76Namai nustatyti. +homes=\u00a76Namai\:\u00a7r {0} +hour=valanda +hours=valandos +ignoredList=\u00a76Ignoruoji\:\u00a7r {0} +ignorePlayer=\u00a76Nuo dabar tu ignoruoji\u00a7c {0} \u00a76\u017eaid\u0117j\u0105. +illegalDate=Neleistinas datos formatas. +infoChapter=\u00a76Select chapter\: +infoChapterPages=\u00a7e ---- \u00a76{0} \u00a7e--\u00a76 Puslapis \u00a7c{1}\u00a76 is \u00a7c{2} \u00a7e---- +infoPages=\u00a7e ---- \u00a76{2} \u00a7e--\u00a76 Puslapis \u00a7c{0}\u00a76/\u00a7c{1} \u00a7e---- +infoUnknownChapter=\u00a74Unknown chapter. +insufficientFunds=\u00a74Insufficient funds available. +invalidCharge=\u00a74Invalid charge. +invalidFireworkFormat=\u00a74Pasirinkimas \u00a7c{0} \u00a74n\u0117ra galimas \u00a7c{1}\u00a74. +invalidHome=\u00a74Namas\u00a7c {0} \u00a74neegzistuoja\! +invalidHomeName=\u00a74Neteisingas namo pavadinimas\! +invalidMob=Neteisingas tipas. +invalidNumber=Invalid Number. +invalidPotion=\u00a74Invalid Potion. +invalidPotionMeta=\u00a74Invalid potion meta\: \u00a7c{0}\u00a74. +invalidSignLine=\u00a74Line\u00a7c {0} \u00a74on sign is invalid. +invalidWarpName=\u00a74Neteisingas warp pavadinimas\! +invalidWorld=\u00a74Invalid world. +is=is +itemCannotBeSold=\u00a74\u0160is daiktas negali b\u016bti parduotas serveryje. +itemMustBeStacked=\u00a74Daiktas turi buti parduotas po 1 stack. +itemNames=\u00a76Daikt\u0173 trumpi pavadinimai\:\u00a7r {0} +itemNotEnough1=\u00a74Tu neturi pakankamai daiktu pardavimui. +itemNotEnough2=\u00a76Jeigu nor\u0117jai parduoti visus savo \u0161ios r\u016b\u0161ies daiktus, naudok /sell daikto pavadinimas. +itemNotEnough3=\u00a76/sell itemname -1 will sell all but one item, etc. +itemSellAir=Tikrai bandei parduoti or\u0105? Paimk daikt\u0105 \u012f rank\u0105. +itemSold=\u00a7aParduota po \u00a7c{0} \u00a7a({1} {2} uz {3} kiekviena). +itemSoldConsole=\u00a7a{0} \u00a7asold {1} for \u00a7a{2} \u00a7a({3} items at {4} each). +itemSpawn=\u00a76Giving\u00a7c {0} \u00a76of\u00a7c {1} +itemType=\u00a76Item\:\u00a7c {0} \u00a76-\u00a7c {1} +itemsCsvNotLoaded=Nepavyko u\u017ekrauti items.csv\! +jailAlreadyIncarcerated=\u00a74\u017daid\u0117jas jau yra kal\u0117jime\:\u00a7c {0} +jailMessage=\u00a74Padarei nusikaltim\u0105, laikas atpirkti nuod\u0117mes. +jailNotExist=\u00a74\u0160is kal\u0117jimas neegzistuoja. +jailReleased=\u00a76\u017daid\u0117jas \u00a7c{0}\u00a76 buvo i\u0161laisvintas. +jailReleasedPlayerNotify=\u00a76Tu buvai paleistas\! +jailSentenceExtended=\u00a76Kal\u0117jimo laikas prat\u0119stas iki\: {0} +jailSet=\u00a76Kal\u0117jimas\u00a7c {0} \u00a76buvo nustatytas. +jumpError=\u00a74That would hurt your computer''s brain. +kickDefault=Isspirtas is serverio. +kickExempt=\u00a74Tu negali i\u0161mesti \u0161io \u017eaid\u0117jo. +kickedAll=\u00a74Visi \u017eaid\u0117jai buvo i\u0161mesti i\u0161 serverio. +kill=\u00a76Nu\u017eudytas\u00a7c {0}\u00a76. +killExempt=\u00a74Negalite nu\u017eudyti \u017eaid\u0117jo \u00a7c{0}\u00a74. +kitCost=\ \u00a77\u00a7o({0})\u00a7r +kitError2=\u00a74\u0160is rinkinys neegzistuoja. Susisiekite su administracija. +kitError=\u00a74N\u0117ra nei vieno rinkinio. +kitGiveTo=\u00a76Duodamas rinkinys\u00a7c {0}\u00a76 \u017eaid\u0117jui \u00a7c{1}\u00a76. +kitInvFull=\u00a74Tavo inventorius pilnas, rinkinys i\u0161metamas ant grind\u0173. +kitNotFound=\u00a74Toks rinkinys neegzistuoja. +kitOnce=\u00a74Tu negali naudoti \u0161io rinkinio kol kas. +kitReceive=\u00a76Pa\u0117miai\u00a7c {0} rinkin\u012f\u00a76. +kitTimed=\u00a74Tu negali dar naudoti \u0161io rinkinio dar\u00a7c {0}\u00a74. +kits=\u00a76Rinkiniai\:\u00a7r {0} +leatherSyntax=\u00a76Leather Color Syntax\: color\:,, eg\: color\:255,0,0. +lightningSmited=\u00a76Thou hast been smitten\! +lightningUse=\u00a76Smiting\u00a7c {0} +listAfkTag=\u00a77[AFK]\u00a7r +listAmount=\u00a76Dabar yra \u00a7c{0}\u00a76 is \u00a7c{1}\u00a76 zaideju prisijungusiu. +listAmountHidden=\u00a76Dabar yra \u00a7c{0}\u00a76/{1}\u00a76 i\u0161 maksimumo \u00a7c{2}\u00a76 \u017eaid\u0117j\u0173 prisijung\u0119. +listGroupTag=\u00a76{0}\u00a7r\: \u00a7r +listHiddenTag=\u00a77[HIDDEN]\u00a7r +loadWarpError=\u00a74Nepavyko u\u017ekrauti warp {0}. +localFormat=[L]<{0}> {1} +mailClear=\u00a76Norint pa\u017eym\u0117ti lai\u0161kus skaitytais, ra\u0161ykite\u00a7c /mail clear\u00a76. +mailCleared=\u00a76Lai\u0161kai i\u0161valyti\! +mailSent=\u00a76Lai\u0161kas i\u0161si\u0173stas\! +markMailAsRead=\u00a76Norint pa\u017eym\u0117ti lai\u0161kus skaitytais, ra\u0161ykite\u00a7c /mail clear\u00a76. +markedAsAway=\u00a76Tu buvai pa\u017eym\u0117tas, jog esi AFK. +markedAsNotAway=\u00a76Tu buvai pa\u017eym\u0117tas, jog daugiau nebesi AFK. +matchingIPAddress=\u00a76\u0160ie \u017eaid\u0117jai anks\u010diau prisijungti i\u0161 \u0161io IP adreso\: +maxHomes=\u00a74Tu negali nustatyti daugiau nei\u00a7c {0} \u00a74namus. +mayNotJail=\u00a74Tu negali \u012fkalinti \u0161\u012f \u017emog\u0173\! +me=a\u0161 +minute=minut\u0117 +minutes=minut\u0117s +missingItems=\u00a74Tu neturi \u00a7c{0}x {1}\u00a74. +mobSpawnError=\u00a74Klaida kei\u010diant gyv\u016bn\u0173 spawneri. +mobSpawnLimit=Mob quantity limited to server limit. +mobSpawnTarget=\u00a74Privalai \u017ei\u016br\u0117ti \u012f gyv\u016bn\u0173 spawneri. +mobsAvailable=\u00a76Gyv\u016bnai\:\u00a7r {0} +moneyRecievedFrom=\u00a7aGavai{0} i\u0161 {1}. +moneySentTo=\u00a7aNusiuntei{0} \u017eaid\u0117jui\: {1}. +month=m\u0117nesis +months=m\u0117nesiai +moreThanZero=\u00a74Kiekiai turi b\u016bti didesni u\u017e 0. +moveSpeed=\u00a76Nustatytas\u00a7c {0} \u00a76greitis \u00a7c{1} \u00a76\u017eaid\u0117jui \u00a7c{2}\u00a76. +msgFormat=\u00a76[\u00a7c{0}\u00a76 -> \u00a7c{1}\u00a76] \u00a7r{2} +multipleCharges=\u00a74You cannot apply more than one charge to this firework. +multiplePotionEffects=\u00a74You cannot apply more than one effect to this potion. +muteExempt=\u00a74Tu negali u\u017etildyti \u0161io \u017eaid\u0117jo. +muteNotify=\u00a7c{0} \u00a76U\u017etild\u0117 \u00a7c{1}\u00a76. +mutedPlayer=\u00a76\u017daid\u0117jas\u00a7c {0} \u00a76buvo u\u017etildytas. +mutedPlayerFor=\u00a76\u017daid\u0117jas\u00a7c {0} \u00a76buvo u\u017etildytas\u00a7c {1}\u00a76. +mutedUserSpeaks={0} band\u0117 ra\u0161yti, bet yra u\u017etildytas. +nearbyPlayers=\u00a76\u017daid\u0117jai netoliese\:\u00a7r {0} +negativeBalanceError=\u00a74Vartotojas negali tur\u0117ti neigiamo balanso. +nickChanged=\u00a76Slapyvardis pakeistas. +nickDisplayName=\u00a74You have to enable change-displayname in Essentials config. +nickInUse=\u00a74Toks vardas jau naudojamas. +nickNamesAlpha=\u00a74Slapyvardi turi sudaryti tik raid\u0117s arba skaitmenys. +nickNoMore=\u00a76Tu daugiau nebeturi slapyvardzio. +nickSet=\u00a76Tavo slapyvardis dabar yra \u00a7c{0}\u00a76. +nickTooLong=\u00a74\u0160itas slapyvardis yra per ilgas. +noAccessCommand=\u00a74Tu neturi teisi\u0173 \u0161iai komandai. +noAccessPermission=\u00a74J\u016bs neturite leidimo prieiti prie \u00a7c{0}\u00a74. +noBreakBedrock=\u00a74Tu negali sunaikinti bedrock. +noDestroyPermission=\u00a74J\u016bs neturite teis\u0117s sugriauti \u00a7c{0}\u00a74. +noDurability=\u00a74This item does not have a durability. +noGodWorldWarning=\u00a74Warning\! God mode in this world disabled. +noHelpFound=\u00a74No matching commands. +noHomeSetPlayer=\u00a76\u017daid\u0117jas n\u0117ra nusistat\u0119s nam\u0173. +noIgnored=\u00a76Tu nieko neignoruoji. +noKitPermission=\u00a74Tau reikia \u00a7c{0}\u00a74 teis\u0117s, kad naudotum \u0161\u012f rinkin\u012f. +noKits=\u00a76N\u0117ra galim\u0173 rinkini\u0173 dabar. +noMail=\u00a76Tu neturi joki\u0173 lai\u0161k\u0173. +noMatchingPlayers=\u00a76\u017daid\u0117jai nebuvo rasti. +noMetaFirework=\u00a74You do not have permission to apply firework meta. +noMetaPerm=\u00a74You do not have permission to apply \u00a7c{0}\u00a74 meta to this item. +noNewMail=\u00a76Tu neturi nauj\u0173 lai\u0161k\u0173. +noPendingRequest=\u00a74J\u016bs neturite laukian\u010di\u0105 u\u017eklaus\u0105. +noPerm=\u00a74Tu neturi \u00a7c{0}\u00a74 teis\u0117s. +noPermToSpawnMob=\u00a74You don''t have permission to spawn this mob. +noPlacePermission=\u00a74Tu neturi teisi\u0173 pad\u0117ti blokus \u0161alia lentel\u0117s. +noPotionEffectPerm=\u00a74You do not have permission to apply potion effect \u00a7c{0} \u00a74to this potion. +noPowerTools=\u00a76You have no power tools assigned. +noWarpsDefined=\u00a76Jokie warps neegzistuoja. +none=niekas +notAllowedToQuestion=\u00a74J\u016bs nesate \u012fgaliotas naudotis klausim\u0105. +notAllowedToShout=\u00a74You are not authorized to shout. +notEnoughExperience=\u00a74Tu turi per ma\u017eai patirties. +notEnoughMoney=\u00a74Tu neturi pakankamai lesu. +notFlying=neskrendi +notRecommendedBukkit=\u00a74* \! * Bukkit version is not the recommended build for Essentials. +notSupportedYet=Not supported yet. +nothingInHand=Tu nieko neturi savo rankose. +now=dabar +nuke=\u00a75May death rain upon them. +numberRequired=Numeris eina ten. +onlyDayNight=Naudojimas\: /time \u00a72day/night. +onlyPlayerSkulls=\u00a74Savinink\u0105 galite nustatyti tik ant \u017eaid\u0117jo kaukol\u0117s (\u00a7c397\:3\u00a74). +onlyPlayers=\u00a74Turite b\u016bti \u017eaidime, jeigu norite naudoti \u00a7c{0}\u00a74. +onlySunStorm=\u00a74Naudojimas\: /weather \u00a72sun/storm. +orderBalances=\u00a76Ordering balances of\u00a7c {0} \u00a76users, please wait... +oversizedTempban=\u00a74Tu negali u\u017eblokuoti \u017eaid\u0117jo laikinai. +pTimeCurrent=\u00a7c{0}\u00a76''s time is\u00a7c {1}\u00a76. +pTimeCurrentFixed=\u00a7c{0}\u00a76''s time is fixed to\u00a7c {1}\u00a76. +pTimeNormal=\u00a7c{0}\u00a76''s time is normal and matches the server. +pTimeOthersPermission=Tu neturi teisi\u0173 pakeisti kito \u017eaid\u0117jo laiko. +pTimePlayers=\u00a76These players have their own time\:\u00a7r +pTimeReset=\u00a76Player time has been reset for\: \u00a7c{0} +pTimeSet=\u00a76Player time is set to \u00a7c{0}\u00a76 for\: \u00a7c{1}. +pTimeSetFixed=\u00a76Player time is fixed to \u00a7c{0}\u00a76 for\: \u00a7c{1}. +pWeatherCurrent=\u00a7c{0}\u00a76''s weather is\u00a7c {1}\u00a76. +pWeatherInvalidAlias=Neteisingas oro tipas +pWeatherNormal=\u00a7c{0}\u00a76''s weather is normal and matches the server. +pWeatherOthersPermission=\u00a74Tu neturi teisi\u0173 nustatyti kito \u017eaid\u0117jo orus. +pWeatherPlayers=\u00a76These players have their own weather\:\u00a7r +pWeatherReset=\u00a76Player weather has been reset for\: \u00a7c{0} +pWeatherSet=\u00a76Player weather is set to \u00a7c{0}\u00a76 for\: \u00a7c{1}. +pendingTeleportCancelled=\u00a74Teleportacija buvo at\u0161aukta. +playerBanIpAddress=\u00a76Player\u00a7c {0} \u00a76banned IP address\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerBanned=\u00a7c{0} \u00a76u\u017ebanino\u00a7c {1} \u00a76u\u017e \u00a7c{2}\u00a76. +playerInJail=\u00a7c{0}\u00a74 ir taip s\u0117di kaleime. +playerJailed=\u00a76\u017daid\u0117jas\u00a7c {0} \u00a76\u012fkalintas. +playerJailedFor=\u00a76\u017daid\u0117jas\u00a7c {0} \u00a76pasodintas \u012f kal\u0117jim\u0105 u\u017e{1}. +playerKicked=\u00a76\u017daid\u0117jas\u00a7c {0} \u00a76i\u0161mestas {1} u\u017e {2}. +playerMuted=\u00a76Tu buvai u\u017etildytas\! +playerMutedFor=\u00a76Tu buvai u\u017etildytas u\u017e\u00a7c {0}. +playerNeverOnServer=\u00a74\u017daid\u0117jas\u00a7c {0} \u00a74niekada nebuvo prisijung\u0119s prie \u0161io serverio. +playerNotFound=\u00a74\u017daid\u0117jas nerastas. +playerUnbanIpAddress=\u00a76Player\u00a7c {0} \u00a76unbanned IP\: {1}. +playerUnbanned=\u00a76\u017daid\u0117jas\u00a7c {0} \u00a76atblokuotas\u00a7c {1}. +playerUnmuted=\u00a76Tau v\u0117l leista kalb\u0117ti. +pong=Pong\! +posPitch=\u00a76Pitch\: {0} (Head angle) +posX=\u00a76X\: {0} (+East <-> -West) +posY=\u00a76Y\: {0} (+Up <-> -Down) +posYaw=\u00a76Yaw\: {0} (Rotation) +posZ=\u00a76Z\: {0} (+South <-> -North) +possibleWorlds=\u00a76Possible worlds are the numbers \u00a7c0\u00a76 through \u00a7c{0}\u00a76. +potions=\u00a76Aleksyrai\:\u00a7r {0}\u00a76. +powerToolAir=\u00a74Command can''t be attached to air. +powerToolAlreadySet=\u00a74Komanda \u00a7c{0}\u00a74 ir taip priskirta prie \u00a7c{1}\u00a74. +powerToolAttach=\u00a7c{0}\u00a76 command assigned to {1}. +powerToolClearAll=\u00a76All powertool commands have been cleared. +powerToolList=\u00a76Item \u00a7c{1} \u00a76has the following commands\: \u00a7c{0}\u00a76. +powerToolListEmpty=\u00a74Item \u00a7c{0} \u00a74has no commands assigned. +powerToolNoSuchCommandAssigned=\u00a74Komanda \u00a7c{0}\u00a74 n\u0117ra priskirta prie \u00a7c{1}\u00a74. +powerToolRemove=\u00a76Komanda \u00a7c{0}\u00a76 pa\u0161alinta nuo \u00a7c{1}\u00a76. +powerToolRemoveAll=\u00a76Visos komandos pa\u0161alintos nuo \u00a7c{0}\u00a76. +powerToolsDisabled=\u00a76All of your power tools have been disabled. +powerToolsEnabled=\u00a76All of your power tools have been enabled. +questionFormat=\u00a72[Question]\u00a7r {0} +readNextPage=\u00a76Ra\u0161yk\u00a7c /{0} {1} \u00a76norint per\u017ei\u016br\u0117ti kit\u0105 puslap\u012f. +recipe=\u00a76Receptas u\u017e \u00a7c {0} \u00a76(\u00a7c{2} \u00a7c{1}) +recipeBadIndex=There is no recipe by that number. +recipeFurnace=\u00a76Kepti\: \u00a7c{0}\u00a76. +recipeGrid=\u00a7c{0}X \u00a76| \u00a7{1}X \u00a76| \u00a7{2}X +recipeGridItem=\u00a7c{0}X \u00a76yra \u00a7c{1} +recipeMore=\u00a76Rasyk /{0} \u00a7c{1}\u00a76 norint pamatyti receptus \u00a7c{2}\u00a76. +recipeNone=No recipes exist for {0} +recipeNothing=nothing +recipeShapeless=\u00a76Combine \u00a7c{0} +recipeWhere=\u00a76Where\: {0} +removed=\u00a76Removed\u00a7c {0} \u00a76entities. +repair=\u00a76Tu sekmingai pataisei\: \u00a7c{0}. +repairAlreadyFixed=\u00a74Sis daiktas nereikalauja pataisymo. +repairEnchanted=\u00a74Tu neturi teisiu taisyti enchanted daiktu. +repairInvalidType=\u00a74\u0160is daiktas negali b\u016bti pataisytas. +repairNone=\u00a74Tu neturi daiktu, kuriuos reiketu pataisyti. +requestAccepted=\u00a76Teleportacija priimta. +requestAcceptedFrom=\u00a7c{0} \u00a76priem\u0117 tavo teleportacijos pra\u0161ym\u0105. +requestDenied=\u00a76Teleportacijos pra\u0161ymas atmestas. +requestDeniedFrom=\u00a7c{0} \u00a76atmete tavo teleportacijos prasyma. +requestSent=\u00a76Pra\u0161ymas nusi\u0173stas\u00a7c {0}\u00a76. +requestTimedOut=\u00a74Teleportacijos pra\u0161ymas anuliuotas. +requiredBukkit=\u00a76* \! * You need atleast build {0} of CraftBukkit, download it from http\://dl.bukkit.org/downloads/craftbukkit/ +resetBal=\u00a76Balansas buvo nustatytas \u012f \u00a7c{0} \u00a76visiems prisijungusiems \u017eaid\u0117jams. +resetBalAll=\u00a76Balansas buvo nustatytas \u012f \u00a7c{0} \u00a76visiems \u017eaid\u0117jams. +returnPlayerToJailError=\u00a74\u012evyko klaida bandant gra\u017einti \u017eaid\u0117j\u0105\u00a7c {0} \u00a74\u012f kal\u0117jim\u0105 \u00a7c{1}\u00a74\! +runningPlayerMatch=\u00a76Running search for players matching ''\u00a7c{0}\u00a76'' (this could take a little while) +second=sekund\u0117 +seconds=sekund\u0117s +seenOffline=\u00a7c{0} \u00a76yra \u00a74atsijung\u0119s\u00a76 nuo \u00a7c{1}\u00a76. +seenOnline=\u00a7c{0} \u00a76yra \u00a7aprisijung\u0119s\u00a76 nuo \u00a7c{1}\u00a76. +serverFull=Serveris yra pilnas\! +serverTotal=\u00a76Server\u012f i\u0161 viso\:\u00a7c {0} +setBal=\u00a7aTavo balansas buvo nustatytas\: {0}. +setBalOthers=\u00a7aTu nustatei {0}\u00a7a''s balans\u0105 \u012f {1}. +setSpawner=\u00a76Spawnerio tipas buvo pakeistas \u012f\u00a7c {0}\u00a76. +sheepMalformedColor=\u00a74Malformed color. +shoutFormat=\u00a76[Shout]\u00a7r {0} +signFormatFail=\u00a74[{0}] +signFormatSuccess=\u00a71[{0}] +signFormatTemplate=[{0}] +signProtectInvalidLocation=\u00a74Tu negali statyti lentel\u0117s \u010dia. +similarWarpExist=\u00a74A warp with a similar name already exists. +slimeMalformedSize=\u00a74Malformed size. +socialSpy=\u00a76SocialSpy for \u00a7c{0}\u00a76\: \u00a7c{1} +soloMob=\u00a74That mob likes to be alone. +spawnSet=\u00a76Spawn location set for group\u00a7c {0}\u00a76. +spawned=spawned +sudoExempt=\u00a74You cannot sudo this user. +sudoRun=\u00a76Forcing\u00a7c {0} \u00a76to run\:\u00a7r /{1} +suicideMessage=\u00a76Viso \u017eiaurus pasauli... +suicideSuccess=\u00a76{0} \u00a76took their own life. +survival=i\u0161likimas +takenFromAccount=\u00a7a{0} buvo paimta i\u0161 tavo balanso. +takenFromOthersAccount=\u00a7a{0} paimta i\u0161 {1}\u00a7a vartotojo. Naujas balansas\: {2}. +teleportAAll=\u00a76Teleportacijos pra\u0161ymas nusi\u0173stas visiems... +teleportAll=\u00a76Teleportuojami visi \u017eaid\u0117jai... +teleportAtoB=\u00a7c{0}\u00a76 nuteleportavo tave pas \u00a7c{1}\u00a76. +teleportDisabled=\u00a7c{0} \u00a74yra i\u0161jung\u0119s teleportacijas. +teleportHereRequest=\u00a7c{0}\u00a76 pra\u0161o, kad atsiteleportuotum pas juos. +teleportNewPlayerError=\u00a74Nepavyko atiteleportuoti naujo \u017eaid\u0117jo\! +teleportRequest=\u00a7c{0}\u00a76 pra\u0161o, kad gal\u0117tu pas tave atsiteleportuoti. +teleportRequestTimeoutInfo=\u00a76Pra\u0161ymas bus anuliuotas po\u00a7c {0} sekundzi\u0173\u00a76. +teleportTop=\u00a76Teleportuojama \u012f pat\u012f vir\u0161\u0173. +teleportationCommencing=\u00a76Prasideda teleportacija... +teleportationDisabled=\u00a76Teleportacija \u00a7ci\u0161jungta\u00a76. +teleportationDisabledFor=\u00a76Teleportacija \u00a7ci\u0161jungta \u00a76\u017eaid\u0117jui \u00a7c{0}\u00a76. +teleportationEnabled=\u00a76Teleportacija \u00a7c\u012fjungta\u00a76. +teleportationEnabledFor=\u00a76Teleportacija \u00a7c\u012fjungta \u00a76\u017eaid\u0117jui \u00a7c{0}\u00a76. +teleporting=\u00a76Teleportuojama... +teleportToPlayer=\u00a76Teleportuojama pas \u00a7c{0}\u00a76. +tempBanned=\u00a7cYou have been temporarily banned for {0}\:\n\u00a7r{2} +tempbanExempt=\u00a74Tu negali u\u017eblokuoti \u0161io \u017eaid\u0117jo laikinai. +thunder=\u00a76You\u00a7c {0} \u00a76thunder in your world. +thunderDuration=\u00a76You\u00a7c {0} \u00a76thunder in your world for\u00a7c {1} \u00a76seconds. +timeBeforeHeal=\u00a74Laikas iki kito pagydymo\:\u00a7c {0}\u00a76. +timeBeforeTeleport=\u00a74Laikas iki kitos teleportacijos\:\u00a7c {0}\u00a76. +timeFormat=\u00a7c{0}\u00a76 arba \u00a7c{1}\u00a76 arba \u00a7c{2}\u00a76 +timeSetPermission=\u00a74Tu negali nustatyti laiko. +timeWorldCurrent=\u00a76The current time in\u00a7c {0} \u00a76is \u00a7c{1}\u00a76. +timeWorldSet=\u00a76The time was set to\u00a7c {0} \u00a76in\: \u00a7c{1}\u00a76. +totalWorthAll=\u00a7aSold all items and blocks for a total worth of \u00a7c{1}\u00a7a. +totalWorthBlocks=\u00a7aSold all blocks for a total worth of \u00a7c{1}\u00a7a. +tps=\u00a76Current TPS \= {0} +tradeSignEmpty=\u00a74The trade sign has nothing available for you. +tradeSignEmptyOwner=\u00a74There is nothing to collect from this trade sign. +treeFailure=\u00a74Tree generation failure. Try again on grass or dirt. +treeSpawned=\u00a76Tree spawned. +true=\u00a7atrue\u00a7r +typeTpaccept=\u00a76Norint priimti teleportacija, ra\u0161ykit \u00a7c/tpaccept\u00a76. +typeTpdeny=\u00a76Norint atmesti teleportacija, ra\u0161ykit \u00a7c/tpdeny\u00a76. +typeWorldName=\u00a76You can also type the name of a specific world. +unableToSpawnMob=\u00a74Unable to spawn mob. +unignorePlayer=\u00a76Tu daugiau nebeignoruoji\u00a7c {0} \u00a76\u017eaid\u0117jo. +unknownItemId=\u00a74Ne\u017einomas daikto ID\:\u00a7r {0}\u00a74. +unknownItemInList=\u00a74Ne\u017einomas daiktas {0} {1} s\u0105ra\u0161e. +unknownItemName=\u00a74Ne\u017einomas daikto pavadinimas\: {0}. +unlimitedItemPermission=\u00a74Neturite teis\u0117s neribotam kiekiui \u00a7c{0}\u00a74. +unlimitedItems=\u00a76Unlimited items\:\u00a7r +unmutedPlayer=\u00a76\u017daid\u0117jui\u00a7c {0} \u00a76v\u0117l leista ra\u0161yti. +unvanishedReload=\u00a74A reload has forced you to become visible. +upgradingFilesError=Error while upgrading the files. +uptime=\u00a76Uptime\:\u00a7c {0} +userAFK=\u00a77{0} \u00a75is currently AFK and may not respond. +userDoesNotExist=\u00a74The user\u00a7c {0} \u00a74does not exist. +userIsAway=\u00a77* {0} \u00a77dabar yra AFK r\u0117\u017eime. +userIsNotAway=\u00a77* {0} \u00a77nebera AFK r\u0117\u017eime. +userJailed=\u00a76Tu buvai \u012fkalintas\! +userUnknown=\u00a74Warning\: The user ''\u00a7c{0}\u00a74'' has never joined this server. +userdataMoveBackError=Failed to move userdata/{0}.tmp to userdata/{1}\! +userdataMoveError=Failed to move userdata/{0} to userdata/{1}.tmp\! +usingTempFolderForTesting=Using temp folder for testing\: +vanished=\u00a76You are now completely invisible to normal users, and hidden from in-game commands. +versionMismatch=\u00a74Version mismatch\! Please update {0} to the same version. +versionMismatchAll=\u00a74Version mismatch\! Please update all Essentials jars to the same version. +voiceSilenced=\u00a76Tu buvai u\u017etildytas\! +walking=walking +warpDeleteError=\u00a74Problem deleting the warp file. +warpList={0} +warpListPermission=\u00a74You do not have Permission to list warps. +warpNotExist=\u00a74Toks warp neegzistuoja. +warpOverwrite=\u00a74You cannot overwrite that warp. +warpSet=\u00a76Warp\u00a7c {0} \u00a76nustatytas. +warpUsePermission=\u00a74Tu neturi teis\u0117s naudotis \u0161iuo warp. +warpingTo=\u00a76Permet\u0105 \u012f\u00a7c {0}\u00a76. +warps=\u00a76Warps\:\u00a7r {0} +warpsCount=\u00a76Yra\u00a7c {0} \u00a76teleport\u0173. Rodomas puslapis \u00a7c{1} \u00a76i\u0161 \u00a7c{2}\u00a76. +weatherStorm=\u00a76Tu nustatei or\u0105 \u012f \u00a7cstorm\u00a76, pasaulyje\:\u00a7c {0}\u00a76. +weatherStormFor=\u00a76You set the weather to \u00a7cstorm\u00a76 in\u00a7c {0} \u00a76for {1} seconds. +weatherSun=\u00a76Tu nustatei or\u0105 \u012f \u00a7csun\u00a76, pasaulyje\:\u00a7c {0}\u00a76. +weatherSunFor=\u00a76You set the weather to \u00a7csun\u00a76 in\u00a7c {0} \u00a76for {1} seconds. +whoisAFK=\u00a76 - AFK\:\u00a7r {0} +whoisBanned=\u00a76 - U\u017eblokuotas\:\u00a7r {0} +whoisExp=\u00a76 - Exp\:\u00a7r {0} (Level {1}) +whoisFly=\u00a76 - Fly r\u0117\u017eimas\:\u00a7r {0} ({1}) +whoisGamemode=\u00a76 - \u017daidimo r\u0117\u017eimas\:\u00a7r {0} +whoisGeoLocation=\u00a76 - Vieta\:\u00a7r {0} +whoisGod=\u00a76 - Dievo r\u0117\u017eimas\:\u00a7r {0} +whoisHealth=\u00a76 - Gyvyb\u0117s\:\u00a7r {0}/20 +whoisIPAddress=\u00a76 - IP Adresas\:\u00a7r {0} +whoisJail=\u00a76 - Kal\u0117jimas\:\u00a7r {0} +whoisLocation=\u00a76 - Vieta\:\u00a7r ({0}, {1}, {2}, {3}) +whoisMoney=\u00a76 - Balansas\:\u00a7r {0} +whoisMuted=\u00a76 - U\u017etildytas\:\u00a7r {0} +whoisNick=\u00a76 - Slapyvardis\: \u00a7r {0} +whoisOp=\u00a76 - OP\:\u00a7r {0} +whoisTop=\u00a76 \=\=\=\=\=\= WhoIs\:\u00a7c {0} \u00a76\=\=\=\=\=\= +worth=\u00a7aStack of {0} worth \u00a7c{1}\u00a7a ({2} item(s) at {3} each) +worthMeta=\u00a7aStack of {0} with metadata of {1} worth \u00a7c{2}\u00a7a ({3} item(s) at {4} each) +worthSet=\u00a76Worth value set +year=metai +years=metus +youAreHealed=\u00a76Tu buvai pagydytas. +youHaveNewMail=\u00a76Tu turi\u00a7c {0} \u00a76prane\u0161im\u0173\! Ra\u0161yk \u00a7c/mail read\u00a76, kad per\u017ei\u016br\u0117tum lai\u0161kus. +whoisHunger=\u00a76 - Hunger\:\u00a7r {0}/20 (+{1} saturation) +kitDelay=\u00a7m{0}\u00a7r +giveSpawnFailure=\u00a74Not enough space, \u00a7c{0} \u00a7c{1} \u00a74was lost. +noKitGroup=\u00a74Tu neturi teisi\u0173 \u0161iam rinkiniui. +inventoryClearingFromAll=\u00a76Clearing the inventory of all users... +inventoryClearingAllItems=\u00a76Cleared all inventory items from {0}\u00a76. +inventoryClearingAllArmor=\u00a76Cleared all inventory items and armor from {0}\u00a76.\u00a0 +inventoryClearingAllStack=\u00a76Cleared all\u00a7c {0} \u00a76from {1}\u00a76. +inventoryClearingStack=\u00a76Removed\u00a7c {0} \u00a76of\u00a7c {1} \u00a76from {2}\u00a76. +inventoryClearFail=\u00a74Player {0} \u00a74does not have\u00a7c {1} \u00a74of\u00a7c {2}\u00a74. +localNoOne= +totalSellableAll=\u00a7aVis\u0173 \u0161iu parduodam\u0173 daikt\u0173 vert\u0117 yra \u00a7c{1}\u00a7a. +totalSellableBlocks=\u00a7aVis\u0173 \u0161i\u0173 parduodam\u0173 blok\u0173 vert\u0117 yra \u00a7c{1}\u00a7a. +radiusTooBig=\u00a74Radius is too big\! Maximum radius is {0}. +isIpBanned=\u00a76IP \u00a7c{0} \u00a76yra u\u017eblokuotas. +mobDataList=\u00a76Valid mob data\:\u00a7r {0} +vanish=\u00a76Vanish for {0}\u00a76\: {1} +noLocationFound=\u00a74No valid location found. +coordsKeyword={0}, {1}, {2} +banExemptOffline=\u00a74Tu negali u\u017eblokuoti neprisijungusi\u0173 \u017eaid\u0117j\u0173. +tempbanExemptOffline=\u00a74Tu negali u\u017eblokuoti laikinai neprisijungusi\u0173 \u017eaid\u0117j\u0173. +mayNotJailOffline=\u00a74Tu negali pasodinti \u012f kal\u0117jim\u0105 neprisijungusi\u0173 \u017eaid\u0117j\u0173. +muteExemptOffline=\u00a74Tu negali u\u017etildyti neprisijungusi\u0173 \u017eaid\u0117j\u0173. +ignoreExempt=\u00a74Tu negali ignoruoti \u0161io \u017eaid\u0117jo. +unsafeTeleportDestination=Teleportavimasis yra nesaugus ir teleport-safety yra i\u0161jungtas. +noMetaJson=JSON Metadata nera palaikoma sioje Bukkit serverio versijoje. +maxMoney=Cant translate +skullChanged=\u00a76Galva pakeista \u012f \u017eaid\u0117jo \u00a7c{0}\u00a76 galv\u0105. +alphaNames=\u017daid\u0117j\u0173 vardai gali b\u016bti tik raidiniai, skaitiniai. +givenSkull=Tu gavai \u00a7c{0}\u00a76 galv\u0105. +noPermissionSkull=Tu neturi teisi\u0173 redaguoti \u0161i\u0105 galv\u0105. +teleportInvalidLocation=Koordina\u010di\u0173 reik\u0161m\u0117 negali b\u016bti daugiau nei 30000000 +invalidSkull=\u00a74Pra\u0161ome laikyti \u017eaid\u0117jo galv\u0105. +weatherInvalidWorld=Pasaulio, pavadinimu {0} nerasta\! +gameModeInvalid=\u00a74Tau reikia nurodyti galiojant\u012f \u017eaid\u0117j\u0105/re\u017eim\u0105. +mailTooLong=\u00a74Pa\u0161to \u017einut\u0117 per ilga. Stenkit\u0117s nevir\u0161yti 1000 simboli\u0173. +mailDelay=Per daug lai\u0161k\u0173 buvo i\u0161si\u0173stos per paskutin\u0119 minut\u0119. Did\u017eiausias\: {0} +seenAccounts=\u00a76\u017daid\u0117jas dar kitaip \u017einomas kaip\:\u00a7c {0} +unableToSpawnItem=\u00a74Negalima pasiimti \u00a7c{0}\u00a74, \u0161is daiktas \u012fra\u0161ytas \u012f juodaj\u012f s\u0105ra\u0161\u0105. +itemsConverted=\u00a76Converted all items into blocks. +itemsNotConverted=\u00a74You have no items that can be converted into blocks. +mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\: +mailMessage={0} + +whoisTempBanned=\u00a76 - Ban expires:\u00a7r {0} +playerTempBanned=\u00a76Player \u00a7c{0}\u00a76 temporarily banned \u00a7c{1}\u00a76 for \u00a7c{2}\u00a76: \u00a7c{3}\u00a76. +mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1} diff --git a/Essentials/src/messages_nl.properties b/Essentials/src/messages_nl.properties new file mode 100644 index 0000000000..51c3c6936c --- /dev/null +++ b/Essentials/src/messages_nl.properties @@ -0,0 +1,558 @@ +#X-Generator: crowdin.net +#version: TeamCity +# Single quotes have to be doubled: '' +# Translations start here +# by: +action=\u00a75* {0} \u00a75{1} +addedToAccount=\u00a7a{0} is gestort op uw rekening. +addedToOthersAccount=\u00a7a{0} toegevoegd aan {1}\u00a7a zijn rekening. Nieuw saldo\: {2} +adventure=avontuur +alertBroke=gebroken\: +alertFormat=\u00a73[{0}] \u00a7f {1} \u00a76 {2} bij\: {3} +alertPlaced=geplaatst\: +alertUsed=gebruikt\: +antiBuildBreak=\u00a74U heeft geen toestemming om {0} blokken breken. +antiBuildCraft=\u00a74U mag hier geen\u00a7c {0} \u00a74maken. +antiBuildDrop=\u00a74U mag hier geen\u00a7c {0} \u00a74laten vallen. +antiBuildInteract=\u00a74U mag geen {0} gebruiken. +antiBuildPlace=\u00a74U mag hier geen {0} plaatsen. +antiBuildUse=\u00a74U mag geen\u00a7c {0}\u00a74 gebruiken. +autoAfkKickReason=U bent van de server afgeschopt omdat u niets hebt gedaan voor meer dan {0} minuten. +backAfterDeath=\u00a76Gebruik het /back commando om terug te keren naar uw sterfplaats. +backUsageMsg=\u00a77Naar Uw vorige locatie aan het gaan. +backupDisabled=Een extern backup script is niet geconfigureerd. +backupFinished=Backup voltooid. +backupStarted=Backup gestart. +balance=\u00a77Saldo\: {0} +balanceOther=\u00a7aSaldo van {0}\u00a7a\:\u00a7c {1} +balanceTop=\u00a77 Top saldo ({0}) +banExempt=\u00a77U kunt deze speler niet verbannen. +banFormat=Verbannen\: {0} +bed=\u00a7obed\u00a7r +bedMissing=\u00a74Uw bed is niet ingesteld, ontbreekt of is geblokkeerd. +bedNull=\u00a7mbed\u00a7r +bedSet=\u00a76Bed spawn ingesteld\! +bigTreeFailure=\u00a7cMaken van een grote boom is mislukt. Probeer het opnieuw op gras of dirt. +bigTreeSuccess=\u00a77Grote boom gemaakt. +blockList=\u00a76Essentials heeft de volgende commandos doorgegeven naar een andere plugin\: +bookAuthorSet=\u00a76Auteur van het boek is veranderd naar\: {0} +bookLocked=\u00a7cDit boek is nu vergrendeld. +bookTitleSet=\u00a76Titel van het boek is veranderd naar\: {0} +broadcast=\u00a7r\u00a76[\u00a74Omroep\u00a76]\u00a7a {0} +buildAlert=\u00a7cU bent niet bevoegd om te bouwen. +bukkitFormatChanged=Bukkit versie formaat veranderd. Versie niet nagekeken. +burnMsg=\u00a77Je hebt {0} voor {1} seconde(n) in brand gezet. +canTalkAgain=\u00a77U kunt weer praten. +cannotStackMob=\u00a74U heeft geen toestemming om meerdere mobs op elkaar te stapelen. +cantFindGeoIpDB=De GeoIP database kon niet gevonden worden\! +cantReadGeoIpDB=Fout bij het lezen van de GeoIP database\! +cantSpawnItem=\u00a7cU bent niet bevoegd om {0} te spawnen. +chatTypeAdmin=[A] +chatTypeLocal=[L] +chatTypeSpy=[Spion] +cleaned=Gebruikersbestanden opgeschoont. +cleaning=Opschonen van gebruikersbestanden. +commandFailed=Opdracht {0} is mislukt\: +commandHelpFailedForPlugin=Fout bij het verkrijgen van hulp voor\: {0}. +commandNotLoaded=\u00a7cOpdracht {0} is fout geladen. +compassBearing=\u00a77Ligging\: {0} ({1} graden). +configFileMoveError=Het verplaatsen van config.yml naar de backup locatie is mislukt. +configFileRenameError=Fout bij het hernoemen van de tijdelijke map naar config.yml +connectedPlayers=\u00a76Spelers online\u00a7r +connectionFailed=Fout bij het verbinden. +cooldownWithMessage=\u00a7cAfkoeltijd\: {0} +corruptNodeInConfig=\u00a74Waarschuwing\: Uw configuratiebestand bevat een fout {0}. +couldNotFindTemplate=Het sjabloon kon niet worden gevonden {0}. +creatingConfigFromTemplate=Bezig met aanmaken van een config vanaf sjabloon\: {0} +creatingEmptyConfig=Bezig met het aanmaken van een lege configuratie\: {0} +creative=creatief +currency={0}{1} +currentWorld=Huidige Wereld\: {0} +day=dag +days=dagen +defaultBanReason=De Ban Hamer heeft gesproken\! +deleteFileError=Het bestand kon niet verwijderd worden\: {0} +deleteHome=\u00a77Huis {0} is verwijderd. +deleteJail=\u00a77Gevangenis {0} is verwijderd. +deleteWarp=\u00a77Warp {0} is verwijderd. +deniedAccessCommand={0} was de toegang verboden tot het commando. +denyBookEdit=\u00a74U kunt dit boek niet ontgrendelen. +denyChangeAuthor=\u00a74U kunt de auteur van dit boek niet aanpassen. +denyChangeTitle=\u00a74U kunt de titel van dit boek niet aanpassen +depth=\u00a76U zit op zeeniveau. +depthAboveSea=\u00a76U zit {0} blok(ken) boven zeeniveau. +depthBelowSea=\u00a76U zit {0} blok(ken) onder zeeniveau. +destinationNotSet=Bestemming niet ingesteld. +disableUnlimited=\u00a77Oneindig plaatsen van {0} uitgeschakeld voor {1}. +disabled=uitgeschakeld +disabledToSpawnMob=Het spawnen van mobs is uitgeschakeld in het configuratie bestand. +distance=\u00a76Afstand\: {0} +dontMoveMessage=\u00a77Beginnen met teleporteren over {0}. Niet bewegen. +downloadingGeoIp=Bezig met downloaden van GeoIP database ... Dit kan een tijdje duren (country\: 0.6 MB, city\: 20MB) +duplicatedUserdata=Dubbele gebruikersdata\: {0} en {1}. +durability=\u00a77Dit gereedschap kan nog \u00a7c{0}\u00a77 gebruikt worden. +editBookContents=\u00a7eU kunt nu de inhoud van dit boek aanpassen. +enableUnlimited=\u00a76Oneindig \u00a7c {0} \u00a76gegeven aan \u00a7c{1}\u00a76. +enabled=ingeschakeld +enchantmentApplied=\u00a76De enchantment\u00a7c {0}\u00a76 is toegepast aan het voorwerp in je hand. +enchantmentNotFound=\u00a74Betovering niet gevonden\! +enchantmentPerm=\u00a7cU heeft geen toestemming voor {0}. +enchantmentRemoved=\u00a76De betovering {0} is verwijderd van het voorwerp in uw hand. +enchantments=\u00a76Betoveringen\:\u00a7r {0} +errorCallingCommand=Fout bij het aanroepen van het commando /{0} +errorWithMessage=\u00a7cFout\:\u00a74 {0} +essentialsHelp1=Het bestand is beschadigd en Essentials kan het niet openenen. Essentials is nu uitgeschakeld. Als u dit probleem niet zelf kunt oplossen ga dan naar http\://tiny.cc/EssentialsChat +essentialsHelp2=Het bestand is beschadigd en Essentials kan het niet openenen. Essentials is nu uitgeschakeld. Als u dit probleem niet zelf kun oplossen ga dan naar http\://tiny.cc/EssentialsChat of typ /essentialshelp in het spel. +essentialsReload=\u00a76Essentials is herladen\u00a7c {0}. +exp=\u00a7c{0} \u00a76heeft\u00a7c {1} \u00a76exp (level\u00a7c {2}\u00a76) en heeft nog\u00a7c {3} \u00a76exp meer nodig om een level hoger te gaan. +expSet=\u00a7c{0} \u00a76heeft nu\u00a7c {1} \u00a76exp. +extinguish=\u00a76U heeft uzelf geblust. +extinguishOthers=\u00a76Je hebt {0}\u00a76 geblust. +failedToCloseConfig=Fout bij het sluiten van configuratie {0} +failedToCreateConfig=Fout tijdens het aanmaken van configuratie {0} +failedToWriteConfig=Fout bij het cre\u00ebren van configuratie {0} +false=\u00a74Onjuist\u00a7r +feed=\u00a77Je honger is verzadigd. +feedOther=U heeft de honger van {0} verzadigd. +fileRenameError=Hernoemen van {0} mislukt +fireworkColor=\u00a74U moet een kleur aan het vuurwerk geven om een effect toe te voegen. +fireworkEffectsCleared=\u00a76Alle effecten zijn van de vastgehouden stapel verwijderd. +fireworkSyntax=\u00a76Firework parameters\:\u00a7c color\: [fade\:] [shape\:] [effect\:]\n\u00a76Om meerdere kleuren/effecten toe te voegen, scheid de waarden met komma''s\: \u00a7cred,blue,pink\n\u00a76Shapes\:\u00a7c star, ball, large, creeper, burst \u00a76Effects\:\u00a7c trail, twinkle. +flyMode=\u00a77Zet vliegen {0} voor {1}. +flying=vliegen +foreverAlone=\u00a7cU heeft niemand naar wie u kan reageren. +fullStack=\u00a74U heeft al een volledige stapel. +gameMode=De gamemodus van {1} is veranderd naar {0}. +gcWorld=\u00a76 {0} "\u00a7c {1} \u00a76"\: \u00a7c {2} \u00a76 chunks, \u00a7c {3} \u00a76 entiteiten, \u00a7c {4} \u00a76 tiles. +gcfree=Vrij geheugen\: {0} MB +gcmax=Maximaal geheugen\: {0} MB +gctotal=Toegewezen geheugen\: {0} MB +geoIpUrlEmpty=GeoIP download url is leeg. +geoIpUrlInvalid=GeoIP download url is ongeldig. +geoipJoinFormat=\u00a76Speler \u00a7c{0} \u00a76komt uit \u00a7c{1}\u00a76. +giveSpawn=\u00a7c {0} {1} \u00a76gegeven aan \u00a7c{2}\u00a76. +godDisabledFor=\u00a7cuitgezet\u00a76 voor\u00a7c {0}\n +godEnabledFor=\u00a7aingeschakeld\u00a76 voor\u00a7c {0}. +godMode=\u00a76God modus\u00a7c {0}\u00a76. +groupDoesNotExist=\u00a74Er is niemand on-line in deze groep\! +groupNumber=\u00a7c{0}\u00a7f online, voor de volledige lijst type\u00a7c /{1} {2} +hatArmor=\u00a74Fout, u kunt dit voorwerp niet als hoed gebruiken\! +hatEmpty=\u00a74Je draagt geen hoed. +hatFail=\u00a74Je hebt iets nodig om te dragen als hoed. +hatPlaced=\u00a76Veel plezier met je nieuwe hoed\! +hatRemoved=\u00a76Uw hoed is verwijderd. +haveBeenReleased=\u00a76U bent vrijgelaten. +heal=\u00a76U bent genezen. +healDead=\u00a74U kunt niet iemand genezen die dood is\! +healOther=\u00a76U heeft\u00a7c {0}\u00a76 genezen. +helpConsole=typ ''?'' om de commands voor de console te zien. +helpFrom=\u00a76Commando''s van {0}\: +helpLine=\u00a76/{0}\u00a7r\: {1} +helpMatching=\u00a76Commandos die overeenkomen met "{0}"\: +helpOp=\u00a74[HelpOp]\u00a7r \u00a76{0}\:\u00a7r {1} +helpPlugin=\u00a74{0}\u00a7r\: Plugin Hulp\: /help {1} +holdBook=\u00a74U houdt geen beschrijfbaar boek vast. +holdFirework=\u00a74U moet vuurwerk vasthouden om een effect toe te voegen. +holdPotion=\u00a74U moet een toverdrank vast houden om er een effect aan toe te voegen. +holeInFloor=\u00a74Gat in de vloer\! +homeSet=\u00a76Home ingesteld. +homes=\u00a76Homes\:\u00a7r {0} +hour=uur +hours=uren +ignoredList=\u00a76Genegeerd\:\u00a7r {0} +ignorePlayer=\u00a76Vanaf nu negeert u \u00a7c{0}\u00a76. +illegalDate=Illegaal data formaat. +infoChapter=\u00a76Selecteer hoofdstuk\: +infoChapterPages=\u00a7e ---- \u00a76{0} \u00a7e--\u00a76 Pagina \u00a7c{1}\u00a76 van de \u00a7c{2} \u00a7e---- +infoPages=\u00a7e ---- \u00a76{2} \u00a7e--\u00a76 Pagina \u00a74{0}\u00a76/\u00a74{1} \u00a7e---- +infoUnknownChapter=\u00a74Onbekend hoofdstuk. +insufficientFunds=\u00a74Saldo niet toereikend. +invalidCharge=\u00a7cOngeldige prijs. +invalidFireworkFormat=\u00a74De optie \u00a7c{0} \u00a74is geen geldige waarde \u00a7c{1}\u00a74.\n +invalidHome=Home {0} Bestaat niet. +invalidHomeName=\u00a74Ongeldige home naam. +invalidMob=\u00a74Ongeldig mob type. +invalidNumber=Ongeldig Nummer. +invalidPotion=\u00a74Ongeldige Toverdrank. +invalidPotionMeta=\u00a74Ongeldige toverdrank meta\: \u00a7c{0}\u00a74. +invalidSignLine=Regel {0} op het bordje is ongeldig. +invalidWarpName=\u00a74Ongeldige warp naam. +invalidWorld=\u00a7cOngeldige wereld. +is=is +itemCannotBeSold=Dat voorwerp kan niet aan de server worden verkocht. +itemMustBeStacked=Voorwerp moet geruild worden als stapel. Een hoeveelheid van 2 moet dus geruild worden als twee stapels, etc. +itemNames=Kortere namen voor het item\: {0} +itemNotEnough1=\u00a74Je hebt niet genoeg van die voorwerpen om te verkopen. +itemNotEnough2=\u00a76Type /sell itemnaam Als u alle voorwerpen van die soort wilt verkopen. +itemNotEnough3=\u00a77/sell itemname -1 zorgt ervoor dat ze allemaal behalve 1 worden verkocht, etc. +itemSellAir=U wilde serieus lucht verkopen? Plaats een voorwerp in uw hand. +itemSold=\u00a77Verkocht voor \u00a7c{0} \u00a77({1} {2} voorwerpen voor {3} per stuk) +itemSoldConsole={0} verkocht {1} voor \u00a77{2} \u00a77({3} voorwerpen voor {4} per stuk) +itemSpawn=\u00a77Geeft {0} {1} +itemType=\u00a76Voorwerp\:\u00a7c {0} \u00a76-\u00a7c {1} +itemsCsvNotLoaded=Kon items.csv niet laden\! +jailAlreadyIncarcerated=\u00a74Deze persoon zit al in de gevangenis\:\u00a7c {0} +jailMessage=\u00a74U begaat een misdrijf, U zit uw tijd uit. +jailNotExist=\u00a74Die gevangenis bestaat niet. +jailReleased=\u00a76Speler \u00a7c{0}\u00a76 vrijgelaten. +jailReleasedPlayerNotify=\u00a76U bent vrijgelaten\! +jailSentenceExtended=\u00a76Gevangenistijd verlengt tot\: {0} +jailSet=\u00a76Gevangenis\u00a7c {0}\u00a76 is ingesteld. +jumpError=\u00a74Dat zal uw computer hoofdpijn geven. +kickDefault=U bent van de server afgeschopt. +kickExempt=\u00a74U kunt die speler niet van de server afschoppen. +kickedAll=\u00a74Alle spelers van de server afgeschopt. +kill=\u00a76U vermoorde\u00a7c {0}\u00a76. +killExempt=\u00a74Je kan niet vermoorden\u00a7c{0}\u00a74.\n +kitCost=\ \u00a77\u00a7o({0})\u00a7r +kitError2=\u00a74Die kit is niet goed ingesteld. Neem contact op met een administrator. +kitError=\u00a74Er zijn geen geldige kits. +kitGiveTo=\u00a76Geeft kit\u00a7c {0}\u00a76 aan \u00a7c{1}\u00a76.\n +kitInvFull=\u00a74Uw inventaris was vol, de kit wordt op de grond geplaatst. +kitNotFound=\u00a74Deze kit bestaat niet. +kitOnce=\u00a74U kunt deze kit niet opnieuw gebruiken. +kitReceive=\u00a76kit\u00a7c {0}\u00a76 ontvangen. +kitTimed=\u00a74U kunt die kit pas weer gebruiken over\u00a7c {0}\u00a74. +kits=\u00a76Kits\:\u00a7r {0} +leatherSyntax=\u00a76Leer Kleur Syntaxis\: color\:,, eg\: color\:255,0,0. +lightningSmited=\u00a76Gij zijt getroffen\! +lightningUse=\u00a7c{0}\u00a76 wordt getroffen door bliksem. +listAfkTag=\u00a77[AFK]\u00a7f +listAmount=\u00a76Er zijn \u00a7c{0}\u00a76 van het maximum \u00a7c{1}\u00a76 spelers online. +listAmountHidden=\u00a76Er zijn \u00a7c{0}\u00a76/{1}\u00a76 van het maximum \u00a7c{2}\u00a76 spelers online. +listGroupTag=\u00a76{0} \u00a7r\: \u00a7r +listHiddenTag=\u00a77[VERBORGEN]\u00a7f +loadWarpError=\u00a74Fout bij het laden van warp {0}. +localFormat=[L]<{0}> {1} +mailClear=\u00a76Om je mail te markeren als gelezen, typ\u00a7c /mail clear\u00a76.\n +mailCleared=\u00a76Berichten verwijderd\! +mailSent=\u00a76Bericht verzonden\! +markMailAsRead=\u00a76Om je mail te markeren als gelezen, typ\u00a7c /mail clear\u00a76.\n +markedAsAway=\u00a76U staat nu als afwezig gemarkeerd. +markedAsNotAway=\u00a76U staat niet meer als afwezig gemarkeerd. +matchingIPAddress=\u00a76De volgende spelers logden eerder in op dat IP adres\: +maxHomes=\u00a74U kunt niet meer dan\u00a7c {0}\u00a74 huizen zetten. +mayNotJail=\u00a7cU mag die speler niet in de gevangenis zetten. +me=ik +minute=minuut +minutes=minuten +missingItems=\u00a74Je hebt geen\u00a7c{0}x {1}\u00a74.\n +mobSpawnError=\u00a74Fout bij het veranderen van de mob spawner. +mobSpawnLimit=De hoeveelheid mobs zijn gelimiteerd door de server limiet. +mobSpawnTarget=\u00a74Doelblok moet een mob spawner zijn. +mobsAvailable=\u00a76Mobs\:\u00a7r {0} +moneyRecievedFrom=\u00a7a{0} is ontvangen van {1}. +moneySentTo=\u00a7a{0} is verzonden naar {1}. +month=maand +months=maanden +moreThanZero=\u00a74Het aantal moet groter zijn dan 0. +moveSpeed=\u00a76Verander {0} snelheid naar\u00a7c {1} \u00a76voor \u00a7c{2}\u00a76.\n +msgFormat=\u00a76[\u00a7c{0}\u00a76 -> \u00a7c{1}\u00a76] \u00a7r{2} +multipleCharges=\u00a74U kunt niet meer dan \u00e9\u00e9n lading aan dit vuurwerk toevoegen. +multiplePotionEffects=\u00a74U kunt niet meer dan \u00e9\u00e9n effect aan dit toverdrankje toevoegen. +muteExempt=\u00a74U kunt deze speler niet dempen. +muteNotify=\u00a7c{0} \u00a76heeft \u00a7c{1} \u00a76gedempt. +mutedPlayer=\u00a76Speler\u00a7c {0} \u00a76gedempt. +mutedPlayerFor=\u00a76Speler\u00a7c {0} \u00a76is gedempt gedurende\u00a7c {1}\u00a76. +mutedUserSpeaks={0} probeerde te praten, maar is gedempt. +nearbyPlayers=\u00a76Spelers dichtbij\:\u00a7r {0} +negativeBalanceError=Het is voor deze gebruiker niet toegestaan om een negatief saldo te hebben. +nickChanged=Bijnaam veranderd. +nickDisplayName=\u00a74U moet ''change-displayname'' inschakelen in de Essentials configuratie. +nickInUse=\u00a7cDie naam is al in gebruik. +nickNamesAlpha=\u00a7cBijnamen moeten alfanumeriek zijn. +nickNoMore=\u00a76U heeft geen bijnaam meer. +nickSet=\u00a76Jou bijnaam is nu \u00a7c{0}\u00a76.\n +nickTooLong=\u00a74Die bijnaam is te lang. +noAccessCommand=\u00a74U heeft geen toegang tot dat commando. +noAccessPermission=\u00a74Je hebt geen toestemming om dat te openen \u00a7c{0}\u00a74.\n +noBreakBedrock=\u00a74U heeft geen toestemming om bodemgesteente te breken. +noDestroyPermission=&4Je hebt geen permissie om dat &c{0}&4 te slopen. +noDurability=\u00a7cDit voorwerp heeft geen levensduur. +noGodWorldWarning=\u00a7cWaarschuwing\! God modus is uitgeschakeld in deze wereld. +noHelpFound=\u00a7cGeen overeenkomende commandos. +noHomeSetPlayer=Speler heeft geen home. +noIgnored=\u00a76U negeert niemand. +noKitPermission=\u00a74U heeft de \u00a7c{0}\u00a74 toestemming nodig om die kit te gebruiken. +noKits=\u00a77Er zijn nog geen kits beschikbaar. +noMail=\u00a76U heeft geen berichten. +noMatchingPlayers=\u00a76Geen matchende spelers gevonden. +noMetaFirework=\u00a74U heeft geen toestemming om vuurwerk meta toe te passen. +noMetaPerm=\u00a74U heeft geen toestemming om de \u00a7c{0}\u00a74 meta toe te passen op dit item. +noNewMail=\u00a77U heeft geen nieuwe berichten. +noPendingRequest=\u00a74U heeft geen afwachtende aanvragen. +noPerm=\u00a74U heeft de \u00a7c{0}\u00a74 toestemming niet. +noPermToSpawnMob=\u00a74U heeft geen toestemming om deze mob te spawnen. +noPlacePermission=\u00a74U heeft geen toestemming om een blok naast dat bord te plaatsen. +noPotionEffectPerm=\u00a74U heeft geen toestemming om het \u00a7c{0} \u00a74effect aan deze toverdrank toe te voegen. +noPowerTools=\u00a76U heeft geen powertools toegewezen. +noWarpsDefined=Geen warps gedefinieerd +none=geen +notAllowedToQuestion=\u00a74U bent niet bevoegd om de vraag functie te gebruiken. +notAllowedToShout=\u00a74U bent niet bevoegd om de roep functie te gebruiken. +notEnoughExperience=\u00a74U heeft niet genoeg experience. +notEnoughMoney=\u00a74U heeft niet genoeg geld. +notFlying=Niet aan het vliegen. +notRecommendedBukkit=* \! * De Bukkit versie is niet de aangeraden build voor Essentials. +notSupportedYet=Nog niet ondersteund. +nothingInHand=\u00a74U heeft niets in uw hand. +now=nu +nuke=\u00a75Moge de dood op hen neerregenen. +numberRequired=Daar moet een nummer, gekkie. +onlyDayNight=/time ondersteund alleen day/night. +onlyPlayerSkulls=&4Je kan alleen de Eigenaar van een hoofd Zetten\! +onlyPlayers=&4Alleen ingame spelers kunnen &c{0}&4 gebruiken. +onlySunStorm=\u00a74/weather ondersteunt alleen sun/storm. +orderBalances=\u00a76Saldo''s bestellen van\u00a7c {0} \u00a76gebruikers, een moment geduld alstublieft... +oversizedTempban=\u00a74U kunt een speler niet verbannen voor deze lange period van tijd. +pTimeCurrent=\u00a7c{0}\u00a76''s tijd is\u00a7c {1}\u00a76. +pTimeCurrentFixed=\u00a7cc{0}\u00a76''s tijd is vastgezet op\u00a7c {1}\u00a76. +pTimeNormal=\u00a7c{0}\u00a76''s tijd is normaal en komt overeen met de server. +pTimeOthersPermission=\u00a74U bent niet bevoegd om een andere speler zijn tijd te veranderen. +pTimePlayers=\u00a76Deze spelers hebben hun eigen tijd\:\u00a7r +pTimeReset=\u00a76Speler tijd is gereset voor\: \u00a7c{0} +pTimeSet=\u00a76Speler tijd is ingesteld op \u00a7c{0}\u00a76 voor\: \u00a7c{1}\u00a76. +pTimeSetFixed=\u00a76Speler tijd is vast gezet op \u00a7c{0}\u00a76 voor\: \u00a7c{1}\u00a76. +pWeatherCurrent=\u00a7c{0}\u00a76''s weer is\u00a7c {1}\u00a76. +pWeatherInvalidAlias=\u00a74Ongeldig weertype. +pWeatherNormal=\u00a7c{0}\u00a76''s weer is normaal en gelijk aan de server. +pWeatherOthersPermission=\u00a74U heeft geen toestemming om het weer van andere spelers in te stellen. +pWeatherPlayers=\u00a76Deze spelers hebben hun eigen weer\:\u00a7r +pWeatherReset=\u00a76Speler weer is gereset voor\: \u00a7c{0} +pWeatherSet=\u00a76Speler weer is ingesteld op \u00a7c{0}\u00a76 voor\: \u00a7c{1}. +pendingTeleportCancelled=\u00a74Afwachtende teleportatie afgelast. +playerBanIpAddress=\u00a76Player\u00a7c {0} \u00a76banned IP address\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerBanned=&4Speler &c{0} &6is gebanned voor &4{2} +playerInJail=&4De speler is al in de gevangenis &c{0}&4. +playerJailed=\u00a76Speler\u00a7c {0} \u00a76is in de gevangenis gezet. +playerJailedFor=\u00a76Speler\u00a7c {0} \u00a76is in de gevangenis gezet voor {1}. +playerKicked=\u00a76Speler\u00a7c {0} \u00a76schopt {1} van de server voor {2}. +playerMuted=\u00a76U bent gedempt\! +playerMutedFor=\u00a76U bent gedempt voor\u00a7c {0}. +playerNeverOnServer=\u00a74Speler\u00a7c {0} \u00a74is nooit op deze server geweest. +playerNotFound=\u00a74Speler niet gevonden. +playerUnbanIpAddress=\u00a76Speler\u00a7c {0} \u00a76Verwijderde ban op IP\: {1}. +playerUnbanned=\u00a76Speler\u00a7c {0} \u00a76verwijderde ban van {1}. +playerUnmuted=\u00a76Speler mag weer praten. +pong=Pong\! +posPitch=\u00a76Pitch\: {0} (Gezichtspunt) +posX=\u00a76X\: {0} (+Oost <-> -West) +posY=\u00a76Y\: {0} (+Boven <-> -Beneden) +posYaw=\u00a76Yaw\: {0} (Rotatie) +posZ=\u00a76Z\: {0} (+Zuid <-> -Noord) +possibleWorlds=\u00a76Mogelijke werelden zijn de nummers \u00a7c0\u00a76 door \u00a7c{0}\u00a76. +potions=\u00a76Toverdranken\:\u00a7r {0}\u00a76. +powerToolAir=\u00a74Commando kan niet worden gehecht aan lucht. +powerToolAlreadySet=\u00a74Commando \u00a7c{0}\u00a74 is al verbonden naar \u00a7c{1}\u00a74. +powerToolAttach=\u00a7c{0}\u00a76 commando gehecht aan {1}. +powerToolClearAll=\u00a76Alle powertool commando''s zijn verwijderd. +powerToolList=\u00a76Voorwerp \u00a7c{1}\u00a76 heeft de volgende commando''s\: \u00a7c{0}\u00a76. +powerToolListEmpty=\u00a74Voorwerp \u00a7c{0}\u00a74 heeft geen commando''s toegewezen. +powerToolNoSuchCommandAssigned=\u00a74Commando \u00a7c{0}\u00a74 is niet verbonden naar \u00a7c{1}\u00a74. +powerToolRemove=\u00a76Commando \u00a7c{0}\u00a76 verwijderd van \u00a7c{1}\u00a76. +powerToolRemoveAll=\u00a76Alle commandos zijn verwijderd van \u00a7c{0}\u00a76. +powerToolsDisabled=\u00a76Al uw powertools zijn uitgeschakeld. +powerToolsEnabled=\u00a76Al uw powertools zijn ingeschakeld. +questionFormat=\u00a77[Vraag]\u00a7f {0} +readNextPage=Type /{0} {1} om de volgende pagina te lezen. +recipe=\u00a76Recept voor \u00a7c{0}\u00a76 (\u00a7c{1}\u00a76 van \u00a7c{2}\u00a76) +recipeBadIndex=Er is geen recept met dat nummer. +recipeFurnace=\u00a76Smelt\: \u00a7c{0}\u00a76. +recipeGrid=\u00a7c{0}X \u00a76| \u00a7{1}X \u00a76| \u00a7{2}X +recipeGridItem=\u00a7c{0}X \u00a76is \u00a7c{1} +recipeMore=\u00a76Type /{0} \u00a7c{1}\u00a76 om andere recepten te zien van \u00a7c{2} +recipeNone=Er bestaan geen recepten voor {0}. +recipeNothing=niets +recipeShapeless=\u00a76Combineer \u00a7c{0} +recipeWhere=\u00a76Waar\: {0} +removed=\u00a77{0} entiteiten verwijderd. +repair=\u00a76Je hebt succesvol gerepareerd\: \u00a7c{0}\u00a76. +repairAlreadyFixed=\u00a77Dit voorwerp hoeft niet gerepareerd te worden. +repairEnchanted=\u00a74U heeft geen toestemming om dit voorwerp te repareren. +repairInvalidType=\u00a7cDit voorwerp kan niet gerepareerd worden. +repairNone=\u00a74Er zijn geen voorwerpen die gerepareerd moeten worden. +requestAccepted=\u00a77Teleporteer aanvraag geaccepteerd. +requestAcceptedFrom=\u00a7c{0} \u00a76accepteerde uw teleportatie aanvraag. +requestDenied=\u00a77Teleporteer aanvraag geweigerd. +requestDeniedFrom=\u00a7c{0} \u00a76heeft uw teleportatie aanvraag geweigerd. +requestSent=\u00a77Aanvraag verstuurd naar {0}\u00a77. +requestTimedOut=\u00a7cTeleportatie verzoek is verlopen. +requiredBukkit=\u00a76* \! * U heeft op zijn minst build {0} van CraftBukkit nodig, download het vanaf http\://dl.bukkit.org/downloads/craftbukkit/ +resetBal=\u00a76Balans is gereset naar \u00a7c{0} \u00a76voor alle online spelers. +resetBalAll=\u00a76Saldo is gereset naar \u00a7c{0} \u00a76voor alle spelers. +returnPlayerToJailError=\u00a74Een error is verschenen tijdens het proberen om het terugsturen van speler\u00a7c {0} \u00a74naar gevangenis\: \u00a7c{1}\u00a74\! +runningPlayerMatch=\u00a76Zoeken naar spelers die ''\u00a7c{0}\u00a76'' matchen (Dit kan even duren) +second=seconde +seconds=seconden +seenOffline=\u00a76Speler\u00a7c {0} \u00a76is \u00a74offline\u00a76 sins \u00a7c{1}\u00a76. +seenOnline=\u00a76Speler\u00a7c {0} \u00a76is \u00a7aonline\u00a76 sins \u00a7c{1}\u00a76. +serverFull=Server is vol. +serverTotal=\u00a76Server Totaal\:\u00a7c {0} +setBal=\u00a7aUw saldo is ingesteld op {0}. +setBalOthers=\u00a7aU heeft het saldo van {0} \u00a7aingesteld op {1}. +setSpawner=\u00a76Veranderde oproeper type naar\u00a7c {0}\u00a76. +sheepMalformedColor=\u00a74Misvormde kleur. +shoutFormat=\u00a76[Schreeuw]\u00a7r {0} +signFormatFail=\u00a74[{0}] +signFormatSuccess=\u00a71[{0}] +signFormatTemplate=[{0}] +signProtectInvalidLocation=\u00a74U bent niet bevoegd om hier een bord te plaatsen. +similarWarpExist=\u00a74Er bestaat al een warp met dezelfde naam. +slimeMalformedSize=\u00a74Misvormde grootte. +socialSpy=\u00a76SocialSpy voor \u00a7c{0}\u00a76\: \u00a7c{1} +soloMob=\u00a74Die mob is liever in zijn eentje. +spawnSet=\u00a76Spawn locatie voor de groep\u00a7c {0} \u00a76ingesteld. +spawned=Gespawnt +sudoExempt=\u00a74U kunt deze speler niet sudo\u00ebn. +sudoRun=\u00a76Forcing\u00a7c {0} \u00a76to run\:\u00a7r /{1} +suicideMessage=\u00a76Vaarwel wrede wereld... +suicideSuccess=\u00a76{0} \u00a76pleegde zelfmoord. +survival=overleving +takenFromAccount=\u00a7a{0} is van uw rekening afgehaald. +takenFromOthersAccount=\u00a7a{0} is van {1}\u00a7a''s rekening gehaald. Nieuw saldo\: {2}. +teleportAAll=\u00a76Teleportatie verzoek verzonden naar alle spelers... +teleportAll=\u00a76Bezig met teleporteren van alle spelers... +teleportAtoB=\u00a7c{0}\u00a76 heeft je geteleport naar \u00a7c{1}\u00a76. +teleportDisabled=\u00a7c{0} \u00a74heeft teleporteren uitgeschakeld. +teleportHereRequest=\u00a7c{0}\u00a76 Heeft gevraagd of u naar hem wilt teleporteren. +teleportNewPlayerError=\u00a74Fout bij het teleporteren van nieuwe speler\! +teleportRequest=\u00a7c{0}\u00a76 vraagt of hij naar u kan teleporteren. +teleportRequestTimeoutInfo=\u00a76Dit verzoekt verloopt na\u00a7c {0} seconde(n)\u00a76. +teleportTop=\u00a77Bezig met teleporteren naar het hoogste punt. +teleportationCommencing=\u00a76an het beginnen met teleporteren... +teleportationDisabled=\u00a76Teleportatie \u00a7cuitgezet\u00a76. +teleportationDisabledFor=\u00a76Teleportatie \u00a7cuitgezet \u00a76voor \u00a7c{0}\u00a76. +teleportationEnabled=\u00a76Teleportatie \u00a7caangezet\u00a76. +teleportationEnabledFor=\u00a76Teleportatie \u00a7caangezet \u00a76voor \u00a7c{0}\u00a76. +teleporting=\u00a76Bezig met teleporteren... +teleportToPlayer=\u00a76Teleporteren naar \u00a7c{0}\u00a76. +tempBanned=\u00a7cYou have been temporarily banned for {0}\:\n\u00a7r{2} +tempbanExempt=\u00a74U kunt deze speler niet tijdelijk verbannen. +thunder=\u00a76U heeft onweer\u00a7c {0} \u00a76in uw wereld. +thunderDuration=\u00a76U heeft onweer \u00a7c{0}\u00a76 in uw wereld voor \u00a7c{1}\u00a76 seconde(n). +timeBeforeHeal=\u00a74Afkoeltijd tot de volgende genezing\:\u00a7c {0}\u00a76. +timeBeforeTeleport=\u00a74Afkoeltijd tot de volgende teleportatie\:\u00a7c {0}\u00a76. +timeFormat=\u00a7c{0}\u00a76 of \u00a7c{1}\u00a76 of \u00a7c{2}\u00a76 +timeSetPermission=\u00a74U bent niet bevoegd om de tijd te veranderen. +timeWorldCurrent=\u00a76De huidige tijd in \u00a7c{0}\u00a76 is \u00a7c{1}\u00a76. +timeWorldSet=\u00a76De tijd was veranderd naar \u00a7c{0}\u00a76 in\: \u00a7c{1}\u00a76. +totalWorthAll=\u00a7aAlle spullen verkocht voor een totale waarde van \u00a7c{1}\u00a7a. +totalWorthBlocks=\u00a7aAlle blokken verkocht voor een totale waarde van \u00a7c{1}\u00a7a. +tps=\u00a76Huidige TPS \= {0} +tradeSignEmpty=\u00a74Dit handelsbord heeft niets beschikbaar voor u. +tradeSignEmptyOwner=\u00a74Er is niets te innen bij dit handelsbord. +treeFailure=\u00a74Fout bij het genereren van de boom. Probeer het opnieuw op gras of aarde. +treeSpawned=\u00a76Boom gegenereerd. +true=\u00a7ajuist\u00a7r +typeTpaccept=\u00a76Om te accepteren, typ \u00a7c/tpaccept\u00a76. +typeTpdeny=\u00a76Om te weigeren, typ \u00a7c/tpdeny\u00a76. +typeWorldName=\u00a76U kunt ook de naam van een specifieke wereld typen. +unableToSpawnMob=\u00a74De mob kan niet gespawnt worden. +unignorePlayer=\u00a76U negeert \u00a7c{0}\u00a76 niet meer. +unknownItemId=\u00a74Onbekend voorwerp id\: \u00a7r{0}\u00a74. +unknownItemInList=\u00a74Onbekend voorwerp {0} in {1} lijst. +unknownItemName=\u00a74Onbekende voorwerp naam\: {0}. +unlimitedItemPermission=\u00a74Geen toegang voor oneindig voorwerp \u00a7c{0}\u00a74. +unlimitedItems=Oneindige voorwerpen\: +unmutedPlayer=Speler {0} mag weer spreken. +unvanishedReload=\u00a74Een herlading heeft u geforceerd om zichtbaar te worden. +upgradingFilesError=Fout tijdens het upgraden van de bestanden. +uptime=\u00a76Tijd dat de server aanstaat\:\u00a7c {0} +userAFK=\u00a75{0} \u00a75is AFK,en zal mogelijk niet reageren. +userDoesNotExist=Speler {0} bestaat niet. +userIsAway={0} is nu afwezig. +userIsNotAway={0} is niet meer afwezig. +userJailed=\u00a76U bent in de gevangenis gezet\! +userUnknown=\u00a74Waarschuwing\: De gebruiker ''\u00a7c{0}\u00a74'' is nooit op deze server geweest. +userdataMoveBackError=Fout bij het verplaasten van userdata/{0}.tmp naar userdata/{1} +userdataMoveError=Fout bij het verplaasten van userdata/{0} naar userdata/{1}.tmp +usingTempFolderForTesting=Tijdelijke map om te testen\: +vanished=\u00a76U bent nu volledig onzichtbaar voor normale gebruikers, en verborgen voor in-game commando''s. +versionMismatch=Verkeerde versie\! Update {0} naar dezelfde versie. +versionMismatchAll=Verkeerde versie\! Update alle Essentials jars naar dezelfde versie. +voiceSilenced=\u00a76Je bent het zwijgen opgelegd\! +walking=Lopende +warpDeleteError=Fout bij het verwijderen van het warp bestand. +warpList={0} +warpListPermission=\u00a74U heeft geen toestemming om warps weer te geven. +warpNotExist=Die warp bestaat niet. +warpOverwrite=\u00a74U kunt deze warp niet overschrijven. +warpSet=\u00a77Warp {0} ingesteld. +warpUsePermission=\u00a74U heeft geen toestemming om die warp te gebruiken. +warpingTo=\u00a77Aan het warpen naar {0}. +warps=\u00a76Warps\:\u00a7r {0} +warpsCount=\u00a76Er zijn\u00a7c {0} \u00a76warps. Getoonde pagina \u00a7c{1} \u00a76van \u00a7c{2}\u00a76. +weatherStorm=\u00a76U heeft het weer naar \u00a7cstormachtig\u00a76 gezet in\u00a7c {0}\u00a76. +weatherStormFor=\u00a76U heeft het weer in \u00a7c{0}\u00a76 naar \u00a7cstormachtig\u00a76 gezet voor {1} seconde(n). +weatherSun=\u00a76U heeft het weer naar \u00a7czonnig\u00a76 gezet in\u00a7c {0}\u00a76. +weatherSunFor=\u00a76U heeft het weer in \u00a7c{0}\u00a76 naar \u00a7czonnig\u00a76 gezet voor {1} seconde(n). +whoisAFK=\u00a76 - Afwezig\:\u00a7f {0} +whoisBanned=\u00a76 - Verbannen\:\u00a7f {0} +whoisExp=\u00a76 - Exp\:\u00a7f {0} (Level {1}) +whoisFly=\u00a76 - Vlieg modus\:\u00a7f {0} ({1}) +whoisGamemode=\u00a76 - Spelmodus\:\u00a7f {0} +whoisGeoLocation=\u00a76 - Locatie\:\u00a7f {0} +whoisGod=\u00a76 - God modus\:\u00a7f {0} +whoisHealth=\u00a76 - Gezondheid\:\u00a7f {0}/20 +whoisIPAddress=\u00a76 - IP Adres\:\u00a7f {0} +whoisJail=\u00a76 - Gevangenis\:\u00a7f {0} +whoisLocation=\u00a76 - Locatie\:\u00a7f ({0}, {1}, {2}, {3}) +whoisMoney=\u00a76 - Geld\:\u00a7f {0} +whoisMuted=\u00a76 - Gedempt\:\u00a7f {0} +whoisNick=\u00a76 - Bijnaam\:\u00a7f {0} +whoisOp=\u00a76 - OP\:\u00a7f {0} +whoisTop=\u00a76 \=\=\=\=\=\= WhoIs\:\u00a7f {0} \u00a76\=\=\=\=\=\= +worth=\u00a7aStapel {0} met waarde \u00a7c{1}\u00a7a ({2} voorwerp(en) voor {3} per stuk) +worthMeta=\u00a7aStapel {0} met een metadata van {1} met waarde \u00a7c{2}\u00a7a ({3} voorwerp(en) voor {4} per stuk) +worthSet=\u00a76Waarde ingesteld +year=jaar +years=jaren +youAreHealed=\u00a76U bent genezen. +youHaveNewMail=\u00a76U heeft \u00a7c{0}\u00a76 berichten\! Type \u00a7c/mail read\u00a76 om uw berichten te bekijken. +whoisHunger=\u00a76 - Honger\:\u00a7r {0}/20 (+{1} Verzadiging) +kitDelay=\u00a7m{0}\u00a7r +giveSpawnFailure=\u00a74Niet genoeg ruimte, \u00a7c{0} \u00a7c{1} \u00a74is verloren gegaan. +noKitGroup=\u00a74U heeft geen toestemming om deze kit te gebruiken. +inventoryClearingFromAll=\u00a76Inventarissen van alle gebruikers leegmaken.... +inventoryClearingAllItems=\u00a76Alle inventaris voorwerpen van {0}\u00a76 zijn verwijderd. +inventoryClearingAllArmor=\u00a76Alle inventaris voorwerpen en het harnas van {0}\u00a76 zijn verwijderd. +inventoryClearingAllStack=\u00a76Alle\u00a7c {0} \u00a76van {1}\u00a76 is verwijderd. +inventoryClearingStack=\u00a76\u00a7c {0} \u00a76stuks\u00a7c {1} \u00a76zijn verwijderd uit de inventaris van {2}\u00a76. +inventoryClearFail=\u00a74Player {0} \u00a74heeft geen\u00a7c {1} \u00a74stuks\u00a7c {2}\u00a74. +localNoOne= +totalSellableAll=\u00a7aDe totale waarde van alle verkoopbare voorwerpen en blokken is \u00a7c {1} \u00a7a. +totalSellableBlocks=\u00a7aDe totale waarde van alle verkoopbare blokken is \u00a7c {1} \u00a7a. +radiusTooBig=\u00a74Straal is te groot\! Maximale straal is {0}. +isIpBanned=\u00a76IP \u00a7c {0} \u00a76is verbannen. +mobDataList=\u00a76Geldige mob gegevens\: \u00a7r {0} +vanish=\u00a76Verdwijn voor {0} \u00a76\: {1} +noLocationFound=\u00a74Geen geldige locatie gevonden. +coordsKeyword={0}, {1}, {2} +banExemptOffline=\u00a74U mag geen spelers verbannen die offline zijn. +tempbanExemptOffline=\u00a74Je mag geen spelers tijdelijk verbannen wanneer zij offline zijn. +mayNotJailOffline=\u00a74Je mag geen spelers in de gevangenis zetten wanneer zij offline zijn. +muteExemptOffline=\u00a74U mag spelers die offline zijn niet dempen. +ignoreExempt=\u00a74U kunt die speler niet negeren. +unsafeTeleportDestination=\u00a74De teleportatie bestemming is onveilig en teleport-veiligheid is uitgeschakeld. +noMetaJson=JSON Metadata is niet ondersteunt in deze versie van Bukkit. +maxMoney=\u00a74Deze transactie overschrijdt het balans van dit account. +skullChanged=\u00a76Schedel veranderd naar \u00a7c{0}\u00a76. +alphaNames=\u00a74Speler namen kunnen alleen uit letters, cijfers en onderstreepjes bestaan. +givenSkull=\u00a76U heeft de schedel ontvangen van \u00a7c{0}\u00a76. +noPermissionSkull=\u00a76Je hebt geen permissie om die schedel aan te passen. +teleportInvalidLocation=De waarde van co\u00f6rdinaten kan niet hoger dan 30000000 zijn +invalidSkull=\u00a74Houd alstublieft een schedel vast. +weatherInvalidWorld=De wereld genaamd {0} is niet gevonden\! +gameModeInvalid=\u00a74U moet een geldige speler/mode opgeven. +mailTooLong=\u00a74Mail bericht te lang. Probeer om het onder 1000 tekens te houden. +mailDelay=Er zijn teveel mails verzonden in een minuut. Het maximale aantal berichten\: {0} +seenAccounts=\u00a76Speler is ook bekend als\:\u00a7c {0} +unableToSpawnItem=\u00a74Kan niet spawnen \u00a7c{0}\u00a74, dit is geen spawnbaar voorwerp. +itemsConverted=\u00a76Converted all items into blocks. +itemsNotConverted=\u00a74You have no items that can be converted into blocks. +mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\: +mailMessage={0} + +whoisTempBanned=\u00a76 - Ban expires:\u00a7r {0} +playerTempBanned=\u00a76Player \u00a7c{0}\u00a76 temporarily banned \u00a7c{1}\u00a76 for \u00a7c{2}\u00a76: \u00a7c{3}\u00a76. +mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1} diff --git a/Essentials/src/messages_pl.properties b/Essentials/src/messages_pl.properties new file mode 100644 index 0000000000..f402a0e990 --- /dev/null +++ b/Essentials/src/messages_pl.properties @@ -0,0 +1,558 @@ +#X-Generator: crowdin.net +#version: TeamCity +# Single quotes have to be doubled: '' +# Translations start here +# by: +action=\u00a75* {0} \u00a75{1} +addedToAccount=\u00a7a{0} zostalo dodane do twojego konta. +addedToOthersAccount=\u00a7a{0} zostalo dodane do konta {1}\u00a7. Nowy stan konta\: {2}. +adventure=Przygoda +alertBroke=zniszczyl\: +alertFormat=\u00a73[{0}] \u00a7f {1} \u00a77 {2} at\: {3} +alertPlaced=postawil\: +alertUsed=uzyl\: +antiBuildBreak=\u00a74Nie masz uprawnien by zniszczyc blok {0} tutaj. +antiBuildCraft=\u00a74Nie masz uprawnien by stworzyc\u00a7c {0}\u00a74. +antiBuildDrop=\u00a74Nie masz uprawnien by wyrzucic\u00a7c {0}\u00a74. +antiBuildInteract=\u00a74Nie masz uprawnien by odzialywac z {0}. +antiBuildPlace=\u00a74Nie masz uprawnien by postawic {0} tutaj. +antiBuildUse=\u00a74Nie masz uprawnien by uzyc {0}. +autoAfkKickReason=Zostales wyrzucony z serwera za nie ruszanie sie przez wiecej niz {0} minut. +backAfterDeath=\u00a77Uzyj komendy /back aby powrocic na miejsce swojej smierci. +backUsageMsg=\u00a77Transportowano Cie do poprzedniej lokacji. +backupDisabled=\u00a74Zewnetrzny skrypt backupu nie zostal skonfigurowany. +backupFinished=\u00a77Backup zakonczony. +backupStarted=\u00a77Backup rozpoczety. +balance=\u00a7aStan konta\:\u00a7c {0} +balanceOther=\u00a7aStan konta gracza \u00a77{0} \u00a7awynosi\:\u00a7c {1} +balanceTop=\u00a77Najbogatsi gracze ({0}) +banExempt=\u00a74Nie mozesz zbanowac tego gracza. +banFormat=\u00a74Zbanowano\: {0} +bed=\u00a7olozko\u00a7r +bedMissing=\u00a74Twoje lozko nie zostalo ustawione, lub jest zablokowane. +bedNull=\u00a7mlozko\u00a7r +bedSet=\u00a77Spawn w lozku ustawiony\! +bigTreeFailure=\u00a74Nie mozna tutaj postawic duzego drzewa. Sprobuj ponownie na ziemi lub trawie. +bigTreeSuccess=\u00a77Stworzono duze drzewo. +blockList=\u00a77Essentials przekazuje nastepujace polecenie do innej wtyczki\: +bookAuthorSet=\u00a77Ustawiono autora ksiazki na {0} . +bookLocked=\u00a7cKsiazka jest teraz zablokowana. +bookTitleSet=\u00a77Ustawiono tytul ksiazki na {0} . +broadcast=\u00a7r\u00a77[\u00a74Ogloszenie\u00a77]\u00a7a {0} +buildAlert=\u00a74Nie mozesz tu budowac +bukkitFormatChanged=Format wersji Bukkita jest zmieniony. Wersja nie jest sprawdzana. +burnMsg=\u00a77Podpaliles\u00a7c {0} \u00a77na \u00a7c{1} sekund\u00a77. +canTalkAgain=\u00a77Znow mozesz mowic. +cannotStackMob=\u00a74Nie masz uprawnien by stackowac wiele mobow +cantFindGeoIpDB=Nie mozna znalezc bazy danych GeoIP\! +cantReadGeoIpDB=Odczytywanie bazy danych GeoIP zawiodlo\! +cantSpawnItem=\u00a74Nie mozesz stworzyc przedmiotu\u00a7c {0}\u00a74. +chatTypeAdmin=[A] +chatTypeLocal=[L] +chatTypeSpy=[Szpieg] +cleaned=Pliki gracza wyczyszczono. +cleaning=Czyszczene plikow gracza. +commandFailed=Komenda {0} zawiodla. +commandHelpFailedForPlugin=Blad podczas uzyskiwania pomocy dla\: {0} +commandNotLoaded=\u00a74Komenda {0} nie jest zaladowana\! +compassBearing=\u00a77Lozko\: {0} ({1} stopni). +configFileMoveError=Nie udalo sie przeniesc config.yml do lokalizacji backupa. +configFileRenameError=Nie udalo sie zmienic nazwy tymczasowego pliku na config.yml +connectedPlayers=\u00a77Aktywni gracze\u00a7r +connectionFailed=Blad podczas otwierania polaczenia. +cooldownWithMessage=Odczekaj\: {0} +corruptNodeInConfig=\u00a74Uwaga\: Twoj plik konfiguracyjny ma uszkodzony wpis\: {0} +couldNotFindTemplate=\u00a74Nie mozna znalezc szablonu\: {0} +creatingConfigFromTemplate=Tworzenie konfiguracji z szablonu\: {0} +creatingEmptyConfig=Stworzono pusty config\: {0} +creative=Kreatywny +currency={0}{1} +currentWorld=\u00a77Biezacy swiat\:\u00a7c {0} +day=dzien +days=dni +defaultBanReason=Admin ma zawsze racje\! +deleteFileError=Nie mozna usunac pliku\: {0} +deleteHome=\u00a77Dom\u00a7c {0} \u00a77zostal usuniety. +deleteJail=\u00a77Wiezienie\u00a7c {0} \u00a77zostalo usuniete. +deleteWarp=\u00a77Warp\u00a7c {0} \u00a77zostal usuniety. +deniedAccessCommand=\u00a7c{0} \u00a74nie ma dostepu do tego polecenia +denyBookEdit=\u00a74Nie mozesz odblokowac tej ksiazki. +denyChangeAuthor=\u00a74Nie mozesz zmienic autora tej ksiazki. +denyChangeTitle=\u00a74Nie mozesz zmienic tytulu tej ksiazki. +depth=\u00a77Jestes na poziomie morza. +depthAboveSea=\u00a77Jestes\u00a7c {0} \u00a77blok(ow) nad poziomem morza. +depthBelowSea=\u00a77Jestes\u00a7c {0} \u00a77blok(ow) pod poziomem morza. +destinationNotSet=Cel nieokreslony. +disableUnlimited=\u00a77Wylaczone nieograniczone tworzenia\u00a7c {0} \u00a77dla {1}. +disabled=wylaczone +disabledToSpawnMob=\u00a74Tworzenie tego moba zostalo wylaczone w pliku config. +distance=\u00a77Odleglosc\: {0} +dontMoveMessage=\u00a77Teleportacja nastapi za\u00a7c {0}\u00a77. Prosze sie nie ruszac. +downloadingGeoIp=Pobieranie bazy danych GeoIP... To moze zajac chwile (kraj\: 0.6 MB, miasto\: 20MB) +duplicatedUserdata=Kopiowanie danych uzytkownika\: {0} i {1} +durability=\u00a76Temu narz\u0119dziu pozosta\u0142o \u00a7c{0}\u00a76 u\u017cy\u0107 +editBookContents=\u00a7eNie mozesz teraz edytowac tej ksiazki. +enableUnlimited=\u00a76Przyznano nielimitowan\u0105 ilo\u015b\u0107\u00a7c {0} \u00a76dla {1}. +enabled=wlaczone +enchantmentApplied=\u00a77Ulepszenie\u00a7c {0} \u00a77zostalo przyznane przedmiotowi w twoim reku. +enchantmentNotFound=\u00a74Ulepszenie nie odnalezione +enchantmentPerm=\u00a74Nie masz zezwolenia na\u00a7c {0}\u00a7c4. +enchantmentRemoved=\u00a77Ulepszenie\u00a7c {0} \u00a77zostalo usuniete z przedmiotu w twoim reku.. +enchantments=\u00a77Ulepszenia\:\u00a7r {0} +errorCallingCommand=Blad wywolywania komendy /{0} +errorWithMessage=\u00a7cBlad\:\u00a74 {0} +essentialsHelp1=Plik jest uszkodzony i Essentials nie moze go otworzyc. Essentials jest teraz wylaczone. Jesli nie mozesz samemu naprawic pliku, idz na http\://tiny.cc/EssentialsChat +essentialsHelp2=Plik jest uszkodzony i Essentials nie moze go otworzyc. Essentials jest teraz wylaczone. Jesli nie mozesz samemu naprawic pliku, wpisz /essentialshelp w grze lub wejdz na http\://tiny.cc/EssentialsChat +essentialsReload=\u00a76Essentials prze\u0142adowa\u0142\u00a7c {0}. +exp=\u00a7c{0} \u00a77ma\u00a7c {1} \u00a77doswiadczenia (poziom\u00a7c {2}\u00a77), potrzebuje\u00a7c {3} \u00a77wiecej doswiadczenia do nastepnego poziomu. +expSet=\u00a7c{0} \u00a77teraz ma\u00a7c {1} \u00a77doswiadczenia. +extinguish=\u00a77Zostales ugaszony. +extinguishOthers=\u00a77Ugasiles {0}\u00a77. +failedToCloseConfig=Blad podczas zamykania configu {0} +failedToCreateConfig=Blad podczas tworzenia configu {0} +failedToWriteConfig=Blad podczas pisania configu {0} +false=\u00a74nie\u00a7r +feed=\u00a77Twoj glod zostal zaspokojony. +feedOther=\u00a76Zaspokoi\u0142e\u015b apetyt {0}\u00a76. +fileRenameError=Blad podczas zmiany nazwy pliku \u0093{0}\u0094. +fireworkColor=\u00a74Musisz dodac kolor fajerwerki by dodac do niej efekt. +fireworkEffectsCleared=\u00a77Usunieto wszystkie efekty trzymanych w reku fajerwerek. +fireworkSyntax=\u00a77Parametry Fajerwerki\:\u00a74 color\: [fade\:] [shape\:] [effect\:]\n\u00a77By uzyc wielu kolorow/efektow, oddziel wartosci przecinkami\: \u00a74red,blue,pink\n\u00a77Ksztalty\:\u00a74 star, ball, large, creeper, burst \u00a77Efekty\:\u00a74 trail, twinkle. +flyMode=\u00a77Ustawiono latanie\u00a7c {0} \u00a77dla {1}\u00a77. +flying=latanie +foreverAlone=\u00a74Nie masz komu odpisac. +fullStack=\u00a74Juz masz pelen stack. +gameMode=\u00a76Zmieni\u0142e\u015b tryb gry {1}\u00a76 na\u00a7c {0}\u00a76. +gcWorld=\u00a76{0} "\u00a7c{1}\u00a76"\: \u00a7c{2}\u00a76 chunki, \u00a7c{3}\u00a76 istoty, \u00a7c{4}\u00a76 byty blok\u00f3w. +gcfree=\u00a77Wolna pamiec\:\u00a7c {0} MB +gcmax=\u00a77Maksymalna pamiec\:\u00a7c {0} MB +gctotal=Alokowana pamiec\: {0} MB +geoIpUrlEmpty=Url pobierania GeoIP jest pusty. +geoIpUrlInvalid=Url pobierania GeoIP jest nieprawidlowy. +geoipJoinFormat=\u00a76Gracz \u00a7c{0} \u00a76przybyl z \u00a7c{1}\u00a76. +giveSpawn=\u00a77Dales\u00a7c {1} {0} \u00a77graczowi\u00a7c {2}\u00a77. +godDisabledFor=\u00a74wy\u0142\u00a76 dla\u00a7c {0} +godEnabledFor=\u00a7awlaczony\u00a77 dla\u00a7c {0}. +godMode=\u00a77Godmode\u00a7c {0}\u00a77. +groupDoesNotExist=\u00a74W tej grupie nikt nie jest online. +groupNumber={0} online, by zobaczyc pelna liste wpisz /{1} {2} +hatArmor=\u00a74Blad, nie mozesz uzyc tego jako kapelusz. +hatEmpty=\u00a74Nie nosisz aktualnie kapelusza. +hatFail=\u00a74Musisz cos trzymac w dloni. +hatPlaced=\u00a77Ciesz sie nowym kapeluszem\! +hatRemoved=\u00a77Twoj kapelusz zostal usuniety. +haveBeenReleased=\u00a77Zostales wypuszczony. +heal=\u00a77Zostales uleczony. +healDead=\u00a74Nie mozesz uleczyc kogos kto nie zyje\! +healOther=\u00a77Uleczono gracza {0}. +helpConsole=Aby uzyskac pomoc z konsoli, wpisz ?. +helpFrom=\u00a77Komendy od {0}\: +helpLine=\u00a76/{0}\u00a7r\: {1} +helpMatching=\u00a77Komendy odpowiadajace "\u00a7c{0}\u00a77"\: +helpOp=\u00a74[HelpOp]\u00a7r \u00a77{0}\:\u00a7r {1} +helpPlugin=\u00a74{0}\u00a7r\: Pomoc pluginu\: /help {1} +holdBook=\u00a74Nie trzymasz napisanej ksiazki. +holdFirework=\u00a74Musisz trzymac fajerwerke by dodac efekt. +holdPotion=\u00a74Musisz trzymac miksture by dodac do niej efekt. +holeInFloor=\u00a74Kosmos +homeSet=\u00a77Dom zostal ustawiony. +homes=\u00a77Domy\:\u00a7r {0} +hour=godzina +hours=godzin +ignoredList=\u00a76Ignorowani\:\u00a7r {0} +ignorePlayer=\u00a77Od tej chwili ignorujesz gracza \u00a7c{0}\u00a77. +illegalDate=Nie prawidlowy format daty. +infoChapter=\u00a77Wybierz rozdzial\: +infoChapterPages=\u00a7e ---- \u00a76{0} \u00a7e--\u00a76 Strona \u00a7c{1}\u00a76 z \u00a7c{2} \u00a7e---- +infoPages=\u00a7e ---- \u00a77{2} \u00a7e--\u00a77 Strona \u00a7c{0}\u00a77/\u00a7c{1} \u00a7e---- +infoUnknownChapter=\u00a74Nieznany rozdzial. +insufficientFunds=\u00a74Nie posiadasz wystarczajacych srodkow. +invalidCharge=\u00a74Nieprawid\u0142owa op\u0142ata. +invalidFireworkFormat=\u00a76Opcja \u00a74{0} \u00a76nie jest prawid\u0142ow\u0105 warto\u015bci\u0105 dla \u00a74{1}\u00a76. +invalidHome=\u00a74Dom\u00a7c {0} \u00a74nie istnieje. +invalidHomeName=\u00a74Niepoprawna nazwa domu. +invalidMob=\u00a74Niepoprawny typ moba. +invalidNumber=Niepoprawny Numer. +invalidPotion=\u00a74Niepoprawna mikstura. +invalidPotionMeta=\u00a74Niepoprawna wartosc mikstury\: \u00a7c{0}\u00a74. +invalidSignLine=\u00a74Linia\u00a7c {0} \u00a74na znaku jest bledna. +invalidWarpName=\u00a74Niepoprawna nazwa warpa. +invalidWorld=\u00a74Nieprawidlowy swiat. +is=jest +itemCannotBeSold=\u00a7rNie mozesz sprzedac tego przedmiotu serwerowi. +itemMustBeStacked=\u00a74Przedmiotem handluje sie w stackach. Wielkosc 2s to dwa stacki itd. +itemNames=\u00a77Krotka nazwa\:\u00a7r {0} +itemNotEnough1=\u00a74Masz za malo tego przedmiotu, aby go sprzedac. +itemNotEnough2=\u00a77Jesli chcesz sprzedac wszystkie przedmioty tego typu, wpisz /sell nazwaprzedmiotu +itemNotEnough3=\u00a77/sell nazwaprzedmiotu -1 sprzeda cala ilosc przedmiotu poza 1 sztuka itd. +itemSellAir=Serio probujesz sprzedac powietrze? Miej w reku przedmiot.. +itemSold=\u00a7aSprzedano za \u00a7c{0} \u00a7a({1} {2} po {3} kazdy) +itemSoldConsole=\u00a7a{0} \u00a7aSprzedano {1} za \u00a7a{2} \u00a7a({3} sztuki po {4} kazda) +itemSpawn=\u00a77Otrzymano\u00a7c {0} \u00a77z\u00a7c {1} +itemType=\u00a77Przedmiot\:\u00a7c {0} \u00a77-\u00a7c {1} +itemsCsvNotLoaded=Nie mozna wczytac pliku items.csv. +jailAlreadyIncarcerated=\u00a74Ten gracz jest juz w wiezieniu \u00a7c{0} \u00a74. +jailMessage=\u00a74Za kazde przewinienie czeka kara. +jailNotExist=\u00a74Nie ma takiego wiezienia. +jailReleased=\u00a77Gracz \u00a7c{0}\u00a77 zostal wypuszczony z wiezienia. +jailReleasedPlayerNotify=\u00a77Zostales zwolniony\! +jailSentenceExtended=\u00a77Czas pobyty w wiezieniu zwiekszono do\: {0} +jailSet=\u00a77Stworzles wiezienie \u00a7c{0}\u00a77. +jumpError=\u00a74To moglo by ci cos zrobic. +kickDefault=Zostales wyrzucony z serwera. +kickExempt=\u00a74Nie mozesz wyrzucic tej osoby. +kickedAll=\u00a74Wyrzucono wszystkich graczy z serwera +kill=\u00a77Gracz \u00a7c{0} \u00a77zostal zabity. +killExempt=\u00a74Nie mo\u017cesz zabi\u0107 {0} +kitCost=\ \u00a77\u00a7o({0})\u00a7r +kitError2=\u00a74Ten zestal jest zle skonfigurowany. Skontaktuj sie z administratorem\! +kitError=\u00a74Nie ma prawidlowych zestawow. +kitGiveTo=\u00a76Przyznano {1}\u00a76 zestaw\u00a7c {0}\u00a76. +kitInvFull=\u00a74Twoj ekwipunek jest pelen, zestaw zostal wyrzucony na podloge. +kitNotFound=\u00a74Ten zestaw nie istnieje . +kitOnce=\u00a74Nie mozesz uzyc tego zestawu ponownie. +kitReceive=\u00a77Otrzymales zestaw\u00a7c {0}\u00a77. +kitTimed=\u00a74Nie mozesz wziasc tego zestawu przez kolejne\u00a7c {0}\u00a74. +kits=\u00a77Zestawy\:\u00a7r {0} +leatherSyntax=\u00a77Skladnia Koloru Skory\: color\:,, np\: color\:255,0,0. +lightningSmited=\u00a77Zostales uderzony piorunem. +lightningUse=\u00a77Uderzono piorunem\u00a7c {0}\u00a77. +listAfkTag=\u00a77[AFK]\u00a7f +listAmount=\u00a77Na serwerze jest \u00a7c{0}\u00a77 graczy z maksimum \u00a7c{1}\u00a77 online. +listAmountHidden=\u00a77Na serwerze jest \u00a7c{0}\u00a77/{1}\u00a77 graczy z maksimum \u00a7c{2}\u00a77 online. +listGroupTag=\u00a77{0}\u00a7r\: \u00a7r +listHiddenTag=\u00a77[UKRYTY]\u00a7r +loadWarpError=\u00a74Blad przy wczytywaniu warpu {0}. +localFormat=[L]<{0}> {1} +mailClear=\u00a76Aby oznaczy\u0107 swoj\u0105 poczt\u0119 jako przeczytan\u0105, wpisz\u00a7c /mail clear\u00a76. +mailCleared=\u00a77Skrzynka oprozniona\!\! +mailSent=\u00a77Wiadomosc wyslana\! +markMailAsRead=\u00a76Aby oznaczy\u0107 swoj\u0105 poczt\u0119 jako przeczytan\u0105, wpisz\u00a7c /mail clear\u00a76. +markedAsAway=\u00a77Zostales oznaczony jako nieobecny. +markedAsNotAway=\u00a77Juz nie jestes nieobecny. +matchingIPAddress=\u00a77Gracz wczesniej byl zalogowany z tego adresu IP\: +maxHomes=\u00a74Nie mozesz ustawic wiecej niz\u00a7c {0} \u00a74domow. +mayNotJail=\u00a74Nie mozesz wtracic do wiezienia tej osoby. +me=Ja +minute=minuta +minutes=minut +missingItems=\u00a74Nie posiadasz {0}x {1}. +mobSpawnError=\u00a74Blad podczas zmiany spawnera. +mobSpawnLimit=Ilosc mobow ograniczona do limitu serwera. +mobSpawnTarget=\u00a74Blok musi byc spawnerem. +mobsAvailable=\u00a77Moby\: {0} +moneyRecievedFrom=\u00a7a{0} otrzymane od {1} +moneySentTo=\u00a7a{0} zostalo wyslane do {1} +month=miesiac +months=miesiecy +moreThanZero=\u00a74Ilosc musi byc wieksza niz 0. +moveSpeed=\u00a76Zmieni\u0142e\u015b szybko\u015b\u0107 {0}nia dla\u00a76 {2}\u00a76 na\u00a7c {1}\u00a76. +msgFormat=\u00a76[\u00a7c{0}\u00a76 -> \u00a7c{1}\u00a76] \u00a7r{2} +multipleCharges=\u00a74Nie mozesz ustawic wiecej niz jeden ladunek dla tej fajerwerki. +multiplePotionEffects=\u00a74Nie mozesz ustawic wiecej niz jeden efekt dla tej mikstury. +muteExempt=\u00a74Nie mozesz wyciszyc tego gracza.. +muteNotify=\u00a7c{0} \u00a76wyciszy\u0142 \u00a7c{1}\u00a76. +mutedPlayer=\u00a76Gracz\u00a7c {0} \u00a76zosta\u0142 wyciszony. +mutedPlayerFor=\u00a76Gracz\u00a7c {0} \u00a76zosta\u0142 wyciszony za\u00a7c {1}\u00a76. +mutedUserSpeaks={0} probowal sie odezwac, ale jest wyciszony. +nearbyPlayers=\u00a77Gracze w poblizu\:\u00a7r {0} +negativeBalanceError=\u00a74Gracz nie moze miec ujemnego stanu konta. +nickChanged=\u00a77Nick gracza zostal zmieniony. +nickDisplayName=\u00a74Musisz wlaczyc change-displayname w configu Essential. +nickInUse=\u00a74Ten pseudonim jest juz w uzyciu. +nickNamesAlpha=\u00a74Pseudonimy musza byc alfanumeryczne. +nickNoMore=\u00a77Nie masz juz pseudonimu. +nickSet=\u00a76Twoj nowy nick\: \u00a7c{0}\u00a76. +nickTooLong=\u00a74Ten pseudonim jest za d\u0142ugi. +noAccessCommand=\u00a74Nie masz dostepu do tej komendy. +noAccessPermission=\u00a74Nie jeste\u015b uprawniony do dost\u0119pu do tego {0}. +noBreakBedrock=\u00a74Nie masz uprawnien do niszczenia bedrocka. +noDestroyPermission=\u00a74Nie jeste\u015b uprawniony do niszczenia tego {0}. +noDurability=\u00a74Ten przedmiot nie jest wytrzymaly. +noGodWorldWarning=\u00a74Uwaga\! Godmode jest wylaczony w tym swiecie\!. +noHelpFound=\u00a74Nie ma odpowiadajacych komend. +noHomeSetPlayer=\u00a77Gracz nie ma ustawionego domu. +noIgnored=\u00a77Nikogo nie ignorujesz. +noKitPermission=\u00a74Musisz posiadac uprawnienia \u00a7c{0}\u00a74 aby uzywac tego zestawu. +noKits=\u00a77Nie ma jeszcze dostepnych zestawow. +noMail=\u00a77Nie masz zadnych wiadomosci. +noMatchingPlayers=\u00a77Nie znaleziono pasujacych graczy. +noMetaFirework=\u00a74Nie masz uprawnien by zastosowac wartosci fajerwerce. +noMetaPerm=\u00a74Nie masz uprawnien by zastosowac wartosci \u00a7c{0}\u00a74 dla tego przedmiotu. +noNewMail=\u00a77Nie masz zadnych nowych wiadomosci. +noPendingRequest=\u00a74Nie masz oczekujacej prosby. +noPerm=\u00a74Nie masz uprawnien do \u00a7c{0}\u00a74. +noPermToSpawnMob=\u00a74Nie masz uprawnien do tworzenia tego moba.. +noPlacePermission=\u00a74Nie masz uprawnien do stawiania bloku kolo tego znaku.. +noPotionEffectPerm=\u00a74Nie masz uprawnien by dodac efekt \u00a7c{0} \u00a74tej miksturze. +noPowerTools=\u00a77Nie masz przypisanego zadnego power tool. +noWarpsDefined=\u00a77Nie ma zadnych warpow. +none=zaden +notAllowedToQuestion=\u00a74Nie mozesz zadac tego pytania. +notAllowedToShout=\u00a74Nie mozesz krzyczec.. +notEnoughExperience=\u00a74Nie masz wystarczajaco duzo doswiadczenia. +notEnoughMoney=\u00a74Nie masz tyle pieniedzy. +notFlying=nie lata +notRecommendedBukkit=\u00a74* \! * Wersja Bukkita nie jest rekomendowana dla Essentials. +notSupportedYet=Jeszcze nie wspierane. +nothingInHand=\u00a74Nie masz nic w reku.. +now=teraz +nuke=\u00a75Niech smierc pochlonie caly swiat\! +numberRequired=Tutaj powinna byc liczba, gluptasie. +onlyDayNight=/time obsluguje tylko day/night. +onlyPlayerSkulls=\u00a74Mo\u017cesz tylko zmienia\u0107 w\u0142a\u015bciciela g\u0142owy gracza (397\:3). +onlyPlayers=\u00a74Tylko gracze bedacy w grze moga uzyc {0}. +onlySunStorm=\u00a74/weather obsluguje tylko sun/storm. +orderBalances=Pobieram fundusze {0} graczy, prosze czekac ... +oversizedTempban=\u00a74Nie mozesz teraz zbanowac tego gracza. +pTimeCurrent=Czas \u00a7e{0} u00a7f to {1}. +pTimeCurrentFixed=\u00a77Czas \u00a7c{0}\u00a77 przywrocony do\u00a7c {1}\u00a77. +pTimeNormal=\u00a77Czas \u00a7c{0}''s\u00a77 jest normalny i odpowiada serwerowemu. +pTimeOthersPermission=\u00a74Nie masz uprawnien do zmiany czasu innym. +pTimePlayers=\u00a77Ci gracze beda miec wlasny czas\:\u00a7r +pTimeReset=\u00a77Czas gracza zostal zresetowany dla \u00a7c{0} +pTimeSet=\u00a77Czas gracza ustawiony na \u00a7c{0}\u00a77 dla\: \u00a7c{1}. +pTimeSetFixed=\u00a77Czas gracza przywrocony do \u00a7c{0}\u00a77 dla \u00a7c{1}. +pWeatherCurrent=\u00a7c{0}\u00a77 pogoda to\u00a7c {1}\u00a77. +pWeatherInvalidAlias=\u00a74Niepoprawny typ pogody +pWeatherNormal=\u00a7c{0}\u00a77 pogoda jest normalna i pasuje do serwera. +pWeatherOthersPermission=\u00a74Nie masz uprawnien, by zmienic pogode pozostalym graczom. +pWeatherPlayers=\u00a77Ci gracze maja wlasna pogode\:\u00a7r +pWeatherReset=\u00a77Gracz zresetowal pogode dla\: \u00a7c{0} +pWeatherSet=\u00a77 Gracz ustawil pogode \u00a7c{0}\u00a77 dla\: \u00a7c{1}. +pendingTeleportCancelled=\u00a74Oczekujace zapytanie teleportacji odrzucone. +playerBanIpAddress=\u00a76Player\u00a7c {0} \u00a76banned IP address\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerBanned=\u00a7c{0} \u00a76zbanowa\u0142\u00a7c {1} \u00a76za {2}. +playerInJail=\u00a74Gracz jest juz w wiezieniu \u00a7c{0}\u00a77. +playerJailed=\u00a77Gracz\u00a7c {0} \u00a77zostal wtracony do wiezienia. +playerJailedFor=\u00a77Gracz\u00a7c {0} \u00a77zostal wtracony do wiezienia na {1}. +playerKicked=\u00a77Gracz\u00a7c {0} \u00a77wyrzucil {1} za {2}. +playerMuted=\u00a77Zostales wyciszony. +playerMutedFor=\u00a77Zostales wyciszony na\u00a7c {0}. +playerNeverOnServer=\u00a74Gracz\u00a7c {0} \u00a74nigdy nie byl na tym serwerze. +playerNotFound=\u00a74Nie odnaleziono gracza. +playerUnbanIpAddress=\u00a77Graczowi\u00a7c {0} \u00a77 odbanowano IP\: {1}. +playerUnbanned=\u00a7c{0} \u00a76odbanowa\u0142\u00a7c {1}. +playerUnmuted=\u00a77Twoj glos zostal przywrocony. +pong=Pong\! +posPitch=\u00a77Pitch\: {0} (Head angle) +posX=\u00a77X\: {0} (+Wschod <-> -Zachod) +posY=\u00a77Y\: {0} (+Gora <-> -Dol) +posYaw=\u00a77Wysokosc\: {0} (Rotacja) +posZ=\u00a77Z\: {0} (+Poludnie <-> -Polnoc) +possibleWorlds=\u00a76Mo\u017cliwe \u015bwiaty to numery od 0 do {0}. +potions=\u00a77Mikstury\:\u00a7r {0}\u00a77. +powerToolAir=\u00a74Nie zartuj, chcesz przypisac polecenie do powietrza? +powerToolAlreadySet=\u00a74Komenda \u00a7c{0}\u00a74 jest ju\u017c przypisana do {1}. +powerToolAttach=\u00a7c{0}\u00a77 polecenie przypisane do {1}. +powerToolClearAll=\u00a77Wszystkie przypisane polecenia zostaly usuniete\! +powerToolList=\u00a77Przedmiot \u00a7c{1} \u00a77zawiera nastepujace polecenia\: \u00a7c{0}\u00a77. +powerToolListEmpty=\u00a74Przedmiot \u00a7c{0} \u00a74nie ma przypisanych polecen. +powerToolNoSuchCommandAssigned=\u00a74Komenda \u00a7c{0}\u00a74 nie jest przypisana do {1}. +powerToolRemove=\u00a76Usuni\u0119to komende \u00a7c{0}\u00a76 z {1}. +powerToolRemoveAll=\u00a76Usuni\u0119to wszystkie komendy z {0}. +powerToolsDisabled=\u00a77Wszystkie twoje podpiecia zostaly zdezaktywowane. +powerToolsEnabled=\u00a77Wszystkie twoje podpiecia zostaly aktywowane. +questionFormat=\u00a72[Pytanie]\u00a7r {0} +readNextPage=\u00a77Wpisz\u00a7c /{0} {1} \u00a77aby przeczytac nastepna strone +recipe=\u00a76Receptura dla \u00a7c{0}\u00a76 ({1} z {2}) +recipeBadIndex=Nie ma receptury dla tego numeru. +recipeFurnace=\u00a76Przepal \u00a7c{0} +recipeGrid=\u00a7c{0}X \u00a76| \u00a7{1}X \u00a76| \u00a7{2}X +recipeGridItem=\u00a7{0}X \u00a76to \u00a7c{1} +recipeMore=\u00a77Wpisz /{0} \u00a7c{1}\u00a77 by zobaczyc receptury dla \u00a7c{2} \u00a77. +recipeNone=Nie ma receptur dla {0} . +recipeNothing=nic +recipeShapeless=\u00a77Kombinacja \u00a7c{0} +recipeWhere=\u00a77Gdzie\: {0} +removed=\u00a77Usunieto\u00a7c {0} \u00a77podmiotow. +repair=\u00a76Naprawi\u0142e\u015b pomy\u015blnie swoje\: \u00a7c{0}. +repairAlreadyFixed=\u00a74Ten przedmiot nie potrzebuje naprawy +repairEnchanted=\u00a74Nie masz zezwolenia do naprawiania ulepszonych przedmiotow. +repairInvalidType=\u00a74Ten przedmiot nie moze byc naprawiony. +repairNone=\u00a74\u017badne twoje przedmioty nie potrzebuj\u0105 naprawy. +requestAccepted=\u00a77Prosba o teleportacje - zaakceptowano. +requestAcceptedFrom=\u00a7c{0} \u00a77zaakceptowal Twoja prosbe o teleportacje. +requestDenied=\u00a77Prosba o teleportacje - odrzucona. +requestDeniedFrom=\u00a7c{0} \u00a77odrzucil Twoja prosbe o teleportacje. +requestSent=\u00a77Twoja prosba o teleportacje zostala wyslana do\u00a7c {0}\u00a77. +requestTimedOut=\u00a77Prosba o teleportacje - przedawniona. +requiredBukkit=* \! * Potrzebujesz najnowszego {0} CraftBukkit-a, pobierz go z http\://dl.bukkit.org/downloads/craftbukkit/ +resetBal=\u00a76Saldo zosta\u0142o zresetowane na \u00a7a{0} \u00a76dla wszystkich graczy b\u0119d\u0105cych online. +resetBalAll=\u00a76Saldo zosta\u0142o zresetowane na \u00a7a{0} \u00a76dla wszystkich graczy. +returnPlayerToJailError=\u00a74Wyst\u0105pi\u0142 b\u0142\u0105d podczas powracania gracza\u00a7c {0} \u00a74do wi\u0119zienia\: {1}\! +runningPlayerMatch=\u00a77Wyszukiwanie pasujacych graczy ''\u00a7c{0}\u00a77'' (to moze chwile potrwac) +second=sekunda +seconds=sekund +seenOffline=\u00a76Gracz\u00a7c {0} \u00a76jest \u00a74offline\u00a76 od {1}. +seenOnline=\u00a76Gracz\u00a7c {0} \u00a76jest \u00a7aonline\u00a76 od {1}. +serverFull=Serwer jest pelen graczy, sprobuj pozniej. +serverTotal=\u00a77Podsumowanie serwera\:\u00a7c {0} +setBal=\u00a7aTwoj stan konta ustawiono na {0}. +setBalOthers=\u00a7aUstawi\u0142e\u015b saldo {0}\u00a7a na {1}. +setSpawner=\u00a76Zmieniono typ spawnera na\u00a7c {0} +sheepMalformedColor=\u00a74Niewlasciwa barwa. +shoutFormat=\u00a77[Shout]\u00a7r {0} +signFormatFail=\u00a74[{0}] +signFormatSuccess=\u00a71[{0}] +signFormatTemplate=[{0}] +signProtectInvalidLocation=\u00a74Nie masz zezwolenia do tworzenia tutaj znakow. +similarWarpExist=\u00a74Warp o tej nazwie juz istnieje. +slimeMalformedSize=\u00a74Niewlasciwy rozmiar. +socialSpy=\u00a76SocialSpy dla {0}\u00a76\: {1} +soloMob=\u00a74Ten mob lubi byc sam. +spawnSet=\u00a77Ustawiono punkt spawnu dla grupy\u00a7c {0}\u00a77. +spawned=stworzono +sudoExempt=\u00a74Nie mozesz podniesc uprawnien tego uzytkownika. +sudoRun=\u00a76Forcing\u00a7c {0} \u00a76to run\:\u00a7r /{1} +suicideMessage=\u00a77Zegnaj okrutny swiecie. +suicideSuccess=\u00a77{0} dokonal zamachu na swoje zycie +survival=Przetrwanie +takenFromAccount=\u00a7a{0} zostalo pobrane z konta. +takenFromOthersAccount=\u00a7a{0} zostalo pobrane z {1}\u00a7a konta. Nowy stan konta\: {2} +teleportAAll=\u00a77Prosbe o teleportacje - wyslano do wszystkich graczy. +teleportAll=\u00a77Teleportowano wszystkich graczy. +teleportAtoB=\u00a76Zosta\u0142e\u015b przeteleportowany przez \u00a7c{0}\u00a76 do {1}\u00a76. +teleportDisabled=\u00a7c{0} \u00a74ma zdezaktywowana teleportacje. +teleportHereRequest=\u00a7c{0}\u00a77 ma zadanie przeteleportowac cie do nich. +teleportNewPlayerError=\u00a74Blad przy teleportowniu nowego gracza. +teleportRequest=\u00a7c{0}\u00a77 prosbe o teleportacje do Ciebie. +teleportRequestTimeoutInfo=\u00a77 Prosba o teleportacje przedawni sie za\u00a7c {0} \u00a77sekund. +teleportTop=\u00a77Teleportacja na wierzch. +teleportationCommencing=\u00a77Teleport rozgrzewa sie... +teleportationDisabled=\u00a76Teleportacja wy\u0142\u0105czona. +teleportationDisabledFor=\u00a76Teleportacja wy\u0142\u0105czona dla {0}. +teleportationEnabled=\u00a76Teleportacja w\u0142\u0105czona. +teleportationEnabledFor=\u00a76Teleportacja w\u0142\u0105czona dla {0}. +teleporting=\u00a77Teleportacja... +teleportToPlayer=\u00a76Teleportowanie do \u00a7c{0}\u00a76. +tempBanned=\u00a7cYou have been temporarily banned for {0}\:\n\u00a7r{2} +tempbanExempt=\u00a74Nie mozesz tymczasowo zbanowac tego gracza. +thunder=\u00a7c{0} \u00a77przywowlal burze. +thunderDuration=\u00a77Gracz \u00a7c{0} \u00a77przywolal burze na\u00a7c {1} \u00a77sekund. +timeBeforeHeal=\u00a77Czas przed nastepnym uzdrowieniem\:\u00a7c {0}\u00a77. +timeBeforeTeleport=\u00a77Czas przed nastepnym teleportem\:\u00a7c {0}. +timeFormat=\u00a7c{0}\u00a76 lub \u00a7c{1}\u00a76 lub \u00a7c{2}\u00a76 +timeSetPermission=\u00a74Nie masz uprawnien do ustawiania czasu. +timeWorldCurrent=\u00a77Obecny czas\u00a7c {0} \u00a77to \u00a7c{1}\u00a77. +timeWorldSet=\u00a77Czas ustawiono\u00a7c {0} \u00a77w\: \u00a7c{1}\u00a77. +totalWorthAll=\u00a7aSprzedano wszystkie Twoje bloki i przedmioty za kwote {1}. +totalWorthBlocks=\u00a7aSprzedano wszystkie Twoje bloki za kwote {1}. +tps=\u00a77Aktualne TPS \= {0} +tradeSignEmpty=\u00a74Tabliczka handlowa nie jest dla Ciebie dostepna. +tradeSignEmptyOwner=\u00a74Nie ma nic do pobrania z tej tabliczki. +treeFailure=\u00a74Utworzenie drzewa nie powiodlo sie, sprobuj na trawie lub ziemi. +treeSpawned=\u00a77Stworzono drzewo. +true=\u00a72tak\u00a7r +typeTpaccept=\u00a77Aby zaakceptowac teleport, wpisz \u00a7c/tpaccept\u00a77. +typeTpdeny=\u00a77Aby odmowic teleportacji, wpisz \u00a7c/tpdeny\u00a77. +typeWorldName=\u00a77Mozesz rowniez wpisac nazwe danego swiata. +unableToSpawnMob=\u00a74Nie udalo sie stworzyc potwora. +unignorePlayer=\u00a77Nie ignorujesz juz gracza \u00a7c{0}\u00a77. +unknownItemId=\u00a74Nieznane id przedmiotu\:\u00a7r {0}\u00a74. +unknownItemInList=\u00a74Nieznany przedmiot {0} w liscie {1} . +unknownItemName=\u00a74Nieznana nazwa przedmiotu\: {0}. +unlimitedItemPermission=\u00a74Brak uprawnie\u0144 na nielimitowane u\u017cycie {0}. +unlimitedItems=\u00a77Nielimitowane przedmioty\:\u00a7r +unmutedPlayer=\u00a77Gracz\u00a7c {0} \u00a77moze znowu mowic. +unvanishedReload=\u00a74Przeladowanie spowodowalo ze cie widac. +upgradingFilesError=Wystapil blad podczas aktualizowaniu plikow. +uptime=\u00a77Aktywny od\:\u00a7c {0} +userAFK=\u00a74{0} \u00a7\u00a77jest teraz AFK i nie reaguje. +userDoesNotExist=\u00a74Uzytkownik\u00a7c {0} \u00a74nie istnieje w bazie danych. +userIsAway=\u00a75{0} \u00a75jest teraz AFK. +userIsNotAway=\u00a7c{0} \u00a75nie jest juz AFK. +userJailed=\u00a77Zostales zamkniety w wiezieniu. +userUnknown=\u00a74Ostrzezenie\: Gracz ''\u00a7c{0}\u00a74'' nigdy nie byl na tym serwerze. +userdataMoveBackError=Nie udalo sie przeniesc userdata/{0}.tmp do userdata/{1} +userdataMoveError=Nie udalo sie przeniesc userdata/{0} do userdata/{1}.tmp +usingTempFolderForTesting=Uzywam tymczasowego folderu dla testu\: +vanished=\u00a77Juz jestes niewidoczny. +versionMismatch=\u00a74Niepoprawna wersja\! Prosze zaktualizowac {0} do tej samej wersji co inne pliki. +versionMismatchAll=\u00a74Niepoprawna wersja\! Prosze zaktualizowac wszystkie pliki Essentials do tej samej wersji. +voiceSilenced=\u00a77Twe usta zostaly zaszyte. +walking=chodzi +warpDeleteError=\u00a74Wystapil problem podczas usuwania pliku z Warpami. +warpList={0} +warpListPermission=\u00a74Nie masz pozwolenia na sprawdzenie listy Warp\u00c3\u00b3w.. +warpNotExist=\u00a74Ten Warp nie istnieje. +warpOverwrite=\u00a74Nie mozesz nadpisac tego Warpa. +warpSet=\u00a77Warp\u00a7c {0} \u00a77stworzony. +warpUsePermission=\u00a74Nie masz pozwolenie na korzystanie z tego Warpa. +warpingTo=\u00a77Teleportuje do\u00a7c {0}\u00a77. +warps=Warpy\: {0} +warpsCount=\u00a76Jest\u00a7c {0} \u00a76warp\u00f3w. Wy\u015bwietlanie strony {1} z {2}. +weatherStorm=\u00a77Ustawiles \u00a7cburze\u00a77 w\u00a7c {0}\u00a77. +weatherStormFor=\u00a77Ustawiles \u00a7cburze\u00a77 w\u00a7c {0} \u00a77na {1} sekund. +weatherSun=\u00a77Ustawiles \u00a7cbezchmurna\u00a77 pogode w\u00a7c {0}\u00a77. +weatherSunFor=\u00a77Ustawiles bezchmurna pogode w\u00a7c {0} \u00a77na {1} sekund. +whoisAFK=\u00a77 - AFK\:\u00a7r {0} +whoisBanned=\u00a77 - Zbanowany\:\u00a7r {0}. +whoisExp=\u00a77 - Punkty Doswiadczenia\:\u00a7r {0} (Poziom {1}). +whoisFly=\u00a77 - Latanie\:\u00a7r {0} ({1}) +whoisGamemode=\u00a77 - Tryb Gry\:\u00a7r {0}. +whoisGeoLocation=\u00a77 - Lokalizacja\:\u00a7r {0}. +whoisGod=\u00a77 - Godmode\:\u00a7r {0}. +whoisHealth=\u00a77 - Zdrowie\:\u00a7r {0}/20. +whoisIPAddress=\u00a77 - Adres IP\:\u00a7r {0}. +whoisJail=\u00a77 - W wiezieniu\:\u00a7r {0}. +whoisLocation=\u00a77 - Lokalizacja\:\u00a7r ({0}, {1}, {2}, {3}) +whoisMoney=\u00a77 - Pieniadze\:\u00a7r {0}. +whoisMuted=\u00a77 - Wyciszony\:\u00a7r {0} +whoisNick=\u00a77 - Nick\:\u00a7r {0} +whoisOp=\u00a77 - OP\:\u00a7r {0} +whoisTop=\u00a76 \=\=\=\=\=\= WhoIs\:\u00a7c {0} \u00a76\=\=\=\=\=\= +worth=\u00a7aStack {0} jest warty \u00a7c{1}\u00a7a ({2}rzedmiot(y) po {3} kazdy) +worthMeta=\u00a7aStack {0} z metadata {1} jest warty \u00a7c{2}\u00a7a ({3} przedmiot(y) po {4} kazdy) +worthSet=\u00a77Cena przedmiotu ustawiona. +year=rok +years=lat +youAreHealed=\u00a77Zostales uleczony. +youHaveNewMail=\u00a77Masz\u00a7c {0} \u00a77wiadomosci\! Wpisz \u00a7c/mail read\u00a77 aby je przeczytac. +whoisHunger=\u00a76 - G\u0142\u00f3d\:\u00a7r {0}/20 (+{1} saturacji) +kitDelay=\u00a7m{0}\u00a7r +giveSpawnFailure=\u00a74Niewystarczaj\u0105ce miejsce, \u00a7c{0} \u00a7c{1} \u00a74zosta\u0142o utracone. +noKitGroup=\u00a74Nie masz dost\u0119pu do tego zestawu. +inventoryClearingFromAll=\u00a76Czyszczenie ekwipunku wszystkich graczy... +inventoryClearingAllItems=\u00a76Wyczyszczono wszystkie przedmioty z ekwipunku {0}\u00a76. +inventoryClearingAllArmor=\u00a76Wyczyszczono zbroj\u0119 oraz wszystkie przedmioty z ekwipunku {0}\u00a76. +inventoryClearingAllStack=\u00a76Wyczyszczono wszystkie \u00a7c {0} \u00a76z {1}\u00a76. +inventoryClearingStack=\u00a76Usun\u0105\u0142e\u015b\u00a7c {0} {1} \u00a76graczowi {2}\u00a76. +inventoryClearFail=\u00a74Gracz {0} \u00a74nie posiada\u00a7c {1} {2}\u00a74. +localNoOne= +totalSellableAll=\u00a7aCa\u0142kowita warto\u015b\u0107 wszystkich sprzedawalnych przedmiot\u00f3w i blok\u00f3w wynosi \u00a7c{1}\u00a7a. +totalSellableBlocks=\u00a7aCa\u0142kowita warto\u015b\u0107 wszystkich sprzedawalnych blok\u00f3w wynosi \u00a7c{1}\u00a7a. +radiusTooBig=\u00a74Zasi\u0119g jest zbyt du\u017cy\! Maksymalny zasi\u0119g to {0}. +isIpBanned=\u00a77IP \u00a7c{0} \u00a77jest zbanowany. +mobDataList=\u00a76Prawid\u0142owe dane moba\:\u00a7r {0} +vanish=\u00a76Vanish dla {0}\u00a76\: {1} +noLocationFound=\u00a74Nie znaleziono prawidlowej lokalizacji. +coordsKeyword={0}, {1}, {2} +banExemptOffline=\u00a74Nie mozesz zablokowac graczy offline. +tempbanExemptOffline=\u00a74Nie mozesz tymczasowo zablokowac graczy offline. +mayNotJailOffline=\u00a74Nie mo\u017cesz wi\u0119zi\u0107 graczy b\u0119d\u0105cych offline. +muteExemptOffline=\u00a74Nie mo\u017cesz wyciszy\u0107 graczy b\u0119d\u0105chych offline. +ignoreExempt=\u00a74Nie mo\u017cesz ignorowa\u0107 tego gracza. +unsafeTeleportDestination=\u00a74Cel teleportacji jest niebezpieczny, a teleport-safety jest wy\u0142\u0105czone. +noMetaJson=Metadata JSON nie jest ob\u0142ugiwana w tej wersji Bukkita. +maxMoney=\u00a74Ta tranzakcja przekroczy\u0142aby limit salda dla tego konta +skullChanged=\u00a76Czaszka zosta\u0142a zmieniona na \u00a7c{0}\u00a76. +alphaNames=\u00a74Nazwa gracza mo\u017ce tylko zawiera\u0107 litery, cyfry i podkre\u015blenia +givenSkull=\u00a76Otrzyma\u0142e\u015b czaszk\u0119 \u00a7c{0}\u00a76. +noPermissionSkull=\u00a74Nie jeste\u015b uprawiony, aby zmieni\u0107 t\u0105 czaszk\u0119. +teleportInvalidLocation=Warto\u015b\u0107 koordynat\u00f3w nie mo\u017ce przekroczy\u0107 30000000 +invalidSkull=\u00a74Prosz\u0119, trzymaj czaszk\u0119 gracza. +weatherInvalidWorld=\u015awiat o nazwie {0} nie zosta\u0142 odnaleziony\! +gameModeInvalid=\u00a74Musisz poda\u0107 prawid\u0142owego gracza/tryb. +mailTooLong=\u00a74Wiadomo\u015b\u0107 mail jest zbyt d\u0142uga. Postaraj si\u0119 utrzyma\u0107 j\u0105 poni\u017cej 1000 znak\u00f3w. +mailDelay=Zbyt du\u017co maili zosta\u0142o wys\u0142ane w czasie ostaniej minuty. Maksymalna ilo\u015b\u0107\: {0} +seenAccounts=\u00a76Gracz jest tak\u017ce znany jako\:\u00a7c {0} +unableToSpawnItem=\u00a74Nie mo\u017cna stworzy\u0107 \u00a7c{0}\u00a74, poniewa\u017c ten przedmiot nie jest mo\u017cliwy do stworzenia. +itemsConverted=\u00a76Converted all items into blocks. +itemsNotConverted=\u00a74You have no items that can be converted into blocks. +mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\: +mailMessage={0} + +whoisTempBanned=\u00a76 - Ban expires:\u00a7r {0} +playerTempBanned=\u00a76Player \u00a7c{0}\u00a76 temporarily banned \u00a7c{1}\u00a76 for \u00a7c{2}\u00a76: \u00a7c{3}\u00a76. +mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1} diff --git a/Essentials/src/messages_pt.properties b/Essentials/src/messages_pt.properties new file mode 100644 index 0000000000..bcb1fb7f0c --- /dev/null +++ b/Essentials/src/messages_pt.properties @@ -0,0 +1,558 @@ +#X-Generator: crowdin.net +#version: TeamCity +# Single quotes have to be doubled: '' +# Translations start here +# by: +action=\u00a75* {0} \u00a75{1} +addedToAccount=\u00a7a{0} foi adicionado em sua conta. +addedToOthersAccount=\u00a7a{0} foi adicionado na conta de {1}\u00a7a. Novo saldo\: {2} +adventure=aventura +alertBroke=quebrado\: +alertFormat=\u00a73[{0}] \u00a7r {1} \u00a76 {2} em\: {3} +alertPlaced=colocado\: +alertUsed=usado\: +antiBuildBreak=\u00a74Voce nao tem permissao para quebrar\u00a7c {0} \u00a74blocos aqui. +antiBuildCraft=\u00a74Voce nao tem permissao para criar\u00a7c {0}\u00a74. +antiBuildDrop=\u00a74Voce nao tem permissao para dropar\u00a7c {0}\u00a74. +antiBuildInteract=\u00a74Voc\u00c3\u00aa nao tem permissao para interagir com\u00a7c {0}\u00a74. +antiBuildPlace=\u00a74Voc\u00ea n\u00e3o tem permiss\u00e3o para colocar\u00a7c {0} \u00a74aqui. +antiBuildUse=\u00a74Voc\u00c3\u00aa nao tem permissao para usar\u00a7c {0}\u00a74. +autoAfkKickReason=Voc\u00c3\u00aa foi kickado por ficar parado por mais de {0} minutos. +backAfterDeath=\u00a76Digite /back para retornar ao local onde voce morreu. +backUsageMsg=\u00a76Voltando ao local anterior. +backupDisabled=\u00a74Um script externo nao foi configurado. +backupFinished=\u00a76Backup acabou. +backupStarted=\u00a76Backup come\u00c3\u00a7ou. +balance=\u00a7aSaldo\:\u00a7c {0} +balanceOther=\u00a7aSaldo de {0}\u00a7a\:\u00a7c {1} +balanceTop=\u00a76Mais ricos ({0}) +banExempt=\u00a74Voce nao pode banir este jogador. +banFormat=\u00a74Banidos\:\n\u00a7r{0} +bed=\u00a7ocama\u00a7r +bedMissing=\u00a74Sua cama nao foi definida, esta corrompida ou esta bloqueada. +bedNull=\u00a7mcama\u00a7r +bedSet=\u00a76Cama definida\! +bigTreeFailure=\u00a74Falha ao gerar uma Arvore grande. Tente novamente na grama ou na terra. +bigTreeSuccess=\u00a76Arvore grande gerada. +blockList=\u00a76Essentials passou os seguintes comandos para outro plugin\: +bookAuthorSet=\u00a76Autor do livro definido para {0}. +bookLocked=\u00a76O livro esta trancado agora. +bookTitleSet=\u00a76Ti\u00adtulo do livro definido para {0}. +broadcast=\u00a7r\u00a76 [\u00a74Transmiss\u00e3o\u00a76] \u00a7a {0} +buildAlert=\u00a74Voce nao tem permissao para construir. +bukkitFormatChanged=Formato da versao do Bukkit alterada. Versao nao verificada. +burnMsg=\u00a76Voce colocou fogo em\u00a7c {0} \u00a76por\u00a7c {1} segundos\u00a76. +canTalkAgain=\u00a76Voce pode falar novamente. +cannotStackMob=\u00a74Voce nao tem permissao para empilhar varios mobs. +cantFindGeoIpDB=Nao foi possivel encontrar dados de GeoIP\! +cantReadGeoIpDB=Falha na leitura de dados GeoIP\! +cantSpawnItem=\u00a74Voce nao tem permissao para gerar o item\u00a7c {0}\u00a74. +chatTypeAdmin=[A] +chatTypeLocal=[L] +chatTypeSpy=[Espiao] +cleaned=Os arquivos do usuario foram apagados. +cleaning=Apagando arquivos do usuario. +commandFailed=Comando {0} falhou\: +commandHelpFailedForPlugin=Erro ao tentar adquirir ajuda para o plugin\: {0} +commandNotLoaded=\u00a74Comando {0} esta carregado incorretamente. +compassBearing=\u00a76Rolamento\: {0} ({1} graus). +configFileMoveError=Falha ao mover config.yml para o local de backup. +configFileRenameError=Falha ao renomear o arquivo tempor\u00e1rio para config.yml. +connectedPlayers=\u00a76Jogadores conectados\u00a7r +connectionFailed=Falha ao estabelecer conexao. +cooldownWithMessage=\u00a74Resfriamento\: {0} +corruptNodeInConfig=\u00a74Aviso\: Seu arquivo de configuracao tem um no {0} corrompido. +couldNotFindTemplate=\u00a74Template nao encontrado {0} +creatingConfigFromTemplate=Criando configuracao do template\: {0} +creatingEmptyConfig=Criando configuracao vazia\: {0} +creative=criativo +currency={0}{1} +currentWorld=\u00a76Mundo atual\:\u00a7c {0} +day=dia +days=dias +defaultBanReason=Bateu o martelo do Ban\! +deleteFileError=Nao foi possivel deletar o arquivo\: {0} +deleteHome=\u00a76Casa\u00a7c {0} \u00a76foi removida. +deleteJail=\u00a76Prisao\u00a7c {0} \u00a76foi removida. +deleteWarp=\u00a76Warp\u00a7c {0} \u00a76foi removido. +deniedAccessCommand=\u00a7c{0} \u00a74foi negado o acesso ao comando. +denyBookEdit=\u00a74Voc\u00ea nao pode desbloquear este livro. +denyChangeAuthor=\u00a74Voce nao pode alterar o autor deste livro. +denyChangeTitle=\u00a74Voce nao pode alterar o t\u00edtulo deste livro. +depth=\u00a76Voce esta no nivel do mar. +depthAboveSea=\u00a76Voce esta aa\u00a7c {0} \u00a76bloco(s) acima do nivel do mar. +depthBelowSea=\u00a76Voce esta a\u00a7c {0} \u00a76bloco(s) abaixo do nivel do mar. +destinationNotSet=Destino nao definido\! +disableUnlimited=\u00a76Permissao de colocar coisas ilimitadas desativada para\u00a7c {0} \u00a76por {1}. +disabled=desabilitado +disabledToSpawnMob=\u00a74Spawnar este mob foi desativado na configurasao. +distance=\u00a76Distancia\: {0} +dontMoveMessage=\u00a76Teletransporte ira come\u00e7ar em \u00a7c {0}\u00a76. Nao se mecha. +downloadingGeoIp=Baixando o banco de dados GeoIP... isso pode levar um tempo (pais\: 0.6 MB, cidade\: 20MB) +duplicatedUserdata=Dados do usuario dupliacado\: {0} e {1}. +durability=\u00a76Essa ferramenta ainda pode ser usada mais \u00a7c{0}\u00a76 vezes +editBookContents=\u00a7eVoce pode agora editar o conteudo deste livro. +enableUnlimited=\u00a76Dando quantidade ilimidada de\u00a7c {0} \u00a76para \u00a7c{1}\u00a76. +enabled=habilitado +enchantmentApplied=\u00a76O encantamento\u00a7c {0} \u00a76foi aplicado ao item em sua mao. +enchantmentNotFound=\u00a74Encantamento nao encontrado\! +enchantmentPerm=\u00a74Voce nao tem permissao para\u00a7c {0}\u00a74. +enchantmentRemoved=\u00a76O encantamento\u00a7c {0} \u00a76foi removido do item em sua mao. +enchantments=\u00a76Encantamentos\:\u00a7r {0} +errorCallingCommand=Erro ao usar o comando /{0} +errorWithMessage=\u00a7cErro\:\u00a74 {0} +essentialsHelp1=O arquivo esta corrompido e o Essentials nao consegue abri\u00ad-lo. Essentials desativado. Se voce nao consegue arrumar o arquivo sozinho, acesse http\://tiny.cc/EssentialsChat +essentialsHelp2=O arquivo esta corrompido e o Essentials nao consegue abri\u00ad-lo. Essentials desativado. Se voce nao consegue arrumar o arquivo sozinho, digite /essentialshelp no jogo ou acesse http\://tiny.cc/EssentialsChat +essentialsReload=\u00a76Essentials recarregado\u00a7c {0}. +exp=\u00a7c{0} \u00a76tem\u00a7c {1} \u00a76de exp (nivel\u00a7c {2}\u00a76) e precisa de\u00a7c {3} \u00a76mais exp para subir de ni\u00advel. +expSet=\u00a7c{0} \u00a76agora tem\u00a7c {1} \u00a76de exp. +extinguish=\u00a76Voce se matou. +extinguishOthers=\u00a76Voce matou {0}\u00a76. +failedToCloseConfig=Falha ao fechar a configuracao {0}. +failedToCreateConfig=Falha ao criar a configuracao {0}. +failedToWriteConfig=Falha ao escrever a configuracao {0}. +false=\u00a74falso\u00a7r +feed=\u00a76Seu apetite foi saciado. +feedOther=\u00a76Voc\u00ea saciou o apetite de {0}\u00a76. +fileRenameError=Falha ao renomear o arquivo {0}\! +fireworkColor=\u00a74Parametros inseridos para criar um fogo de artifi\u00adcio invalidos. Defina uma cor antes. +fireworkEffectsCleared=\u00a76Todos os efeitos deste pack foram removidos. +fireworkSyntax=\u00a76Par\u00c3\u00a2metros do fogo de artif\u00c3\u00adcio\:\u00a7c color\: [fade\:] [shape\:] [effect\:]\n\u00a76Para usar m\u00c3\u00baltiplas cores ou efeitos, separe-os entre v\u00c3\u00adrgulas\: \u00a7cred,blue,pink\n\u00a76Formatos\:\u00a7c star, ball, large, creeper, burst \u00a76Efeitos\:\u00a7c trail, twinkle. +flyMode=\u00a76Modo Voar foi\u00a7c {0} \u00a76para {1}\u00a76. +flying=voando +foreverAlone=\u00a74Voc\u00c3\u00aa nao tem ningu\u00c3\u00a9m a quem responder. +fullStack=\u00a74Voc\u00c3\u00aa j\u00c3\u00a1 tem um pack completo. +gameMode=\u00a76Modo de jogo\u00a7c {0} \u00a76definido para {1}\u00a76. +gcWorld=\u00a76 {0} "\u00a7c {1} \u00a76"\: \u00a7c {2} \u00a76 peda\u00e7os, \u00a7c {3} \u00a76 unidades, \u00a7c {4} \u00a76 placas. +gcfree=\u00a76Mem\u00f3ria livre\:\u00a7c {0} MB. +gcmax=\u00a76Mem\u00c3\u00b3ria m\u00c3\u00a1xima\:\u00a7c {0} MB. +gctotal=\u00a76Mem\u00c3\u00b3ria alocada\:\u00a7c {0} MB. +geoIpUrlEmpty=URL de download do GeoIP est\u00c3\u00a1 vazio. +geoIpUrlInvalid=URL de download do GeoIP inv\u00c3\u00a1lido. +geoipJoinFormat=\u00a76Jogador \u00a7c{0} \u00a76vem de \u00a7c{1}\u00a76. +giveSpawn=\u00a76Dando\u00a7c {0}\u00a7c {1} \u00a76para\u00a7c {2}\u00a76. +godDisabledFor=\u00a7cdesabilitado\u00a76 para\u00a7c {0} +godEnabledFor=\u00a7aativado\u00a76 para\u00a7c {0}. +godMode=\u00a76Modo deus\u00a7c {0}\u00a76. +groupDoesNotExist=\u00a74Nao h\u00c3\u00a1 ningu\u00c3\u00a9m online nesse grupo\! +groupNumber=\u00a7c{0}\u00a7f online, para a lista completa\:\u00a7c /{1} {2} +hatArmor=\u00a74Voc\u00c3\u00aa nao pode usar esse item como chap\u00c3\u00a9u\! +hatEmpty=\u00a74Voc\u00c3\u00aa nao est\u00c3\u00a1 usando chap\u00c3\u00a9u. +hatFail=\u00a74Voc\u00c3\u00aa deve ter algo em sua mao para vestir. +hatPlaced=\u00a76Aproveite seu novo chap\u00c3\u00a9u\! +hatRemoved=\u00a76Seu chap\u00c3\u00a9u foi removido. +haveBeenReleased=\u00a76Voc\u00c3\u00aa foi liberado. +heal=\u00a76Voc\u00c3\u00aa foi curado. +healDead=\u00a74Voc\u00c3\u00aa nao pode curar algu\u00c3\u00a9m que est\u00c3\u00a1 morto\! +healOther=\u00a7c {0}\u00a76foi curado. +helpConsole=Para ver ajuda pelo console, digite ?. +helpFrom=\u00a76Comandos de {0}\: +helpLine=\u00a76/{0}\u00a7r\: {1} +helpMatching=\u00a76Comandos correspondidos com "\u00a7c{0}\u00a76"\: +helpOp=\u00a7 4\u00ba [AjudaOp] \u00a7r \u00a7 6 {0}\: \u00a7r {1} +helpPlugin=\u00a74{0}\u00a7r\: Ajuda do Plugin\: /help {1} +holdBook=\u00a74Voc\u00c3\u00aa nao est\u00c3\u00a1 segurando um livro que possa escrever. +holdFirework=\u00a74Voc\u00c3\u00aa deve estar segurando um fogo de artif\u00c3\u00adcio para adicionar efeitos. +holdPotion=\u00a74Voc\u00c3\u00aa deve estar segurando uma po\u00c3\u00a7ao para aplicar efeitos para ela. +holeInFloor=\u00a74Buraco no chao\! +homeSet=\u00a76Casa definida. +homes=\u00a76Casas\:\u00a7r {0} +hour=hora +hours=horas +ignoredList=\u00a76Ignorado\:\u00a7r {0} +ignorePlayer=\u00a76Voc\u00c3\u00aa est\u00c3\u00a1 agora ignorando o jogador\u00a7c {0} \u00a76. +illegalDate=Formate de data ilegal. +infoChapter=\u00a76Selecione o Cap\u00edtulo\: +infoChapterPages=\u00a7e ---- \u00a76{0} \u00a7e--\u00a76 P\u00e1gina \u00a7c{1}\u00a76 de \u00a7c{2} \u00a7e---- +infoPages=\u00a7e ---- \u00a76{2} \u00a7e--\u00a76 P\u00c3\u00a1gina \u00a7c{0}\u00a76/\u00a7c{1} \u00a7e---- +infoUnknownChapter=\u00a74Cap\u00edtulo Desconhecido. +insufficientFunds=\u00a74Dinheiro insuficiente. +invalidCharge=\u00a74Argumento inv\u00c3\u00a1lido. +invalidFireworkFormat=\u00a74A op\u00e7\u00e3o \u00a7c{0} \u00a74n\u00e3o \u00e9 v\u00e1lida para \u00a7c{1}\u00a74. +invalidHome=\u00a74Casa\u00a7c {0} \u00a74nao existe\! +invalidHomeName=\u00a74Nome de casa inv\u00c3\u00a1lido\! +invalidMob=\u00a74Tipo de mob invalido. +invalidNumber=N\u00c3\u00bamero inv\u00c3\u00a1lido. +invalidPotion=\u00a74Po\u00c3\u00a7ao inv\u00c3\u00a1lida. +invalidPotionMeta=\u00a74Meta inv\u00c3\u00a1lida de po\u00c3\u00a7ao\: \u00a7c{0}\u00a74. +invalidSignLine=\u00a74Linha\u00a7c {0} \u00a74na placa est\u00c3\u00a1 inv\u00c3\u00a1lida. +invalidWarpName=\u00a74Nome de warp inv\u00c3\u00a1lido\! +invalidWorld=\u00a74Mundo inv\u00c3\u00a1lido. +is=\u00c3\u00a9 +itemCannotBeSold=\u00a74Esse item nao pode ser vendido para o servidor. +itemMustBeStacked=\u00a74O item deve ser trocado em packs. A quantidade de 2 deveria ser 2 packs, etc. +itemNames=\u00a76Nomes pequenos para o item\:\u00a7r {0} +itemNotEnough1=\u00a74Voc\u00c3\u00aa nao itens o suficiente para vender. +itemNotEnough2=\u00a76Se voc\u00c3\u00aa quis vender todos os seus itens de um tipo, digite /sell nomedoitem. +itemNotEnough3=\u00a76/sell nomedoitem -1 ir\u00c3\u00a1 vender tudo menos um item, etc. +itemSellAir=Voc\u00c3\u00aa realmente tentou vender Ar? Coloque um item em sua mao. +itemSold=\u00a7aVendido por \u00a7c{0} \u00a7a({1} {2} a {3} cada). +itemSoldConsole=\u00a7a{0} \u00a7avendeu {1} por \u00a7a{2} \u00a7a({3} itens a {4} each). +itemSpawn=\u00a76Dando\u00a7c {0}\u00a7c {1} +itemType=\u00cdtem \u00a76\:\u00a7c {0} \u00a76-\u00a7c {1} +itemsCsvNotLoaded=Nao p\u00c3\u00b4de carregar o items.csv\! +jailAlreadyIncarcerated=\u00a74Essa pessoa j\u00c3\u00a1 est\u00c3\u00a1 na cadeia\:\u00a7c {0} +jailMessage=\u00a74Voc\u00c3\u00aa foi condenado. Pense bem antes de fazer o que fez. +jailNotExist=\u00a74Essa cadeia nao existe. +jailReleased=\u00a76Jogador \u00a7c{0}\u00a76 liberado. +jailReleasedPlayerNotify=\u00a76Voc\u00c3\u00aa foi liberado\! +jailSentenceExtended=\u00a76Tempo na cadeia extendido para\: {0} +jailSet=\u00a76Cadeia\u00a7c {0} \u00a76foi definida. +jumpError=\u00a74Isso machucaria o c\u00c3\u00a9rebro do computador. +kickDefault=Kickado do servidor. +kickExempt=\u00a74Voc\u00c3\u00aa nao pode kickar essa pessoa. +kickedAll=\u00a74Todos os jogadores foram kickados. +kill=\u00a76Matou\u00a7c {0}\u00a76. +killExempt=\u00a74Voc\u00ea n\u00e3o pode matar \u00a7c{0}\u00a74. +kitCost=\ \u00a77\u00a7o({0})\u00a7r +kitError2=\u00a74Esse kit nao existe ou foi definido impropriamente. +kitError=\u00a74Nao h\u00c3\u00a1 kits v\u00c3\u00a1lidos. +kitGiveTo=\u00a76Dando o kit\u00a7c {0}\u00a76 para \u00a7c{1}\u00a76. +kitInvFull=\u00a74Seu invent\u00c3\u00a1rio est\u00c3\u00a1 cheio, colocando o kit no chao. +kitNotFound=\u00a74Esse kit n\u00e3o existe. +kitOnce=\u00a74Voc\u00c3\u00aa nao pode usar esse kit novamente. +kitReceive=\u00a76Recebido kit\u00a7c {0}\u00a76. +kitTimed=\u00a74Voc\u00c3\u00aa nao pode usar esse kit novamente por\u00a7c {0}\u00a74. +kits=\u00a76Kits\:\u00a7r {0} +leatherSyntax=\u00a76Sintaxe das Cores do Couro\: color\:,, ex\: color\:255,0,0. +lightningSmited=\u00a76Foste ferido\! +lightningUse=\u00a76Castigando\u00a7c {0} +listAfkTag=\u00a77[Ausente]\u00a7r +listAmount=\u00a76H\u00c3\u00a1 \u00a7c{0}\u00a76 de no m\u00c3\u00a1ximo \u00a7c{1}\u00a76 jogadores online. +listAmountHidden=\u00a76H\u00c3\u00a1 \u00a7c{0}\u00a76/{1}\u00a76 de no m\u00c3\u00a1ximo \u00a7c{2}\u00a76 jogadores online. +listGroupTag=\u00a76{0}\u00a7r\: \u00a7r +listHiddenTag=\u00a77[ESCONDIDO]\u00a7r +loadWarpError=\u00a74Falha ao carregar o warp {0}. +localFormat=[L]<{0}> {1} +mailClear=\u00a76Para marcar seus e-mails como lidos, digite\u00a7c /mail clear\u00a76. +mailCleared=\u00a76E-mails Removidos\! +mailSent=\u00a76E-mail enviado\! +markMailAsRead=\u00a76Para marcar teus e-mails como lidos, digite\u00a7c /mail clear\u00a76. +markedAsAway=\u00a76Voc\u00c3\u00aa est\u00c3\u00a1 agora marcado como ausente. +markedAsNotAway=\u00a76Voc\u00c3\u00aa nao est\u00c3\u00a1 mais marcado como ausente. +matchingIPAddress=\u00a76Os seguintes jogadores logaram com esse endere\u00c3\u00a7o de IP\: +maxHomes=\u00a74Voc\u00c3\u00aa nao pode definir mais de\u00a7c {0} \u00a74casas. +mayNotJail=\u00a74Voc\u00c3\u00aa nao pode prender essa pessoa\! +me=eu +minute=minuto +minutes=minutos +missingItems=\u00a74Voc\u00ea n\u00e3o tem \u00a7c{0}x {1}\u00a74. +mobSpawnError=\u00a74Erro ao mudar o mob spawner. +mobSpawnLimit=Quantidade de mobs aumentada at\u00c3\u00a9 o limite do servidor. +mobSpawnTarget=\u00a74Alvo deve ser um mob spawner. +mobsAvailable=\u00a76Mobs\:\u00a7r {0} +moneyRecievedFrom=\u00a7aVoc\u00c3\u00aa recebeu {0} de {1}. +moneySentTo=\u00a7aVoc\u00c3\u00aa enviou {0} para {1}. +month=m\u00c3\u00aas +months=meses +moreThanZero=\u00a74Quantidades devem ser maior que 0. +moveSpeed=\u00a76Velocidade de \u00a7c{2}\u00a76 foi definida de {0} para \u00a7c {1} \u00a76. +msgFormat=\u00a76[\u00a7c{0}\u00a76 -> \u00a7c{1}\u00a76] \u00a7r{2} +multipleCharges=\u00a74Voc\u00c3\u00aa nao pode aplicar mais de um comando para esse fogo de artif\u00c3\u00adcio. +multiplePotionEffects=\u00a74Voc\u00c3\u00aa nao pode aplicar mais de um efeito para essa po\u00c3\u00a7ao. +muteExempt=\u00a74Voc\u00c3\u00aa nao pode silenciar esse jogador. +muteNotify=\u00a7c{0} \u00a76silenciou \u00a7c{1}\u00a76. +mutedPlayer=\u00a76Jogador\u00a7c {0} \u00a76silenciado. +mutedPlayerFor=\u00a76Jogador\u00a7c {0} \u00a76silenciado por\u00a7c {1}\u00a76. +mutedUserSpeaks={0} tentou falar, mas est\u00c3\u00a1 silenciado. +nearbyPlayers=\u00a76Jogadores por perto\:\u00a7r {0} +negativeBalanceError=\u00a74Usu\u00c3\u00a1rio nao tem permissao para ter um saldo negativo. +nickChanged=\u00a76Nick alterado. +nickDisplayName=\u00a74Voc\u00c3\u00aa precisa ativar o change-displayname na configura\u00c3\u00a7ao do Essentials. +nickInUse=\u00a74Esse nome j\u00c3\u00a1 est\u00c3\u00a1 em uso. +nickNamesAlpha=\u00a74Nicks devem ser alfanum\u00c3\u00a9ricos. +nickNoMore=\u00a76Voc\u00c3\u00aa nao tem mais um nick. +nickSet=\u00a76Seu nick agora \u00e9 \u00a7c{0}\u00a76. +nickTooLong=\u00a74Nome \u00e9 muito grande. +noAccessCommand=\u00a74Voc\u00c3\u00aa nao tem acesso a esse comando. +noAccessPermission=\u00a74Voc\u00ea n\u00e3o tem permiss\u00e3o para acessar \u00a7c{0}\u00a74. +noBreakBedrock=\u00a74Voc\u00c3\u00aa nao tem permissao para quebrar bedrock. +noDestroyPermission=\u00a74voc\u00ea n\u00e3o tem permiss\u00e3o para destruir \u00a7c{0}\u00a74. +noDurability=\u00a74Esse item nao tem durabilidade. +noGodWorldWarning=\u00a74Cuidado\! Modo deus nao est\u00c3\u00a1 desativado nesse mundo. +noHelpFound=\u00a74Nenhum comando correspondendo. +noHomeSetPlayer=\u00a76Jogador nao definiu uma casa. +noIgnored=\u00a76Voc\u00ea n\u00e3o est\u00e1 ignorando ningu\u00e9m. +noKitPermission=\u00a74Voc\u00c3\u00aa precisa da permissao \u00a7c{0}\u00a74 para usar esse kit. +noKits=\u00a76Nao existem kits dispon\u00c3\u00adveis ainda. +noMail=\u00a76Voc\u00c3\u00aa nao tem nenhum e-mail. +noMatchingPlayers=\u00a76Nenhum jogador correspondente encontrado. +noMetaFirework=\u00a74Voc\u00c3\u00aa nao tem permissao para aplicar meta para fogos de artif\u00c3\u00adcio. +noMetaPerm=\u00a74Voc\u00c3\u00aa nao tem permissao para aplicar meta (\u00a7c{0})\u00a74 para esse item. +noNewMail=\u00a76Voc\u00c3\u00aa nao tem novos e-mails. +noPendingRequest=\u00a74Voc\u00c3\u00aa nao tem uma solicita\u00c3\u00a7ao. +noPerm=\u00a74Voc\u00c3\u00aa nao tem a permissao \u00a7c{0}\u00a74. +noPermToSpawnMob=\u00a74Voc\u00c3\u00aa nao tem permissao para spawnar esse mob. +noPlacePermission=\u00a74Voc\u00c3\u00aa nao tem permissao para colocar um bloco perto dessa placa. +noPotionEffectPerm=\u00a74Voc\u00c3\u00aa nao tem permissao para aplicar o efeito \u00a7c{0} \u00a74para essa po\u00c3\u00a7ao. +noPowerTools=\u00a76Voc\u00c3\u00aa nao tem nenhuma ferramenta de poder atribu\u00c3\u00adda. +noWarpsDefined=\u00a76Nenhum warp definido. +none=nada +notAllowedToQuestion=\u00a74Voc\u00c3\u00aa nao tem permissao para usar a pergunta. +notAllowedToShout=\u00a74Voc\u00c3\u00aa nao tem permissao para gritar. +notEnoughExperience=\u00a74Voc\u00c3\u00aa nao tem experi\u00c3\u00aancia o suficiente. +notEnoughMoney=\u00a74Voc\u00c3\u00aa nao tem dinheiro o suficiente. +notFlying=nao est\u00c3\u00a1 voando +notRecommendedBukkit=\u00a74* \! * Versao do Bukkit nao \u00c3\u00a9 recomendada para essa versao do Essentials. +notSupportedYet=Nao suportado ainda. +nothingInHand=\u00a74Voc\u00c3\u00aa nao tem nada em sua mao. +now=agora +nuke=\u00a75Pode chover a morte sobre eles. +numberRequired=Vai um n\u00c3\u00bamero a\u00c3\u00ad, seu bobo. +onlyDayNight=/time suporta apenas day/night. +onlyPlayerSkulls=\u00a74Voc\u00ea s\u00f3 pode definir o propriet\u00e1rio de cr\u00e2nios de jogador (\u00a7c397\:3\u00a74). +onlyPlayers=\u00a74Apenas jogadores in-game podem usar \u00a7c{0}\u00a74. +onlySunStorm=\u00a74/weather suporta apenas sun/storm. +orderBalances=\u00a76Organizando saldos de\u00a7c {0} \u00a76usu\u00c3\u00a1rios, aguarde... +oversizedTempban=\u00a74Voc\u00c3\u00aa nao pode banir um jogador por esse per\u00c3\u00adodo de tempo. +pTimeCurrent=\u00a76O tempo para \u00a7c{0}\u00a76 \u00c3\u00a9 \u00a7c {1}\u00a76. +pTimeCurrentFixed=\u00a76O tempo para \u00a7c{0}\u00a76 foi arrumado para\u00a7c {1}\u00a76. +pTimeNormal=\u00a76O tempo de \u00a7c{0}\u00a76 est\u00c3\u00a1 normal e correspondendo ao do servidor. +pTimeOthersPermission=\u00a74Voc\u00c3\u00aa nao tem permissao para definir o tempo de outros jogadores. +pTimePlayers=\u00a76Esses jogadores tem seus pr\u00c3\u00b3prios tempos\:\u00a7r +pTimeReset=\u00a76O tempo do jogador foi resetado para\: \u00a7c{0} +pTimeSet=\u00a76Tempo do jogador definido em \u00a7c{0}\u00a76 para\: \u00a7c{1}. +pTimeSetFixed=\u00a76Tempo do jogador arrumado em \u00a7c{0}\u00a76 para\: \u00a7c{1}. +pWeatherCurrent=\u00a7c{0}\u00a76 clima \u00e9\u00a7c {1}\u00a76. +pWeatherInvalidAlias=Tipo de clima \u00a74 Inv\u00e1lido +pWeatherNormal=Clima \u00a7c{0}\u00a76 est\u00e1 normal e coincide com o servidor. +pWeatherOthersPermission=\u00a74Voc\u00ea n\u00e3o est\u00e3o autorizados a definir o tempo dos outros jogadores. +pWeatherPlayers=\u00a76Estes jogadores possuem seu pr\u00f3prio clima\:\u00a7r +pWeatherReset=\u00a76O clima do jogador foi restaurado para\: \u00a7c{0} +pWeatherSet=\u00a76O clima do jogador foi definido para \u00a7c{0}\u00a76 por\: \u00a7c{1}. +pendingTeleportCancelled=\u00a74Pedido de teleporte cancelado. +playerBanIpAddress=\u00a76Player\u00a7c {0} \u00a76banned IP address\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerBanned=\u00a76Jogador\u00a7c {0} \u00a76banido\u00a7c {1} \u00a76por \u00a7c{2}\u00a76. +playerInJail=\u00a74Jogador atualmente na cadeia\u00a7c {0}\u00a74. +playerJailed=\u00a76JogadorPlayer\u00a7c {0} \u00a76preso. +playerJailedFor=\u00a76Jogador\u00a7c {0} \u00a76preso por {1}. +playerKicked=\u00a76Jogador\u00a7c {0} \u00a76kickou {1} por {2}. +playerMuted=\u00a76Voc\u00c3\u00aa foi silenciado\! +playerMutedFor=\u00a76Voc\u00c3\u00aa foi mutado por\u00a7c {0}. +playerNeverOnServer=\u00a74Jogador\u00a7c {0} \u00a74nunca esteve nesse servidor. +playerNotFound=\u00a74Jogador nao encontrado. +playerUnbanIpAddress=\u00a76Jogador\u00a7c {0} \u00a76desbaniu o IP\: {1}. +playerUnbanned=\u00a76Jogador\u00a7c {0} \u00a76desbaniu\u00a7c {1}. +playerUnmuted=\u00a76Voc\u00c3\u00aa nao est\u00c3\u00a1 mais silenciado. +pong=Pong\! +posPitch=\u00a76Pitch\: {0} (Angulo da Cabe\u00c3\u00a7a) +posX=\u00a76X\: {0} (+Leste <-> -Oeste) +posY=\u00a76Y\: {0} (+Cima <-> -Baixo) +posYaw=\u00a76Yaw\: {0} (Rota\u00c3\u00a7ao) +posZ=\u00a76Z\: {0} (+Sul <-> -Norte) +possibleWorlds=\u00a76Possible worlds are the numbers \u00a7c0\u00a76 through \u00a7c{0}\u00a76. +potions=\u00a76Po\u00c3\u00a7oes\:\u00a7r {0}\u00a76. +powerToolAir=\u00a74O comando nao pode ser atribu\u00c3\u00addo ao ar. +powerToolAlreadySet=\u00a74Comando \u00a7c{0}\u00a74 J\u00e1 Foi Atribuido to \u00a7c{1}\u00a74. +powerToolAttach=\u00a7c{0}\u00a76 comando atribu\u00c3\u00addo a {1}. +powerToolClearAll=\u00a76Todos as ferramentas de poder foram removidas. +powerToolList=\u00a76Item \u00a7c{1} \u00a76tem os seguintes comandos\: \u00a7c{0}\u00a76. +powerToolListEmpty=\u00a74Item \u00a7c{0} \u00a74nao tem comandos atribu\u00c3\u00addos. +powerToolNoSuchCommandAssigned=\u00a74Command \u00a7c{0}\u00a74 has not been assigned to \u00a7c{1}\u00a74. +powerToolRemove=\u00a76Esse Comando\u00a7c{0}\u00a76 Foi Removido \u00a7c{1}\u00a76. +powerToolRemoveAll=\u00a76All commands removed from \u00a7c{0}\u00a76. +powerToolsDisabled=\u00a76Todas as suas ferramentas de poder foram desativadas. +powerToolsEnabled=\u00a76Todas as suas ferramentas de poder foram ativadas. +questionFormat=\u00a72[Pergunta]\u00a7r {0} +readNextPage=\u00a76Digite\u00a7c /{0} {1} \u00a76para ler a pr\u00c3\u00b3xima p\u00c3\u00a1gina. +recipe=\u00a76Recipe for \u00a7c{0}\u00a76 (\u00a7c{1}\u00a76 of \u00a7c{2}\u00a76) +recipeBadIndex=Nao h\u00c3\u00a1 receita para esse n\u00c3\u00bamero. +recipeFurnace=\u00a76Smelt\: \u00a7c{0}\u00a76. +recipeGrid=\u00a7c{0}X \u00a76| \u00a7{1}X \u00a76| \u00a7{2}X +recipeGridItem=\u00a7c{0}X \u00a76\u00e9 \u00a7c{1} +recipeMore=\u00a76Digite /{0} \u00a7c{1}\u00a76 para ver outras receitas para \u00a7c{2}\u00a76. +recipeNone=Nao h\u00c3\u00a1 receitas para {0} +recipeNothing=nada +recipeShapeless=\u00a76Combinar \u00a7c{0} +recipeWhere=\u00a76Onde\: {0} +removed=\u00a7c{0} \u00a76entidades removidas. +repair=\u00a76Voc\u00ea reparou seu \u00a7c{0}\u00a76 com sucesso. +repairAlreadyFixed=\u00a74Esse item nao precisa de reparo. +repairEnchanted=\u00a74Voc\u00c3\u00aa nao tem permissao para reparar itens encantados. +repairInvalidType=\u00a74Esse item nao pode ser reparado. +repairNone=\u00a74N\u00e3o haviam itens para serem reparados. +requestAccepted=\u00a76Pedido de teleporte aceito. +requestAcceptedFrom=\u00a7c{0} \u00a76aceitou seu pedido de teleporte. +requestDenied=\u00a76Pedido de teleporte negado. +requestDeniedFrom=\u00a7c{0} \u00a76negou seu pedido de teleporte. +requestSent=\u00a76Pedido enviado para\u00a7c {0}\u00a76. +requestTimedOut=\u00a74Pedido de teleporte se esgotou. +requiredBukkit=\u00a76* \! * Voc\u00c3\u00aa precisa de pelo menos a constru\u00c3\u00a7ao {0} do CraftBukkit, baixe-a em http\://dl.bukkit.org/downloads/craftbukkit/ +resetBal=\u00a76Balance has been reset to \u00a7c{0} \u00a76for all online players. +resetBalAll=\u00a76Balance has been reset to \u00a7c{0} \u00a76for all players. +returnPlayerToJailError=\u00a74Error occurred when trying to return player\u00a7c {0} \u00a74to jail\: \u00a7c{1}\u00a74\! +runningPlayerMatch=\u00a76Realizando busca por jogadores correspodentes a ''\u00a7c{0}\u00a76'' (isso pode levar um tempo) +second=segundo +seconds=segundos +seenOffline=\u00a76Jogador\u00a7c {0} \u00a76est\u00e1 \u00a74offline\u00a76 desde \u00a7c{1}\u00a76. +seenOnline=\u00a76Jogador\u00a7c {0} \u00a76est\u00e1 \u00a7aonline\u00a76 desde \u00a7c{1}\u00a76. +serverFull=Servidor cheio\! +serverTotal=\u00a76Total do Servidor\:\u00a7c {0} +setBal=\u00a7aSeu saldo foi definido para {0}. +setBalOthers=\u00a7aVoc\u00ea configurou o seu balan\u00e7o atual de {0}\u00a7a para {1}. +setSpawner=\u00a76Changed spawner type to\u00a7c {0}\u00a76. +sheepMalformedColor=\u00a74Cor mal especificada. +shoutFormat=\u00a77[\u00a73G\u00a77]\u00a7r {0} +signFormatFail=\u00a74[{0}] +signFormatSuccess=\u00a71[{0}] +signFormatTemplate=[{0}] +signProtectInvalidLocation=\u00a74Voc\u00c3\u00aa nao tem permissao para criar placas aqui. +similarWarpExist=\u00a74Um warp com um nome similar j\u00c3\u00a1 existe. +slimeMalformedSize=\u00a74Tamanho mal especificado. +socialSpy=\u00a76SocialSpy for \u00a7c{0}\u00a76\: \u00a7c{1} +soloMob=\u00a74Esse mob gosta de ficar sozinho. +spawnSet=\u00a76Ponto de Spawn definido para o grupo\u00a7c {0}\u00a76. +spawned=spawnado +sudoExempt=\u00a74Voc\u00c3\u00aa nao pode usar sudo nesse usu\u00c3\u00a1rio. +sudoRun=\u00a76Forcing\u00a7c {0} \u00a76to run\:\u00a7r /{1} +suicideMessage=\u00a76Adeus mundo cruel... +suicideSuccess=\u00a76{0} \u00a76se matou. +survival=sobreviv\u00c3\u00aancia +takenFromAccount=\u00a7a{0} foi removido sua conta. +takenFromOthersAccount=\u00a7a{0} foi removido da conta de {1}\u00a7a. Novo saldo\: {2}. +teleportAAll=\u00a76Pedido de teleporte enviado para todos os jogadores... +teleportAll=\u00a76Teleportando todos os jogadores... +teleportAtoB=\u00a7c{0}\u00a76 teleportou voc\u00ea para \u00a7c{1}\u00a76. +teleportDisabled=\u00a7c{0} \u00a74est\u00c3\u00a1 com teleporte desativado. +teleportHereRequest=\u00a7c{0}\u00a76 pediu para que se teleporte at\u00c3\u00a9 ele. +teleportNewPlayerError=\u00a74Falha ao teleportar novo jogador\! +teleportRequest=\u00a7c{0}\u00a76 pediu para teleportar at\u00c3\u00a9 voc\u00c3\u00aa. +teleportRequestTimeoutInfo=\u00a76Esse pedido ir\u00c3\u00a1 se esgotar depois de\u00a7c {0} segundos\u00a76. +teleportTop=\u00a76Teleportando para o topo. +teleportationCommencing=\u00a76Teleportando iniciando... +teleportationDisabled=\u00a76Teleportation \u00a7cdisabled\u00a76. +teleportationDisabledFor=\u00a76Teleportation \u00a7cdisabled \u00a76for \u00a7c{0}\u00a76. +teleportationEnabled=\u00a76Teleportation \u00a7cenabled\u00a76. +teleportationEnabledFor=\u00a76Teleportation \u00a7cenabled \u00a76for \u00a7c{0}\u00a76. +teleporting=\u00a76Teleportando... +teleportToPlayer=\u00a76Teleporting to \u00a7c{0}\u00a76. +tempBanned=\u00a7cYou have been temporarily banned for {0}\:\n\u00a7r{2} +tempbanExempt=\u00a74Voc\u00c3\u00aa nao pode banir temporariamente esse jogador. +thunder=\u00a76Voc\u00c3\u00aa\u00a7c {0} \u00a76trovoada em seu mundo. +thunderDuration=\u00a76Voc\u00c3\u00aa\u00a7c {0} \u00a76trovoada em seu mundo por\u00a7c {1} \u00a76segundos. +timeBeforeHeal=\u00a76Tempo antes da pr\u00c3\u00b3xima cura\:\u00a7c {0}\u00a76. +timeBeforeTeleport=\u00a76Tempo antes do pr\u00c3\u00b3ximo teleporte\:\u00a7c {0} +timeFormat=\u00a7c{0}\u00a76 or \u00a7c{1}\u00a76 or \u00a7c{2}\u00a76 +timeSetPermission=\u00a74Voc\u00c3\u00aa nao tem permissao para definir o tempo. +timeWorldCurrent=\u00a76O tempo atual em\u00a7c {0} \u00a76\u00c3\u00a9 \u00a7c{1}\u00a76. +timeWorldSet=\u00a76O tempo foi definido para\u00a7c {0} \u00a76em\: \u00a7c{1}\u00a76. +totalWorthAll=\u00a7aTodos os itens e blocos foram vendidos por um total de \u00a7c{1}\u00a7a. +totalWorthBlocks=\u00a7aTodos os blocos foram vendidos por um total de \u00a7c{1}\u00a7a. +tps=\u00a76TPS Atual \= {0} +tradeSignEmpty=\u00a74A placa de troca nao tem nada dispon\u00c3\u00advel para voc\u00c3\u00aa. +tradeSignEmptyOwner=\u00a74Nao h\u00c3\u00a1 nada para coletar dessa placa de troca. +treeFailure=\u00a74Erro ao gerar \u00c3\u00a1rvore. Tente novamente na terra ou na grama. +treeSpawned=\u00a76Arvore gerada. +true=\u00a7averdadeiro\u00a7r +typeTpaccept=\u00a76Para teleportar, digite \u00a7c/tpaccept\u00a76. +typeTpdeny=\u00a76Para recusar o pedido, digite \u00a7c/tpdeny\u00a76. +typeWorldName=\u00a76Voc\u00c3\u00aa pode tamb\u00c3\u00a9m digitar o nome de um mundo espec\u00c3\u00adfico. +unableToSpawnMob=\u00a74Incapaz de spawnar o mob. +unignorePlayer=\u00a76Voc\u00c3\u00aa nao est\u00c3\u00a1 mais ignorando o jogador\u00a7c {0} \u00a76. +unknownItemId=\u00a74ID do item inv\u00c3\u00a1lido\: \u00a7r {0}\u00a74. +unknownItemInList=\u00a74Iten desconhecido {0} na lista {1}. +unknownItemName=\u00a74Nome de item desconhecido\: {0}. +unlimitedItemPermission=\u00a74Sem permiss\u00e3o para item \u00a7c{0}\u00a74 ilimitado. +unlimitedItems=\u00a76Itens ilimitados\:\u00a7r +unmutedPlayer=\u00a76Jogador\u00a7c {0} \u00a76nao est\u00c3\u00a1 mais silenciado. +unvanishedReload=\u00a74Um reload for\u00c3\u00a7ou-lhe a ficar vis\u00c3\u00advel novamente. +upgradingFilesError=Erro ao aprimorar os arquivos. +uptime=\u00a76Uptime\:\u00a7c {0} +userAFK=\u00a75{0} \u00a75est\u00c3\u00a1 atualmente AFK e pode nao responder. +userDoesNotExist=\u00a74O usu\u00c3\u00a1rio\u00a7c {0} \u00a74nao existe. +userIsAway=\u00a75{0} \u00a75est\u00c3\u00a1 agora AFK. +userIsNotAway=\u00a75{0} \u00a75nao est\u00c3\u00a1 mais AFK. +userJailed=\u00a76Voc\u00c3\u00aa foi condenado\! +userUnknown=\u00a74Aviso\: O usu\u00c3\u00a1rio ''\u00a7c{0}\u00a74'' nunca entrou nesse servidor. +userdataMoveBackError=Falha ao mover o userdata/{0}.tmp para userdata/{1}\! +userdataMoveError=Falha ao mover userdata/{0} para userdata/{1}.tmp\! +usingTempFolderForTesting=Usando pasta tempor\u00c3\u00a1ria para teste\: +vanished=\u00a76Voc\u00c3\u00aa est\u00c3\u00a1 agora completamente invis\u00c3\u00advel para jogadores normais, e escondido de comandos in-game. +versionMismatch=\u00a74Versao nao correspondente\! Por favor atualize o {0} para a mesma versao. +versionMismatchAll=\u00a74Versao nao correspondente\! Por favor atualize todos os jars do Essentials para a mesma versao. +voiceSilenced=\u00a76Sua voz foi silenciada\! +walking=caminhando +warpDeleteError=\u00a74Problema ao deletar o arquivo do warp. +warpList={0} +warpListPermission=\u00a74Voce nao tem permissao para listar os warps. +warpNotExist=\u00a74Esse warp nao existe. +warpOverwrite=\u00a74Voce nao pode sobreescrever esse warp. +warpSet=\u00a76Warp\u00a7c {0} \u00a76definido. +warpUsePermission=\u00a74Voce nao tem permissao para usar esse warp. +warpingTo=\u00a76Teleportando para\u00a7c {0}\u00a76. +warps=\u00a76Warps\:\u00a7r {0} +warpsCount=\u00a76There are\u00a7c {0} \u00a76warps. Showing page \u00a7c{1} \u00a76of \u00a7c{2}\u00a76. +weatherStorm=\u00a76Voc\u00c3\u00aa definiu o tempo para \u00a7ctempestade\u00a76 em\u00a7c {0}\u00a76. +weatherStormFor=\u00a76Voc\u00c3\u00aa definiu o tempo para \u00a7ctempestade\u00a76 em\u00a7c {0} \u00a76por {1} segundos. +weatherSun=\u00a76Voc\u00c3\u00aa definiu o tempo para \u00a7csol\u00a76 em\u00a7c {0}\u00a76. +weatherSunFor=\u00a76Voc\u00ea definiu o tempo para \u00a7csun\u00a76 em\u00a7c {0} \u00a76por {1} segundos. +whoisAFK=\u00a76 - AFK\:\u00a7r {0} +whoisBanned=\u00a76 - Banido\:\u00a7r {0} +whoisExp=\u00a76 - Exp\:\u00a7r {0} (N\u00c3\u00advel {1}) +whoisFly=\u00a76 - Modo Fly\:\u00a7r {0} ({1}) +whoisGamemode=\u00a76 - Modo de Jogo\:\u00a7r {0} +whoisGeoLocation=\u00a76 - Localiza\u00c3\u00a7ao\:\u00a7r {0} +whoisGod=\u00a76 - Modo deus\:\u00a7r {0} +whoisHealth=\u00a76 - Vida\:\u00a7r {0}/20 +whoisIPAddress=\u00a76 - Endere\u00c3\u00a7o IP\:\u00a7r {0} +whoisJail=\u00a76 - Na cadeia\:\u00a7r {0} +whoisLocation=\u00a76 - Localiza\u00c3\u00a7ao\:\u00a7r ({0}, {1}, {2}, {3}) +whoisMoney=\u00a76 - Dinheiro\:\u00a7r {0} +whoisMuted=\u00a76 - Silenciado\:\u00a7r {0} +whoisNick=\u00a76 - Apelido\:\u00a7r {0} +whoisOp=\u00a76 - OP\:\u00a7r {0} +whoisTop=\u00a76 \=\=\=\=\=\= Quem\u00c3\u0089\:\u00a7c {0} \u00a76\=\=\=\=\=\= +worth=\u00a7aPack de {0} vale \u00a7c{1}\u00a7a ({2} a {3} cada) +worthMeta=\u00a7aPack de {0} com metadata de {1} vale \u00a7c{2}\u00a7a ({3} a {4} cada) +worthSet=\u00a76Valor definido +year=ano +years=anos +youAreHealed=\u00a76Voc\u00c3\u00aa foi curado. +youHaveNewMail=\u00a76Voc\u00c3\u00aa tem\u00a7c {0} \u00a76mensagens\! Digite \u00a7c/mail read\u00a76 para v\u00c3\u00aa-las. +whoisHunger=\u00a76 - Fome\:\u00a7r {0}/20 (+{1} satura\u00e7\u00e3o) +kitDelay=\u00a7m{0}\u00a7r +giveSpawnFailure=\u00a74N\u00e3o tem espa\u00e7o, \u00a7c{0} \u00a7c{1} \u00a74 foi perdido. +noKitGroup=\u00a74Voc\u00ea n\u00e3o tem acesso \u00e0 este kit. +inventoryClearingFromAll=\u00a76Esvaziando os invent\u00e1rios de todos os usu\u00e1rios... +inventoryClearingAllItems=\u00a76Limpou todos os itens do invent\u00e1rio de {0}\u00a76. +inventoryClearingAllArmor=\u00a76Limpou todos os itens do invent\u00e1rio e armaduras de {0}\u00a76.\u00a0 +inventoryClearingAllStack=\u00a76Limpou todos \u00a7c {0} \u00a76de {1}\u00a76. +inventoryClearingStack=\u00a76Removido\u00a7c {0} \u00a76de\u00a7c {1} \u00a76de {2}\u00a76. +inventoryClearFail=\u00a74Jogador {0} \u00a74n\u00e3o tem \u00a7c {1} \u00a74de\u00a7c {2}\u00a74. +localNoOne= +totalSellableAll=\u00a7aO valor total dos itens e blocos dispon\u00edveis para venda \u00e9 de \u00a7c{1}\u00a7a. +totalSellableBlocks=\u00a7aO valor total dos blocos dispon\u00edveis para venda \u00e9 de \u00a7c{1}\u00a7a. +radiusTooBig=\u00a74O raio e muito grande. O raio maximo permitido \u00e9 de {0}. +isIpBanned=\u00a76IP \u00a7c{0} \u00a76 esta banido. +mobDataList=\u00a76Dados do mob validos\:\u00a7r {0} +vanish=\u00a76Invisivel para {0}\u00a76\: {1} +noLocationFound=\u00a74Nenhuma localizacao valida encontrada. +coordsKeyword={0}, {1}, {2} +banExemptOffline=\u00a74Voce nao pode banir jogadores desconectados. +tempbanExemptOffline=\u00a74Voce nao pode banir temporariamente jogadores desconectados. +mayNotJailOffline=\u00a74Voce nao pode prender jogadores desconectados. +muteExemptOffline=\u00a74Voce nao pode silenciar jogadores desconectados. +ignoreExempt=\u00a74Voce nao pode ignorar aquele jogador. +unsafeTeleportDestination=\u00a74O destino de teleporte \u00e9 inseguro teleporte-seguran\u00e7a est\u00e1 desabilitado. +noMetaJson=Metadata JSON n\u00e3o \u00e9 suportado nesta vers\u00e3o do Bukkit. +maxMoney=\u00a74Esta transa\u00e7\u00e3o iria exceder o limite de saldo para esta conta. +skullChanged=\u00a76Skull changed to \u00a7c{0}\u00a76. +alphaNames=\u00a74Nomes de jogadores s\u00f3 podem conter letras, n\u00fameros e sublinhados. +givenSkull=\u00a76Voc\u00ea recebeu o cr\u00e2nio do 6\u00ba par\u00e1grafo \u00a7c {0}. +noPermissionSkull=\u00a74Voc\u00ea n\u00e3o tem permiss\u00e3o para modificar esse cr\u00e2nio. +teleportInvalidLocation=Valor de coordenadas n\u00e3o pode ser mais 30000000 +invalidSkull=\u00a74Por favor,segure um cr\u00e2nio do Jogador. +weatherInvalidWorld=Mundo chamado de {0} n\u00e3o foi encontrado\! +gameModeInvalid=\u00a74Voc\u00ea precisa especificar um jogador/modo v\u00e1lido. +mailTooLong=\u00a74Mail message too long. Try to keep it below 1000 characters. +mailDelay=Muitos e-mails foram enviados no \u00faltimo minuto. M\u00e1ximo\: {0} +seenAccounts=\u00a76Player has also been known as\:\u00a7c {0} +unableToSpawnItem=\u00a74Cannot spawn \u00a7c{0}\u00a74, this is not a spawnable item. +itemsConverted=\u00a76Converted all items into blocks. +itemsNotConverted=\u00a74You have no items that can be converted into blocks. +mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\: +mailMessage={0} + +whoisTempBanned=\u00a76 - Ban expires:\u00a7r {0} +playerTempBanned=\u00a76Player \u00a7c{0}\u00a76 temporarily banned \u00a7c{1}\u00a76 for \u00a7c{2}\u00a76: \u00a7c{3}\u00a76. +mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1} diff --git a/Essentials/src/messages_pt_BR.properties b/Essentials/src/messages_pt_BR.properties new file mode 100644 index 0000000000..d989429d5a --- /dev/null +++ b/Essentials/src/messages_pt_BR.properties @@ -0,0 +1,558 @@ +#X-Generator: crowdin.net +#version: TeamCity +# Single quotes have to be doubled: '' +# Translations start here +# by: +action=\u00a75* {0} \u00a75{1} +addedToAccount=\u00a7a{0} foi adicionado em sua conta. +addedToOthersAccount=\u00a7a{0} foi adicionado na conta de {1}\u00a7a. Novo saldo\: {2} +adventure=aventura +alertBroke=quebrado\: +alertFormat=\u00a73[{0}] \u00a7r {1} \u00a76 {2} em\: {3} +alertPlaced=colocado\: +alertUsed=usado\: +antiBuildBreak=\u00a74Voce nao tem permissao para quebrar\u00a7c {0} \u00a74blocos aqui. +antiBuildCraft=\u00a74Voce nao tem permissao para create\u00a7c {0}\u00a74. +antiBuildDrop=\u00a74Voce nao tem permissao para dropar\u00a7c {0}\u00a74. +antiBuildInteract=\u00a74Voce nao tem permissao para interagir com\u00a7c {0}\u00a74. +antiBuildPlace=\u00a74Voce nao tem permissao para colocar\u00a7c {0} \u00a74aqui. +antiBuildUse=\u00a74Voce nao tem permissao para usar\u00a7c {0}\u00a74. +autoAfkKickReason=Voce foi kickado por ficar parado por mais de {0} minutos. +backAfterDeath=\u00a76Digite /back para retornar onde morreu. +backUsageMsg=\u00a76Voltando ao local anterior. +backupDisabled=\u00a74Um script externo nao foi configurado. +backupFinished=\u00a76Backup acabou. +backupStarted=\u00a76Backup Iniciado. +balance=\u00a7aSaldo\:\u00a7c {0} +balanceOther=\u00a7aSaldo de {0}\u00a7a\:\u00a7c {1} +balanceTop=\u00a76Mais ricos ({0}) +banExempt=\u00a74Voce nao pode banir este jogador. +banFormat=\u00a74Banido por\:\n\u00a7r{0} +bed=\u00a7ocama\u00a7r +bedMissing=\u00a74Sua cama nao foi definida, esta corrompida ou esta bloqueada. +bedNull=\u00a7mcama\u00a7r +bedSet=\u00a76Cama definida\! +bigTreeFailure=\u00a74Falha ao gerar uma Arvore grande. Tente novamente na grama ou na terra. +bigTreeSuccess=\u00a76Arvore grande gerada. +blockList=\u00a76Essentials passou os seguintes comandos para outro plugin\: +bookAuthorSet=\u00a76Autor do livro definido para {0}. +bookLocked=\u00a76O livro esta trancado agora. +bookTitleSet=\u00a76T\u00c3\u00adtulo do livro definido para {0}. +broadcast=\u00a7r\u00a76 [\u00a74Transmiss\u00e3o\u00a76] \u00a7a {0} +buildAlert=\u00a74Voce nao tem permissao para construir. +bukkitFormatChanged=Formato da versao do Bukkit alterada. Versao nao verificada. +burnMsg=\u00a76Voce colocou fogo em\u00a7c {0} \u00a76por\u00a7c {1} segundos\u00a76. +canTalkAgain=\u00a76Voce pode falar novamente. +cannotStackMob=\u00a74Voce nao tem permissao para criar varios mobs. +cantFindGeoIpDB=Nao foi possivel encontrar dados de GeoIP\! +cantReadGeoIpDB=Falha ao ler o banco de dados do GeoIP\! +cantSpawnItem=\u00a74Voce nao tem permissao para gerar o item\u00a7c {0}\u00a74. +chatTypeAdmin=[A] +chatTypeLocal=[L] +chatTypeSpy=[Espiao] +cleaned=Os arquivos do usuario foram apagados. +cleaning=Apagando arquivos do usuario. +commandFailed=Comando {0} falhou\: +commandHelpFailedForPlugin=Erro ao adquirir ajuda do plugin\: {0} +commandNotLoaded=\u00a74Comando {0} esta carregado incorretamente. +compassBearing=\u00a76Apontado para\: {0} ({1} graus). +configFileMoveError=Falha ao mover a config.yml para o local do backup. +configFileRenameError=Falha ao renomear o arquivo temporario para config.yml. +connectedPlayers=\u00a76Jogadores conectados\u00a7r +connectionFailed=Falha ao conectar. +cooldownWithMessage=\u00a74Tempo restante\: {0} +corruptNodeInConfig=\u00a74Noti\u00adcia\: Seu arquivo de configuracao esta corrompido ({0}). +couldNotFindTemplate=\u00a74Template nao encontrado {0} +creatingConfigFromTemplate=Criando configuracao baseado no modelo\: {0} +creatingEmptyConfig=Criando configuracao vazia\: {0} +creative=criativo +currency={0}{1} +currentWorld=\u00a76Mundo Atual\:\u00a7c {0} +day=dia +days=dias +defaultBanReason=O Martelo Proibicao falou\! +deleteFileError=Nao p\u00c3\u00b4de deletar o arquivo\: {0} +deleteHome=\u00a76Casa\u00a7c {0} \u00a76foi removida. +deleteJail=\u00a76Cadeia\u00a7c {0} \u00a76foi removida. +deleteWarp=\u00a76Warp\u00a7c {0} \u00a76foi removido. +deniedAccessCommand=\u00a7c{0} \u00a74foi negado a utilizar o comando. +denyBookEdit=\u00a74Voce nao pode destravar este livro. +denyChangeAuthor=\u00a74Voce nao pode mudar o autor deste livro. +denyChangeTitle=\u00a74Voce nao pode mudar o titulo deste livro. +depth=\u00a76Voce esta no nivel do mar. +depthAboveSea=\u00a76Voce esta a\u00a7c {0} \u00a76bloco(s) acima do ni\u00advel do mar. +depthBelowSea=\u00a76Voce esta a\u00a7c {0} \u00a76bloco(s) abaixo do ni\u00advel do mar. +destinationNotSet=Destino nao definido\! +disableUnlimited=\u00a76Permissao de colocar coisas ilimitadas desativada para\u00a7c {0} \u00a76por {1}. +disabled=desativou +disabledToSpawnMob=\u00a74Spawnar este mob foi desativado na configuracao. +distance=\u00a76Distancia\: {0} +dontMoveMessage=\u00a76Teleporte ira come\u00e7ar em\u00a7c {0}\u00a76. Nao se mova. +downloadingGeoIp=Baixando o banco de dados GeoIP... isso pode levar um tempo (pa\u00c3\u00ads\: 0.6 MB, cidade\: 20MB) +duplicatedUserdata=Dados do usuario dupliacado\: {0} e {1}. +durability=\u00a76Esse ferramenta ainda pode ser usada mais \u00a7c{0}\u00a76 vezes +editBookContents=\u00a7eVoce pode agora editar o conteudo deste livro. +enableUnlimited=\u00a76Dando quantidade ilimidada de\u00a7c {0} \u00a76para \u00a7c{1}\u00a76. +enabled=ativou +enchantmentApplied=\u00a76O encantamento\u00a7c {0} \u00a76foi aplicado ao item em sua mao. +enchantmentNotFound=\u00a74Encantamento nao encontrado\! +enchantmentPerm=\u00a74Voce nao tem permissao para\u00a7c {0}\u00a74. +enchantmentRemoved=\u00a76O encantamento\u00a7c {0} \u00a76foi removido do item em sua mao. +enchantments=\u00a76Encantamentos\:\u00a7r {0} +errorCallingCommand=Erro ao usar o comando /{0} +errorWithMessage=\u00a7cErro\:\u00a74 {0} +essentialsHelp1=O arquivo est\u00c3\u00a1 corrompido e o Essentials nao consegue abr\u00c3\u00ad-lo. Essentials desativado. Se voc\u00c3\u00aa nao consegue arrumar o arquivo sozinho, acesse http\://tiny.cc/EssentialsChat +essentialsHelp2=O arquivo esta corrompido e o Essentials nao consegue abri\u00ad-lo. Essentials desativado. Se voce nao consegue arrumar o arquivo sozinho, digite /essentialshelp no jogo ou acesse http\://tiny.cc/EssentialsChat +essentialsReload=\u00a76Essentials recarregado\u00a7c {0}. +exp=\u00a7c{0} \u00a76tem\u00a7c {1} \u00a76de exp (n\u00c3\u00advel\u00a7c {2}\u00a76) e precisa de\u00a7c {3} \u00a76mais exp para subir de n\u00c3\u00advel. +expSet=\u00a7c{0} \u00a76agora tem\u00a7c {1} \u00a76de exp. +extinguish=\u00a76Voce se extinguiu. +extinguishOthers=\u00a76Voce extinguiu {0}\u00a76. +failedToCloseConfig=Falha ao fechar a configuracao {0}. +failedToCreateConfig=Falha ao criar a configuracao {0}. +failedToWriteConfig=Falha ao escrever a configuracao {0}. +false=\u00a74falso\u00a7r +feed=\u00a76Seu apetite foi saciado. +feedOther=\u00a76Voc\u00ea saciou a fome de {0}\u00a76. +fileRenameError=Falha ao renomear o arquivo {0}\! +fireworkColor=\u00a74Parametros inseridos para criar um fogo de artifi\u00adcio invalidos. Defina um cor antes. +fireworkEffectsCleared=\u00a76Todos os efeitos deste pack foram removidos. +fireworkSyntax=\u00a76Parametros do fogo de artifi\u00adcio\:\u00a7c color\: [fade\:] [shape\:] [effect\:]\n\u00a76Para usar multiplas cores ou efeitos, separe-os entre vi\u00adrgulas\: \u00a7cred,blue,pink\n\u00a76Formatos\:\u00a7c star, ball, large, creeper, burst \u00a76Efeitos\:\u00a7c trail, twinkle. +flyMode=\u00a76Modo Voar foi\u00a7c {0} \u00a76para {1}\u00a76. +flying=voando +foreverAlone=\u00a74Voce nao tem ninguem a quem responder. +fullStack=\u00a74Voce ja tem um pack completo. +gameMode=\u00a76Modo de jogo\u00a7c {0} \u00a76definido para {1}\u00a76. +gcWorld=\u00a76 {0} "\u00a7c {1} \u00a76"\: \u00a7c {2} \u00a76 peda\u00e7os, \u00a7c {3} \u00a76 unidades, \u00a7c {4} \u00a76 telhas. +gcfree=\u00a76Mem\u00c3\u00b3ria livre\:\u00a7c {0} MB. +gcmax=\u00a76Memoria maxima\:\u00a7c {0} MB. +gctotal=\u00a76Mem\u00c3\u00b3ria alocada\:\u00a7c {0} MB. +geoIpUrlEmpty=URL de download do GeoIP esta vazio. +geoIpUrlInvalid=URL de download do GeoIP invalido. +geoipJoinFormat=\u00a76Jogador \u00a7c{0} \u00a76vem de \u00a7c{1}\u00a76. +giveSpawn=\u00a76Dando\u00a7c {0}\u00a7c {1} \u00a76para\u00a7c {2}\u00a76. +godDisabledFor=\u00a7cdesabilitado\u00a76 para\u00a7c {0} +godEnabledFor=\u00a7aativado\u00a76 para\u00a7c {0}. +godMode=\u00a76Modo deus\u00a7c {0}\u00a76. +groupDoesNotExist=\u00a74Nao ha ninguem online nesse grupo\! +groupNumber=\u00a7c{0}\u00a7f online, para a lista completa\:\u00a7c /{1} {2} +hatArmor=\u00a74Voce nao pode usar esse item como chapeu\! +hatEmpty=\u00a74Voce nao esta usando chapeu. +hatFail=\u00a74Voce deve ter algo em sua mao para vestir. +hatPlaced=\u00a76Aproveite seu novo chapeu\! +hatRemoved=\u00a76Seu chapeu foi removido. +haveBeenReleased=\u00a76Voce foi liberado. +heal=\u00a76Voce foi curado. +healDead=\u00a74Voce nao pode curar alguem que esta morto\! +healOther=\u00a7c {0}\u00a76foi curado. +helpConsole=Para ver ajuda pelo console, digite ?. +helpFrom=\u00a76Comandos de {0}\: +helpLine=\u00a76/{0}\u00a7r\: {1} +helpMatching=\u00a76Comandos correspondidos com "\u00a7c{0}\u00a76"\: +helpOp=\u00a7 4\u00ba [AjudaOp] \u00a7r \u00a7 6 {0}\: \u00a7r {1} +helpPlugin=\u00a74{0}\u00a7r\: Ajuda do Plugin\: /help {1} +holdBook=\u00a74Voce nao esta segurando um livro que possa escrever. +holdFirework=\u00a74Voce deve estar segurando um fogo de artifi\u00adcio para adicionar efeitos. +holdPotion=\u00a74Voce deve estar segurando uma pocao para aplicar efeitos para ela. +holeInFloor=\u00a74Buraco no chao\! +homeSet=\u00a76Casa definida. +homes=\u00a76Casas\:\u00a7r {0} +hour=hora +hours=horas +ignoredList=\u00a76Ignorado\:\u00a7r {0} +ignorePlayer=\u00a76Voce esta agora ignorando o jogador\u00a7c {0} \u00a76. +illegalDate=Formate de data ilegal. +infoChapter=\u00a76Selecione o Cap\u00edtulo\: +infoChapterPages=\u00a7e ---- \u00a76{0} \u00a7e--\u00a76 P\u00e1gina \u00a7c{1}\u00a76 de \u00a7c{2} \u00a7e---- +infoPages=\u00a7e ---- \u00a76{2} \u00a7e--\u00a76 Pagina \u00a7c{0}\u00a76/\u00a7c{1} \u00a7e---- +infoUnknownChapter=\u00a74Cap\u00edtulo Desconhecido. +insufficientFunds=\u00a74Dinheiro insuficiente. +invalidCharge=\u00a74Argumento invalido. +invalidFireworkFormat=\u00a74A op\u00e7\u00e3o \u00a7c{0} \u00a74n\u00e3o \u00e9 v\u00e1lida para \u00a7c{1}\u00a74. +invalidHome=\u00a74Casa\u00a7c {0} \u00a74nao existe\! +invalidHomeName=\u00a74Nome de casa invalido\! +invalidMob=\u00a74Tipo de mob invalido. +invalidNumber=Numero invalido. +invalidPotion=\u00a74Pocao invalida. +invalidPotionMeta=\u00a74Meta invalida de pocao\: \u00a7c{0}\u00a74. +invalidSignLine=\u00a74Linha\u00a7c {0} \u00a74na placa esta invalida. +invalidWarpName=\u00a74Nome de warp invalido\! +invalidWorld=\u00a74Mundo invalido. +is=e +itemCannotBeSold=\u00a74Esse item nao pode ser vendido para o servidor. +itemMustBeStacked=\u00a74O item deve ser trocado em packs. A quantidade de 2 deveria ser 2 packs, etc. +itemNames=\u00a76Nomes pequenos para o item\:\u00a7r {0} +itemNotEnough1=\u00a74Voce nao itens o suficiente para vender. +itemNotEnough2=\u00a76Se voce quis vender todos os seus itens de um tipo, digite /sell nomedoitem. +itemNotEnough3=\u00a76/sell nomedoitem -1 ira vender tudo menos um item, etc. +itemSellAir=Vocerealmente tentou vender Ar? Coloque um item em sua mao. +itemSold=\u00a7aVendido por \u00a7c{0} \u00a7a({1} {2} a {3} cada). +itemSoldConsole=\u00a7a{0} \u00a7avendeu {1} por \u00a7a{2} \u00a7a({3} itens a {4} each). +itemSpawn=\u00a76Dando\u00a7c {0}\u00a7c {1} +itemType=\u00a76Item\:\u00a7c {0} \u00a76-\u00a7c {1} +itemsCsvNotLoaded=Nao p\u00c3\u00b4de carregar o items.csv\! +jailAlreadyIncarcerated=\u00a74Essa pessoa ja esta na cadeia\:\u00a7c {0} +jailMessage=\u00a74Voce foi condenado. Pense bem antes de fazer o que fez. +jailNotExist=\u00a74Essa cadeia nao existe. +jailReleased=\u00a76Jogador \u00a7c{0}\u00a76 liberado. +jailReleasedPlayerNotify=\u00a76Voce foi liberado\! +jailSentenceExtended=\u00a76Tempo na cadeia extendido para\: {0} +jailSet=\u00a76Cadeia\u00a7c {0} \u00a76foi definida. +jumpError=\u00a74Isso machucaria o cerebro do computador. +kickDefault=Kickado do servidor. +kickExempt=\u00a74Voce nao pode kickar essa pessoa. +kickedAll=\u00a74Todos os jogadores foram kickados. +kill=\u00a76Matou\u00a7c {0}\u00a76. +killExempt=\u00a74Voc\u00ea n\u00e3o pode matar \u00a7c{0}\u00a74. +kitCost=\ \u00a77\u00a7o({0})\u00a7r +kitError2=\u00a74Esse kit nao existe ou foi definido impropriamente. +kitError=\u00a74Nao ha kits validos. +kitGiveTo=\u00a76Dando o kit\u00a7c {0}\u00a76 para \u00a7c{1}\u00a76. +kitInvFull=\u00a74Seu inventario esta cheio, colocando o kit no chao. +kitNotFound=\u00a74Esse kit n\u00e3o existe. +kitOnce=\u00a74Voce nao pode usar esse kit novamente. +kitReceive=\u00a76Recebido kit\u00a7c {0}\u00a76. +kitTimed=\u00a74Voce nao pode usar esse kit novamente por\u00a7c {0}\u00a74. +kits=\u00a76Kits\:\u00a7r {0} +leatherSyntax=\u00a76Sintaxe das Cores do Couro\: color\:,, ex\: color\:255,0,0. +lightningSmited=\u00a76Foste ferido\! +lightningUse=\u00a76Castigando\u00a7c {0} +listAfkTag=\u00a77[Ausente]\u00a7r +listAmount=\u00a76Ha \u00a7c{0}\u00a76 de no maximo \u00a7c{1}\u00a76 jogadores online. +listAmountHidden=\u00a76Ha \u00a7c{0}\u00a76/{1}\u00a76 de no maximo \u00a7c{2}\u00a76 jogadores online. +listGroupTag=\u00a76{0}\u00a7r\: \u00a7r +listHiddenTag=\u00a77[ESCONDIDO]\u00a7r +loadWarpError=\u00a74Falha ao carregar o warp {0}. +localFormat=[L]<{0}> {1} +mailClear=\u00a76Para marcar seus e-mails como lidos, digite\u00a7c /mail clear\u00a76. +mailCleared=\u00a76E-mails Removidos\! +mailSent=\u00a76E-mail enviado\! +markMailAsRead=\u00a76Para marcar seus e-mails como lidos, digite\u00a7c /mail clear\u00a76. +markedAsAway=\u00a76Voce esta agora marcado como ausente. +markedAsNotAway=\u00a76Voce nao esta mais marcado como ausente. +matchingIPAddress=\u00a76Os seguintes jogadores logaram com esse endereco de IP\: +maxHomes=\u00a74Voce nao pode definir mais de\u00a7c {0} \u00a74casas. +mayNotJail=\u00a74Voce nao pode prender essa pessoa\! +me=eu +minute=minuto +minutes=minutos +missingItems=\u00a74Voc\u00ea n\u00e3o tem \u00a7c{0}x {1}\u00a74. +mobSpawnError=\u00a74Erro ao mudar o mob spawner. +mobSpawnLimit=Quantidade de mobs aumentada ate o limite do servidor. +mobSpawnTarget=\u00a74Alvo deve ser um mob spawner. +mobsAvailable=\u00a76Mobs\:\u00a7r {0} +moneyRecievedFrom=\u00a7aVoce recebeu {0} de {1}. +moneySentTo=\u00a7aVoce enviou {0} para {1}. +month=mes +months=meses +moreThanZero=\u00a74Quantidades devem ser maior que 0. +moveSpeed=\u00a76Velocidade de \u00a7c{2}\u00a76 foi definida de {0} para \u00a7c {1} \u00a76. +msgFormat=\u00a76[\u00a7c{0}\u00a76 -> \u00a7c{1}\u00a76] \u00a7r{2} +multipleCharges=\u00a74Voce nao pode aplicar mais de um comando para esse fogo de artificio. +multiplePotionEffects=\u00a74Voce nao pode aplicar mais de um efeito para essa pocao. +muteExempt=\u00a74Voce nao pode silenciar esse jogador. +muteNotify=\u00a7c {0} \u00a76 silenciou o jogador \u00a7 6 \u00a7c {1} . +mutedPlayer=\u00a76Jogador\u00a7c {0} \u00a76silenciado. +mutedPlayerFor=\u00a76Jogador\u00a7c {0} \u00a76silenciado por\u00a7c {1}\u00a76. +mutedUserSpeaks={0} tentou falar, mas esta silenciado. +nearbyPlayers=\u00a76Jogadores por perto\:\u00a7r {0} +negativeBalanceError=\u00a74Usuario nao tem permissao para ter um saldo negativo. +nickChanged=\u00a76Nick alterado. +nickDisplayName=\u00a74Voce precisa ativar o change-displayname na configuracao do Essentials. +nickInUse=\u00a74Esse nome ja esta em uso. +nickNamesAlpha=\u00a74Nicks devem ser alfanumericos. +nickNoMore=\u00a76Voce nao tem mais um nick. +nickSet=\u00a76Seu nick agora \u00e9 \u00a7c{0}\u00a76. +nickTooLong=\u00a74Esse Nome \u00e9 muito grande. +noAccessCommand=\u00a74Voce nao tem acesso a esse comando. +noAccessPermission=\u00a74Voc\u00ea n\u00e3o tem permiss\u00e3o para acessar \u00a7c{0}\u00a74. +noBreakBedrock=\u00a74Voce nao tem permissao para quebrar bedrock. +noDestroyPermission=\u00a74voc\u00ea n\u00e3o tem permiss\u00e3o para destruir \u00a7c{0}\u00a74. +noDurability=\u00a74Esse item nao tem durabilidade. +noGodWorldWarning=\u00a74Cuidado\! Modo deus nao esta desativado nesse mundo. +noHelpFound=\u00a74Nenhum comando correspondendo. +noHomeSetPlayer=\u00a76Jogador nao definiu uma casa. +noIgnored=\u00a76Voc\u00ea n\u00e3o est\u00e1 ignorando ningu\u00e9m. +noKitPermission=\u00a74Voce precisa da permissao \u00a7c{0}\u00a74 para usar esse kit. +noKits=\u00a76Nao existem kits dispon\u00c3\u00adveis ainda. +noMail=\u00a76Voce nao tem nenhum e-mail. +noMatchingPlayers=\u00a76Nenhum jogador correspondente encontrado. +noMetaFirework=\u00a74Voce nao tem permissao para aplicar meta para fogos de artifi\u00adcio. +noMetaPerm=\u00a74Voc\u00c3\u00aa nao tem permissao para aplicar meta (\u00a7c{0})\u00a74 para esse item. +noNewMail=\u00a76Voce nao tem novos e-mails. +noPendingRequest=\u00a74Voce nao tem uma solicitacao. +noPerm=\u00a74Voce nao tem a permissao \u00a7c{0}\u00a74. +noPermToSpawnMob=\u00a74Voce nao tem permissao para spawnar esse mob. +noPlacePermission=\u00a74Voce nao tem permissao para colocar um bloco perto dessa placa. +noPotionEffectPerm=\u00a74Voce nao tem permissao para aplicar o efeito \u00a7c{0} \u00a74para essa pocao. +noPowerTools=\u00a76Voce nao tem nenhuma ferramenta de poder atribuida. +noWarpsDefined=\u00a76Nenhum warp definido. +none=nada +notAllowedToQuestion=\u00a74Vocenao tem permissao para usar a pergunta. +notAllowedToShout=\u00a74Voce nao tem permissao para gritar. +notEnoughExperience=\u00a74Voce nao tem experiencia o suficiente. +notEnoughMoney=\u00a74Voce nao tem dinheiro o suficiente. +notFlying=nao esta voando +notRecommendedBukkit=\u00a74* \! * Versao do Bukkit nao e recomendada para essa versao do Essentials. +notSupportedYet=Nao suportado ainda. +nothingInHand=\u00a74Voce nao tem nada em sua mao. +now=agora +nuke=\u00a75Pode chover a morte sobre eles. +numberRequired=Vai um n\u00c3\u00bamero a\u00c3\u00ad, seu bobo. +onlyDayNight=/time suporta apenas day/night. +onlyPlayerSkulls=\u00a74Voc\u00ea s\u00f3 pode definir o propriet\u00e1rio de cr\u00e2nios de jogador (\u00a7c397\:3\u00a74). +onlyPlayers=\u00a74Apenas jogadores no jogo podem usar \u00a7c{0}\u00a74. +onlySunStorm=\u00a74/weather suporta apenas sun/storm. +orderBalances=\u00a76Organizando saldos de\u00a7c {0} \u00a76usuarios, aguarde... +oversizedTempban=\u00a74Voce nao pode banir um jogador por esse peri\u00adodo de tempo. +pTimeCurrent=\u00a76O tempo para \u00a7c{0}\u00a76 e \u00a7c {1}\u00a76. +pTimeCurrentFixed=\u00a76O tempo para \u00a7c{0}\u00a76 foi arrumado para\u00a7c {1}\u00a76. +pTimeNormal=\u00a76O tempo de \u00a7c{0}\u00a76 esta normal e correspondendo ao do servidor. +pTimeOthersPermission=\u00a74Voce nao tem permissao para definir o tempo de outros jogadores. +pTimePlayers=\u00a76Esses jogadores tem seus pr\u00c3\u00b3prios tempos\:\u00a7r +pTimeReset=\u00a76O tempo do jogador foi resetado para\: \u00a7c{0} +pTimeSet=\u00a76Tempo do jogador definido em \u00a7c{0}\u00a76 para\: \u00a7c{1}. +pTimeSetFixed=\u00a76Tempo do jogador arrumado em \u00a7c{0}\u00a76 para\: \u00a7c{1}. +pWeatherCurrent=\u00a7c{0}\u00a76 o clima \u00e9\u00a7c {1}\u00a76. +pWeatherInvalidAlias=Tipo de clima \u00a74 Inv\u00e1lido +pWeatherNormal=O clima \u00a7c{0}\u00a76 est\u00e1 normal e coincide com o servidor. +pWeatherOthersPermission=\u00a74Voc\u00ea n\u00e3o est\u00e3o autorizados a definir o clima dos outros jogadores. +pWeatherPlayers=\u00a76Estes jogadores possuem seu pr\u00f3prio clima\:\u00a7r +pWeatherReset=\u00a76O clima do jogador foi restaurado para\: \u00a7c{0} +pWeatherSet=\u00a76O clima do jogador foi definido para \u00a7c{0}\u00a76 por\: \u00a7c{1}. +pendingTeleportCancelled=\u00a74Pedido de teleporte cancelado. +playerBanIpAddress=\u00a76Player\u00a7c {0} \u00a76banned IP address\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerBanned=\u00a76Jogador\u00a7c {0} \u00a76banido\u00a7c {1} \u00a76por \u00a7c{2}\u00a76. +playerInJail=\u00a74Jogador atualmente esta na cadeia\u00a7c {0}\u00a74. +playerJailed=\u00a76JogadorPlayer\u00a7c {0} \u00a76preso. +playerJailedFor=\u00a76Jogador\u00a7c {0} \u00a76preso por {1}. +playerKicked=\u00a76Jogador\u00a7c {0} \u00a76kickou {1} por {2}. +playerMuted=\u00a76Voce foi silenciado\! +playerMutedFor=\u00a76Voc\u00ea est\u00e1 silenciado por\u00a7c {0}. +playerNeverOnServer=\u00a74Jogador\u00a7c {0} \u00a74nunca esteve nesse servidor. +playerNotFound=\u00a74Jogador nao encontrado. +playerUnbanIpAddress=\u00a76Jogador\u00a7c {0} \u00a76desbaniu o IP\: {1}. +playerUnbanned=\u00a76Jogador\u00a7c {0} \u00a76desbaniu\u00a7c {1}. +playerUnmuted=\u00a76Voc\u00ea n\u00e3o est\u00e1 mais silenciado. +pong=Pong\! +posPitch=\u00a76Pitch\: {0} (Angulo da Cabeca) +posX=\u00a76X\: {0} (+Leste <-> -Oeste) +posY=\u00a76Y\: {0} (+Cima <-> -Baixo) +posYaw=\u00a76Yaw\: {0} (Rotacao) +posZ=\u00a76Z\: {0} (+Sul <-> -Norte) +possibleWorlds=\u00a76Possiveis mundos s\u00e3o os n\u00fameros \u00a7c0\u00a76 atrav\u00e9s de \u00a7c {0} \u00a7 6. +potions=\u00a76Pocoes\:\u00a7r {0}\u00a76. +powerToolAir=\u00a74O comando nao pode ser atribu\u00c3\u00addo ao ar. +powerToolAlreadySet=\u00a74Comando \u00a7c{0}\u00a74 J\u00e1 Foi Atribuido para \u00a7c{1}\u00a74. +powerToolAttach=\u00a7c{0}\u00a76 comando atribu\u00c3\u00addo a {1}. +powerToolClearAll=\u00a76Todos as ferramentas de poder foram removidas. +powerToolList=\u00a76Item \u00a7c{1} \u00a76tem os seguintes comandos\: \u00a7c{0}\u00a76. +powerToolListEmpty=\u00a74Item \u00a7c{0} \u00a74nao tem comandos atribu\u00c3\u00addos. +powerToolNoSuchCommandAssigned=\u00a74Comando \u00a7c {0} \u00a7 4\u00ba n\u00e3o foi atribu\u00eddo a \u00a7c {1} \u00a7 4\u00ba. +powerToolRemove=\u00a76Esse Comando\u00a7c{0}\u00a76 Foi Removido de \u00a7c{1}\u00a76. +powerToolRemoveAll=\u00a76Todos os comandos removidos do 6\u00ba \u00a7c {0}. +powerToolsDisabled=\u00a76Todas as suas ferramentas de poder foram desativadas. +powerToolsEnabled=\u00a76Todas as suas ferramentas de poder foram ativadas. +questionFormat=\u00a72[Pergunta]\u00a7r {0} +readNextPage=\u00a76Digite\u00a7c /{0} {1} \u00a76para ler a proxima pagina. +recipe=\u00a76Receita para \u00a7c {0} \u00a7. 6 (\u00a7 6 \u00a7c {1} de \u00a7c {2} \u00a7 6) +recipeBadIndex=Nao ha receita para esse numero. +recipeFurnace=\u00a76Fundir\: \u00a7 6 \u00a7c {0}. +recipeGrid=\u00a7c{0}X \u00a76| \u00a7{1}X \u00a76| \u00a7{2}X +recipeGridItem=\u00a7c{0}X \u00a76\u00e9 \u00a7c{1} +recipeMore=\u00a76Digite /{0} \u00a7c{1}\u00a76 para ver outras receitas para \u00a7c{2}\u00a76. +recipeNone=Nao ha receitas para {0} +recipeNothing=nada +recipeShapeless=\u00a76Combinar \u00a7c{0} +recipeWhere=\u00a76Onde\: {0} +removed=\u00a7c{0} \u00a76entidades removidas. +repair=\u00a76Voc\u00ea reparou seu \u00a7c{0}\u00a76 com sucesso. +repairAlreadyFixed=\u00a74Esse item nao precisa de reparo. +repairEnchanted=\u00a74Voce nao tem permissao para reparar itens encantados. +repairInvalidType=\u00a74Esse item nao pode ser reparado. +repairNone=\u00a74N\u00e3o haviam itens para serem reparados. +requestAccepted=\u00a76Pedido de teleporte aceito. +requestAcceptedFrom=\u00a7c{0} \u00a76aceitou seu pedido de teleporte. +requestDenied=\u00a76Pedido de teleporte negado. +requestDeniedFrom=\u00a7c{0} \u00a76negou seu pedido de teleporte. +requestSent=\u00a76Pedido enviado para\u00a7c {0}\u00a76. +requestTimedOut=\u00a74Pedido de teleporte se esgotou. +requiredBukkit=\u00a76* \! * Voce precisa de pelo menos a construcao {0} do CraftBukkit, baixe-a em http\://dl.bukkit.org/downloads/craftbukkit/ +resetBal=\u00a76Saldos de todos os jogadores online resetados para \u00a7a{0}\u00a76. +resetBalAll=\u00a76Saldos de todos os jogadores resetados para \u00a7a{0}\u00a76. +returnPlayerToJailError=\u00a74Um erro ocorreu ao tentar retornar o jogador\u00a7c {0} \u00a74para a cadeia\: {1}\! +runningPlayerMatch=\u00a76Realizando busca por jogadores correspodentes a ''\u00a7c{0}\u00a76'' (isso pode levar um tempo) +second=segundo +seconds=segundo +seenOffline=\u00a76Jogador\u00a7c {0} \u00a76est\u00e1 \u00a74offline\u00a76 desde \u00a7c{1}\u00a76. +seenOnline=\u00a76Jogador\u00a7c {0} \u00a76est\u00e1 \u00a7aonline\u00a76 desde \u00a7c{1}\u00a76. +serverFull=Servidor cheio\! +serverTotal=\u00a76Total do Servidor\:\u00a7c {0} +setBal=\u00a7aSeu saldo foi definido para {0}. +setBalOthers=\u00a7aVoc\u00ea configurou o seu balan\u00e7o atual de {0}\u00a7a para {1}. +setSpawner=\u00a76Spawner alterado para\u00a7c {0}. +sheepMalformedColor=\u00a74Cor mal especificada. +shoutFormat=\u00a77[\u00a73G\u00a77]\u00a7r {0} +signFormatFail=\u00a74[{0}] +signFormatSuccess=\u00a71[{0}] +signFormatTemplate=[{0}] +signProtectInvalidLocation=\u00a74Vocenao tem permissao para criar placas aqui. +similarWarpExist=\u00a74Um warp com um nome similar ja existe. +slimeMalformedSize=\u00a74Tamanho mal especificado. +socialSpy=\u00a76SocialSpy para \u00a7c {0} \u00a7 6\: \u00a7c {1} +soloMob=\u00a74Esse mob gosta de ficar sozinho. +spawnSet=\u00a76Ponto de Spawn definido para o grupo\u00a7c {0}\u00a76. +spawned=spawnado +sudoExempt=\u00a74Voce nao pode usar sudo nesse usuario. +sudoRun=\u00a76Forcing\u00a7c {0} \u00a76to run\:\u00a7r /{1} +suicideMessage=\u00a76Adeus mundo cruel... +suicideSuccess=\u00a76{0} \u00a76se matou. +survival=sobrevivencia +takenFromAccount=\u00a7a{0} foi removido sua conta. +takenFromOthersAccount=\u00a7a{0} foi removido da conta de {1}\u00a7a. Novo saldo\: {2}. +teleportAAll=\u00a76Pedido de teleporte enviado para todos os jogadores... +teleportAll=\u00a76Teleportando todos os jogadores... +teleportAtoB=\u00a7c{0}\u00a76 teleportou voc\u00ea para \u00a7c{1}\u00a76. +teleportDisabled=\u00a7c{0} \u00a74esta com teleporte desativado. +teleportHereRequest=\u00a7c{0}\u00a76 pediu para que se teleporte ate ele. +teleportNewPlayerError=\u00a74Falha ao teleportar novo jogador\! +teleportRequest=\u00a7c{0}\u00a76 pediu para teleportar ate voce. +teleportRequestTimeoutInfo=\u00a76Esse pedido ira se esgotar depois de\u00a7c {0} segundos\u00a76. +teleportTop=\u00a76Teleportando para o topo. +teleportationCommencing=\u00a76Teleportando iniciando... +teleportationDisabled=\u00a76Teletrasporte \u00a7cdesabilitado\u00a76. +teleportationDisabledFor=\u00a76Teletrasporte \u00a7cdisabilitado \u00a76para \u00a7c {0} \u00a7 6. +teleportationEnabled=\u00a76Teletrasporte \u00a7habilitado\u00a76. +teleportationEnabledFor=\u00a76Teletrasporte \u00a7chabilitado \u00a76para \u00a7c {0} \u00a7 6. +teleporting=\u00a76Teleportando... +teleportToPlayer=\u00a76Teletransportando para \u00a7 6 \u00a7c {0}. +tempBanned=\u00a7cYou have been temporarily banned for {0}\:\n\u00a7r{2} +tempbanExempt=\u00a74Voce nao pode banir temporariamente esse jogador. +thunder=\u00a76Voce\u00a7c {0} \u00a76trovoada em seu mundo. +thunderDuration=\u00a76Voce\u00a7c {0} \u00a76trovoada em seu mundo por\u00a7c {1} \u00a76segundos. +timeBeforeHeal=\u00a76Tempo antes da pr\u00c3\u00b3xima cura\:\u00a7c {0}\u00a76. +timeBeforeTeleport=\u00a76Tempo antes do pr\u00c3\u00b3ximo teleporte\:\u00a7c {0} +timeFormat=\u00a7 6 \u00a7c {0} ou \u00a7c {1} \u00a7 6 ou \u00a7c {2} \u00a7 6 +timeSetPermission=\u00a74Voce nao tem permiss\u00e3o para definir o tempo. +timeWorldCurrent=\u00a76O tempo atual em\u00a7c {0} \u00a76e \u00a7c{1}\u00a76. +timeWorldSet=\u00a76O tempo foi definido para\u00a7c {0} \u00a76em\: \u00a7c{1}\u00a76. +totalWorthAll=\u00a7aTodos os itens e blocos foram vendidos por um total de \u00a7c{1}\u00a7a. +totalWorthBlocks=\u00a7aTodos os blocos foram vendidos por um total de \u00a7c{1}\u00a7a. +tps=\u00a76TPS Atual \= {0} +tradeSignEmpty=\u00a74A placa de troca nao tem nada disponivel para voce. +tradeSignEmptyOwner=\u00a74Nao hanada para coletar dessa placa de troca. +treeFailure=\u00a74Erro ao gerar Arvore. Tente novamente na terra ou na grama. +treeSpawned=\u00a76Arvore gerada. +true=\u00a7averdadeiro\u00a7r +typeTpaccept=\u00a76Para teleportar, digite \u00a7c/tpaccept\u00a76. +typeTpdeny=\u00a76Para recusar o pedido, digite \u00a7c/tpdeny\u00a76. +typeWorldName=\u00a76Voce pode tambem digitar o nome de um mundo especi\u00adfico. +unableToSpawnMob=\u00a74Incapaz de spawnar o mob. +unignorePlayer=\u00a76Voce nao esta mais ignorando o jogador\u00a7c {0} \u00a76. +unknownItemId=\u00a74ID do item invalido\: \u00a7r {0}\u00a74. +unknownItemInList=\u00a74Iten desconhecido {0} na lista {1}. +unknownItemName=\u00a74Nome de item desconhecido\: {0}. +unlimitedItemPermission=\u00a74Sem permiss\u00e3o para item \u00a7c{0}\u00a74 ilimitado. +unlimitedItems=\u00a76Itens ilimitados\:\u00a7r +unmutedPlayer=\u00a76Jogador\u00a7c {0} \u00a76nao esta mais silenciado. +unvanishedReload=\u00a74Um reload forcou-lhe a ficar visi\u00advel novamente. +upgradingFilesError=Erro ao aprimorar os arquivos. +uptime=\u00a76Tempo online\:\u00a7c {0} +userAFK=\u00a75{0} \u00a75esta atualmente AFK e pode nao responder. +userDoesNotExist=\u00a74O usuario\u00a7c {0} \u00a74nao existe. +userIsAway=\u00a75{0} \u00a75esta agora AFK. +userIsNotAway=\u00a75{0} \u00a75nao esta mais AFK. +userJailed=\u00a76Voce foi condenado\! +userUnknown=\u00a74Aviso\: O usuario ''\u00a7c{0}\u00a74'' nunca entrou nesse servidor. +userdataMoveBackError=Falha ao mover o userdata/{0}.tmp para userdata/{1}\! +userdataMoveError=Falha ao mover userdata/{0} para userdata/{1}.tmp\! +usingTempFolderForTesting=Usando pasta temporaria para teste\: +vanished=\u00a76Voce esta agora completamente invisi\u00advel para jogadores normais, e escondido de comandos in-game. +versionMismatch=\u00a74Versao nao correspondente\! Por favor atualize o {0} para a mesma versao. +versionMismatchAll=\u00a74Versao nao correspondente\! Por favor atualize todos os jars do Essentials para a mesma versao. +voiceSilenced=\u00a76Sua voz foi silenciada\! +walking=caminhando +warpDeleteError=\u00a74Problema ao deletar o arquivo do warp. +warpList={0} +warpListPermission=\u00a74Voce nao tem permissao para listar os warps. +warpNotExist=\u00a74Esse warp nao existe. +warpOverwrite=\u00a74Voce nao pode sobreescrever esse warp. +warpSet=\u00a76Warp\u00a7c {0} \u00a76definido. +warpUsePermission=\u00a74Voce nao tem permissao para usar esse warp. +warpingTo=\u00a76Teleportando para\u00a7c {0}\u00a76. +warps=\u00a76Warps\:\u00a7r {0} +warpsCount=\u00a76Aqui tem\u00a7c {0} \u00a76warps. Mostrando p\u00e1gina \u00a7c {1} \u00a76de \u00a7c {2} \u00a7 6. +weatherStorm=\u00a76Voce definiu o tempo para \u00a7ctempestade\u00a76 em\u00a7c {0}\u00a76. +weatherStormFor=\u00a76Voce definiu o tempo para \u00a7ctempestade\u00a76 em\u00a7c {0} \u00a76por {1} segundos. +weatherSun=\u00a76Voce definiu o tempo para \u00a7csol\u00a76 em\u00a7c {0}\u00a76. +weatherSunFor=\u00a76Voce definiu o tempo para \u00a7csun\u00a76 em\u00a7c {0} \u00a76por {1} seconds. +whoisAFK=\u00a76 - AFK\:\u00a7r {0} +whoisBanned=\u00a76 - Banido\:\u00a7r {0} +whoisExp=\u00a76 - Exp\:\u00a7r {0} (N\u00c3\u00advel {1}) +whoisFly=\u00a76 - Modo Fly\:\u00a7r {0} ({1}) +whoisGamemode=\u00a76 - Modo de Jogo\:\u00a7r {0} +whoisGeoLocation=\u00a76 - Localizacao\:\u00a7r {0} +whoisGod=\u00a76 - Modo deus\:\u00a7r {0} +whoisHealth=\u00a76 - Vida\:\u00a7r {0}/20 +whoisIPAddress=\u00a76 - Endereco IP\:\u00a7r {0} +whoisJail=\u00a76 - Na cadeia\:\u00a7r {0} +whoisLocation=\u00a76 - Localizacao\:\u00a7r ({0}, {1}, {2}, {3}) +whoisMoney=\u00a76 - Dinheiro\:\u00a7r {0} +whoisMuted=\u00a76 - Silenciado\:\u00a7r {0} +whoisNick=\u00a76 - Apelido\:\u00a7r {0} +whoisOp=\u00a76 - OP\:\u00a7r {0} +whoisTop=\u00a76 \=\=\=\=\=\= Quem\u00c3\u0089\:\u00a7c {0} \u00a76\=\=\=\=\=\= +worth=\u00a7aPack de {0} vale \u00a7c{1}\u00a7a ({2} a {3} cada) +worthMeta=\u00a7aPack de {0} com metadata de {1} vale \u00a7c{2}\u00a7a ({3} a {4} cada) +worthSet=\u00a76Valor definido +year=ano +years=anos +youAreHealed=\u00a76Voce foi curado. +youHaveNewMail=\u00a76Voce tem\u00a7c {0} \u00a76mensagens\! Digite \u00a7c/mail read\u00a76 para ve-las. +whoisHunger=\u00a76 - Fome\:\u00a7r {0}/20 (+{1} satura\u00e7\u00e3o) +kitDelay=\u00a7m{0}\u00a7r +giveSpawnFailure=\u00a74N\u00e3o tem espa\u00e7o, \u00a7c{0} \u00a7c{1} \u00a74 foi perdido. +noKitGroup=\u00a74Voc\u00ea n\u00e3o tem acesso \u00e0 este kit. +inventoryClearingFromAll=\u00a76Esvaziando os invent\u00e1rios de todos os usu\u00e1rios... +inventoryClearingAllItems=\u00a76Limpou todos os itens do invent\u00e1rio de {0}\u00a76. +inventoryClearingAllArmor=\u00a76Limpou todos os itens do invent\u00e1rio e armaduras de {0}\u00a76.\u00a0. +inventoryClearingAllStack=\u00a76Limpou todos \u00a7c {0} \u00a76de {1}\u00a76. +inventoryClearingStack=\u00a76Removido\u00a7c {0} \u00a76de\u00a7c {1} \u00a76de {2}\u00a76. +inventoryClearFail=\u00a74Jogador {0} \u00a74n\u00e3o tem \u00a7c {1} \u00a74de\u00a7c {2}\u00a74. +localNoOne= +totalSellableAll=\u00a7aO valor total dos itens e blocos dispon\u00edveis para venda \u00e9 de \u00a7c{1}\u00a7a. +totalSellableBlocks=\u00a7aO valor total dos blocos dispon\u00edveis para venda \u00e9 de \u00a7c{1}\u00a7a. +radiusTooBig=\u00a74O raio e muito grande. O raio maximo permitido \u00e9 de {0}. +isIpBanned=\u00a76IP \u00a7c{0} \u00a76 esta banido. +mobDataList=\u00a76Dados do mob validos\:\u00a7r {0} +vanish=\u00a76Invisivel para {0}\u00a76\: {1} +noLocationFound=\u00a74Nenhuma localizacao valida encontrada. +coordsKeyword={0}, {1}, {2} +banExemptOffline=\u00a74Voce nao pode banir jogadores desconectados. +tempbanExemptOffline=\u00a74Voce nao pode banir temporariamente jogadores desconectados. +mayNotJailOffline=\u00a74Voce nao pode prender jogadores desconectados. +muteExemptOffline=\u00a74Voce nao pode silenciar jogadores desconectados. +ignoreExempt=\u00a74Voce nao pode ignorar este jogador. +unsafeTeleportDestination=\u00a74O destino de teleporte \u00e9 inseguro e o teleporte de seguran\u00e7a est\u00e1 desabilitado. +noMetaJson=Metadata JSON n\u00e3o \u00e9 suportado nesta vers\u00e3o do Bukkit. +maxMoney=\u00a74Esta transa\u00e7\u00e3o iria exceder o limite de saldo para esta conta. +skullChanged=\u00a76Cr\u00e2nio mudou para \u00a7c {0}. \u00a7 6. +alphaNames=\u00a74Nomes de jogadores s\u00f3 podem conter letras, n\u00fameros e sublinhados. +givenSkull=\u00a76Voc\u00ea recebeu o cr\u00e2nio de \u00a7c{0}\u00a76. +noPermissionSkull=\u00a74Voc\u00ea n\u00e3o tem permiss\u00e3o para modificar esse cr\u00e2nio. +teleportInvalidLocation=Valores de coordenadas n\u00e3o pode ser maior que 30000000 +invalidSkull=\u00a74Por favor,segure um cr\u00e2nio do Jogador. +weatherInvalidWorld=Mundo {0} n\u00e3o foi encontrado\! +gameModeInvalid=\u00a74Voc\u00ea precisa especificar um modo de jogador v\u00e1lido. +mailTooLong=\u00a74Mensagem de e-mail muito longa tente ficar apenas em 1000 letras. +mailDelay=Muitos e-mails foram enviados no \u00faltimo minuto. M\u00e1ximo\: {0} +seenAccounts=\u00a76Player tamb\u00e9m foi conhecido como\: \u00a7c {0} +unableToSpawnItem=\u00a74Nao pode criar \u00a7c{0}\u00a74, esse item n\u00e3o e cri\u00e1vel. +itemsConverted=\u00a76Converted all items into blocks. +itemsNotConverted=\u00a74You have no items that can be converted into blocks. +mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\: +mailMessage={0} + +whoisTempBanned=\u00a76 - Ban expires:\u00a7r {0} +playerTempBanned=\u00a76Player \u00a7c{0}\u00a76 temporarily banned \u00a7c{1}\u00a76 for \u00a7c{2}\u00a76: \u00a7c{3}\u00a76. +mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1} diff --git a/Essentials/src/messages_ro.properties b/Essentials/src/messages_ro.properties new file mode 100644 index 0000000000..66341ec919 --- /dev/null +++ b/Essentials/src/messages_ro.properties @@ -0,0 +1,558 @@ +#X-Generator: crowdin.net +#version: TeamCity +# Single quotes have to be doubled: '' +# Translations start here +# by: +action=\u00a75* {0} \u00a75{1} +addedToAccount=\u00a7a{0} au fost adaugati in contul tau. +addedToOthersAccount=\u00a7a{0} au fost adaugati in contul lui {1}\u00a7a. Balanta noua\: {2} +adventure=aventur\u0103 +alertBroke=stricat\: +alertFormat=\u00a73[{0}] \u00a7r {1} \u00a76 {2} la\: {3} +alertPlaced=situat\: +alertUsed=folosit\: +antiBuildBreak=\u00a74Nu ai permisiunea s\u0103 spargi\u00a7c {0} \u00a74aici. +antiBuildCraft=\u00a74Nu ai permisiunea s\u0103 creezi\u00a7c {0}\u00a74. +antiBuildDrop=\u00a74Nu ai permisiunea s\u0103 arunci\u00a7c {0}\u00a74. +antiBuildInteract=\u00a74Nu ai permisiunea s\u0103 interactionezi cu\u00a7c {0}\u00a74. +antiBuildPlace=\u00a74Nu ai permisiunea s\u0103 plasezi\u00a7c {0} \u00a74aici. +antiBuildUse=\u00a74Nu ai permisiunea s\u0103 utilizezi\u00a7c {0}\u00a74. +autoAfkKickReason=Ai fost dat afar\u0103 deoarece ai fost AFK mai mult de {0} minute. +backAfterDeath=\u00a76Utilizeaz\u0103 comanda /back pentru a te \u00eentoarce la locul mor\u0163ii. +backUsageMsg=\u00a76\u00eentoarcerea la locul anterior. +backupDisabled=\u00a74Scriptul extern pentru Backup nu a fost configurat. +backupFinished=\u00a76Backup terminat. +backupStarted=\u00a76Backup \u00eenceput. +balance=\u00a7aBalan\u0163\u0103\:\u00a7c {0} +balanceOther=\u00a7aBalan\u0163a lui {0} \u00a7a\:\u00a7c {1} +balanceTop=\u00a76Topul balan\u0163elor ({0}) +banExempt=\u00a74Nu po\u0163i interzice acest juc\u0103tor. +banFormat=\u00a74Interzi\u0219i\:\n\u00a7r{0} +bed=\u00a7opat\u00a7r +bedMissing=\u00a74Patul t\u0103u nu a fost setat, lipse\u0219te sau este blocat. +bedNull=\u00a7mpat\u00a7r +bedSet=\u00a76Patul a fost setat\! +bigTreeFailure=\u00a74Generarea copacului mare a e\u0219uat. \u00cencearc\u0103 pe p\u0103m\u00e2nt sau iarb\u0103. +bigTreeSuccess=\u00a76Copac mare generat. +blockList=\u00a76Essentials a retransmis comenzile urm\u0103toare c\u0103tre alt plugin\: +bookAuthorSet=\u00a76Autorul c\u0103r\u021bii setat la {0}. +bookLocked=\u00a76Aceast\u0103 carte este acum blocat\u0103. +bookTitleSet=\u00a76Titlul c\u0103r\u021bii setat la {0}. +broadcast=\u00a7r\u00a74[Broadcast]\u00a7a {0} +buildAlert=\u00a74Nu ai permisiunea de a construi. +bukkitFormatChanged=Formatul versiunii Bukkit a fost schimbat. Versiunea nu este verificata. +burnMsg=\u00a76I-ai dat foc lui\u00a7c {0} \u00a76pentru\u00a7c {1} secunde\u00a76. +canTalkAgain=\u00a76Poti vorbi din nou acum. +cannotStackMob=\u00a74Nu. ai permissiunea sa stackezi mobii. +cantFindGeoIpDB=Nu se gaseste baza de data GeoIP\! +cantReadGeoIpDB=Citirea bazei de date GeoIP a dat gres\! +cantSpawnItem=\u00a74Nu ai permisiunea de a genera obiectul\u00a7c {0}\u00a74. +chatTypeAdmin=[A] +chatTypeLocal=[L] +chatTypeSpy=[Spion] +cleaned=Fisierele jucatorilor au fost curatate. +cleaning=Fisierele jucatorilor se curata. +commandFailed=Comanda {0} a esuat\: +commandHelpFailedForPlugin=Eroare primire ajutor pentru pluginul\: {0} +commandNotLoaded=\u00a74Comanda {0} este partial incarcata. +compassBearing=\u00a76Directie\: {0} ({1} grade). +configFileMoveError=Eroare mut\u00e2nd fi\u0219ierul config.yml in loca\u021bia Backup. +configFileRenameError=Eroare redenumind fi\u0219ierul config.yml. +connectedPlayers=\u00a76Juc\u0103tori conecta\u021bi\: \u00a7r +connectionFailed=Deschiderea conexiunii a e\u0219uat. +cooldownWithMessage=\u00a74Timp r\u0103mas\: {0} +corruptNodeInConfig=\u00a74Nota\: Configura\u021bia ta are un ''nod'' corupt. {0}. +couldNotFindTemplate=\u00a74Nu s-a gasit sablonul {0} +creatingConfigFromTemplate=Se creaza configuratie de la sablonul\: {0} +creatingEmptyConfig=Se creaza o configuratie goala\: {0} +creative=creativ +currency={0}{1} +currentWorld=\u00a76Lumea actuala\:\u00a7c {0} +day=zi +days=zile +defaultBanReason=Ai fost interzis pe server\! +deleteFileError=Nu s-a putut sterge fisierul\: {0} +deleteHome=\u00a76Casa\u00a7c {0} \u00a76a fost stearsa. +deleteJail=\u00a76Inchisoarea\u00a7c {0} \u00a76a fost stearsa. +deleteWarp=\u00a76Teleportarea\u00a7c {0} \u00a76a fost stearsa. +deniedAccessCommand=\u00a7c{0} \u00a74are accesul interzis la comanda. +denyBookEdit=\u00a74Nu poti debloca aceasta carte. +denyChangeAuthor=\u00a74Nu poti schimba autorul acestei carti. +denyChangeTitle=\u00a74Nu poti schimba titlu acestei carti. +depth=\u00a76Esti la nivelul oceanului. +depthAboveSea=\u00a76Esti cu\u00a7c {0} \u00a76bloc(uri) deasupra nivelului oceanului. +depthBelowSea=\u00a76Esti cu\u00a7c {0} \u00a76bloc(uri) sub nivelul oceanului. +destinationNotSet=Destinatia nu a fost setata\! +disableUnlimited=\u00a76Plasarea nelimitata de\u00a7c {0} \u00a76a fost dezactivata pentru {1}. +disabled=dezactivat +disabledToSpawnMob=\u00a74Generarea acestui mob a fost dezactivata din configuratie. +distance=\u00a76Distanta\: {0} +dontMoveMessage=\u00a76Vei fi teleportat in\u00a7c {0}\u00a76. Nu te misca. +downloadingGeoIp=Baza GeoIP se descarca... Poate dura o vreme. +duplicatedUserdata=Informatiile jucatorilor duplicate\: {0} and {1}. +durability=\u00a76Aceasta unealta are \u00a7c{0}\u00a76 utilizari ramase +editBookContents=\u00a7eAcum poti modifica continutul acestei carti. +enableUnlimited=\u00a76Giving unlimited amount of\u00a7c {0} \u00a76to \u00a7c{1}\u00a76. +enabled=activat +enchantmentApplied=\u00a76Magia\u00a7c {0} \u00a76a fost aplicata pe obiectul din mana. +enchantmentNotFound=\u00a74Magia nu a fost gasita\! +enchantmentPerm=\u00a74YNu ai permisiunea pentru\u00a7c {0}\u00a74. +enchantmentRemoved=\u00a76Magia\u00a7c {0} \u00a76a fost scoasa de pe obiect. +enchantments=\u00a76Magii\:\u00a7r {0} +errorCallingCommand=Eroare executand comanda /{0} +errorWithMessage=\u00a7cEroare\:\u00a74 {0} +essentialsHelp1=Fisierul este stricat si nu poate fi deschis. Essentials este acum dezactivat. Daca nu poti rezolva problema singur, dute la http\://tiny.cc/EssentialsChat +essentialsHelp2=Fisierul este stricat si nu poate fi deschis. Essentials este acum dezactivat. Daca nu poti rezolva problema singur, dute la http\://tiny.cc/EssentialsChat +essentialsReload=\u00a76Essentials reloaded\u00a7c {0}. +exp=\u00a7c{0} \u00a76are\u00a7c {1} \u00a76experienta (nivel\u00a7c {2}\u00a76) si are nevoie de \u00a7c {3} \u00a76experienta pentru a atinge un nou nivel. +expSet=\u00a7c{0} \u00a76are acum\u00a7c {1} \u00a76experienta. +extinguish=\u00a76Te-ai stins singur. +extinguishOthers=\u00a76Ai stins pe {0}\u00a76. +failedToCloseConfig=Eroare la inchiderea configuratiei {0}. +failedToCreateConfig=Eroare la creearea configuratiei {0}. +failedToWriteConfig=Eroare la scrierea configuratiei {0}. +false=\u00a74fals\u00a7r +feed=\u00a76Apetitul tau a fost saturat. +feedOther=\u00a76You satiated the appetite of \u00a7c{0}\u00a76. +fileRenameError=Redenumirea fisierului {0} a esuat\! +fireworkColor=\u00a74Parametri de incarcare insertati sunt invalizi, trebuie sa setati o culoare intai. +fireworkEffectsCleared=\u00a76Efectele rachetelor au fost scoase. +fireworkSyntax=\u00a76Parametri rachetelor\:\u00a7c culoare\: [cadere\:] [forma\:] [efect\:]\n\u00a76Pentru a utiliza mai mult culor/efecte, separati valorile prin virgula\: \u00a7cred,blue,pink\n\u00a76forme\:\u00a7c star, ball, large, creeper, burst \u00a76efecte\:\u00a7c trail, twinkle. +flyMode=\u00a76Modul de zburat\u00a7c {0} \u00a76a fost setat pentru {1}\u00a76. +flying=zburand +foreverAlone=\u00a74Nu ai pe nimeni la care sa raspunzi. +fullStack=\u00a74Ai deja un stac intreg. +gameMode=\u00a76Set game mode\u00a7c {0} \u00a76for \u00a7c{1}\u00a76. +gcWorld=\u00a76 {0} "\u00a76 \u00a7c {1}"\: \u00a7c {2} \u00a76 bucati, \u00a7c {3} \u00a76 entitati, \u00a7c {4} \u00a76 gresie. +gcfree=\u00a76Memorie libera\:\u00a7c {0} MB. +gcmax=\u00a76Memorie maxima\:\u00a7c {0} MB. +gctotal=\u00a76Memorie alocata\:\u00a7c {0} MB. +geoIpUrlEmpty=URL-ul pentru descarcare GeoIP este gol. +geoIpUrlInvalid=URL-ul pentru descarcare GeoIP este invalid. +geoipJoinFormat=\u00a76Jucatorul \u00a7c{0} \u00a76a intrat din \u00a7c{1}\u00a76. +giveSpawn=\u00a76I-ai dat\u00a7c {0} \u00a76bucata(ti) de\u00a7c {1} lui\u00a7c {2}\u00a76. +godDisabledFor=\u00a7cdisabled\u00a76 for\u00a7c {0} +godEnabledFor=\u00a7aactivat\u00a76 pentru\u00a7c {0}. +godMode=\u00a76Modul GOD\u00a7c {0}\u00a76. +groupDoesNotExist=\u00a74Nu sunt jucatori conectati din aceasta grupa\! +groupNumber=\u00a7c{0}\u00a7f online, toata lista\:\u00a7c /{1} {2} +hatArmor=\u00a74Nu poti folosi acest obicat ca palarie\! +hatEmpty=\u00a74Nu porti o palarie. +hatFail=\u00a74Trebuie sa ai ceva de purtat in mana. +hatPlaced=\u00a76EBucurate de noua palarie\! +hatRemoved=\u00a76Palaria ta a fost scoasa. +haveBeenReleased=\u00a76Ai fost eliberat. +heal=\u00a76Ai fost vindecat. +healDead=\u00a74Nu pot vindeca pe cineva mort\! +healOther=\u00a76L-ai vindecat pe\u00a7c {0}\u00a76. +helpConsole=Pentru a vedea ajutorul din CONSOLA, scrie ?. +helpFrom=\u00a76Comenzi din {0}\: +helpLine=\u00a76/{0}\u00a7r\: {1} +helpMatching=\u00a76Comenzi potrivite "\u00a7c{0}\u00a76"\: +helpOp=\u00a74[AjutorOP]\u00a7r \u00a76{0}\:\u00a7r {1} +helpPlugin=\u00a74{0}\u00a7r\: Ajutor plugin\: /help {1} +holdBook=\u00a74Nu detii o carte scriabila. +holdFirework=\u00a74Trebuie sa tii in mana o racheta pentru a-i adauga efecte. +holdPotion=\u00a74Trebuie sa tii in mana o potiune pentru a-i adauga efecte. +holeInFloor=\u00a74Gaura in podea\! +homeSet=\u00a76Casa setata. +homes=\u00a76Case\:\u00a7r {0} +hour=ora +hours=ore +ignoredList=\u00a76Ignorat\:\u00a7r {0} +ignorePlayer=\u00a76Il ignori pe jucatorul\u00a7c {0} \u00a76de acum. +illegalDate=Formatul datei este ilegala. +infoChapter=\u00a76Selecta\u021bi Capitolul\: +infoChapterPages=\u00a7e---\u00a76 {0} \u00a7e--\u00a76 Pagina \u00a7c {1} \u00a76 de \u00a7c {2} \u00a7e--- +infoPages=\u00a7e ---- \u00a76{2} \u00a7e--\u00a76 Pagina \u00a7c{0}\u00a76/\u00a7c{1} \u00a7e---- +infoUnknownChapter=\u00a74Capitol necunoscut. +insufficientFunds=\u00a74Fonduri insuficiente. +invalidCharge=\u00a74Incarcare invalida. +invalidFireworkFormat=\u00a74The option \u00a7c{0} \u00a74is not a valid value for \u00a7c{1}\u00a74. +invalidHome=\u00a74Casa\u00a7c {0} \u00a74nu exista\! +invalidHomeName=\u00a74Numele casei este invalida\! +invalidMob=Tip de mob invalid. +invalidNumber=Numar invalid. +invalidPotion=\u00a74Potiune invalida. +invalidPotionMeta=\u00a74Potiune meta invalida\: \u00a7c{0}\u00a74. +invalidSignLine=\u00a74Linia\u00a7c {0} \u00a74de pe semn este invalida. +invalidWarpName=\u00a74Numele teleportarei este invalida\! +invalidWorld=\u00a74Lume invalida. +is=este +itemCannotBeSold=\u00a74Acest obiect nu poate fi vandut pe server. +itemMustBeStacked=\u00a74Obiectul trebuie comercializat in stacuri. O cantitate de 2s ar trebuie sa fie 2 stacuri, s.a.m.d. +itemNames=\u00a76Numele scurte ale obiectului\:\u00a7r {0} +itemNotEnough1=\u00a74YNu ai destul din acest obiect pentru a-l putea vinde. +itemNotEnough2=\u00a76Daca ai vrut sa vinzi toate obiectele de tipul acela, foloseste /sell +itemNotEnough3=\u00a76/sell va vinde totul inafara de 1, s.a.m.d. +itemSellAir=Chiar ai incercat sa vinzi ''aer''? Pune-ti un obiect in mana. +itemSold=\u00a7aVandut pentru \u00a7c{0} \u00a7a({1} {2} la {3} fiecare). +itemSoldConsole=\u00a7a{0} \u00a7aa vandut {1} pentru \u00a7a{2} \u00a7a({3} obiecte la {4} fiecare). +itemSpawn=\u00a76Ai primit\u00a7c {0} \u00a76bucata(ti) de\u00a7c {1} +itemType=\u00a76Obiect\:\u00a7c {0} \u00a76-\u00a7c {1} +itemsCsvNotLoaded=Nu s-a putut incarca fisierul items.csv\! +jailAlreadyIncarcerated=\u00a74Acest jucator este deja in inchisoare\:\u00a7c {0} +jailMessage=\u00a74Incalci reguli, trebuie sa platesti. +jailNotExist=\u00a74Aceasta inchisoare nu exista. +jailReleased=\u00a76Jucatorul \u00a7c{0}\u00a76 a fost eliberat. +jailReleasedPlayerNotify=\u00a76Ai fost eliberat\! +jailSentenceExtended=\u00a76Timpul pedepsei a fost crescut la\: {0} +jailSet=\u00a76Inchisoarea\u00a7c {0} \u00a76a fost creata. +jumpError=\u00a74Asta ar putea sa raneasca creierul calculatorul. +kickDefault=Ai fost dat afara de pe server. +kickExempt=\u00a74Nu poti da afara acest jucator. +kickedAll=\u00a74Ai dat afara toti jucatorii de pe server. +kill=\u00a76Ai ucis (pe)\u00a7c {0} \u00a76. +killExempt=\u00a74You cannot kill \u00a7c{0}\u00a74. +kitCost=\ \u00a77\u00a7o({0})\u00a7r +kitError2=\u00a74Acest kit este nedefinit. Contactati un operator. +kitError=\u00a74Nu sunt kituri valide. +kitGiveTo=\u00a76Giving kit\u00a7c {0}\u00a76 to \u00a7c{1}\u00a76. +kitInvFull=\u00a74Inventarul tau este plin, kitul este aruncat jos. +kitNotFound=\u00a74Acest kit nu exista. +kitOnce=\u00a74Nu poti folosi acest kit din nou. +kitReceive=\u00a76Ai primit kitul\u00a7c {0}\u00a76. +kitTimed=\u00a74Nu poti folosit acest kit inca\u00a7c {0}\u00a74. +kits=\u00a76Kituri\:\u00a7r {0} +leatherSyntax=\u00a76Sintaxa culorilor la piele\: color\:,, ex\: color\:255,0,0. +lightningSmited=\u00a76Ai fost fulgerat\! +lightningUse=\u00a76L-ai fulgerat pe\u00a7c {0} +listAfkTag=\u00a77 [AFK] \u00a7r +listAmount=\u00a76Sunt \u00a7c{0}\u00a76 din maxim \u00a7c{1}\u00a76 jucatori online. +listAmountHidden=\u00a76Sunt \u00a7c{0}\u00a76/{1}\u00a76 din maxim \u00a7c{2}\u00a76 jucatori online. +listGroupTag=\u00a76 {0} \u00a7r\: \u00a7r +listHiddenTag=\u00a77[Ascuns]\u00a7r +loadWarpError=\u00a74Incarcarea teleportarii a esuat {0}. +localFormat=[L]<{0}> {1} +mailClear=\u00a76To mark your mail as read, type\u00a7c /mail clear\u00a76. +mailCleared=\u00a76Posta curatata\! +mailSent=\u00a76Mail trimis\! +markMailAsRead=\u00a76To mark your mail as read, type\u00a7c /mail clear\u00a76. +markedAsAway=\u00a76Ai fost marcat ca si . +markedAsNotAway=\u00a76Nu mai esti marcat ca si . +matchingIPAddress=\u00a76Jucatori s-au logat anterior de pe aceste IP-uri\: +maxHomes=\u00a74Nu poti seta mai mult de\u00a7c {0} \u00a74case. +mayNotJail=\u00a74Nu poti incarcera acest jucator\! +me=eu +minute=minut +minutes=minute +missingItems=\u00a74You do not have \u00a7c{0}x {1}\u00a74. +mobSpawnError=\u00a74Eroare in schimbarea mob generator. +mobSpawnLimit=Cantitatea de mobi a fost limitata la limita serverului. +mobSpawnTarget=\u00a74Blocul tinta trebuie sa fie un generator. +mobsAvailable=\u00a76Mobi\:\u00a7r {0} +moneyRecievedFrom=\u00a7a{0} au fost primiti de la {1}. +moneySentTo=\u00a7a{0} au fost trimisi catre {1}. +month=luna +months=luni +moreThanZero=\u00a74Cantitatea trebuie sa fie mai mare de 0. +moveSpeed=\u00a76Set {0} speed to\u00a7c {1} \u00a76for \u00a7c{2}\u00a76. +msgFormat=\u00a76[\u00a7c{0}\u00a76 -> \u00a7c{1}\u00a76] \u00a7r{2} +multipleCharges=\u00a74Nu poti aplica mai mult de o incarcare pe racheta. +multiplePotionEffects=\u00a74Nu poti aplica mai mult de un efect pe potiune. +muteExempt=\u00a74Nu poti sa opresti vorbitul acestui jucator. +muteNotify=\u00a7c {0} \u00a76l-a adus la tacere pe \u00a7c {1}. +mutedPlayer=\u00a76Juc\u0103torul\u00a7c {0} \u00a76a fost adus la tacere. +mutedPlayerFor=\u00a76Juc\u0103torul\u00a7c {0} \u00a76nu mai are voie sa vorbeasca pentru \u00a7c {1}\u00a76. +mutedUserSpeaks={0} a incercat sa vorbeasca, dar nu are voie. +nearbyPlayers=\u00a76Jucatori in apropiere\:\u00a7r {0} +negativeBalanceError=\u00a74Jucatorul nu are permisiunea sa aiba o balanta negativa. +nickChanged=\u00a76Nume schimbat. +nickDisplayName=\u00a74Trebuie sa activezi schimbarea numelui din configuratie. +nickInUse=\u00a74Acest nume este deja in uz. +nickNamesAlpha=\u00a74Numele trebuie sa fie alfanumeric. +nickNoMore=\u00a76Nu mai ai nume. +nickSet=\u00a76Your nickname is now \u00a7c{0}\u00a76. +nickTooLong=\u00a74Acest nume este prea lung. +noAccessCommand=\u00a74Nu ai acces la aceasta comanda. +noAccessPermission=\u00a74You do not have permission to access that \u00a7c{0}\u00a74. +noBreakBedrock=\u00a74Nu ai permisiunea sa spargi roca. +noDestroyPermission=\u00a74You do not have permission to destroy that \u00a7c{0}\u00a74. +noDurability=\u00a74Acest obiect nu are durabilitate. +noGodWorldWarning=\u00a74Avertisment\! Modul GOD este dezactivat in aceasta lume. +noHelpFound=\u00a74Nici o comanda nu se potriveste. +noHomeSetPlayer=\u00a76Jucatorul nu are setata casa. +noIgnored=\u00a76Tu nu ignori pe nimeni. +noKitPermission=\u00a74Ai nevoie de permisiunea \u00a7c{0}\u00a74 pentru a utiliza acest kit. +noKits=\u00a76Nu sunt kituri valabile inca. +noMail=\u00a76Nu ai nici un mail. +noMatchingPlayers=\u00a76Nu s-a gasit potrivire jucatori. +noMetaFirework=\u00a74Nu ai permisiunea sa aplici meta pe racheta. +noMetaPerm=\u00a74Nu ai permisiunea sa aplici meta \u00a7c{0}\u00a74 pe acest obiect. +noNewMail=\u00a76Nu ai mailuri noi. +noPendingRequest=\u00a74Nu ai nici o cerere in asteptare. +noPerm=\u00a74Nu ai permisiunea \u00a7c{0}\u00a74. +noPermToSpawnMob=\u00a74Nu ai permisiunea sa generezi acest mob. +noPlacePermission=\u00a74Nu ai permisiunea sa plasezi un bloc in apropierea acestui semn. +noPotionEffectPerm=\u00a74Nu ai permisiunea sa aplici efectul\u00a7c{0} \u00a74pe aceasta potiune. +noPowerTools=\u00a76Nu ai nicio putere pe acest obiect. +noWarpsDefined=\u00a76Nu sunt teleportari specificate. +none=nimic +notAllowedToQuestion=\u00a74Nu ai permisiunea sa intrebi. +notAllowedToShout=\u00a74Nu ai permisiunea sa strigi. +notEnoughExperience=\u00a74Nu ai destula experienta. +notEnoughMoney=\u00a74Nu ai destule fonduri. +notFlying=nu zbori +notRecommendedBukkit=\u00a74*[\!]* Aceastea versiune Bukkit nu este recomandata pentru acest Essentials. +notSupportedYet=Nu este suportat inca. +nothingInHand=\u00a74Nu ai nimic in mana. +now=acum +nuke=\u00a75Ploua cu decese. +numberRequired=Un numar merge acolo, prostesc. +onlyDayNight=/time suporta doar day/night. +onlyPlayerSkulls=\u00a74You can only set the owner of player skulls (\u00a7c397\:3\u00a74). +onlyPlayers=\u00a74Only in-game players can use \u00a7c{0}\u00a74. +onlySunStorm=\u00a74/weather suporta doar sun/storm. +orderBalances=\u00a76Se ordoneaza balantele a\u00a7c {0} \u00a76jucatori, te rog asteapta... +oversizedTempban=\u00a74Nu poti interzice un jucator pentru asa o perioada de timp. +pTimeCurrent=\u00a76Timpul jucatorului \u00a7c{0}\u00a76 este\u00a7c {1}\u00a76. +pTimeCurrentFixed=\u00a76Timpul jucatorului \u00a7c{0}\u00a76 a fost fixat la\u00a7c {1}\u00a76. +pTimeNormal=\u00a76Timpul jucatorului \u00a7c{0}\u00a76 este timpul normal si potrivit serverului. +pTimeOthersPermission=\u00a74Nu ai permisiunea sa schimb timpul jucatorilor. +pTimePlayers=\u00a76Acesti jucatori au propiul lor timp\:\u00a7r +pTimeReset=\u00a76Timpul jucatorului a fost resetat pentru\: \u00a7c{0} +pTimeSet=\u00a76Timpul jucatorului a fost setat \u00a7c{0}\u00a76 pentru\: \u00a7c{1}. +pTimeSetFixed=\u00a76Timpul jucatorului a fost fixat \u00a7c{0}\u00a76 pentru\: \u00a7c{1}. +pWeatherCurrent=\u00a76Vremea lui \u00a7c{0}\u00a76 este\u00a7c {1}\u00a76. +pWeatherInvalidAlias=\u00a74Vreme invalida +pWeatherNormal=\u00a76Vremea lui\u00a7c {0} \u00a76 normala si se potriveste cu cea a serverului. +pWeatherOthersPermission=\u00a74Nu ai permisiunea sa setezi vremea altui jucator. +pWeatherPlayers=\u00a76Jucatori cu propia-si vreme\: \u00a7r +pWeatherReset=\u00a76Vremea a fost resetata pentru\: \u00a7c {0} +pWeatherSet=\u00a76Vreme este setata la \u00a7c {0} \u00a76 pentru\: \u00a7c {1}. +pendingTeleportCancelled=\u00a74Cererea de teleportare a fost refuzata. +playerBanIpAddress=\u00a76Player\u00a7c {0} \u00a76banned IP address\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerBanned=\u00a76Player\u00a7c {0} \u00a76banned\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerInJail=\u00a74Player is already in jail\u00a7c {0}\u00a74. +playerJailed=\u00a76Jucatorul\u00a7c {0} \u00a76a fost inchis. +playerJailedFor=\u00a76Jucatorul\u00a7c {0} \u00a76a fost inchis pentru\: {1}. +playerKicked=\u00a76Adminul\u00a7c {0} \u00a76l-a dat afara pe {1} pentru\: {2}. +playerMuted=\u00a76Ti-a fost interzis vorbitul\! +playerMutedFor=\u00a76Ti-a fost interzis vorbitul pentru \u00a7c {0}. +playerNeverOnServer=\u00a74Jucatorul\u00a7c {0} \u00a74nu a fost niciodata pe acest server. +playerNotFound=\u00a74Jucatorul nu a fost gasit. +playerUnbanIpAddress=\u00a76Adminul\u00a7c {0} \u00a76i-a scos interzicerea IPului\: {1}. +playerUnbanned=\u00a76Adminul\u00a7c {0} \u00a76i-a scos interzicerea lui {1}. +playerUnmuted=\u00a76Ti s-a dat voie sa vorbesti. +pong=Pong\! +posPitch=\u00a76Inaltime\: {0} (unghiul capului) +posX=\u00a76X\: {0} (+Est <-> -Vest) +posY=\u00a76Y\: {0} (+Sus <-> -Jos) +posYaw=\u00a76Yaw\: {0} (Rotatie) +posZ=\u00a76Z\: {0} (+Sud <-> -Nord) +possibleWorlds=\u00a76Possible worlds are the numbers \u00a7c0\u00a76 through \u00a7c{0}\u00a76. +potions=\u00a76Potiuni\:\u00a7r {0}\u00a76. +powerToolAir=\u00a74Comanda nu poate fi atasata de ''aer''. +powerToolAlreadySet=\u00a74Command \u00a7c{0}\u00a74 is already assigned to \u00a7c{1}\u00a74. +powerToolAttach=\u00a7c{0}\u00a76 comanda pusa {1}. +powerToolClearAll=\u00a76Comenzile au fost scoase de pe acest obiect. +powerToolList=\u00a76Obiectul \u00a7c{1} \u00a76are urmatoarele comenzi\: \u00a7c{0}\u00a76. +powerToolListEmpty=\u00a74Obiectul \u00a7c{0} \u00a74nu are comenzi puse. +powerToolNoSuchCommandAssigned=\u00a74Command \u00a7c{0}\u00a74 has not been assigned to \u00a7c{1}\u00a74. +powerToolRemove=\u00a76Command \u00a7c{0}\u00a76 removed from \u00a7c{1}\u00a76. +powerToolRemoveAll=\u00a76All commands removed from \u00a7c{0}\u00a76. +powerToolsDisabled=\u00a76Toate comenzile de pe obiecte au fost scoase. +powerToolsEnabled=\u00a76Toate comenzile de pe obiect au fost puse. +questionFormat=\u00a72[Intrebare]\u00a7r {0} +readNextPage=\u00a76Scrie\u00a7c /{0} {1} \u00a76pentru a citi pagina urmatoare. +recipe=\u00a76Recipe for \u00a7c{0}\u00a76 (\u00a7c{1}\u00a76 of \u00a7c{2}\u00a76) +recipeBadIndex=Nu este nici o reteta cu acel numar. +recipeFurnace=\u00a76Smelt\: \u00a7c{0}\u00a76. +recipeGrid=\u00a7c{0}X \u00a76| \u00a7{1}X \u00a76| \u00a7{2}X +recipeGridItem=\u00a7c{0}X \u00a76is \u00a7c{1} +recipeMore=\u00a76Type /{0} \u00a7c{1}\u00a76 pentru a vedea alta reteta pentru \u00a7c{2}\u00a76. +recipeNone=Nu exista reteta pentru {0} +recipeNothing=nimic +recipeShapeless=\u00a76Combina \u00a7c{0} +recipeWhere=\u00a76Unde\: {0} +removed=\u00a76S-au sters\u00a7c {0} \u00a76entitati. +repair=\u00a76You have successfully repaired your\: \u00a7c{0}\u00a76. +repairAlreadyFixed=\u00a74Aces obiect nu trebuie reparat. +repairEnchanted=\u00a74Ai ai permisiunea sa repair obiecte magice. +repairInvalidType=\u00a74Acest obiect nu poate fi reparat. +repairNone=\u00a74Nu sunt obiecte ce trebuiesc reparate. +requestAccepted=\u00a76Cererea de teleportare a fost acceptata. +requestAcceptedFrom=\u00a7c{0} \u00a76a acceptat cererea de teleportare. +requestDenied=\u00a76Cererea de teleportare a fost respinsa. +requestDeniedFrom=\u00a7c{0} \u00a76a respins cererea de teleportare. +requestSent=\u00a76Cerere a fost trimisa catre\u00a7c {0}\u00a76. +requestTimedOut=\u00a74Timpul de acceptare s-a terminat. +requiredBukkit=\u00a76*[\!]* Ai nevoie de constructia minima {0} ale Bukkit-ului, descarcal de pe http\://dl.bukkit.org/downloads/craftbukkit/ +resetBal=\u00a76Balance has been reset to \u00a7c{0} \u00a76for all online players. +resetBalAll=\u00a76Balance has been reset to \u00a7c{0} \u00a76for all players. +returnPlayerToJailError=\u00a74Error occurred when trying to return player\u00a7c {0} \u00a74to jail\: \u00a7c{1}\u00a74\! +runningPlayerMatch=\u00a76Ruleaza cautarea pentru potrivite jucatori ''\u00a7c{0}\u00a76'' (Poate dura ceva) +second=secund +seconds=secunde +seenOffline=\u00a76Player\u00a7c {0} \u00a76has been \u00a74offline\u00a76 since \u00a7c{1}\u00a76. +seenOnline=\u00a76Player\u00a7c {0} \u00a76has been \u00a7aonline\u00a76 since \u00a7c{1}\u00a76. +serverFull=Serverul este plin\! +serverTotal=\u00a76Total server\:\u00a7c {0} +setBal=\u00a7aBalanta ta a fost setata la {0}. +setBalOthers=\u00a7aA-ti setat balanta lui {0} \u00a7a la {1}. +setSpawner=\u00a76Changed spawner type to\u00a7c {0}\u00a76. +sheepMalformedColor=\u00a74Culoare malformata. +shoutFormat=\u00a76[Strigat]\u00a7r {0} +signFormatFail=\u00a74[{0}] +signFormatSuccess=\u00a71[{0}] +signFormatTemplate=[{0}] +signProtectInvalidLocation=\u00a74Nu ai permsiunea sa creezi semne aici. +similarWarpExist=\u00a74O teleportare cu acelasi nume deja exista. +slimeMalformedSize=\u00a74Marile malformata. +socialSpy=\u00a76SocialSpy for \u00a7c{0}\u00a76\: \u00a7c{1} +soloMob=\u00a74Acel mob pare sa fie singur. +spawnSet=\u00a76Locatia spawn a fost setata grupului\u00a7c {0}\u00a76. +spawned=generati(te) +sudoExempt=\u00a74Nu poti forta acest jucator. +sudoRun=\u00a76Forcing\u00a7c {0} \u00a76to run\:\u00a7r /{1} +suicideMessage=\u00a76La revedere lume cruda... +suicideSuccess=\u00a76{0} \u00a76si-a luat viata. +survival=supravietuire +takenFromAccount=\u00a7a{0} au fost luati de pe contul tau. +takenFromOthersAccount=\u00a7a{0} au fost luati de pe contul lui {1}\u00a7a. Balanta noua\: {2}. +teleportAAll=\u00a76Cererea de teleportare a fost trimisa catre toti jucatorii... +teleportAll=\u00a76Teleporteaza toti jucatorii... +teleportAtoB=\u00a7c{0}\u00a76 teleported you to \u00a7c{1}\u00a76. +teleportDisabled=\u00a7c{0} \u00a74are teleportarea dezactivata. +teleportHereRequest=\u00a7c{0}\u00a76 ti-a cerut sa te teleportezi la ei. +teleportNewPlayerError=\u00a74Teleportarea jucatorului nou a dat gres\! +teleportRequest=\u00a7c{0}\u00a76 a cerut sa se teleporteze la tine. +teleportRequestTimeoutInfo=\u00a76Aceasta cerere va expira in\u00a7c {0} secunde\u00a76. +teleportTop=\u00a76Teleporteaza la cel mai inalt punct. +teleportationCommencing=\u00a76Teleportarea urmeaza... +teleportationDisabled=\u00a76Teleportation \u00a7cdisabled\u00a76. +teleportationDisabledFor=\u00a76Teleportation \u00a7cdisabled \u00a76for \u00a7c{0}\u00a76. +teleportationEnabled=\u00a76Teleportation \u00a7cenabled\u00a76. +teleportationEnabledFor=\u00a76Teleportation \u00a7cenabled \u00a76for \u00a7c{0}\u00a76. +teleporting=\u00a76Teleporteaza... +teleportToPlayer=\u00a76Teleporting to \u00a7c{0}\u00a76. +tempBanned=\u00a7cYou have been temporarily banned for {0}\:\n\u00a7r{2} +tempbanExempt=\u00a74Nu poti interzice acest jucatoru. +thunder=\u00a76Ai\u00a7c {0} \u00a76ploaia in lumea ta. +thunderDuration=\u00a76Ai\u00a7c {0} \u00a76ploaia in luma ta pentru\u00a7c {1} \u00a76secunde. +timeBeforeHeal=\u00a76Timp pana la urmatoarea vindecare\:\u00a7c {0}\u00a76. +timeBeforeTeleport=\u00a76Timp intre teleportari\:\u00a7c {0} +timeFormat=\u00a7c{0}\u00a76 or \u00a7c{1}\u00a76 or \u00a7c{2}\u00a76 +timeSetPermission=\u00a74Nu ai permisiunea sa setezi timpul. +timeWorldCurrent=\u00a76Timpul curent in lumea\u00a7c {0} \u00a76este \u00a7c{1}\u00a76. +timeWorldSet=\u00a76Timul a fost setat u00a7c {0} \u00a76in\: \u00a7c{1}\u00a76. +totalWorthAll=\u00a7aVindeti toate obiectele pentru un toltal de \u00a7c{1}\u00a7a. +totalWorthBlocks=\u00a7aVindeti toate obiectele pentru un toltal de \u00a7c{1}\u00a7a. +tps=\u00a76TPSul curent \= {0} +tradeSignEmpty=\u00a74Semnul pentru negociere nu are nimic pentru tine. +tradeSignEmptyOwner=\u00a74Nu este nimic de colectat de la acest semn. +treeFailure=\u00a74Generarea copacului a esuat. Incearca pe pamand sau iarba. +treeSpawned=\u00a76Copac generat. +true=\u00a7aadevarat\u00a7r +typeTpaccept=\u00a76Pentru a accepta teleportarea, scrie \u00a7c/tpaccept\u00a76. +typeTpdeny=\u00a76Pentru a refuza teleportarea, scrie \u00a7c/tpdeny\u00a76. +typeWorldName=\u00a76De asemenea poti scrie numele unei lumi. +unableToSpawnMob=\u00a74Nu se poate genera mobul. +unignorePlayer=\u00a76Nu-l mai ignori pe\u00a7c {0} \u00a76de acum inainte. +unknownItemId=\u00a74Nu se cunoaste codul obiectului\:\u00a7r {0}\u00a74. +unknownItemInList=\u00a74Obiect necunoscut {0} in {1} list. +unknownItemName=\u00a74Nume obiect necunoscut\: {0}. +unlimitedItemPermission=\u00a74No permission for unlimited item \u00a7c{0}\u00a74. +unlimitedItems=\u00a76Obiecte nelimitate\:\u00a7r +unmutedPlayer=\u00a76Jucatorul\u00a7c {0} \u00a76are voie sa vorbeasca. +unvanishedReload=\u00a74O reincarcare te-a fortat sa devii din nou vizibil. +upgradingFilesError=Eroare urcand fisierele. +uptime=\u00a76Timp total\:\u00a7c {0} +userAFK=\u00a75{0} \u00a75este acum AFK si este posibil sa nu raspunda. +userDoesNotExist=\u00a74Jucatorul\u00a7c {0} \u00a74nu exista. +userIsAway=\u00a75{0} \u00a75este AFK. +userIsNotAway=\u00a75{0} \u00a75nu mai este AFK. +userJailed=\u00a76Ai fost inchis\! +userUnknown=\u00a74Advertisment\: Jucatorul ''\u00a7c{0}\u00a74'' nu a intrat niciodata pe acest server. +userdataMoveBackError=Mutarea datelor jucatorilor a esuat. /{0}.tmp catre datele jucatorilor /{1}\! +userdataMoveError=Mutarea datelor jucatorilor a esuat. /{0} catre datele jucatorilor /{1}.tmp\! +usingTempFolderForTesting=Se utilizicea un folder temportat pentru test\: +vanished=\u00a76Ai devenit invizibil. +versionMismatch=\u00a74Versiunea nu se potriveste\! Fa update {0} la aceasi versiune. +versionMismatchAll=\u00a74Versiunea nu se potriveste\! Fa uptate la acceasi versiune. +voiceSilenced=\u00a76Vocea ta e fost interzisa +walking=mergand +warpDeleteError=\u00a74Problema in stergerea teleportarii. +warpList={0} +warpListPermission=\u00a74Nu ai permisiunea de a vedea teleportarile. +warpNotExist=\u00a74Aceasta teleportare nu exista. +warpOverwrite=\u00a74Nu poti rescrie peste aceasta teleportare. +warpSet=\u00a76teleportarea\u00a7c {0} \u00a76setata. +warpUsePermission=\u00a74Nu ai permisiunea de a utiliza aceasta teleportare. +warpingTo=\u00a76Teleporteaza catre\u00a7c {0}\u00a76. +warps=\u00a76teleportari\:\u00a7r {0} +warpsCount=\u00a76There are\u00a7c {0} \u00a76warps. Showing page \u00a7c{1} \u00a76of \u00a7c{2}\u00a76. +weatherStorm=\u00a76Ai setat vremea din \u00a7cstorm\u00a76 in\u00a7c {0}\u00a76. +weatherStormFor=\u00a76Ai setat vremea din \u00a7cstorm\u00a76 in\u00a7c {0} \u00a76pentru {1} secunde. +weatherSun=\u00a76Ai setat vremea din \u00a7csun\u00a76 in\u00a7c {0}\u00a76. +weatherSunFor=\u00a76Ai setat vremea din \u00a7csun\u00a76 in\u00a7c {0} \u00a76pentru {1} secunde. +whoisAFK=\u00a76 - AFK\:\u00a7r {0} +whoisBanned=\u00a76 - Interzisi\:\u00a7r {0} +whoisExp=\u00a76 - Experience\:\u00a7r {0} (Level {1}) +whoisFly=\u00a76 - Mod zburator\:\u00a7r {0} ({1}) +whoisGamemode=\u00a76 - Mod de joc\:\u00a7r {0} +whoisGeoLocation=\u00a76 - Locatie\:\u00a7r {0} +whoisGod=\u00a76 - Modul GOD\:\u00a7r {0} +whoisHealth=\u00a76 - Viata\:\u00a7r {0}/20 +whoisIPAddress=\u00a76 - Aresa IP\:\u00a7r {0} +whoisJail=\u00a76 - Inchisi\:\u00a7r {0} +whoisLocation=\u00a76 - Locatia\: \u00a7r ({0}, {1}, {2}, {3}) +whoisMoney=\u00a76 - Bani\:\u00a7r {0} +whoisMuted=\u00a76 - Vorbit interzis\:\u00a7r {0} +whoisNick=\u00a76 - Nume\:\u00a7r {0} +whoisOp=\u00a76 - OP\:\u00a7r {0} +whoisTop=\u00a76 \=\=\= Cine este\:\u00a7c {0} \u00a76 \=\=\= +worth=\u00a7aUn stac de {0} valoreaza \u00a7c{1}\u00a7a ({2} obiect(e) la {3} fiecare) +worthMeta=\u00a7aUn stac de {0} cu metadata de {1} valoreaza \u00a7c{2}\u00a7a ({3} obiect(e) la {4} fiecare) +worthSet=\u00a76Valoarea ''valorii'' setata +year=an +years=ani +youAreHealed=\u00a76Ai fost vindecat. +youHaveNewMail=\u00a76Ai\u00a7c {0} \u00a76mesaje\! scrie \u00a7c/mail read\u00a76 pentru a-ti vedea mesajele. +whoisHunger=\u00a76 - Foame\: \u00a7r {0} / 20 (+ satura\u0163ie {1}) +kitDelay=\u00a7m{0}\u00a7r +giveSpawnFailure=\u00a74Spatiu insuficient, \u00a7c {0} \u00a7c {1} \u00a74au fost pierdute. +noKitGroup=\u00a74Nu ai acces la acest kit. +inventoryClearingFromAll=\u00a76Se curata inventarul tuturor jucatorilor... +inventoryClearingAllItems=\u00a76Se curata inventarul lui {0} \u00a76. +inventoryClearingAllArmor=\u00a76Se curata tot inventarul lui {0} \u00a76. +inventoryClearingAllStack=\u00a76Se curata\u00a7c {0} \u00a76ale lui {1} \u00a76. +inventoryClearingStack=\u00a76Se curata\u00a7c {0} \u00a76of\u00a7c {1} \u00a76de la {2} \u00a76. +inventoryClearFail=\u00a74Jucatorul {0} \u00a74nu are\u00a7c {1} \u00a74de\u00a7c {2} \u00a74. +localNoOne= +totalSellableAll=\u00a7aValoare totala a obiectelor vanzabile este de \u00a7c{1}\u00a7a. +totalSellableBlocks=\u00a7aValoare totala a obiectelor vanzabile este de \u00a7c{1}\u00a7a. +radiusTooBig=\u00a74Distanta este prea mare\! Distanta maxima este de {0}. +isIpBanned=\u00a76IP-ul \u00a7c {0} \u00a76este interzis. +mobDataList=\u00a76Mob data valide \u00a7r\: {0} +vanish=\u00a76Invizibil pentru {0}\u00a76\: {1} +noLocationFound=\u00a74Nici-o loca\u021bie valid\u0103 g\u0103sit\u0103. +coordsKeyword={0}, {1}, {2} +banExemptOffline=\u00a74Nu poti interzice jucatorii inactivi. +tempbanExemptOffline=\u00a74Nu poti interzice temporar jucatorii inactivi. +mayNotJailOffline=\u00a74Nu poti incarcera jucatorii inactivi. +muteExemptOffline=\u00a74Nu poti aduce la tacere jucatorii inactivi. +ignoreExempt=\u00a74Nu poti ignora acest jucator. +unsafeTeleportDestination=Destinatia de teleportare este nesigura si teleportarea in siguranta este dezactivata. +noMetaJson=JSON Metadata is not supported in this version of Bukkit. +maxMoney=\u00a74Aceasta tranzactie ar depasi suma din acest cont. +skullChanged=\u00a76Skull changed to \u00a7c{0}\u00a76. +alphaNames=\u00a74Numele playerilor pot contine doar litere, cifre si underline. +givenSkull=\u00a76Ti-a fost dat craniul lui \u00a7c{0}\u00a76. +noPermissionSkull=\u00a74Nu ai permisiunea sa modifici acel craniu. +teleportInvalidLocation=Valoarea coordonatelor nu poate trece de 30000000 +invalidSkull=\u00a74Te rog tine un craniu al unui player. +weatherInvalidWorld=Lumea numita {0} nu a fost gasita\! +gameModeInvalid=\u00a74Trebuie sa specifici un jucator/mod valid. +mailTooLong=\u00a74Mail message too long. Try to keep it below 1000 characters. +mailDelay=Prea multe mail-uri au fost trimise in ultimul minute.Maxim \: {0} +seenAccounts=\u00a76Player has also been known as\:\u00a7c {0} +unableToSpawnItem=\u00a74Cannot spawn \u00a7c{0}\u00a74, this is not a spawnable item. +itemsConverted=\u00a76Converted all items into blocks. +itemsNotConverted=\u00a74You have no items that can be converted into blocks. +mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\: +mailMessage={0} + +whoisTempBanned=\u00a76 - Ban expires:\u00a7r {0} +playerTempBanned=\u00a76Player \u00a7c{0}\u00a76 temporarily banned \u00a7c{1}\u00a76 for \u00a7c{2}\u00a76: \u00a7c{3}\u00a76. +mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1} diff --git a/Essentials/src/messages_ru.properties b/Essentials/src/messages_ru.properties new file mode 100644 index 0000000000..af4e222d25 --- /dev/null +++ b/Essentials/src/messages_ru.properties @@ -0,0 +1,558 @@ +#X-Generator: crowdin.net +#version: TeamCity +# Single quotes have to be doubled: '' +# Translations start here +# by: +action=\u00a75* {0} \u00a75{1} +addedToAccount=\u00a7a{0} \u0431\u044b\u043b\u043e \u043d\u0430\u0447\u0438\u0441\u043b\u0435\u043d\u043e \u0432\u0430\u043c. +addedToOthersAccount=\u00a7a{0} \u0437\u0430\u0447\u0438\u0441\u043b\u0435\u043d\u043e \u043d\u0430 \u0430\u043a\u043a\u0430\u0443\u043d\u0442 {1}\u00a7a. \u0422\u0435\u043a\u0443\u0449\u0438\u0439 \u0431\u0430\u043b\u0430\u043d\u0441\: {2} +adventure=\u043f\u0440\u0438\u043a\u043b\u044e\u0447\u0435\u043d\u0447\u0435\u0441\u043a\u0438\u0439 +alertBroke=\u0441\u043b\u043e\u043c\u0430\u043b\: +alertFormat=\u00a73 [{0}] \u00a7r {1} \u00a76 {2} \u0432\: {3} +alertPlaced=\u043f\u043e\u0441\u0442\u0430\u0432\u0438\u043b\: +alertUsed=\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\: +antiBuildBreak=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432 \u043b\u043e\u043c\u0430\u0442\u044c\u00a7c {0} \u00a74. +antiBuildCraft=\u00a74\u0412\u0430\u043c \u043d\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c\u00a7c {0}\u00a74. +antiBuildDrop=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432 \u0432\u044b\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0442\u044c\u00a7c {0}\u00a74. +antiBuildInteract=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432 \u043d\u0430 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441\u00a7c {0}\u00a74. +antiBuildPlace=\u00a74\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432 \u0434\u043b\u044f \u0440\u0430\u0437\u043c\u0435\u0449\u0435\u043d\u0438\u044f\u00a7c {0} \u00a74. +antiBuildUse=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432 \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f\u00a7c {0}\u00a74. +autoAfkKickReason=\u0412\u044b \u0431\u044b\u043b\u0438 \u043a\u0438\u043a\u043d\u0443\u0442\u044b \u0437\u0430 \u043d\u0430\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u0431\u043e\u043b\u0435\u0435 {0} \u043c\u0438\u043d\u0443\u0442 \u0432 AFK. +backAfterDeath=\u00a76\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 /back \u0447\u0442\u043e\u0431\u044b \u0432\u0435\u0440\u043d\u0443\u0442\u044c\u0441\u044f \u043d\u0430 \u043c\u0435\u0441\u0442\u043e \u0441\u043c\u0435\u0440\u0442\u0438. +backUsageMsg=\u00a76\u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043d\u0430 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0443\u044e \u043b\u043e\u043a\u0430\u0446\u0438\u044e. +backupDisabled=\u00a74\u0412\u043d\u0435\u0448\u043d\u0438\u0439 \u0441\u043a\u0440\u0438\u043f\u0442 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0433\u043e \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0435 \u0431\u044b\u043b \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d. +backupFinished=\u00a76\u0420\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0435 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043e. +backupStarted=\u00a76\u0420\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0435 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0430\u0447\u0430\u0442\u043e. +balance=\u00a7a\u0411\u0430\u043b\u0430\u043d\u0441\:\u00a7c {0} +balanceOther=\u00a7a\u0411\u0430\u043b\u0430\u043d\u0441 {0}\u00a7a\:\u00a7c {1} +balanceTop=\u00a76\u0422\u043e\u043f \u0431\u043e\u0433\u0430\u0447\u0435\u0439 ({0}) +banExempt=\u00a74\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0437\u0430\u0431\u0430\u043d\u0438\u0442\u044c \u044d\u0442\u043e\u0433\u043e \u0438\u0433\u0440\u043e\u043a\u0430. +banFormat=\u00a74\u0417\u0430\u0431\u0430\u043d\u0435\u043d\:\n\u00a7r{0} +bed=\u00a7o\u043a\u0440\u043e\u0432\u0430\u0442\u044c\u00a7r +bedMissing=\u0412\u0430\u0448\u0430 \u043a\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430, \u043f\u043e\u0442\u0435\u0440\u044f\u043d\u0430 \u0438\u043b\u0438 \u043a \u043d\u0435\u0439 \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d \u0434\u043e\u0441\u0442\u0443\u043f. +bedNull=\u00a7m\u043a\u0440\u043e\u0432\u0430\u0442\u044c\u00a7r +bedSet=\u00a76\u0421\u043f\u0430\u0432\u043d \u043a\u0440\u043e\u0432\u0430\u0442\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\! +bigTreeFailure=\u00a74\u041d\u0435\u0443\u0434\u0430\u0447\u043d\u0430\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u0434\u0435\u0440\u0435\u0432\u0430. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0432 \u0434\u0440\u0443\u0433\u043e\u043c \u043c\u0435\u0441\u0442\u0435. +bigTreeSuccess=\u00a76\u0411\u043e\u043b\u044c\u0448\u043e\u0435 \u0434\u0435\u0440\u0435\u0432\u043e \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e \u0443\u0434\u0430\u0447\u043d\u043e. +blockList=\u00a76Essentials \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u043c\u0438 \u0434\u0440\u0443\u0433\u043e\u043c\u0443 \u043f\u043b\u0430\u0433\u0438\u043d\u0443\: +bookAuthorSet=\u00a76\u041d\u043e\u0432\u044b\u0439 \u0430\u0432\u0442\u043e\u0440 \u043a\u043d\u0438\u0433\u0438\: {0}. +bookLocked=\u00a76\u0422\u0435\u043f\u0435\u0440\u044c \u044d\u0442\u0430 \u043a\u043d\u0438\u0433\u0430 \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u0430. +bookTitleSet=\u00a76\u041d\u043e\u0432\u043e\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043a\u043d\u0438\u0433\u0438\: {0}. +broadcast=\u00a7r\u00a76[\u00a74\u041e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u0435\u00a76]\u00a7a {0} +buildAlert=\u00a74\u0412\u0430\u043c \u043d\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u043e \u0441\u0442\u0440\u043e\u0438\u0442\u044c. +bukkitFormatChanged=\u0412\u0435\u0440\u0441\u0438\u044f Bukkit-\u044f\u0434\u0440\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0430. \u0412\u0435\u0440\u0441\u0438\u044f \u043d\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f. +burnMsg=\u00a76\u0412\u044b \u043f\u043e\u0434\u043e\u0436\u0433\u043b\u0438\u00a7c {0} \u00a76\u043d\u0430 \u00a7c {1} \u0441\u0435\u043a\u0443\u043d\u0434\u00a76. +canTalkAgain=\u00a76\u0412\u044b \u0441\u043d\u043e\u0432\u0430 \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u0447\u0430\u0442. +cannotStackMob=\u00a74\u0423 \u0432\u0430\u0441 \u043d\u0435\u0442 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043d\u0430 \u0441\u0442\u0435\u043a \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043c\u043e\u0431\u043e\u0432. +cantFindGeoIpDB=\u041d\u0435 \u043c\u043e\u0433\u0443 \u043d\u0430\u0439\u0442\u0438 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 GeoIP\! +cantReadGeoIpDB=\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0447\u0442\u0435\u043d\u0438\u0438 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 GeoIP\! +cantSpawnItem=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f\u00a7c {0}\u00a74. +chatTypeAdmin=[A] +chatTypeLocal=[L] +chatTypeSpy=[Spy] +cleaned=\u0424\u0430\u0439\u043b\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043e\u0447\u0438\u0449\u0435\u043d\u044b. +cleaning=\u041e\u0447\u0438\u0441\u0442\u043a\u0430 \u043f\u0440\u043e\u0444\u0438\u043b\u044f \u0438\u0433\u0440\u043e\u043a\u0430. +commandFailed=\u041a\u043e\u043c\u0430\u043d\u0434\u0430 {0} \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u0430\u044f\: +commandHelpFailedForPlugin=\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0434\u043b\u044f \u043f\u043b\u0430\u0433\u0438\u043d\u0430\: {0} +commandNotLoaded=\u00a74\u041a\u043e\u043c\u0430\u043d\u0434\u0430 {0} \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u0430. +compassBearing=\u00a76\u0410\u0437\u0438\u043c\u0443\u0442\: {0} ({1} \u0433\u0440\u0430\u0434\u0443\u0441\u043e\u0432). +configFileMoveError=\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u044c config.yml \u0432 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u0443\u044e \u043a\u043e\u043f\u0438\u044e. +configFileRenameError=\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u0432 config.yml +connectedPlayers=\u00a76\u0418\u0433\u0440\u043e\u043a\u043e\u0432 \u043e\u043d\u043b\u0430\u0439\u043d\u00a7r +connectionFailed=\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435. +cooldownWithMessage=\u00a74\u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435\: {0} +corruptNodeInConfig=\u00a74\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435\: \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0438\u043c\u0435\u0435\u0442 \u043d\u0430\u0440\u0443\u0448\u0435\u043d\u0438\u044f {0} \u0443\u0437\u043b\u0430. +couldNotFindTemplate=\u00a74\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043d\u0430\u0439\u0442\u0438 \u0448\u0430\u0431\u043b\u043e\u043d {0} +creatingConfigFromTemplate=\u0421\u043e\u0437\u0434\u0430\u044e \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0438\u0437 \u0448\u0430\u0431\u043b\u043e\u043d\u0430\: {0} +creatingEmptyConfig=\u0421\u043e\u0437\u0434\u0430\u044e \u043f\u0443\u0441\u0442\u043e\u0439 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b\: {0} +creative=\u0442\u0432\u043e\u0440\u0447\u0435\u0441\u043a\u0438\u0439 +currency={0}{1} +currentWorld=\u00a76\u0422\u0435\u043a\u0443\u0449\u0438\u0439 \u043c\u0438\u0440\:\u00a7c {0} +day=\u0434\u0435\u043d\u044c +days=\u0434\u043d\u0435\u0439 +defaultBanReason=\u041d\u0430 \u0432\u0430\u0441 \u043d\u0430\u043b\u043e\u0436\u0438\u043b\u0438 \u0432\u0435\u043b\u0438\u043a\u0443\u044e \u043f\u0435\u0447\u0430\u0442\u044c \u0411\u0430\u043d\u0430\! +deleteFileError=\u041d\u0435 \u0443\u0434\u0430\u0435\u0442\u0441\u044f \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0444\u0430\u0439\u043b\: {0} +deleteHome=\u00a76\u0422\u043e\u0447\u043a\u0430 \u0434\u043e\u043c\u0430\u00a7c {0} \u00a76\u0443\u0434\u0430\u043b\u0435\u043d\u0430. +deleteJail=\u00a76\u0422\u044e\u0440\u044c\u043c\u0430\u00a7c {0} \u00a76\u0443\u0434\u0430\u043b\u0435\u043d\u0430. +deleteWarp=\u00a76\u0412\u0430\u0440\u043f\u00a7c {0} \u00a76\u0443\u0434\u0430\u043b\u0451\u043d. +deniedAccessCommand=\u00a7c{0} \u00a74\u043e\u0442\u043a\u0430\u0437\u0430\u043d\u043e \u0432 \u0434\u043e\u0441\u0442\u0443\u043f\u0435 \u043a \u043a\u043e\u043c\u0430\u043d\u0434\u0435. +denyBookEdit=\u00a74\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u044d\u0442\u0443 \u043a\u043d\u0438\u0433\u0443. +denyChangeAuthor=\u00a74\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0430\u0432\u0442\u043e\u0440\u0430 \u044d\u0442\u043e\u0439 \u043a\u043d\u0438\u0433\u0438. +denyChangeTitle=\u00a74\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u044d\u0442\u043e\u0439 \u043a\u043d\u0438\u0433\u0438. +depth=\u00a76\u0412\u044b \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u043c\u043e\u0440\u044f. +depthAboveSea=\u00a76\u0412\u044b \u043d\u0430\u00a7c {0} \u00a76\u0431\u043b\u043e\u043a(\u043e\u0432) \u043d\u0430\u0434 \u0443\u0440\u043e\u0432\u043d\u0435\u043c \u043c\u043e\u0440\u044f. +depthBelowSea=\u00a76\u0412\u044b \u043d\u0430\u00a7c {0} \u00a76\u0431\u043b\u043e\u043a(\u043e\u0432) \u043d\u0438\u0436\u0435 \u0443\u0440\u043e\u0432\u043d\u044f \u043c\u043e\u0440\u044f. +destinationNotSet=\u0422\u043e\u0447\u043a\u0430 \u043f\u0440\u0438\u0431\u044b\u0442\u0438\u044f \u043d\u0435 \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0430\! +disableUnlimited=\u00a76\u041e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u043e \u043d\u0435\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u043e\u0435 \u0440\u0430\u0437\u043c\u0435\u0449\u0435\u043d\u0438\u0435\u00a7c {0} \u00a76\u0434\u043b\u044f {1}. +disabled=\u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d\u043e +disabledToSpawnMob=\u00a74\u0421\u043f\u0430\u0443\u043d \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043c\u043e\u0431\u0430 \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445. +distance=\u00a76\u0414\u0438\u0441\u0442\u0430\u043d\u0446\u0438\u044f\: {0} +dontMoveMessage=\u00a76\u0422\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0430\u0446\u0438\u044f \u043d\u0430\u0447\u043d\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437\u00a7c {0}\u00a76. \u041d\u0435 \u0434\u0432\u0438\u0433\u0430\u0439\u0442\u0435\u0441\u044c. +downloadingGeoIp=\u0418\u0434\u0451\u0442 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 GeoIP... \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043d\u044f\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0440\u0435\u043c\u044f (\u0441\u0442\u0440\u0430\u043d\u0430\: 0,6 MB \u0433\u043e\u0440\u043e\u0434\: 20MB) +duplicatedUserdata=\u0414\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439\: {0} and {1}. +durability=\u00a76\u042d\u0442\u043e\u0442 \u043f\u0440\u0435\u0434\u043c\u0435\u0442 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0449\u0451 \u00a7c{0}\u00a76 \u0440\u0430\u0437 +editBookContents=\u00a7e\u0422\u0435\u043f\u0435\u0440\u044c \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u044d\u0442\u043e\u0439 \u043a\u043d\u0438\u0433\u0438. +enableUnlimited=\u00a76\u0412\u044b\u0434\u0430\u043d\u043e \u043d\u0435\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u00a7c {0} \u00a76\u0438\u0433\u0440\u043e\u043a\u0443 \u00a7c{1}\u00a76. +enabled=\u0432\u043a\u043b\u044e\u0447\u0435\u043d +enchantmentApplied=\u00a76\u0417\u0430\u0447\u0430\u0440\u043e\u0432\u0430\u043d\u0438\u0435\:\u00a7c {0} \u00a76\u0431\u044b\u043b\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u043e \u043a \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u0443 \u0432 \u0432\u0430\u0448\u0435\u0439 \u0440\u0443\u043a\u0435. +enchantmentNotFound=\u00a74\u0427\u0430\u0440\u044b \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b\! +enchantmentPerm=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0434\u043b\u044f\u00a7c {0}\u00a74. +enchantmentRemoved=\u00a76\u0417\u0430\u0447\u0430\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u00a7c {0} \u00a76\u0431\u044b\u043b\u043e \u0441\u043d\u044f\u0442\u043e \u0441 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u0430 \u0432 \u0432\u0430\u0448\u0435\u0439 \u0440\u0443\u043a\u0435. +enchantments=\u00a76\u0412\u0438\u0434\u044b \u0437\u0430\u0447\u0430\u0440\u043e\u0432\u0430\u043d\u0438\u0439\:\u00a7r {0} +errorCallingCommand=\u041e\u0448\u0438\u0431\u043a\u0430 \u0432\u044b\u0437\u043e\u0432\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u044b /{0} +errorWithMessage=\u00a7c\u041e\u0448\u0438\u0431\u043a\u0430\:\u00a74 {0} +essentialsHelp1=\u0424\u0430\u0439\u043b \u0438\u0441\u043f\u043e\u0440\u0447\u0435\u043d, Essentials \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0435\u0433\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u044c. Essentials \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d. \u0422\u044b \u043c\u043e\u0436\u0435\u0448\u044c \u0441\u0430\u043c \u0443\u0441\u0442\u0440\u0430\u043d\u0438\u0442\u044c \u044d\u0442\u043e, \u043f\u0435\u0440\u0435\u0439\u0434\u044f \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 http\://tiny.cc/EssentialsChat +essentialsHelp2=\u0424\u0430\u0439\u043b \u0438\u0441\u043f\u043e\u0440\u0447\u0435\u043d, Essentials \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0435\u0433\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u044c. Essentials \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d. \u0422\u044b \u043c\u043e\u0436\u0435\u0448\u044c \u0441\u0430\u043c \u0443\u0441\u0442\u0440\u0430\u043d\u0438\u0442\u044c \u044d\u0442\u043e, \u0432\u0432\u0435\u0434\u044f /essentialshelp \u0432 \u0438\u0433\u0440\u0435, \u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u0439\u0434\u044f \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 http\://tiny.cc/EssentialsChat +essentialsReload=\u00a76Essentials \u043f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u00a7c {0}. +exp=c{0} \u00a76\u0438\u043c\u0435\u0435\u0442\u00a7c {1} \u00a76\u043e\u043f\u044b\u0442\u0430 (\u0443\u0440\u043e\u0432\u0435\u043d\u044c\u00a7c {2}\u00a76) \u043d\u0443\u0436\u043d\u043e\u00a7c {3} \u00a76\u043e\u043f\u044b\u0442\u0430 \u0434\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f. +expSet=\u00a7c{0} \u00a76\u0442\u0435\u043f\u0435\u0440\u044c \u0438\u043c\u0435\u0435\u0442\u00a7c {1} \u00a76\u043e\u043f\u044b\u0442\u0430. +extinguish=\u00a76\u0412\u044b \u043f\u043e\u0442\u0443\u0448\u0438\u043b\u0438 \u0441\u0435\u0431\u044f. +extinguishOthers=\u00a76\u0412\u044b \u043f\u043e\u0442\u0443\u0448\u0438\u043b\u0438 {0}\u00a76. +failedToCloseConfig=\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0437\u0430\u043a\u0440\u044b\u0442\u0438\u0438 \u0444\u0430\u0439\u043b\u0430 {0}. +failedToCreateConfig=\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0444\u0430\u0439\u043b\u0430 {0}. +failedToWriteConfig=\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u0444\u0430\u0439\u043b {0}. +false=\u00a74\u043b\u043e\u0436\u044c\u00a7r +feed=\u00a76\u0412\u0430\u0448 \u0433\u043e\u043b\u043e\u0434 \u0443\u0442\u0430\u043b\u0451\u043d. +feedOther=\u00a76\u0412\u044b \u0443\u0442\u043e\u043b\u0438\u043b\u0438 \u0433\u043e\u043b\u043e\u0434 \u0438\u0433\u0440\u043e\u043a\u0430 \u00a7c{0}\u00a76. +fileRenameError=\u041f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430 {0} \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c\! +fireworkColor=\u00a74\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0444\u0435\u0439\u0435\u0440\u0432\u0435\u0440\u043a\u0430 \u0437\u0430\u0434\u0430\u043d\u044b \u043d\u0435 \u0432\u0435\u0440\u043d\u043e, \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0446\u0432\u0435\u0442. +fireworkEffectsCleared=\u00a76\u0423\u0431\u0440\u0430\u043d\u044b \u0432\u0441\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u044b. +fireworkSyntax=\u00a76\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0424\u0435\u0439\u0435\u0440\u0432\u0435\u0440\u043a\u0430\:\u00a7c color\:<\u0446\u0432\u0435\u0442> [fade\:<\u0446\u0432\u0435\u0442>] [shape\:<\u0444\u043e\u0440\u043c\u0430>] [effect\:<\u044d\u0444\u0444\u0435\u043a\u0442>]\n\u00a76\u0427\u0442\u043e\u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0446\u0432\u0435\u0442\u043e\u0432/\u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432, \u0440\u0430\u0437\u0434\u0435\u043b\u044f\u0439\u0442\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u044f\u0442\u044b\u043c\u0438\: \u00a7cred,blue,pink\n\u00a76\u0424\u043e\u0440\u043c\u044b\:\u00a7c star, ball, large, creeper, burst \u00a76\u042d\u0444\u0444\u0435\u043a\u0442\u044b\:\u00a7c trail, twinkle. +flyMode=\u00a76\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d \u0440\u0435\u0436\u0438\u043c \u043f\u043e\u043b\u0435\u0442\u0430\u00a7c {0} \u00a76\u0434\u043b\u044f {1}\u00a76. +flying=\u043b\u0435\u0442\u0430\u0435\u0442 +foreverAlone=\u00a74\u0414\u0430\u043d\u043d\u043e\u0433\u043e \u0438\u0433\u0440\u043e\u043a\u0430 \u043d\u0435\u0442 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435. +fullStack=\u00a74\u0423 \u0412\u0430\u0441 \u0443\u0436\u0435 \u0441\u0442\u0430\u043a \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043e\u0432. +gameMode=\u00a76\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d \u0440\u0435\u0436\u0438\u043c \u0438\u0433\u0440\u044b\u00a7c {0} \u00a76\u0434\u043b\u044f \u0438\u0433\u0440\u043e\u043a\u0430 \u00a7c{1}\u00a76. +gcWorld=\u00a76{0} "\u00a7c{1}\u00a76"\: \u00a7c{2}\u00a76 \u0447\u0430\u043d\u043a\u043e\u0432, \u00a7c{3}\u00a76 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432, \u00a7c{4}\u00a76 \u0442\u0430\u0439\u043b\u043e\u0432. +gcfree=\u00a76\u0421\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u0439 \u043f\u0430\u043c\u044f\u0442\u0438\:\u00a7c {0} MB. +gcmax=\u00a76\u041c\u0430\u043a\u0441\u0438\u043c\u0443\u043c \u043f\u0430\u043c\u044f\u0442\u0438\:\u00a7c {0} MB. +gctotal=\u00a76\u0412\u044b\u0434\u0435\u043b\u0435\u043d\u043e \u043f\u0430\u043c\u044f\u0442\u0438\:\u00a7c {0} MB. +geoIpUrlEmpty=\u0421\u0441\u044b\u043b\u043a\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 GeoIP \u043f\u0443\u0441\u0442\u0430. +geoIpUrlInvalid=\u0421\u0441\u044b\u043b\u043a\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 GeoIP \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u0430. +geoipJoinFormat=\u00a76\u0418\u0433\u0440\u043e\u043a \u00a7c{0} \u00a76\u043f\u0440\u0438\u0448\u0435\u043b \u043a \u043d\u0430\u043c \u0438\u0437 \u00a7c{1}\u00a76. +giveSpawn=\u00a76\u0412\u044b\u0434\u0430\u043d\u043e\u00a7c {0} \u00a76\u0448\u0442\u0443\u043a\u00a7c {1} \u0438\u0433\u0440\u043e\u043a\u0443\u00a7c {2}\u00a76. +godDisabledFor=\u00a7c\u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u00a76 \u0434\u043b\u044f\u00a7c {0} +godEnabledFor=\u00a7a\u0432\u043a\u043b\u044e\u0447\u0435\u043d\u00a76 \u0434\u043b\u044f \u0438\u0433\u0440\u043e\u043a\u0430\u00a7c {0}. +godMode=\u00a76\u0420\u0435\u0436\u0438\u043c \u0411\u043e\u0433\u0430\u00a7c {0}\u00a76. +groupDoesNotExist=\u00a74\u0412 \u0434\u0430\u043d\u043d\u043e\u0439 \u0433\u0440\u0443\u043f\u043f\u0435 \u043d\u0435\u0442 \u0438\u0433\u0440\u043e\u043a\u043e\u0432 \u0432 \u0438\u0433\u0440\u0435\! +groupNumber={0} \u0432 \u0438\u0433\u0440\u0435, \u0434\u043b\u044f \u043f\u043e\u043b\u043d\u043e\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430 \u0432\u0432\u0435\u0434\u0438 /{1} {2} +hatArmor=\u00a74\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0434\u0435\u0442\u044c \u044d\u0442\u043e\u0442 \u043f\u0440\u0435\u0434\u043c\u0435\u0442 \u043d\u0430 \u0433\u043e\u043b\u043e\u0432\u0443\! +hatEmpty=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u0430 \u043d\u0430 \u0433\u043e\u043b\u043e\u0432\u0435. +hatFail=\u00a74\u0412\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0432 \u0440\u0443\u043a\u0435 \u043f\u0440\u0435\u0434\u043c\u0435\u0442, \u0447\u0442\u043e\u0431\u044b \u043e\u0434\u0435\u0442\u044c \u0435\u0433\u043e \u043d\u0430 \u0433\u043e\u043b\u043e\u0432\u0443. +hatPlaced=\u00a76\u0412\u044b \u043e\u0434\u0435\u043b\u0438 \u043f\u0440\u0435\u0434\u043c\u0435\u0442 \u043d\u0430 \u0433\u043e\u043b\u043e\u0432\u0443\! +hatRemoved=\u00a76\u041f\u0440\u0435\u0434\u043c\u0435\u0442 \u0443\u0431\u0440\u0430\u043d \u0441 \u0433\u043e\u043b\u043e\u0432\u044b. +haveBeenReleased=\u00a76\u0412\u044b \u0431\u044b\u043b\u0438 \u0432\u044b\u043f\u0443\u0449\u0435\u043d\u044b. +heal=\u00a76\u0412\u044b \u0431\u044b\u043b\u0438 \u0438\u0441\u0446\u0435\u043b\u0435\u043d\u044b. +healDead=\u00a74\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0432\u044b\u043b\u0435\u0447\u0438\u0442\u044c \u043c\u0435\u0440\u0442\u0432\u043e\u0433\u043e\! +healOther=\u00a76\u0412\u044b\u043b\u0435\u0447\u0438\u043b\u0438\u00a7c {0}\u00a76. +helpConsole=\u0414\u043b\u044f \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u043f\u043e\u043c\u043e\u0449\u0438 \u0438\u0437 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 \u0432\u0432\u0435\u0434\u0438\u0442\u0435 ?. +helpFrom=\u00a76\u041a\u043e\u043c\u0430\u043d\u0434\u044b \u043f\u043b\u0430\u0433\u0438\u043d\u0430 {0}\: +helpLine=\u00a76/{0}\u00a7r\: {1} +helpMatching=\u00a76\u041d\u0430\u0439\u0434\u0435\u043d\u043e \u043a\u043e\u043c\u0430\u043d\u0434 "\u00a7c{0}\u00a76"\: +helpOp=\u00a74[\u041f\u043e\u043c\u043e\u0449\u044c]\u00a7r \u00a76{0}\:\u00a7r {1} +helpPlugin=\u00a7f\u041f\u043e\u043c\u043e\u0449\u044c \u043f\u043e \u043f\u043b\u0430\u0433\u0438\u043d\u0443 \u00a74{0}\u00a7r\: /help {1} +holdBook=\u00a74\u0412\u044b \u043d\u0435 \u0434\u0435\u0440\u0436\u0438\u0442\u0435 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0435\u043c\u0443\u044e \u043a\u043d\u0438\u0433\u0443. +holdFirework=\u00a74\u0412\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0444\u0435\u0439\u0435\u0440\u0432\u0435\u0440\u043a \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432. +holdPotion=\u00a74\u0412\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0437\u0435\u043b\u044c\u0435 \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432. +holeInFloor=\u00a74\u0414\u044b\u0440\u0430 \u0432 \u043f\u043e\u043b\u0443 (\u041d\u0435\u043a\u0443\u0434\u0430 \u0432\u0441\u0442\u0430\u0442\u044c). +homeSet=\u00a76\u0414\u043e\u043c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d. +homes=\u00a76\u0414\u043e\u043c\u0430\:\u00a7r {0} +hour=\u0447\u0430\u0441 +hours=\u0447\u0430\u0441\u043e\u0432 +ignoredList=\u00a76\u0418\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\:\u00a7r {0} +ignorePlayer=\u00a76\u0412\u044b \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u0435\u0442\u0435 \u0438\u0433\u0440\u043e\u043a\u0430\u00a7c {0}\u00a76. +illegalDate=\u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u0434\u0430\u0442\u044b. +infoChapter=\u0412\u044b\u0431\u0435\u0440\u0438 \u0447\u0430\u0441\u0442\u044c\: +infoChapterPages=\u00a76\u0427\u0430\u0441\u0442\u044c {0}, \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u00a7c{1}\u00a76 \u0438\u0437 \u00a7c{2}\u00a76\: +infoPages=\u00a7e --- \u00a76{2} \u00a7e--\u00a76 \u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u00a7c{0}\u00a76/\u00a7c{1} \u00a7e--- +infoUnknownChapter=\u00a74\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c. +insufficientFunds=\u00a74\u041d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0441\u0440\u0435\u0434\u0441\u0442\u0432. +invalidCharge=\u00a74\u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u0437\u0430\u0440\u044f\u0434. +invalidFireworkFormat=\u00a74\u041e\u043f\u0446\u0438\u044f \u00a7c{0} \u00a74\u0438\u043c\u0435\u0435\u0442 \u043d\u0435\u0432\u0435\u0440\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u00a7c{1}\u00a74. +invalidHome=\u00a74\u0414\u043e\u043c\u0430\u00a7c {0} \u00a74\u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442\! +invalidHomeName=\u00a74\u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0434\u043e\u043c\u0430\! +invalidMob=\u00a74\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u044b\u0439 \u0442\u0438\u043f \u043c\u043e\u0431\u0430. +invalidNumber=\u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0435 \u0447\u0438\u0441\u043b\u043e. +invalidPotion=\u00a74\u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0435 \u0437\u0435\u043b\u044c\u0435. +invalidPotionMeta=\u00a74\u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0435 \u043c\u0435\u0442\u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0437\u0435\u043b\u044c\u044f\: \u00a7c{0}\u00a74. +invalidSignLine=\u00a74\u041b\u0438\u043d\u0438\u044f\u00a7c {0} \u00a74\u043d\u0430 \u0442\u0430\u0431\u043b\u0438\u0447\u043a\u0435 \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u0430. +invalidWarpName=\u00a74\u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0432\u0430\u0440\u043f\u0430\! +invalidWorld=\u00a74\u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u043c\u0438\u0440. +is=\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f +itemCannotBeSold=\u00a74\u042d\u0442\u043e\u0442 \u043f\u0440\u0435\u0434\u043c\u0435\u0442 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0434\u0430\u043d. +itemMustBeStacked=\u00a74\u041f\u0440\u0435\u0434\u043c\u0435\u0442\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0432 \u0441\u0442\u0430\u043a\u0435. A quantity of 2s would be two stacks, etc. +itemNames=\u00a76\u041c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u0430\:\u00a7r {0} +itemNotEnough1=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043e\u0432 \u0434\u043b\u044f \u043f\u0440\u043e\u0434\u0430\u0436\u0438. +itemNotEnough2=\u00a76\u0415\u0441\u043b\u0438 \u0412\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u0440\u043e\u0434\u0430\u0442\u044c \u0432\u0441\u0435 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u044b \u044d\u0442\u043e\u0433\u043e \u0442\u0438\u043f\u0430, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 /sell itemname. +itemNotEnough3=\u00a76/sell itemname -1 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0434\u0430\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u044b, \u043a\u0440\u043e\u043c\u0435 \u043e\u0434\u043d\u043e\u0433\u043e, \u0438 \u0442.\u0434. +itemSellAir=\u041f\u0440\u043e\u0434\u0430\u0436\u0430 \u0432\u043e\u0437\u0434\u0443\u0445\u0430 \u043a\u0430\u0440\u0430\u0435\u0442\u0441\u044f \u0441\u043c\u0435\u0440\u0442\u044c\u044e \u043e\u0442 \u043f\u0430\u0434\u0435\u043d\u0438\u044f \u0432 \u043f\u0443\u0441\u0442\u043e\u0442\u0443. \u0412\u043e\u0437\u044c\u043c\u0438 \u0432 \u0440\u0443\u043a\u0443 \u043f\u0440\u0435\u0434\u043c\u0435\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0445\u043e\u0447\u0435\u0448\u044c \u043f\u0440\u043e\u0434\u0430\u0442\u044c. +itemSold=\u00a7a\u041f\u0440\u043e\u0434\u0430\u043d\u043e \u0437\u0430 \u00a7c{0} \u00a7a({1} {2} \u043f\u043e {3} \u043a\u0430\u0436\u0434\u044b\u0439). +itemSoldConsole=\u00a7a{0} \u00a7a\u043f\u0440\u043e\u0434\u0430\u043b {1} \u0437\u0430 \u00a7a{2} \u00a7a({3} \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043e\u0432 \u0437\u0430 {4} \u043a\u0430\u0436\u0434\u044b\u0439). +itemSpawn=\u00a76\u0412\u044b\u0434\u0430\u043d\u043e\u00a7c {0} \u00a76\u0448\u0442\u0443\u043a\u00a7c {1} +itemType=\u00a76\u041f\u0440\u0435\u0434\u043c\u0435\u0442\:\u00a7c {0} \u00a76-\u00a7c {1} +itemsCsvNotLoaded=\u041d\u0435 \u043c\u043e\u0433\u0443 \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c items.csv\! +jailAlreadyIncarcerated=\u00a74\u0438\u0433\u0440\u043e\u043a \u0443\u0436\u0435 \u0432 \u0442\u044e\u0440\u044c\u043c\u0435\:\u00a7c {0} +jailMessage=\u00a74\u0412\u044b \u043f\u043e\u043f\u0430\u043b\u0438 \u0432 \u0442\u044e\u0440\u044c\u043c\u0443. \u041f\u0440\u0438\u044f\u0442\u043d\u043e\u0433\u043e \u043e\u0442\u0434\u044b\u0445\u0430\! +jailNotExist=\u00a74\u042d\u0442\u043e\u0439 \u0442\u044e\u0440\u044c\u043c\u044b \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442. +jailReleased=\u00a76\u0418\u0433\u0440\u043e\u043a \u00a7c{0}\u00a76 \u0432\u044b\u043f\u0443\u0449\u0435\u043d \u043d\u0430 \u0441\u0432\u043e\u0431\u043e\u0434\u0443. +jailReleasedPlayerNotify=\u00a76\u0412\u044b \u0431\u044b\u043b\u0438 \u0432\u044b\u043f\u0443\u0449\u0435\u043d\! +jailSentenceExtended=\u00a76\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432 \u0442\u044e\u0440\u044c\u043c\u0435\: {0} +jailSet=\u00a76\u0422\u044e\u0440\u044c\u043c\u0430\u00a7c {0} \u00a76\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430. +jumpError=\u00a74\u041e\u0443\u0443... \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0432\u0440\u0435\u0434\u0438\u0442\u044c \u0442\u0432\u043e\u0435\u0439 \u0432\u0438\u0434\u0435\u043e\u043a\u0430\u0440\u0442\u0435. +kickDefault=\u0422\u0435\u0431\u044f \u043a\u0438\u043a\u043d\u0443\u043b\u0438 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430. \u041d\u0435 \u0432\u0435\u0434\u0438 \u0441\u0435\u0431\u044f \u043f\u043b\u043e\u0445\u043e ;) +kickExempt=\u00a74\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u043a\u0438\u043a\u043d\u0443\u0442\u044c \u044d\u0442\u043e\u0433\u043e \u0438\u0433\u0440\u043e\u043a\u0430. +kickedAll=\u00a74\u0412\u0441\u0435\u0445 \u0438\u0433\u0440\u043e\u043a\u043e\u0432 \u0441\u043d\u0435\u0441\u043b\u043e \u0443\u0440\u0430\u0433\u0430\u043d\u043d\u044b\u043c \u00a7c/kickall. +kill=\u00a76\u0423\u0431\u0438\u043b\u0438\:\u00a7c {0}\u00a76. +killExempt=\u00a74\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0443\u0431\u0438\u0442\u044c \u00a7c{0}\u00a74. +kitCost=\ \u00a77\u00a7o({0})\u00a7r +kitError2=\u00a74\u042d\u0442\u043e\u0433\u043e \u043d\u0430\u0431\u043e\u0440\u0430 \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0438\u043b\u0438 \u043d\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438. +kitError=\u00a74\u042d\u0442\u043e\u0442 \u043d\u0430\u0431\u043e\u0440 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0432\u044b\u0434\u0430\u043d. +kitGiveTo=\u00a76\u0412\u044b\u0434\u0430\u043d \u043d\u0430\u0431\u043e\u0440\u00a7c {0}\u00a76 \u0438\u0433\u0440\u043e\u043a\u0443 \u00a7c{1}\u00a76. +kitInvFull=\u00a74\u0412\u0430\u0448 \u0438\u043d\u0432\u0435\u043d\u0442\u0430\u0440\u044c \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d. \u041f\u0440\u0435\u0434\u043c\u0435\u0442\u044b \u043d\u0430\u0431\u043e\u0440\u0430 \u043b\u0435\u0436\u0430\u0442 \u043e\u043a\u043e\u043b\u043e \u0412\u0430\u0441. +kitNotFound=\u00a74\u041d\u0430\u0431\u043e\u0440\u0430 \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442. +kitOnce=\u00a74\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u043d\u0430\u0431\u043e\u0440 \u0441\u043d\u043e\u0432\u0430. +kitReceive=\u00a76\u041f\u043e\u043b\u0443\u0447\u0435\u043d \u043d\u0430\u0431\u043e\u0440\u00a7c {0}\u00a76. +kitTimed=\u00a74\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u043d\u0430\u0431\u043e\u0440 \u0440\u0430\u043d\u044c\u0448\u0435, \u0447\u0435\u043c \u0447\u0435\u0440\u0435\u0437\u00a7c {0}\u00a74. +kits=\u00a76\u041d\u0430\u0431\u043e\u0440\u044b\:\u00a7r {0} +leatherSyntax=\u00a76\u0421\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441 \u0446\u0432\u0435\u0442\u0430 \u043a\u043e\u0436\u0438\: color\:<\u043a\u0440\u0430\u0441\u043d\u044b\u0439>,<\u0437\u0435\u043b\u0435\u043d\u044b\u0439>,<\u0441\u0438\u043d\u0438\u0439> \u041f\u0440\u0438\u043c\u0435\u0440\: color\:255,0,0. +lightningSmited=\u00a76\u0412 \u0412\u0430\u0441 \u0443\u0434\u0430\u0440\u0438\u043b\u0430 \u043c\u043e\u043b\u043d\u0438\u044f\! +lightningUse=\u00a76\u0423\u0434\u0430\u0440\u0438\u043b\u0438 \u043c\u043e\u043b\u043d\u0438\u0435\u0439 \u0432 \u0438\u0433\u0440\u043e\u043a\u0430\u00a7c {0} +listAfkTag=\u00a77[\u041e\u0442\u043e\u0448\u0435\u043b]\u00a7r +listAmount=\u00a76\u0421\u0435\u0439\u0447\u0430\u0441 \u00a7c{0}\u00a76 \u0438\u0437 \u00a7c{1}\u00a76 \u0438\u0433\u0440\u043e\u043a\u043e\u0432 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435. +listAmountHidden=\u00a76\u0421\u0435\u0439\u0447\u0430\u0441 \u00a7c{0}\u00a76/{1}\u00a76 \u0438\u0437 \u00a7c{2}\u00a76 \u0438\u0433\u0440\u043e\u043a\u043e\u0432 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435. +listGroupTag=\u00a76{0}\u00a7r\: \u00a7r +listHiddenTag=\u00a77[\u0421\u041a\u0420\u042b\u0422]\u00a7r +loadWarpError=\u00a74\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0432\u0430\u0440\u043f {0}. +localFormat=[L]<{0}> {1} +mailClear=\u00a76\u0427\u0442\u043e\u0431\u044b \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c \u0412\u0430\u0448\u0438 \u043f\u0438\u0441\u044c\u043c\u0430 \u043a\u0430\u043a \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043d\u043d\u044b\u0435, \u0432\u0432\u0435\u0434\u0438\u0442\u0435\u00a7c /mail clear\u00a76. +mailCleared=\u00a76\u041f\u0438\u0441\u044c\u043c\u0430 \u043e\u0447\u0438\u0449\u0435\u043d\u044b\! +mailSent=\u00a76\u041f\u0438\u0441\u044c\u043c\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043e\! +markMailAsRead=\u00a76\u0427\u0442\u043e\u0431\u044b \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c \u0412\u0430\u0448\u0438 \u043f\u0438\u0441\u044c\u043c\u0430 \u043a\u0430\u043a \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043d\u043d\u044b\u0435, \u0432\u0432\u0435\u0434\u0438\u0442\u0435\u00a7c /mail clear\u00a76. +markedAsAway=\u00a76\u0412\u044b \u043e\u0442\u043c\u0435\u0447\u0435\u043d\u044b \u043a\u0430\u043a \u043e\u0442\u043e\u0448\u0435\u0434\u0448\u0438\u0439. +markedAsNotAway=\u00a76\u0422\u0435\u043f\u0435\u0440\u044c \u0412\u044b \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u043e\u0442\u043c\u0435\u0447\u0435\u043d\u044b \u043a\u0430\u043a \u043e\u0442\u043e\u0448\u0435\u0434\u0448\u0438\u0439. +matchingIPAddress=\u00a76\u0418\u0433\u0440\u043e\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u044b\u043b\u0438 \u0437\u0430\u043c\u0435\u0447\u0435\u043d\u044b \u0441 \u044d\u0442\u0438\u043c IP \u0430\u0434\u0440\u0435\u0441\u043e\u043c\: +maxHomes=\u00a74\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435\u00a7c {0} \u00a74\u0434\u043e\u043c\u0430(\u043e\u0432). +mayNotJail=\u00a74\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u044d\u0442\u043e\u0433\u043e \u0438\u0433\u0440\u043e\u043a\u0430 \u0432 \u0442\u044e\u0440\u044c\u043c\u0443\! +me=\u042f +minute=\u043c\u0438\u043d\u0443\u0442\u0430 +minutes=\u043c\u0438\u043d\u0443\u0442 +missingItems=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u00a7c{0}x {1}\u00a74. +mobSpawnError=\u00a74\u041f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0432\u0438\u0434\u0430 \u0441\u043f\u0430\u0443\u043d\u0435\u0440\u0430 \u043c\u043e\u0431\u043e\u0432 (ID 52). +mobSpawnLimit=\u0421\u043f\u0430\u0443\u043d \u043c\u043e\u0431\u043e\u0432 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430. +mobSpawnTarget=\u00a74\u0412\u044b \u0434\u043e\u043b\u0436\u0435\u043d\u044b \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430 \u0441\u043f\u0430\u0443\u043d\u0435\u0440 \u043c\u043e\u0431\u043e\u0432. +mobsAvailable=\u00a76\u041c\u043e\u0431\u044b\:\u00a7r {0} +moneyRecievedFrom=\u00a7a{0} \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043e \u043e\u0442 \u0438\u0433\u0440\u043e\u043a\u0430 {1}. +moneySentTo=\u00a7a{0} \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043e \u0438\u0433\u0440\u043e\u043a\u0443 {1}. +month=\u043c\u0435\u0441\u044f\u0446 +months=\u043c\u0435\u0441\u044f\u0446\u0435\u0432 +moreThanZero=\u00a74\u0417\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 0. +moveSpeed=\u00a76\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c {0} \u043d\u0430\u00a7c {1} \u00a76\u0434\u043b\u044f \u00a7c{2}\u00a76. +msgFormat=\u00a76[\u00a7c{0}\u00a76 -> \u00a7c{1}\u00a76] \u00a7r{2} +multipleCharges=\u00a74\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u043e\u0434\u043d\u043e\u0433\u043e \u0437\u0430\u0440\u044f\u0434\u0430 \u0434\u043b\u044f \u0444\u0435\u0439\u0435\u0440\u0432\u0435\u0440\u043a\u0430. +multiplePotionEffects=\u00a74\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043e\u0434\u043d\u043e\u0433\u043e \u044d\u0444\u0444\u0435\u043a\u0442\u0430 \u0434\u043b\u044f \u0437\u0435\u043b\u044c\u044f. +muteExempt=\u00a74\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0437\u0430\u0442\u043a\u043d\u0443\u0442\u044c \u044d\u0442\u043e\u0433\u043e \u0438\u0433\u0440\u043e\u043a\u0430. +muteNotify=\u00a7c{0} \u00a76\u0431\u044b\u043b \u0437\u0430\u0442\u043a\u043d\u0443\u0442 \u00a7c{1}\u00a76. +mutedPlayer=\u00a76\u0418\u0433\u0440\u043e\u043a {0} \u00a76\u0437\u0430\u0442\u043a\u043d\u0443\u0442. +mutedPlayerFor=\u00a76\u0418\u0433\u0440\u043e\u043a {0} \u00a76\u0437\u0430\u0442\u043a\u043d\u0443\u0442 \u043d\u0430 {1}. +mutedUserSpeaks={0} \u043f\u043e\u043f\u044b\u0442\u0430\u043b\u0441\u044f \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u043d\u043e \u043e\u043d \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c. +nearbyPlayers=\u00a76\u041e\u043a\u0440\u0443\u0436\u0430\u044e\u0449\u0438\u0435 \u0438\u0433\u0440\u043e\u043a\u0438\:\u00a7r {0} +negativeBalanceError=\u00a74\u0418\u0433\u0440\u043e\u043a \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u043f\u0440\u0430\u0432 \u043d\u0430 \u043e\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0431\u0430\u043b\u0430\u043d\u0441. +nickChanged=\u00a76\u041d\u0438\u043a \u0438\u0437\u043c\u0435\u043d\u0435\u043d. +nickDisplayName=\u00a74\u0412\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043e\u043f\u0446\u0438\u044e change-displayname \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 Essentials. +nickInUse=\u00a74\u0414\u0430\u043d\u043d\u044b\u0439 \u043d\u0438\u043a \u0443\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f. +nickNamesAlpha=\u00a74\u041d\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0431\u0443\u043a\u0432\u0435\u043d\u043d\u043e-\u0446\u0438\u0444\u0440\u043e\u0432\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435. +nickNoMore=\u00a76\u0422\u0435\u043f\u0435\u0440\u044c \u0443 \u0412\u0430\u0441 \u0441\u0432\u043e\u0439 \u043d\u0438\u043a. +nickSet=\u00a76\u0422\u0435\u043f\u0435\u0440\u044c \u0412\u0430\u0448 \u043d\u0438\u043a \u00a7c{0}\u00a76. +nickTooLong=\u00a74\u041d\u0438\u043a \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0434\u043b\u0438\u043d\u043d\u044b\u0439. +noAccessCommand=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432 \u0434\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b. +noAccessPermission=\u00a74\u0412\u044b \u043d\u0435 \u0438\u043c\u0435\u0435\u0442\u0435 \u043f\u0440\u0430\u0432 \u043d\u0430 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u00a7c{0}\u00a74. +noBreakBedrock=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432 \u043b\u043e\u043c\u0430\u0442\u044c \u043a\u043e\u0440\u0435\u043d\u043d\u0443\u044e \u043f\u043e\u0440\u043e\u0434\u0443. +noDestroyPermission=\u00a74\u0412\u044b \u043d\u0435 \u0438\u043c\u0435\u0435\u0442\u0435 \u043f\u0440\u0430\u0432 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0443\u0448\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0433\u043e \u00a7c{0}\u00a74. +noDurability=\u00a74\u042d\u0442\u043e\u0442 \u043f\u0440\u0435\u0434\u043c\u0435\u0442 \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0447\u043d\u043e\u0441\u0442\u0438. +noGodWorldWarning=\u00a74\u0412\u043d\u0438\u043c\u0430\u043d\u0438\u0435\! \u0420\u0435\u0436\u0438\u043c \u0411\u043e\u0433\u0430 \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d \u0432 \u044d\u0442\u043e\u043c \u043c\u0438\u0440\u0435. +noHelpFound=\u00a74\u041a\u043e\u043c\u0430\u043d\u0434 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e. +noHomeSetPlayer=\u00a76\u0418\u0433\u0440\u043e\u043a \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u0434\u043e\u043c\u0430. +noIgnored=\u00a76\u0422\u0435\u043f\u0435\u0440\u044c \u0412\u044b \u043d\u0438\u043a\u043e\u0433\u043e \u043d\u0435 \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u0435\u0442\u0435. +noKitPermission=\u00a74\u0423 \u0412\u0430\u0441 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u00a7c{0}\u00a74 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043d\u0430\u0431\u043e\u0440\u0430. +noKits=\u00a76\u041d\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u043d\u0430\u0431\u043e\u0440\u043e\u0432. +noMail=\u00a76\u041d\u043e\u0432\u044b\u0445 \u043f\u0438\u0441\u0435\u043c \u043d\u0435\u0442. +noMatchingPlayers=\u00a76\u0438\u0433\u0440\u043e\u043a \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d. +noMetaFirework=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432 \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043c\u0435\u0442\u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0444\u0435\u0439\u0435\u0440\u0432\u0435\u0440\u043a\u0430. +noMetaPerm=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432 \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043c\u0435\u0442\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u00a7c{0}\u00a74 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u0430. +noNewMail=\u00a76\u041d\u0435\u0442 \u043d\u043e\u0432\u044b\u0445 \u043f\u0438\u0441\u0435\u043c. +noPendingRequest=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u043e\u0436\u0438\u0434\u0430\u044e\u0449\u0438\u0445 \u0437\u0430\u044f\u0432\u043e\u043a \u043d\u0430 \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435. +noPerm=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f \u00a7c{0}\u00a74. +noPermToSpawnMob=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432 \u0434\u043b\u044f \u0441\u043f\u0430\u0443\u043d\u0430 \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u0431\u0430. +noPlacePermission=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432 \u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0431\u043b\u043e\u043a\u0438 \u043e\u043a\u043e\u043b\u043e \u044d\u0442\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0447\u043a\u0438. +noPotionEffectPerm=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432 \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u044d\u0444\u0444\u0435\u043a\u0442\u0430 \u00a7c{0} \u00a74\u043d\u0430 \u044d\u0442\u043e \u0437\u0435\u043b\u044c\u0435. +noPowerTools=\u00a76\u0423 \u0412\u0430\u0441 \u043d\u0435 \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432. +noWarpsDefined=\u00a76\u041d\u0435\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u0432\u0430\u0440\u043f\u043e\u0432. +none=\u043d\u0438\u0447\u0435\u0433\u043e +notAllowedToQuestion=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432 \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439, \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0438\u0445\u0441\u044f \u0441 \u0432\u043e\u043f\u0440\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0437\u043d\u0430\u043a\u0430. +notAllowedToShout=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432 \u043d\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0447\u0430\u0442\u0430. +notEnoughExperience=\u00a74\u041d\u0435 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043e\u043f\u044b\u0442\u0430. +notEnoughMoney=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0434\u0435\u043d\u0435\u0433. +notFlying=\u043d\u0435 \u043b\u0435\u0442\u0430\u0435\u0442 +notRecommendedBukkit=\u00a74* \! * \u0412\u0435\u0440\u0441\u0438\u044f Bukkit \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u0434\u043b\u044f Essentials. +notSupportedYet=\u041d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e. +nothingInHand=\u00a74\u0423 \u0442\u0435\u0431\u044f \u043d\u0435\u0442 \u043d\u0438\u0447\u0435\u0433\u043e \u0432 \u0440\u0443\u043a\u0430\u0445. +now=\u0441\u0435\u0439\u0447\u0430\u0441 +nuke=\u00a75\u0414\u043e\u0436\u0434\u044c \u0421\u043c\u0435\u0440\u0442\u0438 \u043f\u0430\u0434\u0430\u0435\u0442 \u0441 \u043d\u0435\u0431\u0430. +numberRequired=\u0422\u0443\u0442 \u0433\u0434\u0435-\u0442\u043e \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0447\u0438\u0441\u043b\u043e. \u041d\u0435\u043f\u043e\u0440\u044f\u0434\u043e\u043a. +onlyDayNight=\u041a\u043e\u043c\u0430\u043d\u0434\u0430 /time \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e day/night. +onlyPlayerSkulls=\u00a74\u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430 \u0433\u043e\u043b\u043e\u0432\u044b \u0438\u0433\u0440\u043e\u043a\u0430 (\u00a7c397\:3\u00a74). +onlyPlayers=\u00a74\u0422\u043e\u043b\u044c\u043a\u043e \u0432 \u0438\u0433\u0440\u0435 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u00a7c{0}\u00a74. +onlySunStorm=\u00a74\u041a\u043e\u043c\u0430\u043d\u0434\u0430 /weather \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e sun/storm. +orderBalances=\u00a76\u041f\u043e\u0434\u0441\u0447\u0435\u0442 \u0431\u0430\u043b\u0430\u043d\u0441\u0430\u00a7c {0} \u00a76\u0438\u0433\u0440\u043e\u043a\u043e\u0432, \u043f\u043e\u0434\u043e\u0436\u0434\u0438 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0440\u0435\u043c\u044f. +oversizedTempban=\u00a74\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0437\u0430\u0431\u0430\u043d\u0438\u0442\u044c \u0438\u0433\u0440\u043e\u043a\u0430 \u043d\u0430 \u0442\u0430\u043a\u043e\u0439 \u0441\u0440\u043e\u043a. +pTimeCurrent=\u00a76\u0412\u0440\u0435\u043c\u044f \u0438\u0433\u0440\u043e\u043a\u0430 \u00a7c{0} - {1}\u00a76. +pTimeCurrentFixed=\u00a76\u0412\u0440\u0435\u043c\u044f \u0438\u0433\u0440\u043e\u043a\u0430 \u00a7c{0}\u00a76 \u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043e \u043d\u0430\u00a7c {1}\u00a76. +pTimeNormal=\u00a76\u0412\u0440\u0435\u043c\u044f \u0438\u0433\u0440\u043e\u043a\u0430 \u00a7c{0}\u00a76 \u0442\u0435\u043f\u0435\u0440\u044c \u0442\u0430\u043a\u043e\u0435 \u0436\u0435, \u043a\u0430\u043a \u0438 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435. +pTimeOthersPermission=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432 \u0434\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0438\u0433\u0440\u043e\u043a\u0430\u043c. +pTimePlayers=\u00a76\u042d\u0442\u0438 \u0438\u0433\u0440\u043e\u043a\u0438 \u0438\u043c\u0435\u044e\u0442 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f\:\u00a7r +pTimeReset=\u00a76\u0412\u0440\u0435\u043c\u044f \u0441\u0431\u0440\u043e\u0448\u0435\u043d\u043e \u0434\u043b\u044f\: \u00a7c{0} +pTimeSet=\u00a76\u0412\u0440\u0435\u043c\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e \u043d\u0430 \u00a7c{0}\u00a76 \u0434\u043b\u044f\: \u00a7c{1}. +pTimeSetFixed=\u00a76\u0412\u0440\u0435\u043c\u044f \u0438\u0433\u0440\u043e\u043a\u0430 \u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043e \u043d\u0430 \u00a7c{0}\u00a76 \u0434\u043b\u044f\: \u00a7c{1}. +pWeatherCurrent=\u00a76\u041f\u043e\u0433\u043e\u0434\u0430 \u0438\u0433\u0440\u043e\u043a\u0430 \u00a7c{0}\u00a76\: {1}\u00a76. +pWeatherInvalidAlias=\u00a74\u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u0442\u0438\u043f \u043f\u043e\u0433\u043e\u0434\u044b +pWeatherNormal=\u00a76\u041f\u043e\u0433\u043e\u0434\u0430 \u0438\u0433\u0440\u043e\u043a\u0430\u00a7c{0}\u00a76 \u0442\u0435\u043f\u0435\u0440\u044c \u043a\u0430\u043a \u0438 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435. +pWeatherOthersPermission=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e. +pWeatherPlayers=\u00a76\u0418\u0433\u0440\u043e\u043a\u0438 \u0438\u043c\u0435\u044e\u0449\u0438\u0435 \u0441\u0432\u043e\u044e \u043f\u043e\u0433\u043e\u0434\u0443\:\u00a7r +pWeatherReset=\u00a76\u041f\u043e\u0433\u043e\u0434\u0430 \u0438\u0433\u0440\u043e\u043a\u0430 \u0431\u044b\u043b\u0430 \u0441\u0431\u0440\u043e\u0448\u0435\u043d\u0430 \u043d\u0430\: \u00a7c{0} +pWeatherSet=\u00a76\u041f\u043e\u0433\u043e\u0434\u0430 \u0438\u0433\u0440\u043e\u043a\u0430 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430 \u043d\u0430 \u00a7c{0}\u00a76 \u0434\u043b\u044f\: \u00a7c{1}. +pendingTeleportCancelled=\u00a74\u0417\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0430\u0446\u0438\u044e \u043e\u0442\u043c\u0435\u043d\u0435\u043d. +playerBanIpAddress=\u00a76Player\u00a7c {0} \u00a76banned IP address\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerBanned=\u00a76\u0418\u0433\u0440\u043e\u043a\u00a7c {0} \u00a76\u0437\u0430\u0431\u0430\u043d\u0438\u043b\u00a7c {1} \u00a76\u0437\u0430 \u00a7c{2}\u00a76. +playerInJail=\u00a74\u0418\u0433\u0440\u043e\u043a \u0443\u0436\u0435 \u0432 \u0442\u044e\u0440\u044c\u043c\u0435\u00a7c {0}\u00a74. +playerJailed=\u00a76\u0418\u0433\u0440\u043e\u043a\u00a7c {0} \u00a76\u043f\u043e\u0441\u0430\u0436\u0435\u043d \u0432 \u0442\u044e\u0440\u044c\u043c\u0443. +playerJailedFor=\u00a76\u0418\u0433\u0440\u043e\u043a\u00a7c {0} \u00a76\u043f\u043e\u0441\u0430\u0436\u0435\u043d \u0432 \u0442\u044e\u0440\u044c\u043c\u0443 \u043d\u0430 {1}. +playerKicked=\u00a76\u0418\u0433\u0440\u043e\u043a\u00a7c {1} \u00a76\u043a\u0438\u043a\u043d\u0443\u0442 {0}. \u041f\u0440\u0438\u0447\u0438\u043d\u0430\: {2}. +playerMuted=\u00a76\u0422\u0435\u043f\u0435\u0440\u044c \u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u0447\u0430\u0442\! +playerMutedFor=\u00a76\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u0447\u0430\u0442 \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0438\u00a7c {0}. +playerNeverOnServer=\u00a74\u0418\u0433\u0440\u043e\u043a\u0430\u00a7c {0} \u00a74\u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0431\u044b\u043b\u043e \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435. +playerNotFound=\u00a74\u0418\u0433\u0440\u043e\u043a \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d. +playerUnbanIpAddress=\u00a76\u0418\u0433\u0440\u043e\u043a\u00a7c {0} \u00a76\u0440\u0430\u0437\u0431\u0430\u043d\u0438\u043b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 IP \u0430\u0434\u0440\u0435\u0441\: {1}. +playerUnbanned=\u00a76\u0418\u0433\u0440\u043e\u043a\u0430\u00a7c {1} \u00a76\u0440\u0430\u0437\u0431\u0430\u043d\u0438\u043b {0}. +playerUnmuted=\u00a76\u0422\u0435\u043f\u0435\u0440\u044c \u0412\u044b \u0441\u043d\u043e\u0432\u0430 \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u0447\u0430\u0442. +pong=\u041f\u043e\u043d\u0433\! +posPitch=\u00a76\u0412\u044b\u0441\u043e\u0442\u0430\: {0} (\u0423\u0440\u043e\u0432\u0435\u043d\u044c \u0433\u043e\u043b\u043e\u0432\u044b) +posX=\u00a76X\: {0} (+\u0412\u043e\u0441\u0442\u043e\u043a <-> -\u0417\u0430\u043f\u0430\u0434) +posY=\u00a76Y\: {0} (+\u0412\u0432\u0435\u0440\u0445 <-> -\u041d\u0438\u0437) +posYaw=\u00a76Yaw\: {0} (\u0412\u0440\u0430\u0449\u0435\u043d\u0438\u0435) +posZ=\u00a76Z\: {0} (+\u042e\u0433 <-> -\u0421\u0435\u0432\u0435\u0440) +possibleWorlds=\u00a76\u041d\u043e\u043c\u0435\u0440\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 \u043c\u0438\u0440\u043e\u0432 \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0442\u0441\u044f \u0441 \u00a7c0\u00a76 \u0438 \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u00a7c{0}\u00a76. +potions=\u00a76\u0417\u0435\u043b\u044c\u044f\:\u00a7r {0}\u00a76. +powerToolAir=\u00a74\u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0430 \u043d\u0430 \u0440\u0443\u043a\u0443. +powerToolAlreadySet=\u00a74\u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u00a7c{0}\u00a74 \u0443\u0436\u0435 \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0430 \u043d\u0430 \u00a7c{1}\u00a74. +powerToolAttach=\u00a76\u041a\u043e\u043c\u0430\u043d\u0434\u0430\u00a7c {0} \u00a76\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0430 \u043d\u0430 {1}. +powerToolClearAll=\u00a76\u0412\u0441\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0431\u044b\u043b\u0438 \u043e\u0447\u0438\u0449\u0435\u043d\u044b. +powerToolList=\u00a76\u041f\u0440\u0435\u0434\u043c\u0435\u0442 \u00a7c{1} \u00a76\u0438\u043c\u0435\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u0449\u0438\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b\: \u00a7c{0}\u00a76. +powerToolListEmpty=\u00a74\u041f\u0440\u0435\u0434\u043c\u0435\u0442 \u00a7c{0} \u00a74\u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044b\u0445 \u043a\u043e\u043c\u0430\u043d\u0434. +powerToolNoSuchCommandAssigned=\u00a74\u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u00a7c{0}\u00a74 \u043d\u0435 \u0431\u044b\u043b\u0430 \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0430 \u043d\u0430 \u00a7c{1}\u00a74. +powerToolRemove=\u00a76\u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u00a7c{0}\u00a76 \u0441\u043d\u044f\u0442\u0430 \u0441 \u00a7c{1}\u00a76. +powerToolRemoveAll=\u00a76\u0412\u0441\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0441\u043d\u044f\u0442\u044b \u0441 \u00a7c{0}\u00a76. +powerToolsDisabled=\u00a76\u0412\u0441\u0435 \u0412\u0430\u0448\u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d\u044b. +powerToolsEnabled=\u00a76\u0412\u0441\u0435 \u0412\u0430\u0448\u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u044b. +questionFormat=\u00a72[\u0412\u043e\u043f\u0440\u043e\u0441]\u00a7r {0} +readNextPage=\u00a76\u0412\u0432\u0435\u0434\u0438\u00a7c /{0} {1} \u00a76\u0434\u043b\u044f \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b. +recipe=\u00a76\u0420\u0435\u0446\u0435\u043f\u0442 \u00a7c{0}\u00a76 (\u00a7c{1}\u00a76 \u0438\u0437 \u00a7c{2}\u00a76) +recipeBadIndex=\u0420\u0435\u0446\u0435\u043f\u0442\u0430 \u0434\u043b\u044f \u0442\u0430\u043a\u043e\u0433\u043e \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u0430 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e. +recipeFurnace=\u00a76\u0416\u0430\u0440\u0438\u0442\u044c \u0432 \u043f\u0435\u0447\u0438\: \u00a7c{0}\u00a76. +recipeGrid=\u00a7c{0}X \u00a76| \u00a7{1}X \u00a76| \u00a7{2}X +recipeGridItem=\u00a7c{0}X \u00a76\u044d\u0442\u043e \u00a7c{1} +recipeMore=\u00a76\u0412\u0432\u0435\u0434\u0438 /{0} \u00a7c{1}\u00a76 <\u043d\u043e\u043c\u0435\u0440> \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u0440\u0435\u0446\u0435\u043f\u0442\u043e\u0432 \u00a7c{2}\u00a76. +recipeNone=\u041d\u0435\u0442 \u0440\u0435\u0446\u0435\u043f\u0442\u0430 \u0434\u043b\u044f {0} +recipeNothing=\u043d\u0438\u0447\u0435\u0433\u043e +recipeShapeless=\u00a76\u0421\u043c\u0435\u0448\u0438\u0432\u0430\u0435\u043c \u00a7c{0} +recipeWhere=\u00a76\u0413\u0434\u0435\: {0} +removed=\u00a76\u0423\u0431\u0440\u0430\u043d\u043e\u00a7c {0} \u00a76\u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432. +repair=\u00a76\u0412\u044b \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u043f\u043e\u0447\u0438\u043d\u0438\u043b\u0438 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\: \u00a7c{0}. +repairAlreadyFixed=\u00a74\u042d\u0442\u043e\u0442 \u043f\u0440\u0435\u0434\u043c\u0435\u0442 \u043d\u0435 \u043d\u0443\u0436\u0434\u0430\u0435\u0442\u0441\u044f \u0432 \u043f\u043e\u0447\u0438\u043d\u043a\u0435. +repairEnchanted=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u0430\u0432 \u0434\u043b\u044f \u0440\u0435\u043c\u043e\u043d\u0442\u0430 \u0437\u0430\u0447\u0430\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0432\u0435\u0449\u0435\u0439. +repairInvalidType=\u00a74\u042d\u0442\u043e\u0442 \u043f\u0440\u0435\u0434\u043c\u0435\u0442 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0442\u0440\u0435\u043c\u043e\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d. +repairNone=\u00a74\u041d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0447\u0438\u043d\u0438\u0442\u044c. +requestAccepted=\u00a76\u0417\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0430\u0446\u0438\u044e \u043f\u0440\u0438\u043d\u044f\u0442. +requestAcceptedFrom=\u00a7c{0} \u00a76\u043f\u0440\u0438\u043d\u044f\u043b \u0412\u0430\u0448 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435. +requestDenied=\u00a76\u0417\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0430\u0446\u0438\u044e \u0431\u044b\u043b \u043e\u0442\u043a\u043b\u043e\u043d\u0435\u043d. +requestDeniedFrom=\u00a7c{0} \u00a76\u043e\u0442\u043a\u043b\u043e\u043d\u0438\u043b \u0412\u0430\u0448 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0430\u0446\u0438\u044e. +requestSent=\u00a76\u0417\u0430\u043f\u0440\u043e\u0441 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d \u0438\u0433\u0440\u043e\u043a\u0443\u00a7c {0}\u00a76. +requestTimedOut=\u00a74\u0412\u0440\u0435\u043c\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430 \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0430\u0446\u0438\u044e \u0432\u044b\u0448\u043b\u043e. +requiredBukkit=\u00a76* \! * \u0422\u044b \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c {0} \u0431\u0438\u043b\u0434 CraftBukkit, \u0441\u043a\u0430\u0447\u0430\u0442\u044c \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0442\u0443\u0442 http\://dl.bukkit.org/downloads/craftbukkit/ +resetBal=\u00a76\u0411\u0430\u043b\u0430\u043d\u0441 \u0431\u044b\u043b \u0441\u0431\u0440\u043e\u0448\u0435\u043d \u043d\u0430 \u00a7a{0} \u00a76\u0434\u043b\u044f \u0438\u0433\u0440\u043e\u043a\u043e\u0432 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435. +resetBalAll=\u00a76\u0411\u0430\u043b\u0430\u043d\u0441 \u0431\u044b\u043b \u0441\u0431\u0440\u043e\u0448\u0435\u043d \u043d\u0430 \u00a7a{0} \u00a76\u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0438\u0433\u0440\u043e\u043a\u043e\u0432. +returnPlayerToJailError=\u00a74\u041f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0435\u043d\u0438\u0438 \u0438\u0433\u0440\u043e\u043a\u0430\u00a7c {0} \u00a74\u0432 \u0442\u044e\u0440\u044c\u043c\u0443\: \u00a7c{1}\u00a74\! +runningPlayerMatch=\u00a76\u041d\u0430\u0447\u0430\u0442 \u043f\u043e\u0438\u0441\u043a \u0438\u0433\u0440\u043e\u043a\u043e\u0432 \u043f\u043e \u043c\u0430\u0441\u043a\u0435 ''\u00a7c{0}\u00a76'' (\u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043d\u044f\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0440\u0435\u043c\u044f) +second=\u0441\u0435\u043a\u0443\u043d\u0434\u0430 +seconds=\u0441\u0435\u043a\u0443\u043d\u0434 +seenOffline=\u00a76\u0418\u0433\u0440\u043e\u043a\u00a7c {0} \u00a74\u043e\u0444\u0444\u043b\u0430\u0439\u043d\u00a76 \u0441 \u00a7c{1}\u00a76. +seenOnline=\u00a76\u0418\u0433\u0440\u043e\u043a\u00a7c {0} \u00a7a\u043e\u043d\u043b\u0430\u0439\u043d\u00a76 \u0441 \u00a7c{1}\u00a76. +serverFull=\u0421\u0435\u0440\u0432\u0435\u0440 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\! +serverTotal=\u00a76\u0412\u0441\u0435\u0433\u043e\:\u00a7c {0} +setBal=\u00a7a\u0412\u0430\u0448 \u0431\u0430\u043b\u0430\u043d\u0441 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d \u043d\u0430 {0}. +setBalOthers=\u00a7a\u0412\u044b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438 \u0431\u0430\u043b\u0430\u043d\u0441 \u0438\u0433\u0440\u043e\u043a\u0430 {0} \u043d\u0430 {1}. +setSpawner=\u00a76\u0412\u0438\u0434 \u0441\u043f\u0430\u0443\u043d\u0435\u0440\u0430 \u043c\u043e\u0431\u043e\u0432 \u0438\u0437\u043c\u0435\u043d\u0435\u043d \u043d\u0430\u00a7c {0}. +sheepMalformedColor=\u00a74\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u0446\u0432\u0435\u0442. +shoutFormat=\u00a76[G]\u00a7r {0} +signFormatFail=\u00a74[{0}] +signFormatSuccess=\u00a71[{0}] +signFormatTemplate=[{0}] +signProtectInvalidLocation=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u0430\u0431\u043b\u0438\u0447\u0435\u043a \u043d\u0430 \u044d\u0442\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438. +similarWarpExist=\u00a74\u0412\u0430\u0440\u043f \u0441 \u0442\u0430\u043a\u0438\u043c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442. +slimeMalformedSize=\u00a74\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u0440\u0430\u0437\u043c\u0435\u0440. +socialSpy=\u00a76SocialSpy \u0434\u043b\u044f \u00a7c{0}\u00a76\: \u00a7c{1} +soloMob=\u00a74\u042d\u0442\u043e\u0442 \u043c\u043e\u0431 \u043b\u044e\u0431\u0438\u0442 \u0431\u044b\u0442\u044c \u0432 \u043e\u0434\u0438\u043d\u043e\u0447\u0435\u0441\u0442\u0432\u0435. +spawnSet=\u00a76\u0422\u043e\u0447\u043a\u0430 \u0441\u043f\u0430\u0443\u043d\u0430 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430 \u0434\u043b\u044f \u0433\u0440\u0443\u043f\u043f\u044b\u00a7c {0}\u00a76. +spawned=\u0441\u043e\u0437\u0434\u0430\u043d\u043e +sudoExempt=\u00a74\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b sudo \u0441 \u044d\u0442\u043e\u0433\u043e \u0438\u0433\u0440\u043e\u043a\u0430. +sudoRun=\u00a76Forcing\u00a7c {0} \u00a76to run\:\u00a7r /{1} +suicideMessage=\u00a76\u041f\u0440\u043e\u0449\u0430\u0439 \u0441\u0443\u0440\u043e\u0432\u044b\u0439 \u043c\u0438\u0440... +suicideSuccess=\u00a76{0} \u00a76\u043f\u043e\u043a\u043e\u043d\u0447\u0438\u043b \u0436\u0438\u0437\u043d\u044c \u0441\u0430\u043c\u043e\u0443\u0431\u0438\u0439\u0441\u0442\u0432\u043e\u043c. +survival=\u0432\u044b\u0436\u0438\u0432\u0430\u043d\u0438\u0435 +takenFromAccount=\u00a7a{0} \u0431\u044b\u043b\u043e \u0441\u043d\u044f\u0442\u043e \u0441 \u0442\u0432\u043e\u0435\u0433\u043e \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0430. +takenFromOthersAccount=\u00a7a{0} \u0441\u043d\u044f\u0442\u043e \u0441 \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0430 \u0438\u0433\u0440\u043e\u043a\u0430 {1}\u00a7a. \u0422\u0435\u043f\u0435\u0440\u044c \u0435\u0433\u043e \u0431\u0430\u043b\u0430\u043d\u0441\: {2}. +teleportAAll=\u00a76\u0417\u0430\u044f\u0432\u043a\u0438 \u043d\u0430 \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u044b \u0432\u0441\u0435\u043c \u0438\u0433\u0440\u043e\u043a\u0430\u043c... +teleportAll=\u00a76\u0422\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u044e \u0432\u0441\u0435\u0445 \u0438\u0433\u0440\u043e\u043a\u043e\u0432... +teleportAtoB=\u00a7c{0}\u00a76 \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043b \u0412\u0430\u0441 \u043a {1}\u00a76. +teleportDisabled=\u00a7c{0} \u00a74\u043e\u0442\u043a\u043b\u044e\u0447\u0438\u043b \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0430\u0446\u0438\u044e. +teleportHereRequest=\u00a7c{0}\u00a76 \u043f\u0440\u043e\u0441\u0438\u0442 \u0412\u0430\u0441 \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043a \u043d\u0435\u043c\u0443. +teleportNewPlayerError=\u00a74\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u0438\u0433\u0440\u043e\u043a\u0430\! +teleportRequest=\u00a7c{0}\u00a76 \u043f\u0440\u043e\u0441\u0438\u0442 \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043a \u0412\u0430\u043c. +teleportRequestTimeoutInfo=\u00a76\u0417\u0430\u044f\u0432\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0442\u043c\u0435\u043d\u0435\u043d\u0430 \u0447\u0435\u0440\u0435\u0437\u00a7c {0} \u0441\u0435\u043a\u0443\u043d\u0434\u00a76. +teleportTop=\u00a76\u0422\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0430\u0432\u0435\u0440\u0445. +teleportationCommencing=\u00a76\u0422\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f... +teleportationDisabled=\u00a76\u0422\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0438\u0446\u0438\u0438 \u00a7c\u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d\u044b\u00a76. +teleportationDisabledFor=\u00a76\u0422\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0430\u0446\u0438\u0438 \u00a7c\u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d\u044b \u00a76\u0434\u043b\u044f \u00a7c{0}\u00a76. +teleportationEnabled=\u00a76\u0422\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0430\u0446\u0438\u0438 \u00a7c\u0432\u043a\u043b\u044e\u0447\u0435\u043d\u044b\u00a76. +teleportationEnabledFor=\u00a76\u0422\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0430\u0446\u0438\u0438 \u00a7c\u0432\u043a\u043b\u044e\u0447\u0435\u043d\u044b \u00a76\u0434\u043b\u044f \u00a7c{0}\u00a76. +teleporting=\u00a76\u0422\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435... +teleportToPlayer=\u00a76\u0422\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043a \u00a7c{0}\u00a76. +tempBanned=\u00a7cYou have been temporarily banned for {0}\:\n\u00a7r{2} +tempbanExempt=\u00a74\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0437\u0430\u0431\u0430\u043d\u0438\u0442\u044c \u044d\u0442\u043e\u0433\u043e \u0438\u0433\u0440\u043e\u043a\u0430. +thunder=\u00a76\u0422\u044b\u00a7c {0} \u00a76\u0433\u0440\u043e\u0437\u0443 \u0432 \u0441\u0432\u043e\u0435\u043c \u043c\u0438\u0440\u0435. +thunderDuration=\u00a76\u0412\u044b\u00a7c {0} \u00a76\u0433\u0440\u043e\u0437\u0443 \u0432 \u0441\u0432\u043e\u0435\u043c \u043c\u0438\u0440\u0435 \u043d\u0430\u00a7c {1} \u00a76\u0441\u0435\u043a\u0443\u043d\u0434. +timeBeforeHeal=\u00a76\u0412\u0440\u0435\u043c\u0435\u043d\u0438 \u0434\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u043b\u0435\u0447\u0435\u043d\u0438\u044f\:\u00a7c {0}\u00a76. +timeBeforeTeleport=\u00a76\u0412\u0440\u0435\u043c\u0435\u043d\u0438 \u0434\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f\:\u00a7c {0} +timeFormat=\u00a7c{0}\u00a76 \u0438\u043b\u0438 \u00a7c{1}\u00a76 \u0438\u043b\u0438 \u00a7c{2}\u00a76 +timeSetPermission=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432 \u0434\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438. +timeWorldCurrent=\u00a76\u0421\u0435\u0439\u0447\u0430\u0441 \u0432\u0440\u0435\u043c\u044f \u0432\u00a7c {0} \u00a7c{1}\u00a76. +timeWorldSet=\u00a76\u0412\u0440\u0435\u043c\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e \u043d\u0430\u00a7c {0} \u00a76\u0432\: \u00a7c{1}\u00a76. +totalWorthAll=\u00a7a\u041f\u0440\u043e\u0434\u0430\u043d\u044b \u0432\u0441\u0435 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u044b \u0438 \u0431\u043b\u043e\u043a\u0438 \u0441 \u043e\u043a\u043e\u043d\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0446\u0435\u043d\u043e\u0439 \u00a7c{1}\u00a7a. +totalWorthBlocks=\u00a7a\u041f\u0440\u043e\u0434\u0430\u043d\u044b \u0432\u0441\u0435 \u0431\u043b\u043e\u043a\u0438 \u0441 \u043e\u043a\u043e\u043d\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0446\u0435\u043d\u043e\u0439 \u00a7c{1}\u00a7a. +tps=\u00a76TPS \= {0} +tradeSignEmpty=\u00a74\u0412 \u0442\u043e\u0440\u0433\u043e\u0432\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0447\u043a\u0435 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435\u0442\u0443. +tradeSignEmptyOwner=\u00a74\u0412 \u0442\u043e\u0440\u0433\u043e\u0432\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0447\u043a\u0435 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435\u0442\u0443 \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u0430. +treeFailure=\u00a74\u041d\u0435 \u0441\u043c\u043e\u0433 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0435\u0440\u0435\u0432\u043e. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439 \u043d\u0430 \u0433\u0440\u044f\u0437\u0438 \u0438\u043b\u0438 \u0437\u0435\u043c\u043b\u0435. +treeSpawned=\u00a76\u0414\u0435\u0440\u0435\u0432\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u043e. +true=\u00a7a\u0438\u0441\u0442\u0438\u043d\u0430\u00a7r +typeTpaccept=\u00a76\u0414\u043b\u044f \u043f\u0440\u0438\u043d\u044f\u0442\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u00a7c/tpaccept\u00a76. +typeTpdeny=\u00a76\u0414\u043b\u044f \u043e\u0442\u043a\u0430\u0437\u0430 \u043e\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u00a7c/tpdeny\u00a76. +typeWorldName=\u00a76\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u043c\u0438\u0440\u0430. +unableToSpawnMob=\u00a74\u041d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0441\u043f\u0430\u0443\u043d\u0438\u0442\u044c \u043c\u043e\u0431\u0430. +unignorePlayer=\u00a76\u0412\u044b \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043b\u0438 \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0433\u0440\u043e\u043a\u0430\u00a7c {0}\u00a76. +unknownItemId=\u00a74\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u044b\u0439 ID \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u0430\:\u00a7r {0}\u00a74. +unknownItemInList=\u00a74\u041d\u0435\u0438\u0437\u043c\u0435\u0441\u0442\u043d\u044b\u0439 \u043f\u0440\u0435\u0434\u043c\u0435\u0442 {0} \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 {1}. +unknownItemName=\u00a74\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u0430\: {0}. +unlimitedItemPermission=\u00a74\u041d\u0435\u0442 \u043f\u0440\u0430\u0432 \u0434\u043b\u044f \u043d\u0435\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u0430 \u00a7c{0}\u00a74. +unlimitedItems=\u00a76\u0411\u0435\u0437\u043b\u0438\u043c\u0438\u0442\u043d\u044b\u0435 \u0431\u043b\u043e\u043a\u0438\:\u00a7r +unmutedPlayer=\u00a76\u0422\u0435\u043f\u0435\u0440\u044c \u0438\u0433\u0440\u043e\u043a\u00a7c {0} \u00a76\u043c\u043e\u0436\u0435\u0442 \u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u0447\u0430\u0442. +unvanishedReload=\u00a74\u041f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u043b\u0430 \u0412\u0430\u0441 \u0441\u0434\u0435\u043b\u0430\u0442\u044c\u0441\u044f \u0432\u0438\u0434\u0438\u043c\u044b\u043c. +upgradingFilesError=\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0438 \u0444\u0430\u0439\u043b\u043e\u0432. +uptime=\u00a76\u0410\u043f\u0442\u0430\u0439\u043c\:\u00a7c {0} +userAFK=\u00a75\u0418\u0433\u0440\u043e\u043a {0} \u00a75\u043e\u0442\u043e\u0448\u0435\u043b \u0438 \u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u043e\u0442\u0432\u0435\u0447\u0430\u0442\u044c. +userDoesNotExist=\u00a74\u0418\u0433\u0440\u043e\u043a\u0430\u00a7c {0} \u00a74\u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442. +userIsAway=\u00a75{0} \u00a75\u043e\u0442\u043e\u0448\u0435\u043b. +userIsNotAway=\u00a75{0} \u00a75\u0432\u0435\u0440\u043d\u0443\u043b\u0441\u044f. +userJailed=\u00a76\u0412\u044b \u043f\u043e\u0441\u0430\u0436\u0435\u043d\u044b \u0432 \u0442\u044e\u0440\u044c\u043c\u0443\! +userUnknown=\u00a74\u0412\u043d\u0438\u043c\u0430\u043d\u0438\u0435\: \u0418\u0433\u0440\u043e\u043a\u0430 ''\u00a7c{0}\u00a74'' \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435\u0431\u044b\u043b\u043e \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435. +userdataMoveBackError=\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0438 userdata/{0}.tmp \u0432 userdata/{1}\! +userdataMoveError=\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0438 userdata/{0} \u0432 userdata/{1}.tmp\! +usingTempFolderForTesting=\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u043f\u0430\u043f\u043a\u0438 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0430\: +vanished=\u00a76\u0422\u0435\u043f\u0435\u0440\u044c \u0412\u044b \u043d\u0435\u0432\u0438\u0434\u0438\u043c\u044b\u0439. +versionMismatch=\u00a74\u0412\u0435\u0440\u0441\u0438\u0438 \u043d\u0435 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0442\! \u041e\u0431\u043d\u043e\u0432\u0438 {0} \u0434\u043e \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438. +versionMismatchAll=\u00a74\u0412\u0435\u0440\u0441\u0438\u0438 \u043d\u0435 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0442\! \u041e\u0431\u043d\u043e\u0432\u0438 \u0432\u0441\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b Essentials \u0434\u043e \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438. +voiceSilenced=\u00a76\u0412\u044b \u0431\u044b\u043b\u0438 \u0437\u0430\u0433\u043b\u0443\u0448\u0435\u043d\! +walking=\u0445\u043e\u0434\u044c\u0431\u044b +warpDeleteError=\u00a74\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0438 \u0432\u0430\u0440\u043f\u0430. +warpList={0} +warpListPermission=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432 \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u0441\u043f\u0438\u0441\u043a\u0430 \u0432\u0430\u0440\u043f\u043e\u0432. +warpNotExist=\u00a74\u042d\u0442\u043e\u0442 \u0432\u0430\u0440\u043f \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442. +warpOverwrite=\u00a74\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0432\u0430\u0440\u043f. +warpSet=\u00a76\u0412\u0430\u0440\u043f\u00a7c {0} \u00a76\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d. +warpUsePermission=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432 \u0434\u043b\u044f \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0430\u0446\u0438\u0438 \u043d\u0430 \u044d\u0442\u043e\u0442 \u0432\u0430\u0440\u043f. +warpingTo=\u00a76\u041f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0435 \u043d\u0430\u00a7c {0}\u00a76. +warps=\u00a76\u0412\u0430\u0440\u043f\u044b\:\u00a7r {0} +warpsCount=\u00a76\u0412\u0441\u0435\u0433\u043e\u00a7c {0} \u00a76\u0432\u0430\u0440\u043f\u043e\u0432. \u041f\u043e\u043a\u0430\u0437\u0430\u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u00a7c{1} \u00a76\u0438\u0437 \u00a7c{2}\u00a76. +weatherStorm=\u00a76\u0412\u044b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438 \u00a7c\u0448\u0442\u043e\u0440\u043c\u043e\u0432\u0443\u044e\u00a76 \u043f\u043e\u0433\u043e\u0434\u0443 \u0432\u00a7c {0}\u00a76. +weatherStormFor=\u00a76\u0412\u044b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438 \u00a7c\u0448\u0442\u043e\u0440\u043c\u043e\u0432\u0443\u044e\u00a76 \u043f\u043e\u0433\u043e\u0434\u0443 \u0432\u00a7c {0} \u00a76\u043d\u0430 {1} \u0441\u0435\u043a\u0443\u043d\u0434. +weatherSun=\u00a76\u0412\u044b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438 \u00a7c\u0441\u043e\u043b\u043d\u0435\u0447\u043d\u0443\u044e\u00a76 \u043f\u043e\u0433\u043e\u0434\u0443 \u0432\u00a7c {0}\u00a76. +weatherSunFor=\u00a76\u0412\u044b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438 \u00a7c\u0441\u043e\u043b\u043d\u0435\u0447\u043d\u0443\u044e\u00a76 \u043f\u043e\u0433\u043e\u0434\u0443 \u0432\u00a7c {0} \u00a76\u043d\u0430 {1} \u0441\u0435\u043a\u0443\u043d\u0434. +whoisAFK=\u00a76 - AFK\:\u00a7r {0} +whoisBanned=\u00a76 - \u0417\u0430\u0431\u0430\u043d\u0435\u043d\u044b\u0439\:\u00a7r {0} +whoisExp=\u00a76 - \u041e\u043f\u044b\u0442\:\u00a7r {0} (\u0443\u0440\u043e\u0432\u0435\u043d\u044c {1}) +whoisFly=\u00a76 - \u0420\u0435\u0436\u0438\u043c \u043f\u043e\u043b\u0435\u0442\u0430\:\u00a7r {0} ({1}) +whoisGamemode=\u00a76 - \u0418\u0433\u0440\u043e\u0432\u043e\u0439 \u0440\u0435\u0436\u0438\u043c\:\u00a7r {0} +whoisGeoLocation=\u00a76 - \u041c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435\:\u00a7r {0} +whoisGod=\u00a76 - \u0420\u0435\u0436\u0438\u043c \u0411\u043e\u0433\u0430\:\u00a7r {0} +whoisHealth=\u00a76 - \u0417\u0434\u043e\u0440\u043e\u0432\u044c\u0435\:\u00a7r {0}/20 +whoisIPAddress=\u00a76 - IP \u0430\u0434\u0440\u0435\u0441\:\u00a7r {0} +whoisJail=\u00a76 - \u0412 \u0442\u044e\u0440\u044c\u043c\u0435\:\u00a7r {0} +whoisLocation=\u00a76 - \u041c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435\:\u00a7r ({0}, {1}, {2}, {3}) +whoisMoney=\u00a76 - \u0414\u0435\u043d\u044c\u0433\u0438\:\u00a7r {0} +whoisMuted=\u00a76 - \u0412 \u043c\u0443\u0442\u0435\:\u00a7r {0} +whoisNick=\u00a76 - \u041d\u0438\u043a\:\u00a7r {0} +whoisOp=\u00a76 - OP\:\u00a7r {0} +whoisTop=\u00a76 \=\=\=\=\=\= WhoIs\:\u00a7c {0} \u00a76\=\=\=\=\=\= +worth=\u00a7a\u0421\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u0441\u0442\u0430\u043a\u0430 {0} \u0441\u043e\u0441\u0442\u043e\u0432\u043b\u044f\u0435\u0442 \u00a7c{1}\u00a7a ({2} \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043e\u0432 \u0437\u0430 {3} \u043a\u0430\u0436\u0434\u044b\u0439) +worthMeta=\u00a7a\u0421\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u0441\u0442\u0430\u043a\u0430 {0} \u0441 \u043c\u0435\u0442\u0434\u0430\u043d\u043d\u044b\u043c\u0438 {1} \u0441\u043e\u0441\u0442\u043e\u0432\u043b\u044f\u0435\u0442 \u00a7c{2}\u00a7a ({3} \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043e\u0432 \u0437\u0430 {4} \u043a\u0430\u0436\u0434\u044b\u0439) +worthSet=\u00a76\u0426\u0435\u043d\u0430 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430 +year=\u0433\u043e\u0434 +years=\u043b\u0435\u0442 +youAreHealed=\u00a76\u0412\u044b \u0431\u044b\u043b\u0438 \u0432\u044b\u043b\u0435\u0447\u0435\u043d\u044b. +youHaveNewMail=\u00a76\u0423 \u0412\u0430\u0441 \u0435\u0441\u0442\u044c\u00a7c {0} \u00a76\u043d\u043e\u0432\u044b\u0445 \u043f\u0438\u0441\u0435\u043c\! \u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u00a7c/mail read\u00a76 \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u0441\u0432\u043e\u0435\u0439 \u043f\u043e\u0447\u0442\u044b. +whoisHunger=\u00a76 - \u0413\u043e\u043b\u043e\u0434\:\u00a7r {0}/20 (+{1} \u043d\u0430\u0441\u044b\u0449\u0435\u043d\u0438\u0435) +kitDelay=\u00a7m{0}\u00a7r +giveSpawnFailure=\u00a74\u041d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u0433\u043e \u043c\u0435\u0441\u0442\u0430, \u00a7c{0} \u00a7c{1} \u00a74\u043f\u043e\u0442\u0435\u0440\u044f\u043d\u043e. +noKitGroup=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u0431\u043e\u0440\u0443. +inventoryClearingFromAll=\u00a76\u041e\u0447\u0438\u0441\u0442\u043a\u0430 \u0438\u043d\u0432\u0435\u043d\u0442\u0430\u0440\u0435\u0439 \u0432\u0441\u0435\u0445 \u0438\u0433\u0440\u043e\u043a\u043e\u0432... +inventoryClearingAllItems=\u00a76\u0418\u043d\u0432\u0435\u043d\u0442\u0430\u0440\u044c \u043e\u0447\u0438\u0449\u0435\u043d \u0443 {0}\u00a76. +inventoryClearingAllArmor=\u00a76\u0423\u0431\u0440\u0430\u043d\u044b \u0432\u0441\u0435 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u044b \u0438 \u0431\u0440\u043e\u043d\u044f \u0443 {0}\u00a76. +inventoryClearingAllStack=\u00a76\u0423\u0431\u0440\u0430\u043d\u044b \u0432\u0441\u0435\u00a7c {0} \u00a76\u0443 {1}\u00a76. +inventoryClearingStack=\u00a76\u0423\u0431\u0440\u0430\u043d\u043e\u00a7c {0} \u00a76\u0448\u0442\u0443\u043a\u00a7c {1} \u00a76\u0443 {2}\u00a76. +inventoryClearFail=\u00a74\u0418\u0433\u0440\u043e\u043a {0} \u00a74\u043d\u0435 \u0438\u043c\u0435\u0435\u0442\u00a7c {1} \u00a74\u0448\u0442\u0443\u043a\u00a7c {2}\u00a74. +localNoOne= +totalSellableAll=\u00a7a\u041e\u0431\u0449\u0430\u044f \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u0432\u0441\u0435\u0445 \u043f\u0440\u043e\u0434\u0430\u0432\u0430\u0435\u043c\u044b\u0445 \u0431\u043b\u043e\u043a\u043e\u0432 \u0438 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043e\u0432 \u0440\u0430\u0432\u043d\u0430 \u00a7c{1}\u00a7a. +totalSellableBlocks=\u00a7a\u041e\u0431\u0449\u0430\u044f \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u0432\u0441\u0435\u0445 \u043f\u0440\u043e\u0434\u0430\u0432\u0430\u0435\u043c\u044b\u0445 \u0431\u043b\u043e\u043a\u043e\u0432 \u0440\u0430\u0432\u043d\u0430 \u00a7c{1}\u00a7a. +radiusTooBig=\u00a74\u0420\u0430\u0434\u0438\u0443\u0441 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0431\u043e\u043b\u044c\u0448\u043e\u0439\! \u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u0440\u0430\u0434\u0438\u0443\u0441 - {0}. +isIpBanned=\u00a76IP \u00a7c{0} \u00a76\u0437\u0430\u0431\u0430\u043d\u0435\u043d. +mobDataList=\u00a76\u0414\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u043c\u043e\u0431\u044b\:\u00a7r {0} +vanish=\u00a76\u041d\u0435\u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0434\u043b\u044f {0}\u00a76\: {1} +noLocationFound=\u00a74\u041c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e. +coordsKeyword={0}, {1}, {2} +banExemptOffline=\u00a74\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0437\u0430\u0431\u0430\u043d\u0438\u0442\u044c \u0438\u0433\u0440\u043e\u043a\u0430 \u0432 \u043e\u0444\u0444\u043b\u0430\u0439\u043d\u0435. +tempbanExemptOffline=\u00a74\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0437\u0430\u0431\u0430\u043d\u0438\u0442\u044c \u0438\u0433\u0440\u043e\u043a\u0430 \u0432 \u043e\u0444\u0444\u043b\u0430\u0439\u043d\u0435. +mayNotJailOffline=\u00a74\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u0441\u0430\u0434\u0438\u0442\u044c \u0432 \u0442\u044e\u0440\u044c\u043c\u0443 \u0438\u0433\u0440\u043e\u043a\u0430 \u0432 \u043e\u0444\u0444\u043b\u0430\u0439\u043d\u0435. +muteExemptOffline=\u00a74\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0437\u0430\u0442\u043a\u043d\u0443\u0442\u044c \u0438\u0433\u0440\u043e\u043a\u0430 \u0432 \u043e\u0444\u0444\u043b\u0430\u0439\u043d\u0435. +ignoreExempt=\u00a74\u0412\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0433\u043e \u0438\u0433\u0440\u043e\u043a\u0430. +unsafeTeleportDestination=\u00a74\u0422\u0435\u043b\u0435\u043f\u043e\u0440\u0442 \u043d\u0435 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u0435\u043d \u0438 \u0437\u0430\u0449\u0438\u0442\u0430 \u043f\u043e\u0441\u043b\u0435 \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0430\u0446\u0438\u0438 \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0430. +noMetaJson=JSON \u043c\u0435\u0442\u0430 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u044d\u0442\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0435\u0439 Bukkit. +maxMoney=\u00a74\u042d\u0442\u0430 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0435\u0432\u044b\u0448\u0430\u0442\u044c \u0431\u0430\u043b\u0430\u043d\u0441 \u044d\u0442\u043e\u0433\u043e \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0430. +skullChanged=\u00a76\u0413\u043e\u043b\u043e\u0432\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0430 \u043d\u0430 \u00a7c{0}.\u00a76. +alphaNames=\u00a74\u041b\u043e\u0433\u0438\u043d\u044b \u0438\u0433\u0440\u043e\u043a\u043e\u0432 \u043c\u043e\u0433\u0443\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0431\u0443\u043a\u0432\u044b, \u0446\u0438\u0444\u0440\u044b \u0438 \u043f\u043e\u0434\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u0435. +givenSkull=\u00a76\u0412\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u0433\u043e\u043b\u043e\u0432\u0443 \u00a7c{0}\u00a76. +noPermissionSkull=\u00a74\u0423 \u0412\u0430\u0441 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432 \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u0433\u043e\u043b\u043e\u0432\u044b. +teleportInvalidLocation=\u0417\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435, \u0447\u0435\u043c 30000000 +invalidSkull=\u00a74\u0414\u0435\u0440\u0436\u0438\u0442\u0435 \u0433\u043e\u043b\u043e\u0432\u0443 \u0438\u0433\u0440\u043e\u043a\u0430 \u0432 \u0440\u0443\u043a\u0430\u0445. +weatherInvalidWorld=\u041c\u0438\u0440 \u0441 \u0438\u043c\u0435\u043d\u0435\u043c {0} \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\! +gameModeInvalid=\u00a74\u0412\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0438\u0433\u0440\u043e\u043a\u0430 \u0438\u043b\u0438 \u0440\u0435\u0436\u0438\u043c. +mailTooLong=\u00a74\u041f\u043e\u0447\u0442\u043e\u0432\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0434\u043b\u0438\u043d\u043d\u043e\u0435. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0443\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0435\u0433\u043e \u0432 1000 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432. +mailDelay=\u0421\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u043d\u043e\u0433\u043e \u043f\u0438\u0441\u0435\u043c \u0431\u044b\u043b\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u044b \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044e\u044e \u043c\u0438\u043d\u0443\u0442\u0443. \u041c\u0430\u043a\u0441\u0438\u043c\u0443\u043c\: {0} +seenAccounts=\u00a76\u0418\u0433\u0440\u043e\u043a \u0442\u0430\u043a\u0436\u0435 \u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043d \u043a\u0430\u043a\:\u00a7c {0} +unableToSpawnItem=\u00a74\u041d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0434\u0430\u0442\u044c \u00a7c{0}\u00a74, \u044d\u0442\u043e \u043d\u0435 \u0432\u044b\u0434\u0430\u0432\u0430\u0435\u043c\u044b\u0439 \u043f\u0440\u0435\u0434\u043c\u0435\u0442. +itemsConverted=\u00a76Converted all items into blocks. +itemsNotConverted=\u00a74You have no items that can be converted into blocks. +mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\: +mailMessage={0} + +whoisTempBanned=\u00a76 - Ban expires:\u00a7r {0} +playerTempBanned=\u00a76Player \u00a7c{0}\u00a76 temporarily banned \u00a7c{1}\u00a76 for \u00a7c{2}\u00a76: \u00a7c{3}\u00a76. +mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1} diff --git a/Essentials/src/messages_sv.properties b/Essentials/src/messages_sv.properties new file mode 100644 index 0000000000..4f5a2addaa --- /dev/null +++ b/Essentials/src/messages_sv.properties @@ -0,0 +1,558 @@ +#X-Generator: crowdin.net +#version: TeamCity +# Single quotes have to be doubled: '' +# Translations start here +# by: +action=\u00a75* {0} \u00a75{1} +addedToAccount=\u00a7a{0} har blivit tillagt p\u00e5 ditt konto. +addedToOthersAccount=\u00a7a{0} har blivit tillagt p\u00e5 {1}\u00a7a konto. Ny balans\: {2} +adventure=\u00e4ventyr +alertBroke=gjorde s\u00f6nder\: +alertFormat=\u00a73[{0}] \u00a7r {1} \u00a76 {2} vid\: \u00a7{3} +alertPlaced=placerade\: +alertUsed=anv\u00e4nde\: +antiBuildBreak=\u00a74Du har inte till\u00e5telse att ta s\u00f6nder {0} blocks h\u00e4r. +antiBuildCraft=\u00a74Du har inte till\u00e5telse att skapa\u00a7c {0}\u00a74. +antiBuildDrop=\u00a74Du har inte till\u00e5telse att kasta ut\u00a7c {0}\u00a74. +antiBuildInteract=\u00a74Du har inte till\u00e5telse att p\u00e5verka {0}. +antiBuildPlace=\u00a74Du har inte till\u00e5telse att placera {0} h\u00e4r. +antiBuildUse=\u00a74Du har inte till\u00e5telse att anv\u00e4nda {0}. +autoAfkKickReason=Du har blivit utsparkad f\u00f6r att ha varit inaktiv i mer \u00e4n {0} minuter. +backAfterDeath=\u00a77Anv\u00e4nd /back kommandot f\u00f6r att komma tillbaka till din d\u00f6dsplats. +backUsageMsg=\u00a77Tar dig tillbaka till din f\u00f6reg\u00e5ende position. +backupDisabled=Ett externt backup-skript har inte blivit konfigurerat. +backupFinished=Backup klar +backupStarted=Backup startad +balance=\u00a77Balans\: {0} +balanceOther=\u00a7aKonto balans f\u00f6r {0} \u00a7a\u00e4r \u00a7c{1} +balanceTop=\u00a77Topp balans ({0}) +banExempt=\u00a7cDu kan inte banna den spelaren. +banFormat=\u00a74Bannlyst\: \n\u00a7r{0} +bed=\u00a7os\u00e4ng\u00a7r +bedMissing=\u00a74Din s\u00e4ng finns ej, \u00e4r blockerad, eller saknas. +bedNull=\u00a7ms\u00e4ng\u00a7r +bedSet=\u00a76S\u00e4ng spawn definierat\! +bigTreeFailure=\u00a7cEtt stort tr\u00e4d kunde inte genereras misslyckades. F\u00f6s\u00f6k igen p\u00e5 gr\u00e4s eller jord. +bigTreeSuccess=\u00a77Stort tr\u00e4d genererat. +blockList=Essentials vidarebefordrade f\u00f6ljande kommandon till ett annat insticksprogram\: +bookAuthorSet=\u00a76F\u00f6rfattaren av boken \u00e4r nu {0}. +bookLocked=\u00a76Denna bok \u00e4r nu l\u00e5st. +bookTitleSet=\u00a76Titeln av boken har blivit \u00c3\u00a4ndrad till {0} +broadcast=[\u00a7cUts\u00e4ndning\u00a7f]\u00a7a {0} +buildAlert=\u00a7cDu har inte till\u00e5telse att bygga +bukkitFormatChanged=Bukkit versionsformat bytt. Version \u00e4r inte kollad. +burnMsg=\u00a77Du satte eld p\u00e5 {0} i {1} sekunder. +canTalkAgain=\u00a77Du kan nu prata igen\! +cannotStackMob=\u00a74Du har inte till\u00e5telse att stapla monster. +cantFindGeoIpDB=Kunde inte hitta GeoIP-databasen\! +cantReadGeoIpDB=Kunde inte l\u00e4sa inneh\u00e5ll fr\u00e5n GeoIP-databasen\! +cantSpawnItem=\u00a7cDu har inte beh\u00f6righet att spawna {0} +chatTypeAdmin=[A] +chatTypeLocal=[L] +chatTypeSpy=[Spion] +cleaned=Anv\u00e4ndarfiler rensade. +cleaning=Rensar anv\u00e4ndarfiler. +commandFailed=Kommando {0} misslyckades\: +commandHelpFailedForPlugin=Kunde inte hitta hj\u00e4lp f\u00f6r\: {0} +commandNotLoaded=\u00a7cKommando {0} \u00e4r felaktigt laddat. +compassBearing=\u00a77B\u00e4ring\: {0} ({1} grader). +configFileMoveError=Kunde inte flytta config.yml till backup-platsen. +configFileRenameError=Kunde inte byta namn p\u00e5 temp-filen till config.yml +connectedPlayers=\u00a77Anslutna spelare\u00a7r +connectionFailed=Kunde inte \u00f6ppna anslutning. +cooldownWithMessage=\u00a7cNedkylning\: {0} +corruptNodeInConfig=\u00a74Observera\: Din konfigurationsfil har en korrupt {0} nod. +couldNotFindTemplate=Kunde inte hitta mallen {0} +creatingConfigFromTemplate=Skapar konfiguration fr\u00e5n mallen\: {0} +creatingEmptyConfig=Skapar tom konfiguration\: {0} +creative=kreativ +currency={0}{1} +currentWorld=Nuvarande v\u00e4rld\: {0} +day=dag +days=dagar +defaultBanReason=Banhammaren har talat\! +deleteFileError=Kunde inte radera filen\: {0} +deleteHome=\u00a77Hemmet {0} har tagits bort. +deleteJail=\u00a77F\u00e4ngelset {0} har tagits bort. +deleteWarp=\u00a77Warpen {0} har tagits bort. +deniedAccessCommand={0} nekades \u00e5tkomst till kommandot. +denyBookEdit=\u00a74Du kan inte l\u00e5sa upp denna boken. +denyChangeAuthor=\u00a74Du kan inte \u00e4ndra f\u00f6rfattaren av denna bok. +denyChangeTitle=\u00a74Du kan inte \u00e4ndra titel p\u00e5 denna boken. +depth=\u00a77Du \u00e4r p\u00e5 havsniv\u00e5n. +depthAboveSea=\u00a77Du \u00e4r {0} block ovanf\u00f6r havsni\u00e5n. +depthBelowSea=\u00a77Du \u00e4r {0} block under havsniv\u00e5n. +destinationNotSet=Ingen destination \u00e4r inst\u00e4lld. +disableUnlimited=\u00a77Inaktiverade o\u00e4ndligt placerande av {0} f\u00f6r {1}. +disabled=inaktiverad +disabledToSpawnMob=Att spawna fram den h\u00e4r moben \u00e4r inaktiverat i configurationsfilen. +distance=\u00a76Avst\u00e5nd\: {0} +dontMoveMessage=\u00a77Teleporteringen p\u00e5b\u00f6rjas om {0}. R\u00f6r dig inte. +downloadingGeoIp=Laddar ner GeoIP-databasen... det h\u00e4r kan ta en stund (land\: 0.6 MB, stad\: 20MB) +duplicatedUserdata=Dublicerad anv\u00e4ndardata\: {0} och {1} +durability=\u00a77Det h\u00e4r verktyget har \u00a7c{0}\u00a77 anv\u00e4ndningar kvar +editBookContents=\u00a7eDu kan nu \u00e4ndra inneh\u00e5llet i denna bok. +enableUnlimited=Ger o\u00e4ndligt med pengar till +enabled=aktiverad +enchantmentApplied=\u00a77F\u00f6rtrollningen {0} har blivit till\u00e4mpad p\u00e5 saken du har i handen. +enchantmentNotFound=\u00a7cF\u00f6rtrollningen hittades inte +enchantmentPerm=\u00a7cDu har inte beh\u00f6righet att {0} +enchantmentRemoved=\u00a77F\u00f6rtrollningen {0} har tagits bort fr\u00e5n saken i din hand. +enchantments=\u00a77F\u00f6rtrollningar\: {0} +errorCallingCommand=Kunde inte kontakta kommandot /{0} +errorWithMessage=\u00a7cFel\:\u00a74 {0} +essentialsHelp1=Filen \u00e4r trasig och Essentials kan inte \u00f6ppna den. Essentials \u00e4r nu inaktiverat. Om du inte kan fixa problemet sj\u00e4lv, g\u00e5 till http\://tiny.cc/EssentialsChat +essentialsHelp2=Filen \u00e4r trasig och Essentials kan inte \u00f6ppna den. Essentials \u00e4r nu inaktiverat. Om du inte kan fixa problemet sj\u00e4lv, skriv /essentialshelp i spelet eller g\u00e5 till http\://tiny.cc/EssentialsChat +essentialsReload=\u00a76Essentials omladdad\u00a7c {0}. +exp=\u00a7c{0} \u00a77har\u00a7c {1} \u00a77exp (level\u00a7c {2}\u00a77) och beh\u00f6ver\u00a7c {3} \u00a77mer erfarenhet f\u00f6r att g\u00e5 upp en niv\u00e5. +expSet=\u00a7c{0} \u00a77har nu\u00a7c {1} \u00a77erfarenhet. +extinguish=\u00a77Du sl\u00e4ckte dig sj\u00e4lv. +extinguishOthers=\u00a77Du sl\u00e4ckte {0}. +failedToCloseConfig=Kunde inte st\u00e4nga konfiguration {0} +failedToCreateConfig=Kunde inte skapa konfiguration {0} +failedToWriteConfig=Kunde inte skriva konfiguration {0} +false=\u00a74false\u00a7r +feed=\u00a77Din hunger \u00e4r m\u00e4ttad. +feedOther=\u00a76Du m\u00e4ttade \u00a7c{0}s\u00a76 aptit. +fileRenameError=Namnbytet av filen {0} misslyckades +fireworkColor=\u00a74Inkorrekta fyrverkeri parametrar, du m\u00e5ste ange en f\u00e4rg f\u00f6rst. +fireworkEffectsCleared=\u00a76Tog bort alla effekter fr\u00e5n objektet i din hand. +fireworkSyntax=\u00a76Fyrverkeri parametrar\: \u00a7c f\u00e4rg\: [fade\: ] [form\: ] [effekt\: ] \u00a76F\u00f6r att anv\u00e4nda flera f\u00e4rger/effekter, avgr\u00e4nsar du v\u00e4rdena med kommatecken\: \u00a7cred, blue, pink \u00a76Former\:\u00a7c star, ball, larege, creeper, burst \u00a76Effekter\:\u00a7c trail, twinkle. +flyMode=\u00a77Aktiverade flygl\u00e4ge {0} f\u00f6r {1}. +flying=flyger +foreverAlone=\u00a7cDu har ingen att svara. +fullStack=\u00a74Du har redan en full stapel +gameMode=\u00a77Satte {0}s spell\u00e4ge till {1}. +gcWorld=\u00a76 {0} "\u00a7c {1} \u00a76"\: \u00a7c {2} \u00a76 bitar, \u00a7c {3} \u00a76 enheter, \u00a7c {4} \u00a76 titlar. +gcfree=Ledigt minne\: {0} MB +gcmax=Maximalt minne\: {0} MB +gctotal=Tilldelat minne\: {0} MB +geoIpUrlEmpty=Nerladdningsadressen f\u00f6r GeoIP \u00e4r tom. +geoIpUrlInvalid=Nerladdningsadressen f\u00f6r GeoIP \u00e4r ogiltig. +geoipJoinFormat=\u00a76Spelaren \u00a7c{0} \u00a76kommer fr\u00e5n \u00a7c{1}\u00a76. +giveSpawn=\u00a76Ger\u00a7c {0} \u00a76av\u00a7c {1} till\u00a7c {2}\u00a76. +godDisabledFor=\u00a7cdeaktiverat\u00a76 f\u00f6r\u00a7c {0} +godEnabledFor=aktiverat f\u00f6r {0} +godMode=\u00a77Od\u00f6dlighet {0}. +groupDoesNotExist=\u00a74Ingen \u00e4r online i denna gruppen\! +groupNumber=\u00a7c{0}\u00a7f online, f\u00f6r att se alla skriv\:\u00a7c /{1} {2} +hatArmor=\u00a7cFel, du kan inte anv\u00e4nda den h\u00e4r saken som en hatt\! +hatEmpty=\u00a7cDu har inte p\u00e5 dig en hatt. +hatFail=\u00a7cDu m\u00e5ste ha n\u00e5gonting att b\u00e4ra i din hand. +hatPlaced=\u00a7eNjut av din nya hatt\! +hatRemoved=\u00a7eDin hatt har tagits bort. +haveBeenReleased=\u00a77Du har blivit friad +heal=\u00a77Du har blivit l\u00e4kt. +healDead=\u00a74Du kan inte hela n\u00e5gon som \u00e4r d\u00f6d\! +healOther=\u00a77L\u00e4kte {0}. +helpConsole=F\u00f6r att visa hj\u00e4lp fr\u00e5n konsolen, skriv ?. +helpFrom=\u00a77Kommandon fr\u00e5n {0}\: +helpLine=\u00a76/{0}\u00a7r\: {1} +helpMatching=\u00a77Kommandon matchar "{0}"\: +helpOp=\u00a7c[OpHj\u00e4lp]\u00a7f \u00a77{0}\:\u00a7f {1} +helpPlugin=\u00a74{0}\u00a7f\: Hj\u00e4lp f\u00f6r insticksprogram\: /help {1} +holdBook=\u00a74Boken du h\u00c3\u00a5ller i \u00c3\u00a4r inte skrivbar +holdFirework=\u00a74Du m\u00e5ste h\u00e5lla i en fyrverkeripj\u00e4s f\u00f6r att l\u00e4gga till effekter. +holdPotion=\u00a74Du m\u00e5ste h\u00e5lla i en brygd f\u00f6r att ge den effekter. +holeInFloor=H\u00e5l i golvet +homeSet=\u00a77Hem inst\u00e4llt. +homes=Hem\: {0} +hour=timme +hours=timmar +ignoredList=\u00a76Ignorerad\:\u00a7r {0} +ignorePlayer=Du ignorerar spelaren {0} fr\u00e5n och med nu. +illegalDate=Felaktigt datumformat. +infoChapter=\u00a76V\u00e4lj kapitel\: +infoChapterPages=\u00a7e ---- \u00a76{0} \u00a7e--\u00a76 Sida \u00a7c{1}\u00a76 of \u00a7c{2} \u00a7e---- +infoPages=\u00a7e ---- \u00a76{2} \u00a7e--\u00a76 Sida \u00a74{0}\u00a76/\u00a74{1} \u00a7e---- +infoUnknownChapter=\u00a74Ok\u00e4nt kapitel. +insufficientFunds=\u00a74Du har inte r\u00e5d med detta. +invalidCharge=\u00a7cOgiltig laddning. +invalidFireworkFormat=\u00a74V\u00e4rdet \u00a7c{0} \u00a74\u00e4r inte ett korrekt v\u00e4rde f\u00f6r \u00a7c{1}\u00a74. +invalidHome=Hemmet {0} finns inte +invalidHomeName=\u00a74Ogiltigt hemnamn +invalidMob=Ogiltigt mob +invalidNumber=Felaktigt nummer. +invalidPotion=\u00a74Ogiltig brygd. +invalidPotionMeta=\u00a74Ogiltig brygd meta\: \u00a7c{0}\u00a74. +invalidSignLine=Rad {0} p\u00e5 skylten \u00e4r ogiltig. +invalidWarpName=\u00a74Ogiltigt warpnamn +invalidWorld=\u00a7cOgiltig v\u00e4rld. +is=\u00e4r +itemCannotBeSold=Det objektet kan inte s\u00e4ljas till servern. +itemMustBeStacked=Objektet m\u00e5ste k\u00f6pas i staplar. En m\u00e4ngd av 2s kommer bli 2 staplar, etc. +itemNames=F\u00f6rkortning p\u00e5 objekt\: {0} +itemNotEnough1=\u00a7cDu har inte tillr\u00e4ckligt av den saken f\u00f6r att s\u00e4lja. +itemNotEnough2=\u00a77Om du ville s\u00e4lja alla block av den typen, anv\u00e4nd /sell blocknamn +itemNotEnough3=\u00a77/sell blocknamn -1 kommer att s\u00e4lja allt av den blocktypen f\u00f6rutom 1 o.s.v. +itemSellAir=F\u00f6rs\u00f6kte du att s\u00e4lja luft? S\u00e4tt en sak i din hand. +itemSold=\u00a77S\u00e5lde f\u00f6r \u00a7c{0} \u00a77({1} {2} f\u00f6r {3} styck) +itemSoldConsole={0} s\u00e5lde {1} f\u00f6r \u00a77{2} \u00a77({3} saker f\u00f6r {4} styck) +itemSpawn=\u00a77Ger {0} stycken {1} +itemType=Objekt\: {0} - {1} +itemsCsvNotLoaded=Kunde inte ladda items.csv. +jailAlreadyIncarcerated=\u00a7cPersonen \u00e4r redan i f\u00e4ngelse\: {0} +jailMessage=\u00a7cBryter du mot reglerna, f\u00e5r du st\u00e5 ditt kast. +jailNotExist=Det f\u00e4ngelset finns inte. +jailReleased=\u00a77Spelaren \u00a7e{0}\u00a77 \u00e4r frisl\u00e4ppt. +jailReleasedPlayerNotify=\u00a77Du har blivit frisl\u00e4ppt\! +jailSentenceExtended=F\u00e4ngelsestraffet f\u00f6rl\u00e4ngt till\: {0} +jailSet=\u00a77F\u00e4ngelset {0} har skapats +jumpError=Det skulle skadat din dators hj\u00e4rna. +kickDefault=Utsparkad fr\u00e5n server +kickExempt=\u00a7cDu kan inte sparka ut den spelaren. +kickedAll=\u00a7cSparkade ut alla spelare fr\u00e5n servern +kill=\u00a77D\u00f6dade {0}. +killExempt=\u00a74Du kan inte d\u00f6da \u00a7c{0}\u00a74. +kitCost=\ \u00a77\u00a7o({0})\u00a7r +kitError2=\u00a74Det d\u00e4r kittet \u00e4r inte korrekt konfigurerat. Kontakta en administrat\u00f6r. +kitError=\u00a7cDet finns inga giltiga kit. +kitGiveTo=\u00a76Ger kit\u00a7c {0}\u00a76 till \u00a7c{1}\u00a76. +kitInvFull=\u00a7cDitt F\u00f6rr\u00e5d var fullt, placerar kit p\u00e5 golvet +kitNotFound=\u00a74Det d\u00e4r kittet existerar inte. +kitOnce=\u00a74Du kan inte av\u00e4nda det kitet igen. +kitReceive=\u00a76Fick kittet\u00a7c {0}\u00a76. +kitTimed=\u00a7cDu kan inte anv\u00e4nda det kit\:et igen p\u00e5 {0}. +kits=\u00a77Kit\: {0} +leatherSyntax=\u00a76L\u00e4der f\u00e4rg syntax\: f\u00e4rg\:,, tex\: color\:255,0,0. +lightningSmited=\u00a77Blixten har slagit ner p\u00e5 dig +lightningUse=\u00a77En blixt kommer sl\u00e5 ner p\u00e5 {0} +listAfkTag=\u00a77[AFK]\u00a7f +listAmount=\u00a79Det \u00e4r \u00a7c{0}\u00a79 av maximalt \u00a7c{1}\u00a79 spelare online. +listAmountHidden=\u00a79Det \u00e4r \u00a7c{0}\u00a77/{1}\u00a79 Av maximalt \u00a7c{2}\u00a79 spelare online. +listGroupTag=\u00a76 {0} \u00a7r\: \u00a7r +listHiddenTag=\u00a77[G\u00d6MD]\u00a7f +loadWarpError=Kunde inte ladda warp {0} +localFormat=[L]<{0}> {1} +mailClear=\u00a76F\u00f6r att markera dina meddelanden som l\u00e4sta, skriv /mail clear. +mailCleared=\u00a77Meddelanden rensade\! +mailSent=\u00a77Meddelandet skickad\! +markMailAsRead=\u00a76F\u00f6r att markera dina meddelanden som l\u00e4sta, skriv /mail clear. +markedAsAway=\u00a77Du \u00e4r nu markerad som borta. +markedAsNotAway=\u00a77Du \u00e4r inte l\u00e4ngre markerad som borta. +matchingIPAddress=\u00a76F\u00f6ljande spelare har tidigare loggat in fr\u00e5n den IP adressen\: +maxHomes=Du kan inte ha fler \u00e4n {0} hem. +mayNotJail=\u00a7cDu f\u00e5r inte s\u00e4tta den personen i f\u00e4ngelse +me=jag +minute=minut +minutes=minuter +missingItems=\u00a74Du har inte \u00a7c{0}x {1}\u00a74. +mobSpawnError=Fel n\u00e4r mob-spawnaren f\u00f6rs\u00f6kte att \u00e4ndras. +mobSpawnLimit=M\u00e4ngden mobs begr\u00e4nsad till serverns maxgr\u00e4ns +mobSpawnTarget=M\u00e5lblocket m\u00e5ste vara en mob-spawnare. +mobsAvailable=\u00a76Monster\:\u00a7r {0} +moneyRecievedFrom=\u00a7a{0} har tagits emot fr\u00e5n {1} +moneySentTo=\u00a7a{0} har skickats till {1} +month=m\u00e5nad +months=m\u00e5nader +moreThanZero=M\u00e5ngden m\u00e5ste vara st\u00f6rre \u00e4n 0. +moveSpeed=\u00a76Satte {0} fart till\u00a7c {1} \u00a76f\u00f6r \u00a7c{2}\u00a76. +msgFormat=\u00a76[\u00a7c{0}\u00a76 -> \u00a7c{1}\u00a76] \u00a7r{2} +multipleCharges=\u00a74Du kan inte l\u00e4gga till mer \u00e4n en laddning till denna fyrverkeripj\u00e4s. +multiplePotionEffects=\u00a74Du kan inte l\u00e4gga till mer \u00e4n en effekt till denna brygd. +muteExempt=\u00a7cDu kan inte tysta den spelaren. +muteNotify=\u00a74{0} \u00a76har tystat \u00a74{1}. +mutedPlayer=\u00a76Spelare\u00a7c {0} \u00a76tystad. +mutedPlayerFor=\u00a7c {0} \u00a76tystas ner f\u00f6r\u00a7c {1} \u00a76. +mutedUserSpeaks={0} f\u00f6rs\u00f6kte att prata, men blev tystad. +nearbyPlayers=Spelare i n\u00e4rheten\: {0} +negativeBalanceError=Anv\u00e4ndaren \u00e4r inte till\u00e5ten att ha en negativ balans. +nickChanged=Smeknamn \u00e4ndrat. +nickDisplayName=\u00a77Du m\u00e5ste aktivera change-displayname i Essentials-konfigurationen. +nickInUse=\u00a7cDet namnet anv\u00e4nds redan. +nickNamesAlpha=\u00a7cSmeknamn m\u00e5ste vara alfanumeriska. +nickNoMore=\u00a77Du har inte ett smeknamn l\u00e4ngre +nickSet=\u00a76Ditt smeknamn \u00e4r nu \u00a7c{0}\u00a76. +nickTooLong=\u00a74Det d\u00e4r aliaset \u00e4r f\u00f6r l\u00e5ngt. +noAccessCommand=\u00a7cDu har inte tillg\u00e5ng till det kommandot. +noAccessPermission=\u00a74Du har inte beh\u00f6righet att g\u00f6ra det d\u00e4r\u00a7c{0} \u00a74. +noBreakBedrock=Du har inte till\u00e5telse att f\u00f6rst\u00f6ra berggrund. +noDestroyPermission=\u00a74Du har inte beh\u00f6righet att f\u00f6rst\u00f6ra det \u00a7c{0}\u00a74. +noDurability=\u00a7cDen saken har inte en h\u00e5llbarhet. +noGodWorldWarning=\u00a7cVarning\! Od\u00f6dlighet i den h\u00e4r v\u00e4rlden \u00e4r inaktiverat. +noHelpFound=\u00a7cInga matchande kommandon. +noHomeSetPlayer=Den h\u00e4r spelaren har inte ett hem. +noIgnored=\u00a76Du ignorerar inte n\u00e5gon. +noKitPermission=\u00a7cDu beh\u00f6ver \u00a7c{0}\u00a7c tillst\u00e5nd f\u00f6r att anv\u00e4nda det kitet. +noKits=\u00a77Det finns inga kits tillg\u00e4ngliga \u00e4n +noMail=Du har inget meddelande +noMatchingPlayers=\u00a76Inga spelare som matchade kriterierna hittades. +noMetaFirework=\u00a76Du har inte till\u00e5telse att l\u00e4gga till fyrverkeri-meta. +noMetaPerm=\u00a74Du har inte beh\u00f6righet att l\u00e4gga till \u00a7c{0}\u00a7c meta till detta objektet. +noNewMail=\u00a77Du har inget nytt meddelande. +noPendingRequest=Du har inga v\u00e4ntande f\u00f6rfr\u00e5gan. +noPerm=\u00a7cDu har inte \u00a7f{0}\u00a7c till\u00e5telse. +noPermToSpawnMob=\u00a7cDu har inte till\u00e5telse att spawna den h\u00e4r moben. +noPlacePermission=\u00a7cDu har inte till\u00e5telse att placera ett block n\u00e4ra den skylten. +noPotionEffectPerm=\u00a74Du har inte till\u00e5telse att l\u00e4gga till brygd-effekten \u00a7c{0} \u00a74till denna brygden. +noPowerTools=Du har inga power-tools tilldelade. +noWarpsDefined=Inga warpar \u00e4r definerade +none=inga +notAllowedToQuestion=\u00a7cDu har inte tillst\u00e5nd att anv\u00e4nda den fr\u00e5gan. +notAllowedToShout=\u00a7cDu har inte tillst\u00e5nd att ropa. +notEnoughExperience=Du har inte nog med erfarenhet. +notEnoughMoney=Du har inte tillr\u00e4ckligt med pengar. +notFlying=flyger inte +notRecommendedBukkit=* \! * Bukkit-versionen \u00e4r inte rekommenderad f\u00f6r den h\u00e4r versionen av Essentials. +notSupportedYet=St\u00f6ds inte \u00e4n. +nothingInHand=\u00a7cDu har inget i din hand. +now=nu +nuke=L\u00e5t d\u00f6d regna \u00f6ver dem +numberRequired=Det ska vara ett nummer d\u00e4r, dumbom. +onlyDayNight=/time st\u00f6der bara day(dag) eller night(natt). +onlyPlayerSkulls=\u00a74Du kan bara ange \u00e4garen f\u00f6r skallar av spelare (\u00a7c397\:3\u00a74). +onlyPlayers=\u00a74Bara spelare kan anv\u00e4nda \u00a7c{0}\u00a74. +onlySunStorm=/weather st\u00f6der bara sun(sol) eller storm(storm). +orderBalances=Best\u00e4ller balanser av {0} anv\u00e4ndare, v\u00e4nligen v\u00e4nta... +oversizedTempban=\u00a74Du kan inte banna en spelare just vid denna tidpunkt. +pTimeCurrent=\u00a7e{0}''*s\u00a7f klockan \u00e4r {1}. +pTimeCurrentFixed=\u00a7e{0}''s\u00a7f tiden \u00e4r fixerad till {1}. +pTimeNormal=\u00a7e{0}''s\u00a7f tiden \u00e4r normal och matchar servern. +pTimeOthersPermission=\u00a7cDu har inte beh\u00f6righet att st\u00e4lla in andra spelares tid. +pTimePlayers=Dessa spelare har sin egen tid\: +pTimeReset=Spelarens tid har blivit \u00e5terst\u00e4lld till\: \u00a7e{0} +pTimeSet=Spelarens tid \u00e4r inst\u00e4lld till \u00a73{0}\u00a7f till\: \u00a7e{1} +pTimeSetFixed=Spelarens tid \u00e4r fixerad till \u00a73{0}\u00a7f f\u00f6r\: \u00a7e{1} +pWeatherCurrent=\u00a7c{0}\u00a76''s v\u00e4der \u00e4r \u00a7c {1}\u00a76. +pWeatherInvalidAlias=\u00a74Inkorrekt v\u00e4dertyp +pWeatherNormal=\u00a7c{0}\u00a76''s v\u00e4der \u00e4r normalt och matchar serverns. +pWeatherOthersPermission=\u00a74Du har inte till\u00e5telse att st\u00e4lla in andra spelares v\u00e4der. +pWeatherPlayers=\u00a76Dessa spelare har sitt eget v\u00e4der\:\u00a7r +pWeatherReset=\u00a76Personligt v\u00e4der har \u00e5terst\u00e4llts f\u00f6r\: \u00a7c{0} +pWeatherSet=\u00a76Personligt v\u00e4der \u00e4r satt till \u00a7c{0}\u00a76 f\u00f6r\: \u00a7c{1}. +pendingTeleportCancelled=\u00a7cAvvaktande teleporteringsbeg\u00e4ran \u00e4r avbruten. +playerBanIpAddress=\u00a76Player\u00a7c {0} \u00a76banned IP address\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerBanned=\u00a76Spelare\u00a7c {0} \u00a76bannade\u00a7c {1} \u00a76f\u00f6r \u00a7c{2}\u00a76. +playerInJail=\u00a74Spelaren \u00e4r redan i f\u00e4ngelse\u00a7c {0}\u00a74. +playerJailed=\u00a77Spelaren {0} f\u00e4ngslad. +playerJailedFor=\u00a77Spelaren {0} f\u00e4ngslad f\u00f6r {1}. +playerKicked=\u00a7cSpelaren {0} har sparkat ut {1} f\u00f6r {2} +playerMuted=\u00a77Du har blivit tystad +playerMutedFor=\u00a77Du har blivit tystad f\u00f6r {0} +playerNeverOnServer=\u00a7cSpelaren {0} har aldrig varit p\u00e5 den h\u00e4r servern. +playerNotFound=\u00a7cSpelaren hittades inte. +playerUnbanIpAddress=\u00a76Spelaren\u00a7c {0} \u00a76unbannade IPn {1}. +playerUnbanned=\u00a76Spelare\u00a7c {0} \u00a76unbannade\u00a7c{1}. +playerUnmuted=\u00a77Du kan nu prata +pong=Pong\! +posPitch=\u00a76Pitch\: {0} (Huvudvinkel) +posX=\u00a76X\: {0} (+\u00d6ster <-> -V\u00e4st) +posY=\u00a76Y\: {0} (+Upp <-> -Ner) +posYaw=\u00a76Girning\: {0} (Rotation) +posZ=\u00a76Z\: {0} (+Syd <-> -Nort) +possibleWorlds=\u00a76De m\u00f6jliga v\u00e4rldarna \u00e4r nummer \u00a7c0\u00a76 till \u00a7c{0}\u00a76. +potions=\u00a76Brygder\:\u00a7r {0}\u00a76. +powerToolAir=Kommandot kan inte tilldelas luft. +powerToolAlreadySet=\u00a74Kommandot \u00a7c{0}\u00a74 \u00e4r redan angivet f\u00f6r \u00a7c{1}\u00a74. +powerToolAttach=\u00a7c{0}\u00a7f kommandot tilldelat {1}. +powerToolClearAll=Alla powertool-kommandon har blivit rensade. +powerToolList={1} har f\u00f6ljane kommandon\: \u00a7c{0}\u00a7f. +powerToolListEmpty={0} har inga kommandon tilldelade. +powerToolNoSuchCommandAssigned=\u00a74Kommandot \u00a7c{0}\u00a74 har inte tilldelats till \u00a7c{1}\u00a74. +powerToolRemove=\u00a76Kommand \u00a7c{0}\u00a76 har tagits bort fr\u00e5n \u00a7c{1}\u00a76. +powerToolRemoveAll=\u00a76All commands removed from \u00a7c{0}\u00a76. +powerToolsDisabled=Alla dina powertools har blivit inaktiverade. +powerToolsEnabled=Alla dina powertools har blivit aktiverade. +questionFormat=\u00a77[Fr\u00e5ga]\u00a7f {0} +readNextPage=Skriv /{0} {1} f\u00f6r att l\u00e4sa n\u00e4sta sida +recipe=\u00a76Recipe for \u00a7c{0}\u00a76 (\u00a7c{1}\u00a76 of \u00a7c{2}\u00a76) +recipeBadIndex=Det finns inget recept med det numret +recipeFurnace=\u00a76Smelt\: \u00a7c{0}\u00a76. +recipeGrid=\u00a7c{0}X \u00a76| \u00a7{1}X \u00a76| \u00a7{2}X +recipeGridItem=\u00a7c{0}X \u00a76is \u00a7c{1} +recipeMore=\u00a76Skriv /{0} \u00a7c{1}\u00a76 f\u00f6r att se andra recept f\u00f6r \u00a7c{2}\u00a76. +recipeNone=Inga recept existerar f\u00f6r {0} +recipeNothing=ingenting +recipeShapeless=\u00a76Kombinera \u00a7c{0} +recipeWhere=\u00a76Var\: {0} +removed=\u00a77Tog bort {0} enheter. +repair=\u00a76You have successfully repaired your\: \u00a7c{0}\u00a76. +repairAlreadyFixed=\u00a77Den h\u00e4r saken beh\u00f6ver inte repareras. +repairEnchanted=\u00a77Du har inte beh\u00f6righet att reparera f\u00f6rtrollade saker. +repairInvalidType=\u00a7cDen h\u00e4r saken kan inte bli reparerad. +repairNone=\u00a74Det finns inga saker som beh\u00f6ver repareras. +requestAccepted=\u00a77Teleporterings-f\u00f6rfr\u00e5gan accepterad. +requestAcceptedFrom=\u00a77{0} accepterade din teleportations-f\u00f6rfr\u00e5gan. +requestDenied=\u00a77Teleportations-f\u00f6rfr\u00e5gan nekad. +requestDeniedFrom=\u00a77{0} nekade din teleportations-f\u00f6rfr\u00e5gan. +requestSent=\u00a77F\u00f6rfr\u00e5gan skickad till {0}\u00a77. +requestTimedOut=\u00a7cTeleportations-f\u00f6rfr\u00e5gan har g\u00e5tt ut +requiredBukkit=* \! * Du beh\u00f6ver minst bygge {0} av CraftBukkit, ladda ner den fr\u00e5n http\://dl.bukkit.org/downloads/craftbukkit/ +resetBal=\u00a76Balance has been reset to \u00a7c{0} \u00a76for all online players. +resetBalAll=\u00a76Balance has been reset to \u00a7c{0} \u00a76for all players. +returnPlayerToJailError=\u00a74Error occurred when trying to return player\u00a7c {0} \u00a74to jail\: \u00a7c{1}\u00a74\! +runningPlayerMatch=\u00a76K\u00f6r s\u00f6kning efter spelare som matchar ''\u00a7c{0}\u00a76'' (detta kan ta ett tag) +second=sekund +seconds=sekunder +seenOffline=\u00a76Player\u00a7c {0} \u00a76has been \u00a74offline\u00a76 since \u00a7c{1}\u00a76. +seenOnline=\u00a76Player\u00a7c {0} \u00a76has been \u00a7aonline\u00a76 since \u00a7c{1}\u00a76. +serverFull=Servern \u00e4r full +serverTotal=Totalt p\u00e5 servern\: {0} +setBal=\u00a7aDin kontobalans sattes till {0}. +setBalOthers=\u00a7aDu satte {0}\u00a7a''s kontobalans till {1}. +setSpawner=\u00a76Changed spawner type to\u00a7c {0}\u00a76. +sheepMalformedColor=Felformulerad f\u00e4rg. +shoutFormat=\u00a77[Hojtning]\u00a7f {0} +signFormatFail=\u00a74[{0}] +signFormatSuccess=\u00a71[{0}] +signFormatTemplate=[{0}] +signProtectInvalidLocation=\u00a74Du har inte till\u00e5telse att g\u00f6ra skyltar h\u00e4r. +similarWarpExist=En warp med ett liknande namn finns redan. +slimeMalformedSize=Felformulerad storlek. +socialSpy=\u00a76SocialSpy for \u00a7c{0}\u00a76\: \u00a7c{1} +soloMob=Det h\u00e4r monstret gillar att vara ensam +spawnSet=\u00a77Spawnpunkten inst\u00e4lld f\u00f6r gruppen {0}. +spawned=spawnade +sudoExempt=Du kan inte g\u00f6ra en sudo p\u00e5 den h\u00e4r anv\u00e4ndaren +sudoRun=\u00a76Forcing\u00a7c {0} \u00a76to run\:\u00a7r /{1} +suicideMessage=\u00a77Adj\u00f6 grymma v\u00e4rld... +suicideSuccess=\u00a77{0} tog sitt eget liv +survival=\u00f6verlevnad +takenFromAccount=\u00a7c{0} har tagits fr\u00e5n ditt konto. +takenFromOthersAccount=\u00a7c{0} taget fr\u00e5n {1}\u00a7c konto. Ny balans\: {2} +teleportAAll=\u00a77Teleportations-f\u00f6rfr\u00e5gan skickad till alla spelare... +teleportAll=\u00a77Teleporterar alla spelare... +teleportAtoB=\u00a7c{0}\u00a76 teleported you to \u00a7c{1}\u00a76. +teleportDisabled={0} har teleportering inaktiverat. +teleportHereRequest=\u00a7c{0}\u00a7c har fr\u00e5gat dig om du vill teleportera till dem. +teleportNewPlayerError=Messlyckades med att teleportera ny spelare +teleportRequest=\u00a7c{0}\u00a7c har beg\u00e4rt att f\u00e5 teleportera sig till dig. +teleportRequestTimeoutInfo=\u00a77Den h\u00e4r beg\u00e4ran kommer att g\u00e5 ut efter {0} sekunder. +teleportTop=\u00a77Teleporterar till toppen. +teleportationCommencing=\u00a77Teleporteringen p\u00e5b\u00f6rjas... +teleportationDisabled=\u00a76Teleportation \u00a7cdisabled\u00a76. +teleportationDisabledFor=\u00a76Teleportation \u00a7cdisabled \u00a76for \u00a7c{0}\u00a76. +teleportationEnabled=\u00a76Teleportation \u00a7cenabled\u00a76. +teleportationEnabledFor=\u00a76Teleportation \u00a7cenabled \u00a76for \u00a7c{0}\u00a76. +teleporting=\u00a77Teleporterar... +teleportToPlayer=\u00a76Teleporting to \u00a7c{0}\u00a76. +tempBanned=\u00a7cYou have been temporarily banned for {0}\:\n\u00a7r{2} +tempbanExempt=\u00a77Du kan inte tempor\u00e4rt banna den spelaren +thunder=Du {0} \u00e5ska i din v\u00e4rld +thunderDuration=Du {0} i din v\u00e4rld i {1} sekunder. +timeBeforeHeal=Tid f\u00f6re n\u00e4ste l\u00e4kning\: {0} +timeBeforeTeleport=Tid f\u00f6re n\u00e4sta teleportering\: {0} +timeFormat=\u00a7c{0}\u00a76 or \u00a7c{1}\u00a76 or \u00a7c{2}\u00a76 +timeSetPermission=\u00a7cDu har inte tillst\u00e5nd att st\u00e4lla in tiden. +timeWorldCurrent=Den nuvarande tiden i {0} \u00e4r \u00a73{1} +timeWorldSet=Tiden \u00e4r nu {0} i\: \u00a7c{1} +totalWorthAll=\u00a7aS\u00e5lde alla objekt f\u00f6r ett totalt v\u00e4rde av \u00a7c{1}\u00a7a. +totalWorthBlocks=\u00a7aS\u00e5lde alla blocks f\u00f6r ett totalt v\u00e4rde av \u00a7c{1}\u00a7a. +tps=Nuvarande TPS \= {0} +tradeSignEmpty=K\u00f6pskylten har inget tillg\u00e4ngligt f\u00f6r dig. +tradeSignEmptyOwner=Det finns inget att fr\u00e5n den h\u00e4r k\u00f6pskylten. +treeFailure=\u00a7cTr\u00e4dgenereringn misslyckades. Prova igen p\u00e5 gr\u00e4s eller jord. +treeSpawned=\u00a77Tr\u00e4d genererat. +true=sant +typeTpaccept=\u00a77F\u00f6r att teleportera, skriv \u00a7c/tpaccept\u00a77. +typeTpdeny=\u00a77F\u00f6r att neka denna f\u00f6rfr\u00e5gan, skriv \u00a7c/tpdeny\u00a77. +typeWorldName=\u00a77Du kan ocks\u00e5 skriva namnet av en specifik v\u00e4rld. +unableToSpawnMob=Kunde inte spawna moben. +unignorePlayer=Du ignorerar inte spelaren {0} l\u00e4ngre. +unknownItemId=Ok\u00e4nt objekt-ID\: {0} +unknownItemInList=Ok\u00e4nt objekt {0} i listan {1}. +unknownItemName=Ok\u00e4nt objektnamn\: {0} +unlimitedItemPermission=\u00a74No permission for unlimited item \u00a7c{0}\u00a74. +unlimitedItems=Obegr\u00e4nsade objekt\: +unmutedPlayer=Spelaren {0} \u00e4r inte bannlyst l\u00e4ngre. +unvanishedReload=\u00a7cEn omladdning har tvingat dig att bli synlig. +upgradingFilesError=Fel vid uppgradering av filerna +uptime=\u00a76Upptid\:\u00a7c {0} +userAFK=\u00a77{0} \u00a75\u00e4r f\u00f6r n\u00e4rvarande AFK och kanske inte svarar. +userDoesNotExist=Anv\u00e4ndaren {0} existerar inte. +userIsAway={0} \u00e4r nu AFK +userIsNotAway={0} \u00e4r inte l\u00e4ngre AFK +userJailed=\u00a77Du har blivit f\u00e4ngslad +userUnknown=\u00a74Varning\: Anv\u00e4ndaren ''\u00a7c{0}\u00a74'' har aldrig varit inne p\u00e5 denna server tidigare. +userdataMoveBackError=Kunde inte flytta userdata/{0}.tmp till userdata/{1} +userdataMoveError=Kunde inte flytta userdata/{0} till userdata/{1}.tmp +usingTempFolderForTesting=Anv\u00e4nder tempor\u00e4r mapp mapp f\u00f6r testning\: +vanished=\u00a7aDu \u00e4r nu osynlig. +versionMismatch=Versionerna matchar inte\! V\u00e4nligen uppgradera {0} till samma version. +versionMismatchAll=Versionerna matchar inte\! V\u00e4nligen uppgradera alla Essentials jars till samma version. +voiceSilenced=\u00a77Din r\u00f6st har tystats +walking=g\u00e5r +warpDeleteError=Problem med att ta bort warp-filen. +warpList={0} +warpListPermission=\u00a7cDu har inte tillst\u00e5nd att lista warparna. +warpNotExist=Den warpen finns inte. +warpOverwrite=\u00a7cDu kan inte skriva \u00f6ver den warpen. +warpSet=\u00a77Warpen {0} inst\u00e4lld. +warpUsePermission=\u00a7cDU har inte tillst\u00e5nd att anv\u00e4nda den warpen. +warpingTo=\u00a77Warpar till {0}. +warps=Warpar\: {0} +warpsCount=\u00a76There are\u00a7c {0} \u00a76warps. Showing page \u00a7c{1} \u00a76of \u00a7c{2}\u00a76. +weatherStorm=\u00a77Du har st\u00e4llt in v\u00e4dret till storm i {0} +weatherStormFor=\u00a77Du har st\u00e4llt in v\u00e4dret till storm i {0} f\u00f6r {1} sekunder +weatherSun=\u00a77Du har st\u00e4llt in v\u00e4dret till sol i {0} +weatherSunFor=\u00a77Du har st\u00e4llt in v\u00e4dret till sol i {0} f\u00f6r {1} sekunder +whoisAFK=\u00a76 - AFK\:\u00a7f {0} +whoisBanned=\u00a76 - Bannad\:\u00a7f {0} +whoisExp=\u00a76 - Erfarenhet\:\u00a7f {0} (Level {1}) +whoisFly=\u00a76 - Flygl\u00e4ge\:\u00a7f {0} ({1}) +whoisGamemode=\u00a76 - Spell\u00e4ge\:\u00a7f {0} +whoisGeoLocation=\u00a76 - Lokalisering\:\u00a7f {0} +whoisGod=\u00a76 - Gudsl\u00e4ge\:\u00a7f {0} +whoisHealth=\u00a76 - H\u00e4lsa\:\u00a7f {0}/20 +whoisIPAddress=\u00a76 - IP-Adress\:\u00a7f {0} +whoisJail=\u00a76 - F\u00e4ngelse\:\u00a7f {0} +whoisLocation=\u00a76 - Lokalisering\:\u00a7f ({0}, {1}, {2}, {3}) +whoisMoney=\u00a76 - Pengar\:\u00a7f {0} +whoisMuted=\u00a76 - Tystad\:\u00a7f {0} +whoisNick=\u00a76 - Smeknamn\:\u00a7f {0} +whoisOp=\u00a76 - OP\:\u00a7f {0} +whoisTop=\u00a76 \=\=\=\=\=\= WhoIs\:\u00a7c {0} \u00a76\=\=\=\=\=\= +worth=\u00a77Stapeln med {0} ({2} objekt) \u00e4r v\u00e4rd \u00a7c{1}\u00a77 ({3} styck) +worthMeta=\u00a77Stapeln med {0} av typ {1} ({3} objekt) \u00e4r v\u00e4rd \u00a7c{2}\u00a77 ({4} styck) +worthSet=V\u00e4rdet inst\u00e4llt +year=\u00e5r +years=\u00e5r +youAreHealed=\u00a77Du har blivit l\u00e4kt. +youHaveNewMail=\u00a7cDu har {0} meddelanden\!\u00a7f Skriv \u00a77/mail read\u00a7f f\u00f6r att l\u00e4sa dina meddelanden. +whoisHunger=\u00a76 - Hunger\:\u00a7r {0}/20 (+{1} m\u00e4ttnad) +kitDelay=\u00a7m{0}\u00a7r +giveSpawnFailure=\u00a74Inte nog med utrymme, \u00a7c{0} \u00a7c{1} \u00a74f\u00f6rlorades. +noKitGroup=\u00a74Du har inte tillg\u00e5ng till detta kit. +inventoryClearingFromAll=\u00a76Rensar inventoriet f\u00f6r alla spelare... +inventoryClearingAllItems=\u00a76Rensade alla inventory saker fr\u00e5n {0}\u00a76. +inventoryClearingAllArmor=\u00a76Rensade alla inventory objekt och rustning fr\u00e5n {0}\u00a76. +inventoryClearingAllStack=\u00a76Rensade alla\u00a7c {0} \u00a76fr\u00e5n {1}\u00a76. +inventoryClearingStack=\u00a76Tog bort \u00a7c {0} \u00a76av\u00a7c {1} \u00a76fr\u00e5n {2}\u00a76. +inventoryClearFail=\u00a74Spelaren {0} \u00a74har inte \u00a7c {1} \u00a74av\u00a7c {2}\u00a74. +localNoOne= +totalSellableAll=\u00a7aDet totala v\u00e4rdet av alla s\u00e4ljbara objekt \u00e4r \u00a7c {1} \u00a7a. +totalSellableBlocks=\u00a7aDet totala v\u00e4rdet av alla s\u00e4ljbara block \u00e4r \u00a7c {1} \u00a7a. +radiusTooBig=\u00a74Radien \u00e4r f\u00f6r stor\! Den maximala radien \u00e4r {0}. +isIpBanned=\u00a76IP \u00a7c {0} \u00a76\u00e4r bannad. +mobDataList=\u00a76Giltig mob data\:\u00a7r {0} +vanish=\u00a76F\u00f6rsvinna f\u00f6r {0} \u00a76\: {1} +noLocationFound=\u00a74Ingen giltig plats hittad. +coordsKeyword={0}, {1}, {2} +banExemptOffline=\u00a74Du kan inte banna spelare som \u00e4r offline. +tempbanExemptOffline=\u00a74Du kan inte tempor\u00e4rt banna spelare som inte \u00e4r online. +mayNotJailOffline=\u00a74Du kan inte f\u00e4ngsla spelare som inte \u00e4r online. +muteExemptOffline=\u00a74Du kan inte tysta spelare som \u00e4r offline. +ignoreExempt=\u00a74Du f\u00e5r inte ignorera den spelaren. +unsafeTeleportDestination=&5Den h\u00e4r destination \u00e4r os\u00e4ker och teleport s\u00e4kerhet \u00e4r avaktiverat +noMetaJson=JSON Metadata \u00e4r inte kompakt med denna bukkit version. +maxMoney=Den h\u00e4r transaktionen \u00e4r f\u00f6r h\u00f6g f\u00f6r den h\u00e4r anv\u00e4ndaren +skullChanged=\u00a76Skull changed to \u00a7c{0}\u00a76. +alphaNames=Spelar namnen kan \u00e4ndast inneh\u00e5lla bokst\u00e4ver och siffror och understreck +givenSkull=\u00a76Du har f\u00e5tt skallen av \u00a7c{0}\u00a76. +noPermissionSkull=\u00a74Du har inte till\u00e5telse att modifiera det Huvudet. +teleportInvalidLocation=Koordinater kan inte vara \u00f6ver 30000000 +invalidSkull=\u00a74Sn\u00e4lla h\u00e5ll i ett spelar Huvud. +weatherInvalidWorld=V\u00e4rld med namn {0} hittades inte\! +gameModeInvalid=\u00a74Du m\u00e5ste ange en en giltig spelare/l\u00e4ge. +mailTooLong=\u00a74Mail message too long. Try to keep it below 1000 characters. +mailDelay=F\u00f6r m\u00e5nga mails har skickats sen senaste minuten. Max\: {0} +seenAccounts=\u00a76Player has also been known as\:\u00a7c {0} +unableToSpawnItem=\u00a74Cannot spawn \u00a7c{0}\u00a74, this is not a spawnable item. +itemsConverted=\u00a76Converted all items into blocks. +itemsNotConverted=\u00a74You have no items that can be converted into blocks. +mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\: +mailMessage={0} + +whoisTempBanned=\u00a76 - Ban expires:\u00a7r {0} +playerTempBanned=\u00a76Player \u00a7c{0}\u00a76 temporarily banned \u00a7c{1}\u00a76 for \u00a7c{2}\u00a76: \u00a7c{3}\u00a76. +mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1} diff --git a/Essentials/src/messages_tr.properties b/Essentials/src/messages_tr.properties new file mode 100644 index 0000000000..898458eb10 --- /dev/null +++ b/Essentials/src/messages_tr.properties @@ -0,0 +1,558 @@ +#X-Generator: crowdin.net +#version: TeamCity +# Single quotes have to be doubled: '' +# Translations start here +# by: +action=\u00a75* {0} \u00a75{1} +addedToAccount=\u00a7a{0} Hesabiniza Eklendi. +addedToOthersAccount=\u00a7a{0} Hesabina Eklendi {1}\u00a7a Yeni Bakiye\: {2} +adventure=macera +alertBroke=Kirik\: +alertFormat=\u00a73[{0}] \u00a7r {1} \u00a76 {2} icerisinde\: {3} +alertPlaced=Yerlestirildi\: +alertUsed=Kullanildi\: +antiBuildBreak=\u00a74Burada\u00a7c {0} \u00a74blogunu kirabilmek icin gerekli izine sahip degilsin. +antiBuildCraft=\u00a74Burada\u00a7c {0}\u00a74Olusturmak icin gerekli izine sahip degilsin. +antiBuildDrop=\u00a7c {0}\u00a74 Esyasini dusurebilmek icin gerekli izine sahip degilsin. +antiBuildInteract=\u00a7c {0}\u00a74 Ile etkilesime girebilmek icin gerekli izine sahip degilisiniz. +antiBuildPlace=\u00a74Burada\u00a7c {0} \u00a74blogunu yerlestirebilmek icin gerekli izine sahip degilsin. +antiBuildUse=\u00a7c {0}\u00a74 Esyasini kullanabilmek icin gerekli izine sahip degilsin. +autoAfkKickReason={0} Dakikadan Fazla AFK Kaldiginiz Icin Atildiniz. +backAfterDeath=\u00a76Son Bulundugun Konuma Geri Donmek Icin \u00a7c/back y00a76Komutunu Girin +backUsageMsg=\u00a76Son Konuma Geri Donuluyor... +backupDisabled=\u00a74Yedekleme ayarlari yapilandirilmadi. +backupFinished=\u00a76Yedekleme bitti. +backupStarted=\u00a76Yedekleme basladi. +balance=\u00a7aBakiye\:\u00a7c {0} +balanceOther=\u00a7a{0} \u00a7aBakiyesi\:\u00a7c {1} +balanceTop=\u00a76Bakiye Siralamasi ({0}) +banExempt=\u00a74Bu Kisiyi Banlayamazsiniz\! +banFormat=\u00a74Banlandi\:\n\u00a7r{0} +bed=\u00a7oyatak\u00a7r +bedMissing=\u00a74Yatagin bulunamadi, kirilmis yada kayip. +bedNull=\u00a7myatak\u00a7r +bedSet=\u00a76Yatak dogma bolgesi olarak kaydedildi\! +bigTreeFailure=\u00a74Buyuk agac olusturma basarisiz. Cimen yada bir toprak uzerine tekrar deneyin. +bigTreeSuccess=\u00a76Buyuk agac olusturuldu. +blockList=\u00a76Essentials gosterilen bir baska pluginin komutlarini engelliyor\: +bookAuthorSet=\u00a76Kitabin yazarini suna degistirdiniz {0}. +bookLocked=\u00a76Bu kitap artik kilitli. +bookTitleSet=\u00a76Kitabin basligi su sekilde degistirildi {0}. +broadcast=\u00a7r\u00a76[\u00a74Duyuru\u00a76]\u00a7a {0} +buildAlert=\u00a74Bunun Icin Izniniz Yok\! +bukkitFormatChanged=Bukkit Versiyonu Uyumlu Deigl\! +burnMsg=\u00a76Olusturdun\u00a7c {0} \u00a76Ateste \u00a7c {1} seconds\u00a76. +canTalkAgain=\u00a76Artik Konusabilirsin. +cannotStackMob=\u00a74Bunun Icin Izniniz Yok\! +cantFindGeoIpDB=GeoIP Veritabaninda Bulunamadi\! +cantReadGeoIpDB=GeoIP Veritabanini Okuyamadi\! +cantSpawnItem=\u00a74Bu Esyayi Alabilmek Icin Gerekli Izine Sahip Degilsiniz\! +chatTypeAdmin=[A] +chatTypeLocal=[L] +chatTypeSpy=[Casus] +cleaned=Oyuncu Verileri Temizlendi. +cleaning=Oyuncu Verileri Temizleniyor... +commandFailed=Komut {0} Gecersiz\: +commandHelpFailedForPlugin=Hata\:Bu Plugin Hakkinda Yardim Almak Icin\: {0} +commandNotLoaded=\u00a74Komut Yuklenemedi\! +compassBearing=\u00a76Pusula\: {0} ({1}). +configFileMoveError=config.yml dosyasini yedekleme bolgesine tasima isleminde basarisiz oldu. +configFileRenameError=Ayarlar Yuklenirken Hata Olustu\! +connectedPlayers=\u00a76Bagli Oyuncular\u00a7r +connectionFailed=Baglanti Kurulurken Hata Olustu\! +cooldownWithMessage=\u00a74Aralik\: {0} +corruptNodeInConfig=\u00a74Not\: Bu Ayar Config Dosyanizda Bulunmuyor. +couldNotFindTemplate=\u00a74Bir {0} +creatingConfigFromTemplate=Yeni Bir Config Dosyasi Suradan Olusturuluyor\: {0} +creatingEmptyConfig=Bos Bir Config Dosyasi Olusturuluyor\: {0} +creative=Sonsuz Mod +currency={0}{1} +currentWorld=\u00a76Suanki Harita\u00a7c {0} +day=Gun +days=Gunler +defaultBanReason=Sunucudan Uzaklastirildiniz\!\! +deleteFileError=Bu Dosya Silinmedi\: {0} +deleteHome=\u00a76Eviniz Noktan\u0131z\u00a7c {0} \u00a76Silindi. +deleteJail=\u00a76Hapishane Noktasi\u00a7c {0} \u00a76Silindi. +deleteWarp=\u00a76Isinlanma Noktasi\u00a7c {0} \u00a76Silindi. +deniedAccessCommand=\u00a7c{0} \u00a74izininiz Yok. +denyBookEdit=\u00a74Bu Kitabi Acma \u0130znin Yok. +denyChangeAuthor=\u00a74Yazarin Adini Degistiremezsin. +denyChangeTitle=\u00a74Kitabin Basligini Degistiremezsin\! +depth=\u00a76Deniz Seviyesindesiniz. +depthAboveSea=\u00a76Deniz Seviyesinin\u00a7c {0} \u00a76block(s) Ustundesiniz. +depthBelowSea=\u00a76Deniz Seviyesinin\u00a7c {0} \u00a76block(s) Altindasiniz. +destinationNotSet=Bolge Belirlenmedi. +disableUnlimited=\u00a76Sinirsiz Yerlestirme Devre Disi\! +disabled=devre disi\! +disabledToSpawnMob=\u00a74Mob Dogurma Ayarlardan Devre Disi Birakilmis\! +distance=\u00a76Konum\: {0} +dontMoveMessage=\u00a7c {0}\u00a76 Saniye Icerisinde Isinlanicaksiniz Lutfen Hareket Etmeyin. +downloadingGeoIp=GeoIP Veritabani Indiriliyor. +duplicatedUserdata=Kullanici Verisi +durability=\u00a76Bu Aletin \u00a7c{0}\u00a76 kullanim omuru kaldi +editBookContents=\u00a7eKitabi Duzenleyebilirsin. +enableUnlimited=\u00a76Sinirsiz Sayida Veriliyor\:\u00a7c {0} \u00a76to {1}. +enabled=aktif +enchantmentApplied=\u00a76Buyulendi\! +enchantmentNotFound=\u00a7cBuyu Bulunamadi +enchantmentPerm=\u00a74Bunun Icin Izininiz Yok\! +enchantmentRemoved=\u00a76Buyu Silindi\! +enchantments=\u00a76Buyuler\:\u00a7r {0} +errorCallingCommand=Komut Hatasi /{0} +errorWithMessage=\u00a7cHata\:\u00a74 {0} +essentialsHelp1=Plugin Bozuldu Essentials Devre Disi Birakildi Eger Kendin Duzeltemezsen Panelden Ticket Yolla Yada Skype\: nikoladx2 Hasan Kasac\u0131 Yardim Isteyebilirsin. +essentialsHelp2=Plugin Bozuldu Essentials Devre Disi Birakildi Eger Kendin Duzeltemezsen Panelden Ticket Yolla Yada Skype\: nikoladx2 Hasan Kasac\u0131 Yardim Isteyebilirsin. +essentialsReload=\u00a76Essentials Yenilendi\!\u00a7c {0} +exp=\u00a7c{0} \u00a76var\u00a7c {1} \u00a76exp (seviye\u00a7c {2}\u00a76) seviye atlamak icin gerekli olan exp\u00a7c {3} \u00a76 +expSet=\u00a7c{0} \u00a76Artik\u00a7c {1} \u00a76exp. +extinguish=\u00a76Kendini Sondurdun +extinguishOthers=\u00a76Su Kisiyi Sondurdun {0}\u00a76. +failedToCloseConfig=Ayarlari Kapatirkan Hata Olustu {0}. +failedToCreateConfig=Ayarlari Olustururken Hata Olustu {0}. +failedToWriteConfig=Ayarlari Duzenlerken Hata Yapmis Olmalisin {0}. +false=\u00a74yanlis\u00a7r +feed=\u00a76Kendini Besledin. +feedOther=\u00a76Besledin. +fileRenameError=Dosya Isimlendirilirken Hata Olustu +fireworkColor=\u00a74Ilk Once Bir Renk Belirlemelisin. +fireworkEffectsCleared=\u00a76Tum Efektler Silindi. +fireworkSyntax=\u00a76Havaifisek parametreleri\: +flyMode=\u00a76Ucus Modu\! +flying=ucuyor +foreverAlone=\u00a74Tekrar Edebilecegin Biri Yok \:( +fullStack=\u00a74Zaten Ful +gameMode=\u00a76Oyun Modun Degistirildi\! +gcWorld=\u00a76{0} "\u00a7c{1}\u00a76"\: \u00a7c{2}\u00a76 \u00a7c{3}\u00a76 +gcfree=\u00a76Serbest Hafiza\:\u00a7c {0} MB. +gcmax=\u00a76Maximum Hafiza\:\u00a7c {0} MB. +gctotal=\u00a76Kullanilan Hafiza\:\u00a7c {0} MB. +geoIpUrlEmpty=GeoIP IP Hafizasi Bos. +geoIpUrlInvalid=GeoIP Indirilmeye Calisilan IP Gecersiz\! +geoipJoinFormat=\u00a76Oyuncu \u00a7c{0} \u00a7c{1}\u00a76 Tarafindan Geliyor. +giveSpawn=\u00a76Veriliyor\u00a7c {0} \u00a76,\u00a7c {1} to\u00a7c {2}\u00a76. +godDisabledFor=\u00a7c {0} \u00a76Icin Devre Disi +godEnabledFor=\u00a7c {0}\u00a76 Icin Devre Disi +godMode=\u00a76God Modu\! +groupDoesNotExist=\u00a74Bu Grupta Aktif Olan Biri Yok\! +groupNumber=\u00a7c{0}\u00a7f aktif, ful liste icin\:\u00a7c /{1} {2} +hatArmor=\u00a74Bunu Kafana Geciremezsin\! +hatEmpty=\u00a74Kafana Gecirilen Birsey Yok\! +hatFail=\u00a74Ne Yani Havayi Falanmi Kafana Sokacan Elinde Birsey Olmasi Gerekli\! +hatPlaced=\u00a76Yeni Super Oldu Kardesim Gule Gule Kullan\! +hatRemoved=\u00a76Kafan Silindi. +haveBeenReleased=\u00a76Kafan Silindi. +heal=\u00a76Canlandirildin\! +healDead=\u00a74Olu Birine Canmi Vermeyi Denedin Az Once ?\! +healOther=\u00a76Canlandi\u00a7c {0}\u00a76. +helpConsole=Yardim Icin ? Yazin +helpFrom=\u00a76Komutlar {0}\: +helpLine=\u00a76/{0}\u00a7r\: {1} +helpMatching=\u00a76Komutlar Eslesiyor "\u00a7c{0}\u00a76"\: +helpOp=\u00a74[Yardim]\u00a7r \u00a76{0}\:\u00a7r {1} +helpPlugin=\u00a74{0}\u00a7r\: Plugin Yardim\: /yardim {1} +holdBook=\u00a74Yazilabilir Bir Kitap Tutmuyorsun\! +holdFirework=\u00a74Ilk Once Elinde Bir Havai Fisek Olmali Degil mi ? +holdPotion=\u00a74Ilk Once Elinde Bir Iksir Olmasi Gerekli Degil mi ? +holeInFloor=\u00a74Katda Delik\! +homeSet=\u00a76Eviniz Kaydedildi\! +homes=\u00a76Evleriniz\:\u00a7r {0} +hour=saat +hours=Saatler +ignoredList=\u00a76Engellenen\:\u00a7r {0} +ignorePlayer=\u00a76Oyuncu\u00a7c {0} \u00a76Engelledin. +illegalDate=Illegal Tarih Format. +infoChapter=Okuyacagin Bolumu Sec\: +infoChapterPages=\u00a76Bolum {0}, Sayfalar \u00a7c{1}\u00a76,\u00a7c{2}\u00a76\: +infoPages=\u00a7e ---- \u00a76{2} \u00a7e--\u00a76 Sayfalar \u00a7c{0}\u00a76/\u00a7c{1} \u00a7e---- +infoUnknownChapter=Tan\u0131mlanmayan Bolum +insufficientFunds=\u00a74Yeterli Degil. +invalidCharge=\u00a74Gecerli Degil. +invalidFireworkFormat=\u00a74Gecersiz Havaifisek Formati\! +invalidHome=\u00a7c {0} \u00a76adli Bir Eviniz Yok\! +invalidHomeName=\u00a7cUygun Olmayan Ev Ismi\! +invalidMob=\u00a74Bilinmeyen Yaratik T\u00fcr\u00fc. +invalidNumber=Gecersiz Numara. +invalidPotion=\u00a74Gecersiz Iksir. +invalidPotionMeta=\u00a74Gecersiz Iksir Turu \u00a7c{0}\u00a74.\n +invalidSignLine=\u00a74Gecersiz Satir\u00a7c {0} \u00a74Mevcut Degil. +invalidWarpName=\u00a7cGecersiz Is\u0131nlanma Noktasi Adi\! +invalidWorld=\u00a7cGecersiz Harita. +is=olan +itemCannotBeSold=\u00a74Bu Esyayi Sunucuya Satamazsiniz\! +itemMustBeStacked=\u00a74Esya Takasi Icin Elindeki Esyanin Bir Stack(Dolu 64) Olmasi Gerekir. +itemNames=\u00a76Esya Kisaltmalari\:\u00a7r {0} +itemNotEnough1=\u00a74Satmak Icin Yeterli Esyaniz Bulunmamaktadir\! +itemNotEnough2=\u00a76Eger Envanterinde Varolan Tum Esyayi Satmak Istiyorsan /sell itemname. +itemNotEnough3=\u00a76/sell esyaisimi Ile Islemini Gerceklestirebilirsin. +itemSellAir=Havayimi Satacaks\u0131n Hahah Satmak Istedigin Seyi Eline Al. +itemSold=\u00a7aSatilan Esya \u00a7c{0} \u00a7a({1} {2} , {3}). +itemSoldConsole=\u00a7a{0} \u00a7aSatildi {1} , \u00a7a{2} \u00a7a({3} , {4}). +itemSpawn=\u00a76Verilmekte\u00a7c {0} \u00a76-\u00a7c {1} +itemType=\u00a76Esya ve Araclar\:\u00a7c {0} \u00a76-\u00a7c {1} +itemsCsvNotLoaded=Esya Verileri Yuklenmedi\! +jailAlreadyIncarcerated=\u00a74Bu Oyuncu Zaten Hapse Mahkum\:\u00a7c {0} +jailMessage=\u00a74Cezalandirildin Lutfen Kurallara Dikkat Et\! +jailNotExist=\u00a74Boyle Bir Hapishane Noktasi Yok. +jailReleased=\u00a76Oyuncu \u00a7c{0}\u00a76 Hapis Cezasi Bitti Veya Kaldirildi. +jailReleasedPlayerNotify=\u00a76Cezan Bitti Yada Affedildin. +jailSentenceExtended=\u00a76Hapis Cezasinin Bitecegi Zaman\: {0}. +jailSet=\u00a76Hapishane Noktasi\u00a7c {0} \u00a76Olusturuldu. +jumpError=\u00a74Bu Zorlama \u00d6lebilirsin +kickDefault=Oyundan Atildin\! +kickExempt=\u00a74Bu Oyuncuyu Oyundan Atamazsiniz\!\n +kickedAll=\u00a74Herkes Oyundan Atildi. +kill=\u00a76Katledildi\u00a7c {0}\u00a76. +killExempt=\u00a74 Gebertemezsiniz {0} +kitCost=\ \u00a77\u00a7o({0})\u00a7r +kitError2=\u00a74Bu Setde Bir Sorun Var Lutfen Yoneticiye Bildir. +kitError=\u00a74Hic Set Yok\! +kitGiveTo=\u00a76Verilen Set\u00a7c {0}\u00a76 Verilen Sahis {1}\u00a7. +kitInvFull=\u00a74Sirt Cantan Dolu Full\! +kitNotFound=\u00a74Boyle Bir Kit Yok\! +kitOnce=\u00a74Bu Esya Setini Kullanamazin\! +kitReceive=\u00a76Al\u0131nan Kit\u00a7c {0}\u00a76. +kitTimed=\u00a74Bu Esya Setini Tekrar Kullanma Vaktin\u00a7c {0}\u00a74. +kits=\u00a76Esya Setleri\:\u00a7r {0} +leatherSyntax=\u00a76Deri renk s\u00f6zdizimi\: renk\: , , \u00f6rne\u011fin \: renk\: 255, 0, 0. +lightningSmited=\u00a76Thorun Gucu Adina Simsek\! +lightningUse=\u00a76Bu Kisi Simsek Atiyor\u00a7c {0} +listAfkTag=\u00a77[UzaktaAFK]\u00a7r +listAmount=\u00a76Oyuncu Kapasitesi \u00a7c{0}\u00a76 Acik Olan \u00a7c{1}\u00a76. +listAmountHidden=\u00a76Suan \u00a7c{0}\u00a76/{1}\u00a76 Sunucudaki \u00a7c{2}\u00a76 oyuncu cevrimici. +listGroupTag={0}\u00a7f\: +listHiddenTag=\u00a77[Gizlenmis]\u00a7r +loadWarpError=\u00a74Is\u0131nlanma Noktasi Yuklenemedi {0}. +localFormat=[L]<{0}> {1} +mailClear=\u00a76Sectigin Mailleri Temizlemek Icin \u00a7c/mail clear \u00a76Komutunu Gir. +mailCleared=\u00a76E-Postan Temizlendi\! +mailSent=\u00a76E-Posta Gonderildi\! +markMailAsRead=\u00a76Okudugun Postalari Temizlemek Icin /mail clear +markedAsAway=\u00a76Uzak Noktada Tespit Edildin. +markedAsNotAway=\u00a76Isaretin Kalkti. +matchingIPAddress=\u00a76Ayni IP Adresinden ve Noktadan Giris Yapan Oyuncular\: +maxHomes=\u00a74Bu Sayidan\u00a7c {0} \u00a74Fazla Ev Is\u0131nlanma Noktasi Belirleyemezsin\! +mayNotJail=\u00a74Bu Oyuncu Hapse Mahkum Edildi\! +me=Ben +minute=dakika +minutes=Dakikalar +missingItems=\u00a74{0}x {1} Esyaya Sahip Degilsin. +mobSpawnError=\u00a74Yaratik Olusturucu Degisirken Hata Olustu. +mobSpawnLimit=Yaratiklar Sunucu Limitini Asiyor\! +mobSpawnTarget=\u00a74Bu Komutu Girerken Bir Olusturucuya Bakmalisiniz\! +mobsAvailable=\u00a76Yaratiklar\:\u00a7r {0} +moneyRecievedFrom=\u00a7a{0} {1} tarafindan elinden alindi . +moneySentTo=\u00a7a{0} Iletildi {1}. +month=Ay +months=Aylar +moreThanZero=\u00a74Sifirdan Buyuk Deger Gir. +moveSpeed=\u00a76Hiz Degistirildi\! +msgFormat=\u00a76[\u00a7c{0}\u00a76 -> \u00a7c{1}\u00a76] \u00a7r{2} +multipleCharges=\u00a74Bu HavaiFisek Uzerinde Daha Fazla Degisiklik Yapamazsin\! +multiplePotionEffects=\u00a74Bu Iksir Uzerine Daha Fazla Etki Eklemeyezsin\! +muteExempt=\u00a74Bu Adami Susturamazsin\! +muteNotify=\u00a74{0} \u00a76Susturuldu \u00a74{1}\u00a76. +mutedPlayer=\u00a76Oyuncu {0} \u00a76Susturuldu +mutedPlayerFor=\u00a76Oyuncu {0} \u00a76Su Sebepten Dolayi Susturuldu {1}. +mutedUserSpeaks={0} Konusmayi Denedi Fakat Onceden Susturulmustu. +nearbyPlayers=\u00a76Yakindaki Oyuncular\:\u00a7r {0} +negativeBalanceError=\u00a74Kullanici Negatif Degerli Bir Bakiye Icin Gerekli Izine Sahip Degil\! +nickChanged=\u00a76Kullanici Adi Degistirildi\! +nickDisplayName=\u00a74Essentials Ayarlarindan Bir change-displayname Acik Yapman Gerekir. +nickInUse=\u00a74Bu Isim Kullaniliyor\! +nickNamesAlpha=\u00a74Kullanici Ismi Sadece Alfabe Icerikli Olmalidir\! +nickNoMore=\u00a76Artik Bir Kullanici Ismin Yok\! +nickSet=\u00a76Yeni Kullanici Ismin \u00a7c{0} +nickTooLong=\u00a74Bu isim cok uzun. +noAccessCommand=\u00a74Bu Komut Icin Gerekli Yetkiye Sahip Degilsin\! +noAccessPermission=\u00a74Bu Komut Icin Gerekli Yetkiye Sahip Degilsin\! {0}. +noBreakBedrock=\u00a74Sen Az Once Katman Kayasini Yok Etmeyemi Calistin?\! +noDestroyPermission=\u00a74{0} Yokedebilmek Icin Gerekli Izine Sahip Degilsin\! +noDurability=\u00a74Gecersiz\! +noGodWorldWarning=\u00a74Dikkat Bu Dunyada Olumsuzluk Aktif Degil\! +noHelpFound=\u00a74Eslesen Komut Yok\! +noHomeSetPlayer=\u00a76Olusturulmus Hic Evi Yok\! +noIgnored=\u00a76Hi\u00e7 kimseyi g\u00f6z ardi etmiyorsun. +noKitPermission=\u00a74Bu Kiti Kullanmak Icin VIP Satin Almaniz Gerekir\! +noKits=\u00a76Hic Kit Yok\! +noMail=\u00a76Gelen Kutunuz Bos\! +noMatchingPlayers=\u00a76Eslesen Oyuncu Bulunamadi\! +noMetaFirework=\u00a74Bunun Icin Gerekli Izine Sahip Degilsin\! +noMetaPerm=\u00a74Bunun Icin Gerekli Izine Sahip Degilsin\! +noNewMail=\u00a76Size Gelen Yeni Bir Mail Yok +noPendingRequest=\u00a74Size Gelen Herhangi Bir Istek Yok +noPerm=\u00a74Bunun Icin Gerekli Izine Sahip Degilsiniz\! +noPermToSpawnMob=\u00a74Bu Mobu Olusturmak Icin Gerekli Yektiniz Yok\! +noPlacePermission=\u00a74Bu Tabelanin Yanina Herhangi Bir Blok Yerlestiremezsin\! +noPotionEffectPerm=\u00a74Bunun Icin Gerekli Izine Sahip Degilsin\! +noPowerTools=\u00a76Aktif Edilmis Herhangi Bir Guc Aleti Yok\! +noWarpsDefined=\u00a76Hic Warp Yok\! +none=yok +notAllowedToQuestion=\u00a74Soru Sorabilmek Icin Izinin Yok\! +notAllowedToShout=\u00a74Bagirmak Icin Iznin Yok\! +notEnoughExperience=\u00a74Yeterli Exp Yok\! +notEnoughMoney=\u00a74Yetersiz Bakiye\! +notFlying=ucmuyor +notRecommendedBukkit=\u00a74* \! * Bukkit Versiyonunuzu Essentials Onermiyor. +notSupportedYet=Simdilik Desteklenmiyor. +nothingInHand=\u00a74Elinde Hicbirsey Yok\! +now=simdi +nuke=\u00a75nuke +numberRequired=Bir numara oraya gidiyor, sa\u00e7ma. +onlyDayNight=/time sadece day/night destekliyor. +onlyPlayerSkulls=\u00a74Sadece oyuncu sahiplerinin kafa taslarini belirleyebilirsin. (397\:3). +onlyPlayers=\u00a74Sadece Oyun Icinde Kullanilabilir Bir Komut {0}. +onlySunStorm=\u00a74/weather sadece sun/storm destekliyor. +orderBalances=\u00a7c {0} \u00a76Adli oyuncularin bakiyesi listeleniyor, l\u00fctfen bekleyin... +oversizedTempban=\u00a74Oyunculari bu kadar sure yasaklayamazsin. +pTimeCurrent=\u00a7c{0}\u00a76''in zaman\u0131\:\u00a7c {1}\u00a76. +pTimeCurrentFixed=\u00a7c{0}\u00a76''in zaman\u0131 {1}\u00a76''a ayarland\u0131. +pTimeNormal=\u00a7c{0}\u00a76''in zaman\u0131 do\u011fru ve sunucuya uyuyor. +pTimeOthersPermission=\u00a74Di\u011fer oyuncular\u0131n zaman\u0131n\u0131 de\u011fi\u015ftirme yetkin yok. +pTimePlayers=\u00a76Bu oyuncular kendi zamanlar\u0131n\u0131 kullan\u0131yor\:\u00a7r +pTimeReset=\u00a76Oyuncu zamani \u00a7c{0} \u00a76adli uye icin resetlendi. +pTimeSet=\u00a76Oyuncu zamani su oyuncu icin \u00a7c{0}\u00a76, \u00a7c{1} olarak ayarlandi. +pTimeSetFixed=\u00a76Oyuncu zamani su oyuncu icin \u00a7c{0}\u00a76, \u00a7c{1} olarak ayarlandi. +pWeatherCurrent=\u00a7c{0}\u00a76 adli oyuncunun hav adurumu\u00a7c {1}\u00a76. +pWeatherInvalidAlias=\u00a74Gecersiz hava durumu tipi +pWeatherNormal=\u00a7c{0}\u00a76 adli oyuncunun hava durumu sunucunun ki ile eslesiyor. +pWeatherOthersPermission=\u00a74Ba\u015fkalar\u0131n\u0131n hava durumunu de\u011fi\u015ftiremezsin. +pWeatherPlayers=\u00a76Bu oyuncularin kendilerine ozgu hava durumlari var\:\u00a7r +pWeatherReset=\u00a76Oyuncu hava durumu \u00a7c{0} \u00a76 adli oyuncu icin sifirlandi. +pWeatherSet=\u00a76Oyuncu hava durumunu \u00a7c{1} \u00a76adli oyuncu icin \u00a7c{0} olarak ayarlandi. +pendingTeleportCancelled=\u00a74Beklenen isinlanma islemi iptal edildi. +playerBanIpAddress=\u00a76Player\u00a7c {0} \u00a76banned IP address\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerBanned=\u00a76Oyuncu\u00a7c {0} \u00a76banlandi {1} \u00a76Sebep {2}. +playerInJail=\u00a74Bu Adamdan Ne Istiyorsun, Zaten Hapiste\u00a7c {0}\u00a76. +playerJailed=\u00a76Oyuncu\u00a7c {0} \u00a76Hapise Atildi\! Adalet <3 +playerJailedFor=\u00a76Oyuncu\u00a7c {0} \u00a76Hapise Atilma Sebebi {1}. +playerKicked=\u00a76Oyuncu\u00a7c {0} \u00a76Atildi {1} Sebep {2}. +playerMuted=\u00a76Susturuldun\! +playerMutedFor=\u00a76Susturuldun - Sebep\u00a7c {0}. +playerNeverOnServer=\u00a74Oyuncu\u00a7c {0} \u00a74Bu Servere Adimina Bile Atmadi +playerNotFound=\u00a74Oyuncu Bulunamadi\! +playerUnbanIpAddress=\u00a76Oyuncu\u00a7c {0} \u00a76bani kaldirildi IP\: {1}. +playerUnbanned=\u00a76Oyuncu\u00a7c {0} \u00a76Bani Cozuldu {1}. +playerUnmuted=\u00a76Artik Konusabilirsin\! +pong=Gurultu\! +posPitch=\u00a76Egim\: {0} (kafa acisi) +posX=\u00a76X\: {0} (+Dogu <-> -Bati) +posY=\u00a76Y\: {0} (+Yukari <-> -Assagi) +posYaw=\u00a76Yaw\: {0} (Rotasyon) +posZ=\u00a76Z\: {0} (+Guney <-> -Kuzey) +possibleWorlds=\u00a76Possible worlds are the numbers 0 through {0}. +potions=\u00a76Iksirler\:\u00a7r {0}\u00a76. +powerToolAir=\u00a74Komut hava icin eklenemiyor. +powerToolAlreadySet=\u00a74Command \u00a7c{0}\u00a74 is already assigned to {1}. +powerToolAttach=\u00a7c{0}\u00a76 komut {1} olarak atandi. +powerToolClearAll=\u00a76All powertool commands have been cleared. +powerToolList=\u00a76Esya \u00a7c{1} \u00a76\: \u00a7c{0}\u00a76 komutlarini icermekte. +powerToolListEmpty=\u00a74Esya\u00a7c{0} \u00a74hic bir komuta atanmamis. +powerToolNoSuchCommandAssigned=\u00a74Command \u00a7c{0}\u00a74 has not been assigned to {1}. +powerToolRemove=\u00a76Command \u00a7c{0}\u00a76 removed from {1}. +powerToolRemoveAll=\u00a76Tum komutlar {0} tarafindan silinmistir. +powerToolsDisabled=\u00a76Tum guc aletlerin devre disi birakildi. +powerToolsEnabled=\u00a76Tum guc aletlerin aktif edildi. +questionFormat=\u00a72[SORU]\u00a7r {0} +readNextPage=\u00a76Diger Sayfaya Gecmek Icin\u00a7c /{0} {1} \u00a76Yazin. +recipe=\u00a76Recipe for \u00a7c{0}\u00a76 ({1} of {2}) +recipeBadIndex=Numara Belirtin\!. +recipeFurnace=\u00a76Smelt \u00a7c{0} +recipeGrid=\u00a7c{0}X \u00a76| \u00a7{1}X \u00a76| \u00a7{2}X +recipeGridItem=\ \u00a7{0}X \u00a76is \u00a7c{1} +recipeMore=\u00a76Diger \u00a7c{2}\u00a76 tariflerini gormek icin \u00a76/{0} \u00a7c{1}\u00a76 yaz. +recipeNone=No recipes exist for {0} +recipeNothing=hicbir \u015fey +recipeShapeless=\u00a76Birlestirme \u00a7c{0} +recipeWhere=\u00a76Nerede\: {0} +removed=\u00a76\u00a7c {0} \u00a76Esya Silindi\! +repair=\u00a76Basari Ile Tamir Ettin. +repairAlreadyFixed=\u00a74Bu Esya Daha Yeni. +repairEnchanted=\u00a74Bu Esya Buyulu Oldugundan Dolayi Tamir Edilemiyor\! +repairInvalidType=\u00a74Bu Esya Tamir Edilemez\! +repairNone=\u00a74Envanterinde Tamir Edilmesi Gereken Hic Item Yok\! +requestAccepted=\u00a76Isinlanma Istegi Kabul Edildi. +requestAcceptedFrom=\u00a7c{0} \u00a76Isinlanma Istegini Kabul Etti. +requestDenied=\u00a76Isinlanma Istegi Rededildi +requestDeniedFrom=\u00a7c{0} \u00a76Istegini Redetti\! +requestSent=\u00a76Isinlanma Istegi Gonderildi. +requestTimedOut=\u00a74Isinlanma Istegi Zaman Asimina Ugradi\! +requiredBukkit=\u00a76* \! * CraftBukkitiniz Plugin Ile Uyusmuyor Lutfen Son Surumu Yukleyin. +resetBal=\u00a76Bakiyeler Resetlendi \u00a7a{0} \u00a76Tum Online Oyuncular Icin. +resetBalAll=\u00a76Bakiyeler Resetlendi \u00a7a{0} \u00a76Tum Oyuncular Icin. +returnPlayerToJailError=\u00a74Oyuncuyu Cikartirken Sorun Olustu\! +runningPlayerMatch=\u00a76Oyuncu Eslesmesi Suruyor... +second=Saniye +seconds=Saniye +seenOffline=\u00a76Oyuncu\u00a7c {0} \u00a76{1} \u00a76suredir \u00a74offline. +seenOnline=\u00a76Oyuncu\u00a7c {0} \u00a76{1} \u00a76suredir \u00a74cevrim disi. +serverFull=Server Dolu\! +serverTotal=\u00a76Server Kapasitesi\:\u00a7c {0} +setBal=\u00a7aBakiyen {0}. +setBalOthers=\u00a7aOyuncu {0}\u00a7a Bakiyesi Guncellendi Yeni Bakiye {1}. +setSpawner=\u00a76Spawner Tipi Degistirildi\u00a7c {0} +sheepMalformedColor=\u00a74Degistirilmis Renk. +shoutFormat=\u00a76[BAGIR]\u00a7r {0} +signFormatFail=\u00a74[{0}] +signFormatSuccess=\u00a71[{0}] +signFormatTemplate=[{0}] +signProtectInvalidLocation=\u00a74Burada tabela kullanma iznin yok. +similarWarpExist=\u00a74Ayni adda isinlanma noktasi mevcut. +slimeMalformedSize=\u00a74Degistirilmis. +socialSpy=\u00a76Admin Sohbet Modu{0}\u00a76\: {1} +soloMob=\u00a74Bu Mob Yanliz Olmak Istiyor Gibi Gorunuyor +spawnSet=\u00a76Spawn Belirlendi +spawned=dogdu +sudoExempt=\u00a74Bu oyuncuyu sudolayamazsin. +sudoRun=\u00a76Forcing\u00a7c {0} \u00a76to run\:\u00a7r /{1} +suicideMessage=\u00a76Hoscakal... Zalim Dunya\! +suicideSuccess=\u00a76{0} \u00a76Kendi Hayatlarindan Alindi. +survival=hayatta kalma +takenFromAccount=\u00a7a{0} Hesabindan Alindi +takenFromOthersAccount={1}\u00a7a hesabindan \u00a7a{0} kadar alindi . Yeni bakiye\: {2}. +teleportAAll=\u00a76Tum Oyunculara Isinlanma Istegi Gonderildi +teleportAll=\u00a76Oyuncular Isinlaniyor\! +teleportAtoB=\u00a7c{0}\u00a76 Sana Isinlandi {1}\u00a76. +teleportDisabled=\u00a7c{0} \u00a74Isinlanma Modu Aktif Degil\! +teleportHereRequest=\u00a7c{0}\u00a76 Kendisine Isinlanmani Istiyor. +teleportNewPlayerError=\u00a74Yeni Oyuncuyu Isinlarken Hata Oldu +teleportRequest=\u00a7c{0}\u00a76 Sana Bir Isinlanma Istegi Yolladi +teleportRequestTimeoutInfo=\u00a76Istek\u00a7c {0} seconds\u00a76 Sonra Zaman Asimina Ugrayicak. +teleportTop=\u00a76En Yuksege Isinlaniliyor +teleportationCommencing=\u00a76Isinlanma Gerceklesiyor... +teleportationDisabled=\u00a76Isinlanma Devre Disi\! +teleportationDisabledFor=\u00a76Isinlanma Su Kisi Icin Devre Disi\! {0}. +teleportationEnabled=\u00a76Isinlanma Aktif\! +teleportationEnabledFor=\u00a76Isinlanma Su Kisi Icin Aktif {0}. +teleporting=\u00a76Isinlaniliyor... +teleportToPlayer=\u00a76Su Kisiye Isinlaniyorsunuz\: \u00a7c{0}\u00a76. +tempBanned=\u00a7cYou have been temporarily banned for {0}\:\n\u00a7r{2} +tempbanExempt=\u00a74Bu Kisiye Sureli Yasaklama Koyamazsin\! +thunder=\u00a76Dunyanda simsek \u00a7c {0} . +thunderDuration=\u00a76D\u00fcnyanda simsek \u00a7c {1} \u00a76sure boyunca \u00a7c {0}. +timeBeforeHeal=\u00a74Bir Sonraki Canlandirma Icin\:\u00a7c {0}\u00a76 Beklemelisiniz. +timeBeforeTeleport=\u00a74Bir Sonraki Isinlanma Icin\:\u00a7c {0}\u00a76 Bekleyiniz. +timeFormat=\u00a7c{0}\u00a76 or \u00a7c{1}\u00a76 or \u00a7c{2}\u00a76. +timeSetPermission=\u00a74Zamani ayarlamak icin yetkili degilsin. +timeWorldCurrent=\u00a76Gecerli saat dilimi\u00a7c {0} \u00a76 \u00a7c{1}\u00a76. +timeWorldSet=\u00a76Dunya Saati Degistirildi\! +totalWorthAll=\u00a7aBloklarin Kapasitesi \u00a7c{1}\u00a7a. +totalWorthBlocks=\u00a7aBlocklar\u0131n Kapasitesi \u00a7c{1}\u00a7a. +tps=\u00a76Suanki TPS \= {0} +tradeSignEmpty=\u00a74Tabelada Senin Icin Birsey Yok\! +tradeSignEmptyOwner=\u00a74Alacak Birsey Yok\! +treeFailure=\u00a74Agac Dikilmede Sorun Olustu, Cimenin Yada Topragin Ustune Yeniden Deneyin. +treeSpawned=\u00a76Agac Dikildi +true=\u00a7adogru\u00a7r +typeTpaccept=\u00a76Kabul Etmek Icin \u00a7c/tpaccept\u00a76. +typeTpdeny=\u00a76Redetmek Icin \u00a7c/tpdeny\u00a76. +typeWorldName=\u00a76Belirli bir dunya ismi de yazabilirsin. +unableToSpawnMob=\u00a74Spawn Dogurma Acik Degil +unignorePlayer=\u00a76Artik\u00a7c {0}''i \u00a76gormezden gelmiyorsun. +unknownItemId=\u00a74Bilinmeyen Esya ID\:\u00a7r {0}\u00a74. +unknownItemInList=\u00a74Bilinmeyen Esya. +unknownItemName=\u00a74Bilinmeyen Esya Isimi\: {0}. +unlimitedItemPermission=\u00a74Sinirsiz Esya Icin Gerekli Izine Sahip Degilsin. +unlimitedItems=\u00a76Sinirsiz Esya\:\u00a7r +unmutedPlayer=\u00a76Oyuncu\u00a7c {0} \u00a76Artik Konusabilirsin\! +unvanishedReload=\u00a74Sunucu Yeniden Yukleme Sirasinda Gorunmezligini Elinden Aldi. +upgradingFilesError=Dosyalari Yenilerken Bir Sorun Olustu. +uptime=\u00a76Acik kalma Suresi\:\u00a7c {0} +userAFK=\u00a75{0} \u00a75AFK +userDoesNotExist=\u00a74Boyle Bir Oyuncu Yok\! +userIsAway=\u00a75{0} \u00a75Uzun Sure Hareket Etmedigi Ic\u0131n AFK Moduna Gecti\! +userIsNotAway=\u00a75{0} \u00a75Artik AFK Degil. +userJailed=\u00a76Hapse Mahkum Edildin\! +userUnknown=\u00a74Bu Oyuncu Sunucuya Hic Girmemis\! +userdataMoveBackError=Hatali Oyuncu Dosyasi Aktarimi/{0}.tmp to userdata/{1}\! +userdataMoveError=Aktarim Hatali/{0} to userdata/{1}.tmp\! +usingTempFolderForTesting=Test Icin Kullanilan Temp Dosyasi\: +vanished=\u00a76Gorunmezsin\! +versionMismatch=\u00a74Versiyon Uyusmazligi\! Lutfen {0} pluginini ayni surume guncelleyin. +versionMismatchAll=\u00a74Versiyon Uyusmazligi\! Lutfen tum Essentials eklentilerini ayni surume guncelleyin. +voiceSilenced=\u00a76Susturuldun\! +walking=yuruyor +warpDeleteError=\u00a74Is\u0131nlanma Dosyasini Silerken Bir Problem Olustu. +warpList={0} +warpListPermission=\u00a74Is\u0131nlanma Listesini Gormek Icin Gerekli Izine Sahip Degilsiniz. +warpNotExist=\u00a74Boyle Bir Is\u0131nlanma Noktasi Yok +warpOverwrite=\u00a74Bir Is\u0131nlanma Noktasi Ustune Is\u0131nlanma Noktasi Ekleyemezsin\! +warpSet=\u00a76Is\u0131nlanma Noktasi\u00a7c {0} \u00a76Olusturuldu\! +warpUsePermission=\u00a74Bu Is\u0131nlanma Noktasini Kullanmak Icin Izniniz Yok\! +warpingTo=\u00a76Isinlan Warp\u00a7c {0}\u00a76. +warps=\u00a76Warp Listesi\:\u00a7r {0} +warpsCount=\u00a76Sunucuda\u00a7c {0} \u00a76Warp Bulunmakta {1} / {2}. +weatherStorm=\u00a76Zaman Degistirlidi +weatherStormFor=\u00a76Zaman Degistirlidi +weatherSun=\u00a76Zaman Degistirlidi +weatherSunFor=\u00a76Zaman Degistirildi +whoisAFK=\u00a76 - UZAKTA\:\u00a7r {0} +whoisBanned=\u00a76 - Banli\:\u00a7r {0} +whoisExp=\u00a76 - EXP\:\u00a7r {0} (Level {1}) +whoisFly=\u00a76 - Ucma\:\u00a7r {0} ({1}) +whoisGamemode=\u00a76 - Oyun modu\:\u00a7r {0} +whoisGeoLocation=\u00a76 - Konum\:\u00a7r {0} +whoisGod=\u00a76 - Olumsuz\:\u00a7r {0} +whoisHealth=\u00a76 - Can\:\u00a7r {0}/20 +whoisIPAddress=\u00a76 - IP Adres\:\u00a7r {0} +whoisJail=\u00a76 - Hapis\:\u00a7r {0} +whoisLocation=\u00a76 - Konum\:\u00a7r ({0}, {1}, {2}, {3}) +whoisMoney=\u00a76 - Para\:\u00a7r {0} +whoisMuted=\u00a76 - Susturulan\:\u00a7r {0} +whoisNick=\u00a76 - Isim\:\u00a7r {0} +whoisOp=\u00a76 - OP\:\u00a7r {0} +whoisTop=\u00a76 \=\=\=\=\=\= Kim\:\u00a7c {0} \u00a76\=\=\=\=\=\= +worth=\u00a7aDolusu of {0} worth \u00a7c{1}\u00a7a ({2} item(s) at {3} each) +worthMeta=\u00a7aDolusu of {0} metadata of {1} worth \u00a7c{2}\u00a7a ({3} item(s) at {4} each) +worthSet=\u00a76Worth degeri belirlendi\! +year=yil +years=yil +youAreHealed=\u00a76Canlandirildin\! +youHaveNewMail=\u00a76\u00a7c {0} \u00a76Mesajin Var Okumak Icin \u00a7c/mail read\u00a76 Yaz. +whoisHunger=\u00a76 - Aclik\:\u00a7r {0}/20 (+{1}) +kitDelay=\u00a7m{0}\u00a7r +giveSpawnFailure=\u00a74Yeterli Bosluk Yok \u00a7c{0} \u00a7c{1} \u00a74kaybedildi. +noKitGroup=\u00a74Bu alet setine erisebilmek icin gerekli izinin yok. +inventoryClearingFromAll=\u00a76Tum Oyuncular\u0131n Esyalari Siliniyor... +inventoryClearingAllItems=\u00a76Oyuncular\u0131n Tum Esyalarini Silen{0}\u00a76. +inventoryClearingAllArmor=\u00a76Oyuncular\u0131n Herseyini Silen{0}\u00a76. +inventoryClearingAllStack=\u00a76Tum Esyalar\u00a7c {0} \u00a76Tarafindan {1}\u00a76. +inventoryClearingStack=\u00a76Silindi\u00a7c {0} \u00a76of\u00a7c {1} \u00a76Tarafindan {2}\u00a76. +inventoryClearFail=\u00a74Oyuncu{0} \u00a74Temizleme Basarisiz\u00a7c {1} \u00a74of\u00a7c {2}\u00a74. +localNoOne= +totalSellableAll=\u00a7aSatabilecegin Maximum Block Sayisi\u00a7c{1}\u00a7a. +totalSellableBlocks=\u00a7aSatabilecegin Maximum Block Sayisi\u00a7c{1}\u00a7a. +radiusTooBig=\u00a74Mesafe cok buyuk\! En fazla mesafe {0}. +isIpBanned=\u00a76IP \u00a7c{0} \u00a76yasaklandi. +mobDataList=\u00a76Bilinmeyen Yaratik Tipi\:\u00a7r {0} +vanish=\u00a76Gorunmezlik {0}\u00a76\: {1} +noLocationFound=\u00a74Gecerli bir konum bulunamadi. +coordsKeyword=X{0}, Y{1}, Z{2} +banExemptOffline=\u00a74Cevrimdisi oyunculari yasaklayamazsin. +tempbanExemptOffline=\u00a74Cevrimdisi oyunculari sureli yasaklayamazsin. +mayNotJailOffline=\u00a74Cevrimdisi oyunculari hapsedemezsin. +muteExemptOffline=\u00a74Cevrimdisi oyunculari susturamazsin. +ignoreExempt=\u00a74Bu oyuncuyu Engellemezsin. +unsafeTeleportDestination=\u00a74Guvenli Is\u0131nlanma Noktas\u0131 Degil Iptal Ediliyor. +noMetaJson=JSON Metadata Desteklenmeyen Bukkit Surumu. +maxMoney=\u00a74Maximum Paraya Ulastiniz\!. +skullChanged=\u00a76Degisen Kafa Turu \u00a7c{0}.\u00a76. +alphaNames=\u00a74Oyuncu Kullanici Adlari Sadece Harf Ve Rakamlardan Olusmalidir. +givenSkull=\u00a76Suan Ald\u0131g\u0131n\u0131z Kelle \u00a7c{0}\u00a76. +noPermissionSkull=\u00a74You do not have permission to modify that Skull. +teleportInvalidLocation=30000000 Blcok Oteye Gidebilirsin En Fazla\! +invalidSkull=\u00a74Lutfen Oyuncu Kellesini Belirtin. +weatherInvalidWorld=Harita Adi {0} Bulunmadi\! +gameModeInvalid=\u00a74Lutfen Oyun Modunu Belirtin. +mailTooLong=\u00a74Yazacagin Posta 1000 Karakterden Fazla Olmasin\! +mailDelay=Cok Fazla Posta Gonderdin. Maximum\: {0} +seenAccounts=\u00a76Oyuncu Bilgilendirildi as\:\u00a7c {0} +unableToSpawnItem=\u00a74Olusturma Hatali \u00a7c{0}\u00a74, Olusturulmaycak Esya. +itemsConverted=\u00a76Converted all items into blocks. +itemsNotConverted=\u00a74You have no items that can be converted into blocks. +mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\: +mailMessage={0} + +whoisTempBanned=\u00a76 - Ban expires:\u00a7r {0} +playerTempBanned=\u00a76Player \u00a7c{0}\u00a76 temporarily banned \u00a7c{1}\u00a76 for \u00a7c{2}\u00a76: \u00a7c{3}\u00a76. +mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1} diff --git a/Essentials/src/messages_zh.properties b/Essentials/src/messages_zh.properties new file mode 100644 index 0000000000..711f8d71df --- /dev/null +++ b/Essentials/src/messages_zh.properties @@ -0,0 +1,558 @@ +#X-Generator: crowdin.net +#version: TeamCity +# Single quotes have to be doubled: '' +# Translations start here +# by: +action=\u00a75* {0} \u00a75{1} +addedToAccount=\u00a7a{0} \u5df2\u6dfb\u52a0\u5230\u4f60\u7684\u94f6\u884c\u8d26\u6237 +addedToOthersAccount=\u00a7a{0} \u5df2\u88ab\u6dfb\u52a0\u5230 {1} \u00a7a\u7684\u8d26\u6237.\u76ee\u524d\u4f59\u989d\: {2} +adventure=\u5192\u9669\u6a21\u5f0f +alertBroke=\u7834\u574f\: +alertFormat=\u00a73[{0}] \u00a7r {1} \u00a76 {2} \u4e8e\: {3} +alertPlaced=\u653e\u7f6e\: +alertUsed=\u4f7f\u7528\: +antiBuildBreak=\u00a74\u4f60\u6ca1\u6709\u6743\u9650\u7834\u574f\u00a7c {0} \u00a74\u8fd9\u4e2a\u65b9\u5757. +antiBuildCraft=\u00a74\u4f60\u6ca1\u6709\u6743\u9650\u521b\u5efa\u00a7c {0} \u00a74. +antiBuildDrop=\u00a74\u4f60\u6ca1\u6709\u6743\u9650\u6254\u6389\u00a7c {0} \u00a74. +antiBuildInteract=\u00a74\u4f60\u6ca1\u6709\u6743\u9650\u4e0e\u00a7c {0}\u00a74\u4ea4\u4e92. +antiBuildPlace=\u00a74\u4f60\u6ca1\u6709\u6743\u9650\u653e\u7f6e\u00a7c {0} \u00a74\u8fd9\u4e2a\u65b9\u5757. +antiBuildUse=\u00a74\u4f60\u6ca1\u6709\u6743\u9650\u4f7f\u7528\u00a7c {0}\u00a74. +autoAfkKickReason=\u4f60\u56e0\u4e3a\u957f\u65f6\u95f4\u672a\u80fd\u5728\u6e38\u620f\u4e2d\u505a\u51fa\u52a8\u4f5c\u5e76\u8d85\u8fc7 {0} \u5206\u949f\u800c\u88ab\u670d\u52a1\u5668\u8bf7\u51fa\uff01 +backAfterDeath=\u00a76\u4f7f\u7528\u201c/back\u201d\u547d\u4ee4\u6765\u56de\u5230\u6b7b\u4ea1\u5730\u70b9. +backUsageMsg=\u00a76\u6b63\u5728\u56de\u5230\u4e0a\u4e00\u4f4d\u7f6e. +backupDisabled=\u00a74\u5907\u4efd\u914d\u7f6e\u6587\u4ef6\u672a\u88ab\u8bbe\u7f6e. +backupFinished=\u00a76\u5907\u4efd\u5b8c\u6210. +backupStarted=\u00a76\u5907\u4efd\u5f00\u59cb. +balance=\u00a7a\u73b0\u91d1\:\u00a7c{0} +balanceOther=\u00a7a{0}\u7684\u91d1\u94b1\:\u00a7c {1} +balanceTop=\u00a76\u91d1\u94b1\u6392\u884c\:{0} +banExempt=\u00a74\u4f60\u4e0d\u80fd\u5c01\u7981\u90a3\u4e2a\u73a9\u5bb6\u00a7r +banFormat=\u00a74\u5df2\u5c01\u7981\:\n\u00a7r {0} +bed=\u00a7o\u5e8a\u00a7r +bedMissing=\u00a74\u4f60\u7684\u5e8a\u5df2\u4e22\u5931\u6216\u963b\u6321 +bedNull=\u00a7m\u5e8a\u00a7r +bedSet=\u00a76\u5df2\u8bbe\u7f6e\u5e8a\u00a7r +bigTreeFailure=\u00a74\u751f\u6210\u5927\u6811\u5931\u8d25.\u5728\u571f\u5757\u6216\u8349\u5757\u4e0a\u9762\u518d\u8bd5\u4e00\u6b21 +bigTreeSuccess=\u00a76\u5df2\u751f\u6210\u5927\u6811 +blockList=\u00a76Essentials \u63d2\u4ef6\u5c06\u4f20\u9012\u4e0b\u5217\u6307\u4ee4\u7ed9\u53e6\u4e00\u63d2\u4ef6\: +bookAuthorSet=\u00a76\u8fd9\u672c\u4e66\u7684\u4f5c\u8005\u5df2\u88ab\u8bbe\u7f6e\u4e3a {0}. +bookLocked=\u00a76\u8fd9\u672c\u4e66\u5df2\u88ab\u9501\u5b9a. +bookTitleSet=\u00a76\u8fd9\u672c\u4e66\u7684\u6807\u9898\u5df2\u88ab\u8bbe\u7f6e\u4e3a {0}. +broadcast=\u00a7r\u00a76[\u00a74\u516c\u544a\u00a76]\u00a7a {0} +buildAlert=\u00a74\u4f60\u6ca1\u6709\u5efa\u9020\u6743\u9650\! +bukkitFormatChanged=Bukkit\u7248\u672c\u5df2\u6539\u53d8 +burnMsg=\u00a76\u4f60\u4f7f\u73a9\u5bb6 \u00a74{0} \u00a76\u71c3\u70e7\u00a74 {1} \u00a76\u79d2 +canTalkAgain=\u00a76\u4f60\u5df2\u83b7\u5f97\u53d1\u8a00\u7684\u8d44\u683c +cannotStackMob=\u00a74\u60a8\u6ca1\u6709\u6743\u9650\u5806\u53e0\u591a\u4e2a\u5c0f\u602a. +cantFindGeoIpDB=\u627e\u4e0d\u5230GeoIP\u6570\u636e\u5e93\! +cantReadGeoIpDB=GeoIP\u6570\u636e\u5e93\u8bfb\u53d6\u5931\u8d25\! +cantSpawnItem=\u00a74\u4f60\u6ca1\u6709\u6743\u9650\u751f\u6210\u7269\u54c1\u00a7c {0}\u00a74. +chatTypeAdmin=[A] +chatTypeLocal=[L] +chatTypeSpy=[\u76d1\u89c6] +cleaned=\u7528\u6237\u6587\u4ef6\u5df2\u6e05\u7a7a +cleaning=\u6e05\u7a7a\u7528\u6237\u6587\u4ef6... +commandFailed=\u547d\u4ee4 {0} \u5931\u8d25\: +commandHelpFailedForPlugin=\u672a\u80fd\u83b7\u53d6\u6b64\u63d2\u4ef6\u7684\u5e2e\u52a9\:{0} +commandNotLoaded=\u00a74 \u547d\u4ee4{0}\u52a0\u8f7d\u5931\u8d25 +compassBearing=\u00a76\u65b9\u5411\:{0}\uff08{1}\u5ea6\uff09 +configFileMoveError=\u79fb\u52a8config.yml\u6587\u4ef6\u5230\u5907\u4efd\u4f4d\u7f6e\u5931\u8d25 +configFileRenameError=\u91cd\u547d\u540d\u7f13\u5b58\u6587\u4ef6\u4e3aconfig.yml\u5931\u8d25 +connectedPlayers=\u00a76\u76ee\u524d\u5728\u7ebf\: \u00a7r +connectionFailed=\u8fde\u63a5\u5931\u8d25. +cooldownWithMessage=\u00a74\u51b7\u5374\u65f6\u95f4\:{0} +corruptNodeInConfig=\u00a74\u6ce8\u610f\:\u4f60\u7684\u914d\u7f6e\u6587\u4ef6\u5b58\u5728\u4e00\u4e2a\u635f\u574f\u7684 {0} \u8282\u70b9 +couldNotFindTemplate=\u00a74\u65e0\u6cd5\u627e\u5230\u6a21\u7248 {0} +creatingConfigFromTemplate=\u4ece\u6a21\u7248\:{0} \u521b\u5efa\u914d\u7f6e +creatingEmptyConfig=\u521b\u5efa\u7a7a\u7684\u914d\u7f6e\:{0} +creative=\u521b\u9020\u6a21\u5f0f +currency={0}{1} +currentWorld=\u00a76\u5f53\u524d\u4e16\u754c\:\u00a7c {0} +day=\u5929 +days=\u5929 +defaultBanReason=\u767b\u5f55\u5931\u8d25\!\u60a8\u7684\u5e10\u53f7\u5df2\u88ab\u6b64\u670d\u52a1\u5668\u5c01\u7981\! +deleteFileError=\u65e0\u6cd5\u5220\u9664\u6587\u4ef6\:{0} +deleteHome=\u00a76\u5bb6 \u00a7c{0} \u00a76\u88ab\u79fb\u9664 +deleteJail=\u00a76\u76d1\u72f1 \u00a7c{0} \u00a76\u5df2\u88ab\u79fb\u9664 +deleteWarp=\u00a76\u5730\u6807 \u00a7c{0} \u00a76\u5df2\u88ab\u79fb\u9664 +deniedAccessCommand=\u00a7c{0} \u00a74\u88ab\u62d2\u7edd\u4f7f\u7528\u547d\u4ee4 +denyBookEdit=\u00a74\u4f60\u4e0d\u80fd\u89e3\u9501\u8fd9\u672c\u4e66. +denyChangeAuthor=\u00a74\u4f60\u4e0d\u80fd\u6539\u53d8\u8fd9\u672c\u4e66\u7684\u4f5c\u8005. +denyChangeTitle=\u00a74\u4f60\u4e0d\u80fd\u6539\u53d8\u8fd9\u672c\u4e66\u7684\u6807\u9898. +depth=\u00a76\u4f60\u4f4d\u4e8e\u6d77\u5e73\u9762\u5904 +depthAboveSea=\u00a76\u4f60\u4f4d\u4e8e\u6d77\u5e73\u9762\u4e0a\u65b9\u00a7c{0}\u00a76\u683c\u5904 +depthBelowSea=\u00a76\u4f60\u4f4d\u4e8e\u6d77\u5e73\u9762\u4e0b\u65b9\u00a7c{0}\u00a76\u683c\u5904 +destinationNotSet=\u672a\u8bbe\u7f6e\u76ee\u7684\u5730. +disableUnlimited=\u00a76\u53d6\u6d88\u4e86 {1} \u7684\u65e0\u9650\u653e\u7f6e \u00a7c{0} \u00a76\u7684\u80fd\u529b +disabled=\u5173\u95ed +disabledToSpawnMob=\u00a74\u914d\u7f6e\u6587\u4ef6\u4e2d\u5df2\u7981\u6b62\u6b64\u751f\u7269\u7684\u751f\u6210. +distance=\u00a76\u8ddd\u79bb\: {0} +dontMoveMessage=\u00a76\u4f20\u9001\u5c06\u5728\u00a7c{0}\u00a76\u5185\u5f00\u59cb.\u8bf7\u4e0d\u8981\u79fb\u52a8 +downloadingGeoIp=\u4e0b\u8f7d GeoIP \u6570\u636e\u5e93\u4e2d...\u8fd9\u53ef\u80fd\u9700\u8981\u82b1\u8d39\u4e00\u6bb5\u65f6\u95f4 (\u56fd\u5bb6\:0.6 MB, \u57ce\u5e02\: 20 MB) +duplicatedUserdata=\u590d\u5236\u4e86\u73a9\u5bb6\u5b58\u6863\:{0} \u548c {1} +durability=\u00a76\u8fd9\u4e2a\u5de5\u5177\u8fd8\u6709 \u00a74{0}\u00a76 \u6301\u4e45 +editBookContents=\u00a7e\u4f60\u73b0\u5728\u53ef\u4ee5\u7f16\u8f91\u8fd9\u672c\u4e66\u7684\u5185\u5bb9. +enableUnlimited=\u00a76Giving unlimited amount of\u00a7c {0} \u00a76to \u00a7c{1}\u00a76. +enabled=\u5f00\u542f +enchantmentApplied=\u00a76\u9644\u9b54 \u00a7c{0} \u00a76\u5df2\u88ab\u5e94\u7528\u5230\u4f60\u624b\u4e2d\u7684\u5de5\u5177. +enchantmentNotFound=\u00a74\u672a\u627e\u5230\u8be5\u9644\u9b54. +enchantmentPerm=\u00a74\u4f60\u6ca1\u6709\u8fdb\u884c\u00a7c {0} \u00a74\u9644\u9b54\u7684\u6743\u9650. +enchantmentRemoved=\u00a76\u9644\u9b54 \u00a7c{0} \u00a76\u5df2\u4ece\u4f60\u624b\u4e0a\u7684\u5de5\u5177\u79fb\u9664 +enchantments=\u00a76\u9644\u9b54\: \u00a7r{0} +errorCallingCommand=\u9519\u8bef\u7684\u547c\u53eb\u547d\u4ee4\:/{0} +errorWithMessage=\u00a7c\u9519\u8bef\:\u00a74{0} +essentialsHelp1=\u6587\u4ef6\u5df2\u635f\u574f,Essentials\u65e0\u6cd5\u6253\u5f00.Essentials\u73b0\u5728\u5df2\u5173\u95ed.\u5982\u679c\u60a8\u65e0\u6cd5\u81ea\u884c\u4fee\u590d,\u53bb\u7f51\u5740http\://tiny.cc/EssentialsChat +essentialsHelp2=\u6587\u4ef6\u5df2\u635f\u574f,Essentials\u65e0\u6cd5\u6253\u5f00.Essentials\u73b0\u5728\u5df2\u5173\u95ed.\u5982\u679c\u60a8\u65e0\u6cd5\u81ea\u884c\u4fee\u590d,\u53ef\u4ee5\u5c1d\u8bd5\u5728\u6e38\u620f\u5185\u8f93\u5165/essentialshelp\u6216\u8005\u8bbf\u95ee\u7f51\u5740http\://tiny.cc/EssentialsChat +essentialsReload=\u00a76Essentials \u5df2\u91cd\u65b0\u8f7d\u5165\u00a7c {0}. +exp=\u00a74{0} \u00a76\u62e5\u6709\u00a7c {1} \u00a76\u7ecf\u9a8c\u503c (\u7b49\u7ea7\u00a7c {2}\u00a76) \u9700\u8981\u00a7c {3} \u00a76\u7ecf\u9a8c\u624d\u80fd\u5347\u7ea7. +expSet=\u00a76\u4f60\u5c06\u00a7c{0} \u00a76\u7684\u7ecf\u9a8c\u8bbe\u7f6e\u4e3a\u00a7c {1} \u00a76\u7ecf\u9a8c\u503c. +extinguish=\u00a76\u4f60\u7184\u706d\u4e86\u4f60\u81ea\u5df1\u8eab\u4e0a\u7684\u706b +extinguishOthers=\u00a76\u4f60\u7184\u706d\u4e86 {0} \u00a76\u8eab\u4e0a\u7684\u706b +failedToCloseConfig=\u5173\u95ed\u914d\u7f6e {0} \u5931\u8d25 +failedToCreateConfig=\u521b\u5efa\u914d\u7f6e {0} \u5931\u8d25 +failedToWriteConfig=\u5199\u5165\u914d\u7f6e {0} \u5931\u8d25 +false=\u00a74\u5426\u00a7r +feed=\u4f60\u5df2\u7ecf\u9971\u4e86,\u65e0\u6cd5\u518d\u8fdb\u98df. +feedOther=\u00a76You satiated the appetite of \u00a7c{0}\u00a76. +fileRenameError=\u91cd\u547d\u540d\u6587\u4ef6 {0} \u5931\u8d25 +fireworkColor=\u00a74\u4f7f\u7528\u4e86\u65e0\u6548\u7684\u70df\u82b1\u586b\u5145\u53c2\u6570\uff0c\u5fc5\u987b\u9996\u5148\u8bbe\u7f6e\u4e00\u4e2a\u989c\u8272\u3002 +fireworkEffectsCleared=\u00a76\u4ece\u6301\u6709\u7684\u7269\u54c1\u4e2d\u79fb\u9664\u4e86\u6240\u6709\u7279\u6548. +fireworkSyntax=\u00a76\u70df\u82b1\u53c2\u6570\:\u00a7c color\:<\u989c\u8272> [fade\:<\u6de1\u51fa\u989c\u8272>] [shape\:<\u5f62\u6001>] [effect\:<\u7279\u6548>]\n\u00a76\u8981\u4f7f\u7528\u591a\u4e2a\u989c\u8272/\u7279\u6548, \u4f7f\u7528\u9017\u53f7\: \u00a7cred,blue,pink\n\u00a76\u5f62\u72b6\:\u00a7c star, ball, large, creeper, burst \u00a76\u7279\u6548\:\u00a7c trail, twinkle. +flyMode=\u00a76 \u5df2\u8bbe\u7f6e\u4e86\u00a7c{1}\u00a76\u7684\u98de\u884c\u6a21\u5f0f\u4e3a\u00a7c{0}. +flying=\u98de\u884c\u4e2d +foreverAlone=\u00a74\u4f60\u6ca1\u6709\u53ef\u56de\u590d\u7684\u73a9\u5bb6 +fullStack=\u00a74\u4f60\u7684\u7269\u54c1\u5df2\u7ecf\u8fbe\u5230\u6700\u5927\u5806\u53e0. +gameMode=\u00a76\u5df2\u8bbe\u7f6e\u00a7c{1}\u00a76\u7684\u6e38\u620f\u6a21\u5f0f\u4e3a\u00a7c{0}\u00a76. +gcWorld=\u00a76{0} "\u00a7c{1}\u00a76"\: \u00a7c{2}\u00a76 \u533a\u5757, \u00a7c{3}\u00a76 \u5b9e\u4f53, \u00a7c{4}\u00a76 tiles. +gcfree=\u00a76\u7a7a\u95f2\u5185\u5b58\: \u00a7c{0} MB +gcmax=\u00a76\u6700\u5927\u5185\u5b58\: \u00a7c{0} MB. +gctotal=\u00a76\u5df2\u5206\u914d\u5185\u5b58\: \u00a7c{0} MB. +geoIpUrlEmpty=GeoIP\u4e0b\u8f7d\u94fe\u63a5\u4e3a\u7a7a. +geoIpUrlInvalid=GeoIP\u4e0b\u8f7d\u94fe\u63a5\u65e0\u6548. +geoipJoinFormat=\u00a76\u73a9\u5bb6\u00a7c {0} \u00a76\u6765\u81ea\u4e8e \u00a7c{1}\u00a76. +giveSpawn=\u00a76\u7ed9\u4e88\u00a7c {2} \u00a7c {0} \u4e2a\u00a7c {1}\u00a76. +godDisabledFor=\u00a7cdisabled\u00a76 for\u00a7c {0} +godEnabledFor=\u00a74\u5f00\u542f\u4e86\u00a7c {0} \u00a76\u7684\u4e0a\u5e1d\u6a21\u5f0f +godMode=\u00a76\u4e0a\u5e1d\u6a21\u5f0f \u00a7c{0} +groupDoesNotExist=\u00a74\u5f53\u524d\u7ec4\u6ca1\u6709\u4eba\u5728\u7ebf\! +groupNumber=\u00a7c{0}\u00a7f \u5728\u7ebf, \u60f3\u8981\u83b7\u53d6\u5168\u90e8\u4f7f\u7528\:\u00a7c /{1} {2} +hatArmor=\u00a74\u9519\u8bef\:\u4f60\u65e0\u6cd5\u4f7f\u7528\u8fd9\u4e2a\u7269\u54c1\u4f5c\u4e3a\u5e3d\u5b50\! +hatEmpty=\u00a74\u4f60\u73b0\u5728\u8fd8\u6ca1\u6709\u6234\u5e3d\u5b50. +hatFail=\u00a74\u4f60\u5fc5\u987b\u628a\u60f3\u8981\u5e26\u7684\u5e3d\u5b50\u62ff\u5728\u624b\u4e2d. +hatPlaced=\u00a76\u4eab\u53d7\u4f60\u7684\u65b0\u5e3d\u5b50\u628a\! +hatRemoved=\u00a76\u4f60\u7684\u5e3d\u5b50\u5df2\u79fb\u9664. +haveBeenReleased=\u00a76\u4f60\u5df2\u88ab\u91ca\u653e +heal=\u00a76\u4f60\u5df2\u88ab\u6cbb\u7597 +healDead=\u00a74\u4f60\u4e0d\u80fd\u6cbb\u7597\u4e00\u4e2a\u6b7b\u4eba\! +healOther=\u00a76\u5df2\u6cbb\u7597\u00a7c {0}\u00a76. +helpConsole=\u4ece\u63a7\u5236\u53f0\u67e5\u770b\u5e2e\u52a9,\u8bf7\u8f93\u5165\u201c?\u201d +helpFrom=\u00a76\u6765\u81ea\u4e8e {0} \u00a76\u7684\u6307\u4ee4\: +helpLine=\u00a76/{0}\u00a7r\: {1} +helpMatching=\u00a76\u6307\u4ee4\u8fde\u63a5 "\u00a7c{0}\u00a76"\: +helpOp=\u00a74[\u6c42\u52a9OP]\u00a7r \u00a76{0}\:\u00a7r {1} +helpPlugin=\u00a74{0}\u00a7r\: \u63d2\u4ef6\u5e2e\u52a9\: /help {1} +holdBook=\u00a74\u4f60\u9700\u8981\u62ff\u7740\u4e00\u672c\u53ef\u5199\u7684\u4e66. +holdFirework=\u00a74\u4f60\u5fc5\u987b\u62ff\u7740\u70df\u706b\u624d\u80fd\u589e\u52a0\u7279\u6548. +holdPotion=\u00a74\u4f60\u5fc5\u987b\u62ff\u7740\u836f\u6c34\u624d\u80fd\u589e\u52a0\u7279\u6548. +holeInFloor=\u00a74\u76ee\u6807\u811a\u4e0b\u662f\u865a\u7a7a\! +homeSet=\u00a76\u5df2\u8bbe\u7f6e\u5bb6. +homes=\u00a76\u5bb6\:\u00a7r{0} +hour=\u5c0f\u65f6 +hours=\u5c0f\u65f6 +ignoredList=\u00a76\u5df2\u5ffd\u7565\u7684\u73a9\u5bb6\:\u00a7r {0} +ignorePlayer=\u00a76\u4f60\u5c4f\u853d\u4e86\u73a9\u5bb6 \u00a7c{0} +illegalDate=\u9519\u8bef\u7684\u65e5\u671f\u683c\u5f0f +infoChapter=\u00a76\u9009\u62e9\u7ae0\u8282\: +infoChapterPages=\u00a7e ---- \u00a76{0} \u00a7e--\u00a76 \u7b2c\u00a7c{1}\u00a76\u9875\u5171\u00a7c{2}\u00a76\u9875\u00a7e---- +infoPages=\u00a7e----\u7b2c \u00a7c{0}\u00a7e \u9875/\u5171 \u00a7c{1}\u00a7e \u9875---- +infoUnknownChapter=\u00a74\u672a\u77e5\u7ae0\u8282. +insufficientFunds=\u00a74\u53ef\u7528\u8d44\u91d1\u4e0d\u8db3. +invalidCharge=\u00a74\u65e0\u6548\u7684\u4ef7\u683c +invalidFireworkFormat=\u00a74\u8fd9\u4e2a\u9009\u9879 \u00a7c{0} \u00a74\u5bf9 \u00a7c{1}\u00a74 \u4e0d\u662f\u4e00\u4e2a\u6709\u6548\u7684\u503c\u00a74. +invalidHome=\u00a74\u5bb6\u00a7c {0} \u00a74\u4e0d\u5b58\u5728\! +invalidHomeName=\u00a74\u65e0\u6548\u7684\u5bb6\u540d\u79f0\! +invalidMob=\u00a74\u65e0\u6548\u7684\u602a\u7269\u7c7b\u578b. +invalidNumber=\u65e0\u6548\u7684\u6570\u5b57. +invalidPotion=\u00a74\u65e0\u6548\u7684\u836f\u6c34. +invalidPotionMeta=\u00a74\u65e0\u6548\u7684\u836f\u6c34\u6570\u636e\: \u00a7c{0}\u00a74. +invalidSignLine=\u00a74\u724c\u5b50\u4e0a\u7684\u7b2c \u00a7c{0} \u00a74\u884c\u65e0\u6548 +invalidWarpName=\u00a74\u65e0\u6548\u7684\u4f20\u9001\u70b9\u540d\u79f0\! +invalidWorld=\u00a74\u65e0\u6548\u7684\u4e16\u754c\u540d. +is=\u662f +itemCannotBeSold=\u00a74\u8be5\u7269\u54c1\u65e0\u6cd5\u5356\u7ed9\u670d\u52a1\u5668 +itemMustBeStacked=\u00a74\u7269\u54c1\u5fc5\u987b\u6210\u7ec4\u7684\u8fdb\u884c\u4ea4\u6613,2s\u4ee3\u8868\u7684\u6570\u91cf\u662f2\u7ec4\u7269\u54c1,\u4ee5\u6b64\u7c7b\u63a8 +itemNames=\u00a76\u7269\u54c1\u7b80\u6613\u540d\u79f0\:\u00a7r {0} +itemNotEnough1=\u00a74\u4f60\u6ca1\u6709\u8db3\u591f\u7684\u8be5\u7269\u54c1\u6765\u5356\u51fa +itemNotEnough2=\u00a76\u5982\u679c\u4f60\u60f3\u8981\u5356\u6389\u6240\u6709\u4f60\u80cc\u5305\u5185\u7684\u8be5\u7269\u54c1,\u4f7f\u7528\u201c/sell \u7269\u54c1\u540d\u79f0\uff08\u82f1\u6587,\u6216ID\uff09\u201d +itemNotEnough3=\u00a76\u201c/sell \u7269\u54c1\u540d\u79f0 -1\u201d\u5c06\u4f1a\u7559\u51fa\u4e00\u4e2a\u800c\u5356\u6389\u5176\u5b83\u8be5\u79cd\u7269\u54c1,\u4ee5\u6b64\u7c7b\u63a8 +itemSellAir=\u4f60\u96be\u9053\u60f3\u5356\u7a7a\u6c14\u5417\uff1f\u653e\u4e2a\u4e1c\u897f\u5728\u4f60\u624b\u91cc +itemSold=\u00a7a\u83b7\u5f97 \u00a7c {0} \u00a7a \uff08{1} \u5355\u4f4d{2},\u6bcf\u4e2a\u4ef7\u503c {3}\uff09 +itemSoldConsole=\u00a7c{0} \u00a76\u5356\u51fa\u4e86 {1},\u83b7\u5f97\u4e86\u00a76 {2} \u00a76 \uff08{3} \u5355\u4f4d\u7269\u54c1,\u6bcf\u4e2a\u4ef7\u503c {4}\uff09 +itemSpawn=\u00a76\u751f\u6210 {0} \u4e2a {1} +itemType=\u00a76\u7269\u54c1\:\u00a7c {0} \u00a76-\u00a74 {1} +itemsCsvNotLoaded=\u65e0\u6cd5\u52a0\u8f7ditems.csv +jailAlreadyIncarcerated=\u00a74\u5df2\u5728\u76d1\u72f1\u4e2d\u7684\u73a9\u5bb6\:{0} +jailMessage=\u00a74\u8bf7\u5728\u76d1\u72f1\u4e2d\u9762\u58c1\u601d\u8fc7\uff01 +jailNotExist=\u00a74\u8be5\u76d1\u72f1\u4e0d\u5b58\u5728 +jailReleased=\u00a76\u73a9\u5bb6 \u00a7c{0}\u00a76 \u51fa\u72f1\u4e86 +jailReleasedPlayerNotify=\u00a76\u4f60\u5df2\u88ab\u91ca\u653e\uff01 +jailSentenceExtended=\u00a76\u56da\u7981\u65f6\u95f4\u589e\u52a0\u5230\:{0) +jailSet=\u00a76\u76d1\u72f1 {0} \u5df2\u88ab\u8bbe\u7f6e +jumpError=\u00a74\u8fd9\u5c06\u4f1a\u635f\u5bb3\u4f60\u7684\u7535\u8111 +kickDefault=\u4ece\u670d\u52a1\u5668\u8bf7\u51fa +kickExempt=\u00a74\u4f60\u65e0\u6cd5\u8bf7\u51fa\u8be5\u73a9\u5bb6. +kickedAll=\u00a74\u5df2\u5c06\u6240\u6709\u73a9\u5bb6\u8bf7\u51fa\u670d\u52a1\u5668. +kill=\u00a76\u6740\u6b7b\u4e86 \u00a7c{0} +killExempt=\u00a74\u4f60\u4e0d\u80fd\u6740\u6b7b \u00a7c{0}\u00a74. +kitCost=\ \u00a77\u00a7o({0})\u00a7r +kitError2=\u00a74\u8be5\u5de5\u5177\u5305\u53ef\u80fd\u4e0d\u5b58\u5728\u6216\u8005\u88ab\u62d2\u7edd\u4e86.\u8bf7\u8054\u7cfb\u7ba1\u7406\u5458 +kitError=\u00a74\u6ca1\u6709\u65e0\u6548\u7684\u5de5\u5177\u5305 +kitGiveTo=\u00a76Giving kit\u00a7c {0}\u00a76 to \u00a7c{1}\u00a76. +kitInvFull=\u00a74\u4f60\u7684\u80cc\u5305\u5df2\u6ee1,\u5de5\u5177\u5305\u5c06\u653e\u5728\u5730\u4e0a +kitNotFound=\u00a74\u5de5\u5177\u5305\u4e0d\u5b58\u5728. +kitOnce=\u00a74\u4f60\u4e0d\u80fd\u518d\u6b21\u4f7f\u7528\u8be5\u5de5\u5177\u5305. +kitReceive=\u00a76\u6536\u5230\u4e00\u4e2a\u00a7c {0} \u00a76\u5de5\u5177\u5305. +kitTimed=\u00a74\u4f60\u4e0d\u80fd\u518d\u6b21\u5bf9\u5176\u4ed6\u4eba\u4f7f\u7528\u6b64\u5de5\u5177\u5305\u00a7c {0}\u00a74. +kits=\u00a76\u5de5\u5177\u5305\:\u00a7r{0} +leatherSyntax=\u00a76\u76ae\u9769\u989c\u8272\u8bed\u6cd5\: color\:<\u7ea2>,<\u7eff>,<\u84dd> \u4f8b\u5982\: color\:255,0,0. +lightningSmited=\u00a76\u4f60\u521a\u521a\u88ab\u96f7\u51fb\u4e2d\u4e86\! +lightningUse=\u00a76\u96f7\u51fb\u4e2d\u4e86\u00a7c {0} +listAfkTag=\u00a77[\u79bb\u5f00]\u00a7r +listAmount=\u00a76\u5f53\u524d\u6709 \u00a7c{0}\u00a76 \u4e2a\u73a9\u5bb6\u5728\u7ebf,\u6700\u5927\u5728\u7ebf\u4eba\u6570\u4e3a \u00a7c{1}\u00a76 \u4e2a\u73a9\u5bb6. +listAmountHidden=\u00a76\u5f53\u524d\u6709 \u00a7c{0}\u00a76/{1}\u00a76 \u4e2a\u73a9\u5bb6\u5728\u7ebf,\u6700\u5927\u5728\u7ebf\u4eba\u6570 \u00a7c{2}\u00a76 \u4e2a\u73a9\u5bb6 +listGroupTag=\u00a76{0}\u00a7r\: \u00a7r +listHiddenTag=\u00a77[\u9690\u8eab]\u00a7r +loadWarpError=\u00a74\u52a0\u8f7d\u5730\u6807 {0} \u5931\u8d25 +localFormat=[L]<{0}> {1} +mailClear=\u00a76\u82e5\u8981\u6807\u8bb0\u4f60\u7684\u90ae\u4ef6\u4e3a\u5df2\u8bfb,\u8f93\u5165\u00a7c /mail clear\u00a76. +mailCleared=\u00a76\u90ae\u7bb1\u5df2\u6e05\u7a7a\uff01 +mailSent=\u00a76\u90ae\u4ef6\u5df2\u53d1\u51fa\! +markMailAsRead=\u00a76\u82e5\u8981\u6807\u8bb0\u4f60\u7684\u90ae\u4ef6\u4e3a\u5df2\u8bfb,\u8f93\u5165\u00a7c /mail clear\u00a76. +markedAsAway=\u00a76\u4f60\u5df2\u8bbe\u7f6e\u79bb\u5f00. +markedAsNotAway=\u00a76\u4f60\u5df2\u53d6\u6d88\u79bb\u5f00. +matchingIPAddress=\u00a76\u4ee5\u4e0b\u662f\u6765\u81ea\u8be5IP\u5730\u5740\u7684\u73a9\u5bb6\: +maxHomes=\u00a74\u4f60\u65e0\u6cd5\u8bbe\u7f6e\u8d85\u8fc7 {0} \u4e2a\u5bb6. +mayNotJail=\u00a74\u4f60\u65e0\u6cd5\u56da\u7981\u8be5\u73a9\u5bb6 +me=\u6211 +minute=\u5206\u949f +minutes=\u5206\u949f +missingItems=\u00a74You do not have \u00a7c{0}x {1}\u00a74. +mobSpawnError=\u00a74\u66f4\u6539\u5237\u602a\u7b3c\u65f6\u53d1\u751f\u9519\u8bef +mobSpawnLimit=\u751f\u7269\u6570\u91cf\u592a\u591a,\u65e0\u6cd5\u751f\u6210 +mobSpawnTarget=\u00a74\u76ee\u6807\u65b9\u5757\u5fc5\u987b\u662f\u4e00\u4e2a\u5237\u602a\u7b3c +mobsAvailable=\u00a76\u751f\u7269\:\u00a7r {0} +moneyRecievedFrom=\u00a7a\u5df2\u4ece {1} \u63a5\u6536{0} +moneySentTo=\u00a7a{0} \u5df2\u53d1\u9001\u5230 {1} +month=\u6708 +months=\u6708 +moreThanZero=\u00a74\u6570\u91cf\u5fc5\u987b\u5927\u4e8e0 +moveSpeed=\u00a76\u4e3a\u00a7c{2}\u00a76\u8bbe\u7f6e {0} \u00a76\u901f\u5ea6\u4e3a\u00a7c {1} \u00a76. +msgFormat=\u00a76[\u00a7c{0}\u00a76 -> \u00a7c{1}\u00a76] \u00a7r{2} +multipleCharges=\u00a74\u60a8\u4e0d\u80fd\u5bf9\u8fd9\u4e2a\u70df\u82b1\u5e94\u7528\u591a\u79cd\u88c5\u6599. +multiplePotionEffects=\u00a74\u60a8\u4e0d\u80fd\u5bf9\u8fd9\u4e2a\u836f\u6c34\u5e94\u7528\u591a\u79cd\u6548\u679c. +muteExempt=\u00a74\u4f60\u65e0\u6cd5\u7981\u8a00\u8be5\u73a9\u5bb6 +muteNotify=\u00a7c{0} \u00a76\u7981\u8a00\u4e86\u73a9\u5bb6 \u00a7c{1}\u00a76. +mutedPlayer=\u00a76\u73a9\u5bb6\u00a7c {0} \u00a76\u5df2\u88ab\u7981\u8a00. +mutedPlayerFor=\u00a76\u73a9\u5bb6\u00a7c {0} \u00a76\u88ab\u7981\u8a00\u00a7c {1}\u00a76. +mutedUserSpeaks={0} \u60f3\u8981\u8bf4\u8bdd,\u4f46\u88ab\u7981\u8a00\u4e86 +nearbyPlayers=\u00a76\u9644\u8fd1\u7684\u73a9\u5bb6\: \u00a7r{0} +negativeBalanceError=\u00a74\u73b0\u91d1\u4e0d\u53ef\u5c0f\u4e8e\u96f6 +nickChanged=\u00a76\u6635\u79f0\u5df2\u66f4\u6362 +nickDisplayName=\u00a74\u4f60\u9700\u8981\u6fc0\u6d3bchange-displayname.\u8be5\u6587\u4ef6\u5728Essentials\u8bbe\u7f6e\u6587\u4ef6\u4e2d +nickInUse=\u00a74\u90a3\u4e2a\u6635\u79f0\u5df2\u88ab\u4f7f\u7528 +nickNamesAlpha=\u00a74\u6635\u79f0\u5fc5\u987b\u4e3a\u5b57\u6bcd\u6216\u6570\u5b57. +nickNoMore=\u00a76\u4f60\u7684\u6635\u79f0\u5df2\u53d6\u6d88 +nickSet=\u00a76\u4f60\u7684\u6635\u79f0\u73b0\u5728\u662f \u00a7c{0}\u00a76. +nickTooLong=\u00a74\u60a8\u6240\u8f93\u5165\u7684\u6635\u79f0\u8fc7\u957f +noAccessCommand=\u00a74\u4f60\u6ca1\u6709\u4f7f\u7528\u8be5\u547d\u4ee4\u7684\u6743\u9650 +noAccessPermission=\u00a74You do not have permission to access that \u00a7c{0}\u00a74. +noBreakBedrock=\u00a74\u4f60\u4e0d\u80fd\u6467\u6bc1\u57fa\u5ca9\uff01 +noDestroyPermission=\u00a74You do not have permission to destroy that \u00a7c{0}\u00a74. +noDurability=\u00a74\u8fd9\u4e2a\u7269\u54c1\u6ca1\u6709\u8010\u4e45. +noGodWorldWarning=\u00a74\u7981\u6b62\u4f7f\u7528\u4e0a\u5e1d\u6a21\u5f0f. +noHelpFound=\u00a74\u6ca1\u6709\u5339\u914d\u7684\u547d\u4ee4 +noHomeSetPlayer=\u00a76\u8be5\u73a9\u5bb6\u8fd8\u672a\u8bbe\u7f6e\u5bb6 +noIgnored=\u00a76\u4f60\u6ca1\u6709\u5ffd\u7565\u4efb\u4f55\u4eba. +noKitPermission=\u00a74\u4f60\u9700\u8981 \u00a74{0}\u00a74 \u6743\u9650\u6765\u4f7f\u7528\u8be5\u5de5\u5177 +noKits=\u00a76\u8fd8\u6ca1\u6709\u53ef\u83b7\u5f97\u7684\u5de5\u5177 +noMail=\u4f60\u6ca1\u6709\u4efb\u4f55\u90ae\u4ef6 +noMatchingPlayers=\u00a76\u627e\u4e0d\u5230\u5339\u914d\u7684\u73a9\u5bb6. +noMetaFirework=\u00a74\u4f60\u6ca1\u6709\u6743\u9650\u5e94\u7528\u70df\u82b1\u6570\u636e. +noMetaPerm=\u00a74\u4f60\u6ca1\u6709\u6743\u9650\u5e94\u7528 \u00a7c{0}\u00a74 \u7684\u6570\u636e. +noNewMail=\u00a76\u4f60\u6ca1\u6709\u65b0\u7684\u90ae\u4ef6 +noPendingRequest=\u00a74\u4f60\u6ca1\u6709\u5f85\u89e3\u51b3\u7684\u8bf7\u6c42 +noPerm=\u00a74\u4f60\u6ca1\u6709 \u00a7c{0}\u00a74 \u6743\u9650 +noPermToSpawnMob=\u00a74\u4f60\u6ca1\u6709\u751f\u6210\u8be5\u751f\u7269\u7684\u6743\u9650 +noPlacePermission=\u00a74\u4f60\u6ca1\u6709\u5728\u90a3\u4e2a\u724c\u5b50\u65c1\u8fb9\u653e\u65b9\u5757\u7684\u6743\u5229 +noPotionEffectPerm=\u00a74\u4f60\u6ca1\u6709\u6743\u9650\u5e94\u7528\u7279\u6548 \u00a7c{0} \u00a74\u5230\u8fd9\u4e2a\u836f\u6c34. +noPowerTools=\u00a76\u4f60\u6ca1\u6709\u7ed1\u5b9a\u547d\u4ee4 +noWarpsDefined=\u00a74\u6ca1\u6709\u786e\u5b9a\u7684\u5730\u6807 +none=\u65e0 +notAllowedToQuestion=\u00a74\u4f60\u672a\u88ab\u6388\u6743\u4f7f\u7528\u63d0\u95ee\u53d1\u8a00 +notAllowedToShout=\u00a74\u4f60\u672a\u88ab\u6388\u6743\u4f7f\u7528\u558a\u8bdd\u53d1\u8a00 +notEnoughExperience=\u00a74\u4f60\u6ca1\u6709\u8db3\u591f\u7684\u7ecf\u9a8c\u503c +notEnoughMoney=\u00a74\u4f60\u6ca1\u6709\u8db3\u591f\u7684\u8d44\u91d1 +notFlying=\u672a\u98de\u884c +notRecommendedBukkit=\u00a74Bukkit\u7248\u672c\u8fc7\u65e7.\u5efa\u8bae\u66f4\u65b0. +notSupportedYet=\u6682\u4e0d\u652f\u6301 +nothingInHand=\u00a74\u4f60\u6ca1\u6709\u6301\u6709\u4efb\u4f55\u7269\u54c1 +now=\u73b0\u5728 +nuke=\u00a7d\u6838\u6b66\u964d\u843d,\u6ce8\u610f\u9690\u853d\uff01 +numberRequired=\u9700\u8981\u8f93\u5165\u6570\u5b57\uff01 +onlyDayNight=/time \u547d\u4ee4\u53ea\u6709 day/night \u4e24\u4e2a\u9009\u62e9 +onlyPlayerSkulls=\u00a74You can only set the owner of player skulls (\u00a7c397\:3\u00a74). +onlyPlayers=\u00a74Only in-game players can use \u00a7c{0}\u00a74. +onlySunStorm=\u00a74/weather \u547d\u4ee4\u53ea\u6709 sun/storm \u4e24\u4e2a\u9009\u62e9 +orderBalances=\u00a76\u6392\u5e8f {0} \u00a76\u4e2a\u73a9\u5bb6\u7684\u8d44\u91d1\u4e2d,\u8bf7\u7a0d\u5019\u2026\u2026 +oversizedTempban=\u00a74\u4f60\u53ef\u80fd\u6ca1\u6709\u5728\u8fd9\u4e2a\u65f6\u6bb5\u5c01\u7981\u73a9\u5bb6. +pTimeCurrent=\u00a76{0}\u00a7c \u00a76\u7684\u65f6\u95f4\u662f \u00a7c{1} +pTimeCurrentFixed=\u00a7c{0}\u00a76 \u7684\u65f6\u95f4\u88ab\u8fde\u63a5\u5230 \u00a7c{1} +pTimeNormal=\u00a7c{0}\u00a76 \u7684\u65f6\u95f4\u662f\u6b63\u5e38\u7684\u5e76\u4e0e\u670d\u52a1\u5668\u540c\u6b65 +pTimeOthersPermission=\u00a74\u4f60\u672a\u88ab\u6388\u6743\u8bbe\u7f6e\u5176\u4ed6\u73a9\u5bb6\u7684\u65f6\u95f4 +pTimePlayers=\u00a76\u8fd9\u4e9b\u73a9\u5bb6\u6709\u4ed6\u4eec\u81ea\u5df1\u7684\u65f6\u95f4\: +pTimeReset=\u00a76\u8be5\u73a9\u5bb6\u7684\u65f6\u95f4\u88ab\u91cd\u7f6e\:\u00a7c{0} +pTimeSet=\u00a76\u8be5\u73a9\u5bb6\u7684\u65f6\u95f4\u88ab\u8bbe\u5b9a\u4e3a \u00a7c{0}\u00a76 \u5bf9\u8c61\:\u00a7c{1} +pTimeSetFixed=\u00a76\u8be5\u73a9\u5bb6\u65f6\u95f4\u88ab\u8fde\u63a5\u5230 \u00a7c{0}\u00a76 \u5bf9\u8c61\:\u00a7c{1} +pWeatherCurrent=\u00a7c{0}\u00a76\u7684\u5929\u6c14\u662f\u00a7c {1}\u00a76. +pWeatherInvalidAlias=\u00a74\u9519\u8bef\u7684\u5929\u6c14\u7c7b\u578b +pWeatherNormal=\u00a7c{0}\u00a76\u7684\u5929\u6c14\u662f\u6b63\u5e38\u7684. +pWeatherOthersPermission=\u00a74\u60a8\u6ca1\u6709\u88ab\u6388\u6743\u8bbe\u7f6e\u5176\u4ed6\u73a9\u5bb6\u7684\u5929\u6c14. +pWeatherPlayers=\u00a76\u8fd9\u4e9b\u73a9\u5bb6\u90fd\u6709\u81ea\u5df1\u7684\u5929\u6c14\:\u00a7r +pWeatherReset=\u00a76\u73a9\u5bb6\u7684\u5929\u6c14\u88ab\u91cd\u7f6e\: \u00a7c{0} +pWeatherSet=\u00a76\u73a9\u5bb6\u00a7c{1}\u00a76\u7684\u5929\u6c14\u88ab\u8bbe\u7f6e\u4e3a \u00a7c{0}\u00a76 . +pendingTeleportCancelled=\u00a74\u5f85\u5904\u7406\u7684\u4f20\u9001\u8bf7\u6c42\u5df2\u53d6\u6d88 +playerBanIpAddress=\u00a76Player\u00a7c {0} \u00a76banned IP address\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerBanned=\u00a76Player\u00a7c {0} \u00a76banned\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerInJail=\u00a74\u8be5\u73a9\u5bb6\u5df2\u5728\u76d1\u72f1\u00a7c {0}\u00a74\u4e2d\u4e86. +playerJailed=\u00a76\u73a9\u5bb6 \u00a7c{0} \u00a76\u88ab\u902e\u6355\u4e86 +playerJailedFor=\u00a76\u73a9\u5bb6 \u00a7c{0} \u00a76\u88ab\u902e\u6355,\u65f6\u95f4\:{1} +playerKicked=\u00a74\u7ba1\u7406\u5458 \u00a7c{0} \u00a76\u8bf7\u51fa\u4e86 \u00a7c{1},\u00a76\u7406\u7531\:{2} +playerMuted=\u00a76\u4f60\u88ab\u7981\u6b62\u53d1\u8a00 +playerMutedFor=\u00a76\u4f60\u5df2\u88ab\u7981\u8a00.\u7406\u7531\: {0} +playerNeverOnServer=\u00a74\u73a9\u5bb6 \u00a7c{0} \u00a74\u4ece\u6ca1\u51fa\u73b0\u5728\u670d\u52a1\u5668\u8fc7 +playerNotFound=\u00a74\u73a9\u5bb6\u672a\u5728\u7ebf\uff08\u6216\u4e0d\u5b58\u5728\uff09 +playerUnbanIpAddress=\u00a76\u5df2\u89e3\u9664\u7528\u6237\u00a7c {0} \u00a76\u7684\u5c01\u7981IP\: {1}. +playerUnbanned=\u00a76\u7ba1\u7406\u5458\u00a7c {0} \u00a76\u89e3\u5c01\u4e86\u00a7c {1}. +playerUnmuted=\u00a76\u4f60\u88ab\u5141\u8bb8\u53d1\u8a00 +pong=\u556a\uff01 +posPitch=\u00a76\u4ef0\u89d2\: {0} (\u5934\u90e8\u7684\u89d2\u5ea6) +posX=\u00a76X\u5750\u6807\: {0} (+\u4e1c <-> -\u897f) +posY=\u00a76Y\u5750\u6807\: {0} (+\u4e0a <-> -\u4e0b) +posYaw=\u00a76\u89d2\u5ea6\: {0} (\u65cb\u8f6c) +posZ=\u00a76Z\u5750\u6807\: {0} (+\u5357 <-> -\u5317) +possibleWorlds=\u00a76Possible worlds are the numbers \u00a7c0\u00a76 through \u00a7c{0}\u00a76. +potions=\u00a76\u836f\u6c34\:\u00a7r {0}\u00a76. +powerToolAir=\u00a74\u547d\u4ee4\u4e0d\u80fd\u5bf9\u7740\u7a7a\u6c14\u4f7f\u7528. +powerToolAlreadySet=\u00a74Command \u00a7c{0}\u00a74 is already assigned to \u00a7c{1}\u00a74. +powerToolAttach=\u00a7c{0}\u00a76 \u547d\u4ee4\u88ab\u7ed1\u5b9a\u5230 {1} +powerToolClearAll=\u00a76\u6240\u6709\u5feb\u6377\u547d\u4ee4\u5df2\u88ab\u6e05\u9664 +powerToolList=\u00a76\u7269\u54c1\u00a7c{1} \u00a76\u6709\u5982\u4e0b\u547d\u4ee4\:\u00a7c{0}\u00a76. +powerToolListEmpty=\u00a74\u7269\u54c1\u00a7c{0} \u00a74\u6ca1\u6709\u88ab\u7ed1\u5b9a\u547d\u4ee4. +powerToolNoSuchCommandAssigned=\u00a74Command \u00a7c{0}\u00a74 has not been assigned to \u00a7c{1}\u00a74. +powerToolRemove=\u00a76Command \u00a7c{0}\u00a76 removed from \u00a7c{1}\u00a76. +powerToolRemoveAll=\u00a76All commands removed from \u00a7c{0}\u00a76. +powerToolsDisabled=\u00a76\u4f60\u6240\u6709\u7684\u5feb\u6377\u547d\u4ee4\u5df2\u88ab\u51bb\u7ed3. +powerToolsEnabled=\u00a76\u4f60\u6240\u6709\u7684\u5feb\u6377\u547d\u4ee4\u5df2\u88ab\u6fc0\u6d3b. +questionFormat=\u00a72[\u63d0\u95ee]\u00a7r {0} +readNextPage=\u00a76\u8f93\u5165 \u00a7c/{0} {1} \u00a76\u6765\u9605\u8bfb\u4e0b\u4e00\u9875 +recipe=\u00a76Recipe for \u00a7c{0}\u00a76 (\u00a7c{1}\u00a76 of \u00a7c{2}\u00a76) +recipeBadIndex=\u8fd9\u4e2a\u7f16\u53f7\u6ca1\u6709\u5339\u914d\u7684\u5408\u6210\u516c\u5f0f. +recipeFurnace=\u00a76Smelt\: \u00a7c{0}\u00a76. +recipeGrid=\u00a7c{0}X \u00a76| \u00a7{1}X \u00a76| \u00a7{2}X +recipeGridItem=\u00a7c{0}X \u00a76is \u00a7c{1} +recipeMore=\u00a76\u8f93\u5165 /{0} \u00a7c{1}\u00a76 <\u6570\u5b57> \u53bb\u67e5\u770b\u66f4\u591a\u7684 \u00a7c{2}\u00a76\u5408\u6210\u516c\u5f0f. +recipeNone=\u5bf9{0}\u6ca1\u6709\u5339\u914d\u7684\u5408\u6210\u516c\u5f0f +recipeNothing=\u6ca1\u6709\u4e1c\u897f +recipeShapeless=\u00a76\u7ed3\u5408 \u00a7c{0} +recipeWhere=\u00a76\u5f53\: {0} +removed=\u00a76\u79fb\u9664\u4e86\u00a7c {0} \u00a76\u5b9e\u4f53. +repair=\u00a76\u4f60\u5df2\u7ecf\u6210\u529f\u7684\u4fee\u590d\u4e86\u4f60\u7684\:\u00a7c{0}\u00a76. +repairAlreadyFixed=\u00a74\u8be5\u7269\u54c1\u65e0\u9700\u4fee\u590d +repairEnchanted=\u00a74\u4f60\u65e0\u6743\u4fee\u590d\u9644\u9b54\u7269\u54c1 +repairInvalidType=\u00a74\u8be5\u7269\u54c1\u65e0\u6cd5\u4fee\u590d +repairNone=\u00a74\u6ca1\u6709\u9700\u8981\u4fee\u7406\u7684\u7269\u54c1. +requestAccepted=\u00a76\u5df2\u63a5\u53d7\u4f20\u9001\u8bf7\u6c42 +requestAcceptedFrom=\u00a7c{0}\u00a76 \u63a5\u53d7\u4e86\u4f60\u7684\u4f20\u9001\u8bf7\u6c42 +requestDenied=\u00a76\u5df2\u62d2\u7edd\u4f20\u9001\u8bf7\u6c42 +requestDeniedFrom=\u00a7c{0}\u00a76 \u62d2\u7edd\u4e86\u4f60\u7684\u4f20\u9001\u8bf7\u6c42 +requestSent=\u00a76\u8bf7\u6c42\u5df2\u53d1\u9001\u7ed9 {0}\u00a76 +requestTimedOut=\u00a74\u4f20\u9001\u8bf7\u6c42\u8d85\u65f6\u2026\u2026 +requiredBukkit=\u00a76* \! * \u4f60\u81f3\u5c11\u9700\u8981\u7248\u672c {0} \u4ee5\u4e0a\u7684CraftBukkit.\u8bf7\u81f3\u5b98\u7f51\u4e0b\u8f7dhttp\://dl.bukkit.org/downloads/craftbukkit/ +resetBal=\u00a76\u6240\u6709\u5728\u7ebf\u73a9\u5bb6\u7684\u91d1\u94b1\u5df2\u91cd\u7f6e\u4e3a \u00a7c{0} \u00a76. +resetBalAll=\u00a76\u6240\u6709\u73a9\u5bb6\u7684\u91d1\u94b1\u5df2\u91cd\u7f6e\u4e3a \u00a7c{0} \u00a76. +returnPlayerToJailError=\u00a74\u5c06\u73a9\u5bb6\u00a7c {0}\u00a74\u5173\u56de\u76d1\u72f1\u00a7c{1}\u00a74\u65f6\u53d1\u751f\u9519\u8bef\! +runningPlayerMatch=\u00a76\u6b63\u5728\u641c\u7d22\u5339\u914dIP\u5730\u5740 ''\u00a7c{0}\u00a76'' \u7684\u73a9\u5bb6(\u8fd9\u53ef\u80fd\u4f1a\u82b1\u8d39\u4e00\u4e9b\u65f6\u95f4) +second=\u79d2 +seconds=\u79d2 +seenOffline=\u00a76Player\u00a7c {0} \u00a76has been \u00a74offline\u00a76 since \u00a7c{1}\u00a76. +seenOnline=\u00a76Player\u00a7c {0} \u00a76has been \u00a7aonline\u00a76 since \u00a7c{1}\u00a76. +serverFull=\u670d\u52a1\u5668\u5df2\u6ee1 +serverTotal=\u00a76\u670d\u52a1\u5668\u603b\u548c\: {0} +setBal=\u00a7a\u4f60\u7684\u91d1\u94b1\u5df2\u88ab\u8bbe\u7f6e\u4e3a {0}. +setBalOthers=\u00a7a\u6210\u529f\u8bbe\u7f6e {0} \u7684\u91d1\u94b1\u4e3a {1}. +setSpawner=\u00a76\u5df2\u4fee\u6539\u5237\u602a\u7bb1\u7c7b\u522b\u4e3a\u00a7c {0}\u00a76. +sheepMalformedColor=\u00a74\u65e0\u6548\u7684\u989c\u8272 +shoutFormat=\u00a76[\u558a\u8bdd]\u00a7r {0} +signFormatFail=\u00a74[{0}] +signFormatSuccess=\u00a71[{0}] +signFormatTemplate=[{0}] +signProtectInvalidLocation=\u00a74\u4f60\u4e0d\u5141\u8bb8\u5728\u6b64\u653e\u7f6e\u724c\u5b50 +similarWarpExist=\u00a74\u4e00\u4e2a\u540c\u540d\u7684\u5730\u6807\u5df2\u5b58\u5728 +slimeMalformedSize=\u00a74\u5927\u5c0f\u975e\u6cd5 +socialSpy=\u00a76SocialSpy for \u00a7c{0}\u00a76\: \u00a7c{1} +soloMob=\u00a74\u8be5\u751f\u7269\u559c\u6b22\u72ec\u5c45 +spawnSet=\u00a76\u5df2\u4e3a\u00a7c {0}\u00a76 \u7ec4\u8bbe\u7f6e\u51fa\u751f\u70b9. +spawned=\u5df2\u751f\u6210 +sudoExempt=\u00a74\u65e0\u6cd5\u5f3a\u5236\u4f7f\u6b64\u73a9\u5bb6\u6267\u884c\u547d\u4ee4 +sudoRun=\u00a76Forcing\u00a7c {0} \u00a76to run\:\u00a7r /{1} +suicideMessage=\u00a76\u6c38\u522b\u4e86,\u6b8b\u9177\u7684\u4e16\u754c\u2026\u2026 +suicideSuccess=\u00a76{0} \u00a76\u7ed3\u675f\u4e86\u4ed6\u81ea\u5df1\u7684\u751f\u547d. +survival=\u751f\u5b58\u6a21\u5f0f +takenFromAccount=\u00a7a\u4ece\u4f60\u7684\u8d26\u6237\u4e2d\u6263\u9664\u4e86 {0} +takenFromOthersAccount=\u00a7a\u4ece {1} \u00a7a\u4e2d\u7684\u8d26\u6237\u6263\u9664\u4e86 {0}.\u76ee\u524d\u91d1\u94b1\: {2} +teleportAAll=\u00a76\u5411\u6240\u6709\u73a9\u5bb6\u53d1\u9001\u4e86\u4f20\u9001\u8bf7\u6c42\u2026\u2026 +teleportAll=\u00a76\u4f20\u9001\u4e86\u6240\u6709\u73a9\u5bb6\u2026\u2026 +teleportAtoB=\u00a7c{0}\u00a76 teleported you to \u00a7c{1}\u00a76. +teleportDisabled=\u00a7c{0}\u00a74 \u53d6\u6d88\u4e86\u4f20\u9001 +teleportHereRequest=\u00a7c{0}\u00a74 \u8bf7\u6c42\u4f60\u4f20\u9001\u5230\u4ed6\u90a3\u91cc +teleportNewPlayerError=\u00a74\u4f20\u9001\u65b0\u73a9\u5bb6\u5931\u8d25 +teleportRequest=\u00a7c{0}\u00a76 \u8bf7\u6c42\u4f20\u9001\u5230\u4f60\u8fd9\u91cc +teleportRequestTimeoutInfo=\u00a76\u6b64\u8bf7\u6c42\u5c06\u5728 {0} \u79d2\u540e\u81ea\u52a8\u53d6\u6d88. +teleportTop=\u00a76\u4f20\u9001\u5230\u9876\u90e8 +teleportationCommencing=\u00a76\u51c6\u5907\u4f20\u9001... +teleportationDisabled=\u00a76Teleportation \u00a7cdisabled\u00a76. +teleportationDisabledFor=\u00a76Teleportation \u00a7cdisabled \u00a76for \u00a7c{0}\u00a76. +teleportationEnabled=\u00a76Teleportation \u00a7cenabled\u00a76. +teleportationEnabledFor=\u00a76Teleportation \u00a7cenabled \u00a76for \u00a7c{0}\u00a76. +teleporting=\u00a76\u6b63\u5728\u4f20\u9001... +teleportToPlayer=\u00a76\u6b63\u5728\u4f20\u9001\u81f3 \u00a7c{0}\u00a76. +tempBanned=\u00a7cYou have been temporarily banned for {0}\:\n\u00a7r{2} +tempbanExempt=\u00a74\u4f60\u65e0\u6cd5\u4e34\u65f6\u5c01\u7981\u6389\u8be5\u73a9\u5bb6. +thunder=\u00a76\u4f60 \u00a7c{0} \u00a76\u4e86\u4f60\u7684\u4e16\u754c\u7684\u95ea\u7535 +thunderDuration=\u00a76\u4f60 \u00a7c{0} \u00a76\u4e86\u4f60\u7684\u4e16\u754c\u7684\u95ea\u7535\u00a7c {1} \u00a76\u79d2 +timeBeforeHeal=\u00a76\u6cbb\u7597\u51b7\u5374\:{0} +timeBeforeTeleport=\u00a74\u4f20\u9001\u51b7\u5374\:{0}\u00a76. +timeFormat=\u00a7c{0}\u00a76 \u6216 \u00a7c{1}\u00a76 \u6216 \u00a7c{2}\u00a76 +timeSetPermission=\u00a74\u4f60\u6ca1\u6709\u8bbe\u7f6e\u65f6\u95f4\u7684\u6743\u9650 +timeWorldCurrent=\u00a76\u76ee\u524d\u4e16\u754c\u00a7c {0} \u00a76\u7684\u65f6\u95f4\u662f \u00a7c{1}\u00a76. +timeWorldSet=\u00a76\u65f6\u95f4\u88ab\u8bbe\u7f6e\u4e3a\u00a7c{0} \u00a76\u4e8e\u4e16\u754c\:\u00a7c{1}\u00a76. +totalWorthAll=\u00a7a\u51fa\u552e\u7684\u6240\u6709\u7269\u54c1\u548c\u65b9\u5757,\u603b\u4ef7\u503c {1}\u00a7a. +totalWorthBlocks=\u00a7a\u51fa\u552e\u7684\u6240\u6709\u65b9\u5757\u5757,\u603b\u4ef7\u503c {1}\u00a7a. +tps=\u00a76\u5f53\u524d TPS \= {0} +tradeSignEmpty=\u00a74\u4ea4\u6613\u724c\u4e0a\u6ca1\u6709\u4f60\u53ef\u83b7\u5f97\u7684\u4e1c\u897f +tradeSignEmptyOwner=\u00a74\u4ea4\u6613\u724c\u4e0a\u6ca1\u6709\u4f60\u53ef\u6536\u96c6\u7684\u4e1c\u897f +treeFailure=\u00a74\u751f\u6210\u6811\u6728\u5931\u8d25,\u5728\u8349\u5757\u4e0a\u6216\u571f\u4e0a\u518d\u8bd5\u4e00\u6b21 +treeSpawned=\u00a76\u751f\u6210\u6811\u6728\u6210\u529f +true=\u00a7a\u662f\u00a7r +typeTpaccept=\u00a76\u82e5\u60f3\u63a5\u53d7\u4f20\u9001,\u8f93\u5165 \u00a74/tpaccept\u00a76. +typeTpdeny=\u00a76\u82e5\u60f3\u62d2\u7edd\u4f20\u9001,\u8f93\u5165 \u00a74/tpdeny\u00a76 +typeWorldName=\u00a76\u4f60\u4e5f\u53ef\u4ee5\u8f93\u5165\u6307\u5b9a\u7684\u4e16\u754c\u7684\u540d\u5b57 +unableToSpawnMob=\u00a74\u751f\u6210\u751f\u7269\u5931\u8d25 +unignorePlayer=\u00a76\u4f60\u5df2\u4e0d\u518d\u5c4f\u853d\u73a9\u5bb6 {0} +unknownItemId=\u00a74\u672a\u77e5\u7684\u7269\u54c1ID\:\u00a7r {0}\u00a74. +unknownItemInList=\u00a74\u672a\u77e5\u7684\u7269\u54c1 {0} \u4e8e {1} \u5217\u8868 +unknownItemName=\u00a74\u672a\u77e5\u7684\u7269\u54c1\u540d\u79f0\:{0} +unlimitedItemPermission=\u00a74No permission for unlimited item \u00a7c{0}\u00a74. +unlimitedItems=\u00a76\u65e0\u9650\u7269\u54c1\:\u00a7r +unmutedPlayer=\u00a76\u73a9\u5bb6 \u00a7c{0}\u00a76 \u88ab\u5141\u8bb8\u53d1\u8a00 +unvanishedReload=\u00a74\u63d2\u4ef6\u91cd\u8f7d\u8feb\u4f7f\u4f60\u7684\u9690\u8eab\u6a21\u5f0f\u5931\u6548. +upgradingFilesError=\u5347\u7ea7\u6587\u4ef6\u65f6\u53d1\u751f\u9519\u8bef +uptime=\u00a76\u8fd0\u884c\u65f6\u95f4\:\u00a7c {0} +userAFK=\u00a77{0} \u00a75\u73b0\u5728\u5904\u4e8e\u79bb\u5f00\u72b6\u6001, \u53ef\u80fd\u6682\u65f6\u6ca1\u529e\u6cd5\u56de\u5e94. +userDoesNotExist=\u00a74\u73a9\u5bb6 \u00a7c{0} \u00a74\u4e0d\u5b58\u5728. +userIsAway=\u00a77*{0} \u00a77\u6682\u65f6\u79bb\u5f00\u4e86. +userIsNotAway=\u00a77*{0} \u00a77\u56de\u6765\u4e86. +userJailed=\u00a76\u4f60\u5df2\u88ab\u76d1\u7981 +userUnknown=\u00a74\u8b66\u544a\: \u8fd9\u4e2a\u73a9\u5bb6 ''\u00a7c{0}\u00a74'' \u4ece\u6765\u6ca1\u6709\u52a0\u5165\u8fc7\u670d\u52a1\u5668. +userdataMoveBackError=\u79fb\u52a8 userdata/{0}.tmp \u5230 userdata/{1} \u5931\u8d25 +userdataMoveError=\u79fb\u52a8 userdata/{0} \u5230 userdata/{1}.tmp \u5931\u8d25 +usingTempFolderForTesting=\u4f7f\u7528\u7f13\u5b58\u6587\u4ef6\u5939\u6765\u6d4b\u8bd5\: +vanished=\u00a76\u5df2\u8fdb\u5165\u9690\u8eab\u6a21\u5f0f,\u73a9\u5bb6\u5c06\u65e0\u6cd5\u770b\u5230\u4f60. +versionMismatch=\u00a74\u7248\u672c\u4e0d\u5339\u914d\uff01\u8bf7\u5347\u7ea7 {0} \u5230\u76f8\u540c\u7248\u672c. +versionMismatchAll=\u00a74\u7248\u672c\u4e0d\u5339\u914d\uff01\u8bf7\u5347\u7ea7\u6240\u6709Essentials\u7cfb\u5217\u7684\u63d2\u4ef6\u5230\u76f8\u540c\u7248\u672c. +voiceSilenced=\u00a76\u4f60\u5df2\u88ab\u9759\u97f3 +walking=\u884c\u8d70\u4e2d +warpDeleteError=\u00a74\u5220\u9664\u5730\u6807\u6587\u4ef6\u65f6\u53d1\u751f\u9519\u8bef. +warpList={0} +warpListPermission=\u00a74\u4f60\u6ca1\u6709\u5217\u51fa\u5730\u6807\u7684\u6743\u9650. +warpNotExist=\u00a74\u8be5\u5730\u6807\u4e0d\u5b58\u5728 +warpOverwrite=\u00a74\u4f60\u4e0d\u80fd\u91cd\u7f6e\u8be5\u5730\u6807 +warpSet=\u00a76\u5730\u6807 \u00a7c{0} \u00a76\u5df2\u8bbe\u7f6e +warpUsePermission=\u00a74\u4f60\u6ca1\u6709\u4f7f\u7528\u8be5\u5730\u6807\u7684\u6743\u9650 +warpingTo=\u00a76\u4f20\u9001\u5230\u5730\u6807 \u00a7c{0}*\u00a76. +warps=\u00a76\u5730\u6807\: \u00a7r{0} +warpsCount=\u00a76There are\u00a7c {0} \u00a76warps. Showing page \u00a7c{1} \u00a76of \u00a7c{2}\u00a76. +weatherStorm=\u00a76\u4f60\u5c06 {0} \u7684\u5929\u6c14\u6539\u4e3a\u96e8\u96ea +weatherStormFor=\u00a76\u4f60\u5c06 {0} \u7684\u5929\u6c14\u7684\u6539\u4e3a\u96e8\u96ea,\u6301\u7eed {1} \u79d2 +weatherSun=\u00a76\u4f60\u5c06 {0} \u7684\u5929\u6c14\u6539\u4e3a\u6674\u5929 +weatherSunFor=\u00a76\u4f60\u5c06 {0} \u7684\u5929\u6c14\u7684\u6539\u4e3a\u6674\u5929,\u6301\u7eed {1} \u79d2 +whoisAFK=\u00a76 - \u6682\u79bb\:\u00a7r {0} +whoisBanned=\u00a76 - \u5c01\u7981\:\u00a7r {0} +whoisExp=\u00a76 - \u7ecf\u9a8c\:\u00a7r {0} (\u7b49\u7ea7 {1}) +whoisFly=\u00a76 - \u98de\u884c\u6a21\u5f0f\:\u00a7r {0} ({1}) +whoisGamemode=\u00a76 - \u6e38\u620f\u6a21\u5f0f\:\u00a7r {0} +whoisGeoLocation=\u00a76 - \u5730\u7406\u4f4d\u7f6e\:\u00a7r {0} +whoisGod=\u00a76 - \u4e0a\u5e1d\u6a21\u5f0f\:\u00a7r {0} +whoisHealth=\u00a76 - \u751f\u547d\:\u00a7r {0}/20 +whoisIPAddress=\u00a76 - IP\u5730\u5740\:\u00a7r {0} +whoisJail=\u00a76 - \u76d1\u72f1\:\u00a7r {0} +whoisLocation=\u00a76 - \u5750\u6807\:\u00a7r ({0}, {1}, {2}, {3}) +whoisMoney=\u00a76 - \u73b0\u91d1\:\u00a7r {0} +whoisMuted=\u00a76 - \u7981\u8a00\:\u00a7r {0} +whoisNick=\u00a76 - \u6635\u79f0\:\u00a7r {0} +whoisOp=\u00a76 - \u7ba1\u7406\u5458\:\u00a7r {0} +whoisTop=\u00a76 \=\=\=\=\=\= \u00a7c {0} \u00a76\u7684\u8d44\u6599\=\=\=\=\=\= +worth=\u00a76\u4e00\u7ec4 {0} \u4ef7\u503c \u00a74{1}\u00a76\uff08{2} \u5355\u4f4d\u7269\u54c1,\u6bcf\u4e2a\u4ef7\u503c {3}\uff09 +worthMeta=\u00a7a\u4e00\u7ec4\u526f\u7801\u4e3a {1} \u7684 {0} \u4ef7\u503c \u00a7c{2}\u00a76\uff08{3} \u5355\u4f4d\u7269\u54c1,\u6bcf\u4e2a\u4ef7\u503c {4}\uff09 +worthSet=\u00a76\u4ef7\u683c\u5df2\u8bbe\u7f6e +year=\u5e74 +years=\u5e74 +youAreHealed=\u00a76\u4f60\u5df2\u88ab\u6cbb\u7597 +youHaveNewMail=\u00a76\u4f60\u62e5\u6709 \u00a7c{0}\u00a76 \u6761\u6d88\u606f\uff01\u00a7r\u8f93\u5165 \u00a7c/mail read\u00a76 \u6765\u67e5\u770b +whoisHunger=\u00a76 - \u9965\u997f\:\u00a7r {0}/20 (+{1} \u9971\u98df\u5ea6) +kitDelay=\u00a7m{0}\u00a7r +giveSpawnFailure=\u00a74\u7a7a\u95f4\u4e0d\u8db3, \u00a7c{0} \u00a7c{1} \u00a74\u5df2\u4e22\u5931. +noKitGroup=\u00a74\u4f60\u6ca1\u6709\u4f7f\u7528\u8fd9\u4e2a\u5de5\u5177\u5305\u7684\u6743\u9650. +inventoryClearingFromAll=\u00a76\u6e05\u7a7a\u6240\u6709\u73a9\u5bb6\u80cc\u5305\u4e2d... +inventoryClearingAllItems=\u00a76\u5df2\u6e05\u7a7a\u6240\u6709\u80cc\u5305\u7269\u54c1\u81ea {0}\u00a76. +inventoryClearingAllArmor=\u00a76\u5df2\u6e05\u7a7a\u6240\u6709\u80cc\u5305\u7269\u54c1\u548c\u88c5\u5907\u81ea {0}\u00a76.\u00a0 +inventoryClearingAllStack=\u00a76\u6e05\u7a7a\u6240\u6709\u00a7c {0} \u00a76\u81ea {1}\u00a76. +inventoryClearingStack=\u00a76\u79fb\u9664\u00a7c {0} \u00a76\u4e2a\u00a7c {1} \u00a76\u81ea {2}\u00a76. +inventoryClearFail=\u00a74\u73a9\u5bb6 {0} \u00a74\u6ca1\u6709\u00a7c {1} \u00a74\u4e2a\u00a7c {2}\u00a74. +localNoOne= +totalSellableAll=\u00a7a\u6240\u6709\u53ef\u5356\u51fa\u7684\u7269\u54c1\u548c\u65b9\u5757\u7684\u603b\u4ef7\u503c\u4e3a\u00a7c{1}\u00a7a. +totalSellableBlocks=\u00a7a\u6240\u6709\u53ef\u5356\u51fa\u7684\u65b9\u5757\u7684\u603b\u4ef7\u503c\u4e3a\u00a7c{1}\u00a7a. +radiusTooBig=\u00a74\u534a\u5f84\u8fc7\u5927\!\u6700\u5927\u534a\u5f84\u4e3a{0}. +isIpBanned=\u00a76IP\u5730\u5740 \u00a7c{0} \u00a76\u5df2\u88ab\u5c01\u7981. +mobDataList=\u00a76\u65e0\u6548\u7684\u602a\u7269\u6570\u636e\:\u00a7r {0} +vanish=\u00a76\u5df2\u8bbe\u7f6e {0}\u00a76\u7684\u9690\u8eab\u6a21\u5f0f\u4e3a\: {1} +noLocationFound=\u00a74\u672a\u627e\u5230\u6709\u6548\u7684\u4f4d\u7f6e. +coordsKeyword={0}, {1}, {2} +banExemptOffline=\u00a74\u4f60\u53ef\u80fd\u65e0\u6cd5\u5c01\u7981\u5df2\u79bb\u7ebf\u73a9\u5bb6. +tempbanExemptOffline=\u00a74\u4f60\u53ef\u80fd\u65e0\u6cd5\u4e34\u65f6\u5c01\u7981\u5df2\u79bb\u7ebf\u73a9\u5bb6. +mayNotJailOffline=\u00a74\u4f60\u53ef\u80fd\u65e0\u6cd5\u76d1\u7981\u5df2\u79bb\u7ebf\u73a9\u5bb6. +muteExemptOffline=\u00a74\u4f60\u53ef\u80fd\u65e0\u6cd5\u7981\u8a00\u5df2\u79bb\u7ebf\u73a9\u5bb6. +ignoreExempt=\u00a74\u4f60\u65e0\u6cd5\u5ffd\u7565\u90a3\u4e2a\u73a9\u5bb6. +unsafeTeleportDestination=\u00a74The teleport destination is unsafe and teleport-safety is disabled. +noMetaJson=JSON Metadata is not supported in this version of Bukkit. +maxMoney=\u00a74This transaction would exceed the balance limit for this account. +skullChanged=\u00a76Skull changed to \u00a7c{0}\u00a76. +alphaNames=\u00a74\u73a9\u5bb6\u540d\u79f0\u53ea\u80fd\u5305\u542b\u5b57\u6bcd,\u6570\u5b57\u548c\u4e0b\u5212\u7ebf. +givenSkull=\u00a76You have been given the skull of \u00a7c{0}\u00a76. +noPermissionSkull=\u00a74You do not have permission to modify that skull. +teleportInvalidLocation=Value of coordinates cannot be over 30000000 +invalidSkull=\u00a74\u8bf7\u62ff\u7740\u4e00\u4e2a\u73a9\u5bb6\u5934\u9885. +weatherInvalidWorld=\u65e0\u6cd5\u627e\u5230\u4e16\u754c {0} \! +gameModeInvalid=\u00a74You need to specify a valid player/mode. +mailTooLong=\u00a74Mail message too long. Try to keep it below 1000 characters. +mailDelay=Too many mails have been sent within the last minute. Maximum\: {0} +seenAccounts=\u00a76Player has also been known as\:\u00a7c {0} +unableToSpawnItem=\u00a74\u65e0\u6cd5\u751f\u6210\u7269\u54c1 \u00a7c{0}\u00a74, \u8fd9\u662f\u4e00\u4e2a\u4e0d\u53ef\u751f\u6210\u7684\u7269\u54c1. +itemsConverted=\u00a76Converted all items into blocks. +itemsNotConverted=\u00a74You have no items that can be converted into blocks. +mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\: +mailMessage={0} + +whoisTempBanned=\u00a76 - Ban expires:\u00a7r {0} +playerTempBanned=\u00a76Player \u00a7c{0}\u00a76 temporarily banned \u00a7c{1}\u00a76 for \u00a7c{2}\u00a76: \u00a7c{3}\u00a76. +mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1} diff --git a/Essentials/src/messages_zh_HK.properties b/Essentials/src/messages_zh_HK.properties new file mode 100644 index 0000000000..341373af4d --- /dev/null +++ b/Essentials/src/messages_zh_HK.properties @@ -0,0 +1,558 @@ +#X-Generator: crowdin.net +#version: TeamCity +# Single quotes have to be doubled: '' +# Translations start here +# by: +action=\u00a75* {0} \u00a75{1} +addedToAccount=\u00a7a{0} \u5df2\u6dfb\u52a0\u5230\u4f60\u7684\u9280\u884c\u8cec\u6236 +addedToOthersAccount=\u00a7a{0} \u5df2\u88ab\u6dfb\u52a0\u5230 {1} \u00a7a\u7684\u8cec\u6236.\u76ee\u524d\u9918\u984d\: {2} +adventure=\u5192\u96aa\u6a21\u5f0f +alertBroke=\u7834\u58de\: +alertFormat=\u00a73[{0}] \u00a7r {1} \u00a76 {2} \u65bc\: {3} +alertPlaced=\u653e\u7f6e\: +alertUsed=\u4f7f\u7528\: +antiBuildBreak=\u00a74\u4f60\u6c92\u6709\u6b0a\u9650\u7834\u58de\u00a74 {0} \u00a74\u9019\u500b\u65b9\u584a. +antiBuildCraft=\u00a74\u4f60\u6c92\u6709\u6b0a\u9650\u653e\u7f6e\u00a74 {0} \u00a74\u9019\u500b\u65b9\u584a. +antiBuildDrop=\u00a74\u4f60\u6c92\u6709\u6b0a\u9650\u653e\u7f6e\u00a74 {0} \u00a74\u9019\u500b\u65b9\u584a. +antiBuildInteract=\u00a74\u4f60\u6c92\u6709\u6b0a\u9650\u8207\u00a74 {0}\u00a74\u4ea4\u4e92. +antiBuildPlace=\u00a74\u4f60\u6c92\u6709\u6b0a\u9650\u653e\u7f6e\u00a74 {0} \u00a74\u9019\u500b\u65b9\u584a. +antiBuildUse=\u00a74\u4f60\u6c92\u6709\u6b0a\u9650\u4f7f\u7528\u00a74 {0}\u00a74. +autoAfkKickReason=\u4f60\u56e0\u70ba\u9577\u6642\u9593\u672a\u80fd\u5728\u904a\u6232\u4e2d\u505a\u51fa\u52d5\u4f5c\u4e26\u8d85\u904e {0} \u5206\u9418\u800c\u88ab\u670d\u52d9\u5668\u8acb\u51fa\uff01 +backAfterDeath=\u00a76\u4f7f\u7528\u300c/back\u300d\u547d\u4ee4\u4f86\u56de\u5230\u6b7b\u4ea1\u5730\u9ede +backUsageMsg=\u00a76\u56de\u5230\u4e0a\u4e00\u4f4d\u7f6e +backupDisabled=\u00a74\u5099\u4efd\u914d\u7f6e\u6587\u4ef6\u672a\u88ab\u8a2d\u7f6e. +backupFinished=\u00a76\u5099\u4efd\u5b8c\u6210. +backupStarted=\u00a76\u5099\u4efd\u958b\u59cb +balance=\u00a7a\u73fe\u91d1\:{0} +balanceOther=\u00a7a{0}\u7684\u91d1\u9322\:\u00a7c {1} +balanceTop=\u00a76\u91d1\u9322\u6392\u884c\:{0} +banExempt=\u00a74\u4f60\u4e0d\u80fd\u5c01\u7981\u90a3\u500b\u73a9\u5bb6\u00a7r +banFormat=\u00a74\u5df2\u5c01\u7981\:\u00a7r {0} +bed=\u00a77\u5e8a\u00a7r +bedMissing=\u00a7r54\u4f60\u7684\u5e8a\u5df2\u4e1f\u5931\u6216\u963b\u64cb +bedNull=\u00a7m\u5e8a\u00a7r +bedSet=\u00a7m\u5df2\u8a2d\u7f6e\u5e8a\u00a7r +bigTreeFailure=\u00a74\u751f\u6210\u5927\u6a39\u5931\u6557.\u5728\u571f\u584a\u6216\u8349\u584a\u4e0a\u9762\u518d\u8a66\u4e00\u6b21 +bigTreeSuccess=\u00a76\u5df2\u751f\u6210\u5927\u6a39 +blockList=\u00a76Essentials \u5916\u639b\u7a0b\u5f0f\u5c07\u50b3\u905e\u4e0b\u5217\u6307\u4ee4\u7d66\u53e6\u4e00\u5916\u639b\u7a0b\u5f0f\: +bookAuthorSet=\u00a76\u9019\u672c\u66f8\u7684\u4f5c\u8005\u5df2\u88ab\u8a2d\u7f6e\u70ba {0}. +bookLocked=\u00a76\u9019\u672c\u66f8\u73fe\u5728\u6b63\u88ab\u9396\u5b9a. +bookTitleSet=\u00a76\u9019\u672c\u66f8\u7684\u6a19\u984c\u5df2\u88ab\u8a2d\u7f6e\u70ba {0}. +broadcast=\u00a7r\u00a76[\u00a74\u516c\u544a\u00a76]\u00a7a {0} +buildAlert=\u00a74\u4f60\u6c92\u6709\u5efa\u9020\u6b0a\u9650\! +bukkitFormatChanged=Bukkit\u7248\u672c\u5df2\u6539\u8b8a +burnMsg=\u00a76\u4f60\u5c07\u4f7f \u00a74{0} \u00a76\u71c3\u71d2\u00a74 {1} \u00a76\u79d2 +canTalkAgain=\u00a76\u4f60\u5df2\u7372\u5f97\u767c\u8a00\u7684\u8cc7\u683c +cannotStackMob=\u00a74\u60a8\u6c92\u6709\u6b0a\u9650\u5806\u758a\u591a\u500b\u5c0f\u602a. +cantFindGeoIpDB=\u627e\u4e0d\u5230GeoIP\u6578\u64da\u5eab\! +cantReadGeoIpDB=GeoIP\u6578\u64da\u5eab\u8b80\u53d6\u5931\u6557\! +cantSpawnItem=\u00a74\u4f60\u6c92\u6709\u6b0a\u9650\u751f\u6210\u7269\u54c1\u00a7c {0}\u00a74. +chatTypeAdmin=[A] +chatTypeLocal=[L] +chatTypeSpy=[\u76e3\u807d] +cleaned=\u7528\u6236\u6587\u4ef6\u5df2\u6e05\u7a7a +cleaning=\u6e05\u7a7a\u7528\u6236\u6587\u4ef6... +commandFailed=\u547d\u4ee4 {0} \u5931\u6557\: +commandHelpFailedForPlugin=\u672a\u80fd\u7372\u53d6\u6b64\u5916\u639b\u7a0b\u5f0f\u7684\u5e6b\u52a9\:{0} +commandNotLoaded=\u00a74 {0} \u547d\u4ee4\u52a0\u8f09\u5931\u6557 +compassBearing=\u00a76\u65b9\u5411\:{0}\uff08{1}\u5ea6\uff09 +configFileMoveError=\u79fb\u52d5config.yml\u6587\u4ef6\u5230\u5099\u4efd\u4f4d\u7f6e\u5931\u6557 +configFileRenameError=\u91cd\u547d\u540d\u7de9\u5b58\u6587\u4ef6\u70baconfig.yml\u5931\u6557 +connectedPlayers=\u00a76\u76ee\u524d\u5728\u7dda\: \u00a7r +connectionFailed=\u9023\u63a5\u5931\u6557. +cooldownWithMessage=\u00a74\u51b7\u537b\u6642\u9593\:{0} +corruptNodeInConfig=\u00a74\u6ce8\u610f\:\u4f60\u7684\u914d\u7f6e\u5167\u5b58\u5728\u4e00\u500b\u640d\u58de\u7684 {0} \u7bc0\u9ede +couldNotFindTemplate=\u00a74\u7121\u6cd5\u627e\u5230\u6a21\u7248 {0} +creatingConfigFromTemplate=\u5f9e\u6a21\u7248\:{0} \u5275\u5efa\u914d\u7f6e +creatingEmptyConfig=\u5275\u5efa\u7a7a\u7684\u914d\u7f6e\:{0} +creative=\u5275\u9020\u6a21\u5f0f +currency={0}{1} +currentWorld=\u00a76\u7576\u524d\u4e16\u754c\:\u00a74 {0} +day=\u5929 +days=\u5929 +defaultBanReason=\u767b\u9304\u5931\u6557\!\u60a8\u7684\u5e33\u865f\u5df2\u88ab\u6b64\u670d\u52d9\u5668\u5c01\u7981\! +deleteFileError=\u7121\u6cd5\u522a\u9664\u6587\u4ef6\:{0} +deleteHome=\u00a76\u5bb6 \u00a74{0} \u00a76\u88ab\u79fb\u9664 +deleteJail=\u00a76\u76e3\u7344 \u00a74{0} \u00a76\u88ab\u79fb\u9664 +deleteWarp=\u00a76\u5730\u6a19 \u00a74{0} \u00a76\u88ab\u79fb\u9664 +deniedAccessCommand=\u00a7c{0} \u00a74\u88ab\u62d2\u7d55\u4f7f\u7528\u547d\u4ee4 +denyBookEdit=\u00a74\u4f60\u4e0d\u80fd\u89e3\u9396\u9019\u672c\u66f8. +denyChangeAuthor=\u00a74\u4f60\u4e0d\u80fd\u6539\u8b8a\u9019\u672c\u66f8\u7684\u4f5c\u8005. +denyChangeTitle=\u00a74\u4f60\u4e0d\u80fd\u6539\u8b8a\u9019\u672c\u66f8\u7684\u6a19\u984c. +depth=\u00a76\u4f60\u4f4d\u65bc\u6d77\u62d40\u683c\u8655 +depthAboveSea=\u00a76\u4f60\u4f4d\u65bc\u6d77\u62d4\u6b63\u00a7c{0}\u00a76\u683c\u8655 +depthBelowSea=\u00a76\u4f60\u4f4d\u65bc\u6d77\u62d4\u8ca0\u00a7c{0}\u00a76\u683c\u8655 +destinationNotSet=\u76ee\u7684\u5730\u672a\u8a2d\u7f6e. +disableUnlimited=\u00a76\u53d6\u6d88\u4e86 {1} \u7684\u7121\u9650\u653e\u7f6e \u00a7c{0} \u00a76\u7684\u80fd\u529b +disabled=\u95dc\u9589 +disabledToSpawnMob=\u00a74\u5df2\u7981\u6b62\u6b64\u751f\u7269\u7684\u751f\u6210. +distance=\u00a76\u8ddd\u96e2\: {0} +dontMoveMessage=\u00a76\u50b3\u9001\u5c07\u5728{0}\u5167\u958b\u59cb.\u4e0d\u8981\u79fb\u52d5 +downloadingGeoIp=\u4e0b\u8f09GeoIP\u6578\u64da\u5eab\u4e2d +duplicatedUserdata=\u8907\u88fd\u4e86\u73a9\u5bb6\u5b58\u6a94\:{0} \u548c {1} +durability=\u00a76\u9019\u500b\u5de5\u5177\u9084\u6709 \u00a74{0}\u00a76 \u6301\u4e45 +editBookContents=\u00a7e\u4f60\u73fe\u5728\u53ef\u4ee5\u7de8\u8f2f\u9019\u672c\u66f8\u7684\u5167\u5bb9. +enableUnlimited=\u00a76\u7d66\u4e88 \u00a7c{1}\u00a76 \u7121\u9650\u7684\u00a7c {0} \u00a76 \u3002 +enabled=\u958b\u555f +enchantmentApplied=\u00a76\u9644\u9b54 \u00a7c{0} \u00a76\u5df2\u88ab\u61c9\u7528\u5230\u4f60\u624b\u4e2d\u7684\u5de5\u5177. +enchantmentNotFound=\u00a74\u672a\u627e\u5230\u8a72\u9644\u9b54. +enchantmentPerm=\u00a74\u4f60\u6c92\u6709\u9032\u884c\u00a7c {0} \u00a74\u9644\u9b54\u7684\u6b0a\u9650. +enchantmentRemoved=\u00a76\u9644\u9b54 \u00a7c{0} \u00a76\u5df2\u5f9e\u4f60\u624b\u4e0a\u7684\u5de5\u5177\u79fb\u9664 +enchantments=\u00a76\u9644\u9b54\: \u00a7r{0} +errorCallingCommand=\u932f\u8aa4\u7684\u547c\u53eb\u547d\u4ee4\:/{0} +errorWithMessage=\u00a7c\u932f\u8aa4\:{0} +essentialsHelp1=Essentials\u7121\u6cd5\u5c07\u5176\u6253\u958b +essentialsHelp2=Essentials\u7121\u6cd5\u5c07\u5176\u6253\u958b +essentialsReload=\u00a76Essentials \u5df2\u91cd\u65b0\u8f09\u5165\u00a7c {0}\u3002 +exp=\u00a74{0} \u00a76\u64c1\u6709\u00a7c {1} \u00a76\u7d93\u9a57\u503c (\u7b49\u7d1a\u00a7c {2}\u00a76) \u9700\u8981\u00a7c {3} \u00a76\u7d93\u9a57\u624d\u80fd\u5347\u7d1a. +expSet=\u00a7c\u4f60\u5c07{0} \u00a76\u7684\u7d93\u9a57\u8a2d\u7f6e\u70ba\u00a7c {1} \u00a76\u7d93\u9a57\u503c. +extinguish=\u00a76\u4f60\u7184\u6ec5\u4e86\u4f60\u81ea\u5df1\u8eab\u4e0a\u7684\u706b +extinguishOthers=\u00a76\u4f60\u7184\u6ec5\u4e86 {0} \u00a76\u8eab\u4e0a\u7684\u706b +failedToCloseConfig=\u95dc\u9589\u914d\u7f6e {0} \u5931\u6557 +failedToCreateConfig=\u5275\u5efa\u914d\u7f6e {0} \u5931\u6557 +failedToWriteConfig=\u5beb\u5165\u914d\u7f6e {0} \u5931\u6557 +false=\u00a74\u5426\u00a7r +feed=\u5df2\u7d93\u98fd\u548c,\u7121\u6cd5\u589e\u52a0\u98e2\u9913\u5ea6. +feedOther=\u00a76You satiated the appetite of \u00a7c{0}\u00a76. +fileRenameError=\u91cd\u547d\u540d\u6587\u4ef6 {0} \u5931\u6557 +fireworkColor=\u00a74\u4f7f\u7528\u4e86\u7121\u6548\u7684\u7159\u82b1\u586b\u5145\u53c3\u6578\uff0c\u5fc5\u9808\u9996\u5148\u8a2d\u7f6e\u4e00\u500b\u984f\u8272\u3002 +fireworkEffectsCleared=\u00a76\u5f9e\u6301\u6709\u7684\u7269\u54c1\u4e2d\u79fb\u9664\u4e86\u6240\u6709\u7279\u6548. +fireworkSyntax=\u00a76\u7159\u82b1\u53c3\u6578\:\u00a7c color\:<\u984f\u8272> [fade\:<\u6de1\u51fa\u984f\u8272>] [shape\:<\u5f62\u614b>] [effect\:<\u7279\u6548>]\n\u00a76\u8981\u4f7f\u7528\u591a\u500b\u984f\u8272/\u7279\u6548, \u4f7f\u7528\u9017\u865f\: \u00a7cred,blue,pink\n\u00a76\u5f62\u72c0\:\u00a7c star, ball, large, creeper, burst \u00a76\u7279\u6548\:\u00a7c trail, twinkle. +flyMode=\u00a76 \u5df2\u70ba\u00a7c{1}\u00a76\u8a2d\u7f6e\u4e86\u98db\u884c\u6a21\u5f0f\u70ba\u00a7c{0}. +flying=\u98db\u884c\u4e2d +foreverAlone=\u00a74\u4f60\u6c92\u6709\u53ef\u56de\u5fa9\u7684\u73a9\u5bb6 +fullStack=\u00a74\u4f60\u7684\u7269\u54c1\u5df2\u7d93\u6700\u591a\u4e86. +gameMode=\u00a76\u5c07\u00a7c{1}\u00a76\u7684\u904a\u6232\u6a21\u5f0f\u8a2d\u5b9a\u70ba\u00a7c {0} \u00a76\u3002 +gcWorld=\u00a76{0} "\u00a7c{1}\u00a76"\: \u00a7c{2}\u00a76 \u5340\u584a, \u00a7c{3}\u00a76 \u5be6\u9ad4, \u00a7c{4}\u00a76 \u5340\u584a\u8cc7\u6599. +gcfree=\u7a7a\u9592\u5167\u5b58\: \u00a7c{0} MB +gcmax=\u6700\u5927\u5167\u5b58\: \u00a7c{0} MB +gctotal=\u5df2\u5206\u914d\u5167\u5b58\: \u00a7c{0} MB +geoIpUrlEmpty=GeoIP\u4e0b\u8f09\u93c8\u63a5\u70ba\u7a7a +geoIpUrlInvalid=GeoIP\u4e0b\u8f09\u93c8\u63a5\u5931\u6548 +geoipJoinFormat=\u73a9\u5bb6 {0} \u4f86\u81ea\u65bc {1} +giveSpawn=\u00a76\u7d66\u4e88\u00a7c {2} \u00a76 \u00a7c {0} \u500b\u00a7c {1}\u00a76. +godDisabledFor=\u00a7cdisabled\u00a76 for\u00a7c {0} +godEnabledFor=\u00a74\u958b\u555f\u4e86\u00a7c {0} \u00a76\u7684\u4e0a\u5e1d\u6a21\u5f0f +godMode=\u00a76\u4e0a\u5e1d\u6a21\u5f0f \u00a7c{0} +groupDoesNotExist=\u00a74\u7576\u524d\u7d44\u6c92\u6709\u4eba\u5728\u7dda\! +groupNumber=\u00a7c{0}\u00a7f \u5728\u7dda, \u60f3\u8981\u7372\u53d6\u5168\u90e8\u4f7f\u7528\:\u00a7c /{1} {2} +hatArmor=\u00a74\u932f\u8aa4\:\u4f60\u7121\u6cd5\u4f7f\u7528\u9019\u500b\u7269\u54c1\u4f5c\u70ba\u5e3d\u5b50\! +hatEmpty=\u00a74\u4f60\u73fe\u5728\u9084\u6c92\u6709\u6234\u5e3d\u5b50. +hatFail=\u00a74\u4f60\u5fc5\u9808\u628a\u60f3\u8981\u5e36\u7684\u5e3d\u5b50\u62ff\u5728\u624b\u4e2d. +hatPlaced=\u00a7e\u4eab\u53d7\u4f60\u7684\u65b0\u5e3d\u5b50\u628a\! +hatRemoved=\u00a76\u4f60\u7684\u5e3d\u5b50\u5df2\u79fb\u9664. +haveBeenReleased=\u00a76\u4f60\u5df2\u88ab\u91cb\u653e +heal=\u00a76\u4f60\u5df2\u88ab\u6cbb\u7642 +healDead=\u00a74\u4f60\u4e0d\u80fd\u6cbb\u7642\u4e00\u500b\u6b7b\u4eba\! +healOther=\u00a76\u5df2\u6cbb\u7642\u00a7c {0} +helpConsole=\u5f9e\u63a7\u5236\u53f0\u67e5\u770b\u5e6b\u52a9,\u8acb\u8f38\u5165\u300c?\u300d +helpFrom=\u00a76\u4f86\u81ea\u65bc {0} \u7684\u6307\u4ee4 +helpLine=\u00a76/{0}\u00a7r\: {1} +helpMatching=\u00a76\u6307\u4ee4\u9023\u63a5 "\u00a7c{0}\u00a76"\: +helpOp=\u00a74[\u6c42\u52a9OP]\u00a7r \u00a76{0}\:\u00a7r {1} +helpPlugin=\u00a74{0}\u00a7r\: \u5916\u639b\u7a0b\u5f0f\u5e6b\u52a9\: /help {1} +holdBook=\u00a74\u4f60\u9700\u8981\u62ff\u7740\u4e00\u672c\u53ef\u5beb\u7684\u66f8. +holdFirework=\u00a74\u4f60\u5fc5\u9808\u62ff\u7740\u7159\u706b\u624d\u80fd\u589e\u52a0\u7279\u6548. +holdPotion=\u00a74\u4f60\u5fc5\u9808\u62ff\u7740\u85e5\u6c34\u624d\u80fd\u589e\u52a0\u7279\u6548. +holeInFloor=\u00a74\u5730\u677f\u6709\u6d1e\! +homeSet=\u00a76\u5df2\u8a2d\u7f6e\u5bb6~ +homes=\u00a76\u5bb6\:\u00a7r{0} +hour=\u5c0f\u6642 +hours=\u5c0f\u6642 +ignoredList=\u00a76\u5ffd\u7565\:\u00a7r {0} +ignorePlayer=\u00a76\u4f60\u5c4f\u853d\u4e86\u73a9\u5bb6 \u00a7c{0} +illegalDate=\u932f\u8aa4\u7684\u65e5\u671f\u683c\u5f0f +infoChapter=\u00a76\u9078\u64c7\u7ae0\u7bc0\: +infoChapterPages=\u00a7e ---- \u00a76{0} \u00a7e--\u00a76 \u9801\u9762\: \u00a7c{1}\u00a76 / \u00a7c{2} \u00a7e---- +infoPages=\u00a7e----\u7b2c \u00a7c{0}\u00a7e \u9801/\u5171 \u00a7c{1}\u00a7e \u9801---- +infoUnknownChapter=\u00a74\u672a\u77e5\u7ae0\u7bc0\u3002 +insufficientFunds=\u00a74\u53ef\u7528\u8cc7\u91d1\u4e0d\u8db3. +invalidCharge=\u00a74\u7121\u6548\u7684\u50f9\u683c +invalidFireworkFormat=\u00a74The option \u00a7c{0} \u00a74is not a valid value for \u00a7c{1}\u00a74. +invalidHome=\u00a74\u5bb6\u00a7c {0} \u00a74\u4e0d\u5b58\u5728\! +invalidHomeName=\u00a74\u7121\u6548\u7684\u5bb6\u540d\u7a31\! +invalidMob=\u00a74\u7121\u6548\u751f\u7269\u985e\u578b +invalidNumber=\u7121\u6548\u7684\u6578\u5b57. +invalidPotion=\u00a74\u7121\u6548\u7684\u85e5\u6c34. +invalidPotionMeta=\u00a74\u7121\u6548\u7684\u85e5\u6c34\u6578\u64da\: \u00a7c{0}\u00a74. +invalidSignLine=\u00a74\u724c\u5b50\u4e0a\u7684\u7b2c \u00a7c{0} \u00a74\u884c\u7121\u6548 +invalidWarpName=\u00a74\u7121\u6548\u7684\u50b3\u9001\u9ede\u540d\u7a31\! +invalidWorld=\u00a74\u7121\u6548\u7684\u4e16\u754c\u540d. +is=\u662f +itemCannotBeSold=\u00a74\u8a72\u7269\u54c1\u7121\u6cd5\u8ce3\u7d66\u670d\u52d9\u5668 +itemMustBeStacked=\u00a74\u7269\u54c1\u5fc5\u9808\u6210\u7d44\u4ea4\u6613,2s\u7684\u6578\u91cf\u662f2\u7d44,\u4ee5\u6b64\u985e\u63a8 +itemNames=\u00a76\u7269\u54c1\u7c21\u6613\u540d\u7a31\:\u00a7r {0} +itemNotEnough1=\u00a74\u4f60\u6c92\u6709\u8db3\u5920\u7684\u8a72\u7269\u54c1\u4f86\u8ce3\u51fa +itemNotEnough2=\u00a76\u5982\u679c\u4f60\u60f3\u8981\u8ce3\u6389\u6240\u6709\u4f60\u80cc\u5305\u5167\u7684\u8a72\u7269\u54c1,\u4f7f\u7528\u300c/sell \u7269\u54c1\u540d\u7a31\uff08\u82f1\u6587,\u6216ID\uff09\u300d +itemNotEnough3=\u00a76\u300c/sell \u7269\u54c1\u540d\u7a31 -1\u300d\u5c07\u6703\u7559\u51fa\u4e00\u500b\u800c\u8ce3\u6389\u5176\u5b83\u8a72\u7a2e\u7269\u54c1,\u4ee5\u6b64\u985e\u63a8 +itemSellAir=\u4f60\u96e3\u9053\u60f3\u8ce3\u7a7a\u6c23\u55ce\uff1f\u653e\u500b\u6771\u897f\u5728\u4f60\u624b\u88e1 +itemSold=\u00a7a\u7372\u5f97 \u00a7c {0} \u00a7a \uff08{1} \u55ae\u4f4d{2},\u6bcf\u500b\u50f9\u503c {3}\uff09 +itemSoldConsole=\u00a7c{0} \u00a76\u8ce3\u51fa\u4e86 {1},\u7372\u5f97\u4e86\u00a76 {2} \u00a76 \uff08{3} \u55ae\u4f4d\u7269\u54c1,\u6bcf\u500b\u50f9\u503c {4}\uff09 +itemSpawn=\u00a76\u751f\u6210 {0} \u500b {1} +itemType=\u00a76\u7269\u54c1\:\u00a7c {0} \u00a76-\u00a74 {1} +itemsCsvNotLoaded=\u7121\u6cd5\u52a0\u8f09items.csv +jailAlreadyIncarcerated=\u00a74\u5df2\u5728\u76e3\u7344\u4e2d\u7684\u73a9\u5bb6\:{0} +jailMessage=\u00a74\u8acb\u5728\u76e3\u7344\u4e2d\u9762\u58c1\u601d\u904e\uff01 +jailNotExist=\u00a74\u8a72\u76e3\u7344\u4e0d\u5b58\u5728 +jailReleased=\u00a76\u73a9\u5bb6 \u00a7c{0}\u00a76 \u51fa\u7344\u4e86 +jailReleasedPlayerNotify=\u00a76\u4f60\u5df2\u88ab\u91cb\u653e\uff01 +jailSentenceExtended=\u00a76\u56da\u7981\u6642\u9593\u589e\u52a0\u5230\:{0) +jailSet=\u00a76\u76e3\u7344 {0} \u5df2\u88ab\u8a2d\u7f6e +jumpError=\u00a74\u9019\u5c07\u6703\u640d\u5bb3\u4f60\u7684\u96fb\u8166 +kickDefault=\u5f9e\u670d\u52d9\u5668\u8acb\u51fa +kickExempt=\u00a74\u4f60\u7121\u6cd5\u8acb\u51fa\u8a72\u73a9\u5bb6. +kickedAll=\u00a74\u5df2\u5c07\u6240\u6709\u73a9\u5bb6\u8acb\u51fa\u670d\u52d9\u5668. +kill=\u00a76\u6bba\u6b7b\u4e86 \u00a7c{0} +killExempt=\u00a74\u4f60\u4e0d\u80fd\u6bba\u5bb3 \u00a7c{0}\u00a74\u3002 +kitCost=\ \u00a77\u00a7o({0})\u00a7r +kitError2=\u00a74\u8a72\u5de5\u5177\u5305\u53ef\u80fd\u4e0d\u5b58\u5728\u6216\u8005\u88ab\u62d2\u7d55\u4e86. +kitError=\u00a74\u6c92\u6709\u6709\u6548\u7684\u5de5\u5177\u5305 +kitGiveTo=\u00a76\u7d66\u4e88\u00a7c{1}\u00a76\u5de5\u5177\u5305\u00a7c {0}\u00a76\u3002 +kitInvFull=\u00a74\u4f60\u7684\u80cc\u5305\u5df2\u6eff,\u5de5\u5177\u5305\u5c07\u653e\u5728\u5730\u4e0a +kitNotFound=\u00a74\u5de5\u5177\u5305\u4e0d\u5b58\u5728. +kitOnce=\u00a74\u4f60\u4e0d\u80fd\u518d\u6b21\u4f7f\u7528\u8a72\u5de5\u5177\u5305. +kitReceive=\u00a76\u6536\u5230\u4e00\u500b\u00a7c {0} \u00a76\u5de5\u5177\u5305. +kitTimed=\u00a74\u4f60\u4e0d\u80fd\u518d\u6b21\u5c0d\u5176\u4ed6\u4eba\u4f7f\u7528\u6b64\u5de5\u5177\u5305\u00a7c {0}\u00a74. +kits=\u00a76\u5de5\u5177\u5305\:\u00a7r{0} +leatherSyntax=\u00a76\u76ae\u9769\u984f\u8272\u8a9e\u6cd5\: color\:,, \u5982\: color\:255,0,0. +lightningSmited=\u00a76\u4f60\u525b\u525b\u88ab\u96f7\u64ca\u4e2d\u4e86 +lightningUse=\u00a76\u96f7\u64ca\u4e2d\u4e86\u00a7c {0} +listAfkTag=\u00a77[\u96e2\u958b]\u00a7r +listAmount=\u00a76\u7576\u524d\u6709 \u00a7c{0}\u00a76 \u500b\u73a9\u5bb6\u5728\u7dda,\u6700\u5927\u5728\u7dda\u4eba\u6578\u70ba \u00a7c{1}\u00a76 \u500b\u73a9\u5bb6. +listAmountHidden=\u00a76\u7576\u524d\u6709 \u00a7c{0}\u00a76/{1}\u00a76 \u500b\u73a9\u5bb6\u5728\u7dda,\u6700\u5927\u5728\u7dda\u4eba\u6578 \u00a7c{2}\u00a76 \u500b\u73a9\u5bb6 +listGroupTag=\u00a76{0}\u00a7r\: \u00a7r +listHiddenTag=\u00a77[\u96b1\u8eab]\u00a7r +loadWarpError=\u00a74\u52a0\u8f09\u5730\u6a19 {0} \u5931\u6557 +localFormat=[L]<{0}> {1} +mailClear=\u00a76\u8f38\u5165\u00a7c /mail clear\u00a76 \u5c07\u90f5\u4ef6\u6a19\u793a\u70ba\u5df2\u8b80\u3002 +mailCleared=\u00a76\u90f5\u7bb1\u5df2\u6e05\u7a7a\uff01 +mailSent=\u00a76\u90f5\u4ef6\u5df2\u767c\u51fa\uff01 +markMailAsRead=\u00a76\u8f38\u5165\u00a7c /mail clear\u00a76 \u5c07\u90f5\u4ef6\u6a19\u793a\u70ba\u5df2\u8b80\u3002 +markedAsAway=\u00a76\u4f60\u5df2\u8a2d\u7f6e\u96e2\u958b. +markedAsNotAway=\u00a76\u4f60\u5df2\u8a2d\u7f6e\u53d6\u6d88\u96e2\u958b. +matchingIPAddress=\u00a76\u4ee5\u4e0b\u662f\u4f86\u81ea\u8a72IP\u4f4d\u5740\u7684\u73a9\u5bb6\: +maxHomes=\u00a74\u4f60\u7121\u6cd5\u8a2d\u7f6e\u8d85\u904e {0} \u500b\u5bb6. +mayNotJail=\u00a74\u4f60\u7121\u6cd5\u56da\u7981\u8a72\u73a9\u5bb6 +me=\u6211 +minute=\u5206\u9418 +minutes=\u5206\u9418 +missingItems=\u00a74You do not have \u00a7c{0}x {1}\u00a74. +mobSpawnError=\u00a74\u66f4\u6539\u5237\u602a\u7c60\u6642\u767c\u751f\u932f\u8aa4 +mobSpawnLimit=\u751f\u7269\u6578\u91cf\u592a\u591a,\u7121\u6cd5\u751f\u6210 +mobSpawnTarget=\u00a74\u76ee\u6a19\u65b9\u584a\u5fc5\u9808\u662f\u4e00\u500b\u5237\u602a\u7c60 +mobsAvailable=\u00a76\u751f\u7269\:\u00a7r {0} +moneyRecievedFrom=\u00a7a\u5df2\u5f9e {1} \u63a5\u6536{0} +moneySentTo=\u00a7a{0} \u5df2\u767c\u9001\u5230 {1} +month=\u6708 +months=\u6708 +moreThanZero=\u00a74\u6578\u91cf\u5fc5\u9808\u5927\u65bc0 +moveSpeed=\u00a76\u5c07\u00a7c{2}\u00a76\u7684 {0} \u901f\u5ea6\u8a2d\u5b9a\u70ba\u00a7c {1} \u00a76\u3002 +msgFormat=\u00a76[\u00a7c{0}\u00a76 -> \u00a7c{1}\u00a76] \u00a7r{2} +multipleCharges=\u00a74\u60a8\u4e0d\u80fd\u5c0d\u9019\u500b\u7159\u82b1\u61c9\u7528\u591a\u65bc\u4e00\u500b\u7684\u88dd\u6599. +multiplePotionEffects=\u00a74\u60a8\u4e0d\u80fd\u5c0d\u9019\u500b\u7159\u82b1\u61c9\u7528\u591a\u65bc\u4e00\u500b\u7684\u6548\u679c. +muteExempt=\u00a74\u4f60\u7121\u6cd5\u7981\u8a00\u8a72\u73a9\u5bb6 +muteNotify=\u00a7c{0} \u00a76\u5c07 \u00a7c{1} \u00a76\u7981\u8a00\u4e86\u3002 +mutedPlayer=\u00a76\u73a9\u5bb6\u00a7c {0} \u00a76\u88ab\u7981\u8a00\u4e86\u3002 +mutedPlayerFor=\u00a76\u73a9\u5bb6\u00a7c {0} \u00a76\u88ab\u7981\u8a00\u00a7c {1}\u00a76\u3002 +mutedUserSpeaks={0} \u60f3\u8981\u8aaa\u8a71,\u4f46\u88ab\u7981\u8a00\u4e86 +nearbyPlayers=\u00a76\u9644\u8fd1\u7684\u73a9\u5bb6\: {0} +negativeBalanceError=\u00a74\u73fe\u91d1\u4e0d\u53ef\u5c0f\u65bc\u96f6 +nickChanged=\u00a76\u66b1\u7a31\u5df2\u66f4\u63db +nickDisplayName=\u00a74\u4f60\u9700\u8981\u6fc0\u6d3bchange-displayname.\u8a72\u6587\u4ef6\u5728Essentials\u8a2d\u7f6e\u6587\u4ef6\u4e2d +nickInUse=\u00a74\u90a3\u500b\u66b1\u7a31\u5df2\u88ab\u4f7f\u7528 +nickNamesAlpha=\u00a74\u66b1\u7a31\u5fc5\u9808\u70ba\u5b57\u6bcd\u6216\u6578\u5b57. +nickNoMore=\u00a76\u4f60\u4e0d\u518d\u64c1\u6709\u4e00\u500b\u66b1\u7a31 +nickSet=\u00a76\u4f60\u7684\u66b1\u7a31\u73fe\u5728\u662f \u00a7c{0}\u00a76\u3002 +nickTooLong=\u00a74\u9019\u500b\u66b1\u7a31\u592a\u9577. +noAccessCommand=\u00a74\u4f60\u6c92\u6709\u4f7f\u7528\u8a72\u547d\u4ee4\u7684\u6b0a\u9650 +noAccessPermission=\u00a74You do not have permission to access that \u00a7c{0}\u00a74. +noBreakBedrock=\u00a74\u4f60\u4e0d\u80fd\u6467\u6bc0\u57fa\u5ca9\uff01 +noDestroyPermission=\u00a74\u4f60\u6c92\u6709\u6b0a\u9650\u7834\u58de \u00a7c{0}\u00a74\u3002 +noDurability=\u00a74\u9019\u500b\u7269\u54c1\u6c92\u6709\u8010\u4e45. +noGodWorldWarning=\u00a74\u7981\u6b62\u4f7f\u7528\u4e0a\u5e1d\u6a21\u5f0f. +noHelpFound=\u00a74\u6c92\u6709\u5339\u914d\u7684\u547d\u4ee4 +noHomeSetPlayer=\u00a76\u8a72\u73a9\u5bb6\u9084\u672a\u8a2d\u7f6e\u5bb6 +noIgnored=\u00a76\u4f60\u6c92\u6709\u5ffd\u7565\u4efb\u4f55\u4eba\u3002 +noKitPermission=\u00a74\u4f60\u9700\u8981 \u00a74{0}\u00a74 \u6b0a\u9650\u4f86\u4f7f\u7528\u8a72\u5de5\u5177 +noKits=\u00a76\u9084\u6c92\u6709\u53ef\u7372\u5f97\u7684\u5de5\u5177 +noMail=\u4f60\u6c92\u6709\u4efb\u4f55\u90f5\u4ef6 +noMatchingPlayers=\u00a76\u627e\u4e0d\u5230\u5339\u914d\u7684\u73a9\u5bb6. +noMetaFirework=\u00a74\u4f60\u6c92\u6709\u6b0a\u9650\u61c9\u7528\u7159\u82b1\u6578\u64da. +noMetaPerm=\u00a74\u4f60\u6c92\u6709\u6b0a\u9650\u61c9\u7528 \u00a7c{0}\u00a74 \u7684\u6578\u64da. +noNewMail=\u00a76\u4f60\u6c92\u6709\u65b0\u7684\u90f5\u4ef6 +noPendingRequest=\u00a74\u4f60\u6c92\u6709\u5f85\u89e3\u6c7a\u7684\u8acb\u6c42 +noPerm=\u00a74\u4f60\u6c92\u6709 \u00a7c{0}\u00a74 \u6b0a\u9650 +noPermToSpawnMob=\u00a74\u4f60\u6c92\u6709\u751f\u6210\u8a72\u751f\u7269\u7684\u6b0a\u9650 +noPlacePermission=\u00a74\u00a74\u4f60\u6c92\u6709\u5728\u90a3\u500b\u724c\u5b50\u65c1\u908a\u653e\u65b9\u584a\u7684\u6b0a\u5229 +noPotionEffectPerm=\u00a74\u4f60\u6c92\u6709\u6b0a\u9650\u61c9\u7528\u7279\u6548 \u00a7c{0} \u00a74\u5230\u9019\u500b\u85e5\u6c34. +noPowerTools=\u00a76\u4f60\u6c92\u6709\u7d81\u5b9a\u547d\u4ee4 +noWarpsDefined=\u00a74\u6c92\u6709\u78ba\u5b9a\u7684\u5730\u6a19 +none=\u7121 +notAllowedToQuestion=\u00a74\u4f60\u672a\u88ab\u6388\u6b0a\u4f7f\u7528\u63d0\u554f\u767c\u8a00 +notAllowedToShout=\u00a74\u4f60\u672a\u88ab\u6388\u6b0a\u4f7f\u7528\u558a\u8a71\u767c\u8a00 +notEnoughExperience=\u00a74\u4f60\u6c92\u6709\u8db3\u5920\u7684\u7d93\u9a57\u503c +notEnoughMoney=\u00a74\u4f60\u6c92\u6709\u8db3\u5920\u7684\u8cc7\u91d1 +notFlying=\u672a\u98db\u884c +notRecommendedBukkit=\u00a74Bukkit\u7248\u672c\u904e\u820a.\u5efa\u8b70\u66f4\u65b0. +notSupportedYet=\u66ab\u4e0d\u652f\u6301 +nothingInHand=\u00a74\u4f60\u6c92\u6709\u6301\u6709\u4efb\u4f55\u7269\u54c1 +now=\u73fe\u5728 +nuke=\u00a7d\u6838\u6b66\u964d\u843d,\u6ce8\u610f\u96b1\u853d\uff01 +numberRequired=\u9700\u8981\u8f38\u5165\u6578\u5b57\uff01 +onlyDayNight=/time \u547d\u4ee4\u53ea\u6709 day/night \u5169\u500b\u9078\u64c7 +onlyPlayerSkulls=\u00a74\u4f60\u53ea\u80fd\u8a2d\u5b9a\u73a9\u5bb6\u982d\u9871 (\u00a7c397\:3\u00a74) \u7684\u64c1\u6709\u8005\u3002 +onlyPlayers=\u00a74\u53ea\u6709\u904a\u6232\u4e2d\u7684\u73a9\u5bb6\u53ef\u4ee5\u4f7f\u7528 \u00a7c{0}\u00a74\u3002 +onlySunStorm=\u00a74/weather \u547d\u4ee4\u53ea\u6709 sun/storm \u5169\u500b\u9078\u64c7 +orderBalances=\u00a76\u6392\u5e8f {0} \u00a76\u500b\u73a9\u5bb6\u7684\u8cc7\u91d1\u4e2d,\u8acb\u7a0d\u5019\u2026\u2026 +oversizedTempban=\u00a74\u4f60\u53ef\u80fd\u6c92\u6709\u5728\u9019\u500b\u6642\u6bb5\u5c01\u7981\u73a9\u5bb6. +pTimeCurrent=\u00a76{0}\u00a7c \u00a76\u7684\u6642\u9593\u662f \u00a7c{1} +pTimeCurrentFixed=\u00a7c{0}\u00a76 \u7684\u6642\u9593\u88ab\u9023\u63a5\u5230 \u00a7c{1} +pTimeNormal=\u00a7c{0}\u00a76 \u7684\u6642\u9593\u662f\u6b63\u5e38\u7684\u4e26\u8207\u670d\u52d9\u5668\u540c\u6b65 +pTimeOthersPermission=\u00a74\u4f60\u672a\u88ab\u6388\u6b0a\u8a2d\u7f6e\u5176\u4ed6\u73a9\u5bb6\u7684\u6642\u9593 +pTimePlayers=\u00a76\u9019\u4e9b\u73a9\u5bb6\u6709\u4ed6\u5011\u81ea\u5df1\u7684\u6642\u9593\: +pTimeReset=\u00a76\u8a72\u73a9\u5bb6\u7684\u6642\u9593\u88ab\u91cd\u7f6e\:\u00a7c{0} +pTimeSet=\u00a76\u8a72\u73a9\u5bb6\u7684\u6642\u9593\u88ab\u8a2d\u5b9a\u70ba \u00a7c{0}\u00a76 \u5c0d\u8c61\:\u00a7c{1} +pTimeSetFixed=\u00a76\u8a72\u73a9\u5bb6\u6642\u9593\u88ab\u9023\u63a5\u5230 \u00a7c{0}\u00a76 \u5c0d\u8c61\:\u00a7c{1} +pWeatherCurrent=\u00a7c{0}\u00a76\u7684\u5929\u6c23\u662f\u00a7c {1}\u00a76. +pWeatherInvalidAlias=\u00a74\u932f\u8aa4\u7684\u5929\u6c23\u985e\u578b +pWeatherNormal=\u00a7c{0}\u00a76\u7684\u5929\u6c23\u662f\u6b63\u5e38\u7684. +pWeatherOthersPermission=\u00a74\u60a8\u6c92\u6709\u88ab\u6388\u6b0a\u8a2d\u7f6e\u5176\u4ed6\u73a9\u5bb6\u7684\u5929\u6c23. +pWeatherPlayers=\u00a76\u9019\u4e9b\u73a9\u5bb6\u90fd\u6709\u81ea\u5df1\u7684\u5929\u6c23\:\u00a7r +pWeatherReset=\u00a76\u73a9\u5bb6\u7684\u5929\u6c23\u88ab\u91cd\u7f6e\: \u00a7c{0} +pWeatherSet=\u00a76\u73a9\u5bb6\u00a7c{1}\u00a76\u7684\u5929\u6c23\u88ab\u8a2d\u7f6e\u70ba \u00a7c{0}\u00a76 . +pendingTeleportCancelled=\u00a74\u5f85\u8655\u7406\u7684\u50b3\u9001\u8acb\u6c42\u5df2\u53d6\u6d88 +playerBanIpAddress=\u00a76Player\u00a7c {0} \u00a76banned IP address\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerBanned=\u00a76\u73a9\u5bb6\u00a7c {0} \u00a76\u88ab\u5c01\u9396\u00a7c {1} \u00a76\uff0c\u56e0\u70ba \u00a7c{2}\u00a76\u3002 +playerInJail=\u00a74\u73a9\u5bb6\u5df2\u7d93\u5728\u76e3\u7344\u00a7c {0}\u00a74\u3002 +playerJailed=\u00a76\u73a9\u5bb6 \u00a7c{0} \u00a76\u88ab\u902e\u6355\u4e86 +playerJailedFor=\u00a76\u73a9\u5bb6 \u00a7c{0} \u00a76\u88ab\u902e\u6355,\u6642\u9593\:{1} +playerKicked=\u00a74\u7ba1\u7406\u54e1 \u00a7c{0} \u00a76\u8acb\u51fa\u4e86 \u00a7c{1},\u00a76\u7406\u7531\:{2} +playerMuted=\u00a76\u4f60\u88ab\u7981\u6b62\u767c\u8a00 +playerMutedFor=\u00a76\u4f60\u5df2\u88ab\u7981\u8a00.\u7406\u7531\: {0} +playerNeverOnServer=\u00a74\u73a9\u5bb6 \u00a7c{0} \u00a74\u5f9e\u6c92\u51fa\u73fe\u5728\u670d\u52d9\u5668\u904e +playerNotFound=\u00a74\u73a9\u5bb6\u672a\u5728\u7dda\uff08\u6216\u4e0d\u5b58\u5728\uff09 +playerUnbanIpAddress=\u00a76\u5df2\u89e3\u9664\u7528\u6236\u00a7c {0} \u00a76\u7684\u5c01\u7981IP\: {1}. +playerUnbanned=\u00a76\u73a9\u5bb6\u00a7c {0} \u00a76\u5c07\u00a7c {1} \u00a76\u89e3\u9664\u5c01\u9396\u3002 +playerUnmuted=\u00a76\u4f60\u88ab\u5141\u8a31\u767c\u8a00 +pong=\u556a\uff01 +posPitch=\u00a76\u4ef0\u89d2\: {0} (\u982d\u90e8\u7684\u89d2\u5ea6) +posX=\u00a76X\: {0} (+\u6771 <-> -\u897f) +posY=\u00a76Y\: {0} (+\u4e0a <-> -\u4e0b) +posYaw=\u00a76Yaw\: {0} (\u65cb\u8f49) +posZ=\u00a76Z\: {0} (+\u5357 <-> -\u5317) +possibleWorlds=\u00a76Possible worlds are the numbers \u00a7c0\u00a76 through \u00a7c{0}\u00a76. +potions=\u00a76\u85e5\u6c34\:\u00a7r {0}\u00a76. +powerToolAir=\u00a74\u547d\u4ee4\u4e0d\u80fd\u5c0d\u7740\u7a7a\u6c23\u4f7f\u7528. +powerToolAlreadySet=\u00a74\u6307\u4ee4 \u00a7c{0}\u00a74 \u5df2\u7d93\u8a2d\u5b9a\u7d66 \u00a7c{1}\u00a74\u3002 +powerToolAttach=\u00a7c{0}\u00a76 \u547d\u4ee4\u88ab\u7d81\u5b9a\u5230 {1} +powerToolClearAll=\u00a76\u6240\u6709\u5feb\u6377\u547d\u4ee4\u5df2\u88ab\u6e05\u9664 +powerToolList={1} \u6709\u5982\u4e0b\u547d\u4ee4\:\u00a74{0}\u00a7r. +powerToolListEmpty={0} \u6c92\u6709\u88ab\u7d81\u5b9a\u547d\u4ee4 +powerToolNoSuchCommandAssigned=\u00a74\u6307\u4ee4 \u00a7c{0}\u00a74 \u6c92\u6709\u8a2d\u5b9a\u7d66 \u00a7c{1}\u00a74\u3002 +powerToolRemove=\u00a76\u6307\u4ee4 \u00a7c{0}\u00a76 \u5df2\u7d93\u5f9e \u00a7c{1}\u00a76 \u79fb\u9664\u3002 +powerToolRemoveAll=\u00a76\u6240\u6709\u6307\u4ee4\u5df2\u7d93\u5f9e \u00a7c{0}\u00a76 \u79fb\u9664\u3002 +powerToolsDisabled=\u4f60\u6240\u6709\u7684\u5feb\u6377\u547d\u4ee4\u88ab\u51cd\u7d50 +powerToolsEnabled=\u4f60\u6240\u6709\u7684\u5feb\u6377\u547d\u4ee4\u88ab\u6fc0\u6d3b +questionFormat=\u00a72[\u63d0\u554f]\u00a7r {0} +readNextPage=\u00a76\u8f38\u5165 \u00a7c/{0} {1} \u00a76\u4f86\u95b1\u8b80\u4e0b\u4e00\u9801 +recipe=\u00a76Recipe for \u00a7c{0}\u00a76 (\u00a7c{1}\u00a76 of \u00a7c{2}\u00a76) +recipeBadIndex=\u9019\u500b\u7de8\u865f\u6c92\u6709\u5339\u914d\u7684\u5408\u6210\u516c\u5f0f. +recipeFurnace=\u00a76Smelt\: \u00a7c{0}\u00a76. +recipeGrid=\u00a7c{0}X \u00a76| \u00a7{1}X \u00a76| \u00a7{2}X +recipeGridItem=\u00a7c{0}X \u00a76is \u00a7c{1} +recipeMore=\u00a76Type /{0} \u00a7c{1}\u00a76 <\u6578\u5b57> \u53bb\u67e5\u770b\u66f4\u591a\u7684 \u00a7c{2}\u00a76\u5408\u6210\u516c\u5f0f. +recipeNone=\u5c0d{0}\u6c92\u6709\u5339\u914d\u7684\u5408\u6210\u516c\u5f0f +recipeNothing=\u6c92\u6709\u6771\u897f +recipeShapeless=\u00a76\u7d50\u5408 \u00a7c{0} +recipeWhere=\u00a76\u7576\: {0} +removed=\u00a76\u79fb\u9664\u4e86\u00a7c {0} \u00a76\u9805 +repair=\u00a76\u4f60\u5df2\u7d93\u6210\u529f\u4fee\u597d\u4e86\u4f60\u7684\uff1a \u00a7c{0}\u00a76\u3002 +repairAlreadyFixed=\u00a74\u8a72\u7269\u54c1\u7121\u9700\u4fee\u5fa9 +repairEnchanted=\u00a74\u4f60\u7121\u6b0a\u4fee\u5fa9\u9644\u9b54\u7269\u54c1 +repairInvalidType=\u00a74\u8a72\u7269\u54c1\u7121\u6cd5\u4fee\u5fa9 +repairNone=\u00a74\u9019\u88e1\u6c92\u6709\u9700\u8981\u88ab\u4fee\u7406\u7684\u7269\u54c1\u3002 +requestAccepted=\u00a76\u5df2\u63a5\u53d7\u50b3\u9001\u8acb\u6c42 +requestAcceptedFrom=\u00a7c{0}\u00a76 \u63a5\u53d7\u4e86\u4f60\u7684\u50b3\u9001\u8acb\u6c42 +requestDenied=\u00a76\u5df2\u62d2\u7d55\u50b3\u9001\u8acb\u6c42 +requestDeniedFrom=\u00a7c{0}\u00a76 \u62d2\u7d55\u4e86\u4f60\u7684\u50b3\u9001\u8acb\u6c42 +requestSent=\u00a76\u8acb\u6c42\u5df2\u767c\u9001\u7d66 {0}\u00a76 +requestTimedOut=\u00a74\u50b3\u9001\u8acb\u6c42\u8d85\u6642\u2026\u2026 +requiredBukkit=\u00a76\u4f60\u9700\u8981\u7248\u672c {0} \u4ee5\u4e0a\u7684bukkit.\u8acb\u81f3\u5b98\u7db2\u4e0b\u8f09 +resetBal=\u00a76\u6240\u6709\u5728\u7dda\u73a9\u5bb6\u7684\u8ca1\u7522\u5df2\u7d93\u91cd\u7f6e\u70ba \u00a7c{0} \u00a76\u3002 +resetBalAll=\u00a76\u6240\u6709\u73a9\u5bb6\u7684\u8ca1\u7522\u5df2\u7d93\u91cd\u7f6e\u70ba \u00a7c{0} \u00a76\u3002 +returnPlayerToJailError=\u00a74\u5617\u8a66\u5c07\u73a9\u5bb6\u00a7c {0} \u00a74\u95dc\u56de\u76e3\u7344 \u00a7c{1}\u00a74 \u6642\u767c\u751f\u932f\u8aa4\uff01 +runningPlayerMatch=\u00a76\u6b63\u5728\u641c\u7d22\u5339\u914d\u7684\u73a9\u5bb6 \u00a7c{0}\u00a76 (\u9019\u53ef\u80fd\u6703\u82b1\u8cbb\u4e00\u4e9b\u6642\u9593) +second=\u79d2 +seconds=\u79d2 +seenOffline=\u00a76\u73a9\u5bb6\u00a7c {0} \u00a76\u5728 \u00a7c{1}\u00a76 \u5df2\u7d93 \u00a74\u96e2\u7dda\u00a76\u3002 +seenOnline=\u00a76\u73a9\u5bb6\u00a7c {0} \u00a76\u5728 \u00a7c{1}\u00a76 \u5df2\u7d93 \u00a7a\u4e0a\u7dda\u00a76\u3002 +serverFull=\u670d\u52d9\u5668\u5df2\u6eff +serverTotal=\u00a76\u670d\u52d9\u5668\u7e3d\u548c\: {0} +setBal=\u00a7a\u4f60\u7684\u91d1\u9322\u5df2\u88ab\u8a2d\u7f6e\u70ba {0}. +setBalOthers=\u00a7a\u6210\u529f\u8a2d\u7f6e {0} \u7684\u91d1\u9322\u70ba {1}. +setSpawner=\u00a76\u6539\u8b8a\u751f\u602a\u78da\u578b\u614b\u70ba\u00a7c {0}\u00a76\u3002 +sheepMalformedColor=\u00a74\u7121\u6548\u7684\u984f\u8272 +shoutFormat=\u00a76[\u558a\u8a71]\u00a7r {0} +signFormatFail=\u00a74[{0}] +signFormatSuccess=\u00a71[{0}] +signFormatTemplate=[{0}] +signProtectInvalidLocation=\u00a74\u4f60\u4e0d\u5141\u8a31\u5728\u6b64\u653e\u7f6e\u724c\u5b50 +similarWarpExist=\u00a74\u4e00\u500b\u540c\u540d\u7684\u5730\u6a19\u5df2\u5b58\u5728 +slimeMalformedSize=\u00a74\u5927\u5c0f\u975e\u6cd5 +socialSpy=\u00a76SocialSpy for \u00a7c{0}\u00a76\: \u00a7c{1} +soloMob=\u00a74\u8a72\u751f\u7269\u559c\u6b61\u7368\u5c45 +spawnSet=\u00a76\u5df2\u70ba\u00a7c {0}\u00a76 \u7d44\u7684\u8a2d\u7f6e\u51fa\u751f\u9ede +spawned=\u5df2\u751f\u6210 +sudoExempt=\u00a74\u7121\u6cd5\u5f37\u5236\u4f7f\u6b64\u73a9\u5bb6\u57f7\u884c\u547d\u4ee4 +sudoRun=\u00a76Forcing\u00a7c {0} \u00a76to run\:\u00a7r /{1} +suicideMessage=\u00a76\u6c38\u5225\u4e86,\u6b98\u9177\u7684\u4e16\u754c\u2026\u2026 +suicideSuccess=\u00a7c{0} \u00a76\u7d50\u675f\u4e86\u4ed6\u81ea\u5df1\u7684\u751f\u547d +survival=\u751f\u5b58\u6a21\u5f0f +takenFromAccount=\u00a7a\u5f9e\u4f60\u7684\u8cec\u6236\u4e2d\u6263\u9664\u4e86 {0} +takenFromOthersAccount=\u00a7a\u5f9e {1} \u00a7a\u4e2d\u7684\u8cec\u6236\u6263\u9664\u4e86 {0}.\u76ee\u524d\u91d1\u9322\: {2} +teleportAAll=\u00a76\u5411\u6240\u6709\u73a9\u5bb6\u767c\u9001\u4e86\u50b3\u9001\u8acb\u6c42\u2026\u2026 +teleportAll=\u00a76\u50b3\u9001\u4e86\u6240\u6709\u73a9\u5bb6\u2026\u2026 +teleportAtoB=\u00a7c{0}\u00a76 \u5c07\u4f60\u50b3\u9001\u5230 \u00a7c{1}\u00a76\u3002 +teleportDisabled=\u00a7c{0}\u00a74 \u53d6\u6d88\u4e86\u50b3\u9001 +teleportHereRequest=\u00a7c{0}\u00a74 \u8acb\u6c42\u4f60\u50b3\u9001\u5230\u4ed6\u90a3\u88e1 +teleportNewPlayerError=\u00a74\u50b3\u9001\u65b0\u73a9\u5bb6\u5931\u6557 +teleportRequest=\u00a7c{0}\u00a76 \u8acb\u6c42\u50b3\u9001\u5230\u4f60\u9019\u88e1 +teleportRequestTimeoutInfo=\u00a76\u6b64\u8acb\u6c42\u5c07\u5728 {0} \u79d2\u5167\u53d6\u6d88 +teleportTop=\u00a76\u50b3\u9001\u5230\u9802\u90e8 +teleportationCommencing=\u00a76\u6e96\u5099\u50b3\u9001... +teleportationDisabled=\u00a76\u50b3\u9001 \u00a7c\u5df2\u7d93\u7981\u7528\u00a76\u3002 +teleportationDisabledFor=\u00a7c{0}\u00a76\u7684\u50b3\u9001 \u00a7c\u5df2\u7d93\u7981\u7528\u00a76\u3002 +teleportationEnabled=\u00a76\u50b3\u9001 \u00a7c\u5df2\u7d93\u555f\u7528\u00a76\u3002 +teleportationEnabledFor=\u00a7c{0}\u00a76\u7684\u50b3\u9001 \u00a7c\u5df2\u7d93\u555f\u7528\u00a76\u3002 +teleporting=\u00a76\u6b63\u5728\u50b3\u9001... +teleportToPlayer=\u00a76\u50b3\u9001\u5230 \u00a7c{0}\u00a76\u3002 +tempBanned=\u00a7cYou have been temporarily banned for {0}\:\n\u00a7r{2} +tempbanExempt=\u00a76\u4f60\u7121\u6cd5\u81e8\u6642\u5c01\u7981\u6389\u8a72\u73a9\u5bb6 +thunder=\u00a76\u4f60 \u00a7c{0} \u00a76\u4e86\u4f60\u7684\u4e16\u754c\u7684\u9583\u96fb +thunderDuration=\u00a76\u4f60 \u00a7c{0} \u00a76\u4e86\u4f60\u7684\u4e16\u754c\u7684\u9583\u96fb\u00a7c {1} \u00a76\u79d2 +timeBeforeHeal=\u00a76\u6cbb\u7642\u51b7\u537b\:{0} +timeBeforeTeleport=\u00a76\u50b3\u9001\u51b7\u537b\:{0} +timeFormat=\u00a7c{0}\u00a76 \u6216 \u00a7c{1}\u00a76 \u6216 \u00a7c{2}\u00a76 +timeSetPermission=\u00a74\u4f60\u6c92\u6709\u8a2d\u7f6e\u6642\u9593\u7684\u6b0a\u9650 +timeWorldCurrent=\u00a76\u76ee\u524d\u4e16\u754c {0} \u7684\u6642\u9593\u662f \u00a73{1} +timeWorldSet=\u00a76\u6642\u9593\u88ab\u8a2d\u7f6e\u70ba {0} \u65bc\u4e16\u754c\:\u00a74{1} +totalWorthAll=\u00a7a\u51fa\u552e\u7684\u6240\u6709\u7269\u54c1\u548c\u65b9\u584a\uff0c\u7e3d\u50f9\u503c {1}. +totalWorthBlocks=\u00a7a\u51fa\u552e\u7684\u6240\u6709\u65b9\u584a\u584a\uff0c\u7e3d\u50f9\u503c {1}. +tps=\u00a76\u7576\u524d TPS \= {0} +tradeSignEmpty=\u00a74\u4ea4\u6613\u724c\u4e0a\u6c92\u6709\u4f60\u53ef\u7372\u5f97\u7684\u6771\u897f +tradeSignEmptyOwner=\u00a74\u4ea4\u6613\u724c\u4e0a\u6c92\u6709\u4f60\u53ef\u6536\u96c6\u7684\u6771\u897f +treeFailure=\u00a74\u751f\u6210\u6a39\u6728\u5931\u6557,\u5728\u8349\u584a\u4e0a\u6216\u571f\u4e0a\u518d\u8a66\u4e00\u6b21 +treeSpawned=\u00a76\u751f\u6210\u6a39\u6728\u6210\u529f +true=\u00a7a\u662f\u00a7r +typeTpaccept=\u00a76\u82e5\u60f3\u63a5\u53d7\u50b3\u9001,\u8f38\u5165 \u00a74/tpaccept\u00a76 +typeTpdeny=\u00a76\u82e5\u60f3\u62d2\u7d55\u50b3\u9001,\u8f38\u5165 \u00a74/tpdeny\u00a76 +typeWorldName=\u00a76\u4f60\u4e5f\u53ef\u4ee5\u8f38\u5165\u6307\u5b9a\u7684\u4e16\u754c\u7684\u540d\u5b57 +unableToSpawnMob=\u00a74\u751f\u6210\u751f\u7269\u5931\u6557 +unignorePlayer=\u00a76\u4f60\u5df2\u4e0d\u518d\u5c4f\u853d\u73a9\u5bb6 {0} +unknownItemId=\u00a74\u672a\u77e5\u7684\u7269\u54c1ID\:{0} +unknownItemInList=\u00a74\u672a\u77e5\u7684\u7269\u54c1 {0} \u65bc {1} \u5217\u8868 +unknownItemName=\u00a74\u672a\u77e5\u7684\u7269\u54c1\u540d\u7a31\:{0} +unlimitedItemPermission=\u00a74\u6c92\u6709\u7121\u9650\u7269\u54c1 \u00a7c{0}\u00a74 \u7684\u6b0a\u9650\u3002 +unlimitedItems=\u00a76\u7121\u9650\u7269\u54c1\: +unmutedPlayer=\u00a76\u73a9\u5bb6 \u00a7c{0}\u00a76 \u88ab\u5141\u8a31\u767c\u8a00 +unvanishedReload=\u00a74\u5916\u639b\u7a0b\u5f0f\u91cd\u8f09\u8feb\u4f7f\u4f60\u7684\u96b1\u8eab\u6a21\u5f0f\u5931\u6548. +upgradingFilesError=\u5347\u7d1a\u6587\u4ef6\u6642\u767c\u751f\u932f\u8aa4 +uptime=\u00a76\u904b\u884c\u6642\u9593\:\u00a7c {0} +userAFK=\u00a75{0} \u00a75\u73fe\u5728\u96e2\u958b, \u53ef\u80fd\u66ab\u6642\u6c92\u8fa6\u6cd5\u56de\u61c9. +userDoesNotExist=\u00a74\u73a9\u5bb6 \u00a7c{0} \u00a74\u4e0d\u5b58\u5728. +userIsAway=\u00a7d{0} \u00a7d\u66ab\u6642\u96e2\u958b\u4e86 +userIsNotAway=\u00a7d{0} \u00a7d\u56de\u4f86\u4e86 +userJailed=\u00a76\u4f60\u5df2\u88ab\u76e3\u7981 +userUnknown=\u00a74\u8b66\u544a\: \u9019\u500b\u73a9\u5bb6 \u00a7c{0}\u00a74 \u5f9e\u4f86\u6c92\u6709\u52a0\u5165\u904e\u670d\u52d9\u5668. +userdataMoveBackError=\u79fb\u52d5 userdata/{0}.tmp \u5230 userdata/{1} \u5931\u6557 +userdataMoveError=\u79fb\u52d5 userdata/{0} \u5230 userdata/{1}.tmp \u5931\u6557 +usingTempFolderForTesting=\u4f7f\u7528\u7de9\u5b58\u6587\u4ef6\u593e\u4f86\u6e2c\u8a66\: +vanished=\u00a76\u5df2\u9032\u5165\u96b1\u8eab\u6a21\u5f0f,\u73a9\u5bb6\u5c07\u7121\u6cd5\u770b\u5230\u4f60. +versionMismatch=\u00a74\u7248\u672c\u4e0d\u5339\u914d\uff01\u8acb\u5347\u7d1a {0} \u5230\u76f8\u540c\u7248\u672c. +versionMismatchAll=\u00a74\u7248\u672c\u4e0d\u5339\u914d\uff01\u8acb\u5347\u7d1a\u6240\u6709Essentials\u7cfb\u5217\u7684\u5916\u639b\u7a0b\u5f0f\u5230\u76f8\u540c\u7248\u672c. +voiceSilenced=\u00a76\u5df2\u975c\u97f3 +walking=\u884c\u8d70\u4e2d +warpDeleteError=\u00a74\u522a\u9664\u5730\u6a19\u6587\u4ef6\u6642\u767c\u751f\u932f\u8aa4. +warpList={0} +warpListPermission=\u00a74\u4f60\u6c92\u6709\u5217\u51fa\u5730\u6a19\u7684\u6b0a\u9650. +warpNotExist=\u00a74\u8a72\u5730\u6a19\u4e0d\u5b58\u5728 +warpOverwrite=\u00a74\u4f60\u4e0d\u80fd\u91cd\u7f6e\u8a72\u5730\u8868 +warpSet=\u00a76\u5730\u6a19 \u00a7c{0} \u00a76\u5df2\u8a2d\u7f6e +warpUsePermission=\u00a74\u4f60\u6c92\u6709\u4f7f\u7528\u8a72\u5730\u6a19\u7684\u6b0a\u9650 +warpingTo=\u00a76\u50b3\u9001\u5230\u5730\u6a19 \u00a7c{0} +warps=\u00a76\u5730\u6a19\: \u00a7r{0} +warpsCount=\u00a76\u9019\u4e9b\u662f\u00a7c {0} \u00a76warps\uff0c\u986f\u793a\u9801\u6578\uff1a\u7b2c \u00a7c{1} \u00a76\u9801\uff0c\u5171 \u00a7c{2}\u00a76 \u9801\u3002 +weatherStorm=\u00a76\u4f60\u5c07 {0} \u7684\u5929\u6c23\u6539\u70ba\u96e8\u96ea +weatherStormFor=\u00a76\u4f60\u5c07 {0} \u7684\u5929\u6c23\u7684\u6539\u70ba\u96e8\u96ea,\u6301\u7e8c {1} \u79d2 +weatherSun=\u00a76\u4f60\u5c07 {0} \u7684\u5929\u6c23\u6539\u70ba\u6674\u5929 +weatherSunFor=\u00a76\u4f60\u5c07 {0} \u7684\u5929\u6c23\u7684\u6539\u70ba\u6674\u5929,\u6301\u7e8c {1} \u79d2 +whoisAFK=\u00a76 - \u66ab\u96e2\:\u00a7r {0} +whoisBanned=\u00a76 - \u5c01\u7981\:\u00a7r {0} +whoisExp=\u00a76 - \u7d93\u9a57\:\u00a7r {0} (\u7b49\u7d1a {1}) +whoisFly=\u00a76 - \u98db\u884c\u6a21\u5f0f\:\u00a7r {0} ({1}) +whoisGamemode=\u00a76 - \u904a\u6232\u6a21\u5f0f\:\u00a7r {0} +whoisGeoLocation=\u00a76 - \u5730\u7406\u4f4d\u7f6e\:\u00a7r {0} +whoisGod=\u00a76 - \u4e0a\u5e1d\u6a21\u5f0f\:\u00a7r {0} +whoisHealth=\u00a76 - \u751f\u547d\:\u00a7r {0}/20 +whoisIPAddress=\u00a76 - IP\u4f4d\u5740\:\u00a7r {0} +whoisJail=\u00a76 - \u76e3\u7344\:\u00a7r {0} +whoisLocation=\u00a76 - \u5750\u6a19\:\u00a7r ({0}, {1}, {2}, {3}) +whoisMoney=\u00a76 - \u73fe\u91d1\:\u00a7r {0} +whoisMuted=\u00a76 - \u7981\u8a00\:\u00a7r {0} +whoisNick=\u00a76 - \u66b1\u7a31\:\u00a7r {0} +whoisOp=\u00a76 - OP\:\u00a7r {0} +whoisTop=\u00a76 \=\=\=\=\=\= \u00a7c {0} \u00a76\u7684\u8cc7\u6599\=\=\=\=\=\= +worth=\u00a76\u4e00\u7d44 {0} \u50f9\u503c \u00a74{1}\u00a76\uff08{2} \u55ae\u4f4d\u7269\u54c1,\u6bcf\u500b\u50f9\u503c {3}\uff09 +worthMeta=\u00a7a\u4e00\u7d44\u526f\u78bc\u70ba {1} \u7684 {0} \u50f9\u503c \u00a7c{2}\u00a76\uff08{3} \u55ae\u4f4d\u7269\u54c1,\u6bcf\u500b\u50f9\u503c {4}\uff09 +worthSet=\u00a76\u50f9\u683c\u5df2\u8a2d\u7f6e +year=\u5e74 +years=\u5e74 +youAreHealed=\u00a76\u4f60\u5df2\u88ab\u6cbb\u7642 +youHaveNewMail=\u00a76\u4f60\u64c1\u6709 \u00a7c{0}\u00a76 \u689d\u6d88\u606f\uff01\u00a7r\u8f38\u5165 \u00a7c/mail read\u00a76 \u4f86\u67e5\u770b +whoisHunger=\u00a76 - \u98e2\u9913\:\u00a7r {0}/20 (+{1} \u98fd\u98df\u5ea6) +kitDelay=\u00a7m{0}\u00a7r +giveSpawnFailure=\u00a74\u6c92\u6709\u8db3\u5920\u7684\u7a7a\u9593, \u00a7c{0} \u00a7c{1} \u00a74\u5df2\u907a\u5931. +noKitGroup=\u00a74\u4f60\u6c92\u6709\u6b0a\u9650\u4f7f\u7528\u9019\u500b\u5de5\u5177\u7d44. +inventoryClearingFromAll=\u00a76\u6e05\u9664\u6240\u6709\u73a9\u5bb6\u7684\u96a8\u8eab\u7269\u54c1... +inventoryClearingAllItems=\u00a76\u6e05\u9664{0}\u7684\u96a8\u8eab\u7269\u54c1\u00a76. +inventoryClearingAllArmor=\u00a76\u6e05\u9664{0}\u7684\u96a8\u8eab\u7269\u54c1\u548c\u88dd\u5099\u00a76.\u00a0 +inventoryClearingAllStack=\u00a76\u6e05\u9664\u6240\u6709{1}\u00a76\u7684\u00a7c{0}\u00a76. +inventoryClearingStack=\u00a76\u6e05\u9664{2}\u7684\u00a7c{0}\u00a76\u500b\u00a7c{1}\u00a76. +inventoryClearFail=\u00a7\u73a9\u5bb6{0}\u00a74\u4e26\u6c92\u6709\u00a7c{1}\u00a74\u500b\u00a7c{2}\u00a74. +localNoOne= +totalSellableAll=\u00a7a\u6240\u6709\u53ef\u8ce3\u51fa\u7269\u54c1\u548c\u65b9\u584a\u7684\u50f9\u503c\u70ba\u00a7c{1}\u00a7a. +totalSellableBlocks=\u00a7a\u6240\u6709\u53ef\u8ce3\u51fa\u65b9\u584a\u7684\u50f9\u503c\u70ba\u00a7c{1}\u00a7a. +radiusTooBig=\u00a74\u7bc4\u570d\u592a\u5927\! \u6700\u5927\u7bc4\u570d\u70ba{0}. +isIpBanned=\u00a76IP \u00a7c{0} \u00a76\u5df2\u88ab\u5c01\u9396\u3002 +mobDataList=\u00a76\u6709\u6548\u7684\u751f\u7269\u8cc7\u6599\uff1a\u00a7r {0} +vanish=\u00a76\u5c07 {0} \u00a76\u7684\u96b1\u5f62\u6a21\u5f0f {1} +noLocationFound=\u00a74\u627e\u4e0d\u5230\u6709\u6548\u5730\u9ede\u3002 +coordsKeyword={0}, {1}, {2} +banExemptOffline=\u00a74\u4f60\u4e0d\u80fd\u5c01\u9396\u96e2\u7dda\u73a9\u5bb6\u3002 +tempbanExemptOffline=\u00a74\u4f60\u4e0d\u80fd\u66ab\u6642\u5c01\u9396\u96e2\u7dda\u73a9\u5bb6\u3002 +mayNotJailOffline=\u00a74\u4f60\u4e0d\u80fd\u5c07\u96e2\u7dda\u73a9\u5bb6\u95dc\u5165\u76e3\u7344\u3002 +muteExemptOffline=\u00a74\u4f60\u4e0d\u80fd\u5c07\u96e2\u7dda\u73a9\u5bb6\u7981\u8a00 +ignoreExempt=\u00a74\u4f60\u4e0d\u80fd\u5ffd\u7565\u90a3\u500b\u73a9\u5bb6\u3002 +unsafeTeleportDestination=\u00a74\u50b3\u9001\u76ee\u7684\u5730\u4e0d\u5b89\u5168\u4e14\u5b89\u5168\u50b3\u9001\u8655\u65bc\u7981\u7528\u72c0\u614b +noMetaJson=\u9019\u500b\u7248\u672c\u7684 Bukkit \u4e0d\u652f\u63f4 JSON \u4e2d\u7e7c\u8cc7\u6599 +maxMoney=\u00a74\u9019\u7b46\u4ea4\u6613\u5c07\u8d85\u51fa\u6b64\u5e33\u6236\u7684\u9918\u984d\u9650\u5236 +skullChanged=\u00a76\u982d\u9871\u4fee\u6539\u70ba \u00a7c{0}\u00a76\u3002 +alphaNames=\u00a74\u73a9\u5bb6\u540d\u7a31\u53ea\u80fd\u7531\u5b57\u6bcd\u3001\u6578\u5b57\u3001\u5e95\u7dda\u7d44\u6210\u3002 +givenSkull=\u00a76\u4f60\u53d6\u5f97\u4e86\u00a7c {0} \u00a76\u7684\u982d\u9871\u3002 +noPermissionSkull=\u00a74\u4f60\u6c92\u6709\u6b0a\u9650\u4fee\u6539\u9019\u500b\u982d\u9871\u3002 +teleportInvalidLocation=\u5ea7\u6a19\u7684\u6578\u503c\u4e0d\u5f97\u8d85\u904e 30000000 +invalidSkull=\u00a74\u8acb\u62ff\u8457\u73a9\u5bb6\u982d\u9871 +weatherInvalidWorld=\u627e\u4e0d\u5230\u540d\u70ba {0} \u7684\u4e16\u754c\uff01 +gameModeInvalid=\u00a74\u4f60\u5fc5\u9808\u6307\u5b9a\u4e00\u500b\u6709\u6548\u7684\u73a9\u5bb6\u6216\u6a21\u5f0f +mailTooLong=\u00a74\u90f5\u4ef6\u8a0a\u606f\u904e\u9577\uff0c\u8acb\u4e0d\u8981\u8d85\u904e1000\u5b57\u3002 +mailDelay=\u5728\u6700\u5f8c\u4e00\u5206\u9418\u5167\u767c\u9001\u592a\u591a\u90f5\u4ef6\uff0c\u6700\u591a {0} \u5c01 +seenAccounts=\u00a76Player has also been known as\:\u00a7c {0} +unableToSpawnItem=\u00a74\u7121\u6cd5\u751f\u6210 \u00a7c{0}\u00a74\uff0c\u9019\u4e0d\u662f\u53ef\u751f\u6210\u7684\u7269\u4ef6\u3002 +itemsConverted=\u00a76Converted all items into blocks. +itemsNotConverted=\u00a74You have no items that can be converted into blocks. +mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\: +mailMessage={0} + +whoisTempBanned=\u00a76 - Ban expires:\u00a7r {0} +playerTempBanned=\u00a76Player \u00a7c{0}\u00a76 temporarily banned \u00a7c{1}\u00a76 for \u00a7c{2}\u00a76: \u00a7c{3}\u00a76. +mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1} diff --git a/Essentials/src/messages_zh_TW.properties b/Essentials/src/messages_zh_TW.properties new file mode 100644 index 0000000000..b49ee4e52f --- /dev/null +++ b/Essentials/src/messages_zh_TW.properties @@ -0,0 +1,558 @@ +#X-Generator: crowdin.net +#version: TeamCity +# Single quotes have to be doubled: '' +# Translations start here +# by: +action=\u00a75* {0} \u00a75{1} +addedToAccount=\u00a7a{0} \u5df2\u6dfb\u52a0\u5230\u4f60\u7684\u9280\u884c\u8cec\u6236 +addedToOthersAccount=\u00a7a{0} \u5df2\u88ab\u6dfb\u52a0\u5230 {1} \u00a7a\u7684\u8cec\u6236.\u76ee\u524d\u9918\u984d\: {2} +adventure=\u5192\u96aa\u6a21\u5f0f +alertBroke=\u7834\u58de\: +alertFormat=\u00a73[{0}] \u00a7r {1} \u00a76 {2} \u65bc\: {3} +alertPlaced=\u653e\u7f6e\: +alertUsed=\u4f7f\u7528\: +antiBuildBreak=\u00a74\u4f60\u6c92\u6709\u8a31\u53ef\u6b0a\u7834\u58de\u00a74 {0} \u00a74\u9019\u500b\u65b9\u584a. +antiBuildCraft=\u00a74\u4f60\u6c92\u6709\u8a31\u53ef\u6b0a\u653e\u7f6e\u00a74 {0} \u00a74\u9019\u500b\u65b9\u584a. +antiBuildDrop=\u00a74\u4f60\u6c92\u6709\u8a31\u53ef\u6b0a\u653e\u7f6e\u00a74 {0} \u00a74\u9019\u500b\u65b9\u584a. +antiBuildInteract=\u00a74\u4f60\u6c92\u6709\u8a31\u53ef\u6b0a\u8207\u00a74 {0}\u00a74\u4ea4\u4e92. +antiBuildPlace=\u00a74\u4f60\u6c92\u6709\u8a31\u53ef\u6b0a\u653e\u7f6e\u00a74 {0} \u00a74\u9019\u500b\u65b9\u584a. +antiBuildUse=\u00a74\u4f60\u6c92\u6709\u8a31\u53ef\u6b0a\u4f7f\u7528\u00a74 {0}\u00a74. +autoAfkKickReason=\u4f60\u56e0\u70ba\u9577\u6642\u9593\u672a\u80fd\u5728\u904a\u6232\u4e2d\u505a\u51fa\u52d5\u4f5c\u4e26\u8d85\u904e {0} \u5206\u9418\u800c\u88ab\u4f3a\u670d\u5668\u8acb\u51fa\uff01 +backAfterDeath=\u00a76\u4f7f\u7528\u300c/back\u300d\u6307\u4ee4\u4f86\u56de\u5230\u6b7b\u4ea1\u5730\u9ede +backUsageMsg=\u00a76\u56de\u5230\u4e0a\u4e00\u4f4d\u7f6e +backupDisabled=\u00a74\u5099\u4efd\u914d\u7f6e\u6587\u4ef6\u672a\u88ab\u8a2d\u7f6e. +backupFinished=\u00a76\u5099\u4efd\u5b8c\u6210. +backupStarted=\u00a76\u5099\u4efd\u958b\u59cb +balance=\u00a7a\u73fe\u91d1\:{0} +balanceOther=\u00a7a{0}\u7684\u91d1\u9322\:\u00a7c {1} +balanceTop=\u00a76\u91d1\u9322\u6392\u884c\:{0} +banExempt=\u00a74\u4f60\u4e0d\u80fd\u5c01\u7981\u90a3\u500b\u73a9\u5bb6\u00a7r +banFormat=\u00a74\u5df2\u5c01\u7981\:\u00a7r {0} +bed=\u00a77\u5e8a\u00a7r +bedMissing=\u00a74\u4f60\u7684\u5e8a\u5df2\u4e1f\u5931\u6216\u963b\u64cb +bedNull=\u00a7m\u5e8a\u00a7r +bedSet=\u00a76\u5df2\u8a2d\u7f6e\u5e8a +bigTreeFailure=\u00a74\u751f\u6210\u5927\u6a39\u5931\u6557.\u5728\u571f\u584a\u6216\u8349\u584a\u4e0a\u9762\u518d\u8a66\u4e00\u6b21 +bigTreeSuccess=\u00a76\u5df2\u751f\u6210\u5927\u6a39 +blockList=\u00a76Essentials \u63d2\u4ef6\u5c07\u50b3\u905e\u4e0b\u5217\u6307\u4ee4\u7d66\u5176\u4ed6\u63d2\u4ef6\: +bookAuthorSet=\u00a76\u9019\u672c\u66f8\u7684\u4f5c\u8005\u5df2\u88ab\u8a2d\u7f6e\u70ba {0}. +bookLocked=\u00a76\u9019\u672c\u66f8\u73fe\u5728\u6b63\u88ab\u9396\u5b9a. +bookTitleSet=\u00a76\u9019\u672c\u66f8\u7684\u6a19\u984c\u5df2\u88ab\u8a2d\u7f6e\u70ba {0}. +broadcast=\u00a7r\u00a76[\u00a74\u516c\u544a\u00a76]\u00a7a {0} +buildAlert=\u00a74\u4f60\u6c92\u6709\u5efa\u9020\u8a31\u53ef\u6b0a\! +bukkitFormatChanged=Bukkit\u7248\u672c\u5df2\u6539\u8b8a +burnMsg=\u00a76\u4f60\u5c07\u4f7f \u00a74{0} \u00a76\u71c3\u71d2\u00a74 {1} \u00a76\u79d2 +canTalkAgain=\u00a76\u4f60\u5df2\u7372\u5f97\u767c\u8a00\u7684\u8cc7\u683c +cannotStackMob=\u00a74\u60a8\u6c92\u6709\u8a31\u53ef\u6b0a\u5806\u758a\u591a\u500b\u5c0f\u602a. +cantFindGeoIpDB=\u627e\u4e0d\u5230GeoIP\u8cc7\u6599\u5eab\! +cantReadGeoIpDB=GeoIP\u8cc7\u6599\u5eab\u8b80\u53d6\u5931\u6557\! +cantSpawnItem=\u00a74\u4f60\u6c92\u6709\u8a31\u53ef\u6b0a\u751f\u6210\u7269\u54c1\u00a7c {0}\u00a74. +chatTypeAdmin=[A] +chatTypeLocal=[L] +chatTypeSpy=[\u76e3\u807d] +cleaned=\u73a9\u5bb6\u8cc7\u6599\u5df2\u6e05\u9664 +cleaning=\u6e05\u9664\u73a9\u5bb6\u8cc7\u6599... +commandFailed=\u6307\u4ee4 {0} \u5931\u6557\: +commandHelpFailedForPlugin=\u7121\u6cd5\u53d6\u5f97\u6b64\u63d2\u4ef6\u7684\u8aaa\u660e\:{0} +commandNotLoaded=\u00a74 {0} \u6307\u4ee4\u8f09\u5165\u5931\u6557 +compassBearing=\u00a76\u65b9\u5411\:{0}\uff08{1}\u5ea6\uff09 +configFileMoveError=\u79fb\u52d5config.yml\u6587\u4ef6\u5230\u5099\u4efd\u4f4d\u7f6e\u5931\u6557 +configFileRenameError=\u91cd\u547d\u540d\u7de9\u5b58\u6587\u4ef6\u70baconfig.yml\u5931\u6557 +connectedPlayers=\u00a76\u76ee\u524d\u5728\u7dda\: \u00a7r +connectionFailed=\u9023\u63a5\u5931\u6557. +cooldownWithMessage=\u00a74\u51b7\u537b\u6642\u9593\:{0} +corruptNodeInConfig=\u00a74\u6ce8\u610f\:\u4f60\u7684\u914d\u7f6e\u5167\u5b58\u5728\u4e00\u500b\u640d\u58de\u7684 {0} \u7bc0\u9ede +couldNotFindTemplate=\u00a74\u7121\u6cd5\u627e\u5230\u6a21\u7248 {0} +creatingConfigFromTemplate=\u5f9e\u6a21\u7248\:{0} \u5275\u5efa\u914d\u7f6e +creatingEmptyConfig=\u5275\u5efa\u7a7a\u7684\u914d\u7f6e\:{0} +creative=\u5275\u9020\u6a21\u5f0f +currency={0}{1} +currentWorld=\u00a76\u7576\u524d\u4e16\u754c\:\u00a74 {0} +day=\u5929 +days=\u5929 +defaultBanReason=\u767b\u9304\u5931\u6557\!\u60a8\u7684\u5e33\u865f\u5df2\u88ab\u6b64\u4f3a\u670d\u5668\u5c01\u7981\! +deleteFileError=\u7121\u6cd5\u522a\u9664\u6587\u4ef6\:{0} +deleteHome=\u00a76\u5bb6 \u00a74{0} \u00a76\u88ab\u79fb\u9664 +deleteJail=\u00a76\u76e3\u7344 \u00a74{0} \u00a76\u88ab\u79fb\u9664 +deleteWarp=\u00a76\u5730\u6a19 \u00a74{0} \u00a76\u88ab\u79fb\u9664 +deniedAccessCommand=\u00a7c{0} \u00a74\u88ab\u62d2\u7d55\u4f7f\u7528\u547d\u4ee4 +denyBookEdit=\u00a74\u4f60\u4e0d\u80fd\u89e3\u9396\u9019\u672c\u66f8. +denyChangeAuthor=\u00a74\u4f60\u4e0d\u80fd\u6539\u8b8a\u9019\u672c\u66f8\u7684\u4f5c\u8005. +denyChangeTitle=\u00a74\u4f60\u4e0d\u80fd\u6539\u8b8a\u9019\u672c\u66f8\u7684\u6a19\u984c. +depth=\u00a76\u4f60\u4f4d\u65bc\u6d77\u62d40\u683c\u8655 +depthAboveSea=\u00a76\u4f60\u4f4d\u65bc\u6d77\u62d4\u6b63\u00a7c{0}\u00a76\u683c\u8655 +depthBelowSea=\u00a76\u4f60\u4f4d\u65bc\u6d77\u62d4\u8ca0\u00a7c{0}\u00a76\u683c\u8655 +destinationNotSet=\u76ee\u7684\u5730\u672a\u8a2d\u7f6e. +disableUnlimited=\u00a76\u53d6\u6d88\u4e86 {1} \u7684\u7121\u9650\u653e\u7f6e \u00a7c{0} \u00a76\u7684\u80fd\u529b +disabled=\u95dc\u9589 +disabledToSpawnMob=\u00a74\u5df2\u7981\u6b62\u6b64\u751f\u7269\u7684\u751f\u6210. +distance=\u00a76\u8ddd\u96e2\: {0} +dontMoveMessage=\u00a76\u50b3\u9001\u5c07\u5728{0}\u5167\u958b\u59cb.\u4e0d\u8981\u79fb\u52d5 +downloadingGeoIp=\u4e0b\u8f09GeoIP\u8cc7\u6599\u5eab\u4e2d +duplicatedUserdata=\u8907\u88fd\u4e86\u73a9\u5bb6\u5b58\u6a94\:{0} \u548c {1} +durability=\u00a76\u9019\u500b\u5de5\u5177\u9084\u6709 \u00a74{0}\u00a76 \u6301\u4e45 +editBookContents=\u00a7e\u4f60\u73fe\u5728\u53ef\u4ee5\u7de8\u8f2f\u9019\u672c\u66f8\u7684\u5167\u5bb9. +enableUnlimited=\u00a76\u7d66\u4e88 \u00a7c{1}\u00a76 \u7121\u9650\u7684\u00a7c {0} \u00a76 \u3002 +enabled=\u958b\u555f +enchantmentApplied=\u00a76\u9644\u9b54 \u00a7c{0} \u00a76\u5df2\u88ab\u61c9\u7528\u5230\u4f60\u624b\u4e2d\u7684\u5de5\u5177. +enchantmentNotFound=\u00a74\u672a\u627e\u5230\u8a72\u9644\u9b54. +enchantmentPerm=\u00a74\u4f60\u6c92\u6709\u9032\u884c\u00a7c {0} \u00a74\u9644\u9b54\u7684\u8a31\u53ef\u6b0a. +enchantmentRemoved=\u00a76\u9644\u9b54 \u00a7c{0} \u00a76\u5df2\u5f9e\u4f60\u624b\u4e0a\u7684\u5de5\u5177\u79fb\u9664 +enchantments=\u00a76\u9644\u9b54\: \u00a7r{0} +errorCallingCommand=\u932f\u8aa4\u7684\u547c\u53eb\u6307\u4ee4\:/{0} +errorWithMessage=\u00a7c\u932f\u8aa4\:{0} +essentialsHelp1=Essentials\u7121\u6cd5\u5c07\u5176\u6253\u958b +essentialsHelp2=Essentials\u7121\u6cd5\u5c07\u5176\u6253\u958b +essentialsReload=\u00a76Essentials \u5df2\u91cd\u65b0\u8f09\u5165\u00a7c {0}\u3002 +exp=\u00a74{0} \u00a76\u64c1\u6709\u00a7c {1} \u00a76\u7d93\u9a57\u503c (\u7b49\u7d1a\u00a7c {2}\u00a76) \u9700\u8981\u00a7c {3} \u00a76\u7d93\u9a57\u624d\u80fd\u5347\u7d1a. +expSet=\u00a7c\u4f60\u5c07{0} \u00a76\u7684\u7d93\u9a57\u8a2d\u7f6e\u70ba\u00a7c {1} \u00a76\u7d93\u9a57\u503c. +extinguish=\u00a76\u4f60\u7184\u6ec5\u4e86\u4f60\u81ea\u5df1\u8eab\u4e0a\u7684\u706b +extinguishOthers=\u00a76\u4f60\u7184\u6ec5\u4e86 {0} \u00a76\u8eab\u4e0a\u7684\u706b +failedToCloseConfig=\u95dc\u9589\u914d\u7f6e {0} \u5931\u6557 +failedToCreateConfig=\u5275\u5efa\u914d\u7f6e {0} \u5931\u6557 +failedToWriteConfig=\u5beb\u5165\u914d\u7f6e {0} \u5931\u6557 +false=\u00a74\u5426\u00a7r +feed=\u5df2\u7d93\u98fd\u548c,\u7121\u6cd5\u589e\u52a0\u98e2\u9913\u5ea6. +feedOther=\u00a76You satiated the appetite of \u00a7c{0}\u00a76. +fileRenameError=\u91cd\u547d\u540d\u6587\u4ef6 {0} \u5931\u6557 +fireworkColor=\u00a74\u4f7f\u7528\u4e86\u7121\u6548\u7684\u7159\u82b1\u586b\u5145\u53c3\u6578\uff0c\u5fc5\u9808\u9996\u5148\u8a2d\u7f6e\u4e00\u500b\u984f\u8272\u3002 +fireworkEffectsCleared=\u00a76\u5f9e\u6301\u6709\u7684\u7269\u54c1\u4e2d\u79fb\u9664\u4e86\u6240\u6709\u7279\u6548. +fireworkSyntax=\u00a76\u7159\u82b1\u53c3\u6578\:\u00a7c color\:<\u984f\u8272> [fade\:<\u6de1\u51fa\u984f\u8272>] [shape\:<\u5f62\u614b>] [effect\:<\u7279\u6548>]\n\u00a76\u8981\u4f7f\u7528\u591a\u500b\u984f\u8272/\u7279\u6548, \u4f7f\u7528\u9017\u865f\: \u00a7cred,blue,pink\n\u00a76\u5f62\u72c0\:\u00a7c star, ball, large, creeper, burst \u00a76\u7279\u6548\:\u00a7c trail, twinkle. +flyMode=\u00a76 \u5df2\u70ba\u00a7c{1}\u00a76\u8a2d\u7f6e\u4e86\u98db\u884c\u6a21\u5f0f\u70ba\u00a7c{0}. +flying=\u98db\u884c\u4e2d +foreverAlone=\u00a74\u4f60\u6c92\u6709\u53ef\u56de\u5fa9\u7684\u73a9\u5bb6 +fullStack=\u00a74\u4f60\u7684\u7269\u54c1\u5df2\u7d93\u6700\u591a\u4e86. +gameMode=\u00a76\u5c07\u00a7c{1}\u00a76\u7684\u904a\u6232\u6a21\u5f0f\u8a2d\u5b9a\u70ba\u00a7c {0} \u00a76\u3002 +gcWorld=\u00a76{0} "\u00a7c{1}\u00a76"\: \u00a7c{2}\u00a76 \u5340\u584a, \u00a7c{3}\u00a76 \u5be6\u9ad4, \u00a7c{4}\u00a76 \u5340\u584a\u8cc7\u6599. +gcfree=\u7a7a\u9592\u5167\u5b58\: \u00a7c{0} MB +gcmax=\u6700\u5927\u5167\u5b58\: \u00a7c{0} MB +gctotal=\u5df2\u5206\u914d\u5167\u5b58\: \u00a7c{0} MB +geoIpUrlEmpty=GeoIP\u4e0b\u8f09\u9023\u7d50\u70ba\u7a7a +geoIpUrlInvalid=GeoIP\u4e0b\u8f09\u9023\u7d50\u5931\u6548 +geoipJoinFormat=\u73a9\u5bb6 {0} \u4f86\u81ea\u65bc {1} +giveSpawn=\u00a76\u7d66\u4e88\u00a7c {2} \u00a76 \u00a7c {0} \u500b\u00a7c {1}\u00a76. +godDisabledFor=\u00a7cdisabled\u00a76 for\u00a7c {0} +godEnabledFor=\u00a74\u958b\u555f\u4e86\u00a7c {0} \u00a76\u7684\u4e0a\u5e1d\u6a21\u5f0f +godMode=\u00a76\u4e0a\u5e1d\u6a21\u5f0f \u00a7c{0} +groupDoesNotExist=\u00a74\u7576\u524d\u7d44\u6c92\u6709\u4eba\u5728\u7dda\! +groupNumber=\u00a7c{0}\u00a7f \u5728\u7dda, \u60f3\u8981\u7372\u53d6\u5168\u90e8\u4f7f\u7528\:\u00a7c /{1} {2} +hatArmor=\u00a74\u932f\u8aa4\:\u4f60\u7121\u6cd5\u4f7f\u7528\u9019\u500b\u7269\u54c1\u4f5c\u70ba\u5e3d\u5b50\! +hatEmpty=\u00a74\u4f60\u73fe\u5728\u9084\u6c92\u6709\u6234\u5e3d\u5b50. +hatFail=\u00a74\u4f60\u5fc5\u9808\u628a\u60f3\u8981\u5e36\u7684\u5e3d\u5b50\u62ff\u5728\u624b\u4e2d. +hatPlaced=\u00a7e\u4eab\u53d7\u4f60\u7684\u65b0\u5e3d\u5b50\u628a\! +hatRemoved=\u00a76\u4f60\u7684\u5e3d\u5b50\u5df2\u79fb\u9664. +haveBeenReleased=\u00a76\u4f60\u5df2\u88ab\u91cb\u653e +heal=\u00a76\u4f60\u5df2\u88ab\u6cbb\u7642 +healDead=\u00a74\u4f60\u4e0d\u80fd\u6cbb\u7642\u4e00\u500b\u6b7b\u4eba\! +healOther=\u00a76\u5df2\u6cbb\u7642\u00a7c {0} +helpConsole=\u5f9e\u63a7\u5236\u53f0\u67e5\u770b\u5e6b\u52a9,\u8acb\u8f38\u5165\u300c?\u300d +helpFrom=\u00a76\u4f86\u81ea\u65bc {0} \u7684\u6307\u4ee4 +helpLine=\u00a76/{0}\u00a7r\: {1} +helpMatching=\u00a76\u6307\u4ee4\u7b26\u5408 "\u00a7c{0}\u00a76"\: +helpOp=\u00a74[\u6c42\u52a9OP]\u00a7r \u00a76{0}\:\u00a7r {1} +helpPlugin=\u00a74{0}\u00a7r\: \u5916\u639b\u7a0b\u5f0f\u5e6b\u52a9\: /help {1} +holdBook=\u00a74\u4f60\u9700\u8981\u62ff\u8457\u4e00\u672c\u53ef\u5beb\u7684\u66f8. +holdFirework=\u00a74\u4f60\u5fc5\u9808\u62ff\u8457\u7159\u706b\u624d\u80fd\u589e\u52a0\u7279\u6548. +holdPotion=\u00a74\u4f60\u5fc5\u9808\u62ff\u8457\u85e5\u6c34\u624d\u80fd\u589e\u52a0\u7279\u6548. +holeInFloor=\u00a74\u5730\u677f\u6709\u6d1e\! +homeSet=\u00a76\u5df2\u8a2d\u7f6e\u5bb6~ +homes=\u00a76\u5bb6\:\u00a7r{0} +hour=\u5c0f\u6642 +hours=\u5c0f\u6642 +ignoredList=\u00a76\u5ffd\u7565\:\u00a7r {0} +ignorePlayer=\u00a76\u4f60\u5c4f\u853d\u4e86\u73a9\u5bb6 \u00a7c{0} +illegalDate=\u932f\u8aa4\u7684\u65e5\u671f\u683c\u5f0f +infoChapter=\u00a76\u9078\u64c7\u7ae0\u7bc0\: +infoChapterPages=\u00a7e ---- \u00a76{0} \u00a7e--\u00a76 \u9801\u9762\: \u00a7c{1}\u00a76 / \u00a7c{2} \u00a7e---- +infoPages=\u00a7e----\u7b2c \u00a7c{0}\u00a7e \u9801/\u5171 \u00a7c{1}\u00a7e \u9801---- +infoUnknownChapter=\u00a74\u672a\u77e5\u7ae0\u7bc0\u3002 +insufficientFunds=\u00a74\u53ef\u7528\u8cc7\u91d1\u4e0d\u8db3. +invalidCharge=\u00a74\u7121\u6548\u7684\u50f9\u683c +invalidFireworkFormat=\u00a74The option \u00a7c{0} \u00a74is not a valid value for \u00a7c{1}\u00a74. +invalidHome=\u00a74\u5bb6\u00a7c {0} \u00a74\u4e0d\u5b58\u5728\! +invalidHomeName=\u00a74\u7121\u6548\u7684\u5bb6\u540d\u7a31\! +invalidMob=\u00a74\u7121\u6548\u751f\u7269\u985e\u578b +invalidNumber=\u7121\u6548\u7684\u6578\u5b57. +invalidPotion=\u00a74\u7121\u6548\u7684\u85e5\u6c34. +invalidPotionMeta=\u00a74\u7121\u6548\u7684\u85e5\u6c34\u6578\u64da\: \u00a7c{0}\u00a74. +invalidSignLine=\u00a74\u724c\u5b50\u4e0a\u7684\u7b2c \u00a7c{0} \u00a74\u884c\u7121\u6548 +invalidWarpName=\u00a74\u7121\u6548\u7684\u50b3\u9001\u9ede\u540d\u7a31\! +invalidWorld=\u00a74\u7121\u6548\u7684\u4e16\u754c\u540d. +is=\u662f +itemCannotBeSold=\u00a74\u8a72\u7269\u54c1\u7121\u6cd5\u8ce3\u7d66\u4f3a\u670d\u5668 +itemMustBeStacked=\u00a74\u7269\u54c1\u5fc5\u9808\u6210\u7d44\u4ea4\u6613,2s\u7684\u6578\u91cf\u662f2\u7d44,\u4ee5\u6b64\u985e\u63a8 +itemNames=\u00a76\u7269\u54c1\u7c21\u6613\u540d\u7a31\:\u00a7r {0} +itemNotEnough1=\u00a74\u4f60\u6c92\u6709\u8db3\u5920\u7684\u8a72\u7269\u54c1\u4f86\u8ce3\u51fa +itemNotEnough2=\u00a76\u5982\u679c\u4f60\u60f3\u8981\u8ce3\u6389\u6240\u6709\u4f60\u80cc\u5305\u5167\u7684\u8a72\u7269\u54c1,\u4f7f\u7528\u300c/sell \u7269\u54c1\u540d\u7a31\uff08\u82f1\u6587,\u6216ID\uff09\u300d +itemNotEnough3=\u00a76\u300c/sell \u7269\u54c1\u540d\u7a31 -1\u300d\u5c07\u6703\u7559\u51fa\u4e00\u500b\u800c\u8ce3\u6389\u5176\u5b83\u8a72\u7a2e\u7269\u54c1,\u4ee5\u6b64\u985e\u63a8 +itemSellAir=\u4f60\u96e3\u9053\u60f3\u8ce3\u7a7a\u6c23\u55ce\uff1f\u653e\u500b\u6771\u897f\u5728\u4f60\u624b\u88e1 +itemSold=\u00a7a\u7372\u5f97 \u00a7c {0} \u00a7a \uff08{1} \u55ae\u4f4d{2},\u6bcf\u500b\u50f9\u503c {3}\uff09 +itemSoldConsole=\u00a7c{0} \u00a76\u8ce3\u51fa\u4e86 {1},\u7372\u5f97\u4e86\u00a76 {2} \u00a76 \uff08{3} \u55ae\u4f4d\u7269\u54c1,\u6bcf\u500b\u50f9\u503c {4}\uff09 +itemSpawn=\u00a76\u751f\u6210 {0} \u500b {1} +itemType=\u00a76\u7269\u54c1\:\u00a7c {0} \u00a76-\u00a74 {1} +itemsCsvNotLoaded=\u7121\u6cd5\u8f09\u5165items.csv +jailAlreadyIncarcerated=\u00a74\u5df2\u5728\u76e3\u7344\u4e2d\u7684\u73a9\u5bb6\:{0} +jailMessage=\u00a74\u8acb\u5728\u76e3\u7344\u4e2d\u9762\u58c1\u601d\u904e\uff01 +jailNotExist=\u00a74\u8a72\u76e3\u7344\u4e0d\u5b58\u5728 +jailReleased=\u00a76\u73a9\u5bb6 \u00a7c{0}\u00a76 \u51fa\u7344\u4e86 +jailReleasedPlayerNotify=\u00a76\u4f60\u5df2\u88ab\u91cb\u653e\uff01 +jailSentenceExtended=\u00a76\u56da\u7981\u6642\u9593\u589e\u52a0\u5230\:{0) +jailSet=\u00a76\u76e3\u7344 {0} \u5df2\u88ab\u8a2d\u7f6e +jumpError=\u00a74\u9019\u5c07\u6703\u640d\u5bb3\u4f60\u7684\u96fb\u8166 +kickDefault=\u5f9e\u4f3a\u670d\u5668\u8acb\u51fa +kickExempt=\u00a74\u4f60\u7121\u6cd5\u8acb\u51fa\u8a72\u73a9\u5bb6. +kickedAll=\u00a74\u5df2\u5c07\u6240\u6709\u73a9\u5bb6\u8acb\u51fa\u4f3a\u670d\u5668. +kill=\u00a76\u6bba\u6b7b\u4e86 \u00a7c{0} +killExempt=\u00a74\u4f60\u4e0d\u80fd\u6bba\u5bb3 \u00a7c{0}\u00a74\u3002 +kitCost=\ \u00a77\u00a7o({0})\u00a7r +kitError2=\u00a74\u8a72\u5de5\u5177\u5305\u53ef\u80fd\u4e0d\u5b58\u5728\u6216\u8005\u88ab\u62d2\u7d55\u4e86. +kitError=\u00a74\u6c92\u6709\u6709\u6548\u7684\u5de5\u5177\u5305 +kitGiveTo=\u00a76\u7d66\u4e88\u00a7c{1}\u00a76\u5de5\u5177\u5305\u00a7c {0}\u00a76\u3002 +kitInvFull=\u00a74\u4f60\u7684\u80cc\u5305\u5df2\u6eff,\u5de5\u5177\u5305\u5c07\u653e\u5728\u5730\u4e0a +kitNotFound=\u00a74\u5de5\u5177\u5305\u4e0d\u5b58\u5728. +kitOnce=\u00a74\u4f60\u4e0d\u80fd\u518d\u6b21\u4f7f\u7528\u8a72\u5de5\u5177\u5305. +kitReceive=\u00a76\u6536\u5230\u4e00\u500b\u00a7c {0} \u00a76\u5de5\u5177\u5305. +kitTimed=\u00a74\u4f60\u4e0d\u80fd\u518d\u6b21\u5c0d\u5176\u4ed6\u4eba\u4f7f\u7528\u6b64\u5de5\u5177\u5305\u00a7c {0}\u00a74. +kits=\u00a76\u5de5\u5177\u5305\:\u00a7r{0} +leatherSyntax=\u00a76\u76ae\u9769\u984f\u8272\u8a9e\u6cd5\: color\:,, \u5982\: color\:255,0,0. +lightningSmited=\u00a76\u4f60\u525b\u525b\u88ab\u96f7\u64ca\u4e2d\u4e86 +lightningUse=\u00a76\u96f7\u64ca\u4e2d\u4e86\u00a7c {0} +listAfkTag=\u00a77[\u96e2\u958b]\u00a7r +listAmount=\u00a76\u7576\u524d\u6709 \u00a7c{0}\u00a76 \u500b\u73a9\u5bb6\u5728\u7dda,\u6700\u5927\u5728\u7dda\u4eba\u6578\u70ba \u00a7c{1}\u00a76 \u500b\u73a9\u5bb6. +listAmountHidden=\u00a76\u7576\u524d\u6709 \u00a7c{0}\u00a76/{1}\u00a76 \u500b\u73a9\u5bb6\u5728\u7dda,\u6700\u5927\u5728\u7dda\u4eba\u6578 \u00a7c{2}\u00a76 \u500b\u73a9\u5bb6 +listGroupTag=\u00a76{0}\u00a7r\: \u00a7r +listHiddenTag=\u00a77[\u96b1\u8eab]\u00a7r +loadWarpError=\u00a74\u8f09\u5165\u5730\u6a19 {0} \u5931\u6557 +localFormat=[L]<{0}> {1} +mailClear=\u00a76\u8f38\u5165\u00a7c /mail clear\u00a76 \u5c07\u90f5\u4ef6\u6a19\u793a\u70ba\u5df2\u8b80\u3002 +mailCleared=\u00a76\u90f5\u7bb1\u5df2\u6e05\u7a7a\uff01 +mailSent=\u00a76\u90f5\u4ef6\u5df2\u767c\u51fa\uff01 +markMailAsRead=\u00a76\u8f38\u5165\u00a7c /mail clear\u00a76 \u5c07\u90f5\u4ef6\u6a19\u793a\u70ba\u5df2\u8b80\u3002 +markedAsAway=\u00a76\u4f60\u5df2\u8a2d\u7f6e\u96e2\u958b. +markedAsNotAway=\u00a76\u4f60\u5df2\u8a2d\u7f6e\u53d6\u6d88\u96e2\u958b. +matchingIPAddress=\u00a76\u4ee5\u4e0b\u662f\u4f86\u81ea\u8a72IP\u4f4d\u5740\u7684\u73a9\u5bb6\: +maxHomes=\u00a74\u4f60\u7121\u6cd5\u8a2d\u7f6e\u8d85\u904e {0} \u500b\u5bb6. +mayNotJail=\u00a74\u4f60\u7121\u6cd5\u56da\u7981\u8a72\u73a9\u5bb6 +me=\u6211 +minute=\u5206\u9418 +minutes=\u5206\u9418 +missingItems=\u00a74You do not have \u00a7c{0}x {1}\u00a74. +mobSpawnError=\u00a74\u66f4\u6539\u5237\u602a\u7c60\u6642\u767c\u751f\u932f\u8aa4 +mobSpawnLimit=\u751f\u7269\u6578\u91cf\u592a\u591a,\u7121\u6cd5\u751f\u6210 +mobSpawnTarget=\u00a74\u76ee\u6a19\u65b9\u584a\u5fc5\u9808\u662f\u4e00\u500b\u5237\u602a\u7c60 +mobsAvailable=\u00a76\u751f\u7269\:\u00a7r {0} +moneyRecievedFrom=\u00a7a\u5df2\u5f9e {1} \u63a5\u6536{0} +moneySentTo=\u00a7a{0} \u5df2\u767c\u9001\u5230 {1} +month=\u6708 +months=\u6708 +moreThanZero=\u00a74\u6578\u91cf\u5fc5\u9808\u5927\u65bc0 +moveSpeed=\u00a76\u5c07\u00a7c{2}\u00a76\u7684 {0} \u901f\u5ea6\u8a2d\u5b9a\u70ba\u00a7c {1} \u00a76\u3002 +msgFormat=\u00a76[\u00a7c{0}\u00a76 -> \u00a7c{1}\u00a76] \u00a7r{2} +multipleCharges=\u00a74\u60a8\u4e0d\u80fd\u5c0d\u9019\u500b\u7159\u82b1\u61c9\u7528\u591a\u65bc\u4e00\u500b\u7684\u88dd\u6599. +multiplePotionEffects=\u00a74\u60a8\u4e0d\u80fd\u5c0d\u9019\u500b\u7159\u82b1\u61c9\u7528\u591a\u65bc\u4e00\u500b\u7684\u6548\u679c. +muteExempt=\u00a74\u4f60\u7121\u6cd5\u7981\u8a00\u8a72\u73a9\u5bb6 +muteNotify=\u00a7c{0} \u00a76\u5c07 \u00a7c{1} \u00a76\u7981\u8a00\u4e86\u3002 +mutedPlayer=\u00a76\u73a9\u5bb6\u00a7c {0} \u00a76\u88ab\u7981\u8a00\u4e86\u3002 +mutedPlayerFor=\u00a76\u73a9\u5bb6\u00a7c {0} \u00a76\u88ab\u7981\u8a00\u00a7c {1}\u00a76\u3002 +mutedUserSpeaks={0} \u60f3\u8981\u8aaa\u8a71,\u4f46\u88ab\u7981\u8a00\u4e86 +nearbyPlayers=\u00a76\u9644\u8fd1\u7684\u73a9\u5bb6\: {0} +negativeBalanceError=\u00a74\u73fe\u91d1\u4e0d\u53ef\u5c0f\u65bc\u96f6 +nickChanged=\u00a76\u66b1\u7a31\u5df2\u66f4\u63db +nickDisplayName=\u00a74\u4f60\u9700\u8981\u6fc0\u6d3bchange-displayname.\u8a72\u6587\u4ef6\u5728Essentials\u8a2d\u7f6e\u6587\u4ef6\u4e2d +nickInUse=\u00a74\u90a3\u500b\u66b1\u7a31\u5df2\u88ab\u4f7f\u7528 +nickNamesAlpha=\u00a74\u66b1\u7a31\u5fc5\u9808\u70ba\u5b57\u6bcd\u6216\u6578\u5b57. +nickNoMore=\u00a76\u4f60\u4e0d\u518d\u64c1\u6709\u4e00\u500b\u66b1\u7a31 +nickSet=\u00a76\u4f60\u7684\u66b1\u7a31\u73fe\u5728\u662f \u00a7c{0}\u00a76\u3002 +nickTooLong=\u00a74\u9019\u500b\u66b1\u7a31\u592a\u9577. +noAccessCommand=\u00a74\u4f60\u6c92\u6709\u4f7f\u7528\u8a72\u547d\u4ee4\u7684\u8a31\u53ef\u6b0a +noAccessPermission=\u00a74You do not have permission to access that \u00a7c{0}\u00a74. +noBreakBedrock=\u00a74\u4f60\u4e0d\u80fd\u6467\u6bc0\u57fa\u5ca9\uff01 +noDestroyPermission=\u00a74\u4f60\u6c92\u6709\u6b0a\u9650\u7834\u58de \u00a7c{0}\u00a74\u3002 +noDurability=\u00a74\u9019\u500b\u7269\u54c1\u6c92\u6709\u8010\u4e45. +noGodWorldWarning=\u00a74\u7981\u6b62\u4f7f\u7528\u4e0a\u5e1d\u6a21\u5f0f. +noHelpFound=\u00a74\u6c92\u6709\u7b26\u5408\u7684\u6307\u4ee4. +noHomeSetPlayer=\u00a76\u8a72\u73a9\u5bb6\u9084\u672a\u8a2d\u7f6e\u5bb6 +noIgnored=\u00a76\u4f60\u6c92\u6709\u5ffd\u7565\u4efb\u4f55\u4eba\u3002 +noKitPermission=\u00a74\u4f60\u9700\u8981 \u00a74{0}\u00a74 \u8a31\u53ef\u6b0a\u4f86\u4f7f\u7528\u8a72\u5de5\u5177 +noKits=\u00a76\u9084\u6c92\u6709\u53ef\u7372\u5f97\u7684\u5de5\u5177 +noMail=\u4f60\u6c92\u6709\u4efb\u4f55\u90f5\u4ef6 +noMatchingPlayers=\u00a76\u627e\u4e0d\u5230\u5339\u914d\u7684\u73a9\u5bb6. +noMetaFirework=\u00a74\u4f60\u6c92\u6709\u8a31\u53ef\u6b0a\u61c9\u7528\u7159\u82b1\u6578\u64da. +noMetaPerm=\u00a74\u4f60\u6c92\u6709\u8a31\u53ef\u6b0a\u61c9\u7528 \u00a7c{0}\u00a74 \u7684\u6578\u64da. +noNewMail=\u00a76\u4f60\u6c92\u6709\u65b0\u7684\u90f5\u4ef6 +noPendingRequest=\u00a74\u4f60\u6c92\u6709\u5f85\u89e3\u6c7a\u7684\u8acb\u6c42 +noPerm=\u00a74\u4f60\u6c92\u6709 \u00a7c{0}\u00a74 \u8a31\u53ef\u6b0a +noPermToSpawnMob=\u00a74\u4f60\u6c92\u6709\u751f\u6210\u8a72\u751f\u7269\u7684\u8a31\u53ef\u6b0a +noPlacePermission=\u00a74\u00a74\u4f60\u6c92\u6709\u5728\u90a3\u500b\u724c\u5b50\u65c1\u908a\u653e\u65b9\u584a\u7684\u6b0a\u5229 +noPotionEffectPerm=\u00a74\u4f60\u6c92\u6709\u8a31\u53ef\u6b0a\u61c9\u7528\u7279\u6548 \u00a7c{0} \u00a74\u5230\u9019\u500b\u85e5\u6c34. +noPowerTools=\u00a76\u4f60\u6c92\u6709\u7d81\u5b9a\u547d\u4ee4 +noWarpsDefined=\u00a74\u6c92\u6709\u78ba\u5b9a\u7684\u5730\u6a19 +none=\u7121 +notAllowedToQuestion=\u00a74\u4f60\u672a\u88ab\u6388\u6b0a\u4f7f\u7528\u63d0\u554f\u767c\u8a00 +notAllowedToShout=\u00a74\u4f60\u672a\u88ab\u6388\u6b0a\u4f7f\u7528\u558a\u8a71\u767c\u8a00 +notEnoughExperience=\u00a74\u4f60\u6c92\u6709\u8db3\u5920\u7684\u7d93\u9a57\u503c +notEnoughMoney=\u00a74\u4f60\u6c92\u6709\u8db3\u5920\u7684\u8cc7\u91d1 +notFlying=\u672a\u98db\u884c +notRecommendedBukkit=\u00a74Bukkit\u7248\u672c\u904e\u820a.\u5efa\u8b70\u66f4\u65b0. +notSupportedYet=\u66ab\u4e0d\u652f\u6301 +nothingInHand=\u00a74\u4f60\u6c92\u6709\u6301\u6709\u4efb\u4f55\u7269\u54c1 +now=\u73fe\u5728 +nuke=\u00a7d\u6838\u6b66\u964d\u843d,\u6ce8\u610f\u96b1\u853d\uff01 +numberRequired=\u9700\u8981\u8f38\u5165\u6578\u5b57\uff01 +onlyDayNight=/time \u547d\u4ee4\u53ea\u6709 day/night \u5169\u500b\u9078\u64c7 +onlyPlayerSkulls=\u00a74\u4f60\u53ea\u80fd\u8a2d\u5b9a\u73a9\u5bb6\u982d\u9871 (\u00a7c397\:3\u00a74) \u7684\u64c1\u6709\u8005\u3002 +onlyPlayers=\u00a74\u53ea\u6709\u904a\u6232\u4e2d\u7684\u73a9\u5bb6\u53ef\u4ee5\u4f7f\u7528 \u00a7c{0}\u00a74\u3002 +onlySunStorm=\u00a74/weather \u547d\u4ee4\u53ea\u6709 sun/storm \u5169\u500b\u9078\u64c7 +orderBalances=\u00a76\u6392\u5e8f {0} \u00a76\u500b\u73a9\u5bb6\u7684\u8cc7\u91d1\u4e2d,\u8acb\u7a0d\u5019\u2026\u2026 +oversizedTempban=\u00a74\u4f60\u53ef\u80fd\u6c92\u6709\u5728\u9019\u500b\u6642\u6bb5\u5c01\u7981\u73a9\u5bb6. +pTimeCurrent=\u00a76{0}\u00a7c \u00a76\u7684\u6642\u9593\u662f \u00a7c{1} +pTimeCurrentFixed=\u00a7c{0}\u00a76 \u7684\u6642\u9593\u88ab\u9023\u63a5\u5230 \u00a7c{1} +pTimeNormal=\u00a7c{0}\u00a76 \u7684\u6642\u9593\u662f\u6b63\u5e38\u7684\u4e26\u8207\u4f3a\u670d\u5668\u540c\u6b65 +pTimeOthersPermission=\u00a74\u4f60\u672a\u88ab\u6388\u6b0a\u8a2d\u7f6e\u5176\u4ed6\u73a9\u5bb6\u7684\u6642\u9593 +pTimePlayers=\u00a76\u9019\u4e9b\u73a9\u5bb6\u6709\u4ed6\u5011\u81ea\u5df1\u7684\u6642\u9593\: +pTimeReset=\u00a76\u8a72\u73a9\u5bb6\u7684\u6642\u9593\u88ab\u91cd\u7f6e\:\u00a7c{0} +pTimeSet=\u00a76\u8a72\u73a9\u5bb6\u7684\u6642\u9593\u88ab\u8a2d\u5b9a\u70ba \u00a7c{0}\u00a76 \u5c0d\u8c61\:\u00a7c{1} +pTimeSetFixed=\u00a76\u8a72\u73a9\u5bb6\u6642\u9593\u88ab\u9023\u63a5\u5230 \u00a7c{0}\u00a76 \u5c0d\u8c61\:\u00a7c{1} +pWeatherCurrent=\u00a7c{0}\u00a76\u7684\u5929\u6c23\u662f\u00a7c {1}\u00a76. +pWeatherInvalidAlias=\u00a74\u932f\u8aa4\u7684\u5929\u6c23\u985e\u578b +pWeatherNormal=\u00a7c{0}\u00a76\u7684\u5929\u6c23\u662f\u6b63\u5e38\u7684. +pWeatherOthersPermission=\u00a74\u60a8\u6c92\u6709\u88ab\u6388\u6b0a\u8a2d\u7f6e\u5176\u4ed6\u73a9\u5bb6\u7684\u5929\u6c23. +pWeatherPlayers=\u00a76\u9019\u4e9b\u73a9\u5bb6\u90fd\u6709\u81ea\u5df1\u7684\u5929\u6c23\:\u00a7r +pWeatherReset=\u00a76\u73a9\u5bb6\u7684\u5929\u6c23\u88ab\u91cd\u7f6e\: \u00a7c{0} +pWeatherSet=\u00a76\u73a9\u5bb6\u00a7c{1}\u00a76\u7684\u5929\u6c23\u88ab\u8a2d\u7f6e\u70ba \u00a7c{0}\u00a76 . +pendingTeleportCancelled=\u00a74\u5f85\u8655\u7406\u7684\u50b3\u9001\u8acb\u6c42\u5df2\u53d6\u6d88 +playerBanIpAddress=\u00a76Player\u00a7c {0} \u00a76banned IP address\u00a7c {1} \u00a76for\: \u00a7c{2}\u00a76. +playerBanned=\u00a76\u73a9\u5bb6\u00a7c {0} \u00a76\u88ab\u5c01\u9396\u00a7c {1} \u00a76\uff0c\u56e0\u70ba \u00a7c{2}\u00a76\u3002 +playerInJail=\u00a74\u73a9\u5bb6\u5df2\u7d93\u5728\u76e3\u7344\u00a7c {0}\u00a74\u3002 +playerJailed=\u00a76\u73a9\u5bb6 \u00a7c{0} \u00a76\u88ab\u902e\u6355\u4e86 +playerJailedFor=\u00a76\u73a9\u5bb6 \u00a7c{0} \u00a76\u88ab\u902e\u6355,\u6642\u9593\:{1} +playerKicked=\u00a74\u7ba1\u7406\u54e1 \u00a7c{0} \u00a76\u8acb\u51fa\u4e86 \u00a7c{1},\u00a76\u7406\u7531\:{2} +playerMuted=\u00a76\u4f60\u88ab\u7981\u6b62\u767c\u8a00 +playerMutedFor=\u00a76\u4f60\u5df2\u88ab\u7981\u8a00.\u7406\u7531\: {0} +playerNeverOnServer=\u00a74\u73a9\u5bb6 \u00a7c{0} \u00a74\u5f9e\u6c92\u51fa\u73fe\u5728\u4f3a\u670d\u5668\u904e +playerNotFound=\u00a74\u73a9\u5bb6\u672a\u5728\u7dda\uff08\u6216\u4e0d\u5b58\u5728\uff09 +playerUnbanIpAddress=\u00a76\u5df2\u89e3\u9664\u7528\u6236\u00a7c {0} \u00a76\u7684\u5c01\u7981IP\: {1}. +playerUnbanned=\u00a76\u73a9\u5bb6\u00a7c {0} \u00a76\u5c07\u00a7c {1} \u00a76\u89e3\u9664\u5c01\u9396\u3002 +playerUnmuted=\u00a76\u4f60\u88ab\u5141\u8a31\u767c\u8a00 +pong=\u556a\uff01 +posPitch=\u00a76\u4ef0\u89d2\: {0} (\u982d\u90e8\u7684\u89d2\u5ea6) +posX=\u00a76X\: {0} (+\u6771 <-> -\u897f) +posY=\u00a76Y\: {0} (+\u4e0a <-> -\u4e0b) +posYaw=\u00a76Yaw\: {0} (\u65cb\u8f49) +posZ=\u00a76Z\: {0} (+\u5357 <-> -\u5317) +possibleWorlds=\u00a76Possible worlds are the numbers \u00a7c0\u00a76 through \u00a7c{0}\u00a76. +potions=\u00a76\u85e5\u6c34\:\u00a7r {0}\u00a76. +powerToolAir=\u00a74\u6307\u4ee4\u4e0d\u80fd\u5c0d\u8457\u7a7a\u6c23\u4f7f\u7528. +powerToolAlreadySet=\u00a74\u6307\u4ee4 \u00a7c{0}\u00a74 \u5df2\u7d93\u8a2d\u5b9a\u7d66 \u00a7c{1}\u00a74\u3002 +powerToolAttach=\u00a7c{0}\u00a76 \u6307\u4ee4\u88ab\u95dc\u806f\u7d66 {1} +powerToolClearAll=\u00a76\u6240\u6709\u6bba\u624b\u7d1a\u6307\u4ee4\u5df2\u88ab\u6e05\u9664 +powerToolList={1} \u6709\u5982\u4e0b\u547d\u4ee4\:\u00a74{0}\u00a7r. +powerToolListEmpty=\u00a7c{0} \u6c92\u6709\u88ab\u95dc\u806f\u5230\u6307\u4ee4. +powerToolNoSuchCommandAssigned=\u00a74\u6307\u4ee4 \u00a7c{0}\u00a74 \u6c92\u6709\u8a2d\u5b9a\u7d66 \u00a7c{1}\u00a74\u3002 +powerToolRemove=\u00a76\u6307\u4ee4 \u00a7c{0}\u00a76 \u5df2\u7d93\u5f9e \u00a7c{1}\u00a76 \u79fb\u9664\u3002 +powerToolRemoveAll=\u00a76\u6240\u6709\u6307\u4ee4\u5df2\u7d93\u5f9e \u00a7c{0}\u00a76 \u79fb\u9664\u3002 +powerToolsDisabled=\u4f60\u6240\u6709\u7684\u5feb\u6377\u547d\u4ee4\u88ab\u51cd\u7d50 +powerToolsEnabled=\u4f60\u6240\u6709\u7684\u5feb\u6377\u547d\u4ee4\u88ab\u6fc0\u6d3b +questionFormat=\u00a72[\u63d0\u554f]\u00a7r {0} +readNextPage=\u00a76\u8f38\u5165 \u00a7c/{0} {1} \u00a76\u4f86\u95b1\u8b80\u4e0b\u4e00\u9801 +recipe=\u00a76Recipe for \u00a7c{0}\u00a76 (\u00a7c{1}\u00a76 of \u00a7c{2}\u00a76) +recipeBadIndex=\u9019\u500b\u7de8\u865f\u6c92\u6709\u5339\u914d\u7684\u5408\u6210\u516c\u5f0f. +recipeFurnace=\u00a76Smelt\: \u00a7c{0}\u00a76. +recipeGrid=\u00a7c{0}X \u00a76| \u00a7{1}X \u00a76| \u00a7{2}X +recipeGridItem=\u00a7c{0}X \u00a76is \u00a7c{1} +recipeMore=\u00a76Type /{0} \u00a7c{1}\u00a76 <\u6578\u5b57> \u53bb\u67e5\u770b\u66f4\u591a\u7684 \u00a7c{2}\u00a76\u5408\u6210\u516c\u5f0f. +recipeNone=\u5c0d{0}\u6c92\u6709\u5339\u914d\u7684\u5408\u6210\u516c\u5f0f +recipeNothing=\u6c92\u6709\u6771\u897f +recipeShapeless=\u00a76\u7d50\u5408 \u00a7c{0} +recipeWhere=\u00a76\u7576\: {0} +removed=\u00a76\u79fb\u9664\u4e86\u00a7c {0} \u00a76\u9805 +repair=\u00a76\u4f60\u5df2\u7d93\u6210\u529f\u4fee\u597d\u4e86\u4f60\u7684\uff1a \u00a7c{0}\u00a76\u3002 +repairAlreadyFixed=\u00a74\u8a72\u7269\u54c1\u7121\u9700\u4fee\u5fa9 +repairEnchanted=\u00a74\u4f60\u7121\u6b0a\u4fee\u5fa9\u9644\u9b54\u7269\u54c1 +repairInvalidType=\u00a74\u8a72\u7269\u54c1\u7121\u6cd5\u4fee\u5fa9 +repairNone=\u00a74\u9019\u88e1\u6c92\u6709\u9700\u8981\u88ab\u4fee\u7406\u7684\u7269\u54c1\u3002 +requestAccepted=\u00a76\u5df2\u63a5\u53d7\u50b3\u9001\u8acb\u6c42 +requestAcceptedFrom=\u00a7c{0}\u00a76 \u63a5\u53d7\u4e86\u4f60\u7684\u50b3\u9001\u8acb\u6c42 +requestDenied=\u00a76\u5df2\u62d2\u7d55\u50b3\u9001\u8acb\u6c42 +requestDeniedFrom=\u00a7c{0}\u00a76 \u62d2\u7d55\u4e86\u4f60\u7684\u50b3\u9001\u8acb\u6c42 +requestSent=\u00a76\u8acb\u6c42\u5df2\u767c\u9001\u7d66 {0}\u00a76 +requestTimedOut=\u00a74\u50b3\u9001\u8acb\u6c42\u8d85\u6642\u2026\u2026 +requiredBukkit=\u00a76\u4f60\u9700\u8981\u7248\u672c {0} \u4ee5\u4e0a\u7684bukkit.\u8acb\u81f3\u5b98\u7db2\u4e0b\u8f09 +resetBal=\u00a76\u6240\u6709\u5728\u7dda\u73a9\u5bb6\u7684\u8ca1\u7522\u5df2\u7d93\u91cd\u7f6e\u70ba \u00a7c{0} \u00a76\u3002 +resetBalAll=\u00a76\u6240\u6709\u73a9\u5bb6\u7684\u8ca1\u7522\u5df2\u7d93\u91cd\u7f6e\u70ba \u00a7c{0} \u00a76\u3002 +returnPlayerToJailError=\u00a74\u5617\u8a66\u5c07\u73a9\u5bb6\u00a7c {0} \u00a74\u95dc\u56de\u76e3\u7344 \u00a7c{1}\u00a74 \u6642\u767c\u751f\u932f\u8aa4\uff01 +runningPlayerMatch=\u00a76\u6b63\u5728\u641c\u7d22\u5339\u914d\u7684\u73a9\u5bb6 \u00a7c{0}\u00a76 (\u9019\u53ef\u80fd\u6703\u82b1\u8cbb\u4e00\u4e9b\u6642\u9593) +second=\u79d2 +seconds=\u79d2 +seenOffline=\u00a76\u73a9\u5bb6\u00a7c {0} \u00a76\u5728 \u00a7c{1}\u00a76 \u5df2\u7d93 \u00a74\u96e2\u7dda\u00a76\u3002 +seenOnline=\u00a76\u73a9\u5bb6\u00a7c {0} \u00a76\u5728 \u00a7c{1}\u00a76 \u5df2\u7d93 \u00a7a\u4e0a\u7dda\u00a76\u3002 +serverFull=\u4f3a\u670d\u5668\u5df2\u6eff +serverTotal=\u00a76\u4f3a\u670d\u5668\u7e3d\u548c\: {0} +setBal=\u00a7a\u4f60\u7684\u91d1\u9322\u5df2\u88ab\u8a2d\u7f6e\u70ba {0}. +setBalOthers=\u00a7a\u6210\u529f\u8a2d\u7f6e {0} \u7684\u91d1\u9322\u70ba {1}. +setSpawner=\u00a76\u6539\u8b8a\u751f\u602a\u78da\u578b\u614b\u70ba\u00a7c {0}\u00a76\u3002 +sheepMalformedColor=\u00a74\u7121\u6548\u7684\u984f\u8272 +shoutFormat=\u00a76[\u558a\u8a71]\u00a7r {0} +signFormatFail=\u00a74[{0}] +signFormatSuccess=\u00a71[{0}] +signFormatTemplate=[{0}] +signProtectInvalidLocation=\u00a74\u4f60\u4e0d\u5141\u8a31\u5728\u6b64\u653e\u7f6e\u724c\u5b50 +similarWarpExist=\u00a74\u4e00\u500b\u540c\u540d\u7684\u5730\u6a19\u5df2\u5b58\u5728 +slimeMalformedSize=\u00a74\u5927\u5c0f\u975e\u6cd5 +socialSpy=\u00a76SocialSpy for \u00a7c{0}\u00a76\: \u00a7c{1} +soloMob=\u00a74\u8a72\u751f\u7269\u559c\u6b61\u7368\u5c45 +spawnSet=\u00a76\u5df2\u70ba\u00a7c {0}\u00a76 \u7d44\u7684\u8a2d\u7f6e\u51fa\u751f\u9ede +spawned=\u5df2\u751f\u6210 +sudoExempt=\u00a74\u7121\u6cd5\u5f37\u5236\u4f7f\u6b64\u73a9\u5bb6\u57f7\u884c\u547d\u4ee4 +sudoRun=\u00a76Forcing\u00a7c {0} \u00a76to run\:\u00a7r /{1} +suicideMessage=\u00a76\u6c38\u5225\u4e86,\u6b98\u9177\u7684\u4e16\u754c\u2026\u2026 +suicideSuccess=\u00a7c{0} \u00a76\u7d50\u675f\u4e86\u4ed6\u81ea\u5df1\u7684\u751f\u547d +survival=\u751f\u5b58\u6a21\u5f0f +takenFromAccount=\u00a7a\u5f9e\u4f60\u7684\u8cec\u6236\u4e2d\u6263\u9664\u4e86 {0} +takenFromOthersAccount=\u00a7a\u5f9e {1} \u00a7a\u4e2d\u7684\u8cec\u6236\u6263\u9664\u4e86 {0}.\u76ee\u524d\u91d1\u9322\: {2} +teleportAAll=\u00a76\u5411\u6240\u6709\u73a9\u5bb6\u767c\u9001\u4e86\u50b3\u9001\u8acb\u6c42\u2026\u2026 +teleportAll=\u00a76\u50b3\u9001\u4e86\u6240\u6709\u73a9\u5bb6\u2026\u2026 +teleportAtoB=\u00a7c{0}\u00a76 \u5c07\u4f60\u50b3\u9001\u5230 \u00a7c{1}\u00a76\u3002 +teleportDisabled=\u00a7c{0}\u00a74 \u53d6\u6d88\u4e86\u50b3\u9001 +teleportHereRequest=\u00a7c{0}\u00a74 \u8acb\u6c42\u4f60\u50b3\u9001\u5230\u4ed6\u90a3\u88e1 +teleportNewPlayerError=\u00a74\u50b3\u9001\u65b0\u73a9\u5bb6\u5931\u6557 +teleportRequest=\u00a7c{0}\u00a76 \u8acb\u6c42\u50b3\u9001\u5230\u4f60\u9019\u88e1 +teleportRequestTimeoutInfo=\u00a76\u6b64\u8acb\u6c42\u5c07\u5728 {0} \u79d2\u5167\u53d6\u6d88 +teleportTop=\u00a76\u50b3\u9001\u5230\u9802\u90e8 +teleportationCommencing=\u00a76\u6e96\u5099\u50b3\u9001... +teleportationDisabled=\u00a76\u50b3\u9001 \u00a7c\u5df2\u7d93\u7981\u7528\u00a76\u3002 +teleportationDisabledFor=\u00a7c{0}\u00a76\u7684\u50b3\u9001 \u00a7c\u5df2\u7d93\u7981\u7528\u00a76\u3002 +teleportationEnabled=\u00a76\u50b3\u9001 \u00a7c\u5df2\u7d93\u555f\u7528\u00a76\u3002 +teleportationEnabledFor=\u00a7c{0}\u00a76\u7684\u50b3\u9001 \u00a7c\u5df2\u7d93\u555f\u7528\u00a76\u3002 +teleporting=\u00a76\u6b63\u5728\u50b3\u9001... +teleportToPlayer=\u00a76\u50b3\u9001\u5230 \u00a7c{0}\u00a76\u3002 +tempBanned=\u00a7cYou have been temporarily banned for {0}\:\n\u00a7r{2} +tempbanExempt=\u00a76\u4f60\u7121\u6cd5\u81e8\u6642\u5c01\u7981\u6389\u8a72\u73a9\u5bb6 +thunder=\u00a76\u4f60 \u00a7c{0} \u00a76\u4e86\u4f60\u7684\u4e16\u754c\u7684\u9583\u96fb +thunderDuration=\u00a76\u4f60 \u00a7c{0} \u00a76\u4e86\u4f60\u7684\u4e16\u754c\u7684\u9583\u96fb\u00a7c {1} \u00a76\u79d2 +timeBeforeHeal=\u00a76\u6cbb\u7642\u51b7\u537b\:{0} +timeBeforeTeleport=\u00a76\u50b3\u9001\u51b7\u537b\:{0} +timeFormat=\u00a7c{0}\u00a76 \u6216 \u00a7c{1}\u00a76 \u6216 \u00a7c{2}\u00a76 +timeSetPermission=\u00a74\u4f60\u6c92\u6709\u8a2d\u7f6e\u6642\u9593\u7684\u8a31\u53ef\u6b0a +timeWorldCurrent=\u00a76\u76ee\u524d\u4e16\u754c {0} \u7684\u6642\u9593\u662f \u00a73{1} +timeWorldSet=\u00a76\u6642\u9593\u88ab\u8a2d\u7f6e\u70ba {0} \u65bc\u4e16\u754c\:\u00a74{1} +totalWorthAll=\u00a7a\u51fa\u552e\u7684\u6240\u6709\u7269\u54c1\u548c\u65b9\u584a\uff0c\u7e3d\u50f9\u503c {1}. +totalWorthBlocks=\u00a7a\u51fa\u552e\u7684\u6240\u6709\u65b9\u584a\u584a\uff0c\u7e3d\u50f9\u503c {1}. +tps=\u00a76\u7576\u524d TPS \= {0} +tradeSignEmpty=\u00a74\u4ea4\u6613\u724c\u4e0a\u6c92\u6709\u4f60\u53ef\u7372\u5f97\u7684\u6771\u897f +tradeSignEmptyOwner=\u00a74\u4ea4\u6613\u724c\u4e0a\u6c92\u6709\u4f60\u53ef\u6536\u96c6\u7684\u6771\u897f +treeFailure=\u00a74\u751f\u6210\u6a39\u6728\u5931\u6557,\u5728\u8349\u584a\u4e0a\u6216\u571f\u4e0a\u518d\u8a66\u4e00\u6b21 +treeSpawned=\u00a76\u751f\u6210\u6a39\u6728\u6210\u529f +true=\u00a7a\u662f\u00a7r +typeTpaccept=\u00a76\u82e5\u60f3\u63a5\u53d7\u50b3\u9001,\u8f38\u5165 \u00a74/tpaccept\u00a76 +typeTpdeny=\u00a76\u82e5\u60f3\u62d2\u7d55\u50b3\u9001,\u8f38\u5165 \u00a74/tpdeny\u00a76 +typeWorldName=\u00a76\u4f60\u4e5f\u53ef\u4ee5\u8f38\u5165\u6307\u5b9a\u7684\u4e16\u754c\u7684\u540d\u5b57 +unableToSpawnMob=\u00a74\u751f\u6210\u751f\u7269\u5931\u6557 +unignorePlayer=\u00a76\u4f60\u5df2\u4e0d\u518d\u5c4f\u853d\u73a9\u5bb6 {0} +unknownItemId=\u00a74\u672a\u77e5\u7684\u7269\u54c1ID\:{0} +unknownItemInList=\u00a74\u672a\u77e5\u7684\u7269\u54c1 {0} \u65bc {1} \u5217\u8868 +unknownItemName=\u00a74\u672a\u77e5\u7684\u7269\u54c1\u540d\u7a31\:{0} +unlimitedItemPermission=\u00a74\u6c92\u6709\u7121\u9650\u7269\u54c1 \u00a7c{0}\u00a74 \u7684\u6b0a\u9650\u3002 +unlimitedItems=\u00a76\u7121\u9650\u7269\u54c1\: +unmutedPlayer=\u00a76\u73a9\u5bb6 \u00a7c{0}\u00a76 \u88ab\u5141\u8a31\u767c\u8a00 +unvanishedReload=\u00a74\u5916\u639b\u7a0b\u5f0f\u91cd\u8f09\u8feb\u4f7f\u4f60\u7684\u96b1\u8eab\u6a21\u5f0f\u5931\u6548. +upgradingFilesError=\u5347\u7d1a\u6587\u4ef6\u6642\u767c\u751f\u932f\u8aa4 +uptime=\u00a76\u904b\u884c\u6642\u9593\:\u00a7c {0} +userAFK=\u00a75{0} \u00a75\u73fe\u5728\u96e2\u958b, \u53ef\u80fd\u66ab\u6642\u6c92\u8fa6\u6cd5\u56de\u61c9. +userDoesNotExist=\u00a74\u73a9\u5bb6 \u00a7c{0} \u00a74\u4e0d\u5b58\u5728. +userIsAway=\u00a7d{0} \u00a7d\u66ab\u6642\u96e2\u958b\u4e86 +userIsNotAway=\u00a7d{0} \u00a7d\u56de\u4f86\u4e86 +userJailed=\u00a76\u4f60\u5df2\u88ab\u76e3\u7981 +userUnknown=\u00a74\u8b66\u544a\: \u9019\u500b\u73a9\u5bb6 \u00a7c{0}\u00a74 \u5f9e\u4f86\u6c92\u6709\u52a0\u5165\u904e\u4f3a\u670d\u5668. +userdataMoveBackError=\u79fb\u52d5 userdata/{0}.tmp \u5230 userdata/{1} \u5931\u6557 +userdataMoveError=\u79fb\u52d5 userdata/{0} \u5230 userdata/{1}.tmp \u5931\u6557 +usingTempFolderForTesting=\u4f7f\u7528\u7de9\u5b58\u6587\u4ef6\u593e\u4f86\u6e2c\u8a66\: +vanished=\u00a76\u73fe\u5728\u958b\u59cb\u4f60\u5c07\u4e0d\u6703\u88ab\u4e00\u822c\u73a9\u5bb6\u767c\u73fe, \u800c\u4e14\u5728\u904a\u6232\u5167\u7684\u6307\u4ee4\u6d88\u5931. +versionMismatch=\u00a74\u7248\u672c\u4e0d\u5339\u914d\uff01\u8acb\u5347\u7d1a {0} \u5230\u76f8\u540c\u7248\u672c. +versionMismatchAll=\u00a74\u7248\u672c\u4e0d\u5339\u914d\uff01\u8acb\u5347\u7d1a\u6240\u6709Essentials\u7cfb\u5217\u7684\u5916\u639b\u7a0b\u5f0f\u5230\u76f8\u540c\u7248\u672c. +voiceSilenced=\u00a76\u5df2\u975c\u97f3 +walking=\u884c\u8d70\u4e2d +warpDeleteError=\u00a74\u522a\u9664\u5730\u6a19\u6587\u4ef6\u6642\u767c\u751f\u932f\u8aa4. +warpList={0} +warpListPermission=\u00a74\u4f60\u6c92\u6709\u5217\u51fa\u5730\u6a19\u7684\u8a31\u53ef\u6b0a. +warpNotExist=\u00a74\u8a72\u5730\u6a19\u4e0d\u5b58\u5728 +warpOverwrite=\u00a74\u4f60\u4e0d\u80fd\u91cd\u7f6e\u8a72\u5730\u8868 +warpSet=\u00a76\u5730\u6a19 \u00a7c{0} \u00a76\u5df2\u8a2d\u7f6e +warpUsePermission=\u00a74\u4f60\u6c92\u6709\u4f7f\u7528\u8a72\u5730\u6a19\u7684\u8a31\u53ef\u6b0a +warpingTo=\u00a76\u50b3\u9001\u5230\u5730\u6a19 \u00a7c{0} +warps=\u00a76\u5730\u6a19\: \u00a7r{0} +warpsCount=\u00a76\u9019\u4e9b\u662f\u00a7c {0} \u00a76warps\uff0c\u986f\u793a\u9801\u6578\uff1a\u7b2c \u00a7c{1} \u00a76\u9801\uff0c\u5171 \u00a7c{2}\u00a76 \u9801\u3002 +weatherStorm=\u00a76\u4f60\u5c07 {0} \u7684\u5929\u6c23\u6539\u70ba\u96e8\u96ea +weatherStormFor=\u00a76\u4f60\u5c07 {0} \u7684\u5929\u6c23\u7684\u6539\u70ba\u96e8\u96ea,\u6301\u7e8c {1} \u79d2 +weatherSun=\u00a76\u4f60\u5c07 {0} \u7684\u5929\u6c23\u6539\u70ba\u6674\u5929 +weatherSunFor=\u00a76\u4f60\u5c07 {0} \u7684\u5929\u6c23\u7684\u6539\u70ba\u6674\u5929,\u6301\u7e8c {1} \u79d2 +whoisAFK=\u00a76 - \u66ab\u96e2\:\u00a7r {0} +whoisBanned=\u00a76 - \u5c01\u7981\:\u00a7r {0} +whoisExp=\u00a76 - \u7d93\u9a57\:\u00a7r {0} (\u7b49\u7d1a {1}) +whoisFly=\u00a76 - \u98db\u884c\u6a21\u5f0f\:\u00a7r {0} ({1}) +whoisGamemode=\u00a76 - \u904a\u6232\u6a21\u5f0f\:\u00a7r {0} +whoisGeoLocation=\u00a76 - \u5730\u7406\u4f4d\u7f6e\:\u00a7r {0} +whoisGod=\u00a76 - \u4e0a\u5e1d\u6a21\u5f0f\:\u00a7r {0} +whoisHealth=\u00a76 - \u751f\u547d\:\u00a7r {0}/20 +whoisIPAddress=\u00a76 - IP\u4f4d\u5740\:\u00a7r {0} +whoisJail=\u00a76 - \u76e3\u7344\:\u00a7r {0} +whoisLocation=\u00a76 - \u5750\u6a19\:\u00a7r ({0}, {1}, {2}, {3}) +whoisMoney=\u00a76 - \u73fe\u91d1\:\u00a7r {0} +whoisMuted=\u00a76 - \u7981\u8a00\:\u00a7r {0} +whoisNick=\u00a76 - \u66b1\u7a31\:\u00a7r {0} +whoisOp=\u00a76 - OP\:\u00a7r {0} +whoisTop=\u00a76 \=\=\=\=\=\= \u00a7c {0} \u00a76\u7684\u8cc7\u6599\=\=\=\=\=\= +worth=\u00a76\u4e00\u7d44 {0} \u50f9\u503c \u00a74{1}\u00a76\uff08{2} \u55ae\u4f4d\u7269\u54c1,\u6bcf\u500b\u50f9\u503c {3}\uff09 +worthMeta=\u00a7a\u4e00\u7d44\u526f\u78bc\u70ba {1} \u7684 {0} \u50f9\u503c \u00a7c{2}\u00a76\uff08{3} \u55ae\u4f4d\u7269\u54c1,\u6bcf\u500b\u50f9\u503c {4}\uff09 +worthSet=\u00a76\u50f9\u683c\u5df2\u8a2d\u7f6e +year=\u5e74 +years=\u5e74 +youAreHealed=\u00a76\u4f60\u5df2\u88ab\u6cbb\u7642 +youHaveNewMail=\u00a76\u4f60\u6709 \u00a7c{0}\u00a76 \u689d\u8a0a\u606f\uff01\u00a7r\u8f38\u5165 \u00a7c/mail read\u00a76 \u4f86\u67e5\u770b +whoisHunger=\u00a76 - \u98e2\u9913\:\u00a7r {0}/20 (+{1} \u98fd\u98df\u5ea6) +kitDelay=\u00a7m{0}\u00a7r +giveSpawnFailure=\u00a74\u6c92\u6709\u8db3\u5920\u7684\u7a7a\u9593, \u00a7c{0} \u00a7c{1} \u00a74\u5df2\u907a\u5931. +noKitGroup=\u00a74\u4f60\u6c92\u6709\u6b0a\u9650\u4f7f\u7528\u9019\u500b\u5de5\u5177\u7d44. +inventoryClearingFromAll=\u00a76\u6e05\u9664\u6240\u6709\u73a9\u5bb6\u7684\u96a8\u8eab\u7269\u54c1... +inventoryClearingAllItems=\u00a76\u6e05\u9664{0}\u7684\u96a8\u8eab\u7269\u54c1\u00a76. +inventoryClearingAllArmor=\u00a76\u6e05\u9664{0}\u7684\u96a8\u8eab\u7269\u54c1\u548c\u88dd\u5099\u00a76.\u00a0 +inventoryClearingAllStack=\u00a76\u6e05\u9664\u6240\u6709{1}\u00a76\u7684\u00a7c{0}\u00a76. +inventoryClearingStack=\u00a76\u6e05\u9664{2}\u7684\u00a7c{0}\u00a76\u500b\u00a7c{1}\u00a76. +inventoryClearFail=\u00a7\u73a9\u5bb6{0}\u00a74\u4e26\u6c92\u6709\u00a7c{1}\u00a74\u500b\u00a7c{2}\u00a74. +localNoOne= +totalSellableAll=\u00a7a\u6240\u6709\u53ef\u8ce3\u51fa\u7269\u54c1\u548c\u65b9\u584a\u7684\u50f9\u503c\u70ba\u00a7c{1}\u00a7a. +totalSellableBlocks=\u00a7a\u6240\u6709\u53ef\u8ce3\u51fa\u65b9\u584a\u7684\u50f9\u503c\u70ba\u00a7c{1}\u00a7a. +radiusTooBig=\u00a74\u7bc4\u570d\u592a\u5927\! \u6700\u5927\u7bc4\u570d\u70ba{0}. +isIpBanned=\u00a76IP \u00a7c{0} \u00a76\u5df2\u88ab\u5c01\u9396\u3002 +mobDataList=\u00a76\u6709\u6548\u7684\u751f\u7269\u8cc7\u6599\uff1a\u00a7r {0} +vanish=\u00a76\u5c07 {0} \u00a76\u7684\u96b1\u5f62\u6a21\u5f0f {1} +noLocationFound=\u00a74\u627e\u4e0d\u5230\u6709\u6548\u5730\u9ede\u3002 +coordsKeyword={0}, {1}, {2} +banExemptOffline=\u00a74\u4f60\u4e0d\u80fd\u5c01\u9396\u96e2\u7dda\u73a9\u5bb6\u3002 +tempbanExemptOffline=\u00a74\u4f60\u4e0d\u80fd\u66ab\u6642\u5c01\u9396\u96e2\u7dda\u73a9\u5bb6\u3002 +mayNotJailOffline=\u00a74\u4f60\u4e0d\u80fd\u5c07\u96e2\u7dda\u73a9\u5bb6\u95dc\u5165\u76e3\u7344\u3002 +muteExemptOffline=\u00a74\u4f60\u4e0d\u80fd\u5c07\u96e2\u7dda\u73a9\u5bb6\u7981\u8a00 +ignoreExempt=\u00a74\u4f60\u4e0d\u80fd\u5ffd\u7565\u90a3\u500b\u73a9\u5bb6\u3002 +unsafeTeleportDestination=\u00a74\u50b3\u9001\u76ee\u7684\u5730\u4e0d\u5b89\u5168\u4e14\u5b89\u5168\u50b3\u9001\u8655\u65bc\u7981\u7528\u72c0\u614b +noMetaJson=\u9019\u500b\u7248\u672c\u7684 Bukkit \u4e0d\u652f\u63f4 JSON \u4e2d\u7e7c\u8cc7\u6599 +maxMoney=\u00a74\u9019\u7b46\u4ea4\u6613\u5c07\u8d85\u51fa\u6b64\u5e33\u6236\u7684\u9918\u984d\u9650\u5236 +skullChanged=\u00a76\u982d\u9871\u4fee\u6539\u70ba \u00a7c{0}\u00a76\u3002 +alphaNames=\u00a74\u73a9\u5bb6\u540d\u7a31\u53ea\u80fd\u7531\u5b57\u6bcd\u3001\u6578\u5b57\u3001\u5e95\u7dda\u7d44\u6210\u3002 +givenSkull=\u00a76\u4f60\u53d6\u5f97\u4e86\u00a7c {0} \u00a76\u7684\u982d\u9871\u3002 +noPermissionSkull=\u00a74\u4f60\u6c92\u6709\u6b0a\u9650\u4fee\u6539\u9019\u500b\u982d\u9871\u3002 +teleportInvalidLocation=\u5ea7\u6a19\u7684\u6578\u503c\u4e0d\u5f97\u8d85\u904e 30000000 +invalidSkull=\u00a74\u8acb\u62ff\u8457\u73a9\u5bb6\u982d\u9871 +weatherInvalidWorld=\u627e\u4e0d\u5230\u540d\u70ba {0} \u7684\u4e16\u754c\uff01 +gameModeInvalid=\u00a74\u4f60\u5fc5\u9808\u6307\u5b9a\u4e00\u500b\u6709\u6548\u7684\u73a9\u5bb6\u6216\u6a21\u5f0f +mailTooLong=\u00a74\u90f5\u4ef6\u8a0a\u606f\u904e\u9577\uff0c\u8acb\u4e0d\u8981\u8d85\u904e1000\u5b57\u3002 +mailDelay=\u5728\u6700\u5f8c\u4e00\u5206\u9418\u5167\u767c\u9001\u592a\u591a\u90f5\u4ef6\uff0c\u6700\u591a {0} \u5c01 +seenAccounts=\u00a76Player has also been known as\:\u00a7c {0} +unableToSpawnItem=\u00a74\u7121\u6cd5\u751f\u6210 \u00a7c{0}\u00a74\uff0c\u9019\u4e0d\u662f\u53ef\u751f\u6210\u7684\u7269\u4ef6\u3002 +itemsConverted=\u00a76Converted all items into blocks. +itemsNotConverted=\u00a74You have no items that can be converted into blocks. +mailSentTo=\u00a7c{0}\u00a76 has been sent the following mail\: +mailMessage={0} + +whoisTempBanned=\u00a76 - Ban expires:\u00a7r {0} +playerTempBanned=\u00a76Player \u00a7c{0}\u00a76 temporarily banned \u00a7c{1}\u00a76 for \u00a7c{2}\u00a76: \u00a7c{3}\u00a76. +mailFormat=\u00a76[\u00a7r{0}\u00a76] \u00a7r{1} diff --git a/Essentials/src/motd.txt b/Essentials/src/motd.txt new file mode 100644 index 0000000000..9dd5a40366 --- /dev/null +++ b/Essentials/src/motd.txt @@ -0,0 +1,4 @@ +&6Welcome, {PLAYER}&6! +&6Type &c/help&6 for a list of commands. +&6Type &c/list&6 to see who else is online. +&6Players online:&c {ONLINE} &6- World time:&c {WORLDTIME12} \ No newline at end of file diff --git a/Essentials/src/net/ess3/api/Economy.java b/Essentials/src/net/ess3/api/Economy.java new file mode 100644 index 0000000000..283ef37229 --- /dev/null +++ b/Essentials/src/net/ess3/api/Economy.java @@ -0,0 +1,7 @@ +package net.ess3.api; + + +public class Economy extends com.earth2me.essentials.api.Economy +{ + +} diff --git a/Essentials/src/net/ess3/api/IEssentials.java b/Essentials/src/net/ess3/api/IEssentials.java new file mode 100644 index 0000000000..be5671176f --- /dev/null +++ b/Essentials/src/net/ess3/api/IEssentials.java @@ -0,0 +1,6 @@ +package net.ess3.api; + +public interface IEssentials extends com.earth2me.essentials.IEssentials +{ + +} diff --git a/Essentials/src/net/ess3/api/II18n.java b/Essentials/src/net/ess3/api/II18n.java new file mode 100644 index 0000000000..5bbe0e7024 --- /dev/null +++ b/Essentials/src/net/ess3/api/II18n.java @@ -0,0 +1,7 @@ +package net.ess3.api; + + +public interface II18n extends com.earth2me.essentials.api.II18n +{ + +} diff --git a/Essentials/src/net/ess3/api/IItemDb.java b/Essentials/src/net/ess3/api/IItemDb.java new file mode 100644 index 0000000000..eb9afb3c51 --- /dev/null +++ b/Essentials/src/net/ess3/api/IItemDb.java @@ -0,0 +1,7 @@ +package net.ess3.api; + + +public interface IItemDb extends com.earth2me.essentials.api.IItemDb +{ + +} diff --git a/Essentials/src/net/ess3/api/IJails.java b/Essentials/src/net/ess3/api/IJails.java new file mode 100644 index 0000000000..d36e4f76b1 --- /dev/null +++ b/Essentials/src/net/ess3/api/IJails.java @@ -0,0 +1,7 @@ +package net.ess3.api; + + +public interface IJails extends com.earth2me.essentials.api.IJails +{ + +} diff --git a/Essentials/src/net/ess3/api/IReload.java b/Essentials/src/net/ess3/api/IReload.java new file mode 100644 index 0000000000..b706342e27 --- /dev/null +++ b/Essentials/src/net/ess3/api/IReload.java @@ -0,0 +1,7 @@ +package net.ess3.api; + + +public interface IReload extends com.earth2me.essentials.api.IReload +{ + +} diff --git a/Essentials/src/net/ess3/api/ISettings.java b/Essentials/src/net/ess3/api/ISettings.java new file mode 100644 index 0000000000..256cf16351 --- /dev/null +++ b/Essentials/src/net/ess3/api/ISettings.java @@ -0,0 +1,7 @@ +package net.ess3.api; + + +public interface ISettings extends com.earth2me.essentials.ISettings +{ + +} diff --git a/Essentials/src/net/ess3/api/ITeleport.java b/Essentials/src/net/ess3/api/ITeleport.java new file mode 100644 index 0000000000..967b38ba31 --- /dev/null +++ b/Essentials/src/net/ess3/api/ITeleport.java @@ -0,0 +1,7 @@ +package net.ess3.api; + + +public interface ITeleport extends com.earth2me.essentials.api.ITeleport +{ + +} diff --git a/Essentials/src/net/ess3/api/IUser.java b/Essentials/src/net/ess3/api/IUser.java new file mode 100644 index 0000000000..b68c6e5cfc --- /dev/null +++ b/Essentials/src/net/ess3/api/IUser.java @@ -0,0 +1,8 @@ +package net.ess3.api; + + + +public interface IUser extends com.earth2me.essentials.IUser +{ + +} diff --git a/Essentials/src/net/ess3/api/IWarps.java b/Essentials/src/net/ess3/api/IWarps.java new file mode 100644 index 0000000000..c71ef7d7f3 --- /dev/null +++ b/Essentials/src/net/ess3/api/IWarps.java @@ -0,0 +1,7 @@ +package net.ess3.api; + + +public interface IWarps extends com.earth2me.essentials.api.IWarps +{ + +} diff --git a/Essentials/src/net/ess3/api/InvalidNameException.java b/Essentials/src/net/ess3/api/InvalidNameException.java new file mode 100644 index 0000000000..013ac7ef0d --- /dev/null +++ b/Essentials/src/net/ess3/api/InvalidNameException.java @@ -0,0 +1,16 @@ +package net.ess3.api; + + +public class InvalidNameException extends Exception +{ + /** + * NOTE: This is not implemented yet, just here for future 3.x api support + * Allow serialization of the InvalidNameException exception + */ + private static final long serialVersionUID = 1485321420293663139L; + + public InvalidNameException(Throwable thrwbl) + { + super(thrwbl); + } +} diff --git a/Essentials/src/net/ess3/api/InvalidWorldException.java b/Essentials/src/net/ess3/api/InvalidWorldException.java new file mode 100644 index 0000000000..210b077620 --- /dev/null +++ b/Essentials/src/net/ess3/api/InvalidWorldException.java @@ -0,0 +1,20 @@ +package net.ess3.api; + +import static com.earth2me.essentials.I18n.tl; + + +public class InvalidWorldException extends Exception +{ + private final String world; + + public InvalidWorldException(final String world) + { + super(tl("invalidWorld")); + this.world = world; + } + + public String getWorld() + { + return this.world; + } +} diff --git a/Essentials/src/net/ess3/api/MaxMoneyException.java b/Essentials/src/net/ess3/api/MaxMoneyException.java new file mode 100644 index 0000000000..bdc78aad21 --- /dev/null +++ b/Essentials/src/net/ess3/api/MaxMoneyException.java @@ -0,0 +1,12 @@ +package net.ess3.api; + +import static com.earth2me.essentials.I18n.tl; + + +public class MaxMoneyException extends Exception +{ + public MaxMoneyException() + { + super(tl("maxMoney")); + } +} diff --git a/Essentials/src/net/ess3/api/NoLoanPermittedException.java b/Essentials/src/net/ess3/api/NoLoanPermittedException.java new file mode 100644 index 0000000000..ed9cd8ca94 --- /dev/null +++ b/Essentials/src/net/ess3/api/NoLoanPermittedException.java @@ -0,0 +1,12 @@ +package net.ess3.api; + +import static com.earth2me.essentials.I18n.tl; + + +public class NoLoanPermittedException extends Exception +{ + public NoLoanPermittedException() + { + super(tl("negativeBalanceError")); + } +} diff --git a/Essentials/src/net/ess3/api/UserDoesNotExistException.java b/Essentials/src/net/ess3/api/UserDoesNotExistException.java new file mode 100644 index 0000000000..9be186a5a4 --- /dev/null +++ b/Essentials/src/net/ess3/api/UserDoesNotExistException.java @@ -0,0 +1,12 @@ +package net.ess3.api; + +import static com.earth2me.essentials.I18n.tl; + + +public class UserDoesNotExistException extends Exception +{ + public UserDoesNotExistException(String name) + { + super(tl("userDoesNotExist", name)); + } +} diff --git a/Essentials/src/net/ess3/api/events/AfkStatusChangeEvent.java b/Essentials/src/net/ess3/api/events/AfkStatusChangeEvent.java new file mode 100644 index 0000000000..048bf1ce4d --- /dev/null +++ b/Essentials/src/net/ess3/api/events/AfkStatusChangeEvent.java @@ -0,0 +1,12 @@ +package net.ess3.api.events; + +import net.ess3.api.IUser; + + +public class AfkStatusChangeEvent extends StatusChangeEvent +{ + public AfkStatusChangeEvent(IUser affected, boolean value) + { + super(affected, affected, value); + } +} diff --git a/Essentials/src/net/ess3/api/events/GodStatusChangeEvent.java b/Essentials/src/net/ess3/api/events/GodStatusChangeEvent.java new file mode 100644 index 0000000000..2d141cf6da --- /dev/null +++ b/Essentials/src/net/ess3/api/events/GodStatusChangeEvent.java @@ -0,0 +1,12 @@ +package net.ess3.api.events; + +import net.ess3.api.IUser; + + +public class GodStatusChangeEvent extends StatusChangeEvent +{ + public GodStatusChangeEvent(IUser affected, IUser controller, boolean value) + { + super(affected, controller, value); + } +} diff --git a/Essentials/src/net/ess3/api/events/IgnoreStatusChangeEvent.java b/Essentials/src/net/ess3/api/events/IgnoreStatusChangeEvent.java new file mode 100644 index 0000000000..2ea76228f3 --- /dev/null +++ b/Essentials/src/net/ess3/api/events/IgnoreStatusChangeEvent.java @@ -0,0 +1,12 @@ +package net.ess3.api.events; + +import net.ess3.api.IUser; + + +public class IgnoreStatusChangeEvent extends StatusChangeEvent +{ + public IgnoreStatusChangeEvent(IUser affected, IUser controller, boolean value) + { + super(affected, controller, value); + } +} diff --git a/Essentials/src/net/ess3/api/events/JailStatusChangeEvent.java b/Essentials/src/net/ess3/api/events/JailStatusChangeEvent.java new file mode 100644 index 0000000000..ff884d1a24 --- /dev/null +++ b/Essentials/src/net/ess3/api/events/JailStatusChangeEvent.java @@ -0,0 +1,12 @@ +package net.ess3.api.events; + +import net.ess3.api.IUser; + + +public class JailStatusChangeEvent extends StatusChangeEvent +{ + public JailStatusChangeEvent(IUser affected, IUser controller, boolean value) + { + super(affected, controller, value); + } +} \ No newline at end of file diff --git a/Essentials/src/net/ess3/api/events/LocalChatSpyEvent.java b/Essentials/src/net/ess3/api/events/LocalChatSpyEvent.java new file mode 100644 index 0000000000..1071a9f6d0 --- /dev/null +++ b/Essentials/src/net/ess3/api/events/LocalChatSpyEvent.java @@ -0,0 +1,128 @@ +package net.ess3.api.events; + +import static com.earth2me.essentials.I18n.tl; +import java.util.IllegalFormatException; +import java.util.Set; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + + +public class LocalChatSpyEvent extends Event implements Cancellable +{ + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled = false; + private String message; + private String format; + private Player player; + private final Set recipients; + + public LocalChatSpyEvent(final boolean async, final Player who, final String format, final String message, final Set players) + { + super(async); + this.format = tl("chatTypeLocal").concat(tl("chatTypeSpy")).concat(format); + this.message = message; + recipients = players; + player = who; + } + + /** + * Gets the message that the player is attempting to send. This message will be used with {@link #getFormat()}. + * + * @return Message the player is attempting to send + */ + public String getMessage() + { + return message; + } + + /** + * Sets the message that the player will send. This message will be used with {@link #getFormat()}. + * + * @param message New message that the player will send + */ + public void setMessage(String message) + { + this.message = message; + } + + /** + * Gets the format to use to display this chat message. When this event finishes execution, the first format + * parameter is the {@link Player#getDisplayName()} and the second parameter is {@link #getMessage()} + * + * @return {@link String#format(String, Object...)} compatible format string + */ + public String getFormat() + { + return format; + } + + /** + * Sets the format to use to display this chat message. When this event finishes execution, the first format + * parameter is the {@link Player#getDisplayName()} and the second parameter is {@link #getMessage()} + * + * @param format {@link String#format(String, Object...)} compatible format string + * @throws IllegalFormatException if the underlying API throws the exception + * @throws NullPointerException if format is null + * @see String#format(String, Object...) + */ + public void setFormat(final String format) throws IllegalFormatException, NullPointerException + { + // Oh for a better way to do this! + try + { + String.format(format, player, message); + } + catch (RuntimeException ex) + { + ex.fillInStackTrace(); + throw ex; + } + + this.format = format; + } + + /** + * Gets a set of recipients that this chat message will be displayed to. + * + * @return All Players who will see this chat message + */ + public Set getRecipients() + { + return recipients; + } + + /** + * Returns the player involved in this event + * + * @return Player who is involved in this event + */ + public final Player getPlayer() + { + return player; + } + + @Override + public boolean isCancelled() + { + return cancelled; + } + + @Override + public void setCancelled(boolean cancel) + { + this.cancelled = cancel; + } + + @Override + public HandlerList getHandlers() + { + return handlers; + } + + public static HandlerList getHandlerList() + { + return handlers; + } +} diff --git a/Essentials/src/net/ess3/api/events/MuteStatusChangeEvent.java b/Essentials/src/net/ess3/api/events/MuteStatusChangeEvent.java new file mode 100644 index 0000000000..428883d764 --- /dev/null +++ b/Essentials/src/net/ess3/api/events/MuteStatusChangeEvent.java @@ -0,0 +1,12 @@ +package net.ess3.api.events; + +import net.ess3.api.IUser; + + +public class MuteStatusChangeEvent extends StatusChangeEvent +{ + public MuteStatusChangeEvent(IUser affected, IUser controller, boolean value) + { + super(affected, controller, value); + } +} diff --git a/Essentials/src/net/ess3/api/events/NickChangeEvent.java b/Essentials/src/net/ess3/api/events/NickChangeEvent.java new file mode 100644 index 0000000000..ac4a83b757 --- /dev/null +++ b/Essentials/src/net/ess3/api/events/NickChangeEvent.java @@ -0,0 +1,21 @@ +package net.ess3.api.events; + +import net.ess3.api.IUser; +import org.bukkit.event.Cancellable; + + +public class NickChangeEvent extends StateChangeEvent implements Cancellable +{ + private String newValue; + + public NickChangeEvent(IUser affected, IUser controller, String value) + { + super(affected, controller); + this.newValue = value; + } + + public String getValue() + { + return newValue; + } +} diff --git a/Essentials/src/net/ess3/api/events/SignBreakEvent.java b/Essentials/src/net/ess3/api/events/SignBreakEvent.java new file mode 100644 index 0000000000..9c3e69d7ee --- /dev/null +++ b/Essentials/src/net/ess3/api/events/SignBreakEvent.java @@ -0,0 +1,13 @@ +package net.ess3.api.events; + +import com.earth2me.essentials.signs.EssentialsSign; +import net.ess3.api.IUser; + + +public class SignBreakEvent extends SignEvent +{ + public SignBreakEvent(EssentialsSign.ISign sign, EssentialsSign essSign, IUser user) + { + super(sign, essSign, user); + } +} diff --git a/Essentials/src/net/ess3/api/events/SignCreateEvent.java b/Essentials/src/net/ess3/api/events/SignCreateEvent.java new file mode 100644 index 0000000000..ac0520119e --- /dev/null +++ b/Essentials/src/net/ess3/api/events/SignCreateEvent.java @@ -0,0 +1,13 @@ +package net.ess3.api.events; + +import com.earth2me.essentials.signs.EssentialsSign; +import net.ess3.api.IUser; + + +public class SignCreateEvent extends SignEvent +{ + public SignCreateEvent(EssentialsSign.ISign sign, EssentialsSign essSign, IUser user) + { + super(sign, essSign, user); + } +} diff --git a/Essentials/src/net/ess3/api/events/SignEvent.java b/Essentials/src/net/ess3/api/events/SignEvent.java new file mode 100644 index 0000000000..01689db19b --- /dev/null +++ b/Essentials/src/net/ess3/api/events/SignEvent.java @@ -0,0 +1,68 @@ +package net.ess3.api.events; + +import com.earth2me.essentials.signs.EssentialsSign; +import com.earth2me.essentials.signs.EssentialsSign.ISign; +import net.ess3.api.IUser; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + + +/** + * This handles common boilerplate for other SignEvent + * + */ +public class SignEvent extends Event implements Cancellable +{ + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled = false; + ISign sign; + EssentialsSign essSign; + IUser user; + + public SignEvent(final ISign sign, final EssentialsSign essSign, final IUser user) + { + super(); + this.sign = sign; + this.essSign = essSign; + this.user = user; + } + + public ISign getSign() + { + return sign; + } + + public EssentialsSign getEssentialsSign() + { + return essSign; + } + + public IUser getUser() + { + return user; + } + + @Override + public HandlerList getHandlers() + { + return handlers; + } + + public static HandlerList getHandlerList() + { + return handlers; + } + + @Override + public boolean isCancelled() + { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) + { + this.cancelled = cancelled; + } +} diff --git a/Essentials/src/net/ess3/api/events/SignInteractEvent.java b/Essentials/src/net/ess3/api/events/SignInteractEvent.java new file mode 100644 index 0000000000..f67f68a0e0 --- /dev/null +++ b/Essentials/src/net/ess3/api/events/SignInteractEvent.java @@ -0,0 +1,13 @@ +package net.ess3.api.events; + +import com.earth2me.essentials.signs.EssentialsSign; +import net.ess3.api.IUser; + + +public class SignInteractEvent extends SignEvent +{ + public SignInteractEvent(EssentialsSign.ISign sign, EssentialsSign essSign, IUser user) + { + super(sign, essSign, user); + } +} diff --git a/Essentials/src/net/ess3/api/events/StateChangeEvent.java b/Essentials/src/net/ess3/api/events/StateChangeEvent.java new file mode 100644 index 0000000000..bcdfc247cb --- /dev/null +++ b/Essentials/src/net/ess3/api/events/StateChangeEvent.java @@ -0,0 +1,66 @@ +package net.ess3.api.events; + +import net.ess3.api.IUser; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + + +/** + * This handles common boilerplate for other StateChangeEvents + * + */ +public class StateChangeEvent extends Event implements Cancellable +{ + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled = false; + IUser affected; + IUser controller; + + public StateChangeEvent(IUser affected, IUser controller) + { + super(); + this.affected = affected; + this.controller = controller; + } + + public StateChangeEvent(boolean isAsync, IUser affected, IUser controller) + { + super(isAsync); + this.affected = affected; + this.controller = controller; + } + + public IUser getAffected() + { + return this.affected; + } + + public IUser getController() + { + return controller; + } + + @Override + public HandlerList getHandlers() + { + return handlers; + } + + public static HandlerList getHandlerList() + { + return handlers; + } + + @Override + public boolean isCancelled() + { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) + { + this.cancelled = cancelled; + } +} diff --git a/Essentials/src/net/ess3/api/events/StatusChangeEvent.java b/Essentials/src/net/ess3/api/events/StatusChangeEvent.java new file mode 100644 index 0000000000..d8d43a0428 --- /dev/null +++ b/Essentials/src/net/ess3/api/events/StatusChangeEvent.java @@ -0,0 +1,31 @@ +package net.ess3.api.events; + +import net.ess3.api.IUser; +import org.bukkit.event.Cancellable; + + +/** + * This handles common boilerplate for other StatusChangeEvents + * + */ +public class StatusChangeEvent extends StateChangeEvent implements Cancellable +{ + private boolean newValue; + + public StatusChangeEvent(IUser affected, IUser controller, boolean value) + { + super(affected, controller); + this.newValue = value; + } + + public StatusChangeEvent(boolean isAsync, IUser affected, IUser controller, boolean value) + { + super(isAsync, affected, controller); + this.newValue = value; + } + + public boolean getValue() + { + return newValue; + } +} diff --git a/Essentials/src/net/ess3/api/events/UserBalanceUpdateEvent.java b/Essentials/src/net/ess3/api/events/UserBalanceUpdateEvent.java new file mode 100644 index 0000000000..f656388ee7 --- /dev/null +++ b/Essentials/src/net/ess3/api/events/UserBalanceUpdateEvent.java @@ -0,0 +1,49 @@ +package net.ess3.api.events; + +import java.math.BigDecimal; + +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + + +public class UserBalanceUpdateEvent extends Event +{ + private static final HandlerList handlers = new HandlerList(); + private final Player player; + private final BigDecimal originalBalance; + private final BigDecimal balance; + + public UserBalanceUpdateEvent(Player player, BigDecimal originalBalance, BigDecimal balance) + { + this.player = player; + this.originalBalance = originalBalance; + this.balance = balance; + } + + @Override + public HandlerList getHandlers() + { + return handlers; + } + + public static HandlerList getHandlerList() + { + return handlers; + } + + public Player getPlayer() + { + return player; + } + + public BigDecimal getNewBalance() + { + return balance; + } + + public BigDecimal getOldBalance() + { + return originalBalance; + } +} diff --git a/Essentials/src/plugin.yml b/Essentials/src/plugin.yml new file mode 100644 index 0000000000..dc2725d4bf --- /dev/null +++ b/Essentials/src/plugin.yml @@ -0,0 +1,485 @@ +# This determines the command prefix when there are conflicts (/name:home, /name:help, etc.) +name: Essentials +main: com.earth2me.essentials.Essentials +# Note to developers: This next line cannot change, or the automatic versioning system will break. +version: TeamCity +website: http://tiny.cc/EssentialsCommands +description: Provides an essential, core set of commands for Bukkit. +authors: [Zenexer, ementalo, Aelux, Brettflan, KimKandor, snowleo, ceulemans, Xeology, KHobbits, md_5, Iaccidentally] +commands: + afk: + description: Marks you as away-from-keyboard. + usage: / [player] + aliases: [eafk,away,eaway] + antioch: + description: 'A little surprise for operators.' + usage: / [message] + aliases: [eantioch,grenade,egrenade,tnt,etnt] + back: + description: Teleports you to your location prior to tp/spawn/warp. + usage: / + aliases: [eback,return,ereturn] + backup: + description: Runs the backup if configured. + usage: / + aliases: [ebackup] + balance: + description: States the current balance of a player. + usage: / [player] + aliases: [bal,ebal,ebalance,money,emoney] + balancetop: + description: Gets the top balance values. + usage: / + aliases: [ebalancetop,baltop,ebaltop] + ban: + description: Bans a player. + usage: / [reason] + aliases: [eban] + banip: + description: Bans an IP address. + usage: /
+ aliases: [ebanip] + book: + description: Allows reopening and editing of sealed books. + usage: / [title|author [name]] + aliases: [ebook] + break: + description: Breaks the block you are looking at. + usage: / + aliases: [ebreak] + broadcast: + description: Broadcasts a message to the entire server. + usage: / + aliases: [bc,ebc,bcast,ebcast,ebroadcast,shout,eshout] + bigtree: + description: Spawn a big tree where you are looking. + usage: / + aliases: [ebigtree,largetree,elargetree] + burn: + description: Set a player on fire. + usage: / + aliases: [eburn] + clearinventory: + description: Clear all items in your inventory. + usage: / [player|*] [item[:]|*|**] [amount] + aliases: [ci,eci,clean,eclean,clear,eclear,clearinvent,eclearinvent,eclearinventory] + condense: + description: Condenses items into a more compact blocks. + usage: / [||hand|inventory] + aliases: [econdense,compact,ecompact,blocks,eblocks,toblocks,etoblocks] + compass: + description: Describes your current bearing. + usage: / + aliases: [ecompass,direction,edirection] + customtext: + description: Allows you to create custom text commands. + usage: / - Define in bukkit.yml + delhome: + description: Removes a home. + usage: / [player:] + aliases: [edelhome,remhome,eremhome,rmhome,ermhome] + deljail: + description: Removes a jail. + usage: / + aliases: [edeljail,remjail,eremjail,rmjail,ermjail] + delwarp: + description: Deletes the specified warp. + usage: / + aliases: [edelwarp,remwarp,eremwarp,rmwarp,ermwarp] + depth: + description: States current depth, relative to sea level. + usage: /depth + aliases: [edepth,height,eheight] + eco: + description: Manages the server economy. + usage: / + aliases: [eeco,economy,eeconomy] + enchant: + description: Enchants the item the user is holding. + usage: / [level] + aliases: [eenchant,enchantment,eenchantment] + enderchest: + description: Lets you see inside an enderchest. + usage: / [player] + aliases: [echest,eechest,eenderchest,endersee,eendersee,ec,eec] + essentials: + description: Reloads essentials. + usage: / + aliases: [eessentials, ess, eess, essversion] + exp: + description: Give, set or look at a players exp. + usage: / [show|set|give] [playername [amount]] + aliases: [eexp,xp] + ext: + description: Extinguish players. + usage: / [player] + aliases: [eext,extinguish,eextinguish] + feed: + description: Satisfy the hunger. + usage: / [player] + aliases: [eat,eeat,efeed] + fly: + description: Take off, and soar! + usage: / [player] [on|off] + aliases: [efly] + fireball: + description: Throw a fireball. + usage: / [small|skull] + aliases: [efireball,fireentity,efireentity,fireskull,efireskull] + firework: + description: Allows you to modify a stack of fireworks. + usage: / <|power [amount]|clear|fire [amount]> + aliases: [efirework] + gamemode: + description: Change player gamemode. + usage: / [player] + aliases: [adventure,eadventure,adventuremode,eadventuremode,creative,eecreative,creativemode,ecreativemode,egamemode,gm,egm,gma,egma,gmc,egmc,gms,egms,gmt,egmt,survival,esurvival,survivalmode,esurvivalmode] + gc: + description: Reports memory, uptime and tick info. + usage: / [all] + aliases: [lag,elag,egc,mem,emem,memory,ememory,uptime,euptime,tps,etps,entities,eentities] + getpos: + description: Get your current coordinates or those of a player. + usage: / [player] + aliases: [coords,egetpos,position,eposition,whereami,ewhereami,getlocation,egetlocation,getloc,egetloc] + give: + description: Give a player an item. + usage: / [amount [itemmeta...]] + aliases: [egive] + god: + description: Enables your godly powers. + usage: / [player] [on|off] + aliases: [egod,godmode,egodmode,tgm,etgm] + hat: + description: Get some cool new headgear. + usage: / [remove] + aliases: [ehat,head,ehead] + heal: + description: Heals you or the given player. + usage: / [player] + aliases: [eheal] + help: + description: Views a list of available commands. + usage: / [search term] [page] + aliases: [ehelp] + helpop: + description: Message online admins. + usage: / + aliases: [ac,eac,amsg,eamsg,ehelpop] + home: + description: Teleport to your home. + usage: / [player:][name] + aliases: [ehome,homes,ehomes] + ignore: + description: Ignore or unignore other players. + usage: / + aliases: [eignore,unignore,eunignore,delignore,edelignore,remignore,eremignore,rmignore,ermignore] + info: + description: Shows information set by the server owner. + usage: / [chapter] [page] + aliases: [about,eabout,ifo,eifo,einfo,inform,einform,news,enews] + invsee: + description: See the inventory of other players. + usage: / + aliases: [einvsee] + item: + description: Spawn an item. + usage: / [amount [itemmeta...]] + aliases: [i,eitem,ei] + itemdb: + description: Searches for an item. + usage: / + aliases: [dura,edura,durability,edurability,eitemdb,itemno,eitemno] + jails: + description: List all jails. + usage: / + aliases: [ejails] + jump: + description: Jumps to the nearest block in the line of sight. + usage: / + aliases: [j,ej,ejump,jumpto,ejumpto] + kick: + description: Kicks a specified player with a reason. + usage: / [reason] + aliases: [ekick] + kickall: + description: Kicks all players off the server except the issuer. + usage: / [reason] + aliases: [ekickall] + kill: + description: Kills specified player. + usage: / + aliases: [ekill] + kit: + description: Obtains the specified kit or views all available kits. + usage: / [kit] [player] + aliases: [ekit,kits,ekits] + kittycannon: + description: Throw an exploding kitten at your opponent. + usage: / + aliases: [ekittycannon] + lightning: + description: The power of Thor. Strike at cursor or player. + usage: / [player] [power] + aliases: [elightning,shock,eshock,smite,esmite,strike,estrike,thor,ethor] + list: + description: List all online players. + usage: / [group] + aliases: [elist,online,eonline,playerlist,eplayerlist,plist,eplist,who,ewho] + mail: + description: Manages inter-player, intra-server mail. + usage: / [read|clear|send [to] [message]|sendall [message]] + aliases: [email,eemail,memo,ememo] + me: + description: Describes an action in the context of the player. + usage: / + aliases: [action,eaction,describe,edescribe,eme] + more: + description: Fills the item stack in hand to maximum size. + usage: / + aliases: [emore] + motd: + description: Views the Message Of The Day. + usage: / [chapter] [page] + aliases: [emotd] + msg: + description: Sends a private message to the specified player. + usage: / + aliases: [w,m,t,pm,emsg,epm,tell,etell,whisper,ewhisper] + mute: + description: Mutes or unmutes a player. + usage: / [datediff] + aliases: [emute,silence,esilence] + near: + description: Lists the players near by or around a player. + usage: / [playername] [radius] + aliases: [enear,nearby,enearby] + nick: + description: Change your nickname or that of another player. + usage: / [player] + aliases: [enick,nickname,enickname] + nuke: + description: May death rain upon them. + usage: / [player] + aliases: [enuke] + pay: + description: Pays another player from your balance. + usage: / + aliases: [epay] + ping: + description: Pong! + usage: / + aliases: [echo,eecho,eping,pong,epong] + potion: + description: Adds custom potion effects to a potion. + usage: / power: duration:> + aliases: [epotion,elixer,eelixer] + powertool: + description: Assigns a command to the item in hand. + usage: / [l:|a:|r:|c:|d:][command] [arguments] - {player} can be replaced by name of a clicked player. + aliases: [epowertool,pt,ept] + powertooltoggle: + description: Enables or disables all current powertools. + usage: / + aliases: [epowertooltoggle,ptt,eptt,pttoggle,epttoggle] + ptime: + description: Adjust player's client time. Add @ prefix to fix. + usage: / [list|reset|day|night|dawn|17:30|4pm|4000ticks] [player|*] + aliases: [playertime,eplayertime,eptime] + pweather: + description: Adjust a player's weather + usage: / [list|reset|storm|sun|clear] [player|*] + aliases: [playerweather,eplayerweather,epweather] + r: + description: Quickly reply to the last player to message you. + usage: / + aliases: [er,reply,ereply] + realname: + description: Displays the username of a user based on nick. + usage: / + aliases: [erealname] + recipe: + description: Displays how to craft items. + usage: / [number] + aliases: [formula,eformula,method,emethod,erecipe,recipes,erecipes] + remove: + description: Removes entities in your world. + usage: / [radius|world] + aliases: [eremove,butcher,ebutcher,killall,ekillall,mobkill,emobkill] + repair: + description: Repairs the durability of one or all items. + usage: / [hand|all] + aliases: [fix,efix,erepair] + rules: + description: Views the server rules. + usage: / [chapter] [page] + aliases: [erules] + seen: + description: Shows the last logout time of a player. + usage: / + aliases: [eseen] + sell: + description: Sells the item currently in your hand. + usage: / <||hand|inventory|blocks> [-][amount] + aliases: [esell] + sethome: + description: Set your home to your current location. + usage: / [[player:]name] + aliases: [esethome,createhome,ecreatehome] + setjail: + description: Creates a jail where you specified named [jailname]. + usage: / + aliases: [esetjail,createjail,ecreatejail] + setwarp: + description: Creates a new warp. + usage: / + aliases: [createwarp,ecreatewarp,esetwarp] + setworth: + description: Set the sell value of an item. + usage: / [itemname|id] + aliases: [esetworth] + skull: + description: Set the owner of a player skull + usage: / [owner] + aliases: [eskull, playerskull, eplayerskull, head, ehead] + socialspy: + description: Toggles if you can see msg/mail commands in chat. + usage: / [player] [on|off] + aliases: [esocialspy] + spawner: + description: Change the mob type of a spawner. + usage: / [delay] + aliases: [changems,echangems,espawner,mobspawner,emobspawner] + spawnmob: + description: Spawns a mob. + usage: / [:data][,[:data]] [amount] [player] + aliases: [mob,emob,spawnentity,espawnentity,espawnmob] + speed: + description: Change your speed limits. + usage: / [type] [player] + aliases: [flyspeed,eflyspeed,fspeed,efspeed,espeed,walkspeed,ewalkspeed,wspeed,ewspeed] + sudo: + description: Make another user perform a command. + usage: / + aliases: [esudo] + suicide: + description: Causes you to perish. + usage: / + aliases: [esuicide] + tempban: + description: Temporary ban a user. + usage: / + aliases: [etempban] + thunder: + description: Enable/disable thunder. + usage: / [duration] + aliases: [ethunder] + time: + description: Display/Change the world time. Defaults to current world. + usage: / [day|night|dawn|17:30|4pm|4000ticks] [worldname|all] + aliases: [day,eday,night,enight,etime] + togglejail: + description: Jails/Unjails a player, TPs them to the jail specified. + usage: / [datediff] + aliases: [jail,ejail,tjail,etjail,etogglejail,unjail,eunjail] + top: + description: Teleport to the highest block at your current position. + usage: / + aliases: [etop] + tp: + description: Teleport to a player. + usage: / [otherplayer] + aliases: [tele,etele,teleport,eteleport,etp,tp2p,etp2p] + tpa: + description: Request to teleport to the specified player. + usage: / + aliases: [call,ecall,etpa,tpask,etpask] + tpaall: + description: Requests all players online to teleport to you. + usage: / + aliases: [etpaall] + tpaccept: + description: Accepts a teleport request. + usage: / [otherplayer] + aliases: [etpaccept,tpyes,etpyes] + tpahere: + description: Request that the specified player teleport to you. + usage: / + aliases: [etpahere] + tpall: + description: Teleport all online players to another player. + usage: / + aliases: [etpall] + tpdeny: + description: Reject a teleport request. + usage: / + aliases: [etpdeny,tpno,etpno] + tphere: + description: Teleport a player to you. + usage: / + aliases: [s,etphere] + tpo: + description: Teleport override for tptoggle. + usage: / [otherplayer] + aliases: [etpo] + tpohere: + description: Teleport here override for tptoggle. + usage: / + aliases: [etpohere] + tppos: + description: Teleport to coordinates. + usage: / [yaw] [pitch] + aliases: [etppos] + tptoggle: + description: Blocks all forms of teleportation. + usage: / [player] [on|off] + aliases: [etptoggle] + tree: + description: Spawn a tree where you are looking. + usage: / + aliases: [etree] + unban: + description: Unbans the specified player. + usage: / + aliases: [pardon,eunban,epardon] + unbanip: + description: Unbans the specified IP address. + usage: /
+ aliases: [eunbanip,pardonip,epardonip] + unlimited: + description: Allows the unlimited placing of items. + usage: / [player] + aliases: [eunlimited,ul,unl,eul,eunl] + vanish: + description: Hide yourself from other players. + usage: / [player] [on|off] + aliases: [v,ev,evanish] + warp: + description: List all warps or warp to the specified location. + usage: / [player] + aliases: [ewarp,warps,ewarps] + weather: + description: Sets the weather. + usage: / [duration] + aliases: [rain,erain,sky,esky,storm,estorm,sun,esun,eweather] + whois: + description: Determine the username behind a nickname. + usage: / + aliases: [ewhois] + workbench: + description: Opens up a workbench. + usage: / + aliases: [craft,ecraft,wb,ewb,wbench,ewbench,eworkbench] + world: + description: Switch between worlds. + usage: / [world] + aliases: [eworld] + worth: + description: Calculates the worth of items in hand or as specified. + usage: / <||hand|inventory|blocks> [-][amount] + aliases: [eprice,price,eworth] + +permissions: + essentials.*: + default: op + description: Give players with op everything by default diff --git a/Essentials/src/rules.txt b/Essentials/src/rules.txt new file mode 100644 index 0000000000..486bfdf293 --- /dev/null +++ b/Essentials/src/rules.txt @@ -0,0 +1,3 @@ +[1] Be respectful +[2] Be ethical +[3] Use common sense \ No newline at end of file diff --git a/Essentials/src/worth.yml b/Essentials/src/worth.yml new file mode 100644 index 0000000000..7d273e45da --- /dev/null +++ b/Essentials/src/worth.yml @@ -0,0 +1,186 @@ +worth: + + # Items not listed in this file will not be sellable on the server + # Setting the worth to 0 will sell items for free, delete the item or set to -1 to disable. + + # This will set the worth of all logs to '2' + log: 2.0 + + # This will work similar to the above syntax + wool: + '0': 20 + + # This will only allow selling leaves with datavalue '0' and '1' + leaves: + '0': 1.0 + '1': 1.0 + + # This will allow the selling of all, but sells '0' slightly cheaper + sapling: + '0': 2.0 + '*': 2.5 + + + stonebutton: 6.0 + wood: 0.50 + arrow: 3.50 + diamondpickaxe: 650.0 + rawfish: 5.0 + minecart: 23.0 + leatherchestplate: 85.0 + storageminecart: 30.0 + leaves: 1.0 + feather: 3.0 + goldchestplate: 6.5 + mushroomsoup: 4.5 + bread: 30.0 + stationarywater: 1.0 + workbench: 2.5 + stonehoe: 2.5 + brownmushroom: 2.0 + mossycobblestone: 90.0 + diamondhoe: 400.0 + woodsword: 1.0 + torch: 4.0 + grass: 1.0 + poweredminecart: 32.0 + snowball: 1.0 + goldenapple: 100.0 + leatherleggings: 75.0 + diamondaxe: 650.0 + slimeball: 50.0 + fence: 1.0 + stonespade: 1.5 + claybrick: 5.0 + noteblock: 36.0 + ironaxe: 22.0 + coalore: 15.0 + clayball: 3.0 + fishingrod: 10.0 + ironhoe: 22.0 + goldrecord: 100.0 + ironpickaxe: 22.0 + irondoor: 22.0 + bucket: 22.0 + redrose: 2.0 + grilledpork: 7.0 + gravel: 1.0 + wooddoor: 3.0 + chainmailhelmet: 40.0 + ironchestplate: 22.0 + diamondblock: 2000.0 + diamondhelmet: 1000.0 + goldhelmet: 6.0 + redstonetorchon: 32.0 + ironspade: 22.0 + furnace: 8.5 + ironsword: 22.0 + dispenser: 58.0 + woodaxe: 2.0 + seeds: 2.0 + painting: 25.0 + woodplate: 1.0 + redstoneore: 30.0 + diamondspade: 210.0 + waterbucket: 40.0 + water: 1.0 + bedrock: 100.0 + irondoorblock: 15.0 + goldhoe: 6.0 + sand: 1.0 + goldsword: 6.0 + stoneaxe: 3.0 + bookshelf: 140.0 + ironblock: 190.0 + jackolantern: 56.0 + boat: 3.0 + diamondchestplate: 1750.0 + redstonewire: 30.0 + redmushroom: 2.0 + string: 5.0 + stoneplate: 6.0 + wallsign: 1.0 + cactus: 10.0 + sulphur: 20.0 + rails: 22.0 + ironore: 18.0 + leatherhelmet: 52.0 + stone: 3.00 + egg: 1.0 + diamondore: 200.0 + woodhoe: 2.0 + goldleggings: 6.0 + chainmailleggings: 50.0 + yellowflower: 2.0 + ironhelmet: 22.0 + obsidian: 130.0 + dirt: 1.0 + leather: 10.0 + leatherboots: 42.0 + lever: 1.0 + cobblestone: 1.0 + cake: 180.0 + woodstairs: 1.0 + ironingot: 22.0 + goldore: 45.0 + pumpkin: 50.0 + bed: 68.0 + watch: 6.0 + ironleggings: 22.0 + sign: 1.5 + doublestep: 1.0 + woodpickaxe: 2.0 + stonepickaxe: 4.0 + chainmailboots: 30.0 + diamondleggings: 1500.0 + cookedfish: 7.0 + saddle: 100.0 + cobblestonestairs: 1.5 + tnt: 100.0 + glowingredstoneore: 30.0 + apple: 10.0 + woodspade: 1.0 + goldingot: 105.0 + diode: 110.0 + soil: 1.0 + clay: 12.0 + goldblock: 450.0 + stick: 0.25 + paper: 10.0 + brick: 21.0 + stationarylava: 1.0 + chest: 4.0 + sandstone: 3.0 + goldpickaxe: 6.0 + compass: 22.0 + sugarcane: 10.0 + diamondsword: 420.0 + goldboots: 6.0 + sponge: 80.0 + stonesword: 2.5 + coal: 15.0 + goldaxe: 6.0 + bone: 2.0 + diamond: 200.0 + glass: 3.00 + goldspade: 6.0 + lapisblock: 950.0 + lavabucket: 40.0 + wheat: 9.0 + ladder: 0.5 + sugarcaneblock: 15.0 + bowl: 0.50 + chainmailchestplate: 40.0 + diamondboots: 850.0 + lapisore: 100.0 + lava: 25.0 + milkbucket: 40.0 + redstone: 32.0 + greenrecord: 100.0 + inksack: 10.0 + glowstonedust: 10.0 + book: 45.0 + bow: 15.0 + ironboots: 22.0 + step: 1.5 + sugar: 10.0 diff --git a/Essentials/test/com/earth2me/essentials/EconomyTest.java b/Essentials/test/com/earth2me/essentials/EconomyTest.java new file mode 100644 index 0000000000..00d994b2b6 --- /dev/null +++ b/Essentials/test/com/earth2me/essentials/EconomyTest.java @@ -0,0 +1,126 @@ +package com.earth2me.essentials; + +import com.earth2me.essentials.api.NoLoanPermittedException; +import com.earth2me.essentials.api.UserDoesNotExistException; +import java.io.IOException; +import junit.framework.TestCase; +import static junit.framework.TestCase.assertFalse; +import static junit.framework.TestCase.fail; +import net.ess3.api.Economy; +import org.bukkit.World.Environment; +import org.bukkit.plugin.InvalidDescriptionException; +import org.junit.Test; + + +public class EconomyTest extends TestCase +{ + private final transient Essentials ess; + private static final String NPCNAME = "npc1"; + private static final String PLAYERNAME = "testPlayer1"; + + public EconomyTest(final String testName) + { + super(testName); + final FakeServer server = new FakeServer(); + server.createWorld("testWorld", Environment.NORMAL); + ess = new Essentials(server); + try + { + ess.setupForTesting(server); + } + catch (InvalidDescriptionException ex) + { + fail("InvalidDescriptionException"); + } + catch (IOException ex) + { + fail("IOException"); + } + server.addPlayer(new OfflinePlayer(PLAYERNAME, ess.getServer())); + } + + // only one big test, since we use static instances + @Test + public void testEconomy() + { + // test NPC + assertFalse("NPC does not exists", Economy.playerExists(NPCNAME)); + assertTrue("Create NPC", Economy.createNPC(NPCNAME)); + assertTrue("NPC exists", Economy.playerExists(NPCNAME)); + assertNotNull("NPC can be accessed", ess.getOfflineUser(NPCNAME)); + try + { + Economy.removeNPC(NPCNAME); + } + catch (UserDoesNotExistException ex) + { + fail(ex.getMessage()); + } + assertFalse("NPC can be removed", Economy.playerExists(NPCNAME)); + + //test Math + try + { + + assertTrue("Player exists", Economy.playerExists(PLAYERNAME)); + Economy.resetBalance(PLAYERNAME); + assertEquals("Player has no money", 0.0, Economy.getMoney(PLAYERNAME)); + Economy.add(PLAYERNAME, 10.0); + assertEquals("Add money", 10.0, Economy.getMoney(PLAYERNAME)); + Economy.subtract(PLAYERNAME, 5.0); + assertEquals("Subtract money", 5.0, Economy.getMoney(PLAYERNAME)); + Economy.multiply(PLAYERNAME, 2.0); + assertEquals("Multiply money", 10.0, Economy.getMoney(PLAYERNAME)); + Economy.divide(PLAYERNAME, 2.0); + assertEquals("Divide money", 5.0, Economy.getMoney(PLAYERNAME)); + Economy.setMoney(PLAYERNAME, 10.0); + assertEquals("Set money", 10.0, Economy.getMoney(PLAYERNAME)); + } + catch (NoLoanPermittedException ex) + { + fail(ex.getMessage()); + } + catch (UserDoesNotExistException ex) + { + fail(ex.getMessage()); + } + + //test Format + assertEquals("Format $1000", "$1000", Economy.format(1000.0)); + assertEquals("Format $10", "$10", Economy.format(10.0)); + assertEquals("Format $10.10", "$10.10", Economy.format(10.10)); + assertEquals("Format $10.10", "$10.10", Economy.format(10.1000001)); + assertEquals("Format $10.10", "$10.10", Economy.format(10.1099999)); + + + //test Exceptions + try + { + assertTrue("Player exists", Economy.playerExists(PLAYERNAME)); + Economy.resetBalance(PLAYERNAME); + assertEquals("Reset balance", 0.0, Economy.getMoney(PLAYERNAME)); + Economy.subtract(PLAYERNAME, 5.0); + fail("Did not throw exception"); + } + catch (NoLoanPermittedException ex) + { + } + catch (UserDoesNotExistException ex) + { + fail(ex.getMessage()); + } + + try + { + Economy.resetBalance("UnknownPlayer"); + fail("Did not throw exception"); + } + catch (NoLoanPermittedException ex) + { + fail(ex.getMessage()); + } + catch (UserDoesNotExistException ex) + { + } + } +} diff --git a/Essentials/test/com/earth2me/essentials/FakeServer.java b/Essentials/test/com/earth2me/essentials/FakeServer.java new file mode 100644 index 0000000000..e11d4ab765 --- /dev/null +++ b/Essentials/test/com/earth2me/essentials/FakeServer.java @@ -0,0 +1,1287 @@ +package com.earth2me.essentials; + +import com.avaje.ebean.config.ServerConfig; +import com.earth2me.essentials.craftbukkit.FakeWorld; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.util.*; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; +import java.util.logging.Logger; +import org.bukkit.*; +import org.bukkit.Warning.WarningState; +import org.bukkit.World.Environment; +import org.bukkit.command.CommandSender; +import org.bukkit.command.ConsoleCommandSender; +import org.bukkit.command.PluginCommand; +import org.bukkit.conversations.Conversation; +import org.bukkit.conversations.ConversationAbandonedEvent; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.help.HelpMap; +import org.bukkit.inventory.*; +import org.bukkit.map.MapView; +import org.bukkit.permissions.Permissible; +import org.bukkit.permissions.Permission; +import org.bukkit.permissions.PermissionAttachment; +import org.bukkit.permissions.PermissionAttachmentInfo; +import org.bukkit.plugin.EventExecutor; +import org.bukkit.plugin.InvalidDescriptionException; +import org.bukkit.plugin.InvalidPluginException; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginLoader; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.RegisteredListener; +import org.bukkit.plugin.ServicesManager; +import org.bukkit.plugin.UnknownDependencyException; +import org.bukkit.plugin.messaging.Messenger; +import org.bukkit.scheduler.BukkitScheduler; +import org.bukkit.scheduler.BukkitTask; +import org.bukkit.scheduler.BukkitWorker; +import org.bukkit.scoreboard.ScoreboardManager; +import org.bukkit.util.CachedServerIcon; + + +public class FakeServer implements Server +{ + private List players = new ArrayList(); + private final List worlds = new ArrayList(); + PluginManager pluginManager = new FakePluginManager(); + + public FakeServer() + { + if (Bukkit.getServer() == null) + { + Bukkit.setServer(this); + } + } + + @Override + public String getName() + { + return "Essentials Fake Server"; + } + + @Override + public String getVersion() + { + return "1.0"; + } + + @Override + public Player[] _INVALID_getOnlinePlayers() + { + return players.toArray(new Player[0]); + } + + @Override + public Collection getOnlinePlayers() + { + return players; + } + + public void setOnlinePlayers(List players) + { + this.players = players; + } + + @Override + public int getMaxPlayers() + { + return 100; + } + + @Override + public int getPort() + { + return 25565; + } + + @Override + public String getIp() + { + return "127.0.0.1"; + } + + @Override + public String getServerName() + { + return "Test Server"; + } + + @Override + public String getServerId() + { + return "Test Server"; + } + + @Override + public int broadcastMessage(String string) + { + int i = 0; + for (Player player : players) + { + player.sendMessage(string); + i++; + } + return i; + } + + @Override + public String getUpdateFolder() + { + return "update"; + } + + @Override + public File getUpdateFolderFile() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isHardcore() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Player getPlayer(String string) + { + for (Player player : players) + { + if (player.getName().equalsIgnoreCase(string)) + { + return player; + } + } + return null; + } + + @Override + public List matchPlayer(String string) + { + List matches = new ArrayList(); + for (Player player : players) + { + if (player.getName().substring(0, Math.min(player.getName().length(), string.length())).equalsIgnoreCase(string)) + { + matches.add(player); + } + } + return matches; + } + + @Override + public PluginManager getPluginManager() + { + return pluginManager; + } + + @Override + public BukkitScheduler getScheduler() + { + return new BukkitScheduler() + { + @Override + public int scheduleSyncDelayedTask(Plugin plugin, Runnable r, long l) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int scheduleSyncDelayedTask(Plugin plugin, Runnable r) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int scheduleSyncRepeatingTask(Plugin plugin, Runnable r, long l, long l1) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int scheduleAsyncRepeatingTask(Plugin plugin, Runnable r, long l, long l1) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Future callSyncMethod(Plugin plugin, Callable clbl) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void cancelTask(int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void cancelTasks(Plugin plugin) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void cancelAllTasks() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isCurrentlyRunning(int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isQueued(int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List getActiveWorkers() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List getPendingTasks() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BukkitTask runTask(Plugin plugin, Runnable r) throws IllegalArgumentException + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BukkitTask runTaskAsynchronously(Plugin plugin, Runnable r) throws IllegalArgumentException + { + r.run(); + return null; + } + + @Override + public BukkitTask runTaskLater(Plugin plugin, Runnable r, long l) throws IllegalArgumentException + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BukkitTask runTaskLaterAsynchronously(Plugin plugin, Runnable r, long l) throws IllegalArgumentException + { + r.run(); + return null; + } + + @Override + public BukkitTask runTaskTimer(Plugin plugin, Runnable r, long l, long l1) throws IllegalArgumentException + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BukkitTask runTaskTimerAsynchronously(Plugin plugin, Runnable r, long l, long l1) throws IllegalArgumentException + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int scheduleAsyncDelayedTask(Plugin plugin, Runnable r, long l) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int scheduleAsyncDelayedTask(Plugin plugin, Runnable r) + { + throw new UnsupportedOperationException("Not supported yet."); + } + }; + } + + @Override + public ServicesManager getServicesManager() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List getWorlds() + { + return worlds; + } + + public World createWorld(String string, Environment e) + { + World w = new FakeWorld(string, e); + worlds.add(w); + return w; + } + + public World createWorld(String string, Environment e, long l) + { + World w = new FakeWorld(string, e); + worlds.add(w); + return w; + } + + @Override + public World getWorld(String string) + { + for (World world : worlds) + { + if (world.getName().equalsIgnoreCase(string)) + { + return world; + } + } + return null; + } + + @Override + public void reload() + { + } + + @Override + public Logger getLogger() + { + return Logger.getLogger("Minecraft"); + } + + @Override + public PluginCommand getPluginCommand(String string) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void savePlayers() + { + } + + @Override + public boolean dispatchCommand(CommandSender cs, String string) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void configureDbConfig(ServerConfig sc) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean addRecipe(Recipe recipe) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void addPlayer(Player base1) + { + players.add(base1); + pluginManager.callEvent(new PlayerJoinEvent(base1, null)); + } + + public OfflinePlayer createPlayer(String name) + { + OfflinePlayer player = new OfflinePlayer(name, this); + player.setLocation(new Location(worlds.get(0), 0, 0, 0, 0, 0)); + return player; + } + + @Override + public World createWorld(WorldCreator creator) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean unloadWorld(String string, boolean bln) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean unloadWorld(World world, boolean bln) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Map getCommandAliases() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getSpawnRadius() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setSpawnRadius(int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean getOnlineMode() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + public World getWorld(long l) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public World getWorld(UUID uuid) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getViewDistance() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean getAllowNether() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean hasWhitelist() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public MapView getMap(short s) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public MapView createMap(World world) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean getAllowFlight() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setWhitelist(boolean bln) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Set getWhitelistedPlayers() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void reloadWhitelist() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Player getPlayerExact(String string) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void shutdown() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int broadcast(String string, String string1) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public org.bukkit.OfflinePlayer getOfflinePlayer(final String string) + { + return createOPlayer(string); + } + + private org.bukkit.OfflinePlayer createOPlayer(final String string) + { + return new org.bukkit.OfflinePlayer() + { + @Override + public boolean isOnline() + { + return false; + } + + @Override + public String getName() + { + return string; + } + + @Override + public boolean isBanned() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setBanned(boolean bln) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isWhitelisted() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setWhitelisted(boolean bln) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Player getPlayer() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isOp() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setOp(boolean bln) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Map serialize() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long getFirstPlayed() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long getLastPlayed() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean hasPlayedBefore() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Location getBedSpawnLocation() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public UUID getUniqueId() + { + if (string == "testPlayer1") + { + return UUID.fromString("3c9ebe1a-9098-43fd-bc0c-a369b76817ba"); + } + else if (string == "npc1") + { + return null; + } + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + }; + } + + @Override + public Set getIPBans() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void banIP(String string) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void unbanIP(String string) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Set getBannedPlayers() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public GameMode getDefaultGameMode() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setDefaultGameMode(GameMode gamemode) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ConsoleCommandSender getConsoleSender() + { + return new ConsoleCommandSender() + { + @Override + public void sendMessage(String message) + { + System.out.println("Console message: " + message); + } + + @Override + public void sendMessage(String[] messages) + { + for (String message : messages) + { + System.out.println("Console message: " + message); + } + } + + @Override + public Server getServer() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getName() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isPermissionSet(String name) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isPermissionSet(Permission perm) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean hasPermission(String name) + { + return true; + } + + @Override + public boolean hasPermission(Permission perm) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin, int ticks) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void removeAttachment(PermissionAttachment attachment) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void recalculatePermissions() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Set getEffectivePermissions() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isOp() + { + return true; + } + + @Override + public void setOp(boolean value) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isConversing() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void acceptConversationInput(String input) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean beginConversation(Conversation conversation) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void abandonConversation(Conversation conversation) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void abandonConversation(Conversation conversation, ConversationAbandonedEvent details) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void sendRawMessage(String message) + { + throw new UnsupportedOperationException("Not supported yet."); + } + }; + } + + @Override + public Set getOperators() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getBukkitVersion() + { + return "Essentials Fake-Server"; + } + + @Override + public File getWorldContainer() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public OfflinePlayer[] getOfflinePlayers() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean getAllowEnd() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Messenger getMessenger() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void sendPluginMessage(Plugin plugin, String string, byte[] bytes) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Set getListeningPluginChannels() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean useExactLoginLocation() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getTicksPerAnimalSpawns() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getTicksPerMonsterSpawns() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List getRecipesFor(ItemStack is) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Iterator recipeIterator() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void clearRecipes() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void resetRecipes() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public HelpMap getHelpMap() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Inventory createInventory(InventoryHolder ih, InventoryType it) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Inventory createInventory(InventoryHolder ih, int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Inventory createInventory(InventoryHolder ih, int i, String string) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getWorldType() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean getGenerateStructures() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long getConnectionThrottle() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getMonsterSpawnLimit() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getAnimalSpawnLimit() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getWaterAnimalSpawnLimit() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isPrimaryThread() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getMotd() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public WarningState getWarningState() + { + return WarningState.DEFAULT; + } + + @Override + public int getAmbientSpawnLimit() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getShutdownMessage() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ItemFactory getItemFactory() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ScoreboardManager getScoreboardManager() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CachedServerIcon getServerIcon() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CachedServerIcon loadServerIcon(File file) throws IllegalArgumentException, Exception + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CachedServerIcon loadServerIcon(BufferedImage bufferedImage) throws IllegalArgumentException, Exception + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setIdleTimeout(int i) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getIdleTimeout() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public UnsafeValues getUnsafe() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BanList getBanList(BanList.Type arg0) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Player getPlayer(UUID arg0) + { + for (Player player : players) + { + if (player.getUniqueId().equals(arg0)) + { + return player; + } + } + return null; + } + + @Override + public org.bukkit.OfflinePlayer getOfflinePlayer(UUID arg0) + { + if (arg0.toString().equalsIgnoreCase("3c9ebe1a-9098-43fd-bc0c-a369b76817ba")) + { + return createOPlayer("testPlayer1"); + } + if (arg0.toString().equalsIgnoreCase("f4a37409-5c40-3b2c-9cd6-57d3c5abdc76")) + { + return createOPlayer("npc1"); + } + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Inventory createInventory(InventoryHolder arg0, InventoryType arg1, String arg2) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + + class FakePluginManager implements PluginManager + { + ArrayList listeners = new ArrayList(); + + @Override + public void registerInterface(Class loader) throws IllegalArgumentException + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Plugin getPlugin(String name) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Plugin[] getPlugins() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isPluginEnabled(String name) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isPluginEnabled(Plugin plugin) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Plugin loadPlugin(File file) throws InvalidPluginException, InvalidDescriptionException, UnknownDependencyException + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Plugin[] loadPlugins(File directory) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void disablePlugins() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void clearPlugins() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void callEvent(Event event) throws IllegalStateException + { + Logger.getLogger("Minecraft").info("Called event " + event.getEventName()); + if (event instanceof PlayerJoinEvent) + { + for (RegisteredListener listener : listeners) + { + if (listener.getListener() instanceof EssentialsPlayerListener) + { + PlayerJoinEvent jEvent = (PlayerJoinEvent)event; + EssentialsPlayerListener epl = (EssentialsPlayerListener)listener.getListener(); + epl.onPlayerJoin(jEvent); + Essentials ess = (Essentials)listener.getPlugin(); + ess.getLogger().info("Sending join event to Essentials"); + ess.getUser(jEvent.getPlayer()); + } + } + } + } + + @Override + public void registerEvents(Listener listener, Plugin plugin) + { + listeners.add(new RegisteredListener(listener, null, null, plugin, false)); + } + + @Override + public void registerEvent(Class event, Listener listener, EventPriority priority, EventExecutor executor, Plugin plugin) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void registerEvent(Class event, Listener listener, EventPriority priority, EventExecutor executor, Plugin plugin, boolean ignoreCancelled) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void enablePlugin(Plugin plugin) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void disablePlugin(Plugin plugin) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Permission getPermission(String name) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void addPermission(Permission perm) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void removePermission(Permission perm) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void removePermission(String name) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Set getDefaultPermissions(boolean op) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void recalculatePermissionDefaults(Permission perm) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void subscribeToPermission(String permission, Permissible permissible) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void unsubscribeFromPermission(String permission, Permissible permissible) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Set getPermissionSubscriptions(String permission) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void subscribeToDefaultPerms(boolean op, Permissible permissible) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void unsubscribeFromDefaultPerms(boolean op, Permissible permissible) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Set getDefaultPermSubscriptions(boolean op) + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Set getPermissions() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean useTimings() + { + throw new UnsupportedOperationException("Not supported yet."); + } + }; +} diff --git a/Essentials/test/com/earth2me/essentials/StorageTest.java b/Essentials/test/com/earth2me/essentials/StorageTest.java new file mode 100644 index 0000000000..617d3c6b37 --- /dev/null +++ b/Essentials/test/com/earth2me/essentials/StorageTest.java @@ -0,0 +1,62 @@ +package com.earth2me.essentials; + +import java.io.IOException; +import junit.framework.TestCase; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.World.Environment; +import org.bukkit.plugin.InvalidDescriptionException; +import org.junit.Test; + + +public class StorageTest extends TestCase +{ + Essentials ess; + FakeServer server; + World world; + + public StorageTest() + { + server = new FakeServer(); + world = server.createWorld("testWorld", Environment.NORMAL); + ess = new Essentials(server); + try + { + ess.setupForTesting(server); + } + catch (InvalidDescriptionException ex) + { + fail("InvalidDescriptionException"); + } + catch (IOException ex) + { + fail("IOException"); + } + } + + @Test + public void testOldUserdata() + { + ExecuteTimer ext = new ExecuteTimer(); + ext.start(); + OfflinePlayer base1 = server.createPlayer("testPlayer1"); + server.addPlayer(base1); + ext.mark("fake user created"); + UserData user = (UserData)ess.getUser(base1); + ext.mark("load empty user"); + for (int j = 0; j < 1; j++) + { + user.setHome("home", new Location(world, j, j, j)); + } + ext.mark("change home 1 times"); + user.save(); + ext.mark("write user"); + user.save(); + ext.mark("write user (cached)"); + user.reloadConfig(); + ext.mark("reloaded file"); + user.reloadConfig(); + ext.mark("reloaded file (cached)"); + System.out.println(ext.end()); + } +} diff --git a/Essentials/test/com/earth2me/essentials/ToggleTest.java b/Essentials/test/com/earth2me/essentials/ToggleTest.java new file mode 100644 index 0000000000..d3a496df96 --- /dev/null +++ b/Essentials/test/com/earth2me/essentials/ToggleTest.java @@ -0,0 +1,269 @@ +package com.earth2me.essentials; + +import com.earth2me.essentials.commands.IEssentialsCommand; +import com.earth2me.essentials.commands.NoChargeException; +import java.io.IOException; +import junit.framework.TestCase; +import org.bukkit.World.Environment; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.InvalidDescriptionException; + + +public class ToggleTest extends TestCase +{ + private final OfflinePlayer base1; + private final Essentials ess; + private final FakeServer server; + + public ToggleTest(String testName) + { + super(testName); + server = new FakeServer(); + server.createWorld("testWorld", Environment.NORMAL); + ess = new Essentials(server); + try + { + ess.setupForTesting(server); + } + catch (InvalidDescriptionException ex) + { + fail("InvalidDescriptionException"); + } + catch (IOException ex) + { + fail("IOException"); + } + base1 = server.createPlayer("testPlayer1"); + server.addPlayer(base1); + ess.getUser(base1); + } + + private void runCommand(String command, User user, String[] args) throws Exception + { + IEssentialsCommand cmd; + + try + { + cmd = (IEssentialsCommand)Essentials.class.getClassLoader().loadClass("com.earth2me.essentials.commands.Command" + command).newInstance(); + cmd.setEssentials(ess); + cmd.run(server, user, command, null, args); + } + catch (NoChargeException ex) + { + } + + } + + private void runConsoleCommand(String command, String[] args) throws Exception + { + IEssentialsCommand cmd; + + CommandSender sender = server.getConsoleSender(); + + try + { + cmd = (IEssentialsCommand)Essentials.class.getClassLoader().loadClass("com.earth2me.essentials.commands.Command" + command).newInstance(); + cmd.setEssentials(ess); + cmd.run(server, new CommandSource(sender), command, null, args); + } + catch (NoChargeException ex) + { + } + + } + + public void testFlyToggle() throws Exception + { + User user = ess.getUser(base1); + + assertFalse(user.getBase().getAllowFlight()); + + runCommand("fly", user, new String[] + { + "on" + }); + assertTrue(user.getBase().getAllowFlight()); + + runCommand("fly", user, new String[] + { + "on" + }); + assertTrue(user.getBase().getAllowFlight()); + + runCommand("fly", user, new String[] + { + "off" + }); + assertFalse(user.getBase().getAllowFlight()); + + runCommand("fly", user, new String[] + { + "off" + }); + assertFalse(user.getBase().getAllowFlight()); + + runCommand("fly", user, new String[] + { + }); + assertTrue(user.getBase().getAllowFlight()); + + runCommand("fly", user, new String[] + { + }); + assertFalse(user.getBase().getAllowFlight()); + } + + public void testFlyDisOnToggle() throws Exception + { + User user = ess.getUser(base1); + + user.getBase().setAllowFlight(true); + user.getBase().setFlying(true); + assertTrue(user.getBase().isFlying()); + runCommand("fly", user, new String[] + { + }); + assertFalse(user.getBase().getAllowFlight()); + assertFalse(user.getBase().isFlying()); + } + + public void testGodToggle() throws Exception + { + User user = ess.getUser(base1); + + assertFalse(user.isGodModeEnabled()); + + runCommand("god", user, new String[] + { + "on" + }); + assertTrue(user.isGodModeEnabled()); + + runCommand("god", user, new String[] + { + "on" + }); + assertTrue(user.isGodModeEnabled()); + + runCommand("god", user, new String[] + { + "off" + }); + assertFalse(user.isGodModeEnabled()); + + runCommand("god", user, new String[] + { + "off" + }); + assertFalse(user.isGodModeEnabled()); + + runCommand("god", user, new String[] + { + }); + assertTrue(user.isGodModeEnabled()); + + runCommand("god", user, new String[] + { + }); + assertFalse(user.isGodModeEnabled()); + } + + public void testConsoleToggle() throws Exception + { + User user = ess.getUser(base1); + + assertFalse(user.getBase().getAllowFlight()); + + runConsoleCommand("fly", new String[] + { + base1.getName(), "on" + }); + assertTrue(user.getBase().getAllowFlight()); + + runConsoleCommand("fly", new String[] + { + base1.getName(), "on" + }); + assertTrue(user.getBase().getAllowFlight()); + + runConsoleCommand("fly", new String[] + { + base1.getName(), "off" + }); + assertFalse(user.getBase().getAllowFlight()); + + runConsoleCommand("fly", new String[] + { + base1.getName(), "off" + }); + assertFalse(user.getBase().getAllowFlight()); + + runConsoleCommand("fly", new String[] + { + base1.getName() + }); + assertTrue(user.getBase().getAllowFlight()); + + runConsoleCommand("fly", new String[] + { + base1.getName() + }); + assertFalse(user.getBase().getAllowFlight()); + } + + public void testAliasesToggle() throws Exception + { + User user = ess.getUser(base1); + + assertFalse(user.getBase().getAllowFlight()); + + runConsoleCommand("fly", new String[] + { + base1.getName(), "enable" + }); + assertTrue(user.getBase().getAllowFlight()); + + runConsoleCommand("fly", new String[] + { + base1.getName(), "enable" + }); + assertTrue(user.getBase().getAllowFlight()); + + runConsoleCommand("fly", new String[] + { + base1.getName(), "disable" + }); + assertFalse(user.getBase().getAllowFlight()); + + runConsoleCommand("fly", new String[] + { + base1.getName(), "disable" + }); + assertFalse(user.getBase().getAllowFlight()); + + runConsoleCommand("fly", new String[] + { + base1.getName(), "1" + }); + assertTrue(user.getBase().getAllowFlight()); + + runConsoleCommand("fly", new String[] + { + base1.getName(), "1" + }); + assertTrue(user.getBase().getAllowFlight()); + + runConsoleCommand("fly", new String[] + { + base1.getName(), "0" + }); + assertFalse(user.getBase().getAllowFlight()); + + runConsoleCommand("fly", new String[] + { + base1.getName(), "0" + }); + assertFalse(user.getBase().getAllowFlight()); + + } +} diff --git a/Essentials/test/com/earth2me/essentials/UserTest.java b/Essentials/test/com/earth2me/essentials/UserTest.java new file mode 100644 index 0000000000..7bae28c31c --- /dev/null +++ b/Essentials/test/com/earth2me/essentials/UserTest.java @@ -0,0 +1,97 @@ +package com.earth2me.essentials; + +import java.io.IOException; +import java.math.BigDecimal; +import junit.framework.TestCase; +import net.ess3.api.MaxMoneyException; +import org.bukkit.Location; +import org.bukkit.World.Environment; +import org.bukkit.plugin.InvalidDescriptionException; + + +public class UserTest extends TestCase +{ + private final OfflinePlayer base1; + private final Essentials ess; + private final FakeServer server; + + public UserTest(String testName) + { + super(testName); + server = new FakeServer(); + server.createWorld("testWorld", Environment.NORMAL); + ess = new Essentials(server); + try + { + ess.setupForTesting(server); + } + catch (InvalidDescriptionException ex) + { + fail("InvalidDescriptionException"); + } + catch (IOException ex) + { + fail("IOException"); + } + base1 = server.createPlayer("testPlayer1"); + server.addPlayer(base1); + ess.getUser(base1); + } + + private void should(String what) + { + System.out.println(getName() + " should " + what); + } + + public void testUpdate() + { + OfflinePlayer base1alt = server.createPlayer(base1.getName()); + assertEquals(base1alt, ess.getUser(base1alt).getBase()); + } + + public void testHome() + { + User user = ess.getUser(base1); + Location loc = base1.getLocation(); + user.setHome("home", loc); + OfflinePlayer base2 = server.createPlayer(base1.getName()); + User user2 = ess.getUser(base2); + + Location home = user2.getHome(loc); + assertNotNull(home); + assertEquals(loc.getWorld().getName(), home.getWorld().getName()); + assertEquals(loc.getX(), home.getX()); + assertEquals(loc.getY(), home.getY()); + assertEquals(loc.getZ(), home.getZ()); + assertEquals(loc.getYaw(), home.getYaw()); + assertEquals(loc.getPitch(), home.getPitch()); + } + + public void testMoney() + { + should("properly set, take, give, and get money"); + User user = ess.getUser(base1); + BigDecimal i = new BigDecimal("100.5"); + try + { + user.setMoney(i); + user.takeMoney(new BigDecimal(50)); + i = i.subtract(BigDecimal.valueOf(50)); + user.giveMoney(new BigDecimal(25)); + i = i.add(BigDecimal.valueOf(25)); + } + catch (MaxMoneyException ex) + { + fail(); + } + + assertEquals(user.getMoney(), i); + } + + public void testGetGroup() + { + should("return the default group"); + User user = ess.getUser(base1); + assertEquals(user.getGroup(), "default"); + } +} diff --git a/Essentials/test/com/earth2me/essentials/UtilTest.java b/Essentials/test/com/earth2me/essentials/UtilTest.java new file mode 100644 index 0000000000..497d26d7a5 --- /dev/null +++ b/Essentials/test/com/earth2me/essentials/UtilTest.java @@ -0,0 +1,205 @@ +package com.earth2me.essentials; + +import com.earth2me.essentials.utils.DateUtil; +import com.earth2me.essentials.utils.LocationUtil; +import java.io.IOException; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.HashSet; +import java.util.Set; +import junit.framework.TestCase; +import org.bukkit.World.Environment; +import org.bukkit.plugin.InvalidDescriptionException; + + +public class UtilTest extends TestCase +{ + private final Essentials ess; + private final FakeServer server; + + public UtilTest() + { + server = new FakeServer(); + server.createWorld("testWorld", Environment.NORMAL); + ess = new Essentials(server); + try + { + ess.setupForTesting(server); + } + catch (InvalidDescriptionException ex) + { + fail("InvalidDescriptionException"); + } + catch (IOException ex) + { + fail("IOException"); + } + } + + public void testSafeLocation() + { + Set testSet = new HashSet(); + int count = 0; + int x, y, z, origX, origY, origZ; + x = y = z = origX = origY = origZ = 0; + int i = 0; + while (true) + { + testSet.add(x + ":" + y + ":" + z); + count++; + i++; + if (i >= LocationUtil.VOLUME.length) + { + break; + } + x = origX + LocationUtil.VOLUME[i].x; + y = origY + LocationUtil.VOLUME[i].y; + z = origZ + LocationUtil.VOLUME[i].z; + } + assertTrue(testSet.contains("0:0:0")); + assertTrue(testSet.contains("3:3:3")); + assertEquals(testSet.size(), count); + int diameter = LocationUtil.RADIUS * 2 + 1; + assertEquals(diameter * diameter * diameter, count); + } + + public void testFDDnow() + { + Calendar c = new GregorianCalendar(); + String resp = DateUtil.formatDateDiff(c, c); + assertEquals(resp, "now"); + } + + public void testFDDfuture() + { + Calendar a, b; + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 1, 1, 10, 0, 1); + assertEquals("1 second", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 1, 1, 10, 0, 2); + assertEquals("2 seconds", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 1, 1, 10, 0, 3); + assertEquals("3 seconds", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 1, 1, 10, 1, 0); + assertEquals("1 minute", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 1, 1, 10, 2, 0); + assertEquals("2 minutes", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 1, 1, 10, 3, 0); + assertEquals("3 minutes", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 1, 1, 11, 0, 0); + assertEquals("1 hour", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 1, 1, 12, 0, 0); + assertEquals("2 hours", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 1, 1, 13, 0, 0); + assertEquals("3 hours", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 1, 2, 10, 0, 0); + assertEquals("1 day", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 1, 3, 10, 0, 0); + assertEquals("2 days", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 1, 4, 10, 0, 0); + assertEquals("3 days", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 2, 1, 10, 0, 0); + assertEquals("1 month", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 3, 1, 10, 0, 0); + assertEquals("2 months", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 4, 1, 10, 0, 0); + assertEquals("3 months", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2011, 1, 1, 10, 0, 0); + assertEquals("1 year", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2012, 1, 1, 10, 0, 0); + assertEquals("2 years", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2013, 1, 1, 10, 0, 0); + assertEquals("3 years", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2011, 4, 5, 23, 38, 12); + assertEquals("1 year 3 months 4 days", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 9, 17, 23, 45, 45); + b = new GregorianCalendar(2015, 3, 7, 10, 0, 0); + assertEquals("4 years 5 months 20 days", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2011, 4, 31, 10, 0, 0); + b = new GregorianCalendar(2011, 4, 31, 10, 5, 0); + assertEquals("5 minutes", DateUtil.formatDateDiff(a, b)); + } + + public void testFDDpast() + { + Calendar a, b; + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 1, 1, 9, 59, 59); + assertEquals("1 second", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 1, 1, 9, 59, 58); + assertEquals("2 seconds", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 1, 1, 9, 59, 57); + assertEquals("3 seconds", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 1, 1, 9, 59, 0); + assertEquals("1 minute", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 1, 1, 9, 58, 0); + assertEquals("2 minutes", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 1, 1, 9, 57, 0); + assertEquals("3 minutes", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 1, 1, 9, 0, 0); + assertEquals("1 hour", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 1, 1, 8, 0, 0); + assertEquals("2 hours", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 1, 1, 7, 0, 0); + assertEquals("3 hours", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 5, 10, 0, 0); + b = new GregorianCalendar(2010, 1, 4, 10, 0, 0); + assertEquals("1 day", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 5, 10, 0, 0); + b = new GregorianCalendar(2010, 1, 3, 10, 0, 0); + assertEquals("2 days", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 5, 10, 0, 0); + b = new GregorianCalendar(2010, 1, 2, 10, 0, 0); + assertEquals("3 days", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 5, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 4, 1, 10, 0, 0); + assertEquals("1 month", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 5, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 3, 1, 10, 0, 0); + assertEquals("2 months", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 5, 1, 10, 0, 0); + b = new GregorianCalendar(2010, 2, 1, 10, 0, 0); + assertEquals("3 months", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2009, 1, 1, 10, 0, 0); + assertEquals("1 year", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2008, 1, 1, 10, 0, 0); + assertEquals("2 years", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2007, 1, 1, 10, 0, 0); + assertEquals("3 years", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 1, 1, 10, 0, 0); + b = new GregorianCalendar(2009, 4, 5, 23, 38, 12); + assertEquals("8 months 26 days 10 hours", DateUtil.formatDateDiff(a, b)); + a = new GregorianCalendar(2010, 9, 17, 23, 45, 45); + b = new GregorianCalendar(2000, 3, 7, 10, 0, 0); + assertEquals("10 years 6 months 10 days", DateUtil.formatDateDiff(a, b)); + } +} diff --git a/EssentialsAntiBuild/pom.xml b/EssentialsAntiBuild/pom.xml new file mode 100644 index 0000000000..66eae3c204 --- /dev/null +++ b/EssentialsAntiBuild/pom.xml @@ -0,0 +1,51 @@ + + 4.0.0 + + + net.ess3 + EssentialsParent + 2.x-SNAPSHOT + + + EssentialsAntiBuild + + 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/ + + + + + net.ess3 + Essentials + ${project.version} + + + \ No newline at end of file diff --git a/EssentialsAntiBuild/src/com/earth2me/essentials/antibuild/AntiBuildConfig.java b/EssentialsAntiBuild/src/com/earth2me/essentials/antibuild/AntiBuildConfig.java new file mode 100644 index 0000000000..f0cdfcef4e --- /dev/null +++ b/EssentialsAntiBuild/src/com/earth2me/essentials/antibuild/AntiBuildConfig.java @@ -0,0 +1,74 @@ +package com.earth2me.essentials.antibuild; + + +public enum AntiBuildConfig +{ + disable_build("protect.disable.build", true), + disable_use("protect.disable.use", true), + alert_on_placement("protect.alert.on-placement"), + alert_on_use("protect.alert.on-use"), + alert_on_break("protect.alert.on-break"), + blacklist_placement("protect.blacklist.placement"), + blacklist_usage("protect.blacklist.usage"), + blacklist_break("protect.blacklist.break"), + blacklist_piston("protect.blacklist.piston"), + blacklist_dispenser("protect.blacklist.dispenser"); + private final String configName; + private final String defValueString; + private final boolean defValueBoolean; + private final boolean isList; + private final boolean isString; + + private AntiBuildConfig(final String configName) + { + this(configName, null, false, true, false); + } + + private AntiBuildConfig(final String configName, final boolean defValueBoolean) + { + this(configName, null, defValueBoolean, false, false); + } + + private AntiBuildConfig(final String configName, final String defValueString, final boolean defValueBoolean, final boolean isList, final boolean isString) + { + this.configName = configName; + this.defValueString = defValueString; + this.defValueBoolean = defValueBoolean; + this.isList = isList; + this.isString = isString; + } + + /** + * @return the configName + */ + public String getConfigName() + { + return configName; + } + + /** + * @return the default value String + */ + public String getDefaultValueString() + { + return defValueString; + } + + /** + * @return the default value boolean + */ + public boolean getDefaultValueBoolean() + { + return defValueBoolean; + } + + public boolean isString() + { + return isString; + } + + public boolean isList() + { + return isList; + } +} diff --git a/EssentialsAntiBuild/src/com/earth2me/essentials/antibuild/EssentialsAntiBuild.java b/EssentialsAntiBuild/src/com/earth2me/essentials/antibuild/EssentialsAntiBuild.java new file mode 100644 index 0000000000..8654b99492 --- /dev/null +++ b/EssentialsAntiBuild/src/com/earth2me/essentials/antibuild/EssentialsAntiBuild.java @@ -0,0 +1,63 @@ +package com.earth2me.essentials.antibuild; + +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.java.JavaPlugin; + + +public class EssentialsAntiBuild extends JavaPlugin implements IAntiBuild +{ + private final transient Map settingsBoolean = new EnumMap(AntiBuildConfig.class); + private final transient Map> settingsList = new EnumMap>(AntiBuildConfig.class); + private transient EssentialsConnect ess = null; + + @Override + public void onEnable() + { + final PluginManager pm = this.getServer().getPluginManager(); + final Plugin essPlugin = pm.getPlugin("Essentials"); + if (essPlugin == null || !essPlugin.isEnabled()) + { + return; + } + ess = new EssentialsConnect(essPlugin, this); + + final EssentialsAntiBuildListener blockListener = new EssentialsAntiBuildListener(this); + pm.registerEvents(blockListener, this); + } + + @Override + public boolean checkProtectionItems(final AntiBuildConfig list, final int id) + { + final List itemList = settingsList.get(list); + return itemList != null && !itemList.isEmpty() && itemList.contains(id); + } + + @Override + public EssentialsConnect getEssentialsConnect() + { + return ess; + } + + @Override + public Map getSettingsBoolean() + { + return settingsBoolean; + } + + @Override + public Map> getSettingsList() + { + return settingsList; + } + + @Override + public boolean getSettingBool(final AntiBuildConfig protectConfig) + { + final Boolean bool = settingsBoolean.get(protectConfig); + return bool == null ? protectConfig.getDefaultValueBoolean() : bool; + } +} diff --git a/EssentialsAntiBuild/src/com/earth2me/essentials/antibuild/EssentialsAntiBuildListener.java b/EssentialsAntiBuild/src/com/earth2me/essentials/antibuild/EssentialsAntiBuildListener.java new file mode 100644 index 0000000000..f9e924931f --- /dev/null +++ b/EssentialsAntiBuild/src/com/earth2me/essentials/antibuild/EssentialsAntiBuildListener.java @@ -0,0 +1,325 @@ +package com.earth2me.essentials.antibuild; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import net.ess3.api.IEssentials; +import java.util.logging.Level; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.*; +import org.bukkit.event.hanging.HangingBreakByEntityEvent; +import org.bukkit.event.inventory.CraftItemEvent; +import org.bukkit.event.player.PlayerDropItemEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerPickupItemEvent; +import org.bukkit.inventory.ItemStack; + + +public class EssentialsAntiBuildListener implements Listener +{ + final private transient IAntiBuild prot; + final private transient IEssentials ess; + + public EssentialsAntiBuildListener(final IAntiBuild parent) + { + this.prot = parent; + this.ess = prot.getEssentialsConnect().getEssentials(); + } + + private boolean metaPermCheck(final User user, final String action, final Block block) + { + if (block == null) + { + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "AntiBuild permission check failed, invalid block."); + } + return false; + } + return metaPermCheck(user, action, block.getTypeId(), block.getData()); + } + + private boolean metaPermCheck(final User user, final String action, final int blockId) + { + final String blockPerm = "essentials.build." + action + "." + blockId; + return user.isAuthorized(blockPerm); + } + + private boolean metaPermCheck(final User user, final String action, final int blockId, final short data) + { + final String blockPerm = "essentials.build." + action + "." + blockId; + final String dataPerm = blockPerm + ":" + data; + + if (user.getBase().isPermissionSet(dataPerm)) + { + return user.isAuthorized(dataPerm); + } + else + { + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "DataValue perm on " + user.getName() + " is not directly set: " + dataPerm); + } + } + + return user.isAuthorized(blockPerm); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBlockPlace(final BlockPlaceEvent event) + { + final User user = ess.getUser(event.getPlayer()); + final Block block = event.getBlockPlaced(); + final int typeId = block.getTypeId(); + final Material type = block.getType(); + + if (prot.getSettingBool(AntiBuildConfig.disable_build) && !user.canBuild() && !user.isAuthorized("essentials.build") + && !metaPermCheck(user, "place", block)) + { + if (ess.getSettings().warnOnBuildDisallow()) + { + user.sendMessage(tl("antiBuildPlace", type.toString())); + } + event.setCancelled(true); + return; + } + + if (prot.checkProtectionItems(AntiBuildConfig.blacklist_placement, typeId) && !user.isAuthorized("essentials.protect.exemptplacement")) + { + if (ess.getSettings().warnOnBuildDisallow()) + { + user.sendMessage(tl("antiBuildPlace", type.toString())); + } + event.setCancelled(true); + return; + } + + if (prot.checkProtectionItems(AntiBuildConfig.alert_on_placement, typeId) + && !user.isAuthorized("essentials.protect.alerts.notrigger")) + { + prot.getEssentialsConnect().alert(user, type.toString(), tl("alertPlaced")); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBlockBreak(final BlockBreakEvent event) + { + final User user = ess.getUser(event.getPlayer()); + final Block block = event.getBlock(); + final int typeId = block.getTypeId(); + final Material type = block.getType(); + + if (prot.getSettingBool(AntiBuildConfig.disable_build) && !user.canBuild() && !user.isAuthorized("essentials.build") + && !metaPermCheck(user, "break", block)) + { + if (ess.getSettings().warnOnBuildDisallow()) + { + user.sendMessage(tl("antiBuildBreak", type.toString())); + } + event.setCancelled(true); + return; + } + + if (prot.checkProtectionItems(AntiBuildConfig.blacklist_break, typeId) + && !user.isAuthorized("essentials.protect.exemptbreak")) + { + if (ess.getSettings().warnOnBuildDisallow()) + { + user.sendMessage(tl("antiBuildBreak", type.toString())); + } + event.setCancelled(true); + return; + } + + if (prot.checkProtectionItems(AntiBuildConfig.alert_on_break, typeId) + && !user.isAuthorized("essentials.protect.alerts.notrigger")) + { + prot.getEssentialsConnect().alert(user, type.toString(), tl("alertBroke")); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onHangingBreak(final HangingBreakByEntityEvent event) + { + final Entity entity = event.getRemover(); + if (entity instanceof Player) + { + final User user = ess.getUser((Player)entity); + final EntityType type = event.getEntity().getType(); + final boolean warn = ess.getSettings().warnOnBuildDisallow(); + if (prot.getSettingBool(AntiBuildConfig.disable_build) && !user.canBuild() && !user.isAuthorized("essentials.build")) + { + if (type == EntityType.PAINTING && !metaPermCheck(user, "break", Material.PAINTING.getId())) + { + if (warn) + { + user.sendMessage(tl("antiBuildBreak", Material.PAINTING.toString())); + } + event.setCancelled(true); + } + else if(type == EntityType.ITEM_FRAME && !metaPermCheck(user, "break", Material.ITEM_FRAME.getId())) + { + if (warn) + { + user.sendMessage(tl("antiBuildBreak", Material.ITEM_FRAME.toString())); + } + event.setCancelled(true); + } + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBlockPistonExtend(final BlockPistonExtendEvent event) + { + for (Block block : event.getBlocks()) + { + if (prot.checkProtectionItems(AntiBuildConfig.blacklist_piston, block.getTypeId())) + { + event.setCancelled(true); + return; + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBlockPistonRetract(final BlockPistonRetractEvent event) + { + if (!event.isSticky()) + { + return; + } + final Block block = event.getRetractLocation().getBlock(); + if (prot.checkProtectionItems(AntiBuildConfig.blacklist_piston, block.getTypeId())) + { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.LOW) + public void onPlayerInteract(final PlayerInteractEvent event) + { + // Do not return if cancelled, because the interact event has 2 cancelled states. + final User user = ess.getUser(event.getPlayer()); + final ItemStack item = event.getItem(); + + if (item != null + && prot.checkProtectionItems(AntiBuildConfig.blacklist_usage, item.getTypeId()) + && !user.isAuthorized("essentials.protect.exemptusage")) + { + if (ess.getSettings().warnOnBuildDisallow()) + { + user.sendMessage(tl("antiBuildUse", item.getType().toString())); + } + event.setCancelled(true); + return; + } + + if (item != null + && prot.checkProtectionItems(AntiBuildConfig.alert_on_use, item.getTypeId()) + && !user.isAuthorized("essentials.protect.alerts.notrigger")) + { + prot.getEssentialsConnect().alert(user, item.getType().toString(), tl("alertUsed")); + } + + if (prot.getSettingBool(AntiBuildConfig.disable_use) && !user.canBuild() && !user.isAuthorized("essentials.build")) + { + if (event.hasItem() && !metaPermCheck(user, "interact", item.getTypeId(), item.getDurability())) + { + event.setCancelled(true); + if (ess.getSettings().warnOnBuildDisallow()) + { + user.sendMessage(tl("antiBuildUse", item.getType().toString())); + } + return; + } + if (event.hasBlock() && !metaPermCheck(user, "interact", event.getClickedBlock())) + { + event.setCancelled(true); + if (ess.getSettings().warnOnBuildDisallow()) + { + user.sendMessage(tl("antiBuildInteract", event.getClickedBlock().getType().toString())); + } + } + } + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onCraftItemEvent(final CraftItemEvent event) + { + HumanEntity entity = event.getWhoClicked(); + + if (entity instanceof Player) + { + final User user = ess.getUser((Player)entity); + final ItemStack item = event.getRecipe().getResult(); + + if (prot.getSettingBool(AntiBuildConfig.disable_use) && !user.canBuild() && !user.isAuthorized("essentials.build")) + { + if (!metaPermCheck(user, "craft", item.getTypeId(), item.getDurability())) + { + event.setCancelled(true); + if (ess.getSettings().warnOnBuildDisallow()) + { + user.sendMessage(tl("antiBuildCraft", item.getType().toString())); + } + } + } + } + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onPlayerPickupItem(PlayerPickupItemEvent event) + { + + final User user = ess.getUser(event.getPlayer()); + final ItemStack item = event.getItem().getItemStack(); + + if (prot.getSettingBool(AntiBuildConfig.disable_use) && !user.canBuild() && !user.isAuthorized("essentials.build")) + { + if (!metaPermCheck(user, "pickup", item.getTypeId(), item.getDurability())) + { + event.setCancelled(true); + event.getItem().setPickupDelay(50); + } + } + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onPlayerDropItem(final PlayerDropItemEvent event) + { + + final User user = ess.getUser(event.getPlayer()); + final ItemStack item = event.getItemDrop().getItemStack(); + + if (prot.getSettingBool(AntiBuildConfig.disable_use) && !user.canBuild() && !user.isAuthorized("essentials.build")) + { + if (!metaPermCheck(user, "drop", item.getTypeId(), item.getDurability())) + { + event.setCancelled(true); + user.getBase().updateInventory(); + if (ess.getSettings().warnOnBuildDisallow()) + { + user.sendMessage(tl("antiBuildDrop", item.getType().toString())); + } + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBlockDispense(final BlockDispenseEvent event) + { + final ItemStack item = event.getItem(); + if (prot.checkProtectionItems(AntiBuildConfig.blacklist_dispenser, item.getTypeId())) + { + event.setCancelled(true); + } + } +} diff --git a/EssentialsAntiBuild/src/com/earth2me/essentials/antibuild/EssentialsConnect.java b/EssentialsAntiBuild/src/com/earth2me/essentials/antibuild/EssentialsConnect.java new file mode 100644 index 0000000000..2a7b4ecf7c --- /dev/null +++ b/EssentialsAntiBuild/src/com/earth2me/essentials/antibuild/EssentialsConnect.java @@ -0,0 +1,80 @@ +package com.earth2me.essentials.antibuild; + +import com.earth2me.essentials.IConf; +import com.earth2me.essentials.User; +import static com.earth2me.essentials.I18n.tl; +import net.ess3.api.IEssentials; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + + +public class EssentialsConnect +{ + private static final Logger LOGGER = Logger.getLogger("Minecraft"); + private final transient IEssentials ess; + private final transient IAntiBuild protect; + + public EssentialsConnect(Plugin essPlugin, Plugin essProtect) + { + if (!essProtect.getDescription().getVersion().equals(essPlugin.getDescription().getVersion())) + { + LOGGER.log(Level.WARNING, tl("versionMismatchAll")); + } + ess = (IEssentials)essPlugin; + protect = (IAntiBuild)essProtect; + AntiBuildReloader pr = new AntiBuildReloader(); + pr.reloadConfig(); + ess.addReloadListener(pr); + } + + public void onDisable() + { + } + + public IEssentials getEssentials() + { + return ess; + } + + public void alert(final User user, final String item, final String type) + { + final Location loc = user.getLocation(); + final String warnMessage = tl("alertFormat", user.getName(), type, item, + loc.getWorld().getName() + "," + loc.getBlockX() + "," + + loc.getBlockY() + "," + loc.getBlockZ()); + LOGGER.log(Level.WARNING, warnMessage); + for (Player p : ess.getServer().getOnlinePlayers()) + { + final User alertUser = ess.getUser(p); + if (alertUser.isAuthorized("essentials.protect.alerts")) + { + alertUser.sendMessage(warnMessage); + } + } + } + + + private class AntiBuildReloader implements IConf + { + @Override + public void reloadConfig() + { + for (AntiBuildConfig protectConfig : AntiBuildConfig.values()) + { + if (protectConfig.isList()) + { + protect.getSettingsList().put(protectConfig, ess.getSettings().getProtectList(protectConfig.getConfigName())); + } + else + { + protect.getSettingsBoolean().put(protectConfig, ess.getSettings().getProtectBoolean(protectConfig.getConfigName(), protectConfig.getDefaultValueBoolean())); + } + + } + + } + } +} diff --git a/EssentialsAntiBuild/src/com/earth2me/essentials/antibuild/IAntiBuild.java b/EssentialsAntiBuild/src/com/earth2me/essentials/antibuild/IAntiBuild.java new file mode 100644 index 0000000000..c7b370006c --- /dev/null +++ b/EssentialsAntiBuild/src/com/earth2me/essentials/antibuild/IAntiBuild.java @@ -0,0 +1,19 @@ +package com.earth2me.essentials.antibuild; + +import java.util.List; +import java.util.Map; +import org.bukkit.plugin.Plugin; + + +public interface IAntiBuild extends Plugin +{ + boolean checkProtectionItems(final AntiBuildConfig list, final int id); + + boolean getSettingBool(final AntiBuildConfig protectConfig); + + EssentialsConnect getEssentialsConnect(); + + Map getSettingsBoolean(); + + Map> getSettingsList(); +} diff --git a/EssentialsAntiBuild/src/plugin.yml b/EssentialsAntiBuild/src/plugin.yml new file mode 100644 index 0000000000..cfe6e63672 --- /dev/null +++ b/EssentialsAntiBuild/src/plugin.yml @@ -0,0 +1,9 @@ +# This determines the command prefix when there are conflicts (/name:home, /name:help, etc.) +name: EssentialsAntiBuild +main: com.earth2me.essentials.antibuild.EssentialsAntiBuild +# Note to developers: This next line cannot change, or the automatic versioning system will break. +version: TeamCity +website: http://tiny.cc/EssentialsCommands +description: Provides build protection. +authors: [Zenexer, ementalo, Aelux, Brettflan, KimKandor, snowleo, ceulemans, Xeology, KHobbits, Iaccidentally] +depend: [Essentials] diff --git a/EssentialsChat/pom.xml b/EssentialsChat/pom.xml new file mode 100644 index 0000000000..20916f31f3 --- /dev/null +++ b/EssentialsChat/pom.xml @@ -0,0 +1,51 @@ + + 4.0.0 + + + net.ess3 + EssentialsParent + 2.x-SNAPSHOT + + + EssentialsChat + + 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/ + + + + + net.ess3 + Essentials + ${project.version} + + + \ No newline at end of file diff --git a/EssentialsChat/src/com/earth2me/essentials/chat/ChatStore.java b/EssentialsChat/src/com/earth2me/essentials/chat/ChatStore.java new file mode 100644 index 0000000000..8e40a3dff6 --- /dev/null +++ b/EssentialsChat/src/com/earth2me/essentials/chat/ChatStore.java @@ -0,0 +1,51 @@ +package com.earth2me.essentials.chat; + +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import net.ess3.api.IEssentials; + + +public class ChatStore +{ + private final User user; + private final String type; + private final Trade charge; + private long radius; + + ChatStore(final IEssentials ess, final User user, final String type) + { + this.user = user; + this.type = type; + this.charge = new Trade(getLongType(), ess); + } + + public User getUser() + { + return user; + } + + public Trade getCharge() + { + return charge; + } + + public String getType() + { + return type; + } + + public final String getLongType() + { + return type.length() == 0 ? "chat" : "chat-" + type; + } + + public long getRadius() + { + return radius; + } + + public void setRadius(long radius) + { + this.radius = radius; + } +} diff --git a/EssentialsChat/src/com/earth2me/essentials/chat/EssentialsChat.java b/EssentialsChat/src/com/earth2me/essentials/chat/EssentialsChat.java new file mode 100644 index 0000000000..d8b40d36c1 --- /dev/null +++ b/EssentialsChat/src/com/earth2me/essentials/chat/EssentialsChat.java @@ -0,0 +1,44 @@ +package com.earth2me.essentials.chat; + +import static com.earth2me.essentials.I18n.tl; +import net.ess3.api.IEssentials; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.java.JavaPlugin; + + +public class EssentialsChat extends JavaPlugin +{ + private static final Logger LOGGER = Logger.getLogger("Minecraft"); + + @Override + public void onEnable() + { + final PluginManager pluginManager = getServer().getPluginManager(); + final IEssentials ess = (IEssentials)pluginManager.getPlugin("Essentials"); + if (!this.getDescription().getVersion().equals(ess.getDescription().getVersion())) + { + LOGGER.log(Level.WARNING, tl("versionMismatchAll")); + } + if (!ess.isEnabled()) + { + this.setEnabled(false); + return; + } + + final Map chatStore = Collections.synchronizedMap(new HashMap()); + + final EssentialsChatPlayerListenerLowest playerListenerLowest = new EssentialsChatPlayerListenerLowest(getServer(), ess, chatStore); + final EssentialsChatPlayerListenerNormal playerListenerNormal = new EssentialsChatPlayerListenerNormal(getServer(), ess, chatStore); + final EssentialsChatPlayerListenerHighest playerListenerHighest = new EssentialsChatPlayerListenerHighest(getServer(), ess, chatStore); + pluginManager.registerEvents(playerListenerLowest, this); + pluginManager.registerEvents(playerListenerNormal, this); + pluginManager.registerEvents(playerListenerHighest, this); + + } +} diff --git a/EssentialsChat/src/com/earth2me/essentials/chat/EssentialsChatPlayer.java b/EssentialsChat/src/com/earth2me/essentials/chat/EssentialsChatPlayer.java new file mode 100644 index 0000000000..8b8737e14a --- /dev/null +++ b/EssentialsChat/src/com/earth2me/essentials/chat/EssentialsChatPlayer.java @@ -0,0 +1,100 @@ +package com.earth2me.essentials.chat; + +import com.earth2me.essentials.ChargeException; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import net.ess3.api.IEssentials; +import java.util.Map; +import java.util.logging.Logger; +import org.bukkit.Server; +import org.bukkit.event.Listener; +import org.bukkit.event.player.AsyncPlayerChatEvent; + + +public abstract class EssentialsChatPlayer implements Listener +{ + protected static final Logger logger = Logger.getLogger("Minecraft"); + protected transient IEssentials ess; + protected final transient Server server; + protected final transient Map chatStorage; + + public EssentialsChatPlayer(final Server server, + final IEssentials ess, + final Map chatStorage) + { + this.ess = ess; + this.server = server; + this.chatStorage = chatStorage; + } + + public void onPlayerChat(final AsyncPlayerChatEvent event) + { + } + + public boolean isAborted(final AsyncPlayerChatEvent event) + { + if (event.isCancelled()) + { + return true; + } + return false; + } + + public String getChatType(final String message) + { + if (message.length() == 0) + { + //Ignore empty chat events generated by plugins + return ""; + } + + final char prefix = message.charAt(0); + if (prefix == ess.getSettings().getChatShout()) + { + return "shout"; + } + else if (prefix == ess.getSettings().getChatQuestion()) + { + return "question"; + } + else + { + return ""; + } + } + + public ChatStore getChatStore(final AsyncPlayerChatEvent event) + { + return chatStorage.get(event); + } + + public void setChatStore(final AsyncPlayerChatEvent event, final ChatStore chatStore) + { + chatStorage.put(event, chatStore); + } + + public ChatStore delChatStore(final AsyncPlayerChatEvent event) + { + return chatStorage.remove(event); + } + + protected void charge(final User user, final Trade charge) throws ChargeException + { + charge.charge(user); + } + + protected boolean charge(final AsyncPlayerChatEvent event, final ChatStore chatStore) + { + try + { + charge(chatStore.getUser(), chatStore.getCharge()); + } + catch (ChargeException e) + { + ess.showError(chatStore.getUser().getSource(), e, "\\ chat " + chatStore.getLongType()); + event.setCancelled(true); + return false; + } + return true; + } +} diff --git a/EssentialsChat/src/com/earth2me/essentials/chat/EssentialsChatPlayerListenerHighest.java b/EssentialsChat/src/com/earth2me/essentials/chat/EssentialsChatPlayerListenerHighest.java new file mode 100644 index 0000000000..2a0d621a47 --- /dev/null +++ b/EssentialsChat/src/com/earth2me/essentials/chat/EssentialsChatPlayerListenerHighest.java @@ -0,0 +1,35 @@ +package com.earth2me.essentials.chat; + +import net.ess3.api.IEssentials; +import java.util.Map; +import org.bukkit.Server; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.AsyncPlayerChatEvent; + + +public class EssentialsChatPlayerListenerHighest extends EssentialsChatPlayer +{ + public EssentialsChatPlayerListenerHighest(final Server server, + final IEssentials ess, + final Map chatStorage) + { + super(server, ess, chatStorage); + } + + @EventHandler(priority = EventPriority.HIGHEST) + @Override + public void onPlayerChat(final AsyncPlayerChatEvent event) + { + final ChatStore chatStore = delChatStore(event); + if (isAborted(event) || chatStore == null) + { + return; + } + + /** + * This file should handle charging the user for the action before returning control back + */ + charge(event, chatStore); + } +} diff --git a/EssentialsChat/src/com/earth2me/essentials/chat/EssentialsChatPlayerListenerLowest.java b/EssentialsChat/src/com/earth2me/essentials/chat/EssentialsChatPlayerListenerLowest.java new file mode 100644 index 0000000000..aa40a81484 --- /dev/null +++ b/EssentialsChat/src/com/earth2me/essentials/chat/EssentialsChatPlayerListenerLowest.java @@ -0,0 +1,64 @@ +package com.earth2me.essentials.chat; + +import com.earth2me.essentials.User; +import com.earth2me.essentials.utils.FormatUtil; +import net.ess3.api.IEssentials; +import java.util.Locale; +import java.util.Map; +import org.bukkit.Server; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.scoreboard.Team; + + +public class EssentialsChatPlayerListenerLowest extends EssentialsChatPlayer +{ + public EssentialsChatPlayerListenerLowest(final Server server, + final IEssentials ess, + final Map chatStorage) + { + super(server, ess, chatStorage); + } + + @EventHandler(priority = EventPriority.LOWEST) + @Override + public void onPlayerChat(final AsyncPlayerChatEvent event) + { + if (isAborted(event)) + { + return; + } + + final User user = ess.getUser(event.getPlayer()); + + if (user == null) + { + event.setCancelled(true); + return; + } + + final ChatStore chatStore = new ChatStore(ess, user, getChatType(event.getMessage())); + setChatStore(event, chatStore); + + /** + * This listener should apply the general chat formatting only...then return control back the event handler + */ + event.setMessage(FormatUtil.formatMessage(user, "essentials.chat", event.getMessage())); + String group = user.getGroup(); + String world = user.getWorld().getName(); + Team team = user.getBase().getScoreboard().getPlayerTeam(user.getBase()); + + String format = ess.getSettings().getChatFormat(group); + format = format.replace("{0}", group); + format = format.replace("{1}", world); + format = format.replace("{2}", world.substring(0, 1).toUpperCase(Locale.ENGLISH)); + format = format.replace("{3}", team == null ? "" : team.getPrefix()); + format = format.replace("{4}", team == null ? "" : team.getSuffix()); + format = format.replace("{5}", team == null ? "" : team.getDisplayName()); + synchronized (format) + { + event.setFormat(format); + } + } +} diff --git a/EssentialsChat/src/com/earth2me/essentials/chat/EssentialsChatPlayerListenerNormal.java b/EssentialsChat/src/com/earth2me/essentials/chat/EssentialsChatPlayerListenerNormal.java new file mode 100644 index 0000000000..07e81d9d44 --- /dev/null +++ b/EssentialsChat/src/com/earth2me/essentials/chat/EssentialsChatPlayerListenerNormal.java @@ -0,0 +1,154 @@ +package com.earth2me.essentials.chat; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import static com.earth2me.essentials.chat.EssentialsChatPlayer.logger; +import net.ess3.api.IEssentials; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.logging.Level; +import net.ess3.api.events.LocalChatSpyEvent; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.AsyncPlayerChatEvent; + + +public class EssentialsChatPlayerListenerNormal extends EssentialsChatPlayer +{ + public EssentialsChatPlayerListenerNormal(final Server server, + final IEssentials ess, + final Map chatStorage) + { + super(server, ess, chatStorage); + } + + @EventHandler(priority = EventPriority.NORMAL) + @Override + public void onPlayerChat(final AsyncPlayerChatEvent event) + { + if (isAborted(event)) + { + return; + } + + /** + * This file should handle detection of the local chat features... if local chat is enabled, we need to handle + * it here + */ + long radius = ess.getSettings().getChatRadius(); + if (radius < 1) + { + return; + } + radius *= radius; + + final ChatStore chatStore = getChatStore(event); + final User user = chatStore.getUser(); + chatStore.setRadius(radius); + + if (event.getMessage().length() > 1 && chatStore.getType().length() > 0) + { + final StringBuilder permission = new StringBuilder(); + permission.append("essentials.chat.").append(chatStore.getType()); + + if (user.isAuthorized(permission.toString())) + { + final StringBuilder format = new StringBuilder(); + format.append(chatStore.getType()).append("Format"); + event.setMessage(event.getMessage().substring(1)); + event.setFormat(tl(format.toString(), event.getFormat())); + return; + } + + final StringBuilder errorMsg = new StringBuilder(); + errorMsg.append("notAllowedTo").append(chatStore.getType().substring(0, 1).toUpperCase(Locale.ENGLISH)).append(chatStore.getType().substring(1)); + + user.sendMessage(tl(errorMsg.toString())); + event.setCancelled(true); + return; + } + + final Location loc = user.getLocation(); + final World world = loc.getWorld(); + + if (charge(event, chatStore) == false) + { + return; + } + + Set outList = event.getRecipients(); + Set spyList = new HashSet(); + + try + { + outList.add(event.getPlayer()); + } + catch (UnsupportedOperationException ex) + { + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "Plugin triggered custom chat event, local chat handling aborted.", ex); + } + return; + } + + final String format = event.getFormat(); + event.setFormat(tl("chatTypeLocal").concat(event.getFormat())); + + logger.info(tl("localFormat", user.getName(), event.getMessage())); + + final Iterator it = outList.iterator(); + while (it.hasNext()) + { + final Player onlinePlayer = it.next(); + final User onlineUser = ess.getUser(onlinePlayer); + if (!onlineUser.equals(user)) + { + boolean abort = false; + final Location playerLoc = onlineUser.getLocation(); + if (playerLoc.getWorld() != world) + { + abort = true; + } + else + { + final double delta = playerLoc.distanceSquared(loc); + if (delta > chatStore.getRadius()) + { + abort = true; + } + } + if (abort) + { + if (onlineUser.isAuthorized("essentials.chat.spy")) + { + spyList.add(onlinePlayer); + } + it.remove(); + } + } + } + + if (outList.size() < 2) { + user.sendMessage(tl("localNoOne")); + } + + LocalChatSpyEvent spyEvent = new LocalChatSpyEvent(event.isAsynchronous(), event.getPlayer(), format, event.getMessage(), spyList); + server.getPluginManager().callEvent(spyEvent); + + if (!spyEvent.isCancelled()) + { + for (Player onlinePlayer : spyEvent.getRecipients()) + { + onlinePlayer.sendMessage(String.format(spyEvent.getFormat(), user.getDisplayName(), spyEvent.getMessage())); + } + } + } +} diff --git a/EssentialsChat/src/plugin.yml b/EssentialsChat/src/plugin.yml new file mode 100644 index 0000000000..b75ab8ecc3 --- /dev/null +++ b/EssentialsChat/src/plugin.yml @@ -0,0 +1,10 @@ +# This determines the command prefix when there are conflicts (/name:home, /name:help, etc.) +name: EssentialsChat +main: com.earth2me.essentials.chat.EssentialsChat +# Note to developers: This next line cannot change, or the automatic versioning system will break. +version: TeamCity +website: http://tiny.cc/EssentialsCommands +description: Provides chat control features for Essentials. Requires Permissions. +authors: [Zenexer, ementalo, Aelux, Brettflan, KimKandor, snowleo, ceulemans, Xeology, KHobbits, md_5, Okamosy, Iaccidentally] +depend: [Essentials] +#softdepend: [Factions] \ No newline at end of file diff --git a/EssentialsGeoIP/pom.xml b/EssentialsGeoIP/pom.xml new file mode 100644 index 0000000000..4e886a4bb8 --- /dev/null +++ b/EssentialsGeoIP/pom.xml @@ -0,0 +1,81 @@ + + 4.0.0 + + + net.ess3 + EssentialsParent + 2.x-SNAPSHOT + + + EssentialsGeoIP + + 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/ + + + + + net.ess3 + Essentials + ${project.version} + + + com.maxmind.geoip + geoip-api + 1.2.11 + + + + + + + org.apache.maven.plugins + maven-shade-plugin + 2.1 + + + package + + shade + + + + + + + com.maxmind.geoip:geoip-api + + + + + + + \ No newline at end of file diff --git a/EssentialsGeoIP/src/com/earth2me/essentials/geoip/EssentialsGeoIP.java b/EssentialsGeoIP/src/com/earth2me/essentials/geoip/EssentialsGeoIP.java new file mode 100644 index 0000000000..aced4ccb8d --- /dev/null +++ b/EssentialsGeoIP/src/com/earth2me/essentials/geoip/EssentialsGeoIP.java @@ -0,0 +1,40 @@ +package com.earth2me.essentials.geoip; + +import static com.earth2me.essentials.I18n.tl; +import net.ess3.api.IEssentials; +import java.util.logging.Level; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.java.JavaPlugin; + + +public class EssentialsGeoIP extends JavaPlugin +{ + public EssentialsGeoIP() + { + } + + @Override + public void onDisable() + { + } + + @Override + public void onEnable() + { + final PluginManager pm = getServer().getPluginManager(); + final IEssentials ess = (IEssentials)pm.getPlugin("Essentials"); + if (!this.getDescription().getVersion().equals(ess.getDescription().getVersion())) + { + getLogger().log(Level.WARNING, tl("versionMismatchAll")); + } + if (!ess.isEnabled()) { + this.setEnabled(false); + return; + } + final EssentialsGeoIPPlayerListener playerListener = new EssentialsGeoIPPlayerListener(getDataFolder(), ess); + pm.registerEvents(playerListener, this); + + + getLogger().log(Level.INFO, "This product includes GeoLite data created by MaxMind, available from http://www.maxmind.com/."); + } +} diff --git a/EssentialsGeoIP/src/com/earth2me/essentials/geoip/EssentialsGeoIPPlayerListener.java b/EssentialsGeoIP/src/com/earth2me/essentials/geoip/EssentialsGeoIPPlayerListener.java new file mode 100644 index 0000000000..a6cb28ddc3 --- /dev/null +++ b/EssentialsGeoIP/src/com/earth2me/essentials/geoip/EssentialsGeoIPPlayerListener.java @@ -0,0 +1,189 @@ +package com.earth2me.essentials.geoip; + +import com.earth2me.essentials.EssentialsConf; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.IConf; +import com.earth2me.essentials.User; +import net.ess3.api.IEssentials; +import com.maxmind.geoip.Location; +import com.maxmind.geoip.LookupService; +import com.maxmind.geoip.regionName; +import java.io.*; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.zip.GZIPInputStream; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; + + +public class EssentialsGeoIPPlayerListener implements Listener, IConf +{ + LookupService ls = null; + private static final Logger logger = Logger.getLogger("Minecraft"); + File databaseFile; + File dataFolder; + final EssentialsConf config; + private final transient IEssentials ess; + + public EssentialsGeoIPPlayerListener(File dataFolder, IEssentials ess) + { + this.ess = ess; + this.dataFolder = dataFolder; + this.config = new EssentialsConf(new File(dataFolder, "config.yml")); + config.setTemplateName("/config.yml", EssentialsGeoIP.class); + reloadConfig(); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onPlayerJoin(final PlayerJoinEvent event) + { + ess.runTaskAsynchronously(new Runnable() + { + @Override + public void run() + { + delayedJoin(event.getPlayer()); + } + }); + } + + public void delayedJoin(Player player) + { + User u = ess.getUser(player); + if (u.isAuthorized("essentials.geoip.hide") || player.getAddress() == null) + { + return; + } + InetAddress address = player.getAddress().getAddress(); + StringBuilder sb = new StringBuilder(); + if (config.getBoolean("database.show-cities", false)) + { + Location loc = ls.getLocation(address); + if (loc == null) + { + return; + } + if (loc.city != null) + { + sb.append(loc.city).append(", "); + } + String region = regionName.regionNameByCode(loc.countryCode, loc.region); + if (region != null) + { + sb.append(region).append(", "); + } + sb.append(loc.countryName); + } + else + { + sb.append(ls.getCountry(address).getName()); + } + if (config.getBoolean("show-on-whois", true)) + { + u.setGeoLocation(sb.toString()); + } + if (config.getBoolean("show-on-login", true) && !u.isHidden()) + { + for (Player onlinePlayer : player.getServer().getOnlinePlayers()) + { + User user = ess.getUser(onlinePlayer); + if (user.isAuthorized("essentials.geoip.show")) + { + user.sendMessage(tl("geoipJoinFormat", u.getDisplayName(), sb.toString())); + } + } + } + } + + @Override + public final void reloadConfig() + { + config.load(); + + if (config.getBoolean("database.show-cities", false)) + { + databaseFile = new File(dataFolder, "GeoIPCity.dat"); + } + else + { + databaseFile = new File(dataFolder, "GeoIP.dat"); + } + if (!databaseFile.exists()) + { + if (config.getBoolean("database.download-if-missing", true)) + { + downloadDatabase(); + } + else + { + logger.log(Level.SEVERE, tl("cantFindGeoIpDB")); + return; + } + } + try + { + ls = new LookupService(databaseFile); + } + catch (IOException ex) + { + logger.log(Level.SEVERE, tl("cantReadGeoIpDB"), ex); + } + } + + private void downloadDatabase() + { + try + { + String url; + if (config.getBoolean("database.show-cities", false)) + { + url = config.getString("database.download-url-city"); + } + else + { + url = config.getString("database.download-url"); + } + if (url == null || url.isEmpty()) + { + logger.log(Level.SEVERE, tl("geoIpUrlEmpty")); + return; + } + logger.log(Level.INFO, tl("downloadingGeoIp")); + URL downloadUrl = new URL(url); + URLConnection conn = downloadUrl.openConnection(); + conn.setConnectTimeout(10000); + conn.connect(); + InputStream input = conn.getInputStream(); + if (url.endsWith(".gz")) + { + input = new GZIPInputStream(input); + } + OutputStream output = new FileOutputStream(databaseFile); + byte[] buffer = new byte[2048]; + int length = input.read(buffer); + while (length >= 0) + { + output.write(buffer, 0, length); + length = input.read(buffer); + } + output.close(); + input.close(); + } + catch (MalformedURLException ex) + { + logger.log(Level.SEVERE, tl("geoIpUrlInvalid"), ex); + return; + } + catch (IOException ex) + { + logger.log(Level.SEVERE, tl("connectionFailed"), ex); + } + } +} diff --git a/EssentialsGeoIP/src/config.yml b/EssentialsGeoIP/src/config.yml new file mode 100644 index 0000000000..70d7a51ba5 --- /dev/null +++ b/EssentialsGeoIP/src/config.yml @@ -0,0 +1,10 @@ +database: + show-cities: false + download-if-missing: true + # Url for country + download-url: "http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz" + # Url for cities + download-url-city: "http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz" + +show-on-login: true +show-on-whois: true \ No newline at end of file diff --git a/EssentialsGeoIP/src/plugin.yml b/EssentialsGeoIP/src/plugin.yml new file mode 100644 index 0000000000..adf75b83d7 --- /dev/null +++ b/EssentialsGeoIP/src/plugin.yml @@ -0,0 +1,9 @@ +# This determines the command prefix when there are conflicts (/name:home, /name:help, etc.) +name: EssentialsGeoIP +main: com.earth2me.essentials.geoip.EssentialsGeoIP +# Note to developers: This next line cannot change, or the automatic versioning system will break. +version: TeamCity +website: http://tiny.cc/EssentialsCommands +description: Shows the country or city of a user on login and /whois. +authors: [Zenexer, ementalo, Aelux, Brettflan, KimKandor, snowleo, ceulemans, Xeology] +depend: [Essentials] \ No newline at end of file diff --git a/EssentialsGroupManager/.classpath b/EssentialsGroupManager/.classpath new file mode 100644 index 0000000000..bc81065031 --- /dev/null +++ b/EssentialsGroupManager/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/EssentialsGroupManager/.project b/EssentialsGroupManager/.project new file mode 100644 index 0000000000..7a39e867da --- /dev/null +++ b/EssentialsGroupManager/.project @@ -0,0 +1,27 @@ + + + EssentialsGroupManager + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.ui.externaltools.ExternalToolBuilder + full,incremental, + + + LaunchConfigHandle + <project>/.externalToolBuilders/GroupManager_Builder.launch + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/EssentialsGroupManager/build.xml b/EssentialsGroupManager/build.xml new file mode 100644 index 0000000000..aeec831d5b --- /dev/null +++ b/EssentialsGroupManager/build.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + Builds, tests, and runs the project EssentialsGroupManager. + + + diff --git a/EssentialsGroupManager/nbproject/build-impl.xml b/EssentialsGroupManager/nbproject/build-impl.xml new file mode 100644 index 0000000000..df136f2baa --- /dev/null +++ b/EssentialsGroupManager/nbproject/build-impl.xml @@ -0,0 +1,1411 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set src.dir + Must set test.src.dir + Must set build.dir + Must set dist.dir + Must set build.classes.dir + Must set dist.javadoc.dir + Must set build.test.classes.dir + Must set build.test.results.dir + Must set build.classes.excludes + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No tests executed. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set JVM to use for profiling in profiler.info.jvm + Must set profiler agent JVM arguments in profiler.info.jvmargs.agent + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + + + + + + java -cp "${run.classpath.with.dist.jar}" ${main.class} + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + Must select one file in the IDE or set run.class + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set debug.class + + + + + Must select one file in the IDE or set debug.class + + + + + Must set fix.includes + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + Must select one file in the IDE or set profile.class + This target only works when run from inside the NetBeans IDE. + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + + + Must select some files in the IDE or set test.includes + + + + + Must select one file in the IDE or set run.class + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + Some tests failed; see details above. + + + + + + + + + Must select some files in the IDE or set test.includes + + + + Some tests failed; see details above. + + + + Must select some files in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + Some tests failed; see details above. + + + + + Must select one file in the IDE or set test.class + + + + Must select one file in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + + + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/EssentialsGroupManager/nbproject/genfiles.properties b/EssentialsGroupManager/nbproject/genfiles.properties new file mode 100644 index 0000000000..3c19c576ec --- /dev/null +++ b/EssentialsGroupManager/nbproject/genfiles.properties @@ -0,0 +1,8 @@ +build.xml.data.CRC32=a6709b83 +build.xml.script.CRC32=5b346364 +build.xml.stylesheet.CRC32=28e38971@1.38.2.45 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=a6709b83 +nbproject/build-impl.xml.script.CRC32=e5c840ec +nbproject/build-impl.xml.stylesheet.CRC32=c6d2a60f@1.56.1.46 diff --git a/EssentialsGroupManager/nbproject/project.properties b/EssentialsGroupManager/nbproject/project.properties new file mode 100644 index 0000000000..bc26273ba6 --- /dev/null +++ b/EssentialsGroupManager/nbproject/project.properties @@ -0,0 +1,99 @@ +annotation.processing.enabled=true +annotation.processing.enabled.in.editor=false +annotation.processing.processors.list= +annotation.processing.run.all.processors=true +annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output +application.title=EssentialsGroupManager +application.vendor=gabrielcouto +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.expand-tabs=true +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.indent-shift-width=2 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.spaces-per-tab=2 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=2 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=120 +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-line-wrap=none +auxiliary.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=project +auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.expand-tabs=false +auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.indent-shift-width=4 +auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaces-per-tab=4 +auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.tab-size=4 +auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.text-limit-width=120 +auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.text-line-wrap=none +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +build.generated.sources.dir=${build.dir}/generated-sources +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results +# Uncomment to specify the preferred debugger connection transport: +#debug.transport=dt_socket +debug.classpath=\ + ${run.classpath} +debug.test.classpath=\ + ${run.test.classpath} +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/EssentialsGroupManager.jar +dist.javadoc.dir=${dist.dir}/javadoc +endorsed.classpath= +excludes= +file.reference.bukkit.jar=../lib/bukkit.jar +includes=** +jar.archive.disabled=${jnlp.enabled} +jar.compress=true +jar.index=${jnlp.enabled} +javac.classpath=\ + ${file.reference.bukkit.jar} +# Space-separated list of extra javac options +javac.compilerargs= +javac.deprecation=false +javac.processorpath=\ + ${javac.classpath} +javac.source=1.6 +javac.target=1.6 +javac.test.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +javac.test.processorpath=\ + ${javac.test.classpath} +javadoc.additionalparam= +javadoc.author=false +javadoc.encoding=${source.encoding} +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +jnlp.codebase.type=no.codebase +jnlp.descriptor=application +jnlp.enabled=false +jnlp.mixed.code=default +jnlp.offline-allowed=false +jnlp.signed=false +jnlp.signing= +jnlp.signing.alias= +jnlp.signing.keystore= +main.class= +manifest.file=manifest.mf +meta.inf.dir=${src.dir}/META-INF +mkdist.disabled=true +platform.active=default_platform +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +# Space-separated list of JVM arguments used when running the project +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value +# or test-sys-prop.name=value to set system properties for unit tests): +run.jvmargs= +run.test.classpath=\ + ${javac.test.classpath}:\ + ${build.test.classes.dir} +source.encoding=UTF-8 +src.dir=src +test.src.dir=test diff --git a/EssentialsGroupManager/nbproject/project.xml b/EssentialsGroupManager/nbproject/project.xml new file mode 100644 index 0000000000..6cc53fda9c --- /dev/null +++ b/EssentialsGroupManager/nbproject/project.xml @@ -0,0 +1,15 @@ + + + org.netbeans.modules.java.j2seproject + + + EssentialsGroupManager + + + + + + + + + diff --git a/EssentialsGroupManager/src/Changelog.txt b/EssentialsGroupManager/src/Changelog.txt new file mode 100644 index 0000000000..50a947da7b --- /dev/null +++ b/EssentialsGroupManager/src/Changelog.txt @@ -0,0 +1,233 @@ +Changelog + +v 1.1: + - Fixed users being able to use 'manuadd' to add users to higher groups than their own. + - Added SuperPerms support so GM will update and provide the permissions to plugins which only support Bukkit Perms. + - Added more helpful output to errors on argument lengths. + - GroupManager will now attempt to select the default world when using commands instead of failing and telling you to use '/manselect '. + - Invalid groups assigned to players in users.yml will no longer cause a crash. GM will now set them to the default group instead. + - Fix for Users.yml containing only 'users:' causing a crash. + - GroupManager will now generate a fresh Users and Groups yml if either file is empty. + - Fix for an infinite loop bug with the new Bukkit Perms during a new user creation. + - Fixed BukkitPerms population. Wasn't correctly setting superperms. + - Push updates to superperms for all valid GM commands. + - All GroupManager commands issued by players are now echoed in the console. + - Reverted WorldHolder static change to maintain backward plugin compatibility. + - Update to handle 'getDescription().getPermissions(') returning a list (CB 1172). + - Fix for null in PLAYER_TELEPORT for bukkit perms. + - Fixed wasteful updating of perms on a manload. + - manulistp now accepts an additional + to list ALL Superperms effective permissions (/manulistp +). + - manucheckp also outputs superperms results. + - Removed superperms update on plugins unloading. Unneeded and created undesired lag on shutdown. + - Added a BukkitPermsUpdateTask to only update superperms once on a load/reload. + - Fix for GM not checking inheritance for known superperms nodes. + - Optimized getAllPlayersPermissions and fixed pushing unknown perms to superperms. +v 1.2: + - Changed priority of Registered events to lowest. + - Fixed an issue with superperms where plugins define perms with inheritance after the root perms +v 1.3: + - Rewrote Config loading to use Bukkits Configuration features + - Added an opOverride setting in config. + If present and set to false, op's will not get overriding permissions in GroupManager. + (one op will not be able to alter another op's settings) + - GM will now create all relevant world data files for non mirrored worlds. + (for all worlds named in config.yml) + - Attempt to stop GM wiping groups/users yml's on a bad shut down. + - Added event handling to manage new world creation at runtime. + - Added the ability to handle unknown worlds at server start. + (GM will create the data files for any worlds it finds which are not in the config.yml) + - Fix for Bukkit passing a null To location on a player Portaling + - Fixed manudelsub not correctly selecting the group to remove. + - Added two new permission nodes - groupmanager.notify.self & groupmanager.notify.other + These allow players/admins to be notified when players are moved between groups. +v 1.4: + - Updated for Bukkits new YamlConfiguration. + - Cleared remaining Cast errors cause by object cloning. + - Removed extra notification messages for the player issuing the group move command. + - Added a config setting - bukkit_perms_override: false + Enable to allow default Bukkit based permissions to remain enabled, unless directly negated within GroupManager. + - Fixed reading world mirrors from the config. + - Simplified config.yml while retaining backwards compatibility. + - Added data.save.hours setting to config. This allow control over how long backups are retained. +v 1.5: + - Fixed opOverrides and bukkit_perms_override to read the correct entries. + - Better commenting in config.yml + - Fixed GM to recognize Superperm child nodes. + If you add a node like Towny.admin GM will now correctly report on all child nodes. + - Fixed GM loading world data files twice at startup. + - Improved error reporting for invalid groups.yml + - Added Global Groups + Defined in groupmanager/globalgroups.yml. + Create groups in the yml with a g: prefix, then inherit in the worlds groups files. + - Added Info node support to Global Groups. + - Fixed an error on 'manucheckv'. If the users doesn't have the variable it fell through causing an exception. + - Added checking of subgroups for Info nodes. + - Expanded 'canUserBuild()' to include inheritance and subgroups. + - Added a config.yml setting of 'validate_toggle' for those who prefer 'mantogglevalidate' to always be off. + - Prevent setting 'minutes' in the config to zero causing an error. + - GM will now check to see if it's data files have been changed at each scheduled save. + If the files have been altered (on disc) it will reload, so long as the in-memory data hasn't changed. + If the files on Disc have changed AND there have been changes to it's in-memory data it will show a warning. + You then MUST issue a '/mansave force' to overwrite the disc files, or a '/manload' to overwrite the memory data. + - Fix for an error in checkFullUserPermission caused by players disconnecting mid perms update. + - Notification of being moved to the default group only happens if it's a demotion/promotion (not on join). + - Fixed GM holding files open and causing the time stamp to be incorrect. This caused GM to require a '/mansave force' when it shouldn't be needed. + - Fixed a crash on reload due to bukkit not unloading plugins before reloading. +v 1.6: + - Prevent Group.equals tests throwing a NullPointerException for GlobalGroups. + - Stop throwing errors on an empty users file. + - Optimize sorting to speedup permission tests. + - Fix superperms to pass all tests http://dev.bukkit.org/server-mods/superpermstest/ + - Optimizations include changing the return of comparePermissionString. + - Added file details in error messages for loading groups/users. +v 1.7: + - GM now supports offline players without having to mantogglevalidate + - Offline player checks now support partial name matches. + - Added custom events so plugins can now be notified of changes within GroupManager. + - GM now registers with Bukkits ServicesManager. + - deleting the contents of GlobalGroups.yml will no longer thrown a NullPointerException. + - Removed op permissions from admins in the default GloblaGroups.yml. +v 1.8: + - Changed ServicesManager registration to lowest from normal. + - Fixed 'manucheckp' returning a null for the searched node when it's a group/subgroup. + - 'manpromote' and 'mandemote' now correctly send the notification to the console if the command was issued there. + - Expanded GlobalGroups.yml and Groups.yml to include Towny permissions. + - Delayed GroupManager events so Superperms will be fully updated before plugins receive the events. + - Changed the way events are raised to prevent variable corruption. + - Reload GlobalGroups when you perform a world load. + - Changed GlobalGroups to save/load before local groups in the scheduled data saving/loading + - Fix 'manucheckp' to correctly report if a permission is available from GroupManager or Bukkit. + - Changed over to a reflection method for populating superperms as Bukkit lags when you handle permissions one at a time. + - Major, MAJOR changes to support partial/full world mirroring. + You can now mirror groups.yml, users.yml or both files between different worlds. + - Catch NullPointerErrors generated by blank permission nodes. + - Removed '- bukkit.command' form the globalgroups permission nodes. +v 1.9: + - Optimize populating Bukkit perms so we no longer calculate the child nodes (Bukkit already does this). + - Added a tidy error message for invalid permission entries in GlobalGroups. + - Better optimize assembling of a players permissions and allow the * node to populate all registered superperms. + - Fixed text when adding a subgroup to not say the player was moved. + - Update to new Bukkit Event system. + - Update GroupManagerBridge for new event system. + - Fixed a random null error upon a player portaling. + - Fixed infinite loop error on player join. + - Optimized code to only update the player logging in instead of all players online. + - Added recursive loop detection for World mirroring (you may not set the main world as a mirror of another). + - Fixed fetching world data so it no longer returns the mirrored world for groups. Each world data holder now points to the correct data set, so can be returned as an object. + - Changed addSubGroup() to only add the group if it doesn't already exist (no need to update an already existing group). + - addSubGroup now returns a boolean for success/failure. + - '/manuaddsub' now correctly reports if it was able to add the sub group. + - Allow negation to the * permission node when populating superperms. + - Fix trying to modify an unmodifiable collection breaking superperms. + - Fixed subgroups (I broke earlier). + - Check for a null player object in the PlayerTeleportEvent. + - Trap errors in fetching the mirrors map. + - Fixed an infinite loop error when using '/manudel' on a logged in player. It caused setDefaultGroup to trigger a bukkit update when no GM User existed yet. + - do not allow inherited permissions to negate higher perms. + - Fixed a bug when pushing superperms in the wrong order. + - Fix players retaining permissions when demoted. + - Auto sort permissions on load to speed up population of superperms. + - Negating a parent node after adding all nodes with * will now correctly remove all child nodes of that parent before populating superperms. + eg. + - '*' + - -vanish.* + - vanish.standard + - Track the 'onPlayerChangeWorld' event as some teleports seem to not be triggering a world move. + - Catch all errors in badly formatted groups. + - Fix a bug with getWorldData return the main world data for all mirrors, instead of the worlds parent data. + - Prevent getAllPlayersPermissions() processing a group more than once. Improves performance when using complex inheritance structures. + - Fix world mirroring so it correctly creates data files and data sources for partially mirrored worlds. + - Fixed world mirroring so it returns the correct data for the requested world. + - Change Service registration to register WorldsHolder instead of AnjoPermissionsHandler. This is the correct entry point for all data. + - Depreciate PlayerTeleportEvent, PlayerRespawnEvent and PlayerPortalEvent as it's all handled in PlayerChangedWorldEvent. + This also means we no longer update permissions before we change worlds. + - A command of '/manload' with no world arguments now performs a full reload of GM. + - Update for Bukkit R5 compatability. + - Removed BukkitPermsOverride as this is now the default with bukkit handling child nodes. + - Prevent adding inheritances and info nodes to globalgroups. These are permissions collections, not player groups. + - Prevent promoting players to, and demoting to GlobalGroups. + - Make 'manload' reload the config correctly. + - Minor optimization when checking bukkit permissions. + - Better reporting when a users.yml is failing to load. + - Expanded '/manuadd'to accept an optional variable for the world (eg '/manuadd '). + - Removed some debug spam. + - Don't remove an attachment on a player leaving as Bukkit never forgets it. This fixes non mirrored permissions being messed up if a player relogs. + - Treat all world names as lower case for file handling (please check in your worlds folder. You should have no folders with upper case letters from now). + - Auto rename all case sensitive world folders to lower case (if possible). + - Update GlobalGroups.yml for new/changed Towny permission nodes. + - Stop attempting to push empty permissions when players edit the yml's incorrectly. + - Catch errors caused by bad indentation in yml's. + - Force remove player attachments on disconnect, and tidyup during player join in case of any errors. Fixes a bug of losing permissions. + - Added a new permission node 'groupmanager.op'. This will cause players with this node to be treated as op's when + using GroupManager commands (they will still require each commands permission node to use them). + - Prevent Null entries in group inheritance from throwing errors. +v 2.0: + - Fix GM reporting of permission inheritance to retain the correct order. Lower inheritance groups can no longer negate a higher groups permissions. + - Fix an error I caused trying to modify an unmodifiable list when parsing '*' permissions. + - Don't throw errors when attempting to remove permission attachments (bukkit will have already removed it). + - Remove all permission attachments when performing a manload or restart. + - Expand 'manwhois' to also list a users subgroups. + - Fix a concurrent modification error when removing all attachments. + - Better handling of errors in user and group yml's. + - Added missing confirmation message on '/manload'. + - Stop the error on shutdown if GM failed to load at startup. + - GroupManager will now generate it's own log (in the GM folder) to keep things tidy, but also to account of those players unable to find/access their server.log. + - Startup errors will now lock out ALL commands other than '/manload' + - Fix 'manuadd' to use the default or selected world (via 'manselect'), if the world is not specified in the command. + - Expand GlobalGroups.yml and groups.yml to cover the VanishNoPacket plugin. Demonstrating how to negate and add nodes when using the '*' permission with inheritance. + - Fix silly nested throw/catch statements. Errors are now correctly generated when reading yml's. + - Unregister the worldsHolder as a service on a reload/shutdown instead of the whole plugin. + - Update all code formatting to use tabs for indentation. + - Stop using our own deprecated methods as we tell others to do. + - Finally remove all deprecated methods. + - Re-initialize the WorldsHolder on a reload, as un-registering and re-registering a new holder means all plugins have to check for the new service on every quiery. + - Prevent null perms getting past the GlobalGroups loader. + - Fix forgetting sub groups on a manload. + - Allow 'manucheckp' to notify when superperms reports false but it is really negated. + - Only output a Data update message if something has changed. + - Fix loading users with only numerals in their names to be seen as strings. + - Ignore any sub folders in the Worlds folder which start with a period (fix for storing data in svn respoitories). + - Throw a better error than 'null' when someone removes all groups from a yml. + - Stop force removing attachments and let Bukkit handle it's own mess. + - Change to our own Yaml parsing for globalgroups instead of using the YAMLConfiguration class in bukkit. + - Fix a cases sensitivity bug in world loading. + - Stop using the YamlConfiguration in bukkit for our config handling. We can now support periods in world names. + - Fix GlobalGroups not loading permission nodes. + - Fix an error with Logging set to 'OFF' triggering a cast exception. + - No more null errors from corrupt config.yml's. + - Give a better error when a subgroup is null. + - Include the GM version when logging errors. + - Fix Synchronization on adding subgroups (thanks snowleo). + - Remove info node support from GlobalGroups. It should not have them as GlobalGroups are only permission collections. + - Change order of data in Users.yml to [name, Group, SubGroup, Permissions, Info nodes]. + - Add alphabetically sorted user lists. + - allWorldsDataList now returns fully mirrored worlds which are not identical mirrors (fixes the /manselect list). + - Add support for Rcon. + - Prevent GM commands from being used on CommandBlocks. + - Clear our attachment map upon a manload so we correctly reconfigure a players new permissions. + - Synchronize the raising of GroupManager events to Bukkit.getServer() (should prevent deadlocks). + - Synchronize pushing to Bukkit perms to prevent any ConcurrentModificationException. + - Do not grant any permissions (nor update Bukkit) if the server is in offline mode and the player has the permission node 'groupmanager.noofflineperms'. + - Negate 'groupmanager.noofflineperms' by default in the owner group. + - Add support for BukkitForge using 'overworld' as the main world name. + - Prevent '*' permissions granting the 'groupmanager.noofflineperms' permission. + - Added '/mancheckw ' to inspect which permission files a world is referencing. + - Add config potion to set if GM commands should be allowed on CommnandBlocks. + - Catch the error when using an out of date config for 'allow_commandblocks' So it doesn't kill the whole config. + - '/manselect' will no longer list duplicate worlds. + - Added a new mirroring option in the config of 'all_unnamed_worlds'. This will cause all new or unnamed worlds to use this mirroring. + - Don't allow adding a node with '/manuaddp' and '/mangaddp' which is already negated. + - Warn when adding a node where an exception already exist. + - Only prevent adding nodes with '/manuaddp' and '/mangaddp' if they are exact matches (not wildcards). + - Store worldSelection indexed on the senders name rather than the object (fixes commandblocks using manselect). + - Check subgroup permissions with an equal priority so no one subgroup is higher ranked than another. + - add recursive permission adding/deleting + - Prevent adding sub groups for ranks the granting player doesn't have access to. + - Allow Exceptions in any inherited group to override negation of permissions. +v2.1: + - Update for CraftBukkit 1.7.8-R0.1(3050). + - Add UUID support. + Plugins can still query by player name but a UUID is faster and preferable. + - Set a default mirror map if none is found in the config. + - Fix clones forgetting sub groups. + - Prevent players who have never logged in before from taking over existing accounts. \ No newline at end of file diff --git a/EssentialsGroupManager/src/config.yml b/EssentialsGroupManager/src/config.yml new file mode 100644 index 0000000000..44cfd62428 --- /dev/null +++ b/EssentialsGroupManager/src/config.yml @@ -0,0 +1,50 @@ +settings: + config: + # With this enabled anyone set as op has full permissions when managing GroupManager + # The user will be able to promote players to the same group or even above. + opOverrides: true + + # Default setting for 'mantogglevalidate' + # true will cause GroupManager to attempt name matching by default. + validate_toggle: true + # ************************************************************************************************************************************************************ + # *** NOTE: Having this feature enabled can allow improper use of Command Blocks which may lead to undesireable permission changes. You have been warned! *** + # ************************************************************************************************************************************************************ + allow_commandblocks: false + + data: + save: + # How often GroupManager will save it's data back to groups.yml and users.yml + minutes: 10 + # Number of hours to retain backups (plugins/GroupManager/backup) + hours: 24 + + logging: + # Level of detail GroupManager will use when logging. + # Acceptable entries are - ALL,CONFIG,FINE,FINER,FINEST,INFO,OFF,SEVERE,WARNING + level: INFO + + mirrors: + # Worlds listed here have their settings mirrored in their children. + # The first element 'world' is the main worlds name, and is the parent world. + # subsequent elements 'world_nether' and 'world_the_end' are worlds which will use + # the same user/groups files as the parent. + # the element 'all_unnamed_worlds' specifies all worlds that aren't listed, and automatically mirrors them to it's parent. + # Each child world can be configured to mirror the 'groups', 'users' or both files from its parent. + world: + world_nether: + - users + - groups + world_the_end: + - users + - groups + all_unnamed_worlds: + - users + - groups + # world2: (World2 would have it's own set of user and groups files) + # world3: + # - users (World3 would use the users.yml from world2, but it's own groups.yml) + # world4: + # - groups (World4 would use the groups.yml from world2, but it's own users.yml) + # world5: + # - world6 (this would cause world6 to mirror both files from world5) diff --git a/EssentialsGroupManager/src/globalgroups.yml b/EssentialsGroupManager/src/globalgroups.yml new file mode 100644 index 0000000000..cec4d889d0 --- /dev/null +++ b/EssentialsGroupManager/src/globalgroups.yml @@ -0,0 +1,329 @@ +# These groups only contain permission nodes. +# +# **** You can NOT add anything other than permission nodes **** +# **** This is NOT where you set up the groups which you give to users! **** +# **** goto groupmanager/worlds/worldname/groups.yml if you want to set the actual groups! **** +# +# These collections are to be inherited in your different worlds groups.yml's +# They can also be added as one of a users subgroups, but NOT as a primary group. +# These collections are available to ALL group and user yml's. +# +# Add to and customize these groups to fit your needs. + +groups: + +# Permission nodes for GroupManager +# by ElgarL, snowleo, continued from gabrielcouto's original +# http://wiki.ess3.net + + g:groupmanager_default: + permissions: + - groupmanager.notify.self + + g:groupmanager_moderator: + permissions: + - groupmanager.listgroups + - groupmanager.mandemote + - groupmanager.manpromote + - groupmanager.manselect + - groupmanager.manuadd + - groupmanager.manudel + - groupmanager.manwhois + - groupmanager.notify.other + + g:groupmanager_admin: + permissions: + - groupmanager.mantogglevalidate + - groupmanager.mansave + - groupmanager.mangcheckp + - groupmanager.manglistp + - groupmanager.manucheckp + - groupmanager.manulistp + +# Permission nodes for CraftBukkit +# by many devs and contributors +# http://dl.bukkit.org/ + + g:bukkit_default: + permissions: + - bukkit.broadcast.user + - -bukkit.command.plugins + + g:bukkit_moderator: + permissions: + - bukkit.command.ban + - bukkit.command.ban.ip + - bukkit.command.ban.player + - bukkit.command.gamemode + - bukkit.command.kick + - bukkit.command.unban + - bukkit.command.unban.ip + - bukkit.command.unban.player + + g:bukkit_admin: + permissions: + - bukkit.broadcast + - bukkit.broadcast.admin + - bukkit.command.give + - bukkit.command.help + - bukkit.command.kill + - bukkit.command.list + - bukkit.command.me + - -bukkit.command.op + - -bukkit.command.op.give + - -bukkit.command.op.take + - bukkit.command.plugins + - bukkit.command.reload + - bukkit.command.save + - bukkit.command.save.disable + - bukkit.command.save.enable + - bukkit.command.save.perform + - bukkit.command.say + - bukkit.command.stop + - bukkit.command.teleport + - bukkit.command.tell + - bukkit.command.time + - bukkit.command.time.add + - bukkit.command.time.set + - bukkit.command.version + - bukkit.command.whitelist + - bukkit.command.whitelist.add + - bukkit.command.whitelist.disable + - bukkit.command.whitelist.enable + - bukkit.command.whitelist.list + - bukkit.command.whitelist.reload + - bukkit.command.whitelist.remove + +# Permission nodes for Essentials +# by ementalo, snowleo, and KHobbits +# http://dev.bukkit.org/server-mods/essentials/ + + g:essentials_default: + permissions: + - essentials.help + - essentials.helpop + - essentials.list + - essentials.motd + - essentials.rules + - essentials.spawn + - essentials.jail.allow.help + - essentials.jail.allow.helpop + - essentials.jail.allow.rules + + g:essentials_builder: + permissions: + - essentials.afk + - essentials.afk.auto + - essentials.back + - essentials.back.ondeath + - essentials.balance + - essentials.balance.others + - essentials.balancetop + - essentials.book + - essentials.chat.color + - essentials.chat.format + - essentials.chat.shout + - essentials.chat.question + - essentials.compass + - essentials.delhome + - essentials.depth + - essentials.exp + - essentials.getpos + - essentials.hat + - essentials.home + - essentials.ignore + - essentials.itemdb + - essentials.kit + - essentials.kits.tools + - essentials.mail + - essentials.mail.send + - essentials.me + - essentials.msg + - essentials.msg.color + - essentials.msg.format + - essentials.nick + - essentials.pay + - essentials.ping + - essentials.powertool + - essentials.powertooltoggle + - essentials.protect + - essentials.recipe + - essentials.seen + - essentials.sethome + - essentials.sethome.bed + - essentials.sethome.multiple + - essentials.signs.use.* + - essentials.signs.create.disposal + - essentials.signs.create.mail + - essentials.signs.create.protection + - essentials.signs.create.trade + - essentials.signs.break.disposal + - essentials.signs.break.mail + - essentials.signs.break.protection + - essentials.signs.break.trade + - essentials.suicide + - essentials.time + - essentials.tpa + - essentials.tpaccept + - essentials.tpahere + - essentials.tpdeny + - essentials.warp + - essentials.warp.list + - essentials.worth + - essentials.jail.allow.mail + - essentials.jail.allow.ping + - essentials.jail.allow.seen + + g:essentials_moderator: + permissions: + - -essentials.spawner.enderdragon + - essentials.afk.kickexempt + - essentials.ban + - essentials.ban.notify + - essentials.banip + - essentials.book.title + - essentials.book.others + - essentials.broadcast + - essentials.chat.url + - essentials.chat.magic + - essentials.clearinventory + - essentials.delwarp + - essentials.eco.loan + - essentials.exp.others + - essentials.ext + - essentials.fly + - essentials.fly.safelogin + - essentials.getpos + - essentials.getpos.others + - essentials.helpop.receive + - essentials.home.others + - essentials.invsee + - essentials.jails + - essentials.jump + - essentials.kick + - essentials.kick.notify + - essentials.kill + - essentials.kits.* + - essentials.msg.magic + - essentials.mute + - essentials.mute.notify + - essentials.nick.color + - essentials.nick.others + - essentials.realname + - essentials.seen.banreason + - essentials.seen.extra + - essentials.setwarp + - essentials.signs.create.* + - essentials.signs.break.* + - essentials.spawner + - essentials.spawner.* + - essentials.thunder + - essentials.time + - essentials.time.set + - essentials.protect.alerts + - essentials.protect.admin + - essentials.protect.ownerinfo + - essentials.ptime + - essentials.ptime.others + - essentials.togglejail + - essentials.top + - essentials.tp + - essentials.tp.others + - essentials.tphere + - essentials.tppos + - essentials.tptoggle + - essentials.unban + - essentials.unbanip + - essentials.vanish + - essentials.vanish.effect + - essentials.warps.* + - essentials.weather + - essentials.whois + - essentials.workbench + - essentials.world + - essentials.worlds.* + - essentials.jail.allow.jails + - essentials.jail.allow.togglejail + + g:essentials_admin: + permissions: + - -essentials.backup + - -essentials.essentials + - -essentials.setspawn + - -essentials.reloadall + - -essentials.plugin + - essentials.* + +# Permission nodes for Towny by ElgarL +# http://dev.bukkit.org/server-mods/towny-advanced/ + + g:towny_default: + permissions: + - towny.chat.local + + g:towny_builder: + permissions: + - towny.wild.build.6 + - towny.wild.destroy.6 + - towny.wild.destroy.14 + - towny.wild.destroy.15 + - towny.wild.destroy.16 + - towny.wild.build.17 + - towny.wild.destroy.17 + - towny.wild.destroy.18 + - towny.wild.destroy.21 + - towny.wild.destroy.31 + - towny.wild.destroy.37 + - towny.wild.destroy.38 + - towny.wild.destroy.39 + - towny.wild.destroy.40 + - towny.wild.destroy.50 + - towny.wild.destroy.56 + - towny.wild.destroy.73 + - towny.wild.destroy.74 + - towny.wild.destroy.78 + - towny.wild.destroy.81 + - towny.wild.destroy.82 + - towny.wild.destroy.83 + - towny.wild.destroy.86 + - towny.wild.destroy.103 + - towny.wild.destroy.106 + - towny.wild.destroy.111 + - towny.wild.destroy.115 + + g:towny_moderator: + permissions: + - towny.chat.mod + - towny.wild.switch.64 + - towny.wild.build.83 + - towny.wild.build.86 + - towny.wild.build.103 + - towny.wild.build.111 + - towny.wild.build.115 + + g:towny_admin: + permissions: + - towny.admin + - -towny.wild.destroy.119 + - -towny.wild.destroy.120 + - towny.chat.admin + +# Permission nodes for VanishNoPacket by mbaxter +# http://dev.bukkit.org/server-mods/vanish/ + + g:vanish_moderator: + permissions: + - -vanish.* + - vanish.vanish + - vanish.smokin + - vanish.nofollow + - vanish.nopickup + - vanish.preventincomingdamage + - vanish.hooks.dynmap.alwayshidden + - vanish.hooks.essentials.hide + + g:vanish_admin: + permissions: + - vanish.silentjoin + - vanish.silentquit + - vanish.silentchests \ No newline at end of file diff --git a/EssentialsGroupManager/src/groups.yml b/EssentialsGroupManager/src/groups.yml new file mode 100644 index 0000000000..9c63ffd94c --- /dev/null +++ b/EssentialsGroupManager/src/groups.yml @@ -0,0 +1,74 @@ +# Group inheritance +# +# Any inherited groups prefixed with a g: are global groups +# and are inherited from the GlobalGroups.yml. +# +# Groups without the g: prefix are groups local to this world +# and are defined in the this groups.yml file. +# +# Local group inheritances define your promotion tree when using 'manpromote/mandemote' + +groups: + Default: + default: true + permissions: + - -bukkit.command.kill + inheritance: + - g:groupmanager_default + - g:bukkit_default + - g:essentials_default + - g:towny_default + info: + prefix: '&e' + build: false + suffix: '' + Builder: + default: false + permissions: [] + inheritance: + - default + - g:essentials_builder + - g:towny_builder + info: + prefix: '&2' + build: true + suffix: '' + Moderator: + default: false + permissions: [] + inheritance: + - builder + - g:groupmanager_moderator + - g:bukkit_moderator + - g:essentials_moderator + - g:towny_moderator + - g:vanish_moderator + info: + prefix: '&5' + build: true + suffix: '' + Admin: + default: false + permissions: [] + inheritance: + - moderator + - g:groupmanager_admin + - g:bukkit_admin + - g:essentials_admin + - g:towny_admin + - g:vanish_admin + info: + prefix: '&c' + build: true + suffix: '' + Owner: + default: false + permissions: + - '*' + - -vanish.* + inheritance: + - admin + info: + prefix: '&4' + build: true + suffix: '' diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/GMConfiguration.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/GMConfiguration.java new file mode 100644 index 0000000000..a340482b06 --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/GMConfiguration.java @@ -0,0 +1,210 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.anjocaido.groupmanager; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; + +import org.anjocaido.groupmanager.utils.Tasks; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.SafeConstructor; +import org.yaml.snakeyaml.reader.UnicodeReader; + +/** + * + * @author gabrielcouto + */ +public class GMConfiguration { + + private boolean allowCommandBlocks = false; + private boolean opOverride = true; + private boolean toggleValidate = true; + private Integer saveInterval = 10; + private Integer backupDuration = 24; + private String loggerLevel = "OFF"; + private Map mirrorsMap; + + + private GroupManager plugin; + private Map GMconfig; + + public GMConfiguration(GroupManager plugin) { + + this.plugin = plugin; + + /* + * Set defaults + */ + allowCommandBlocks = false; + opOverride = true; + toggleValidate = true; + saveInterval = 10; + backupDuration = 24; + loggerLevel = "OFF"; + + load(); + } + + @SuppressWarnings("unchecked") + public void load() { + + if (!plugin.getDataFolder().exists()) { + plugin.getDataFolder().mkdirs(); + } + + File configFile = new File(plugin.getDataFolder(), "config.yml"); + + if (!configFile.exists()) { + try { + Tasks.copy(plugin.getResourceAsStream("config.yml"), configFile); + } catch (IOException ex) { + GroupManager.logger.log(Level.SEVERE, "Error creating a new config.yml", ex); + } + } + + Yaml configYAML = new Yaml(new SafeConstructor()); + + try { + FileInputStream configInputStream = new FileInputStream(configFile); + GMconfig = (Map) configYAML.load(new UnicodeReader(configInputStream)); + configInputStream.close(); + + } catch (Exception ex) { + throw new IllegalArgumentException("The following file couldn't pass on Parser.\n" + configFile.getPath(), ex); + } + + /* + * Read our config settings and store them for reading later. + */ + try { + Map config = getElement("config", getElement("settings", GMconfig)); + + try { + allowCommandBlocks = (Boolean) config.get("allow_commandblocks"); + } catch (Exception ex) { + GroupManager.logger.log(Level.SEVERE, "Missing or corrupt 'allow_commandblocks' node. Using default settings", ex); + } + + try { + opOverride = (Boolean) config.get("opOverrides"); + } catch (Exception ex) { + GroupManager.logger.log(Level.SEVERE, "Missing or corrupt 'opOverrides' node. Using default settings", ex); + } + + try { + toggleValidate = (Boolean) config.get("validate_toggle"); + } catch (Exception ex) { + GroupManager.logger.log(Level.SEVERE, "Missing or corrupt 'validate_toggle' node. Using default settings", ex); + } + + /* + * data node for save/backup timers. + */ + try { + Map save = getElement("save", getElement("data", getElement("settings", GMconfig))); + + try { + saveInterval = (Integer) save.get("minutes"); + } catch (Exception ex) { + GroupManager.logger.log(Level.SEVERE, "Missing or corrupt 'minutes' node. Using default setting", ex); + } + + try { + backupDuration = (Integer) save.get("hours"); + } catch (Exception ex) { + GroupManager.logger.log(Level.SEVERE, "Missing or corrupt 'hours' node. Using default setting", ex); + } + + } catch (Exception ex) { + GroupManager.logger.log(Level.SEVERE, "Missing or corrupt 'data' node. Using default settings", ex); + } + + + + Object level = ((Map) getElement("settings", GMconfig).get("logging")).get("level"); + if (level instanceof String) + loggerLevel = (String) level; + + /* + * Store our mirrors map for parsing later. + */ + mirrorsMap = (Map) ((Map) GMconfig.get("settings")).get("mirrors"); + + if (mirrorsMap == null) + throw new Exception(); + + } catch (Exception ex) { + /* + * Flag the error and use defaults + */ + GroupManager.logger.log(Level.SEVERE, "There are errors in your config.yml. Using default settings", ex); + + mirrorsMap = new HashMap(); + } + // Setup defaults + adjustLoggerLevel(); + plugin.setValidateOnlinePlayer(isToggleValidate()); + } + + @SuppressWarnings("unchecked") + private Map getElement(String element, Map map) { + + if (!map.containsKey(element)) { + throw new IllegalArgumentException("The config.yml has no '" + element + ".\n"); + } + + return (Map) map.get(element); + + } + public boolean isAllowCommandBlocks() { + + return allowCommandBlocks; + } + + public boolean isOpOverride() { + + return opOverride; + } + + public boolean isToggleValidate() { + + return toggleValidate; + } + + public Integer getSaveInterval() { + + return saveInterval; + } + + public Integer getBackupDuration() { + + return backupDuration; + } + + public void adjustLoggerLevel() { + + try { + GroupManager.logger.setLevel(Level.parse(loggerLevel)); + return; + } catch (Exception e) { + } + + GroupManager.logger.setLevel(Level.INFO); + } + + public Map getMirrorsMap() { + + if (!mirrorsMap.isEmpty()) { + return mirrorsMap; + } + return null; + + } + +} diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/GlobalGroups.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/GlobalGroups.java new file mode 100644 index 0000000000..ea0e5bc7cd --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/GlobalGroups.java @@ -0,0 +1,480 @@ +package org.anjocaido.groupmanager; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; + +import org.anjocaido.groupmanager.data.Group; +import org.anjocaido.groupmanager.events.GMGroupEvent; +import org.anjocaido.groupmanager.utils.PermissionCheckResult; +import org.anjocaido.groupmanager.utils.Tasks; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.SafeConstructor; +import org.yaml.snakeyaml.reader.UnicodeReader; + +/** + * @author ElgarL + * + */ +public class GlobalGroups { + + private GroupManager plugin; + //private Yaml GGroups; + + private final Map groups = Collections.synchronizedMap(new HashMap()); + + protected long timeStampGroups = 0; + protected boolean haveGroupsChanged = false; + protected File GlobalGroupsFile = null; + + public GlobalGroups(GroupManager plugin) { + + this.plugin = plugin; + load(); + } + + /** + * @return the haveGroupsChanged + */ + public boolean haveGroupsChanged() { + + if (this.haveGroupsChanged) { + return true; + } + synchronized(groups) { + for (Group g : groups.values()) { + if (g.isChanged()) { + return true; + } + } + } + return false; + } + + /** + * @return the timeStampGroups + */ + public long getTimeStampGroups() { + + return timeStampGroups; + } + + /** + * @param timeStampGroups the timeStampGroups to set + */ + protected void setTimeStampGroups(long timeStampGroups) { + + this.timeStampGroups = timeStampGroups; + } + + /** + * @param haveGroupsChanged + * the haveGroupsChanged to set + */ + public void setGroupsChanged(boolean haveGroupsChanged) { + + this.haveGroupsChanged = haveGroupsChanged; + } + + @SuppressWarnings("unchecked") + public void load() { + + Yaml GGroupYAML = new Yaml(new SafeConstructor()); + Map GGroups; + + GroupManager.setLoaded(false); + + // READ globalGroups FILE + if (GlobalGroupsFile == null) + GlobalGroupsFile = new File(plugin.getDataFolder(), "globalgroups.yml"); + + if (!GlobalGroupsFile.exists()) { + try { + // Create a new file if it doesn't exist. + Tasks.copy(plugin.getResourceAsStream("globalgroups.yml"), GlobalGroupsFile); + } catch (IOException ex) { + GroupManager.logger.log(Level.SEVERE, null, ex); + } + } + + /* + * Load the YAML file. + */ + try { + FileInputStream groupsInputStream = new FileInputStream(GlobalGroupsFile); + GGroups = (Map) GGroupYAML.load(new UnicodeReader(groupsInputStream)); + groupsInputStream.close(); + } catch (Exception ex) { + throw new IllegalArgumentException("The following file couldn't pass on Parser.\n" + GlobalGroupsFile.getPath(), ex); + } + + // Clear out old groups + resetGlobalGroups(); + + if (!GGroups.keySet().isEmpty()) { + // Read all global groups + Map allGroups = new HashMap(); + + try { + allGroups = (Map) GGroups.get("groups"); + } catch (Exception ex) { + // ex.printStackTrace(); + throw new IllegalArgumentException("Your " + GlobalGroupsFile.getPath() + " file is invalid. See console for details.", ex); + } + + // Load each groups permissions list. + if (allGroups != null) { + + Iterator groupItr = allGroups.keySet().iterator(); + String groupName; + Integer groupCount = 0; + + /* + * loop each group entry + * and read it's data. + */ + while (groupItr.hasNext()) { + try { + groupCount++; + // Attempt to fetch the next group name. + groupName = groupItr.next(); + } catch (Exception ex) { + throw new IllegalArgumentException("Invalid group name for GlobalGroup entry (" + groupCount + ") in file: " + GlobalGroupsFile.getPath(), ex); + } + + /* + * Create a new group with this name. + */ + Group newGroup = new Group(groupName.toLowerCase()); + Object element; + + // Permission nodes + try { + element = ((Map)allGroups.get(groupName)).get("permissions"); + } catch ( Exception ex) { + throw new IllegalArgumentException("The GlobalGroup ' " + groupName + "' is formatted incorrectly: ", ex); + } + + if (element != null) + if (element instanceof List) { + try { + for (String node : (List) element) { + if ((node != null) && !node.isEmpty()) + newGroup.addPermission(node); + } + } catch (ClassCastException ex) { + throw new IllegalArgumentException("Invalid permission node for global group: " + groupName, ex); + } + } else if (element instanceof String) { + if ((element != null) && !((String)element).isEmpty()) + newGroup.addPermission((String) element); + } else + throw new IllegalArgumentException("Unknown type of permission node for global group: " + groupName); + +// // Info nodes +// try { +// element = ((Map)allGroups.get(groupName)).get("info"); +// } catch ( Exception ex) { +// throw new IllegalArgumentException("The GlobalGroup ' " + groupName + "' is formatted incorrectly: ", ex); +// } +// +// if (element != null) +// if (element instanceof MemorySection) { +// Map vars = new HashMap(); +// for (String key : ((MemorySection) element).getKeys(false)) { +// vars.put(key, ((MemorySection) element).get(key)); +// } +// newGroup.setVariables(vars); +// } else +// throw new IllegalArgumentException("Unknown type of info node for global group: " + groupName); + + // Push a new group + addGroup(newGroup); + } + } + + removeGroupsChangedFlag(); + } + + setTimeStampGroups(GlobalGroupsFile.lastModified()); + GroupManager.setLoaded(true); + // GlobalGroupsFile = null; + } + + /** + * Write the globalgroups.yml file + */ + + public void writeGroups(boolean overwrite) { + + // File GlobalGroupsFile = new File(plugin.getDataFolder(), "globalgroups.yml"); + + if (haveGroupsChanged()) { + if (overwrite || (!overwrite && (getTimeStampGroups() >= GlobalGroupsFile.lastModified()))) { + Map root = new HashMap(); + + Map groupsMap = new HashMap(); + root.put("groups", groupsMap); + synchronized(groups) { + for (String groupKey : groups.keySet()) { + Group group = groups.get(groupKey); + + // Group header + Map aGroupMap = new HashMap(); + groupsMap.put(group.getName(), aGroupMap); + +// // Info nodes +// Map infoMap = new HashMap(); +// aGroupMap.put("info", infoMap); +// +// for (String infoKey : group.getVariables().getVarKeyList()) { +// infoMap.put(infoKey, group.getVariables().getVarObject(infoKey)); +// } + + // Permission nodes + aGroupMap.put("permissions", group.getPermissionList()); + } + } + + if (!root.isEmpty()) { + DumperOptions opt = new DumperOptions(); + opt.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + final Yaml yaml = new Yaml(opt); + try { + yaml.dump(root, new OutputStreamWriter(new FileOutputStream(GlobalGroupsFile), "UTF-8")); + } catch (UnsupportedEncodingException ex) { + } catch (FileNotFoundException ex) { + } + } + setTimeStampGroups(GlobalGroupsFile.lastModified()); + } else { + // Newer file found. + GroupManager.logger.log(Level.WARNING, "Newer GlobalGroups file found, but we have local changes!"); + throw new IllegalStateException("Unable to save unless you issue a '/mansave force'"); + } + removeGroupsChangedFlag(); + } else { + // Check for newer file as no local changes. + if (getTimeStampGroups() < GlobalGroupsFile.lastModified()) { + System.out.print("Newer GlobalGroups file found (Loading changes)!"); + // Backup GlobalGroups file + backupFile(); + load(); + } + } + + } + + /** + * Backup the BlobalGroups file + * + * @param w + */ + private void backupFile() { + + File backupFile = new File(plugin.getBackupFolder(), "bkp_ggroups_" + Tasks.getDateString() + ".yml"); + try { + Tasks.copy(GlobalGroupsFile, backupFile); + } catch (IOException ex) { + GroupManager.logger.log(Level.SEVERE, null, ex); + } + } + + /** + * Adds a group, or replaces an existing one. + * + * @param groupToAdd + */ + public void addGroup(Group groupToAdd) { + + // Create a new group if it already exists + if (hasGroup(groupToAdd.getName())) { + groupToAdd = groupToAdd.clone(); + removeGroup(groupToAdd.getName()); + } + + newGroup(groupToAdd); + haveGroupsChanged = true; + if (GroupManager.isLoaded()) + GroupManager.getGMEventHandler().callEvent(groupToAdd, GMGroupEvent.Action.GROUP_ADDED); + } + + /** + * Creates a new group if it doesn't already exist. + * + * @param newGroup + */ + public Group newGroup(Group newGroup) { + + // Push a new group + if (!groups.containsKey(newGroup.getName().toLowerCase())) { + groups.put(newGroup.getName().toLowerCase(), newGroup); + this.setGroupsChanged(true); + return newGroup; + } + return null; + } + + /** + * Delete a group if it exist. + * + * @param groupName + */ + public boolean removeGroup(String groupName) { + + // Push a new group + if (groups.containsKey(groupName.toLowerCase())) { + groups.remove(groupName.toLowerCase()); + this.setGroupsChanged(true); + if (GroupManager.isLoaded()) + GroupManager.getGMEventHandler().callEvent(groupName.toLowerCase(), GMGroupEvent.Action.GROUP_REMOVED); + return true; + } + return false; + } + + /** + * Returns true if the Global Group exists in the globalgroups.yml + * + * @param groupName + * @return true if the group exists + */ + public boolean hasGroup(String groupName) { + + return groups.containsKey(groupName.toLowerCase()); + } + + /** + * Returns true if the group has the correct permission node. + * + * @param groupName + * @param permissionNode + * @return true if node exists + */ + public boolean hasPermission(String groupName, String permissionNode) { + + if (!hasGroup(groupName)) + return false; + + return groups.get(groupName.toLowerCase()).hasSamePermissionNode(permissionNode); + + } + + /** + * Returns a PermissionCheckResult of the permission node for the group to + * be tested against. + * + * @param groupName + * @param permissionNode + * @return PermissionCheckResult object + */ + public PermissionCheckResult checkPermission(String groupName, String permissionNode) { + + PermissionCheckResult result = new PermissionCheckResult(); + result.askedPermission = permissionNode; + result.resultType = PermissionCheckResult.Type.NOTFOUND; + + if (!hasGroup(groupName)) + return result; + + Group tempGroup = groups.get(groupName.toLowerCase()); + + if (tempGroup.hasSamePermissionNode(permissionNode)) + result.resultType = PermissionCheckResult.Type.FOUND; + if (tempGroup.hasSamePermissionNode("-" + permissionNode)) + result.resultType = PermissionCheckResult.Type.NEGATION; + if (tempGroup.hasSamePermissionNode("+" + permissionNode)) + result.resultType = PermissionCheckResult.Type.EXCEPTION; + + return result; + } + + /** + * Returns a List of all permission nodes for this group null if none + * + * @param groupName + * @return List of all group names + */ + public List getGroupsPermissions(String groupName) { + + if (!hasGroup(groupName)) + return null; + + return groups.get(groupName.toLowerCase()).getPermissionList(); + } + + /** + * Returns a Set of all global group names. + * + * @return Set containing all group names. + */ + /*public Set getGlobalGroups() { + + return groups.keySet(); + }*/ + + /** + * Resets GlobalGroups. + */ + public void resetGlobalGroups() { + this.groups.clear(); + } + + /** + * + * @return a collection of the groups + */ + public Group[] getGroupList() { + synchronized(groups) { + return groups.values().toArray(new Group[0]); + } + } + + /** + * Returns the Global Group or null if it doesn't exist. + * + * @param groupName + * @return Group object + */ + public Group getGroup(String groupName) { + + if (!hasGroup(groupName)) + return null; + + return groups.get(groupName.toLowerCase()); + + } + + /** + * @return the globalGroupsFile + */ + public File getGlobalGroupsFile() { + + return GlobalGroupsFile; + } + + /** + * + */ + public void removeGroupsChangedFlag() { + + setGroupsChanged(false); + synchronized(groups) { + for (Group g : groups.values()) { + g.flagAsSaved(); + } + } + } + +} \ No newline at end of file diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/GroupManager.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/GroupManager.java new file mode 100644 index 0000000000..81eb3064fc --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/GroupManager.java @@ -0,0 +1,2257 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.anjocaido.groupmanager; + +import org.anjocaido.groupmanager.permissions.AnjoPermissionsHandler; +import org.anjocaido.groupmanager.permissions.BukkitPermissions; +import org.anjocaido.groupmanager.utils.GroupManagerPermissions; +import org.anjocaido.groupmanager.Tasks.BukkitPermsUpdateTask; +import org.anjocaido.groupmanager.data.Variables; +import org.anjocaido.groupmanager.data.User; +import org.anjocaido.groupmanager.data.Group; +import org.anjocaido.groupmanager.dataholder.OverloadedWorldHolder; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.anjocaido.groupmanager.dataholder.worlds.WorldsHolder; +import org.anjocaido.groupmanager.events.GMSystemEvent; +import org.anjocaido.groupmanager.events.GMWorldListener; +import org.anjocaido.groupmanager.events.GroupManagerEventHandler; +import org.anjocaido.groupmanager.utils.GMLoggerHandler; +import org.anjocaido.groupmanager.utils.PermissionCheckResult; +import org.anjocaido.groupmanager.utils.Tasks; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.OfflinePlayer; +import org.bukkit.block.Block; +import org.bukkit.command.BlockCommandSender; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.plugin.PluginDescriptionFile; +import org.bukkit.plugin.ServicePriority; +import org.bukkit.plugin.java.JavaPlugin; + + +/** + * + * @author gabrielcouto, ElgarL + */ +public class GroupManager extends JavaPlugin { + + private File backupFolder; + private Runnable commiter; + private ScheduledThreadPoolExecutor scheduler; + private Map> overloadedUsers = new HashMap>(); + private Map selectedWorlds = new HashMap(); + private WorldsHolder worldsHolder; + private boolean validateOnlinePlayer = true; + + private static boolean isLoaded = false; + protected GMConfiguration config; + + protected static GlobalGroups globalGroups; + + private GMLoggerHandler ch; + + private static GroupManagerEventHandler GMEventHandler; + public static BukkitPermissions BukkitPermissions; + private static GMWorldListener WorldEvents; + public static final Logger logger = Logger.getLogger(GroupManager.class.getName()); + + // PERMISSIONS FOR COMMAND BEING LOADED + private OverloadedWorldHolder dataHolder = null; + private AnjoPermissionsHandler permissionHandler = null; + + private String lastError = ""; + + @Override + public void onDisable() { + + onDisable(false); + } + + @Override + public void onEnable() { + /* + * Initialize the event handler + */ + setGMEventHandler(new GroupManagerEventHandler(this)); + onEnable(false); + } + + public void onDisable(boolean restarting) { + + setLoaded(false); + + if (!restarting) { + // Unregister this service if we are shutting down. + this.getServer().getServicesManager().unregister(this.worldsHolder); + } + + disableScheduler(); // Shutdown before we save, so it doesn't interfere. + if (worldsHolder != null) { + try { + worldsHolder.saveChanges(false); + } catch (IllegalStateException ex) { + GroupManager.logger.log(Level.WARNING, ex.getMessage()); + } + } + + + + // Remove all attachments before clearing + if (BukkitPermissions != null) { + BukkitPermissions.removeAllAttachments(); + } + + if (!restarting) { + + if (WorldEvents != null) + WorldEvents = null; + + BukkitPermissions = null; + + } + + // EXAMPLE: Custom code, here we just output some info so we can check that all is well + PluginDescriptionFile pdfFile = this.getDescription(); + System.out.println(pdfFile.getName() + " version " + pdfFile.getVersion() + " is disabled!"); + + if (!restarting) + GroupManager.logger.removeHandler(ch); + } + + public void onEnable(boolean restarting) { + + try { + /* + * reset local variables. + */ + overloadedUsers = new HashMap>(); + selectedWorlds = new HashMap(); + lastError = ""; + + /* + * Setup our logger if we are not restarting. + */ + if (!restarting) { + GroupManager.logger.setUseParentHandlers(false); + ch = new GMLoggerHandler(); + GroupManager.logger.addHandler(ch); + } + GroupManager.logger.setLevel(Level.ALL); + + // Create the backup folder, if it doesn't exist. + prepareFileFields(); + // Load the config.yml + prepareConfig(); + // Load the global groups + globalGroups = new GlobalGroups(this); + + /* + * Configure the worlds holder. + */ + if (!restarting) + worldsHolder = new WorldsHolder(this); + else + worldsHolder.resetWorldsHolder(); + + /* + * This should NEVER happen. No idea why it's still here. + */ + PluginDescriptionFile pdfFile = this.getDescription(); + if (worldsHolder == null) { + GroupManager.logger.severe("Can't enable " + pdfFile.getName() + " version " + pdfFile.getVersion() + ", bad loading!"); + this.getServer().getPluginManager().disablePlugin(this); + throw new IllegalStateException("An error ocurred while loading GroupManager"); + } + + /* + * Prevent our registered events from triggering + * updates as we are not fully loaded. + */ + setLoaded(false); + + /* + * Initialize the world listener and bukkit permissions + * to handle events if this is a fresh start + * + * else + * + * Reset bukkit perms. + */ + if (!restarting) { + WorldEvents = new GMWorldListener(this); + BukkitPermissions = new BukkitPermissions(this); + } else { + BukkitPermissions.reset(); + } + + /* + * Start the scheduler for data saving. + */ + enableScheduler(); + + /* + * Schedule a Bukkit Permissions update for 1 tick later. + * All plugins will be loaded by then + */ + + if (getServer().getScheduler().scheduleSyncDelayedTask(this, new BukkitPermsUpdateTask(), 1) == -1) { + GroupManager.logger.severe("Could not schedule superperms Update."); + /* + * Flag that we are now loaded and should start processing events. + */ + setLoaded(true); + } + + System.out.println(pdfFile.getName() + " version " + pdfFile.getVersion() + " is enabled!"); + + // Register as a service + if (!restarting) + this.getServer().getServicesManager().register(WorldsHolder.class, this.worldsHolder, this, ServicePriority.Lowest); + + } catch (Exception ex) { + + /* + * Store the error and write to the log. + */ + saveErrorLog(ex); + + /* + * Throw an error so Bukkit knows about it. + */ + throw new IllegalArgumentException(ex.getMessage(), ex); + + } + } + + /** + * Write an error.log + * + * @param ex + */ + private void saveErrorLog(Exception ex) { + + if (!getDataFolder().exists()) { + getDataFolder().mkdirs(); + } + + lastError = ex.getMessage(); + + GroupManager.logger.severe("==================================================="); + GroupManager.logger.severe("= ERROR REPORT START - " + this.getDescription().getVersion() + " ="); + GroupManager.logger.severe("==================================================="); + GroupManager.logger.severe("=== PLEASE COPY AND PASTE THE ERROR.LOG FROM THE =="); + GroupManager.logger.severe("= GROUPMANAGER FOLDER TO AN ESSENTIALS DEVELOPER ="); + GroupManager.logger.severe("==================================================="); + GroupManager.logger.severe(lastError); + GroupManager.logger.severe("==================================================="); + GroupManager.logger.severe("= ERROR REPORT ENDED ="); + GroupManager.logger.severe("==================================================="); + + // Append this error to the error log. + try { + String error = "=============================== GM ERROR LOG ===============================\n"; + error += "= ERROR REPORT START - " + this.getDescription().getVersion() + " =\n\n"; + + error += Tasks.getStackTraceAsString(ex); + error += "\n============================================================================\n"; + + Tasks.appendStringToFile(error, (getDataFolder() + System.getProperty("file.separator") + "ERROR.LOG")); + } catch (IOException e) { + // Failed to write file. + e.printStackTrace(); + } + + } + + /** + * @return the validateOnlinePlayer + */ + public boolean isValidateOnlinePlayer() { + + return validateOnlinePlayer; + } + + /** + * @param validateOnlinePlayer the validateOnlinePlayer to set + */ + public void setValidateOnlinePlayer(boolean validateOnlinePlayer) { + + this.validateOnlinePlayer = validateOnlinePlayer; + } + + public static boolean isLoaded() { + + return isLoaded; + } + + public static void setLoaded(boolean isLoaded) { + + GroupManager.isLoaded = isLoaded; + } + + public InputStream getResourceAsStream(String fileName) { + + return this.getClassLoader().getResourceAsStream(fileName); + } + + private void prepareFileFields() { + + backupFolder = new File(this.getDataFolder(), "backup"); + if (!backupFolder.exists()) { + getBackupFolder().mkdirs(); + } + } + + private void prepareConfig() { + + config = new GMConfiguration(this); + } + + public void enableScheduler() { + + if (worldsHolder != null) { + disableScheduler(); + commiter = new Runnable() { + + @Override + public void run() { + + try { + if (worldsHolder.saveChanges(false)) + GroupManager.logger.log(Level.INFO, " Data files refreshed."); + } catch (IllegalStateException ex) { + GroupManager.logger.log(Level.WARNING, ex.getMessage()); + } + } + }; + scheduler = new ScheduledThreadPoolExecutor(1); + long minutes = (long) getGMConfig().getSaveInterval(); + if (minutes > 0) { + scheduler.scheduleAtFixedRate(commiter, minutes, minutes, TimeUnit.MINUTES); + GroupManager.logger.info("Scheduled Data Saving is set for every " + minutes + " minutes!"); + } else + GroupManager.logger.info("Scheduled Data Saving is Disabled!"); + + GroupManager.logger.info("Backups will be retained for " + getGMConfig().getBackupDuration() + " hours!"); + } + } + + public void disableScheduler() { + + if (scheduler != null) { + try { + scheduler.setContinueExistingPeriodicTasksAfterShutdownPolicy(false); + scheduler.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); + scheduler.shutdown(); + } catch (Exception e) { + } + scheduler = null; + GroupManager.logger.info("Scheduled Data Saving is disabled!"); + } + } + + public WorldsHolder getWorldsHolder() { + + return worldsHolder; + } + + /** + * Called when a command registered by this plugin is received. + * + * @param sender + * @param cmd + * @param args + */ + @Override + public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) { + + boolean playerCanDo = false; + boolean isConsole = false; + Player senderPlayer = null, targetPlayer = null; + Group senderGroup = null; + User senderUser = null; + boolean isOpOverride = config.isOpOverride(); + boolean isAllowCommandBlocks = config.isAllowCommandBlocks(); + + // PREVENT GM COMMANDS BEING USED ON COMMANDBLOCKS + if (sender instanceof BlockCommandSender && !isAllowCommandBlocks) { + Block block = ((BlockCommandSender)sender).getBlock(); + GroupManager.logger.warning(ChatColor.RED + "GM Commands can not be called from CommandBlocks"); + GroupManager.logger.warning(ChatColor.RED + "Location: " + ChatColor.GREEN + block.getWorld().getName() + ", " + block.getX() + ", " + block.getY() + ", " + block.getZ()); + return true; + } + + // DETERMINING PLAYER INFORMATION + if (sender instanceof Player) { + senderPlayer = (Player) sender; + + if (!lastError.isEmpty() && !commandLabel.equalsIgnoreCase("manload")) { + sender.sendMessage(ChatColor.RED + "All commands are locked due to an error. " + ChatColor.BOLD + "" + ChatColor.UNDERLINE + "Check plugins/groupmanager/error.log or console" + ChatColor.RESET + "" + ChatColor.RED + " and then try a '/manload'."); + return true; + } + + senderUser = worldsHolder.getWorldData(senderPlayer).getUser(senderPlayer.getName()); + senderGroup = senderUser.getGroup(); + isOpOverride = (isOpOverride && (senderPlayer.isOp() || worldsHolder.getWorldPermissions(senderPlayer).has(senderPlayer, "groupmanager.op"))); + + if (isOpOverride || worldsHolder.getWorldPermissions(senderPlayer).has(senderPlayer, "groupmanager." + cmd.getName())) { + playerCanDo = true; + } + } else { + + if (!lastError.isEmpty() && !commandLabel.equalsIgnoreCase("manload")) { + sender.sendMessage(ChatColor.RED + "All commands are locked due to an error. " + ChatColor.BOLD + "" + ChatColor.UNDERLINE + "Check plugins/groupmanager/error.log or console" + ChatColor.RESET + "" + ChatColor.RED + " and then try a '/manload'."); + return true; + } + + isConsole = true; + } + + // PERMISSIONS FOR COMMAND BEING LOADED + dataHolder = null; + permissionHandler = null; + + if (senderPlayer != null) { + dataHolder = worldsHolder.getWorldData(senderPlayer); + } + + String selectedWorld = selectedWorlds.get(sender.getName()); + if (selectedWorld != null) { + dataHolder = worldsHolder.getWorldData(selectedWorld); + } + + if (dataHolder != null) { + permissionHandler = dataHolder.getPermissionsHandler(); + } + + // VARIABLES USED IN COMMANDS + + int count; + PermissionCheckResult permissionResult = null; + ArrayList removeList = null; + String auxString = null; + List match = null; + User auxUser = null; + Group auxGroup = null; + Group auxGroup2 = null; + + GroupManagerPermissions execCmd = null; + try { + execCmd = GroupManagerPermissions.valueOf(cmd.getName()); + } catch (Exception e) { + // this error happened once with someone. now im prepared... i think + GroupManager.logger.severe("==================================================="); + GroupManager.logger.severe("= ERROR REPORT START ="); + GroupManager.logger.severe("==================================================="); + GroupManager.logger.severe("= COPY AND PASTE THIS TO A GROUPMANAGER DEVELOPER ="); + GroupManager.logger.severe("==================================================="); + GroupManager.logger.severe(this.getDescription().getName()); + GroupManager.logger.severe(this.getDescription().getVersion()); + GroupManager.logger.severe("An error occured while trying to execute command:"); + GroupManager.logger.severe(cmd.getName()); + GroupManager.logger.severe("With " + args.length + " arguments:"); + for (String ar : args) { + GroupManager.logger.severe(ar); + } + GroupManager.logger.severe("The field '" + cmd.getName() + "' was not found in enum."); + GroupManager.logger.severe("And could not be parsed."); + GroupManager.logger.severe("FIELDS FOUND IN ENUM:"); + for (GroupManagerPermissions val : GroupManagerPermissions.values()) { + GroupManager.logger.severe(val.name()); + } + GroupManager.logger.severe("==================================================="); + GroupManager.logger.severe("= ERROR REPORT ENDED ="); + GroupManager.logger.severe("==================================================="); + sender.sendMessage("An error occurred. Ask the admin to take a look at the console."); + } + + if (isConsole || playerCanDo) { + switch (execCmd) { + case manuadd: + + // Validating arguments + if ((args.length != 2) && (args.length != 3)) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/manuadd | optional [world])"); + return true; + } + + // Select the relevant world (if specified) + if (args.length == 3) { + dataHolder = worldsHolder.getWorldData(args[2]); + permissionHandler = dataHolder.getPermissionsHandler(); + } + + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + + if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) { + return false; + } + + if (match != null) { + auxUser = dataHolder.getUser(match.get(0)); + } else { + auxUser = dataHolder.getUser(args[0]); + } + auxGroup = dataHolder.getGroup(args[1]); + if (auxGroup == null) { + sender.sendMessage(ChatColor.RED + "'" + args[1] + "' Group doesnt exist!"); + return false; + } + if (auxGroup.isGlobal()) { + sender.sendMessage(ChatColor.RED + "Players may not be members of GlobalGroups directly."); + return false; + } + + // Validating permissions + if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getLastName(), senderGroup.getName()) : false)) { + sender.sendMessage(ChatColor.RED + "Can't modify a player with the same permissions as you, or higher."); + return true; + } + if (!isConsole && !isOpOverride && (permissionHandler.hasGroupInInheritance(auxGroup, senderGroup.getName()))) { + sender.sendMessage(ChatColor.RED + "The destination group can't be the same as yours, or higher."); + return true; + } + if (!isConsole && !isOpOverride && (!permissionHandler.inGroup(senderUser.getLastName(), auxUser.getGroupName()) || !permissionHandler.inGroup(senderUser.getLastName(), auxGroup.getName()))) { + sender.sendMessage(ChatColor.RED + "You can't modify a player involving a group that you don't inherit."); + return true; + } + + // Seems OK + auxUser.setGroup(auxGroup); + if (!sender.hasPermission("groupmanager.notify.other") || (isConsole)) + sender.sendMessage(ChatColor.YELLOW + "You changed player '" + auxUser.getLastName() + "' group to '" + auxGroup.getName() + "' in world '" + dataHolder.getName() + "'."); + + return true; + + case manudel: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length != 1) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/manudel )"); + return true; + } + if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) { + return false; + } + + if (match != null) { + auxUser = dataHolder.getUser(match.get(0)); + } else { + auxUser = dataHolder.getUser(args[0]); + } + // Validating permission + if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getLastName(), senderGroup.getName()) : false)) { + sender.sendMessage(ChatColor.RED + "You can't modify a player with same permissions as you, or higher."); + return true; + } + // Seems OK + dataHolder.removeUser(auxUser.getLastName()); + sender.sendMessage(ChatColor.YELLOW + "You changed player '" + auxUser.getLastName() + "' to default settings."); + + // If the player is online, this will create new data for the user. + targetPlayer = this.getServer().getPlayer(auxUser.getLastName()); + if (targetPlayer != null) + BukkitPermissions.updatePermissions(targetPlayer); + + return true; + + case manuaddsub: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) { + sender.sendMessage(ChatColor.RED + "Couldn't retrieve your world. World selection is needed."); + sender.sendMessage(ChatColor.RED + "Use /manselect "); + return true; + } + } + // Validating arguments + if (args.length != 2) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/manuaddsub )"); + return true; + } + if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) { + return false; + } + + if (match != null) { + auxUser = dataHolder.getUser(match.get(0)); + } else { + auxUser = dataHolder.getUser(args[0]); + } + auxGroup = dataHolder.getGroup(args[1]); + if (auxGroup == null) { + sender.sendMessage(ChatColor.RED + "'" + args[1] + "' Group doesnt exist!"); + return true; + } + // Validating permission + if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getLastName(), senderGroup.getName()) : false)) { + sender.sendMessage(ChatColor.RED + "You can't modify a player with same permissions as you, or higher."); + return true; + } + if (!isConsole && !isOpOverride && (permissionHandler.hasGroupInInheritance(auxGroup, senderGroup.getName()))) { + sender.sendMessage(ChatColor.RED + "The sub-group can't be the same as yours, or higher."); + return true; + } + if (!isConsole && !isOpOverride && (!permissionHandler.inGroup(senderUser.getLastName(), auxUser.getGroupName()) || !permissionHandler.inGroup(senderUser.getLastName(), auxGroup.getName()))) { + sender.sendMessage(ChatColor.RED + "You can't modify a player involving a group that you don't inherit."); + return true; + } + // Seems OK + if (auxUser.addSubGroup(auxGroup)) + sender.sendMessage(ChatColor.YELLOW + "You added subgroup '" + auxGroup.getName() + "' to player '" + auxUser.getLastName() + "'."); + else + sender.sendMessage(ChatColor.RED + "The subgroup '" + auxGroup.getName() + "' is already available to '" + auxUser.getLastName() + "'."); + + return true; + + case manudelsub: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length != 2) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/manudelsub )"); + return true; + } + if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) { + return false; + } + + if (match != null) { + auxUser = dataHolder.getUser(match.get(0)); + } else { + auxUser = dataHolder.getUser(args[0]); + } + auxGroup = dataHolder.getGroup(args[1]); + if (auxGroup == null) { + sender.sendMessage(ChatColor.RED + "'" + args[1] + "' Group doesnt exist!"); + return true; + } + + // Validating permission + if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getLastName(), senderGroup.getName()) : false)) { + sender.sendMessage(ChatColor.RED + "You can't modify a player with same permissions as you, or higher."); + return true; + } + // Seems OK + auxUser.removeSubGroup(auxGroup); + sender.sendMessage(ChatColor.YELLOW + "You removed subgroup '" + auxGroup.getName() + "' from player '" + auxUser.getLastName() + "' list."); + + // targetPlayer = this.getServer().getPlayer(auxUser.getName()); + // if (targetPlayer != null) + // BukkitPermissions.updatePermissions(targetPlayer); + + return true; + + case mangadd: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length != 1) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/mangadd )"); + return true; + } + auxGroup = dataHolder.getGroup(args[0]); + if (auxGroup != null) { + sender.sendMessage(ChatColor.RED + "'" + args[0] + "' Group already exists!"); + return true; + } + // Seems OK + auxGroup = dataHolder.createGroup(args[0]); + sender.sendMessage(ChatColor.YELLOW + "You created a group named: " + auxGroup.getName()); + + return true; + + case mangdel: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length != 1) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/mangdel )"); + return false; + } + auxGroup = dataHolder.getGroup(args[0]); + if (auxGroup == null) { + sender.sendMessage(ChatColor.RED + "'" + args[0] + "' Group doesnt exist!"); + return true; + } + // Seems OK + dataHolder.removeGroup(auxGroup.getName()); + sender.sendMessage(ChatColor.YELLOW + "You deleted a group named " + auxGroup.getName() + ", it's users are default group now."); + + BukkitPermissions.updateAllPlayers(); + + return true; + + case manuaddp: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length < 2) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/manuaddp [permission2] [permission3]...)"); + return true; + } + + if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) { + return false; + } + + if (match != null) { + auxUser = dataHolder.getUser(match.get(0)); + } else { + auxUser = dataHolder.getUser(args[0]); + } + + // Validating your permissions + if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getLastName(), senderGroup.getName()) : false)) { + sender.sendMessage(ChatColor.RED + "Can't modify player with same group than you, or higher."); + return true; + } + + for (int i = 1; i < args.length; i++) + { + auxString = args[i].replace("'", ""); + + permissionResult = permissionHandler.checkFullUserPermission(senderUser, auxString); + if (!isConsole && !isOpOverride && (permissionResult.resultType.equals(PermissionCheckResult.Type.NOTFOUND) || permissionResult.resultType.equals(PermissionCheckResult.Type.NEGATION))) { + sender.sendMessage(ChatColor.RED + "You can't add a permission you don't have: '" + auxString + "'"); + continue; + } + // Validating permissions of user + permissionResult = permissionHandler.checkUserOnlyPermission(auxUser, auxString); + if (checkPermissionExists(sender, auxString, permissionResult, "user")) + { + continue; + } + // Seems Ok + auxUser.addPermission(auxString); + sender.sendMessage(ChatColor.YELLOW + "You added '" + auxString + "' to player '" + auxUser.getLastName() + "' permissions."); + } + + + targetPlayer = this.getServer().getPlayer(auxUser.getLastName()); + if (targetPlayer != null) + BukkitPermissions.updatePermissions(targetPlayer); + + return true; + + case manudelp: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length < 2) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/manudelp [permission2] [permission3]...)"); + return true; + } + + if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) { + return false; + } + + if (match != null) { + auxUser = dataHolder.getUser(match.get(0)); + } else { + auxUser = dataHolder.getUser(args[0]); + } + + for (int i = 1; i < args.length; i++) + { + auxString = args[i].replace("'", ""); + + if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getLastName(), senderGroup.getName()) : false)) { + sender.sendMessage(ChatColor.RED + "You can't modify a player with same group as you, or higher."); + continue; + } + // Validating your permissions + permissionResult = permissionHandler.checkFullUserPermission(senderUser, auxString); + if (!isConsole && !isOpOverride && (permissionResult.resultType.equals(PermissionCheckResult.Type.NOTFOUND) || permissionResult.resultType.equals(PermissionCheckResult.Type.NEGATION))) { + sender.sendMessage(ChatColor.RED + "You can't remove a permission you don't have: '" + auxString + "'"); + continue; + } + // Validating permissions of user + permissionResult = permissionHandler.checkUserOnlyPermission(auxUser, auxString); + if (permissionResult.resultType.equals(PermissionCheckResult.Type.NOTFOUND)) { + sender.sendMessage(ChatColor.RED + "The user doesn't have direct access to that permission: '" + auxString + "'"); + continue; + } + if (!auxUser.hasSamePermissionNode(auxString)) { + sender.sendMessage(ChatColor.RED + "This permission node doesn't match any node."); + sender.sendMessage(ChatColor.RED + "But might match node: " + permissionResult.accessLevel); + continue; + } + auxUser.removePermission(auxString); + sender.sendMessage(ChatColor.YELLOW + "You removed '" + auxString + "' from player '" + auxUser.getLastName() + "' permissions."); + } + // Seems OK + + targetPlayer = this.getServer().getPlayer(auxUser.getLastName()); + if (targetPlayer != null) + BukkitPermissions.updatePermissions(targetPlayer); + + return true; + + case manuclearp: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length != 1) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/manuclearp )"); + return true; + } + + if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) { + return false; + } + + if (match != null) { + auxUser = dataHolder.getUser(match.get(0)); + } else { + auxUser = dataHolder.getUser(args[0]); + } + // Validating your permissions + if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getLastName(), senderGroup.getName()) : false)) { + sender.sendMessage(ChatColor.RED + "You can't modify a player with same group as you, or higher."); + return true; + } + for (String perm : auxUser.getPermissionList()) { + permissionResult = permissionHandler.checkFullUserPermission(senderUser, perm); + if (!isConsole && !isOpOverride && (permissionResult.resultType.equals(PermissionCheckResult.Type.NOTFOUND) || permissionResult.resultType.equals(PermissionCheckResult.Type.NEGATION))) { + sender.sendMessage(ChatColor.RED + "You can't remove a permission you don't have: '" + perm + "'."); + } + else + { + auxUser.removePermission(perm); + } + } + sender.sendMessage(ChatColor.YELLOW + "You removed all permissions from player '" + auxUser.getLastName() + "'."); + + targetPlayer = this.getServer().getPlayer(auxUser.getLastName()); + if (targetPlayer != null) + BukkitPermissions.updatePermissions(targetPlayer); + + return true; + + case manulistp: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if ((args.length == 0) || (args.length > 2)) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/manulistp (+))"); + return true; + } + + if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) { + return false; + } + + if (match != null) { + auxUser = dataHolder.getUser(match.get(0)); + } else { + auxUser = dataHolder.getUser(args[0]); + } + // Validating permission + // Seems OK + auxString = ""; + for (String perm : auxUser.getPermissionList()) { + auxString += perm + ", "; + } + if (auxString.lastIndexOf(",") > 0) { + auxString = auxString.substring(0, auxString.lastIndexOf(",")); + sender.sendMessage(ChatColor.YELLOW + "The player '" + auxUser.getLastName() + "' has following permissions: " + ChatColor.WHITE + auxString); + sender.sendMessage(ChatColor.YELLOW + "And all permissions from group: " + auxUser.getGroupName()); + auxString = ""; + for (String subGroup : auxUser.subGroupListStringCopy()) { + auxString += subGroup + ", "; + } + if (auxString.lastIndexOf(",") > 0) { + auxString = auxString.substring(0, auxString.lastIndexOf(",")); + sender.sendMessage(ChatColor.YELLOW + "And all permissions from subgroups: " + auxString); + } + } else { + sender.sendMessage(ChatColor.YELLOW + "The player '" + auxUser.getLastName() + "' has no specific permissions."); + sender.sendMessage(ChatColor.YELLOW + "Only all permissions from group: " + auxUser.getGroupName()); + auxString = ""; + for (String subGroup : auxUser.subGroupListStringCopy()) { + auxString += subGroup + ", "; + } + if (auxString.lastIndexOf(",") > 0) { + auxString = auxString.substring(0, auxString.lastIndexOf(",")); + sender.sendMessage(ChatColor.YELLOW + "And all permissions from subgroups: " + auxString); + } + } + + // bukkit perms + if ((args.length == 2) && (args[1].equalsIgnoreCase("+"))) { + targetPlayer = this.getServer().getPlayer(auxUser.getLastName()); + if (targetPlayer != null) { + sender.sendMessage(ChatColor.YELLOW + "Superperms reports: "); + for (String line : BukkitPermissions.listPerms(targetPlayer)) + sender.sendMessage(ChatColor.YELLOW + line); + + } + } + + return true; + + case manucheckp: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length != 2) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/manucheckp )"); + return true; + } + + auxString = args[1].replace("'", ""); + + if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) { + return false; + } + + if (match != null) { + auxUser = dataHolder.getUser(match.get(0)); + } else { + auxUser = dataHolder.getUser(args[0]); + } + targetPlayer = this.getServer().getPlayer(auxUser.getLastName()); + // Validating permission + permissionResult = permissionHandler.checkFullGMPermission(auxUser, auxString, false); + + if (permissionResult.resultType.equals(PermissionCheckResult.Type.NOTFOUND)) { + // No permissions found in GM so fall through and check Bukkit. + sender.sendMessage(ChatColor.YELLOW + "The player doesn't have access to that permission"); + + } else { + // This permission was found in groupmanager. + if (permissionResult.owner instanceof User) { + if (permissionResult.resultType.equals(PermissionCheckResult.Type.NEGATION)) { + sender.sendMessage(ChatColor.YELLOW + "The user has directly a negation node for that permission."); + } else if (permissionResult.resultType.equals(PermissionCheckResult.Type.EXCEPTION)) { + sender.sendMessage(ChatColor.YELLOW + "The user has directly an Exception node for that permission."); + } else { + sender.sendMessage(ChatColor.YELLOW + "The user has directly this permission."); + } + sender.sendMessage(ChatColor.YELLOW + "Permission Node: " + permissionResult.accessLevel); + } else if (permissionResult.owner instanceof Group) { + if (permissionResult.resultType.equals(PermissionCheckResult.Type.NEGATION)) { + sender.sendMessage(ChatColor.YELLOW + "The user inherits a negation permission from group: " + permissionResult.owner.getLastName()); + } else if (permissionResult.resultType.equals(PermissionCheckResult.Type.EXCEPTION)) { + sender.sendMessage(ChatColor.YELLOW + "The user inherits an Exception permission from group: " + permissionResult.owner.getLastName()); + } else { + sender.sendMessage(ChatColor.YELLOW + "The user inherits the permission from group: " + permissionResult.owner.getLastName()); + } + sender.sendMessage(ChatColor.YELLOW + "Permission Node: " + permissionResult.accessLevel); + } + } + + // superperms + if (targetPlayer != null) { + sender.sendMessage(ChatColor.YELLOW + "SuperPerms reports Node: " + targetPlayer.hasPermission(args[1]) + ((!targetPlayer.hasPermission(args[1]) && targetPlayer.isPermissionSet(args[1])) ? " (Negated)": "")); + } + + return true; + + case mangaddp: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length < 2) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/mangaddp [permission2] [permission3]...)"); + return true; + } + + auxGroup = dataHolder.getGroup(args[0]); + if (auxGroup == null) { + sender.sendMessage(ChatColor.RED + "'" + args[0] + "' Group doesnt exist!"); + return false; + } + + for (int i = 1; i < args.length; i++) + { + auxString = args[i].replace("'", ""); + + // Validating your permissions + permissionResult = permissionHandler.checkFullUserPermission(senderUser, auxString); + if (!isConsole && !isOpOverride && (permissionResult.resultType.equals(PermissionCheckResult.Type.NOTFOUND) || permissionResult.resultType.equals(PermissionCheckResult.Type.NEGATION))) { + sender.sendMessage(ChatColor.RED + "You can't add a permission you don't have: '" + auxString + "'"); + continue; + } + // Validating permissions of user + permissionResult = permissionHandler.checkGroupOnlyPermission(auxGroup, auxString); + if (checkPermissionExists(sender, auxString, permissionResult, "group")) + { + continue; + } + // Seems OK + auxGroup.addPermission(auxString); + sender.sendMessage(ChatColor.YELLOW + "You added '" + auxString + "' to group '" + auxGroup.getName() + "' permissions."); + } + + BukkitPermissions.updateAllPlayers(); + + return true; + + case mangdelp: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length < 2) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/mangdelp [permission2] [permission3]...)"); + return true; + } + + auxGroup = dataHolder.getGroup(args[0]); + if (auxGroup == null) { + sender.sendMessage(ChatColor.RED + "'" + args[0] + "' Group doesnt exist!"); + return true; + } + for (int i = 1; i < args.length; i++) + { + auxString = args[i].replace("'", ""); + + // Validating your permissions + permissionResult = permissionHandler.checkFullUserPermission(senderUser, auxString); + if (!isConsole && !isOpOverride && (permissionResult.resultType.equals(PermissionCheckResult.Type.NOTFOUND) || permissionResult.resultType.equals(PermissionCheckResult.Type.NEGATION))) { + sender.sendMessage(ChatColor.RED + "Can't remove a permission you don't have: '" + auxString + "'"); + continue; + } + // Validating permissions of user + permissionResult = permissionHandler.checkGroupOnlyPermission(auxGroup, auxString); + if (permissionResult.resultType.equals(PermissionCheckResult.Type.NOTFOUND)) { + sender.sendMessage(ChatColor.YELLOW + "The group doesn't have direct access to that permission: '" + auxString + "'"); + continue; + } + if (!auxGroup.hasSamePermissionNode(auxString)) { + sender.sendMessage(ChatColor.RED + "This permission node doesn't match any node."); + sender.sendMessage(ChatColor.RED + "But might match node: " + permissionResult.accessLevel); + continue; + } + // Seems OK + auxGroup.removePermission(auxString); + sender.sendMessage(ChatColor.YELLOW + "You removed '" + auxString + "' from group '" + auxGroup.getName() + "' permissions."); + } + + BukkitPermissions.updateAllPlayers(); + + return true; + + case mangclearp: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length != 1) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/mangclearp )"); + return true; + } + + auxGroup = dataHolder.getGroup(args[0]); + if (auxGroup == null) { + sender.sendMessage(ChatColor.RED + "'" + args[0] + "' Group doesnt exist!"); + return true; + } + + for (String perm : auxGroup.getPermissionList()) { + permissionResult = permissionHandler.checkFullUserPermission(senderUser, perm); + if (!isConsole && !isOpOverride && (permissionResult.resultType.equals(PermissionCheckResult.Type.NOTFOUND) || permissionResult.resultType.equals(PermissionCheckResult.Type.NEGATION))) { + sender.sendMessage(ChatColor.RED + "Can't remove a permission you don't have: '" + perm + "'."); + } + else + { + auxGroup.removePermission(perm); + } + } + sender.sendMessage(ChatColor.YELLOW + "You removed all permissions from group '" + auxGroup.getName() + "'."); + + BukkitPermissions.updateAllPlayers(); + + return true; + + case manglistp: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length != 1) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/manglistp )"); + return true; + } + auxGroup = dataHolder.getGroup(args[0]); + if (auxGroup == null) { + sender.sendMessage(ChatColor.RED + "'" + args[0] + "' Group doesnt exist!"); + return true; + } + // Validating permission + + // Seems OK + auxString = ""; + for (String perm : auxGroup.getPermissionList()) { + auxString += perm + ", "; + } + if (auxString.lastIndexOf(",") > 0) { + auxString = auxString.substring(0, auxString.lastIndexOf(",")); + sender.sendMessage(ChatColor.YELLOW + "The group '" + auxGroup.getName() + "' has following permissions: " + ChatColor.WHITE + auxString); + auxString = ""; + for (String grp : auxGroup.getInherits()) { + auxString += grp + ", "; + } + if (auxString.lastIndexOf(",") > 0) { + auxString = auxString.substring(0, auxString.lastIndexOf(",")); + sender.sendMessage(ChatColor.YELLOW + "And all permissions from groups: " + auxString); + } + + } else { + sender.sendMessage(ChatColor.YELLOW + "The group '" + auxGroup.getName() + "' has no specific permissions."); + auxString = ""; + for (String grp : auxGroup.getInherits()) { + auxString += grp + ", "; + } + if (auxString.lastIndexOf(",") > 0) { + auxString = auxString.substring(0, auxString.lastIndexOf(",")); + sender.sendMessage(ChatColor.YELLOW + "Only all permissions from groups: " + auxString); + } + + } + return true; + + case mangcheckp: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length != 2) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/mangcheckp )"); + return true; + } + + auxString = args[1]; + if (auxString.startsWith("'") && auxString.endsWith("'")) + { + auxString = auxString.substring(1, auxString.length() - 1); + } + + auxGroup = dataHolder.getGroup(args[0]); + if (auxGroup == null) { + sender.sendMessage(ChatColor.RED + "'" + args[0] + "' Group doesnt exist!"); + return true; + } + // Validating permission + permissionResult = permissionHandler.checkGroupPermissionWithInheritance(auxGroup, auxString); + if (permissionResult.resultType.equals(PermissionCheckResult.Type.NOTFOUND)) { + sender.sendMessage(ChatColor.YELLOW + "The group doesn't have access to that permission"); + return true; + } + // Seems OK + // auxString = permissionHandler.checkUserOnlyPermission(auxUser, args[1]); + if (permissionResult.owner instanceof Group) { + if (permissionResult.resultType.equals(PermissionCheckResult.Type.NEGATION)) { + sender.sendMessage(ChatColor.YELLOW + "The group inherits the negation permission from group: " + permissionResult.owner.getLastName()); + } else if (permissionResult.resultType.equals(PermissionCheckResult.Type.EXCEPTION)) { + sender.sendMessage(ChatColor.YELLOW + "The group inherits an Exception permission from group: " + permissionResult.owner.getLastName()); + } else { + sender.sendMessage(ChatColor.YELLOW + "The group inherits the permission from group: " + permissionResult.owner.getLastName()); + } + sender.sendMessage(ChatColor.YELLOW + "Permission Node: " + permissionResult.accessLevel); + + } + return true; + + case mangaddi: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length != 2) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/mangaddi )"); + return true; + } + auxGroup = dataHolder.getGroup(args[0]); + if (auxGroup == null) { + sender.sendMessage(ChatColor.RED + "'" + args[0] + "' Group doesnt exist!"); + return true; + } + auxGroup2 = dataHolder.getGroup(args[1]); + if (auxGroup2 == null) { + sender.sendMessage(ChatColor.RED + "'" + args[1] + "' Group doesnt exist!"); + return true; + } + if (auxGroup.isGlobal()) { + sender.sendMessage(ChatColor.RED + "GlobalGroups do NOT support inheritance."); + return true; + } + + // Validating permission + if (permissionHandler.hasGroupInInheritance(auxGroup, auxGroup2.getName())) { + sender.sendMessage(ChatColor.RED + "Group " + auxGroup.getName() + " already inherits " + auxGroup2.getName() + " (might not be directly)"); + return true; + } + // Seems OK + auxGroup.addInherits(auxGroup2); + sender.sendMessage(ChatColor.RED + "Group " + auxGroup2.getName() + " is now in " + auxGroup.getName() + " inheritance list."); + + BukkitPermissions.updateAllPlayers(); + + return true; + + case mangdeli: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length != 2) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/mangdeli )"); + return true; + } + auxGroup = dataHolder.getGroup(args[0]); + if (auxGroup == null) { + sender.sendMessage(ChatColor.RED + "'" + args[0] + "' Group doesnt exist!"); + return true; + } + auxGroup2 = dataHolder.getGroup(args[1]); + if (auxGroup2 == null) { + sender.sendMessage(ChatColor.RED + "'" + args[1] + "' Group doesnt exist!"); + return true; + } + if (auxGroup.isGlobal()) { + sender.sendMessage(ChatColor.RED + "GlobalGroups do NOT support inheritance."); + return true; + } + + // Validating permission + if (!permissionHandler.hasGroupInInheritance(auxGroup, auxGroup2.getName())) { + sender.sendMessage(ChatColor.RED + "Group " + auxGroup.getName() + " does not inherits " + auxGroup2.getName() + "."); + return true; + } + if (!auxGroup.getInherits().contains(auxGroup2.getName())) { + sender.sendMessage(ChatColor.RED + "Group " + auxGroup.getName() + " does not inherits " + auxGroup2.getName() + " directly."); + return true; + } + // Seems OK + auxGroup.removeInherits(auxGroup2.getName()); + sender.sendMessage(ChatColor.RED + "Group " + auxGroup2.getName() + " was removed from " + auxGroup.getName() + " inheritance list."); + + BukkitPermissions.updateAllPlayers(); + + return true; + + case manuaddv: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length < 3) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/manuaddv )"); + return true; + } + if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) { + return false; + } + + if (match != null) { + auxUser = dataHolder.getUser(match.get(0)); + } else { + auxUser = dataHolder.getUser(args[0]); + } + // Validating permission + // Seems OK + auxString = ""; + for (int i = 2; i < args.length; i++) { + auxString += args[i]; + if ((i + 1) < args.length) { + auxString += " "; + } + } + auxString = auxString.replace("'", ""); + auxUser.getVariables().addVar(args[1], Variables.parseVariableValue(auxString)); + sender.sendMessage(ChatColor.YELLOW + "Variable " + ChatColor.GOLD + args[1] + ChatColor.YELLOW + ":'" + ChatColor.GREEN + auxString + ChatColor.YELLOW + "' added to the user " + auxUser.getLastName()); + + return true; + + case manudelv: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length != 2) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/manudelv )"); + return true; + } + if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) { + return false; + } + + if (match != null) { + auxUser = dataHolder.getUser(match.get(0)); + } else { + auxUser = dataHolder.getUser(args[0]); + } + // Validating permission + if (!auxUser.getVariables().hasVar(args[1])) { + sender.sendMessage(ChatColor.RED + "The user doesn't have directly that variable!"); + return true; + } + // Seems OK + auxUser.getVariables().removeVar(args[1]); + sender.sendMessage(ChatColor.YELLOW + "Variable " + ChatColor.GOLD + args[1] + ChatColor.YELLOW + " removed from the user " + ChatColor.GREEN + auxUser.getLastName()); + + return true; + + case manulistv: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length != 1) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/manulistv )"); + return true; + } + if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) { + return false; + } + if (match != null) { + auxUser = dataHolder.getUser(match.get(0)); + } else { + auxUser = dataHolder.getUser(args[0]); + } + // Validating permission + // Seems OK + auxString = ""; + for (String varKey : auxUser.getVariables().getVarKeyList()) { + Object o = auxUser.getVariables().getVarObject(varKey); + auxString += ChatColor.GOLD + varKey + ChatColor.WHITE + ":'" + ChatColor.GREEN + o.toString() + ChatColor.WHITE + "', "; + } + if (auxString.lastIndexOf(",") > 0) { + auxString = auxString.substring(0, auxString.lastIndexOf(",")); + } + sender.sendMessage(ChatColor.YELLOW + "Variables of user " + auxUser.getLastName() + ": "); + sender.sendMessage(auxString + "."); + sender.sendMessage(ChatColor.YELLOW + "Plus all variables from group: " + auxUser.getGroupName()); + + return true; + + case manucheckv: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length != 2) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/manucheckv )"); + return true; + } + if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) { + return false; + } + if (match != null) { + auxUser = dataHolder.getUser(match.get(0)); + } else { + auxUser = dataHolder.getUser(args[0]); + } + // Validating permission + auxGroup = auxUser.getGroup(); + auxGroup2 = permissionHandler.nextGroupWithVariable(auxGroup, args[1]); + + if (!auxUser.getVariables().hasVar(args[1])) { + // Check sub groups + if (!auxUser.isSubGroupsEmpty() && auxGroup2 == null) + for (Group subGroup : auxUser.subGroupListCopy()) { + auxGroup2 = permissionHandler.nextGroupWithVariable(subGroup, args[1]); + if (auxGroup2 != null) + continue; + } + if (auxGroup2 == null) { + sender.sendMessage(ChatColor.YELLOW + "The user doesn't have access to that variable!"); + return true; + } + } + // Seems OK + if (auxUser.getVariables().hasVar(auxString)) { + sender.sendMessage(ChatColor.YELLOW + "The value of variable '" + ChatColor.GOLD + args[1] + ChatColor.YELLOW + "' is: '" + ChatColor.GREEN + auxUser.getVariables().getVarObject(args[1]).toString() + ChatColor.WHITE + "'"); + sender.sendMessage(ChatColor.YELLOW + "This user own directly the variable"); + } + sender.sendMessage(ChatColor.YELLOW + "The value of variable '" + ChatColor.GOLD + args[1] + ChatColor.YELLOW + "' is: '" + ChatColor.GREEN + auxGroup2.getVariables().getVarObject(args[1]).toString() + ChatColor.WHITE + "'"); + if (!auxGroup.equals(auxGroup2)) { + sender.sendMessage(ChatColor.YELLOW + "And the value was inherited from group: " + ChatColor.GREEN + auxGroup2.getName()); + } + + return true; + + case mangaddv: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length < 3) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/mangaddv )"); + return true; + } + auxGroup = dataHolder.getGroup(args[0]); + if (auxGroup == null) { + sender.sendMessage(ChatColor.RED + "'" + args[0] + "' Group doesnt exist!"); + return true; + } + if (auxGroup.isGlobal()) { + sender.sendMessage(ChatColor.RED + "GlobalGroups do NOT support Info Nodes."); + return true; + } + // Validating permission + // Seems OK + auxString = ""; + for (int i = 2; i < args.length; i++) { + auxString += args[i]; + if ((i + 1) < args.length) { + auxString += " "; + } + } + + auxString = auxString.replace("'", ""); + auxGroup.getVariables().addVar(args[1], Variables.parseVariableValue(auxString)); + sender.sendMessage(ChatColor.YELLOW + "Variable " + ChatColor.GOLD + args[1] + ChatColor.YELLOW + ":'" + ChatColor.GREEN + auxString + ChatColor.YELLOW + "' added to the group " + auxGroup.getName()); + + return true; + + case mangdelv: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length != 2) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/mangdelv )"); + return true; + } + auxGroup = dataHolder.getGroup(args[0]); + if (auxGroup == null) { + sender.sendMessage(ChatColor.RED + "'" + args[0] + "' Group doesnt exist!"); + return true; + } + if (auxGroup.isGlobal()) { + sender.sendMessage(ChatColor.RED + "GlobalGroups do NOT support Info Nodes."); + return true; + } + // Validating permission + if (!auxGroup.getVariables().hasVar(args[1])) { + sender.sendMessage(ChatColor.RED + "The group doesn't have directly that variable!"); + return true; + } + // Seems OK + auxGroup.getVariables().removeVar(args[1]); + sender.sendMessage(ChatColor.YELLOW + "Variable " + ChatColor.GOLD + args[1] + ChatColor.YELLOW + " removed from the group " + ChatColor.GREEN + auxGroup.getName()); + + return true; + + case manglistv: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length != 1) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/manglistv )"); + return true; + } + auxGroup = dataHolder.getGroup(args[0]); + if (auxGroup == null) { + sender.sendMessage(ChatColor.RED + "'" + args[0] + "' Group doesnt exist!"); + return true; + } + if (auxGroup.isGlobal()) { + sender.sendMessage(ChatColor.RED + "GlobalGroups do NOT support Info Nodes."); + return true; + } + // Validating permission + // Seems OK + auxString = ""; + for (String varKey : auxGroup.getVariables().getVarKeyList()) { + Object o = auxGroup.getVariables().getVarObject(varKey); + auxString += ChatColor.GOLD + varKey + ChatColor.WHITE + ":'" + ChatColor.GREEN + o.toString() + ChatColor.WHITE + "', "; + } + if (auxString.lastIndexOf(",") > 0) { + auxString = auxString.substring(0, auxString.lastIndexOf(",")); + } + sender.sendMessage(ChatColor.YELLOW + "Variables of group " + auxGroup.getName() + ": "); + sender.sendMessage(auxString + "."); + auxString = ""; + for (String grp : auxGroup.getInherits()) { + auxString += grp + ", "; + } + if (auxString.lastIndexOf(",") > 0) { + auxString = auxString.substring(0, auxString.lastIndexOf(",")); + sender.sendMessage(ChatColor.YELLOW + "Plus all variables from groups: " + auxString); + } + + return true; + + case mangcheckv: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length != 2) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/mangcheckv )"); + return true; + } + auxGroup = dataHolder.getGroup(args[0]); + if (auxGroup == null) { + sender.sendMessage(ChatColor.RED + "'" + args[0] + "' Group doesnt exist!"); + return true; + } + if (auxGroup.isGlobal()) { + sender.sendMessage(ChatColor.RED + "GlobalGroups do NOT support Info Nodes."); + return true; + } + // Validating permission + auxGroup2 = permissionHandler.nextGroupWithVariable(auxGroup, args[1]); + if (auxGroup2 == null) { + sender.sendMessage(ChatColor.RED + "The group doesn't have access to that variable!"); + } + // Seems OK + sender.sendMessage(ChatColor.YELLOW + "The value of variable '" + ChatColor.GOLD + args[1] + ChatColor.YELLOW + "' is: '" + ChatColor.GREEN + auxGroup2.getVariables().getVarObject(args[1]).toString() + ChatColor.WHITE + "'"); + if (!auxGroup.equals(auxGroup2)) { + sender.sendMessage(ChatColor.YELLOW + "And the value was inherited from group: " + ChatColor.GREEN + auxGroup2.getName()); + } + + return true; + + case manwhois: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length != 1) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/manwhois )"); + return true; + } + if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) { + return false; + } + if (match != null) { + auxUser = dataHolder.getUser(match.get(0)); + } else { + auxUser = dataHolder.getUser(args[0]); + } + // Seems OK + sender.sendMessage(ChatColor.YELLOW + "Name: " + ChatColor.GREEN + auxUser.getLastName()); + sender.sendMessage(ChatColor.YELLOW + "Group: " + ChatColor.GREEN + auxUser.getGroup().getName()); + // Compile a list of subgroups + auxString = ""; + for (String subGroup : auxUser.subGroupListStringCopy()) { + auxString += subGroup + ", "; + } + if (auxString.lastIndexOf(",") > 0) { + auxString = auxString.substring(0, auxString.lastIndexOf(",")); + sender.sendMessage(ChatColor.YELLOW + "subgroups: " + auxString); + } + + sender.sendMessage(ChatColor.YELLOW + "Overloaded: " + ChatColor.GREEN + dataHolder.isOverloaded(auxUser.getLastName())); + auxGroup = dataHolder.surpassOverload(auxUser.getLastName()).getGroup(); + if (!auxGroup.equals(auxUser.getGroup())) { + sender.sendMessage(ChatColor.YELLOW + "Original Group: " + ChatColor.GREEN + auxGroup.getName()); + } + // victim.permissions.add(args[1]); + return true; + + case tempadd: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length != 1) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/tempadd )"); + return true; + } + if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) { + return false; + } + if (match != null) { + auxUser = dataHolder.getUser(match.get(0)); + } else { + auxUser = dataHolder.getUser(args[0]); + } + // Validating permission + if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getLastName(), senderGroup.getName()) : false)) { + sender.sendMessage(ChatColor.RED + "Can't modify player with same permissions than you, or higher."); + return true; + } + // Seems OK + if (overloadedUsers.get(dataHolder.getName().toLowerCase()) == null) { + overloadedUsers.put(dataHolder.getName().toLowerCase(), new ArrayList()); + } + dataHolder.overloadUser(auxUser.getLastName()); + overloadedUsers.get(dataHolder.getName().toLowerCase()).add(dataHolder.getUser(auxUser.getLastName())); + sender.sendMessage(ChatColor.YELLOW + "Player set to overload mode!"); + + return true; + + case tempdel: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length != 1) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/tempdel )"); + return true; + } + if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) { + return false; + } + if (match != null) { + auxUser = dataHolder.getUser(match.get(0)); + } else { + auxUser = dataHolder.getUser(args[0]); + } + // Validating permission + if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getLastName(), senderGroup.getName()) : false)) { + sender.sendMessage(ChatColor.RED + "You can't modify a player with same permissions as you, or higher."); + return true; + } + // Seems OK + if (overloadedUsers.get(dataHolder.getName().toLowerCase()) == null) { + overloadedUsers.put(dataHolder.getName().toLowerCase(), new ArrayList()); + } + dataHolder.removeOverload(auxUser.getLastName()); + if (overloadedUsers.get(dataHolder.getName().toLowerCase()).contains(auxUser)) { + overloadedUsers.get(dataHolder.getName().toLowerCase()).remove(auxUser); + } + sender.sendMessage(ChatColor.YELLOW + "Player overload mode is now disabled."); + + return true; + + case templist: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // WORKING + auxString = ""; + removeList = new ArrayList(); + count = 0; + for (User u : overloadedUsers.get(dataHolder.getName().toLowerCase())) { + if (!dataHolder.isOverloaded(u.getLastName())) { + removeList.add(u); + } else { + auxString += u.getLastName() + ", "; + count++; + } + } + if (count == 0) { + sender.sendMessage(ChatColor.YELLOW + "There are no users in overload mode."); + return true; + } + auxString = auxString.substring(0, auxString.lastIndexOf(",")); + if (overloadedUsers.get(dataHolder.getName().toLowerCase()) == null) { + overloadedUsers.put(dataHolder.getName().toLowerCase(), new ArrayList()); + } + overloadedUsers.get(dataHolder.getName().toLowerCase()).removeAll(removeList); + sender.sendMessage(ChatColor.YELLOW + " " + count + " Users in overload mode: " + ChatColor.WHITE + auxString); + + return true; + + case tempdelall: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // WORKING + removeList = new ArrayList(); + count = 0; + for (User u : overloadedUsers.get(dataHolder.getName().toLowerCase())) { + if (dataHolder.isOverloaded(u.getLastName())) { + dataHolder.removeOverload(u.getLastName()); + count++; + } + } + if (count == 0) { + sender.sendMessage(ChatColor.YELLOW + "There are no users in overload mode."); + return true; + } + if (overloadedUsers.get(dataHolder.getName().toLowerCase()) == null) { + overloadedUsers.put(dataHolder.getName().toLowerCase(), new ArrayList()); + } + overloadedUsers.get(dataHolder.getName().toLowerCase()).clear(); + sender.sendMessage(ChatColor.YELLOW + " " + count + "All users in overload mode are now normal again."); + + return true; + + case mansave: + + boolean forced = false; + + if ((args.length == 1) && (args[0].equalsIgnoreCase("force"))) + forced = true; + + try { + worldsHolder.saveChanges(forced); + sender.sendMessage(ChatColor.YELLOW + "All changes were saved."); + } catch (IllegalStateException ex) { + sender.sendMessage(ChatColor.RED + ex.getMessage()); + } + return true; + + case manload: + + /** + * Attempt to reload a specific world + */ + if (args.length > 0) { + + if (!lastError.isEmpty()) { + sender.sendMessage(ChatColor.RED + "All commands are locked due to an error. " + ChatColor.BOLD + "" + ChatColor.UNDERLINE + "Check plugins/groupmanager/error.log or console" + ChatColor.RESET + "" + ChatColor.RED + " and then try a '/manload'."); + return true; + } + + auxString = ""; + for (int i = 0; i < args.length; i++) { + auxString += args[i]; + if ((i + 1) < args.length) { + auxString += " "; + } + } + + isLoaded = false; // Disable Bukkit Perms update and event triggers + + globalGroups.load(); + worldsHolder.loadWorld(auxString); + + sender.sendMessage("The request to reload world '" + auxString + "' was attempted."); + + isLoaded = true; + + BukkitPermissions.reset(); + + } else { + + /** + * Reload all settings and data as no world was specified. + */ + + /* + * Attempting a fresh load. + */ + onDisable(true); + onEnable(true); + + sender.sendMessage("All settings and worlds were reloaded!"); + } + + /** + * Fire an event as none will have been triggered in the reload. + */ + if (GroupManager.isLoaded()) + GroupManager.getGMEventHandler().callEvent(GMSystemEvent.Action.RELOADED); + + return true; + + case listgroups: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // WORKING + auxString = ""; + String auxString2 = ""; + for (Group g : dataHolder.getGroupList()) { + auxString += g.getName() + ", "; + } + for (Group g : getGlobalGroups().getGroupList()) { + auxString2 += g.getName() + ", "; + } + if (auxString.lastIndexOf(",") > 0) { + auxString = auxString.substring(0, auxString.lastIndexOf(",")); + } + if (auxString2.lastIndexOf(",") > 0) { + auxString2 = auxString2.substring(0, auxString2.lastIndexOf(",")); + } + sender.sendMessage(ChatColor.YELLOW + "Groups Available: " + ChatColor.WHITE + auxString); + sender.sendMessage(ChatColor.YELLOW + "GlobalGroups Available: " + ChatColor.WHITE + auxString2); + + return true; + + case manpromote: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length != 2) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/manpromote )"); + return true; + } + if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) { + return false; + } + if (match != null) { + auxUser = dataHolder.getUser(match.get(0)); + } else { + auxUser = dataHolder.getUser(args[0]); + } + auxGroup = dataHolder.getGroup(args[1]); + if (auxGroup == null) { + sender.sendMessage(ChatColor.RED + "'" + args[1] + "' Group doesnt exist!"); + return true; + } + if (auxGroup.isGlobal()) { + sender.sendMessage(ChatColor.RED + "Players may not be members of GlobalGroups directly."); + return true; + } + // Validating permission + if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getLastName(), senderGroup.getName()) : false)) { + sender.sendMessage(ChatColor.RED + "You can't modify a player with same permissions as you, or higher."); + return true; + } + if (!isConsole && !isOpOverride && (permissionHandler.hasGroupInInheritance(auxGroup, senderGroup.getName()))) { + sender.sendMessage(ChatColor.RED + "The destination group can't be the same as yours, or higher."); + return true; + } + if (!isConsole && !isOpOverride && (!permissionHandler.inGroup(senderUser.getLastName(), auxUser.getGroupName()) || !permissionHandler.inGroup(senderUser.getLastName(), auxGroup.getName()))) { + sender.sendMessage(ChatColor.RED + "You can't modify a player involving a group that you don't inherit."); + return true; + } + if (!permissionHandler.hasGroupInInheritance(auxUser.getGroup(), auxGroup.getName()) && !permissionHandler.hasGroupInInheritance(auxGroup, auxUser.getGroupName())) { + sender.sendMessage(ChatColor.RED + "You can't modify a player using groups with different heritage line."); + return true; + } + if (!permissionHandler.hasGroupInInheritance(auxGroup, auxUser.getGroupName())) { + sender.sendMessage(ChatColor.RED + "The new group must be a higher rank."); + return true; + } + // Seems OK + auxUser.setGroup(auxGroup); + if (!sender.hasPermission("groupmanager.notify.other") || (isConsole)) + sender.sendMessage(ChatColor.YELLOW + "You changed " + auxUser.getLastName() + " group to " + auxGroup.getName() + "."); + + return true; + + case mandemote: + // Validating state of sender + if (dataHolder == null || permissionHandler == null) { + if (!setDefaultWorldHandler(sender)) + return true; + } + // Validating arguments + if (args.length != 2) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/mandemote )"); + return true; + } + if ((validateOnlinePlayer) && ((match = validatePlayer(args[0], sender)) == null)) { + return false; + } + if (match != null) { + auxUser = dataHolder.getUser(match.get(0)); + } else { + auxUser = dataHolder.getUser(args[0]); + } + auxGroup = dataHolder.getGroup(args[1]); + if (auxGroup == null) { + sender.sendMessage(ChatColor.RED + "'" + args[1] + "' Group doesnt exist!"); + return true; + } + if (auxGroup.isGlobal()) { + sender.sendMessage(ChatColor.RED + "Players may not be members of GlobalGroups directly."); + return true; + } + // Validating permission + if (!isConsole && !isOpOverride && (senderGroup != null ? permissionHandler.inGroup(auxUser.getLastName(), senderGroup.getName()) : false)) { + sender.sendMessage(ChatColor.RED + "You can't modify a player with same permissions as you, or higher."); + return true; + } + if (!isConsole && !isOpOverride && (permissionHandler.hasGroupInInheritance(auxGroup, senderGroup.getName()))) { + sender.sendMessage(ChatColor.RED + "The destination group can't be the same as yours, or higher."); + return true; + } + if (!isConsole && !isOpOverride && (!permissionHandler.inGroup(senderUser.getLastName(), auxUser.getGroupName()) || !permissionHandler.inGroup(senderUser.getLastName(), auxGroup.getName()))) { + sender.sendMessage(ChatColor.RED + "You can't modify a player involving a group that you don't inherit."); + return true; + } + if (!permissionHandler.hasGroupInInheritance(auxUser.getGroup(), auxGroup.getName()) && !permissionHandler.hasGroupInInheritance(auxGroup, auxUser.getGroupName())) { + sender.sendMessage(ChatColor.RED + "You can't modify a player using groups with different inheritage line."); + return true; + } + if (permissionHandler.hasGroupInInheritance(auxGroup, auxUser.getGroupName())) { + sender.sendMessage(ChatColor.RED + "The new group must be a lower rank."); + return true; + } + // Seems OK + auxUser.setGroup(auxGroup); + if (!sender.hasPermission("groupmanager.notify.other") || (isConsole)) + sender.sendMessage(ChatColor.YELLOW + "You changed " + auxUser.getLastName() + " group to " + auxGroup.getName() + "."); + + return true; + + case mantogglevalidate: + validateOnlinePlayer = !validateOnlinePlayer; + sender.sendMessage(ChatColor.YELLOW + "Validate if player is online, now set to: " + Boolean.toString(validateOnlinePlayer)); + if (!validateOnlinePlayer) { + sender.sendMessage(ChatColor.GOLD + "From now on you can edit players that are not connected... BUT:"); + sender.sendMessage(ChatColor.LIGHT_PURPLE + "From now on you should type the whole name of the player, correctly."); + } + return true; + case mantogglesave: + if (scheduler == null) { + enableScheduler(); + sender.sendMessage(ChatColor.YELLOW + "The auto-saving is enabled!"); + } else { + disableScheduler(); + sender.sendMessage(ChatColor.YELLOW + "The auto-saving is disabled!"); + } + return true; + case manworld: + auxString = selectedWorlds.get(sender.getName()); + if (auxString != null) { + sender.sendMessage(ChatColor.YELLOW + "You have the world '" + dataHolder.getName() + "' in your selection."); + } else { + if (dataHolder == null) { + sender.sendMessage(ChatColor.YELLOW + "There is no world selected. And no world is available now."); + } else { + sender.sendMessage(ChatColor.YELLOW + "You don't have a world in your selection.."); + sender.sendMessage(ChatColor.YELLOW + "Working with the direct world where your player is."); + sender.sendMessage(ChatColor.YELLOW + "Your world now uses permissions of world name: '" + dataHolder.getName() + "' "); + } + } + + return true; + + case manselect: + if (args.length < 1) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/manselect )"); + sender.sendMessage(ChatColor.YELLOW + "Worlds available: "); + ArrayList worlds = worldsHolder.allWorldsDataList(); + auxString = ""; + for (int i = 0; i < worlds.size(); i++) { + auxString += worlds.get(i).getName(); + if ((i + 1) < worlds.size()) { + auxString += ", "; + } + } + sender.sendMessage(ChatColor.YELLOW + auxString); + return false; + } + auxString = ""; + for (int i = 0; i < args.length; i++) { + if (args[i] == null) { + logger.warning("Bukkit gave invalid arguments array! Cmd: " + cmd.getName() + " args.length: " + args.length); + return false; + } + auxString += args[i]; + if (i < (args.length - 1)) { + auxString += " "; + } + } + dataHolder = worldsHolder.getWorldData(auxString); + permissionHandler = dataHolder.getPermissionsHandler(); + selectedWorlds.put(sender.getName(), dataHolder.getName()); + sender.sendMessage(ChatColor.YELLOW + "You have selected world '" + dataHolder.getName() + "'."); + + return true; + + case manclear: + if (args.length != 0) { + sender.sendMessage(ChatColor.RED + "Review your arguments count!"); + return false; + } + selectedWorlds.remove(sender.getName()); + sender.sendMessage(ChatColor.YELLOW + "You have removed your world selection. Working with current world(if possible)."); + + return true; + + case mancheckw: + if (args.length < 1) { + sender.sendMessage(ChatColor.RED + "Review your arguments count! (/mancheckw )"); + sender.sendMessage(ChatColor.YELLOW + "Worlds available: "); + ArrayList worlds = worldsHolder.allWorldsDataList(); + auxString = ""; + for (int i = 0; i < worlds.size(); i++) { + auxString += worlds.get(i).getName(); + if ((i + 1) < worlds.size()) { + auxString += ", "; + } + } + sender.sendMessage(ChatColor.YELLOW + auxString); + return false; + } + + auxString = ""; + for (int i = 0; i < args.length; i++) { + if (args[i] == null) { + logger.warning("Bukkit gave invalid arguments array! Cmd: " + cmd.getName() + " args.length: " + args.length); + return false; + } + auxString += args[i]; + if (i < (args.length - 1)) { + auxString += " "; + } + } + dataHolder = worldsHolder.getWorldData(auxString); + + sender.sendMessage(ChatColor.YELLOW + "You have selected world '" + dataHolder.getName() + "'."); + sender.sendMessage(ChatColor.YELLOW + "This world is using the following data files.."); + sender.sendMessage(ChatColor.YELLOW + "Groups:" + ChatColor.GREEN + " " + dataHolder.getGroupsFile().getAbsolutePath()); + sender.sendMessage(ChatColor.YELLOW + "Users:" + ChatColor.GREEN + " " + dataHolder.getUsersFile().getAbsolutePath()); + + return true; + + default: + break; + } + } + sender.sendMessage(ChatColor.RED + "You are not allowed to use that command."); + return true; + } + + /** + * Checks if a permission exists and of a lower or same priority. + */ + private boolean checkPermissionExists(CommandSender sender, String newPerm, PermissionCheckResult oldPerm, String type) { + + + if (newPerm.startsWith("+")) + { + if (oldPerm.resultType.equals(PermissionCheckResult.Type.EXCEPTION)) + { + sender.sendMessage(ChatColor.RED + "The " + type + " already has direct access to that permission."); + sender.sendMessage(ChatColor.RED + "Node: " + oldPerm.accessLevel); + return true; + } + } + else if (newPerm.startsWith("-")) + { + if (oldPerm.resultType.equals(PermissionCheckResult.Type.EXCEPTION)) + { + sender.sendMessage(ChatColor.RED + "The " + type + " already has an exception for this node."); + sender.sendMessage(ChatColor.RED + "Node: " + oldPerm.accessLevel); + return true; + } + else if (oldPerm.resultType.equals(PermissionCheckResult.Type.NEGATION)) + { + sender.sendMessage(ChatColor.RED + "The " + type + " already has a matching negated node."); + sender.sendMessage(ChatColor.RED + "Node: " + oldPerm.accessLevel); + return true; + } + } + else + { + if (oldPerm.resultType.equals(PermissionCheckResult.Type.EXCEPTION)) + { + sender.sendMessage(ChatColor.RED + "The " + type + " already has an exception for this node."); + sender.sendMessage(ChatColor.RED + "Node: " + oldPerm.accessLevel); + } + else if (oldPerm.resultType.equals(PermissionCheckResult.Type.NEGATION)) + { + sender.sendMessage(ChatColor.RED + "The " + type + " already has a matching negated node."); + sender.sendMessage(ChatColor.RED + "Node: " + oldPerm.accessLevel); + } + else if (oldPerm.resultType.equals(PermissionCheckResult.Type.FOUND)) + { + sender.sendMessage(ChatColor.RED + "The " + type + " already has direct access to that permission."); + sender.sendMessage(ChatColor.RED + "Node: " + oldPerm.accessLevel); + + // Since not all plugins define wildcard permissions, allow setting the permission anyway if the permissions dont match exactly. + return (oldPerm.accessLevel.equalsIgnoreCase(newPerm)); + } + } + return false; + } + + + /** + * Sets up the default world for use. + */ + private boolean setDefaultWorldHandler(CommandSender sender) { + + dataHolder = worldsHolder.getWorldData(worldsHolder.getDefaultWorld().getName()); + permissionHandler = dataHolder.getPermissionsHandler(); + + if ((dataHolder != null) && (permissionHandler != null)) { + selectedWorlds.put(sender.getName(), dataHolder.getName()); + sender.sendMessage(ChatColor.RED + "Couldn't retrieve your world. Default world '" + worldsHolder.getDefaultWorld().getName() + "' selected."); + return true; + } + + sender.sendMessage(ChatColor.RED + "Couldn't retrieve your world. World selection is needed."); + sender.sendMessage(ChatColor.RED + "Use /manselect "); + return false; + + } + + /** + * Send confirmation of a group change. using permission nodes... + * + * groupmanager.notify.self groupmanager.notify.other + * + * @param name + * @param msg + */ + public static void notify(String name, String msg) { + + Player player = Bukkit.getServer().getPlayerExact(name); + + for (Player test : Bukkit.getServer().getOnlinePlayers()) { + if (!test.equals(player)) { + if (test.hasPermission("groupmanager.notify.other")) + test.sendMessage(ChatColor.YELLOW + name + " was" + msg); + } else if ((player != null) && ((player.hasPermission("groupmanager.notify.self")) || (player.hasPermission("groupmanager.notify.other")))) + player.sendMessage(ChatColor.YELLOW + "You were" + msg); + } + + } + + /** + * Load a List of players matching the name given. If none online, check + * Offline. + * + * @param playerName, sender + * @return true if a single match is found + */ + private List validatePlayer(String playerName, CommandSender sender) { + + List players = new ArrayList(); + List match = new ArrayList(); + + players = this.getServer().matchPlayer(playerName); + if (players.isEmpty()) { + // Check for an offline player (exact match). + if (Arrays.asList(this.getServer().getOfflinePlayers()).contains(Bukkit.getOfflinePlayer(playerName))) { + match.add(playerName); + } else { + // look for partial matches + for (OfflinePlayer offline : this.getServer().getOfflinePlayers()) { + if (offline.getName().toLowerCase().startsWith(playerName.toLowerCase())) + match.add(offline.getName()); + } + } + + } else { + for (Player player : players) { + match.add(player.getName()); + } + } + + if (match.isEmpty() || match == null) { + sender.sendMessage(ChatColor.RED + "Player not found!"); + return null; + } else if (match.size() > 1) { + sender.sendMessage(ChatColor.RED + "Too many matches found! (" + match.toString() + ")"); + return null; + } + + return match; + + } + + /** + * @return the config + */ + public GMConfiguration getGMConfig() { + + return config; + } + + /** + * @return the backupFolder + */ + public File getBackupFolder() { + + return backupFolder; + } + + public static GlobalGroups getGlobalGroups() { + + return globalGroups; + + } + + public static GroupManagerEventHandler getGMEventHandler() { + + return GMEventHandler; + } + + public static void setGMEventHandler(GroupManagerEventHandler gMEventHandler) { + + GMEventHandler = gMEventHandler; + } +} diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/Tasks/BukkitPermsUpdateTask.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/Tasks/BukkitPermsUpdateTask.java new file mode 100644 index 0000000000..1a0fc23696 --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/Tasks/BukkitPermsUpdateTask.java @@ -0,0 +1,29 @@ +package org.anjocaido.groupmanager.Tasks; + +import org.anjocaido.groupmanager.GroupManager; + +/* + * + * Created by ElgarL + */ + +public class BukkitPermsUpdateTask implements Runnable { + + public BukkitPermsUpdateTask() { + + super(); + } + + @Override + public void run() { + + // Signal loaded and update BukkitPermissions. + GroupManager.setLoaded(true); + GroupManager.BukkitPermissions.collectPermissions(); + GroupManager.BukkitPermissions.updateAllPlayers(); + + GroupManager.logger.info("Bukkit Permissions Updated!"); + + } + +} \ No newline at end of file diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/DataUnit.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/DataUnit.java new file mode 100644 index 0000000000..90fd28e8d5 --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/DataUnit.java @@ -0,0 +1,205 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.anjocaido.groupmanager.data; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.anjocaido.groupmanager.GroupManager; +import org.anjocaido.groupmanager.dataholder.WorldDataHolder; +import org.anjocaido.groupmanager.utils.StringPermissionComparator; + +/** + * + * @author gabrielcouto + */ +public abstract class DataUnit { + + private WorldDataHolder dataSource; + private String uUID; + private String lastName; + private boolean changed, sorted = false; + private List permissions = Collections.unmodifiableList(Collections.emptyList()); + + public DataUnit(WorldDataHolder dataSource, String name) { + + this.dataSource = dataSource; + this.uUID = name; + } + + public DataUnit(String name) { + + this.uUID = name; + } + + /** + * Every group is matched only by their names and DataSources names. + * + * @param o + * @return true if they are equal. false if not. + */ + @Override + public boolean equals(Object o) { + + if (o instanceof DataUnit) { + DataUnit go = (DataUnit) o; + if (this.getUUID().equalsIgnoreCase(go.getUUID())) { + // Global Group match. + if (this.dataSource == null && go.getDataSource() == null) + return true; + // This is a global group, the object to test isn't. + if (this.dataSource == null && go.getDataSource() != null) + return false; + // This is not a global group, but the object to test is. + if (this.dataSource != null && go.getDataSource() == null) + return false; + // Match on group name and world name. + if (this.dataSource.getName().equalsIgnoreCase(go.getDataSource().getName())) + return true; + } + } + return false; + } + + @Override + public int hashCode() { + + int hash = 5; + hash = 71 * hash + (this.uUID != null ? this.uUID.toLowerCase().hashCode() : 0); + return hash; + } + + /** + * Set the data source to point to a different worldDataHolder + * + * @param source + */ + public void setDataSource(WorldDataHolder source) { + + this.dataSource = source; + } + + /** + * Get the current worldDataHolder this object is pointing to + * + * @return the dataSource + */ + public WorldDataHolder getDataSource() { + + return dataSource; + } + + public String getUUID() { + + return uUID; + } + + public String getLastName() { + + if (uUID.length() < 36) + return this.uUID; + + return this.lastName; + } + + public void setLastName(String lastName) { + + if (!lastName.equals(this.lastName)) { + + this.lastName = lastName; + changed = true; + + } + + } + + public void flagAsChanged() { + + WorldDataHolder testSource = getDataSource(); + String source = ""; + + if (testSource == null) + source = "GlobalGroups"; + else + source = testSource.getName(); + + GroupManager.logger.finest("DataSource: " + source + " - DataUnit: " + getUUID() + " flagged as changed!"); + // for(StackTraceElement st: Thread.currentThread().getStackTrace()){ + // GroupManager.logger.finest(st.toString()); + // } + sorted = false; + changed = true; + } + + public boolean isChanged() { + + return changed; + } + + public void flagAsSaved() { + + WorldDataHolder testSource = getDataSource(); + String source = ""; + + if (testSource == null) + source = "GlobalGroups"; + else + source = testSource.getName(); + + GroupManager.logger.finest("DataSource: " + source + " - DataUnit: " + getUUID() + " flagged as saved!"); + changed = false; + } + + public boolean hasSamePermissionNode(String permission) { + + return permissions.contains(permission); + } + + public void addPermission(String permission) { + + if (!hasSamePermissionNode(permission)) { + List clone = new ArrayList(permissions); + clone.add(permission); + permissions = Collections.unmodifiableList(clone); + } + flagAsChanged(); + } + + public boolean removePermission(String permission) { + + flagAsChanged(); + List clone = new ArrayList(permissions); + boolean ret = clone.remove(permission); + permissions = Collections.unmodifiableList(clone); + return ret; + } + + /** + * Use this only to list permissions. + * You can't edit the permissions using the returned ArrayList instance + * + * @return a copy of the permission list + */ + public List getPermissionList() { + sortPermissions(); + return permissions; + } + + public boolean isSorted() { + + return this.sorted; + } + + public void sortPermissions() { + + if (!isSorted()) { + List clone = new ArrayList(permissions); + Collections.sort(clone, StringPermissionComparator.getInstance()); + permissions = Collections.unmodifiableList(clone); + sorted = true; + } + } +} \ No newline at end of file diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/Group.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/Group.java new file mode 100644 index 0000000000..d07edcef20 --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/Group.java @@ -0,0 +1,200 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.anjocaido.groupmanager.data; + +import org.anjocaido.groupmanager.GroupManager; +import org.anjocaido.groupmanager.dataholder.WorldDataHolder; +import org.anjocaido.groupmanager.events.GMGroupEvent.Action; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * + * @author gabrielcouto/ElgarL + */ +public class Group extends DataUnit implements Cloneable { + + /** + * The group it inherits DIRECTLY! + */ + private List inherits = Collections.unmodifiableList(Collections.emptyList()); + /** + * This one holds the fields in INFO node. + * like prefix = 'c' + * or build = false + */ + private GroupVariables variables = new GroupVariables(this); + + /** + * Constructor for individual World Groups. + * + * @param name + */ + public Group(WorldDataHolder source, String name) { + + super(source, name); + } + + /** + * Constructor for Global Groups. + * + * @param name + */ + public Group(String name) { + + super(name); + } + + /** + * @return the name + */ + public String getName() { + + return this.getUUID(); + } + + /** + * Is this a GlobalGroup + * + * @return true if this is a global group + */ + public boolean isGlobal() { + + return (getDataSource() == null); + } + + /** + * Clone this group + * + * @return a clone of this group + */ + @Override + public Group clone() { + + Group clone; + + if (isGlobal()) { + clone = new Group(this.getName()); + } else { + clone = new Group(getDataSource(), this.getName()); + clone.inherits = this.getInherits().isEmpty() ? + Collections.unmodifiableList(Collections.emptyList()) + : Collections.unmodifiableList(new ArrayList(this.getInherits())); + } + + for (String perm : this.getPermissionList()) { + clone.addPermission(perm); + } + clone.variables = ((GroupVariables) variables).clone(clone); + //clone.flagAsChanged(); + return clone; + } + + /** + * Use this to deliver a group from a different dataSource to another + * + * @param dataSource + * @return Null or Clone + */ + public Group clone(WorldDataHolder dataSource) { + + if (dataSource.groupExists(this.getName())) { + return null; + } + + Group clone = dataSource.createGroup(this.getName()); + + // Don't add inheritance for GlobalGroups + if (!isGlobal()) { + clone.inherits = this.getInherits().isEmpty() ? + Collections.unmodifiableList(Collections.emptyList()) + : Collections.unmodifiableList(new ArrayList(this.getInherits())); + } + for (String perm : this.getPermissionList()) { + clone.addPermission(perm); + } + clone.variables = variables.clone(clone); + clone.flagAsChanged(); //use this to make the new dataSource save the new group + return clone; + } + + /** + * an unmodifiable list of inherits list + * You can't manage the list by here + * Lol... version 0.6 had a problem because this. + * + * @return the inherits + */ + public List getInherits() { + return inherits; + } + + /** + * @param inherit the inherits to set + */ + public void addInherits(Group inherit) { + + if (!isGlobal()) { + if (!this.getDataSource().groupExists(inherit.getName())) { + getDataSource().addGroup(inherit); + } + if (!inherits.contains(inherit.getName().toLowerCase())) { + List clone = new ArrayList(inherits); + clone.add(inherit.getName().toLowerCase()); + inherits = Collections.unmodifiableList(clone); + } + flagAsChanged(); + if (GroupManager.isLoaded()) { + GroupManager.BukkitPermissions.updateAllPlayers(); + GroupManager.getGMEventHandler().callEvent(this, Action.GROUP_INHERITANCE_CHANGED); + } + } + } + + public boolean removeInherits(String inherit) { + + if (!isGlobal()) { + if (this.inherits.contains(inherit.toLowerCase())) { + List clone = new ArrayList(inherits); + clone.remove(inherit.toLowerCase()); + inherits = Collections.unmodifiableList(clone); + flagAsChanged(); + GroupManager.getGMEventHandler().callEvent(this, Action.GROUP_INHERITANCE_CHANGED); + return true; + } + } + return false; + } + + /** + * @return the variables + */ + public GroupVariables getVariables() { + + return variables; + } + + /** + * + * @param varList + */ + public void setVariables(Map varList) { + + if (!isGlobal()) { + GroupVariables temp = new GroupVariables(this, varList); + variables.clearVars(); + for (String key : temp.getVarKeyList()) { + variables.addVar(key, temp.getVarObject(key)); + } + flagAsChanged(); + if (GroupManager.isLoaded()) { + GroupManager.BukkitPermissions.updateAllPlayers(); + GroupManager.getGMEventHandler().callEvent(this, Action.GROUP_INFO_CHANGED); + } + } + } +} diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/GroupVariables.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/GroupVariables.java new file mode 100644 index 0000000000..588d501166 --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/GroupVariables.java @@ -0,0 +1,97 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.anjocaido.groupmanager.data; + +import java.util.Map; + +/** + * + * @author gabrielcouto + */ +public class GroupVariables extends Variables implements Cloneable { + + private Group owner; + + public GroupVariables(Group owner) { + + super(owner); + this.owner = owner; + addVar("prefix", ""); + addVar("suffix", ""); + addVar("build", false); + } + + public GroupVariables(Group owner, Map varList) { + + super(owner); + variables.clear(); + variables.putAll(varList); + if (variables.get("prefix") == null) { + variables.put("prefix", ""); + owner.flagAsChanged(); + } + //thisGrp.prefix = infoNode.get("prefix").toString(); + + if (variables.get("suffix") == null) { + variables.put("suffix", ""); + owner.flagAsChanged(); + } + //thisGrp.suffix = infoNode.get("suffix").toString(); + + if (variables.get("build") == null) { + variables.put("build", false); + owner.flagAsChanged(); + } + this.owner = owner; + } + + /** + * A clone of all vars here. + * + * @return GroupVariables clone + */ + protected GroupVariables clone(Group newOwner) { + + GroupVariables clone = new GroupVariables(newOwner); + synchronized(variables) { + for (String key : variables.keySet()) { + clone.variables.put(key, variables.get(key)); + } + } + newOwner.flagAsChanged(); + return clone; + } + + /** + * Remove a var from the list + * + * @param name + */ + @Override + public void removeVar(String name) { + + try { + this.variables.remove(name); + } catch (Exception e) { + } + if (name.equals("prefix")) { + addVar("prefix", ""); + } else if (name.equals("suffix")) { + addVar("suffix", ""); + } else if (name.equals("build")) { + addVar("build", false); + } + owner.flagAsChanged(); + } + + /** + * @return the owner + */ + @Override + public Group getOwner() { + + return owner; + } +} diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/User.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/User.java new file mode 100644 index 0000000000..83e1701373 --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/User.java @@ -0,0 +1,323 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.anjocaido.groupmanager.data; + +//import com.sun.org.apache.bcel.internal.generic.AALOAD; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.anjocaido.groupmanager.GroupManager; +import org.anjocaido.groupmanager.dataholder.WorldDataHolder; +import org.anjocaido.groupmanager.events.GMUserEvent.Action; +import java.util.Map; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +/** + * + * @author gabrielcouto/ElgarL + */ +public class User extends DataUnit implements Cloneable { + + /** + * + */ + private String group = null; + private final List subGroups = Collections.synchronizedList(new ArrayList()); + /** + * This one holds the fields in INFO node. like prefix = 'c' or build = + * false + */ + private UserVariables variables = new UserVariables(this); + private transient Player bukkitPlayer = null; + + /** + * + * @param name + */ + public User(WorldDataHolder source, String name) { + + super(source, name); + this.group = source.getDefaultGroup().getName(); + } + + /** + * + * @return User clone + */ + @Override + public User clone() { + + User clone = new User(getDataSource(), this.getLastName()); + clone.group = this.group; + + // Clone all subgroups. + clone.subGroups.addAll(this.subGroupListStringCopy()); + + for (String perm : this.getPermissionList()) { + clone.addPermission(perm); + } + // clone.variables = this.variables.clone(); + // clone.flagAsChanged(); + return clone; + } + + /** + * Use this to deliver a user from one WorldDataHolder to another + * + * @param dataSource + * @return null if given dataSource already contains the same user + */ + public User clone(WorldDataHolder dataSource) { + + if (dataSource.isUserDeclared(this.getUUID())) { + return null; + } + + User clone = dataSource.createUser(this.getUUID()); + + if (dataSource.getGroup(group) == null) { + clone.setGroup(dataSource.getDefaultGroup()); + } else { + clone.setGroup(dataSource.getGroup(this.getGroupName())); + } + + // Clone all subgroups. + clone.subGroups.addAll(this.subGroupListStringCopy()); + + for (String perm : this.getPermissionList()) { + clone.addPermission(perm); + } + + clone.variables = this.variables.clone(this); + clone.flagAsChanged(); + return clone; + } + + public User clone(String uUID, String CurrentName) { + + User clone = this.getDataSource().createUser(uUID); + + clone.setLastName(CurrentName); + + // Set the group silently. + clone.setGroup(this.getDataSource().getGroup(this.getGroupName()), false); + + // Clone all subgroups. + clone.subGroups.addAll(this.subGroupListStringCopy()); + + for (String perm : this.getPermissionList()) { + clone.addPermission(perm); + } + + clone.variables = this.variables.clone(this); + clone.flagAsChanged(); + + return clone; + } + + public Group getGroup() { + + Group result = getDataSource().getGroup(group); + if (result == null) { + this.setGroup(getDataSource().getDefaultGroup()); + result = getDataSource().getDefaultGroup(); + } + return result; + } + + /** + * @return the group + */ + public String getGroupName() { + + Group result = getDataSource().getGroup(group); + if (result == null) { + group = getDataSource().getDefaultGroup().getName(); + } + return group; + } + + /** + * Place holder to let people know to stop using this method. + * + * @deprecated use {@link #getLastName()} and {@link #getUUID()}. + * @return a string containing the players last known name. + */ + @Deprecated + public String getName() { + + return this.getLastName(); + + } + + + /** + * @param group + * the group to set + */ + public void setGroup(Group group) { + + setGroup(group, true); + } + + /** + * @param group the group to set + * @param updatePerms if we are to trigger a superperms update. + * + */ + public void setGroup(Group group, Boolean updatePerms) { + + if (!this.getDataSource().groupExists(group.getName())) { + getDataSource().addGroup(group); + } + group = getDataSource().getGroup(group.getName()); + String oldGroup = this.group; + this.group = group.getName(); + flagAsChanged(); + if (GroupManager.isLoaded()) { + if (!GroupManager.BukkitPermissions.isPlayer_join() && (updatePerms)) + GroupManager.BukkitPermissions.updatePlayer(getBukkitPlayer()); + + // Do we notify of the group change? + String defaultGroupName = getDataSource().getDefaultGroup().getName(); + // if we were not in the default group + // or we were in the default group and the move is to a different + // group. + boolean notify = (!oldGroup.equalsIgnoreCase(defaultGroupName)) || ((oldGroup.equalsIgnoreCase(defaultGroupName)) && (!this.group.equalsIgnoreCase(defaultGroupName))); + + if (notify) + GroupManager.notify(this.getLastName(), String.format(" moved to the group %s in %s.", group.getName(), this.getDataSource().getName())); + + if (updatePerms) + GroupManager.getGMEventHandler().callEvent(this, Action.USER_GROUP_CHANGED); + } + } + + public boolean addSubGroup(Group subGroup) { + + // Don't allow adding a subgroup if it's already set as the primary. + if (this.group.equalsIgnoreCase(subGroup.getName())) { + return false; + } + // User already has this subgroup + if (containsSubGroup(subGroup)) + return false; + + // If the group doesn't exists add it + if (!this.getDataSource().groupExists(subGroup.getName())) { + getDataSource().addGroup(subGroup); + } + + subGroups.add(subGroup.getName()); + flagAsChanged(); + if (GroupManager.isLoaded()) { + if (!GroupManager.BukkitPermissions.isPlayer_join()) + GroupManager.BukkitPermissions.updatePlayer(getBukkitPlayer()); + GroupManager.getGMEventHandler().callEvent(this, Action.USER_SUBGROUP_CHANGED); + } + return true; + + //subGroup = getDataSource().getGroup(subGroup.getName()); + //removeSubGroup(subGroup); + //subGroups.add(subGroup.getName()); + } + + public int subGroupsSize() { + + return subGroups.size(); + } + + public boolean isSubGroupsEmpty() { + + return subGroups.isEmpty(); + } + + public boolean containsSubGroup(Group subGroup) { + + return subGroups.contains(subGroup.getName()); + } + + public boolean removeSubGroup(Group subGroup) { + + try { + if (subGroups.remove(subGroup.getName())) { + flagAsChanged(); + if (GroupManager.isLoaded()) + if (!GroupManager.BukkitPermissions.isPlayer_join()) + GroupManager.BukkitPermissions.updatePlayer(getBukkitPlayer()); + GroupManager.getGMEventHandler().callEvent(this, Action.USER_SUBGROUP_CHANGED); + return true; + } + } catch (Exception e) { + } + return false; + } + + public ArrayList subGroupListCopy() { + + ArrayList val = new ArrayList(); + synchronized(subGroups) { + for (String gstr : subGroups) { + Group g = getDataSource().getGroup(gstr); + if (g == null) { + removeSubGroup(g); + continue; + } + val.add(g); + } + } + return val; + } + + public ArrayList subGroupListStringCopy() { + synchronized(subGroups) { + return new ArrayList(subGroups); + } + } + + /** + * @return the variables + */ + public UserVariables getVariables() { + + return variables; + } + + /** + * + * @param varList + */ + public void setVariables(Map varList) { + + //UserVariables temp = new UserVariables(this, varList); + variables.clearVars(); + for (String key : varList.keySet()) { + variables.addVar(key, varList.get(key)); + } + flagAsChanged(); + if (GroupManager.isLoaded()) { + //if (!GroupManager.BukkitPermissions.isPlayer_join()) + // GroupManager.BukkitPermissions.updatePlayer(this.getName()); + GroupManager.getGMEventHandler().callEvent(this, Action.USER_INFO_CHANGED); + } + } + + + public User updatePlayer(Player player) { + + bukkitPlayer = player; + return this; + } + + public Player getBukkitPlayer() { + + if (bukkitPlayer == null) { + bukkitPlayer = Bukkit.getPlayer(this.getLastName()); + } + return bukkitPlayer; + } +} diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/UserVariables.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/UserVariables.java new file mode 100644 index 0000000000..05c3aecee2 --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/UserVariables.java @@ -0,0 +1,56 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.anjocaido.groupmanager.data; + +import java.util.Map; + +/** + * + * @author gabrielcouto + */ +public class UserVariables extends Variables { + + private User owner; + + public UserVariables(User owner) { + + super(owner); + this.owner = owner; + } + + public UserVariables(User owner, Map varList) { + + super(owner); + this.variables.clear(); + this.variables.putAll(varList); + this.owner = owner; + } + + /** + * A clone of all vars here. + * + * @return UserVariables clone + */ + protected UserVariables clone(User newOwner) { + + UserVariables clone = new UserVariables(newOwner); + synchronized(variables) { + for (String key : variables.keySet()) { + clone.variables.put(key, variables.get(key)); + } + } + newOwner.flagAsChanged(); + return clone; + } + + /** + * @return the owner + */ + @Override + public User getOwner() { + + return owner; + } +} diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/Variables.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/Variables.java new file mode 100644 index 0000000000..8e1a54b98f --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/Variables.java @@ -0,0 +1,209 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.anjocaido.groupmanager.data; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * A class that holds variables of a user/group. + * In groups, it holds the contents of INFO node. + * Like: + * prefix + * suffix + * build + * + * @author gabrielcouto + */ +public abstract class Variables implements Cloneable { + + private DataUnit owner; + protected final Map variables = Collections.synchronizedMap(new HashMap()); + + public Variables(DataUnit owner) { + + this.owner = owner; + } + + /** + * Add var to the the INFO node. + * examples: + * addVar("build",true); + * addVar("prefix","c"); + * + * @param name key name of the var + * @param o the object value of the var + */ + public void addVar(String name, Object o) { + + if (o == null) { + return; + } + if (variables.containsKey(name)) { + variables.remove(name); + } + variables.put(name, o); + owner.flagAsChanged(); + } + + /** + * Returns the object inside the var + * + * @param name + * @return a Object if exists. null if doesn't exists + */ + public Object getVarObject(String name) { + + return variables.get(name); + } + + /** + * Get the String value for the given var name + * + * @param name the var key name + * @return "" if null. or the toString() value of object + */ + public String getVarString(String name) { + + Object o = variables.get(name); + try { + return o == null ? "" : o.toString(); + } catch (Exception e) { + return ""; + } + } + + /** + * + * @param name + * @return false if null. or a Boolean.parseBoolean of the string + */ + public Boolean getVarBoolean(String name) { + + Object o = variables.get(name); + try { + return o == null ? false : Boolean.parseBoolean(o.toString()); + } catch (Exception e) { + return false; + } + } + + /** + * + * @param name + * @return -1 if null. or a parseInt of the string + */ + public Integer getVarInteger(String name) { + + Object o = variables.get(name); + try { + return o == null ? -1 : Integer.parseInt(o.toString()); + } catch (Exception e) { + return -1; + } + } + + /** + * + * @param name + * @return -1 if null. or a parseDouble of the string + */ + public Double getVarDouble(String name) { + + Object o = variables.get(name); + try { + return o == null ? -1.0D : Double.parseDouble(o.toString()); + } catch (Exception e) { + return -1.0D; + } + } + + /** + * All variable keys this is holding + * + * @return Set of all variable names. + */ + public String[] getVarKeyList() { + synchronized(variables) { + return variables.keySet().toArray(new String[0]); + } + } + + /** + * verify is a var exists + * + * @param name the key name of the var + * @return true if that var exists + */ + public boolean hasVar(String name) { + + return variables.containsKey(name); + } + + /** + * Returns the quantity of vars this is holding + * + * @return the number of vars + */ + public int getSize() { + + return variables.size(); + } + + /** + * Remove a var from the list + * + * @param name + */ + public void removeVar(String name) { + + try { + variables.remove(name); + } catch (Exception e) { + } + owner.flagAsChanged(); + } + + public static Object parseVariableValue(String value) { + + try { + Integer i = Integer.parseInt(value); + return i; + } catch (NumberFormatException e) { + } + try { + Double d = Double.parseDouble(value); + return d; + } catch (NumberFormatException e) { + } + if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("yes") || value.equalsIgnoreCase("on")) { + return true; + } else if (value.equalsIgnoreCase("false") || value.equalsIgnoreCase("no") || value.equalsIgnoreCase("off")) { + return false; + } + return value; + + } + + public void clearVars() { + + variables.clear(); + owner.flagAsChanged(); + } + + /** + * @return the owner + */ + public DataUnit getOwner() { + + return owner; + } + + public boolean isEmpty() { + + return variables.isEmpty(); + } +} diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/GroupsDataHolder.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/GroupsDataHolder.java new file mode 100644 index 0000000000..1ae4d06bc3 --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/GroupsDataHolder.java @@ -0,0 +1,131 @@ +package org.anjocaido.groupmanager.dataholder; + +import java.io.File; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.anjocaido.groupmanager.data.Group; + +/** + * This container holds all Groups loaded from the relevant groupsFile. + * + * @author ElgarL + * + */ +public class GroupsDataHolder { + + private WorldDataHolder dataSource; + private Group defaultGroup = null; + private File groupsFile; + private boolean haveGroupsChanged = false; + private long timeStampGroups = 0; + + /** + * The actual groups holder + */ + private final Map groups = Collections.synchronizedMap(new HashMap()); + + /** + * Constructor + */ + protected GroupsDataHolder() { + + } + + public void setDataSource(WorldDataHolder dataSource) { + + this.dataSource = dataSource; + //push this data source to the users, so they pull the correct groups data. + synchronized(groups) { + for (Group group : groups.values()) + group.setDataSource(this.dataSource); + } + } + + public WorldDataHolder getDataSource() { + + return this.dataSource; + } + + /** + * @return the defaultGroup + */ + public Group getDefaultGroup() { + + return defaultGroup; + } + + /** + * @param defaultGroup the defaultGroup to set + */ + public void setDefaultGroup(Group defaultGroup) { + + this.defaultGroup = defaultGroup; + } + + /** + * Note: Iteration over this object has to be synchronized! + * @return the groups + */ + public Map getGroups() { + + return groups; + } + + /** + * Resets the Groups + */ + public void resetGroups() { + this.groups.clear(); + } + + /** + * @return the groupsFile + */ + public File getGroupsFile() { + + return groupsFile; + } + + /** + * @param groupsFile the groupsFile to set + */ + public void setGroupsFile(File groupsFile) { + + this.groupsFile = groupsFile; + } + + /** + * @return the haveGroupsChanged + */ + public boolean HaveGroupsChanged() { + + return haveGroupsChanged; + } + + /** + * @param haveGroupsChanged the haveGroupsChanged to set + */ + public void setGroupsChanged(boolean haveGroupsChanged) { + + this.haveGroupsChanged = haveGroupsChanged; + } + + /** + * @return the timeStampGroups + */ + public long getTimeStampGroups() { + + return timeStampGroups; + } + + /** + * @param timeStampGroups the timeStampGroups to set + */ + public void setTimeStampGroups(long timeStampGroups) { + + this.timeStampGroups = timeStampGroups; + } + +} diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/OverloadedWorldHolder.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/OverloadedWorldHolder.java new file mode 100644 index 0000000000..6b494b03c8 --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/OverloadedWorldHolder.java @@ -0,0 +1,220 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.anjocaido.groupmanager.dataholder; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import org.anjocaido.groupmanager.data.User; + +/** + * + * @author gabrielcouto + */ +public class OverloadedWorldHolder extends WorldDataHolder { + + /** + * + */ + protected final Map overloadedUsers = Collections.synchronizedMap(new HashMap()); + + /** + * + * @param ph + */ + public OverloadedWorldHolder(WorldDataHolder ph) { + + super(ph.getName()); + this.setGroupsFile(ph.getGroupsFile()); + this.setUsersFile(ph.getUsersFile()); + this.groups = ph.groups; + this.users = ph.users; + } + + /** + * + * @param userName + * @return user object or a new user if none exists. + */ + @Override + public User getUser(String userName) { + + //OVERLOADED CODE + String userNameLowered = userName.toLowerCase(); + if (overloadedUsers.containsKey(userNameLowered)) { + return overloadedUsers.get(userNameLowered); + } + //END CODE + + return super.getUser(userName); + } + + /** + * + * @param theUser + */ + @Override + public void addUser(User theUser) { + + if (theUser.getDataSource() != this) { + theUser = theUser.clone(this); + } + if (theUser == null) { + return; + } + if ((theUser.getGroup() == null) || (!getGroups().containsKey(theUser.getGroupName().toLowerCase()))) { + theUser.setGroup(getDefaultGroup()); + } + //OVERLOADED CODE + if (overloadedUsers.containsKey(theUser.getUUID().toLowerCase())) { + overloadedUsers.remove(theUser.getUUID().toLowerCase()); + overloadedUsers.put(theUser.getUUID().toLowerCase(), theUser); + return; + } + //END CODE + removeUser(theUser.getUUID()); + getUsers().put(theUser.getUUID().toLowerCase(), theUser); + setUsersChanged(true); + } + + /** + * + * @param userId + * @return true if removed/false if not found. + */ + @Override + public boolean removeUser(String userId) { + + //OVERLOADED CODE + if (overloadedUsers.containsKey(userId.toLowerCase())) { + overloadedUsers.remove(userId.toLowerCase()); + return true; + } + //END CODE + if (getUsers().containsKey(userId.toLowerCase())) { + getUsers().remove(userId.toLowerCase()); + setUsersChanged(true); + return true; + } + return false; + } + + @Override + public boolean removeGroup(String groupName) { + + if (groupName.equals(getDefaultGroup())) { + return false; + } + synchronized(getGroups()) { + for (String key : getGroups().keySet()) { + if (groupName.equalsIgnoreCase(key)) { + getGroups().remove(key); + synchronized(getUsers()) { + for (String userKey : getUsers().keySet()) { + User user = getUsers().get(userKey); + if (user.getGroupName().equalsIgnoreCase(key)) { + user.setGroup(getDefaultGroup()); + } + + } + } + //OVERLOADED CODE + synchronized(overloadedUsers) { + for (String userKey : overloadedUsers.keySet()) { + User user = overloadedUsers.get(userKey); + if (user.getGroupName().equalsIgnoreCase(key)) { + user.setGroup(getDefaultGroup()); + } + + } + } + //END OVERLOAD + setGroupsChanged(true); + return true; + } + } + } + return false; + } + + /** + * + * @return Collection of all users + */ + @Override + public Collection getUserList() { + + Collection overloadedList = new ArrayList(); + synchronized(getUsers()) { + Collection normalList = getUsers().values(); + for (User u : normalList) { + if (overloadedUsers.containsKey(u.getUUID().toLowerCase())) { + overloadedList.add(overloadedUsers.get(u.getUUID().toLowerCase())); + } else { + overloadedList.add(u); + } + } + } + return overloadedList; + } + + /** + * + * @param userId + * @return true if user is overloaded. + */ + public boolean isOverloaded(String userId) { + + return overloadedUsers.containsKey(userId.toLowerCase()); + } + + /** + * + * @param userId + */ + public void overloadUser(String userId) { + + if (!isOverloaded(userId)) { + User theUser = getUser(userId); + theUser = theUser.clone(); + if (overloadedUsers.containsKey(theUser.getUUID().toLowerCase())) { + overloadedUsers.remove(theUser.getUUID().toLowerCase()); + } + overloadedUsers.put(theUser.getUUID().toLowerCase(), theUser); + } + } + + /** + * + * @param userId + */ + public void removeOverload(String userId) { + + User theUser = getUser(userId); + overloadedUsers.remove(theUser.getUUID().toLowerCase()); + } + + /** + * Gets the user in normal state. Surpassing the overload state. + * It doesn't affect permissions. But it enables plugins change the + * actual user permissions even in overload mode. + * + * @param userId + * @return user object + */ + public User surpassOverload(String userId) { + + if (!isOverloaded(userId)) { + return getUser(userId); + } + if (getUsers().containsKey(userId.toLowerCase())) { + return getUsers().get(userId.toLowerCase()); + } + User newUser = createUser(userId); + return newUser; + } +} \ No newline at end of file diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/UsersDataHolder.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/UsersDataHolder.java new file mode 100644 index 0000000000..ee822f1aff --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/UsersDataHolder.java @@ -0,0 +1,114 @@ +package org.anjocaido.groupmanager.dataholder; + +import java.io.File; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.anjocaido.groupmanager.data.User; + +/** + * This container holds all Users loaded from the relevant usersFile. + * + * @author ElgarL + * + */ +public class UsersDataHolder { + + private WorldDataHolder dataSource; + private File usersFile; + private boolean haveUsersChanged = false; + private long timeStampUsers = 0; + + /** + * The actual groups holder + */ + private final Map users = Collections.synchronizedMap(new HashMap()); + + /** + * Constructor + */ + protected UsersDataHolder() { + + } + + public void setDataSource(WorldDataHolder dataSource) { + + this.dataSource = dataSource; + //push this data source to the users, so they pull the correct groups data. + synchronized(users) { + for (User user : users.values()) + user.setDataSource(this.dataSource); + } + } + + /** + * Note: Iteration over this object has to be synchronized! + * @return the users + */ + public Map getUsers() { + + return users; + } + + public WorldDataHolder getDataSource() { + + return this.dataSource; + } + + /** + * Resets the Users + */ + public void resetUsers() { + this.users.clear(); + } + + /** + * @return the usersFile + */ + public File getUsersFile() { + + return usersFile; + } + + /** + * @param usersFile the usersFile to set + */ + public void setUsersFile(File usersFile) { + + this.usersFile = usersFile; + } + + /** + * @return the haveUsersChanged + */ + public boolean HaveUsersChanged() { + + return haveUsersChanged; + } + + /** + * @param haveUsersChanged the haveUsersChanged to set + */ + public void setUsersChanged(boolean haveUsersChanged) { + + this.haveUsersChanged = haveUsersChanged; + } + + /** + * @return the timeStampUsers + */ + public long getTimeStampUsers() { + + return timeStampUsers; + } + + /** + * @param timeStampUsers the timeStampUsers to set + */ + public void setTimeStampUsers(long timeStampUsers) { + + this.timeStampUsers = timeStampUsers; + } + +} diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/WorldDataHolder.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/WorldDataHolder.java new file mode 100644 index 0000000000..f2a43d11e0 --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/WorldDataHolder.java @@ -0,0 +1,1448 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.anjocaido.groupmanager.dataholder; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeSet; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.anjocaido.groupmanager.GroupManager; +import org.anjocaido.groupmanager.data.Group; +import org.anjocaido.groupmanager.data.User; +import org.anjocaido.groupmanager.events.GMGroupEvent; +import org.anjocaido.groupmanager.events.GMSystemEvent; +import org.anjocaido.groupmanager.events.GMUserEvent; +import org.anjocaido.groupmanager.events.GMUserEvent.Action; +import org.anjocaido.groupmanager.permissions.AnjoPermissionsHandler; +import org.bukkit.Server; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginManager; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.SafeConstructor; +import org.yaml.snakeyaml.reader.UnicodeReader; + +/** + * One instance of this should exist per world/mirror it contains all functions + * to manage these data sets and points to the relevant users and groups + * objects. + * + * @author gabrielcouto, ElgarL + */ +public class WorldDataHolder { + + /** + * World name + */ + protected String name; + /** + * The actual groups holder + */ + protected GroupsDataHolder groups = new GroupsDataHolder(); + /** + * The actual users holder + */ + protected UsersDataHolder users = new UsersDataHolder(); + /** + * + */ + protected AnjoPermissionsHandler permissionsHandler; + + /** + * Prevent direct instantiation + * + * @param worldName + */ + public WorldDataHolder(String worldName) { + + name = worldName; + } + + /** + * The main constructor for a new WorldDataHolder + * + * @param worldName + * @param groups + * @param users + */ + public WorldDataHolder(String worldName, GroupsDataHolder groups, UsersDataHolder users) { + + this.name = worldName; + this.groups = groups; + this.users = users; + + // this.defaultGroup = defaultGroup; + } + + /** + * update the dataSource to point to this object. + * + * This should be called whenever a set of world data is fetched. + */ + public void updateDataSource() { + + this.groups.setDataSource(this); + this.users.setDataSource(this); + } + + /** + * Search for a user. If it doesn't exist, create a new one with default + * group. + * + * @param userId the UUID String or name of the user + * @return class that manage that user permission + */ + public User getUser(String userId) { + + if (getUsers().containsKey(userId.toLowerCase())) { + return getUsers().get(userId.toLowerCase()); + } + + // Legacy name matching + if (userId.length() < 36) { + + // Search for a LastName match + for (User user : getUserList()) { + + if (user.getLastName().equalsIgnoreCase(userId)) { + return user; + } + } + + } + + // No user account found so create a new one. + User newUser = createUser(userId); + + return newUser; + } + + /** + * *** Internal GM use only *** + * This is called when a player joins to update/add their UUID. + * + * @param uUID the player objects UUID. + * @param currentName the name they have just logged in with. + * @return the user object for this player. + */ + public User getUser(String uUID, String currentName) { + + // Check for a UUID account + User user = getUsers().get(uUID.toLowerCase()); + + if (user != null) { + + user.setLastName(currentName); + return user; + + } + + // Search for a LastName match + for (User usr : getUserList()) { + + if (usr.getLastName().equalsIgnoreCase(currentName) && usr.getUUID().equalsIgnoreCase(usr.getLastName())) { + + // Clone this user so we can set it's uUID + user = usr.clone(uUID, currentName); + + // Delete it and replace with the new clone. + this.removeUser(usr.getUUID()); + this.addUser(user); + + return getUsers().get(uUID.toLowerCase()); + } + + } + + + // No user account found so create a new one. + User newUser = createUser(uUID); + newUser.setLastName(currentName); + + return newUser; + } + + /** + * Add a user to the list. If it already exists, overwrite the old. + * + * @param theUser the user you want to add to the permission list + */ + public void addUser(User theUser) { + + if (theUser.getDataSource() != this) { + theUser = theUser.clone(this); + } + if (theUser == null) { + return; + } + if ((theUser.getGroup() == null)) { + theUser.setGroup(groups.getDefaultGroup()); + } + removeUser(theUser.getUUID()); + getUsers().put(theUser.getUUID().toLowerCase(), theUser); + setUsersChanged(true); + if (GroupManager.isLoaded()) + GroupManager.getGMEventHandler().callEvent(theUser, Action.USER_ADDED); + } + + /** + * Removes the user from the list. (he might become a default user) + * + * @param userId the UUID or username for the user to remove + * @return true if it had something to remove + */ + public boolean removeUser(String userId) { + + if (getUsers().containsKey(userId.toLowerCase())) { + getUsers().remove(userId.toLowerCase()); + setUsersChanged(true); + if (GroupManager.isLoaded()) + GroupManager.getGMEventHandler().callEvent(userId, GMUserEvent.Action.USER_REMOVED); + return true; + } + return false; + } + + /** + * + * @param userId + * @return true if we have data for this player. + */ + public boolean isUserDeclared(String userId) { + + return getUsers().containsKey(userId.toLowerCase()); + } + + /** + * Change the default group of the file. + * + * @param group the group you want make default. + */ + public void setDefaultGroup(Group group) { + + if (!getGroups().containsKey(group.getName().toLowerCase()) || (group.getDataSource() != this)) { + addGroup(group); + } + groups.setDefaultGroup(getGroup(group.getName())); + setGroupsChanged(true); + if (GroupManager.isLoaded()) + GroupManager.getGMEventHandler().callEvent(GMSystemEvent.Action.DEFAULT_GROUP_CHANGED); + } + + /** + * Returns the default group of the file + * + * @return the default group + */ + public Group getDefaultGroup() { + + return groups.getDefaultGroup(); + } + + /** + * Returns a group of the given name + * + * @param groupName the name of the group + * @return a group if it is found. null if not found. + */ + public Group getGroup(String groupName) { + + if (groupName.toLowerCase().startsWith("g:")) + return GroupManager.getGlobalGroups().getGroup(groupName); + else + return getGroups().get(groupName.toLowerCase()); + } + + /** + * Check if a group exists. Its the same of getGroup, but check if it is + * null. + * + * @param groupName the name of the group + * @return true if exists. false if not. + */ + public boolean groupExists(String groupName) { + + if (groupName.toLowerCase().startsWith("g:")) + return GroupManager.getGlobalGroups().hasGroup(groupName); + else + return getGroups().containsKey(groupName.toLowerCase()); + } + + /** + * Add a group to the list + * + * @param groupToAdd + */ + public void addGroup(Group groupToAdd) { + + if (groupToAdd.getName().toLowerCase().startsWith("g:")) { + GroupManager.getGlobalGroups().addGroup(groupToAdd); + GroupManager.getGMEventHandler().callEvent(groupToAdd, GMGroupEvent.Action.GROUP_ADDED); + return; + } + + if (groupToAdd.getDataSource() != this) { + groupToAdd = groupToAdd.clone(this); + } + removeGroup(groupToAdd.getName()); + getGroups().put(groupToAdd.getName().toLowerCase(), groupToAdd); + setGroupsChanged(true); + if (GroupManager.isLoaded()) + GroupManager.getGMEventHandler().callEvent(groupToAdd, GMGroupEvent.Action.GROUP_ADDED); + } + + /** + * Remove the group from the list + * + * @param groupName + * @return true if had something to remove. false the group was default or + * non-existant + */ + public boolean removeGroup(String groupName) { + + if (groupName.toLowerCase().startsWith("g:")) { + return GroupManager.getGlobalGroups().removeGroup(groupName); + } + + if (getDefaultGroup() != null && groupName.equalsIgnoreCase(getDefaultGroup().getName())) { + return false; + } + if (getGroups().containsKey(groupName.toLowerCase())) { + getGroups().remove(groupName.toLowerCase()); + setGroupsChanged(true); + if (GroupManager.isLoaded()) + GroupManager.getGMEventHandler().callEvent(groupName.toLowerCase(), GMGroupEvent.Action.GROUP_REMOVED); + return true; + } + return false; + + } + + /** + * Creates a new User with the given name and adds it to this holder. + * + * @param userId the UUID or username you want + * @return null if user already exists. or new User + */ + public User createUser(String userId) { + + if (getUsers().containsKey(userId.toLowerCase())) { + return null; + } + User newUser = new User(this, userId); + newUser.setGroup(groups.getDefaultGroup(), false); + addUser(newUser); + setUsersChanged(true); + return newUser; + } + + /** + * Creates a new Group with the given name and adds it to this holder + * + * @param groupName the groupname you want + * @return null if group already exists. or new Group + */ + public Group createGroup(String groupName) { + + if (groupName.toLowerCase().startsWith("g:")) { + Group newGroup = new Group(groupName); + return GroupManager.getGlobalGroups().newGroup(newGroup); + } + + if (getGroups().containsKey(groupName.toLowerCase())) { + return null; + } + + Group newGroup = new Group(this, groupName); + addGroup(newGroup); + setGroupsChanged(true); + return newGroup; + } + + /** + * + * @return a collection of the groups + */ + public Collection getGroupList() { + + synchronized (getGroups()) { + return new ArrayList(getGroups().values()); + } + } + + /** + * + * @return a collection of the users + */ + public Collection getUserList() { + + synchronized (getUsers()) { + return new ArrayList(getUsers().values()); + } + } + + /** + * reads the file again + */ + public void reload() { + + try { + reloadGroups(); + reloadUsers(); + } catch (Exception ex) { + Logger.getLogger(WorldDataHolder.class.getName()).log(Level.SEVERE, null, ex); + } + } + + /** + * Refresh Group data from file + */ + public void reloadGroups() { + + GroupManager.setLoaded(false); + try { + // temporary holder in case the load fails. + WorldDataHolder ph = new WorldDataHolder(this.getName()); + + loadGroups(ph, getGroupsFile()); + // transfer new data + resetGroups(); + for (Group tempGroup : ph.getGroupList()) { + tempGroup.clone(this); + } + this.setDefaultGroup(getGroup(ph.getDefaultGroup().getName())); + this.removeGroupsChangedFlag(); + this.setTimeStampGroups(getGroupsFile().lastModified()); + + ph = null; + } catch (Exception ex) { + Logger.getLogger(WorldDataHolder.class.getName()).log(Level.WARNING, null, ex); + } + GroupManager.setLoaded(true); + GroupManager.getGMEventHandler().callEvent(GMSystemEvent.Action.RELOADED); + } + + /** + * Refresh Users data from file + */ + public void reloadUsers() { + + GroupManager.setLoaded(false); + try { + // temporary holder in case the load fails. + WorldDataHolder ph = new WorldDataHolder(this.getName()); + // copy groups for reference + for (Group tempGroup : this.getGroupList()) { + tempGroup.clone(ph); + } + // setup the default group before loading user data. + ph.setDefaultGroup(ph.getGroup(getDefaultGroup().getName())); + loadUsers(ph, getUsersFile()); + // transfer new data + resetUsers(); + for (User tempUser : ph.getUserList()) { + tempUser.clone(this); + } + this.removeUsersChangedFlag(); + this.setTimeStampUsers(getUsersFile().lastModified()); + + ph = null; + } catch (Exception ex) { + Logger.getLogger(WorldDataHolder.class.getName()).log(Level.WARNING, null, ex); + } + GroupManager.setLoaded(true); + GroupManager.getGMEventHandler().callEvent(GMSystemEvent.Action.RELOADED); + } + + public void loadGroups(File groupsFile) { + + GroupManager.setLoaded(false); + try { + setGroupsFile(groupsFile); + loadGroups(this, groupsFile); + } catch (FileNotFoundException e) { + e.printStackTrace(); + throw new IllegalArgumentException("The file which should contain groups does not exist!\n" + groupsFile.getPath()); + } catch (IOException e) { + e.printStackTrace(); + throw new IllegalArgumentException("Error accessing the groups file!\n" + groupsFile.getPath()); + } + + GroupManager.setLoaded(true); + } + + public void loadUsers(File usersFile) { + + GroupManager.setLoaded(false); + try { + setUsersFile(usersFile); + loadUsers(this, usersFile); + } catch (FileNotFoundException e) { + e.printStackTrace(); + throw new IllegalArgumentException("The file which should contain users does not exist!\n" + usersFile.getPath()); + } catch (IOException e) { + e.printStackTrace(); + throw new IllegalArgumentException("Error accessing the users file!\n" + usersFile.getPath()); + } + + GroupManager.setLoaded(true); + } + + /** + * Returns a NEW data holder containing data read from the files + * + * @param worldName + * @param groupsFile + * @param usersFile + * + * @throws FileNotFoundException + * @throws IOException + */ + public static WorldDataHolder load(String worldName, File groupsFile, File usersFile) throws FileNotFoundException, IOException { + + WorldDataHolder ph = new WorldDataHolder(worldName); + + GroupManager.setLoaded(false); + if (groupsFile != null) + loadGroups(ph, groupsFile); + if (usersFile != null) + loadUsers(ph, usersFile); + GroupManager.setLoaded(true); + + return ph; + } + + /** + * Updates the WorldDataHolder from the Groups file + * + * @param ph + * @param groupsFile + * + * @throws FileNotFoundException + * @throws IOException + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + protected static void loadGroups(WorldDataHolder ph, File groupsFile) throws FileNotFoundException, IOException { + + // READ GROUPS FILE + + Yaml yamlGroups = new Yaml(new SafeConstructor()); + Map groupsRootDataNode; + + if (!groupsFile.exists()) { + throw new IllegalArgumentException("The file which should contain groups does not exist!\n" + groupsFile.getPath()); + } + FileInputStream groupsInputStream = new FileInputStream(groupsFile); + try { + groupsRootDataNode = (Map) yamlGroups.load(new UnicodeReader(groupsInputStream)); + if (groupsRootDataNode == null) { + throw new NullPointerException(); + } + } catch (Exception ex) { + throw new IllegalArgumentException("The following file couldn't pass on Parser.\n" + groupsFile.getPath(), ex); + } finally { + groupsInputStream.close(); + } + + // PROCESS GROUPS FILE + + Map> inheritance = new HashMap>(); + Map allGroupsNode = null; + + /* + * Fetch all groups under the 'groups' entry. + */ + try { + allGroupsNode = (Map) groupsRootDataNode.get("groups"); + } catch (Exception ex) { + throw new IllegalArgumentException("Your " + groupsFile.getPath() + " file is invalid. See console for details.", ex); + } + + if (allGroupsNode == null) { + throw new IllegalArgumentException("You have no groups in " + groupsFile.getPath() + "."); + } + + Iterator groupItr = allGroupsNode.keySet().iterator(); + String groupKey; + Integer groupCount = 0; + + /* + * loop each group entry and process it's data. + */ + while (groupItr.hasNext()) { + + try { + groupCount++; + // Attempt to fetch the next group name. + groupKey = groupItr.next(); + } catch (Exception ex) { + throw new IllegalArgumentException("Invalid group name for group entry (" + groupCount + ") in file: " + groupsFile.getPath(), ex); + } + + /* + * Fetch this groups child nodes + */ + Map thisGroupNode = null; + + try { + thisGroupNode = (Map) allGroupsNode.get(groupKey); + } catch (Exception ex) { + throw new IllegalArgumentException("Invalid child nodes for group '" + groupKey + "' in file: " + groupsFile.getPath(), ex); + } + + /* + * Create a new group with this name in the assigned data source. + */ + Group thisGrp = ph.createGroup(groupKey); + + if (thisGrp == null) { + throw new IllegalArgumentException("I think this Group was declared more than once: " + groupKey + " in file: " + groupsFile.getPath()); + } + + // DEFAULT NODE + + Object nodeData = null; + try { + nodeData = thisGroupNode.get("default"); + } catch (Exception ex) { + throw new IllegalArgumentException("Bad format found in 'permissions' for group: " + groupKey + " in file: " + groupsFile.getPath()); + } + + if (nodeData == null) { + /* + * If no 'default' node is found do nothing. + */ + } else if ((Boolean.parseBoolean(nodeData.toString()))) { + /* + * Set this as the default group. Warn if some other group has + * already claimed that position. + */ + if (ph.getDefaultGroup() != null) { + GroupManager.logger.warning("The group '" + thisGrp.getName() + "' is claiming to be default where '" + ph.getDefaultGroup().getName() + "' already was."); + GroupManager.logger.warning("Overriding first default request in file: " + groupsFile.getPath()); + } + ph.setDefaultGroup(thisGrp); + } + + // PERMISSIONS NODE + + nodeData = null; + try { + nodeData = thisGroupNode.get("permissions"); + } catch (Exception ex) { + throw new IllegalArgumentException("Bad format found in 'permissions' for '" + groupKey + "' in file: " + groupsFile.getPath()); + } + + if (nodeData == null) { + /* + * If no permissions node is found, or it's empty do nothing. + */ + } else { + /* + * There is a permission list Which seems to hold some data + */ + if (nodeData instanceof List) { + /* + * Check each entry and add it as a new permission. + */ + try { + for (Object o : ((List) nodeData)) { + try { + /* + * Only add this permission if it's not empty. + */ + if (!o.toString().isEmpty()) + thisGrp.addPermission(o.toString()); + + } catch (NullPointerException ex) { + // Ignore this entry as it's null. It can be + // safely dropped + } + } + } catch (Exception ex) { + throw new IllegalArgumentException("Invalid formatting found in 'permissions' section for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath(), ex); + } + + } else if (nodeData instanceof String) { + /* + * Only add this permission if it's not empty. + */ + if (!nodeData.toString().isEmpty()) + thisGrp.addPermission((String) nodeData); + + } else { + throw new IllegalArgumentException("Unknown type of 'permissions' node(Should be String or List) for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath()); + } + /* + * Sort all permissions so they are in the correct order for + * checking. + */ + thisGrp.sortPermissions(); + } + + // INFO NODE + + nodeData = null; + try { + nodeData = thisGroupNode.get("info"); + } catch (Exception ex) { + throw new IllegalArgumentException("Bad format found in 'info' section for group: " + groupKey + " in file: " + groupsFile.getPath()); + } + + if (nodeData == null) { + /* + * No info section was found, so leave all variables as + * defaults. + */ + GroupManager.logger.warning("The group '" + thisGrp.getName() + "' has no 'info' section!"); + GroupManager.logger.warning("Using default values: " + groupsFile.getPath()); + + } else if (nodeData instanceof Map) { + try { + if (nodeData != null) { + thisGrp.setVariables((Map) nodeData); + } + } catch (Exception ex) { + throw new IllegalArgumentException("Invalid formatting found in 'info' section for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath(), ex); + } + + } else + throw new IllegalArgumentException("Unknown entry found in 'info' section for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath()); + + // INHERITANCE NODE + + nodeData = null; + try { + nodeData = thisGroupNode.get("inheritance"); + } catch (Exception ex) { + throw new IllegalArgumentException("Bad format found in 'inheritance' section for group: " + groupKey + " in file: " + groupsFile.getPath()); + } + + if (nodeData == null || nodeData instanceof List) { + if (nodeData == null) { + /* + * If no inheritance node is found, or it's empty do + * nothing. + */ + } else if (nodeData instanceof List) { + + try { + for (String grp : (List) nodeData) { + if (inheritance.get(groupKey) == null) { + inheritance.put(groupKey, new ArrayList()); + } + inheritance.get(groupKey).add(grp); + } + + } catch (Exception ex) { + throw new IllegalArgumentException("Invalid formatting found in 'inheritance' section for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath(), ex); + } + + } + } else + throw new IllegalArgumentException("Unknown entry found in 'inheritance' section for group: " + thisGrp.getName() + " in file: " + groupsFile.getPath()); + + // END GROUP + + } + + if (ph.getDefaultGroup() == null) { + throw new IllegalArgumentException("There was no Default Group declared in file: " + groupsFile.getPath()); + } + + /* + * Build the inheritance map and recored any errors + */ + for (String group : inheritance.keySet()) { + List inheritedList = inheritance.get(group); + Group thisGroup = ph.getGroup(group); + if (thisGroup != null) + for (String inheritedKey : inheritedList) { + if (inheritedKey != null) { + Group inheritedGroup = ph.getGroup(inheritedKey); + if (inheritedGroup != null) { + thisGroup.addInherits(inheritedGroup); + } else + GroupManager.logger.warning("Inherited group '" + inheritedKey + "' not found for group " + thisGroup.getName() + ". Ignoring entry in file: " + groupsFile.getPath()); + } + } + } + + ph.removeGroupsChangedFlag(); + // Update the LastModified time. + ph.setGroupsFile(groupsFile); + ph.setTimeStampGroups(groupsFile.lastModified()); + + // return ph; + } + + /** + * Updates the WorldDataHolder from the Users file + * + * @param ph + * @param usersFile + * + * @throws FileNotFoundException + * @throws IOException + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + protected static void loadUsers(WorldDataHolder ph, File usersFile) throws FileNotFoundException, IOException { + + // READ USERS FILE + Yaml yamlUsers = new Yaml(new SafeConstructor()); + Map usersRootDataNode; + if (!usersFile.exists()) { + throw new IllegalArgumentException("The file which should contain users does not exist!\n" + usersFile.getPath()); + } + FileInputStream usersInputStream = new FileInputStream(usersFile); + try { + usersRootDataNode = (Map) yamlUsers.load(new UnicodeReader(usersInputStream)); + if (usersRootDataNode == null) { + throw new NullPointerException(); + } + } catch (Exception ex) { + throw new IllegalArgumentException("The following file couldn't pass on Parser.\n" + usersFile.getPath(), ex); + } finally { + usersInputStream.close(); + } + + // PROCESS USERS FILE + + Map allUsersNode = null; + + /* + * Fetch all child nodes under the 'users' entry. + */ + try { + allUsersNode = (Map) usersRootDataNode.get("users"); + } catch (Exception ex) { + throw new IllegalArgumentException("Your " + usersFile.getPath() + " file is invalid. See console for details.", ex); + } + + // Load users if the file is NOT empty + + if (allUsersNode != null) { + + Iterator usersItr = allUsersNode.keySet().iterator(); + String usersKey; + Object node; + Integer userCount = 0; + + while (usersItr.hasNext()) { + try { + userCount++; + // Attempt to fetch the next user name. + node = usersItr.next(); + if (node instanceof Integer) + usersKey = Integer.toString((Integer) node); + else + usersKey = node.toString(); + + } catch (Exception ex) { + throw new IllegalArgumentException("Invalid node type for user entry (" + userCount + ") in file: " + usersFile.getPath(), ex); + } + + Map thisUserNode = null; + try { + thisUserNode = (Map) allUsersNode.get(node); + } catch (Exception ex) { + throw new IllegalArgumentException("Bad format found for user: " + usersKey + " in file: " + usersFile.getPath()); + } + + User thisUser = ph.createUser(usersKey); + if (thisUser == null) { + throw new IllegalArgumentException("I think this user was declared more than once: " + usersKey + " in file: " + usersFile.getPath()); + } + + // LASTNAME NODES + + Object nodeData = null; + try { + + nodeData = thisUserNode.get("lastname"); + + } catch (Exception ex) { + throw new IllegalArgumentException("Bad format found in 'subgroups' for user: " + usersKey + " in file: " + usersFile.getPath()); + } + + if ((nodeData != null) && (nodeData instanceof String)) { + + thisUser.setLastName((String) nodeData); + + } + + // USER PERMISSIONS NODES + + nodeData = null; + try { + nodeData = thisUserNode.get("permissions"); + } catch (Exception ex) { + throw new IllegalArgumentException("Bad format found in 'permissions' for user: " + usersKey + " in file: " + usersFile.getPath()); + } + + if (nodeData == null) { + /* + * If no permissions node is found, or it's empty do + * nothing. + */ + } else { + try { + if (nodeData instanceof List) { + for (Object o : ((List) nodeData)) { + /* + * Only add this permission if it's not empty + */ + if (!o.toString().isEmpty()) { + thisUser.addPermission(o.toString()); + } + } + } else if (nodeData instanceof String) { + + /* + * Only add this permission if it's not empty + */ + if (!nodeData.toString().isEmpty()) { + thisUser.addPermission(nodeData.toString()); + } + + } + } catch (NullPointerException e) { + // Ignore this entry as it's null. + } + thisUser.sortPermissions(); + } + + + // SUBGROUPS NODES + + nodeData = null; + try { + nodeData = thisUserNode.get("subgroups"); + } catch (Exception ex) { + throw new IllegalArgumentException("Bad format found in 'subgroups' for user: " + usersKey + " in file: " + usersFile.getPath()); + } + + if (nodeData == null) { + /* + * If no subgroups node is found, or it's empty do nothing. + */ + } else if (nodeData instanceof List) { + for (Object o : ((List) nodeData)) { + if (o == null) { + GroupManager.logger.warning("Invalid Subgroup data for user: " + thisUser.getLastName() + ". Ignoring entry in file: " + usersFile.getPath()); + } else { + Group subGrp = ph.getGroup(o.toString()); + if (subGrp != null) { + thisUser.addSubGroup(subGrp); + } else { + GroupManager.logger.warning("Subgroup '" + o.toString() + "' not found for user: " + thisUser.getLastName() + ". Ignoring entry in file: " + usersFile.getPath()); + } + } + } + } else if (nodeData instanceof String) { + Group subGrp = ph.getGroup(nodeData.toString()); + if (subGrp != null) { + thisUser.addSubGroup(subGrp); + } else { + GroupManager.logger.warning("Subgroup '" + nodeData.toString() + "' not found for user: " + thisUser.getLastName() + ". Ignoring entry in file: " + usersFile.getPath()); + } + } + + // USER INFO NODE + + nodeData = null; + try { + nodeData = thisUserNode.get("info"); + } catch (Exception ex) { + throw new IllegalArgumentException("Bad format found in 'info' section for user: " + usersKey + " in file: " + usersFile.getPath()); + } + + if (nodeData == null) { + /* + * If no info node is found, or it's empty do nothing. + */ + } else if (nodeData instanceof Map) { + thisUser.setVariables((Map) nodeData); + + } else + throw new IllegalArgumentException("Unknown entry found in 'info' section for user: " + thisUser.getLastName() + " in file: " + usersFile.getPath()); + + // END INFO NODE + + // PRIMARY GROUP + + nodeData = null; + try { + nodeData = thisUserNode.get("group"); + } catch (Exception ex) { + throw new IllegalArgumentException("Bad format found in 'group' section for user: " + usersKey + " in file: " + usersFile.getPath()); + } + + if (nodeData != null) { + Group hisGroup = ph.getGroup(nodeData.toString()); + if (hisGroup == null) { + GroupManager.logger.warning("There is no group " + thisUserNode.get("group").toString() + ", as stated for player " + thisUser.getLastName() + ": Set to '" + ph.getDefaultGroup().getName() + "' for file: " + usersFile.getPath()); + hisGroup = ph.getDefaultGroup(); + } + thisUser.setGroup(hisGroup); + } else { + thisUser.setGroup(ph.getDefaultGroup()); + } + } + } + + ph.removeUsersChangedFlag(); + // Update the LastModified time. + ph.setUsersFile(usersFile); + ph.setTimeStampUsers(usersFile.lastModified()); + } + + /** + * Write a dataHolder in a specified file + * + * @param ph + * @param groupsFile + */ + public static void writeGroups(WorldDataHolder ph, File groupsFile) { + + Map root = new HashMap(); + + Map groupsMap = new HashMap(); + + root.put("groups", groupsMap); + synchronized (ph.getGroups()) { + for (String groupKey : ph.getGroups().keySet()) { + Group group = ph.getGroups().get(groupKey); + + Map aGroupMap = new HashMap(); + groupsMap.put(group.getName(), aGroupMap); + + if (ph.getDefaultGroup() == null) { + GroupManager.logger.severe("There is no default group for world: " + ph.getName()); + } + aGroupMap.put("default", group.equals(ph.getDefaultGroup())); + + Map infoMap = new HashMap(); + aGroupMap.put("info", infoMap); + + for (String infoKey : group.getVariables().getVarKeyList()) { + infoMap.put(infoKey, group.getVariables().getVarObject(infoKey)); + } + + aGroupMap.put("inheritance", group.getInherits()); + + aGroupMap.put("permissions", group.getPermissionList()); + } + } + + if (!root.isEmpty()) { + DumperOptions opt = new DumperOptions(); + opt.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + final Yaml yaml = new Yaml(opt); + try { + OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(groupsFile), "UTF-8"); + + String newLine = System.getProperty("line.separator"); + + out.write("# Group inheritance" + newLine); + out.write("#" + newLine); + out.write("# Any inherited groups prefixed with a g: are global groups" + newLine); + out.write("# and are inherited from the GlobalGroups.yml." + newLine); + out.write("#" + newLine); + out.write("# Groups without the g: prefix are groups local to this world" + newLine); + out.write("# and are defined in the this groups.yml file." + newLine); + out.write("#" + newLine); + out.write("# Local group inheritances define your promotion tree when using 'manpromote/mandemote'" + newLine); + out.write(newLine); + + yaml.dump(root, out); + out.close(); + } catch (UnsupportedEncodingException ex) { + } catch (FileNotFoundException ex) { + } catch (IOException e) { + } + } + + // Update the LastModified time. + ph.setGroupsFile(groupsFile); + ph.setTimeStampGroups(groupsFile.lastModified()); + ph.removeGroupsChangedFlag(); + + if (GroupManager.isLoaded()) + GroupManager.getGMEventHandler().callEvent(GMSystemEvent.Action.SAVED); + + /* + * FileWriter tx = null; try { tx = new FileWriter(groupsFile, false); + * tx.write(yaml.dump(root)); tx.flush(); } catch (Exception e) { } + * finally { try { tx.close(); } catch (IOException ex) { } } + */ + } + + /** + * Write a dataHolder in a specified file + * + * @param ph + * @param usersFile + */ + public static void writeUsers(WorldDataHolder ph, File usersFile) { + + Map root = new HashMap(); + LinkedHashMap usersMap = new LinkedHashMap(); + + root.put("users", usersMap); + synchronized (ph.getUsers()) { + + // A sorted list of users. + for (String userKey : new TreeSet(ph.getUsers().keySet())) { + User user = ph.getUsers().get(userKey); + if ((user.getGroup() == null || user.getGroup().equals(ph.getDefaultGroup())) && user.getPermissionList().isEmpty() && user.getVariables().isEmpty() && user.isSubGroupsEmpty()) { + continue; + } + + LinkedHashMap aUserMap = new LinkedHashMap(); + usersMap.put(user.getUUID(), aUserMap); + + if (!user.getUUID().equalsIgnoreCase(user.getLastName())) { + aUserMap.put("lastname", user.getLastName()); + } + + // GROUP NODE + if (user.getGroup() == null) { + aUserMap.put("group", ph.getDefaultGroup().getName()); + } else { + aUserMap.put("group", user.getGroup().getName()); + } + + // SUBGROUPS NODE + aUserMap.put("subgroups", user.subGroupListStringCopy()); + + // PERMISSIONS NODE + aUserMap.put("permissions", user.getPermissionList()); + + // USER INFO NODE - BETA + if (user.getVariables().getSize() > 0) { + Map infoMap = new HashMap(); + aUserMap.put("info", infoMap); + for (String infoKey : user.getVariables().getVarKeyList()) { + infoMap.put(infoKey, user.getVariables().getVarObject(infoKey)); + } + } + // END USER INFO NODE - BETA + + } + } + + if (!root.isEmpty()) { + DumperOptions opt = new DumperOptions(); + opt.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + final Yaml yaml = new Yaml(opt); + try { + OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(usersFile), "UTF-8"); + yaml.dump(root, out); + out.close(); + } catch (UnsupportedEncodingException ex) { + } catch (FileNotFoundException ex) { + } catch (IOException e) { + } + } + + // Update the LastModified time. + ph.setUsersFile(usersFile); + ph.setTimeStampUsers(usersFile.lastModified()); + ph.removeUsersChangedFlag(); + + if (GroupManager.isLoaded()) + GroupManager.getGMEventHandler().callEvent(GMSystemEvent.Action.SAVED); + + /* + * FileWriter tx = null; try { tx = new FileWriter(usersFile, false); + * tx.write(yaml.dump(root)); tx.flush(); } catch (Exception e) { } + * finally { try { tx.close(); } catch (IOException ex) { } } + */ + } + + /** + * Don't use this. Unless you want to make this plugin to interact with + * original Nijikokun Permissions This method is supposed to make the + * original one reload the file, and propagate the changes made here. + * + * Prefer to use the AnjoCaido's fake version of Nijikokun's Permission + * plugin. The AnjoCaido's Permission can propagate the changes made on this + * plugin instantly, without need to save the file. + * + * @param server the server that holds the plugin + * @deprecated it is not used anymore... unless if you use original + * Permissions + */ + @Deprecated + public static void reloadOldPlugins(Server server) { + + // Only reload permissions + PluginManager pm = server.getPluginManager(); + Plugin[] plugins = pm.getPlugins(); + for (int i = 0; i < plugins.length; i++) { + // plugins[i].getConfiguration().load(); + try { + plugins[i].getClass().getMethod("setupPermissions").invoke(plugins[i]); + } catch (Exception ex) { + continue; + } + } + } + + /** + * @return the permissionsHandler + */ + public AnjoPermissionsHandler getPermissionsHandler() { + + if (permissionsHandler == null) { + permissionsHandler = new AnjoPermissionsHandler(this); + } + return permissionsHandler; + } + + /** + * @param haveUsersChanged the haveUsersChanged to set + */ + public void setUsersChanged(boolean haveUsersChanged) { + + users.setUsersChanged(haveUsersChanged); + } + + /** + * + * @return true if any user data has changed + */ + public boolean haveUsersChanged() { + + if (users.HaveUsersChanged()) { + return true; + } + synchronized (users.getUsers()) { + for (User u : users.getUsers().values()) { + if (u.isChanged()) { + return true; + } + } + } + return false; + } + + /** + * @param setGroupsChanged the haveGroupsChanged to set + */ + public void setGroupsChanged(boolean setGroupsChanged) { + + groups.setGroupsChanged(setGroupsChanged); + } + + /** + * + * @return true if any group data has changed. + */ + public boolean haveGroupsChanged() { + + if (groups.HaveGroupsChanged()) { + return true; + } + synchronized (groups.getGroups()) { + for (Group g : groups.getGroups().values()) { + if (g.isChanged()) { + return true; + } + } + } + return false; + } + + /** + * + */ + public void removeUsersChangedFlag() { + + setUsersChanged(false); + synchronized (getUsers()) { + for (User u : getUsers().values()) { + u.flagAsSaved(); + } + } + } + + /** + * + */ + public void removeGroupsChangedFlag() { + + setGroupsChanged(false); + synchronized (getGroups()) { + for (Group g : getGroups().values()) { + g.flagAsSaved(); + } + } + } + + /** + * @return the usersFile + */ + public File getUsersFile() { + + return users.getUsersFile(); + } + + /** + * @param file the usersFile to set + */ + public void setUsersFile(File file) { + + users.setUsersFile(file); + } + + /** + * @return the groupsFile + */ + public File getGroupsFile() { + + return groups.getGroupsFile(); + } + + /** + * @param file the groupsFile to set + */ + public void setGroupsFile(File file) { + + groups.setGroupsFile(file); + } + + /** + * @return the name + */ + public String getName() { + + return name; + } + + /** + * Resets Groups. + */ + public void resetGroups() { + + // setDefaultGroup(null); + groups.resetGroups(); + } + + /** + * Resets Users + */ + public void resetUsers() { + + users.resetUsers(); + } + + /** + * Note: Iteration over this object has to be synchronized! + * + * @return the groups + */ + public Map getGroups() { + + return groups.getGroups(); + } + + /** + * Note: Iteration over this object has to be synchronized! + * + * @return the users + */ + public Map getUsers() { + + return users.getUsers(); + } + + /** + * @return the groups + */ + public GroupsDataHolder getGroupsObject() { + + return groups; + } + + /** + * @param groupsDataHolder the GroupsDataHolder to set + */ + public void setGroupsObject(GroupsDataHolder groupsDataHolder) { + + groups = groupsDataHolder; + } + + /** + * @return the users + */ + public UsersDataHolder getUsersObject() { + + return users; + } + + /** + * @param usersDataHolder the UsersDataHolder to set + */ + public void setUsersObject(UsersDataHolder usersDataHolder) { + + users = usersDataHolder; + } + + /** + * @return the timeStampGroups + */ + public long getTimeStampGroups() { + + return groups.getTimeStampGroups(); + } + + /** + * @return the timeStampUsers + */ + public long getTimeStampUsers() { + + return users.getTimeStampUsers(); + } + + /** + * @param timeStampGroups the timeStampGroups to set + */ + protected void setTimeStampGroups(long timeStampGroups) { + + groups.setTimeStampGroups(timeStampGroups); + } + + /** + * @param timeStampUsers the timeStampUsers to set + */ + protected void setTimeStampUsers(long timeStampUsers) { + + users.setTimeStampUsers(timeStampUsers); + } + + public void setTimeStamps() { + + if (getGroupsFile() != null) + setTimeStampGroups(getGroupsFile().lastModified()); + if (getUsersFile() != null) + setTimeStampUsers(getUsersFile().lastModified()); + } + +} diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/worlds/WorldsHolder.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/worlds/WorldsHolder.java new file mode 100644 index 0000000000..55f471fa7d --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/worlds/WorldsHolder.java @@ -0,0 +1,794 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.anjocaido.groupmanager.dataholder.worlds; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.anjocaido.groupmanager.GroupManager; +import org.anjocaido.groupmanager.dataholder.WorldDataHolder; +import org.anjocaido.groupmanager.dataholder.OverloadedWorldHolder; +import org.anjocaido.groupmanager.permissions.AnjoPermissionsHandler; +import org.anjocaido.groupmanager.utils.Tasks; +import org.bukkit.World; +import org.bukkit.entity.Player; + +/** + * + * @author gabrielcouto + */ +public class WorldsHolder { + + /** + * Map with instances of loaded worlds. + */ + private Map worldsData = new HashMap(); + + /** + * Map of mirrors: + * The key is the mirror. + * The object is the mirrored. + * + * Mirror shows the same data of mirrored. + */ + private Map mirrorsGroup = new HashMap(); + private Map mirrorsUser = new HashMap(); + + private String serverDefaultWorldName; + private GroupManager plugin; + private File worldsFolder; + + /** + * + * @param plugin + */ + public WorldsHolder(GroupManager plugin) { + + this.plugin = plugin; + resetWorldsHolder(); + } + + /** + * @return the mirrorsGroup + */ + public Map getMirrorsGroup() { + + return mirrorsGroup; + } + + + /** + * @return the mirrorsUser + */ + public Map getMirrorsUser() { + + return mirrorsUser; + } + + public boolean isWorldKnown(String name) { + + return worldsData.containsKey(name.toLowerCase()); + } + + public void resetWorldsHolder() { + + worldsData = new HashMap(); + mirrorsGroup = new HashMap(); + mirrorsUser = new HashMap(); + + // Setup folders and check files exist for the primary world + verifyFirstRun(); + initialLoad(); + if (serverDefaultWorldName == null) + throw new IllegalStateException("There is no default group! OMG!"); + } + + private void initialLoad() { + + // load the initial world + initialWorldLoading(); + // Configure and load any mirrors and additional worlds as defined in config.yml + mirrorSetUp(); + // search the worlds folder for any manually created worlds (not listed in config.yml) + loadAllSearchedWorlds(); + } + + private void initialWorldLoading() { + + //Load the default world + loadWorld(serverDefaultWorldName); + //defaultWorld = getUpdatedWorldData(serverDefaultWorldName); + } + + private void loadAllSearchedWorlds() { + + /* + * Read all known worlds from Bukkit Create the data files if they don't + * already exist, and they are not mirrored. + */ + for (World world : plugin.getServer().getWorlds()) { + GroupManager.logger.log(Level.FINE, "Checking data for " + world.getName() + "."); + if ((!worldsData.containsKey(world.getName().toLowerCase())) && ((!mirrorsGroup.containsKey(world.getName().toLowerCase())) || (!mirrorsUser.containsKey(world.getName().toLowerCase())))) { + + if (worldsData.containsKey("all_unnamed_worlds")) { + + String usersMirror = mirrorsUser.get("all_unnamed_worlds"); + String groupsMirror = mirrorsGroup.get("all_unnamed_worlds"); + + if (usersMirror != null) + mirrorsUser.put(world.getName().toLowerCase(), usersMirror); + + if (groupsMirror != null) + mirrorsGroup.put(world.getName().toLowerCase(), groupsMirror); + + } + + GroupManager.logger.log(Level.FINE, "Creating folders for " + world.getName() + "."); + setupWorldFolder(world.getName()); + } + } + /* + * Loop over all folders within the worlds folder and attempt to load + * the world data + */ + for (File folder : worldsFolder.listFiles()) { + if (folder.isDirectory() && !folder.getName().startsWith(".")) { + GroupManager.logger.info("World Found: " + folder.getName()); + + /* + * don't load any worlds which are already loaded or fully + * mirrored worlds that don't need data. + */ + if (!worldsData.containsKey(folder.getName().toLowerCase()) && ((!mirrorsGroup.containsKey(folder.getName().toLowerCase())) || (!mirrorsUser.containsKey(folder.getName().toLowerCase())))) { + /* + * Call setupWorldFolder to check case sensitivity and + * convert to lower case, before we attempt to load this + * world. + */ + setupWorldFolder(folder.getName()); + loadWorld(folder.getName().toLowerCase()); + } + + } + } + } + + @SuppressWarnings("rawtypes") + public void mirrorSetUp() { + + mirrorsGroup.clear(); + mirrorsUser.clear(); + Map mirrorsMap = plugin.getGMConfig().getMirrorsMap(); + + HashSet mirroredWorlds = new HashSet(); + + if (mirrorsMap != null) { + for (String source : mirrorsMap.keySet()) { + // Make sure all non mirrored worlds have a set of data files. + setupWorldFolder(source); + // Load the world data + if (!worldsData.containsKey(source.toLowerCase())) + loadWorld(source); + + if (mirrorsMap.get(source) instanceof ArrayList) { + ArrayList mirrorList = (ArrayList) mirrorsMap.get(source); + + // These worlds fully mirror their parent + for (Object o : mirrorList) { + String world = o.toString().toLowerCase(); + if (!world.equalsIgnoreCase(serverDefaultWorldName)) { + try { + mirrorsGroup.remove(world); + mirrorsUser.remove(world); + } catch (Exception e) { + } + mirrorsGroup.put(world, getWorldData(source).getName()); + mirrorsUser.put(world, getWorldData(source).getName()); + + // Track this world so we can create a datasource for it later + mirroredWorlds.add(o.toString()); + + } else + GroupManager.logger.log(Level.WARNING, "Mirroring error with " + o.toString() + ". Recursive loop detected!"); + } + } else if (mirrorsMap.get(source) instanceof Map) { + Map subSection = (Map) mirrorsMap.get(source); + + for (Object key : subSection.keySet()) { + + if (!((String)key).equalsIgnoreCase(serverDefaultWorldName)) { + + if (subSection.get(key) instanceof ArrayList) { + ArrayList mirrorList = (ArrayList) subSection.get(key); + + // These worlds have defined mirroring + for (Object o : mirrorList) { + String type = o.toString().toLowerCase(); + try { + if (type.equals("groups")) + mirrorsGroup.remove(((String)key).toLowerCase()); + + if (type.equals("users")) + mirrorsUser.remove(((String)key).toLowerCase()); + + } catch (Exception e) { + } + if (type.equals("groups")) { + mirrorsGroup.put(((String)key).toLowerCase(), getWorldData(source).getName()); + GroupManager.logger.log(Level.FINE, "Adding groups mirror for " + key + "."); + } + + if (type.equals("users")) { + mirrorsUser.put(((String)key).toLowerCase(), getWorldData(source).getName()); + GroupManager.logger.log(Level.FINE, "Adding users mirror for " + key + "."); + } + } + + // Track this world so we can create a datasource for it later + mirroredWorlds.add((String)key); + + } else + throw new IllegalStateException("Unknown mirroring format for " + (String)key); + + } else { + GroupManager.logger.log(Level.WARNING, "Mirroring error with " + (String)key + ". Recursive loop detected!"); + } + + } + } + } + + // Create a datasource for any worlds not already loaded + for (String world : mirroredWorlds) { + if (!worldsData.containsKey(world.toLowerCase())) { + GroupManager.logger.log(Level.FINE, "No data for " + world + "."); + setupWorldFolder(world); + loadWorld(world, true); + } + } + } + } + + /** + * + */ + public void reloadAll() { + + // Load global groups + GroupManager.getGlobalGroups().load(); + + ArrayList alreadyDone = new ArrayList(); + for (WorldDataHolder w : worldsData.values()) { + if (alreadyDone.contains(w)) { + continue; + } + if (!mirrorsGroup.containsKey(w.getName().toLowerCase())) + w.reloadGroups(); + if (!mirrorsUser.containsKey(w.getName().toLowerCase())) + w.reloadUsers(); + + alreadyDone.add(w); + } + + } + + /** + * + * @param worldName + */ + public void reloadWorld(String worldName) { + + if (!mirrorsGroup.containsKey(worldName.toLowerCase())) + getWorldData(worldName).reloadGroups(); + if (!mirrorsUser.containsKey(worldName.toLowerCase())) + getWorldData(worldName).reloadUsers(); + } + + /** + * Wrapper to retain backwards compatibility + * (call this function to auto overwrite files) + */ + public void saveChanges() { + + saveChanges(true); + } + + /** + * + */ + public boolean saveChanges(boolean overwrite) { + + boolean changed = false; + ArrayList alreadyDone = new ArrayList(); + Tasks.removeOldFiles(plugin, plugin.getBackupFolder()); + + // Write Global Groups + if (GroupManager.getGlobalGroups().haveGroupsChanged()) { + GroupManager.getGlobalGroups().writeGroups(overwrite); + } else { + if (GroupManager.getGlobalGroups().getTimeStampGroups() < GroupManager.getGlobalGroups().getGlobalGroupsFile().lastModified()) { + System.out.print("Newer GlobalGroups file found (Loading changes)!"); + GroupManager.getGlobalGroups().load(); + } + } + + for (OverloadedWorldHolder w : worldsData.values()) { + if (alreadyDone.contains(w)) { + continue; + } + if (w == null) { + GroupManager.logger.severe("WHAT HAPPENED?"); + continue; + } + if (!mirrorsGroup.containsKey(w.getName().toLowerCase())) + if (w.haveGroupsChanged()) { + if (overwrite || (!overwrite && (w.getTimeStampGroups() >= w.getGroupsFile().lastModified()))) { + // Backup Groups file + backupFile(w, true); + + WorldDataHolder.writeGroups(w, w.getGroupsFile()); + changed = true; + //w.removeGroupsChangedFlag(); + } else { + // Newer file found. + GroupManager.logger.log(Level.WARNING, "Newer Groups file found for " + w.getName() + ", but we have local changes!"); + throw new IllegalStateException("Unable to save unless you issue a '/mansave force'"); + } + } else { + //Check for newer file as no local changes. + if (w.getTimeStampGroups() < w.getGroupsFile().lastModified()) { + System.out.print("Newer Groups file found (Loading changes)!"); + // Backup Groups file + backupFile(w, true); + w.reloadGroups(); + changed = true; + } + } + if (!mirrorsUser.containsKey(w.getName().toLowerCase())) + if (w.haveUsersChanged()) { + if (overwrite || (!overwrite && (w.getTimeStampUsers() >= w.getUsersFile().lastModified()))) { + // Backup Users file + backupFile(w, false); + + WorldDataHolder.writeUsers(w, w.getUsersFile()); + changed = true; + //w.removeUsersChangedFlag(); + } else { + // Newer file found. + GroupManager.logger.log(Level.WARNING, "Newer Users file found for " + w.getName() + ", but we have local changes!"); + throw new IllegalStateException("Unable to save unless you issue a '/mansave force'"); + } + } else { + //Check for newer file as no local changes. + if (w.getTimeStampUsers() < w.getUsersFile().lastModified()) { + System.out.print("Newer Users file found (Loading changes)!"); + // Backup Users file + backupFile(w, false); + w.reloadUsers(); + changed = true; + } + } + alreadyDone.add(w); + } + return changed; + } + + /** + * Backup the Groups/Users file + * + * @param w + * @param groups + */ + private void backupFile(OverloadedWorldHolder w, Boolean groups) { + + File backupFile = new File(plugin.getBackupFolder(), "bkp_" + w.getName() + (groups ? "_g_" : "_u_") + Tasks.getDateString() + ".yml"); + try { + Tasks.copy((groups ? w.getGroupsFile() : w.getUsersFile()), backupFile); + } catch (IOException ex) { + GroupManager.logger.log(Level.SEVERE, null, ex); + } + } + + /** + * Returns the dataHolder for the given world. + * If the world is not on the worlds list, returns the default world + * holder. + * + * Mirrors return their parent world data. + * If no mirroring data it returns the default world. + * + * @param worldName + * @return OverloadedWorldHolder + */ + public OverloadedWorldHolder getWorldData(String worldName) { + + String worldNameLowered = worldName.toLowerCase(); + + // Find this worlds data + if (worldsData.containsKey(worldNameLowered)) + return getUpdatedWorldData(worldNameLowered); + + // Oddly no data source was found for this world so attempt to return the global mirror. + if (worldsData.containsKey("all_unnamed_worlds")) { + GroupManager.logger.finest("Requested world " + worldName + " not found or badly mirrored. Returning all_unnamed_worlds world..."); + return getUpdatedWorldData("all_unnamed_worlds"); + } + + // Oddly no data source or global mirror was found for this world so return the default. + GroupManager.logger.finest("Requested world " + worldName + " not found or badly mirrored. Returning default world..."); + return getDefaultWorld(); + } + + /** + * Get the requested world data and update it's dataSource to be relevant + * for this world + * + * @param worldName + * @return updated world holder + */ + private OverloadedWorldHolder getUpdatedWorldData(String worldName) { + + String worldNameLowered = worldName.toLowerCase(); + + if (worldsData.containsKey(worldNameLowered)) { + OverloadedWorldHolder data = worldsData.get(worldNameLowered); + data.updateDataSource(); + return data; + } + return null; + + } + + /** + * Do a matching of playerName, if its found only one player, do + * getWorldData(player) + * + * @param playerName + * @return null if matching returned no player, or more than one. + */ + public OverloadedWorldHolder getWorldDataByPlayerName(String playerName) { + + List matchPlayer = plugin.getServer().matchPlayer(playerName); + if (matchPlayer.size() == 1) { + return getWorldData(matchPlayer.get(0)); + } + return null; + } + + /** + * Retrieves the field player.getWorld().getName() and do + * getWorld(worldName) + * + * @param player + * @return OverloadedWorldHolder + */ + public OverloadedWorldHolder getWorldData(Player player) { + + return getWorldData(player.getWorld().getName()); + } + + /** + * It does getWorld(worldName).getPermissionsHandler() + * + * @param worldName + * @return AnjoPermissionsHandler + */ + public AnjoPermissionsHandler getWorldPermissions(String worldName) { + + return getWorldData(worldName).getPermissionsHandler(); + } + + /** + * Returns the PermissionsHandler for this player data + * + * @param player + * @return AnjoPermissionsHandler + */ + public AnjoPermissionsHandler getWorldPermissions(Player player) { + + return getWorldData(player).getPermissionsHandler(); + } + + /** + * Id does getWorldDataByPlayerName(playerName). + * If it doesnt return null, it will return result.getPermissionsHandler() + * + * @param playerName + * @return null if the player matching gone wrong. + */ + public AnjoPermissionsHandler getWorldPermissionsByPlayerName(String playerName) { + + WorldDataHolder dh = getWorldDataByPlayerName(playerName); + if (dh != null) { + return dh.getPermissionsHandler(); + } + return null; + } + + private void verifyFirstRun() { + + /* Do not use the folder name if this + * is a Bukkit Forge server. + */ + if (plugin.getServer().getName().equalsIgnoreCase("BukkitForge")) { + serverDefaultWorldName = "overworld"; + + } else { + Properties server = new Properties(); + try { + server.load(new FileInputStream(new File("server.properties"))); + serverDefaultWorldName = server.getProperty("level-name").toLowerCase(); + } catch (IOException ex) { + GroupManager.logger.log(Level.SEVERE, null, ex); + } + } + setupWorldFolder(serverDefaultWorldName); + + } + + public void setupWorldFolder(String worldName) { + + String worldNameLowered = worldName.toLowerCase(); + + worldsFolder = new File(plugin.getDataFolder(), "worlds"); + if (!worldsFolder.exists()) { + worldsFolder.mkdirs(); + } + + File defaultWorldFolder = new File(worldsFolder, worldNameLowered); + if ((!defaultWorldFolder.exists()) && ((!mirrorsGroup.containsKey(worldNameLowered))) || (!mirrorsUser.containsKey(worldNameLowered))) { + + /* + * check and convert all old case sensitive folders to lower case + */ + File casedWorldFolder = new File(worldsFolder, worldName); + if ((casedWorldFolder.exists()) && (casedWorldFolder.getName().toLowerCase().equals(worldNameLowered))) { + /* + * Rename the old folder to the new lower cased format + */ + casedWorldFolder.renameTo(new File(worldsFolder, worldNameLowered)); + } else { + /* + * Else we just create the folder + */ + defaultWorldFolder.mkdirs(); + } + } + if (defaultWorldFolder.exists()) { + if (!mirrorsGroup.containsKey(worldNameLowered)) { + File groupsFile = new File(defaultWorldFolder, "groups.yml"); + if (!groupsFile.exists() || groupsFile.length() == 0) { + + InputStream template = plugin.getResourceAsStream("groups.yml"); + try { + Tasks.copy(template, groupsFile); + } catch (IOException ex) { + GroupManager.logger.log(Level.SEVERE, null, ex); + } + } + } + + if (!mirrorsUser.containsKey(worldNameLowered)) { + File usersFile = new File(defaultWorldFolder, "users.yml"); + if (!usersFile.exists() || usersFile.length() == 0) { + + InputStream template = plugin.getResourceAsStream("users.yml"); + try { + Tasks.copy(template, usersFile); + } catch (IOException ex) { + GroupManager.logger.log(Level.SEVERE, null, ex); + } + + } + } + } + } + + /** + * Copies the specified world data to another world + * + * @param fromWorld + * @param toWorld + * @return true if successfully copied. + */ + public boolean cloneWorld(String fromWorld, String toWorld) { + + File fromWorldFolder = new File(worldsFolder, fromWorld.toLowerCase()); + File toWorldFolder = new File(worldsFolder, toWorld.toLowerCase()); + if (toWorldFolder.exists() || !fromWorldFolder.exists()) { + return false; + } + File fromWorldGroups = new File(fromWorldFolder, "groups.yml"); + File fromWorldUsers = new File(fromWorldFolder, "users.yml"); + if (!fromWorldGroups.exists() || !fromWorldUsers.exists()) { + return false; + } + File toWorldGroups = new File(toWorldFolder, "groups.yml"); + File toWorldUsers = new File(toWorldFolder, "users.yml"); + toWorldFolder.mkdirs(); + try { + Tasks.copy(fromWorldGroups, toWorldGroups); + Tasks.copy(fromWorldUsers, toWorldUsers); + } catch (IOException ex) { + Logger.getLogger(WorldsHolder.class.getName()).log(Level.SEVERE, null, ex); + return false; + } + return true; + } + + /** + * Wrapper for LoadWorld(String,Boolean) for backwards compatibility + * + * Load a world from file. + * If it already been loaded, summon reload method from dataHolder. + * + * @param worldName + */ + public void loadWorld(String worldName) { + + loadWorld(worldName, false); + } + + /** + * Load a world from file. + * If it already been loaded, summon reload method from dataHolder. + * + * @param worldName + */ + public void loadWorld(String worldName, Boolean isMirror) { + + String worldNameLowered = worldName.toLowerCase(); + + if (worldsData.containsKey(worldNameLowered)) { + worldsData.get(worldNameLowered).reload(); + return; + } + GroupManager.logger.finest("Trying to load world " + worldName + "..."); + File thisWorldFolder = new File(worldsFolder, worldNameLowered); + if ((isMirror) || (thisWorldFolder.exists() && thisWorldFolder.isDirectory())) { + + // Setup file handles, if not mirrored + File groupsFile = (mirrorsGroup.containsKey(worldNameLowered)) ? null : new File(thisWorldFolder, "groups.yml"); + File usersFile = (mirrorsUser.containsKey(worldNameLowered)) ? null : new File(thisWorldFolder, "users.yml"); + + if ((groupsFile != null) && (!groupsFile.exists())) { + throw new IllegalArgumentException("Groups file for world '" + worldName + "' doesnt exist: " + groupsFile.getPath()); + } + if ((usersFile != null) && (!usersFile.exists())) { + throw new IllegalArgumentException("Users file for world '" + worldName + "' doesnt exist: " + usersFile.getPath()); + } + + WorldDataHolder tempHolder = new WorldDataHolder(worldNameLowered); + + // Map the group object for any mirror + if (mirrorsGroup.containsKey(worldNameLowered)) + tempHolder.setGroupsObject(this.getWorldData(mirrorsGroup.get(worldNameLowered)).getGroupsObject()); + else + tempHolder.loadGroups(groupsFile); + + // Map the user object for any mirror + if (mirrorsUser.containsKey(worldNameLowered)) + tempHolder.setUsersObject(this.getWorldData(mirrorsUser.get(worldNameLowered)).getUsersObject()); + else + tempHolder.loadUsers(usersFile); + + OverloadedWorldHolder thisWorldData = new OverloadedWorldHolder(tempHolder); + + // null the object so we don't keep file handles open where we shouldn't + tempHolder = null; + + // Set the file TimeStamps as it will be default from the initial load. + thisWorldData.setTimeStamps(); + + if (thisWorldData != null) { + GroupManager.logger.finest("Successful load of world " + worldName + "..."); + worldsData.put(worldNameLowered, thisWorldData); + return; + } + + //GroupManager.logger.severe("Failed to load world " + worldName + "..."); + } + } + + /** + * Tells if the such world has been mapped. + * + * It will return true if world is a mirror. + * + * @param worldName + * @return true if world is loaded or mirrored. false if not listed + */ + public boolean isInList(String worldName) { + + if (worldsData.containsKey(worldName.toLowerCase()) || mirrorsGroup.containsKey(worldName.toLowerCase()) || mirrorsUser.containsKey(worldName.toLowerCase())) { + return true; + } + return false; + } + + /** + * Verify if world has it's own file permissions. + * + * @param worldName + * @return true if it has its own holder. false if not. + */ + public boolean hasOwnData(String worldName) { + + if (worldsData.containsKey(worldName.toLowerCase()) && (!mirrorsGroup.containsKey(worldName.toLowerCase()) || !mirrorsUser.containsKey(worldName.toLowerCase()))) { + return true; + } + return false; + } + + /** + * @return the defaultWorld + */ + public OverloadedWorldHolder getDefaultWorld() { + + return getUpdatedWorldData(serverDefaultWorldName); + } + + /** + * Returns all physically loaded worlds which have at least one of their own + * data sets for users or groups which isn't an identical mirror. + * + * @return ArrayList of all loaded worlds + */ + public ArrayList allWorldsDataList() { + + ArrayList list = new ArrayList(); + + for (String world : worldsData.keySet()) { + + if (!world.equalsIgnoreCase("all_unnamed_worlds")) { + + // Fetch the relevant world object + OverloadedWorldHolder data = getWorldData(world); + + if (!list.contains(data)) { + + String worldNameLowered = data.getName().toLowerCase(); + String usersMirror = mirrorsUser.get(worldNameLowered); + String groupsMirror = mirrorsGroup.get(worldNameLowered); + + // is users mirrored? + if (usersMirror != null) { + + // If both are mirrored + if (groupsMirror != null) { + + // if the data sources are the same, return the parent + if (usersMirror == groupsMirror) { + data = getWorldData(usersMirror.toLowerCase()); + + // Only add the parent if it's not already listed. + if (!list.contains(data)) + list.add(data); + + continue; + } + // Both data sources are mirrors, but they are from different parents + // so fall through to add the actual data object. + } + // Groups isn't a mirror so fall through to add this this worlds data source + } + + // users isn't mirrored so we need to add this worlds data source + list.add(data); + } + } + } + return list; + } +} diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMGroupEvent.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMGroupEvent.java new file mode 100644 index 0000000000..fe7c98640e --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMGroupEvent.java @@ -0,0 +1,88 @@ +package org.anjocaido.groupmanager.events; + +import org.anjocaido.groupmanager.GroupManager; +import org.anjocaido.groupmanager.data.Group; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +/** + * @author ElgarL + * + */ +public class GMGroupEvent extends Event { + + /** + * + */ + private static final HandlerList handlers = new HandlerList(); + + @Override + public HandlerList getHandlers() { + + return handlers; + } + + public static HandlerList getHandlerList() { + + return handlers; + } + + ////////////////////////////// + + protected Group group; + + protected String groupName; + + protected Action action; + + public GMGroupEvent(Group group, Action action) { + + super(); + + this.group = group; + this.action = action; + this.groupName = group.getName(); + } + + public GMGroupEvent(String groupName, Action action) { + + super(); + + this.groupName = groupName; + this.action = action; + } + + public Action getAction() { + + return this.action; + } + + public Group getGroup() { + + return group; + } + + public String getGroupName() { + + return groupName; + } + + public enum Action { + GROUP_PERMISSIONS_CHANGED, GROUP_INHERITANCE_CHANGED, GROUP_INFO_CHANGED, GROUP_ADDED, GROUP_REMOVED, + } + + public void schedule(final GMGroupEvent event) { + + synchronized (GroupManager.getGMEventHandler().getServer()) { + if (GroupManager.getGMEventHandler().getServer().getScheduler().scheduleSyncDelayedTask(GroupManager.getGMEventHandler().getPlugin(), new Runnable() { + + @Override + public void run() { + + GroupManager.getGMEventHandler().getServer().getPluginManager().callEvent(event); + } + }, 1) == -1) + GroupManager.logger.warning("Could not schedule GM Event."); + } + } +} \ No newline at end of file diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMSystemEvent.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMSystemEvent.java new file mode 100644 index 0000000000..a04190d99f --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMSystemEvent.java @@ -0,0 +1,63 @@ +package org.anjocaido.groupmanager.events; + +import org.anjocaido.groupmanager.GroupManager; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +/** + * @author ElgarL + * + */ +public class GMSystemEvent extends Event { + + /** + * + */ + private static final HandlerList handlers = new HandlerList(); + + @Override + public HandlerList getHandlers() { + + return handlers; + } + + public static HandlerList getHandlerList() { + + return handlers; + } + + ////////////////////////////// + + protected Action action; + + public GMSystemEvent(Action action) { + + super(); + + this.action = action; + } + + public Action getAction() { + + return this.action; + } + + public enum Action { + RELOADED, SAVED, DEFAULT_GROUP_CHANGED, VALIDATE_TOGGLE, + } + + public void schedule(final GMSystemEvent event) { + + synchronized (GroupManager.getGMEventHandler().getServer()) { + if (GroupManager.getGMEventHandler().getServer().getScheduler().scheduleSyncDelayedTask(GroupManager.getGMEventHandler().getPlugin(), new Runnable() { + + @Override + public void run() { + + GroupManager.getGMEventHandler().getServer().getPluginManager().callEvent(event); + } + }, 1) == -1) + GroupManager.logger.warning("Could not schedule GM Event."); + } + } +} \ No newline at end of file diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMUserEvent.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMUserEvent.java new file mode 100644 index 0000000000..cc7f00eee9 --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMUserEvent.java @@ -0,0 +1,88 @@ +package org.anjocaido.groupmanager.events; + +import org.anjocaido.groupmanager.GroupManager; +import org.anjocaido.groupmanager.data.User; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +/** + * @author ElgarL + * + */ +public class GMUserEvent extends Event { + + /** + * + */ + private static final HandlerList handlers = new HandlerList(); + + @Override + public HandlerList getHandlers() { + + return handlers; + } + + public static HandlerList getHandlerList() { + + return handlers; + } + + ////////////////////////////// + + protected User user; + + protected String userName; + + protected Action action; + + public GMUserEvent(User user, Action action) { + + super(); + + this.user = user; + this.action = action; + this.userName = user.getLastName(); + } + + public GMUserEvent(String userName, Action action) { + + super(); + + this.userName = userName; + this.action = action; + } + + public Action getAction() { + + return this.action; + } + + public User getUser() { + + return user; + } + + public String getUserName() { + + return userName; + } + + public enum Action { + USER_PERMISSIONS_CHANGED, USER_INHERITANCE_CHANGED, USER_INFO_CHANGED, USER_GROUP_CHANGED, USER_SUBGROUP_CHANGED, USER_ADDED, USER_REMOVED, + } + + public void schedule(final GMUserEvent event) { + + synchronized (GroupManager.getGMEventHandler().getServer()) { + if (GroupManager.getGMEventHandler().getServer().getScheduler().scheduleSyncDelayedTask(GroupManager.getGMEventHandler().getPlugin(), new Runnable() { + + @Override + public void run() { + + GroupManager.getGMEventHandler().getServer().getPluginManager().callEvent(event); + } + }, 1) == -1) + GroupManager.logger.warning("Could not schedule GM Event."); + } + } +} \ No newline at end of file diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMWorldListener.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMWorldListener.java new file mode 100644 index 0000000000..51937bd677 --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GMWorldListener.java @@ -0,0 +1,62 @@ +package org.anjocaido.groupmanager.events; + +import org.anjocaido.groupmanager.GroupManager; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.world.WorldInitEvent; + +/** + * @author ElgarL + * + * Handle new world creation from other plugins + * + */ +public class GMWorldListener implements Listener { + + private final GroupManager plugin; + + public GMWorldListener(GroupManager instance) { + + plugin = instance; + registerEvents(); + } + + private void registerEvents() { + + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onWorldInit(WorldInitEvent event) { + + String worldName = event.getWorld().getName(); + + if (GroupManager.isLoaded() && !plugin.getWorldsHolder().isInList(worldName)) { + GroupManager.logger.info("New world detected..."); + GroupManager.logger.info("Creating data for: " + worldName); + + if (plugin.getWorldsHolder().isWorldKnown("all_unnamed_worlds")) { + + String usersMirror = plugin.getWorldsHolder().getMirrorsUser().get("all_unnamed_worlds"); + String groupsMirror = plugin.getWorldsHolder().getMirrorsGroup().get("all_unnamed_worlds"); + + if (usersMirror != null) + plugin.getWorldsHolder().getMirrorsUser().put(worldName.toLowerCase(), usersMirror); + + if (groupsMirror != null) + plugin.getWorldsHolder().getMirrorsGroup().put(worldName.toLowerCase(), groupsMirror); + + } + + plugin.getWorldsHolder().setupWorldFolder(worldName); + plugin.getWorldsHolder().loadWorld(worldName); + + + if (plugin.getWorldsHolder().isInList(worldName)) { + GroupManager.logger.info("Don't forget to configure/mirror this world in config.yml."); + } else + GroupManager.logger.severe("Failed to configure this world."); + } + } +} \ No newline at end of file diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GroupManagerEventHandler.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GroupManagerEventHandler.java new file mode 100644 index 0000000000..d0df57aa78 --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/events/GroupManagerEventHandler.java @@ -0,0 +1,84 @@ +package org.anjocaido.groupmanager.events; + +import org.anjocaido.groupmanager.GroupManager; +import org.anjocaido.groupmanager.data.Group; +import org.anjocaido.groupmanager.data.User; +import org.bukkit.Server; + +/** + * @author ElgarL + * + * Handles all Event generation. + * + */ +public class GroupManagerEventHandler { + + private final Server server; + private final GroupManager plugin; + + + public GroupManagerEventHandler(GroupManager plugin) { + + this.plugin = plugin; + this.server = plugin.getServer(); + + } + + protected void callEvent(GMGroupEvent event) { + + event.schedule(event); + } + + protected void callEvent(GMUserEvent event) { + + event.schedule(event); + } + + protected void callEvent(GMSystemEvent event) { + + event.schedule(event); + } + + public void callEvent(Group group, GMGroupEvent.Action action) { + + callEvent(new GMGroupEvent(group, action)); + } + + public void callEvent(String groupName, GMGroupEvent.Action action) { + + callEvent(new GMGroupEvent(groupName, action)); + } + + public void callEvent(User user, GMUserEvent.Action action) { + + callEvent(new GMUserEvent(user, action)); + } + + public void callEvent(String userName, GMUserEvent.Action action) { + + callEvent(new GMUserEvent(userName, action)); + } + + public void callEvent(GMSystemEvent.Action action) { + + callEvent(new GMSystemEvent(action)); + } + + /** + * @return the plugin + */ + public GroupManager getPlugin() { + + return plugin; + } + + /** + * @return the server + */ + public Server getServer() { + + return server; + } + + +} \ No newline at end of file diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/AnjoPermissionsHandler.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/AnjoPermissionsHandler.java new file mode 100644 index 0000000000..07a8467913 --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/AnjoPermissionsHandler.java @@ -0,0 +1,1346 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.anjocaido.groupmanager.permissions; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.anjocaido.groupmanager.GroupManager; +import org.anjocaido.groupmanager.data.Group; +import org.anjocaido.groupmanager.data.User; +import org.anjocaido.groupmanager.dataholder.WorldDataHolder; +import org.anjocaido.groupmanager.utils.PermissionCheckResult; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +/** + * Everything here maintains the model created by Nijikokun + * + * But implemented to use GroupManager system. Which provides instant changes, + * without file access. + * + * It holds permissions only for one single world. + * + * @author gabrielcouto, ElgarL + */ +public class AnjoPermissionsHandler extends PermissionsReaderInterface { + + WorldDataHolder ph = null; + + /** + * It needs a WorldDataHolder to work with. + * + * @param holder + */ + public AnjoPermissionsHandler(WorldDataHolder holder) { + + ph = holder; + } + + /** + * A short name method, for permission method. + * + * @param player + * @param permission + * @return true if the player has the permission + */ + @Override + public boolean has(Player player, String permission) { + + return permission(player, permission); + } + + /** + * Checks if a player can use that permission node. + * + * @param player + * @param permission + * @return true if the player has the permission + */ + @Override + public boolean permission(Player player, String permission) { + + return checkUserPermission(ph.getUser(player.getName()).updatePlayer(player), permission); + } + + /** + * Checks if a player can use that permission node. + * + * @param playerName + * @param permission + * @return true if the player has the permission + */ + public boolean permission(String playerName, String permission) { + + return checkUserPermission(ph.getUser(playerName), permission); + } + + /** + * Returns the name of the group of that player name. + * + * @param userName + * @return String of players group name. + */ + @Override + public String getGroup(String userName) { + + return ph.getUser(userName).getGroup().getName(); + } + + /** + * Returns All permissions (including inheritance and sub groups) for the + * player, including child nodes from Bukkit. + * + * @param userName + * @return List of all players permissions. + */ + @Override + public List getAllPlayersPermissions(String userName) { + + List perms = new ArrayList(); + + perms.addAll(getAllPlayersPermissions(userName, true)); + + return perms; + } + + /** + * Returns All permissions (including inheritance and sub groups) for the + * player. With or without Bukkit child nodes. + * + * @param userName + * @return Set of all players permissions. + */ + @Override + public Set getAllPlayersPermissions(String userName, Boolean includeChildren) { + + Set playerPermArray = new LinkedHashSet(); + Set overrides = new LinkedHashSet(); + + // Add the players own permissions. + playerPermArray.addAll(populatePerms(ph.getUser(userName).getPermissionList(), includeChildren)); + + ArrayList alreadyProcessed = new ArrayList(); + + // fetch all group permissions + for (String group : getGroups(userName)) { + // Don't process a group more than once. + if (!alreadyProcessed.contains(group)) { + alreadyProcessed.add(group); + + Set groupPermArray = new LinkedHashSet(); + + if (group.startsWith("g:") && GroupManager.getGlobalGroups().hasGroup(group)) { + // GlobalGroups + groupPermArray = populatePerms(GroupManager.getGlobalGroups().getGroupsPermissions(group), includeChildren); + + } else { + // World Groups + groupPermArray = populatePerms(ph.getGroup(group).getPermissionList(), includeChildren); + } + + // Add all group permissions, unless negated by earlier permissions. + for (String perm : groupPermArray) { + boolean negated = (perm.startsWith("-")); + + // Overridden (Exception) permission defeats negation. + if (perm.startsWith("+")) { + overrides.add(perm.substring(1)); + continue; + } + + // Perm doesn't already exists and there is no negation for it + // or It's a negated perm where a normal perm doesn't exists (don't allow inheritance to negate higher perms) + if ((!negated && !playerPermArray.contains(perm) && !wildcardNegation(playerPermArray, perm)) || (negated && !playerPermArray.contains(perm.substring(1)) && !wildcardNegation(playerPermArray, perm.substring(1)))) + playerPermArray.add(perm); + + } + } + + } + + // Process overridden permissions + + Iterator itr = overrides.iterator(); + + while (itr.hasNext()) { + + String node = itr.next(); + + if (playerPermArray.contains("-" + node)) { + playerPermArray.remove("-" + node); + } + + playerPermArray.add(node); + + } + + // Collections.sort(playerPermArray, StringPermissionComparator.getInstance()); + + return playerPermArray; + } + + /** + * Is there a direct or wildcard negation in the list which covers this permission node. + * + * @param playerPermArray + * @param node + * @return + */ + private boolean wildcardNegation(Set playerPermArray, String node) { + + /* + * Check for a negated parent with a wildcard or negated permission + */ + + if (playerPermArray.contains("-" + node)) + return true; + + final String[] parts = node.split("\\."); + final StringBuilder builder = new StringBuilder(node.length()); + for (String part : parts) { + builder.append('*'); + if (playerPermArray.contains("-" + builder.toString())) { + GroupManager.logger.fine("Wildcard Negation found for " + node); + return true; + } + + builder.deleteCharAt(builder.length() - 1); + builder.append(part).append('.'); + } + + /* + * No negated parent found so return false. + */ + GroupManager.logger.fine("No Negation found for " + node); + return false; + + } + + private Set populatePerms(List permsList, boolean includeChildren) { + + // Create a new array so it's modifiable. + List perms = new ArrayList(permsList); + Set permArray = new LinkedHashSet(); + Boolean allPerms = false; + + // Allow * node to populate ALL permissions to Bukkit. + if (perms.contains("*")) { + permArray.addAll(GroupManager.BukkitPermissions.getAllRegisteredPermissions(includeChildren)); + allPerms = true; + perms.remove("*"); + // Remove the no offline perms node as this should not be given. + perms.remove("groupmanager.noofflineperms"); + } + + for (String perm : perms) { + /** + * all permission sets are passed here pre-sorted, alphabetically. + * This means negated nodes will be processed before all permissions + * other than *. + */ + boolean negated = perm.startsWith("-"); + + if (!permArray.contains(perm)) { + permArray.add(perm); + + if ((negated) && (permArray.contains(perm.substring(1)))) + permArray.remove(perm.substring(1)); + + /** + * Process child nodes if required, + * or this is a negated node AND we used * to include all + * permissions, + * in which case we need to remove all children of that node. + */ + if ((includeChildren) || (negated && allPerms)) { + + Map children = GroupManager.BukkitPermissions.getAllChildren((negated ? perm.substring(1) : perm), new LinkedHashSet()); + + if (children != null) { + if (negated) + if (allPerms) { + + // Remove children of negated nodes + for (String child : children.keySet()) + if (children.get(child)) + if (permArray.contains(child)) + permArray.remove(child); + + } else { + + // Add child nodes + for (String child : children.keySet()) + if (children.get(child)) + if ((!permArray.contains(child)) && (!permArray.contains("-" + child))) + permArray.add(child); + } + } + } + } + } + + return permArray; + } + + /** + * Verify if player is in such group. It will check it's groups inheritance. + * + * So if you have a group Admin > Moderator + * + * And verify the player 'MyAdmin', which is Admin, it will return true for + * both Admin or Moderator groups. + * + * If you have a player 'MyModerator', which is Moderator, it will give + * false if you pass Admin in group parameter. + * + * @param name + * @param group + * @return true if in group (with inheritance) + */ + @Override + public boolean inGroup(String name, String group) { + + if (hasGroupInInheritance(ph.getUser(name).getGroup(), group)) { + return true; + } + for (Group subGroup : ph.getUser(name).subGroupListCopy()) { + if (hasGroupInInheritance(subGroup, group)) { + return true; + } + } + return false; + } + + /** + * Gets the appropriate prefix for the user. This method is a utility method + * for chat plugins to get the user's prefix without having to look at every + * one of the user's ancestors. Returns an empty string if user has no + * parent groups. + * + * @param user + * Player's name + * @return Player's prefix + */ + @Override + public String getUserPrefix(String user) { + + String prefix = ph.getUser(user).getVariables().getVarString("prefix"); + if (prefix.length() != 0) { + return prefix; + } + + return getGroupPrefix(getGroup(user)); + } + + /** + * Gets the appropriate prefix for the user. This method is a utility method + * for chat plugins to get the user's prefix without having to look at every + * one of the user's ancestors. Returns an empty string if user has no + * parent groups. + * + * @param user + * Player's name + * @return Player's prefix + */ + @Override + public String getUserSuffix(String user) { + + String suffix = ph.getUser(user).getVariables().getVarString("suffix"); + if (suffix.length() != 0) { + return suffix; + } + + return getGroupSuffix(getGroup(user)); + + } + + /** + * Gets name of the primary group of the user. Returns the name of the + * default group if user has no parent groups, or "Default" if there is no + * default group for that world. + * + * @param user + * Player's name + * @return Name of player's primary group + */ + public String getPrimaryGroup(String user) { + + return getGroup(user); + + } + + /** + * Check if user can build. Checks inheritance and subgroups. + * + * @param userName + * Player's name + * @return true if the user can build + */ + public boolean canUserBuild(String userName) { + + return getPermissionBoolean(userName, "build"); + + } + + /** + * Returns the String prefix for the given group + * + * @param groupName + * @return empty string if found none. + */ + @Override + public String getGroupPrefix(String groupName) { + + Group g = ph.getGroup(groupName); + if (g == null) { + return ""; + } + return g.getVariables().getVarString("prefix"); + } + + /** + * Return the suffix for the given group name + * + * @param groupName + * @return empty string if not found. + */ + @Override + public String getGroupSuffix(String groupName) { + + Group g = ph.getGroup(groupName); + if (g == null) { + return ""; + } + return g.getVariables().getVarString("suffix"); + } + + /** + * Checks the specified group for the Info Build node. Does NOT check + * inheritance + * + * @param groupName + * @return true if can build + */ + @Override + public boolean canGroupBuild(String groupName) { + + Group g = ph.getGroup(groupName); + if (g == null) { + return false; + } + return g.getVariables().getVarBoolean("build"); + } + + /** + * It returns a string variable value, set in the INFO node of the group. It + * will harvest inheritance for value. + * + * @param groupName + * @param variable + * @return null if no group with that variable is found. + */ + @Override + public String getGroupPermissionString(String groupName, String variable) { + + Group start = ph.getGroup(groupName); + if (start == null) { + return null; + } + Group result = nextGroupWithVariable(start, variable); + if (result == null) { + return null; + } + return result.getVariables().getVarString(variable); + } + + /** + * It returns a Integer variable value It will harvest inheritance for + * value. + * + * @param groupName + * @param variable + * @return -1 if none found or not parseable. + */ + @Override + public int getGroupPermissionInteger(String groupName, String variable) { + + Group start = ph.getGroup(groupName); + if (start == null) { + return -1; + } + Group result = nextGroupWithVariable(start, variable); + if (result == null) { + return -1; + } + return result.getVariables().getVarInteger(variable); + } + + /** + * Returns a boolean for given variable in INFO node. It will harvest + * inheritance for value. + * + * @param group + * @param variable + * @return false if not found/not parseable. + */ + @Override + public boolean getGroupPermissionBoolean(String group, String variable) { + + Group start = ph.getGroup(group); + if (start == null) { + return false; + } + Group result = nextGroupWithVariable(start, variable); + if (result == null) { + return false; + } + return result.getVariables().getVarBoolean(variable); + } + + /** + * Returns a double value for the given variable name in INFO node. It will + * harvest inheritance for value. + * + * @param group + * @param variable + * @return -1 if not found / not parseable. + */ + @Override + public double getGroupPermissionDouble(String group, String variable) { + + Group start = ph.getGroup(group); + if (start == null) { + return -1; + } + Group result = nextGroupWithVariable(start, variable); + if (result == null) { + return -1; + } + return result.getVariables().getVarDouble(variable); + } + + /** + * Returns the variable value of the user, in INFO node. + * + * @param user + * @param variable + * @return empty string if not found + */ + @Override + public String getUserPermissionString(String user, String variable) { + + User auser = ph.getUser(user); + if (auser == null) { + return ""; + } + return auser.getVariables().getVarString(variable); + } + + /** + * Returns the variable value of the user, in INFO node. + * + * @param user + * @param variable + * @return -1 if not found + */ + @Override + public int getUserPermissionInteger(String user, String variable) { + + User auser = ph.getUser(user); + if (auser == null) { + return -1; + } + return auser.getVariables().getVarInteger(variable); + } + + /** + * Returns the variable value of the user, in INFO node. + * + * @param user + * @param variable + * @return boolean value + */ + @Override + public boolean getUserPermissionBoolean(String user, String variable) { + + User auser = ph.getUser(user); + if (auser == null) { + return false; + } + return auser.getVariables().getVarBoolean(variable); + } + + /** + * Returns the variable value of the user, in INFO node. + * + * @param user + * @param variable + * @return -1 if not found + */ + @Override + public double getUserPermissionDouble(String user, String variable) { + + User auser = ph.getUser(user); + if (auser == null) { + return -1; + } + return auser.getVariables().getVarDouble(variable); + } + + /** + * Returns the variable value of the user, in INFO node. If not found, it + * will search for his Group variables. It will harvest the inheritance and + * subgroups. + * + * @param user + * @param variable + * @return empty string if not found + */ + @Override + public String getPermissionString(String user, String variable) { + + User auser = ph.getUser(user); + if (auser == null) { + return ""; + } + if (auser.getVariables().hasVar(variable)) { + return auser.getVariables().getVarString(variable); + } + Group start = auser.getGroup(); + if (start == null) { + return ""; + } + Group result = nextGroupWithVariable(start, variable); + if (result == null) { + // Check sub groups + if (!auser.isSubGroupsEmpty()) + for (Group subGroup : auser.subGroupListCopy()) { + result = nextGroupWithVariable(subGroup, variable); + // Found value? + if (result != null) + continue; + } + if (result == null) + return ""; + } + return result.getVariables().getVarString(variable); + // return getUserPermissionString(user, variable); + } + + /** + * Returns the variable value of the user, in INFO node. If not found, it + * will search for his Group variables. It will harvest the inheritance and + * subgroups. + * + * @param user + * @param variable + * @return -1 if not found + */ + @Override + public int getPermissionInteger(String user, String variable) { + + User auser = ph.getUser(user); + if (auser == null) { + return -1; + } + if (auser.getVariables().hasVar(variable)) { + return auser.getVariables().getVarInteger(variable); + } + Group start = auser.getGroup(); + if (start == null) { + return -1; + } + Group result = nextGroupWithVariable(start, variable); + if (result == null) { + // Check sub groups + if (!auser.isSubGroupsEmpty()) + for (Group subGroup : auser.subGroupListCopy()) { + result = nextGroupWithVariable(subGroup, variable); + // Found value? + if (result != null) + continue; + } + if (result == null) + return -1; + } + return result.getVariables().getVarInteger(variable); + // return getUserPermissionInteger(string, string1); + } + + /** + * Returns the variable value of the user, in INFO node. If not found, it + * will search for his Group variables. It will harvest the inheritance and + * subgroups. + * + * @param user + * @param variable + * @return false if not found or not parseable to true. + */ + @Override + public boolean getPermissionBoolean(String user, String variable) { + + User auser = ph.getUser(user); + if (auser == null) { + return false; + } + if (auser.getVariables().hasVar(variable)) { + return auser.getVariables().getVarBoolean(variable); + } + Group start = auser.getGroup(); + if (start == null) { + return false; + } + Group result = nextGroupWithVariable(start, variable); + if (result == null) { + // Check sub groups + if (!auser.isSubGroupsEmpty()) + for (Group subGroup : auser.subGroupListCopy()) { + result = nextGroupWithVariable(subGroup, variable); + // Found value? + if (result != null) + continue; + } + if (result == null) + return false; + } + return result.getVariables().getVarBoolean(variable); + // return getUserPermissionBoolean(user, string1); + } + + /** + * Returns the variable value of the user, in INFO node. If not found, it + * will search for his Group variables. It will harvest the inheritance and + * subgroups. + * + * @param user + * @param variable + * @return -1 if not found. + */ + @Override + public double getPermissionDouble(String user, String variable) { + + User auser = ph.getUser(user); + if (auser == null) { + return -1.0D; + } + if (auser.getVariables().hasVar(variable)) { + return auser.getVariables().getVarDouble(variable); + } + Group start = auser.getGroup(); + if (start == null) { + return -1.0D; + } + Group result = nextGroupWithVariable(start, variable); + if (result == null) { + // Check sub groups + if (!auser.isSubGroupsEmpty()) + for (Group subGroup : auser.subGroupListCopy()) { + result = nextGroupWithVariable(subGroup, variable); + // Found value? + if (result != null) + continue; + } + if (result == null) + return -1.0D; + } + return result.getVariables().getVarDouble(variable); + // return getUserPermissionDouble(string, string1); + } + + /** + * Does not include User's group permission + * + * @param user + * @param permission + * @return PermissionCheckResult + */ + public PermissionCheckResult checkUserOnlyPermission(User user, String permission) { + + user.sortPermissions(); + PermissionCheckResult result = new PermissionCheckResult(); + result.askedPermission = permission; + result.owner = user; + for (String access : user.getPermissionList()) { + result.resultType = comparePermissionString(access, permission); + if (result.resultType != PermissionCheckResult.Type.NOTFOUND) { + result.accessLevel = access; + return result; + } + } + result.resultType = PermissionCheckResult.Type.NOTFOUND; + return result; + } + + /** + * Returns the node responsible for that permission. Does not include User's + * group permission. + * + * @param group + * @param permission + * @return the node if permission is found. if not found, return null + */ + public PermissionCheckResult checkGroupOnlyPermission(Group group, String permission) { + + group.sortPermissions(); + PermissionCheckResult result = new PermissionCheckResult(); + result.owner = group; + result.askedPermission = permission; + for (String access : group.getPermissionList()) { + result.resultType = comparePermissionString(access, permission); + if (result.resultType != PermissionCheckResult.Type.NOTFOUND) { + result.accessLevel = access; + return result; + } + } + result.resultType = PermissionCheckResult.Type.NOTFOUND; + return result; + } + + /** + * Check permissions, including it's group and inheritance. + * + * @param user + * @param permission + * @return true if permission was found. false if not, or was negated. + */ + public boolean checkUserPermission(User user, String permission) { + + PermissionCheckResult result = checkFullGMPermission(user, permission, true); + if (result.resultType == PermissionCheckResult.Type.EXCEPTION || result.resultType == PermissionCheckResult.Type.FOUND) { + return true; + } + + return false; + } + + /** + * Do what checkUserPermission did before. But now returning a + * PermissionCheckResult. + * + * @param user + * @param targetPermission + * @return PermissionCheckResult + */ + public PermissionCheckResult checkFullUserPermission(User user, String targetPermission) { + + return checkFullGMPermission(user, targetPermission, true); + } + + /** + * Wrapper for offline server checks. + * Looks for the 'groupmanager.noofflineperms' permissions and reports no permissions on servers set to offline. + * + * Check user and groups with inheritance and Bukkit if bukkit = true return + * a PermissionCheckResult. + * + * @param user + * @param targetPermission + * @param checkBukkit + * @return PermissionCheckResult + */ + public PermissionCheckResult checkFullGMPermission(User user, String targetPermission, Boolean checkBukkit) { + + /* + * Report no permissions under the following conditions. + * + * We are in offline mode + * and the player has the 'groupmanager.noofflineperms' permission. + */ + if (user == null || targetPermission == null || targetPermission.isEmpty() + || (!Bukkit.getServer().getOnlineMode() + && (checkPermission(user, "groupmanager.noofflineperms", false).resultType == PermissionCheckResult.Type.FOUND))) { + + PermissionCheckResult result = new PermissionCheckResult(); + result.accessLevel = targetPermission; + result.resultType = PermissionCheckResult.Type.NOTFOUND; + + return result; + } + + return checkPermission(user, targetPermission, checkBukkit); + } + + /** + * + * Check user and groups with inheritance and Bukkit if bukkit = true return + * a PermissionCheckResult. + * + * @param user + * @param targetPermission + * @param checkBukkit + * @return PermissionCheckResult + */ + private PermissionCheckResult checkPermission(User user, String targetPermission, Boolean checkBukkit) { + + PermissionCheckResult result = new PermissionCheckResult(); + result.accessLevel = targetPermission; + result.resultType = PermissionCheckResult.Type.NOTFOUND; + + if (checkBukkit) { + // Check Bukkit perms to support plugins which add perms via code + // (Heroes). + final Player player = user.getBukkitPlayer(); + //final Permission bukkitPerm = Bukkit.getPluginManager().getPermission(targetPermission); + if ((player != null) && player.hasPermission(targetPermission)) { + result.resultType = PermissionCheckResult.Type.FOUND; + result.owner = user; + return result; + } + } + + PermissionCheckResult resultUser = checkUserOnlyPermission(user, targetPermission); + if (resultUser.resultType != PermissionCheckResult.Type.NOTFOUND) { + + resultUser.accessLevel = targetPermission; + + if (resultUser.resultType == PermissionCheckResult.Type.EXCEPTION) { + return resultUser; + } + + result = resultUser; + + } + + // IT ONLY CHECKS GROUPS PERMISSIONS IF RESULT FOR USER IS NOT AN EXCEPTION + PermissionCheckResult resultGroup = checkGroupPermissionWithInheritance(user.getGroup(), targetPermission); + if (resultGroup.resultType != PermissionCheckResult.Type.NOTFOUND) { + + resultGroup.accessLevel = targetPermission; + + if (resultGroup.resultType == PermissionCheckResult.Type.EXCEPTION) { + return resultGroup; + } + + // Do not override higher level permissions with negations. + if (result.resultType == PermissionCheckResult.Type.NOTFOUND) { + result = resultGroup; + } + + } + + // Do we have a high level negation? + boolean negated = (result.resultType == PermissionCheckResult.Type.NEGATION); + + // SUBGROUPS CHECK + for (Group subGroup : user.subGroupListCopy()) { + + PermissionCheckResult resultSubGroup = checkGroupPermissionWithInheritance(subGroup, targetPermission); + if (resultSubGroup.resultType != PermissionCheckResult.Type.NOTFOUND) { + + resultSubGroup.accessLevel = targetPermission; + + // Allow exceptions to override higher level negations + // but low level negations can not remove higher level permissions. + if (resultSubGroup.resultType == PermissionCheckResult.Type.EXCEPTION) { + + return resultSubGroup; + + } else if ((resultSubGroup.resultType == PermissionCheckResult.Type.FOUND) && (result.resultType != PermissionCheckResult.Type.NEGATION) && !negated) { + + result = resultSubGroup; + + } else if ((resultSubGroup.resultType == PermissionCheckResult.Type.NEGATION) && !negated) { + + result = resultSubGroup; + } + + } + } + + // THEN IT RETURNS A NOT FOUND + // OR THE RESULT OF THE SUBGROUP SEARCH. + return result; + } + + /** + * Returns the next group, including inheritance, which contains that + * variable name. + * + * It does Breadth-first search + * + * @param start the starting group to look for + * @param targetVariable the variable name + * @return The group if found. Null if not. + */ + public Group nextGroupWithVariable(Group start, String targetVariable) { + + if (start == null || targetVariable == null) { + return null; + } + LinkedList stack = new LinkedList(); + ArrayList alreadyVisited = new ArrayList(); + stack.push(start); + alreadyVisited.add(start); + while (!stack.isEmpty()) { + Group now = stack.pop(); + if (now.getVariables().hasVar(targetVariable)) { + return now; + } + for (String sonName : now.getInherits()) { + Group son = ph.getGroup(sonName); + if (son != null && !alreadyVisited.contains(son)) { + stack.push(son); + alreadyVisited.add(son); + } + } + } + return null; + } + + + /** + * Check if given group inherits another group. + * + * It does Breadth-first search + * + * @param start The group to start the search. + * @param askedGroup Name of the group you're looking for + * @return true if it inherits the group. + */ + public boolean hasGroupInInheritance(Group start, String askedGroup) { + + if (start == null || askedGroup == null) { + return false; + } + LinkedList stack = new LinkedList(); + ArrayList alreadyVisited = new ArrayList(); + stack.push(start); + alreadyVisited.add(start); + while (!stack.isEmpty()) { + Group now = stack.pop(); + if (now.getName().equalsIgnoreCase(askedGroup)) { + return true; + } + for (String sonName : now.getInherits()) { + Group son = ph.getGroup(sonName); + if (son != null && !alreadyVisited.contains(son)) { + stack.push(son); + alreadyVisited.add(son); + } + } + } + return false; + } + + /** + * Returns the result of permission check. Including inheritance. If found + * anything, the PermissionCheckResult that retuns will include the Group + * name, and the result type. Result types will be EXCEPTION, NEGATION, + * FOUND. + * + * If returned type NOTFOUND, the owner will be null, and ownerType too. + * + * It does Breadth-first search + * + * @param start + * @param targetPermission + * @return PermissionCheckResult + */ + public PermissionCheckResult checkGroupPermissionWithInheritance(Group start, String targetPermission) { + + if (start == null || targetPermission == null) { + return null; + } + + LinkedList stack = new LinkedList(); + List alreadyVisited = new ArrayList(); + PermissionCheckResult result = new PermissionCheckResult(); + + stack.push(start); + alreadyVisited.add(start); + + // Set defaults. + result.askedPermission = targetPermission; + result.resultType = PermissionCheckResult.Type.NOTFOUND; + + while (!stack.isEmpty()) { + Group now = stack.pop(); + PermissionCheckResult resultNow = checkGroupOnlyPermission(now, targetPermission); + + if (!resultNow.resultType.equals(PermissionCheckResult.Type.NOTFOUND)) { + + if (resultNow.resultType.equals(PermissionCheckResult.Type.EXCEPTION)) { + resultNow.accessLevel = targetPermission; + return resultNow; + } + + // Negation found so store for later + // as we need to continue looking for an Exception. + result = resultNow; + } + + for (String sonName : now.getInherits()) { + Group son = ph.getGroup(sonName); + if (son != null && !alreadyVisited.contains(son)) { + // Add rather than push to retain inheritance order. + stack.add(son); + alreadyVisited.add(son); + } + } + } + + return result; + } + + /** + * Return whole list of names of groups in a inheritance chain. Including a + * starting group. + * + * It does Breadth-first search. So closer groups will appear first in list. + * + * @param start + * @return the group that passed on test. null if no group passed. + */ + public ArrayList listAllGroupsInherited(Group start) { + + if (start == null) { + return null; + } + LinkedList stack = new LinkedList(); + ArrayList alreadyVisited = new ArrayList(); + stack.push(start); + alreadyVisited.add(start.getName()); + while (!stack.isEmpty()) { + Group now = stack.pop(); + for (String sonName : now.getInherits()) { + Group son = ph.getGroup(sonName); + if (son != null && !alreadyVisited.contains(son.getName())) { + stack.push(son); + alreadyVisited.add(son.getName()); + } + } + } + return alreadyVisited; + } + + /** + * Compare a user permission like 'myplugin.*' against a full plugin + * permission name, like 'myplugin.dosomething'. As the example above, will + * return true. + * + * Please sort permissions before sending them here. So negative tokens get + * priority. + * + * You must test if it start with negative outside this method. It will only + * tell if the nodes are matching or not. + * + * Every '-' or '+' in the beginning is ignored. It will match only node + * names. + * + * @param userAccessLevel + * @param fullPermissionName + * @return PermissionCheckResult.Type + */ + public PermissionCheckResult.Type comparePermissionString(String userAccessLevel, String fullPermissionName) { + + int userAccessLevelLength; + if (userAccessLevel == null || fullPermissionName == null || fullPermissionName.length() == 0 || (userAccessLevelLength = userAccessLevel.length()) == 0) { + return PermissionCheckResult.Type.NOTFOUND; + } + + PermissionCheckResult.Type result = PermissionCheckResult.Type.FOUND; + int userAccessLevelOffset = 0; + if (userAccessLevel.charAt(0) == '+') { + userAccessLevelOffset = 1; + result = PermissionCheckResult.Type.EXCEPTION; + } else if (userAccessLevel.charAt(0) == '-') { + userAccessLevelOffset = 1; + result = PermissionCheckResult.Type.NEGATION; + } + + if (fullPermissionName.equals(userAccessLevel)) { + return result; + } + + if ("groupmanager.noofflineperms".equals(fullPermissionName)) { + result = PermissionCheckResult.Type.NOTFOUND; + } + + if ("*".regionMatches(0, userAccessLevel, userAccessLevelOffset, userAccessLevelLength - userAccessLevelOffset)) { + return result; + } + int fullPermissionNameOffset; + if (fullPermissionName.charAt(0) == '+' || fullPermissionName.charAt(0) == '-') { + fullPermissionNameOffset = 1; + } else { + fullPermissionNameOffset = 0; + } + + if (userAccessLevel.charAt(userAccessLevel.length() - 1) == '*') { + return userAccessLevel.regionMatches(true, userAccessLevelOffset, fullPermissionName, fullPermissionNameOffset, userAccessLevelLength - userAccessLevelOffset - 1) ? result : PermissionCheckResult.Type.NOTFOUND; + } else { + return userAccessLevel.regionMatches(true, userAccessLevelOffset, fullPermissionName, fullPermissionNameOffset, Math.max(userAccessLevelLength - userAccessLevelOffset, fullPermissionName.length() - fullPermissionNameOffset)) ? result : PermissionCheckResult.Type.NOTFOUND; + } + } + + /** + * Returns a list of all groups. + * + * Including subgroups. + * + * @param userName + * @return String[] of all group names. + */ + @Override + public String[] getGroups(String userName) { + + ArrayList allGroups = listAllGroupsInherited(ph.getUser(userName).getGroup()); + for (Group subg : ph.getUser(userName).subGroupListCopy()) { + allGroups.addAll(listAllGroupsInherited(subg)); + } + + String[] arr = new String[allGroups.size()]; + return allGroups.toArray(arr); + } + + /** + * A Breadth-first search thru inheritance model. + * + * Just a model to copy and paste. This will guarantee the closer groups + * will be checked first. + * + * @param start + * @param targerPermission + * @return + */ + @SuppressWarnings("unused") + private Group breadthFirstSearch(Group start, String targerPermission) { + + if (start == null || targerPermission == null) { + return null; + } + LinkedList stack = new LinkedList(); + ArrayList alreadyVisited = new ArrayList(); + stack.push(start); + alreadyVisited.add(start); + while (!stack.isEmpty()) { + Group now = stack.pop(); + PermissionCheckResult resultNow = checkGroupOnlyPermission(now, targerPermission); + if (resultNow.resultType.equals(PermissionCheckResult.Type.EXCEPTION) || resultNow.resultType.equals(PermissionCheckResult.Type.FOUND)) { + return now; + } + if (resultNow.resultType.equals(PermissionCheckResult.Type.NEGATION)) { + return null; + } + for (String sonName : now.getInherits()) { + Group son = ph.getGroup(sonName); + if (son != null && !alreadyVisited.contains(son)) { + stack.push(son); + alreadyVisited.add(son); + } + } + } + return null; + } + + @Override + public Group getDefaultGroup() { + + return ph.getDefaultGroup(); + } + + @Override + public String getInfoString(String entryName, String path, boolean isGroup) { + + if (isGroup) { + Group data = ph.getGroup(entryName); + if (data == null) { + return null; + } + return data.getVariables().getVarString(path); + } else { + User data = ph.getUser(entryName); + if (data == null) { + return null; + } + return data.getVariables().getVarString(path); + } + } + + @Override + public int getInfoInteger(String entryName, String path, boolean isGroup) { + + if (isGroup) { + Group data = ph.getGroup(entryName); + if (data == null) { + return -1; + } + return data.getVariables().getVarInteger(path); + } else { + User data = ph.getUser(entryName); + if (data == null) { + return -1; + } + return data.getVariables().getVarInteger(path); + } + } + + @Override + public double getInfoDouble(String entryName, String path, boolean isGroup) { + + if (isGroup) { + Group data = ph.getGroup(entryName); + if (data == null) { + return -1; + } + return data.getVariables().getVarDouble(path); + } else { + User data = ph.getUser(entryName); + if (data == null) { + return -1; + } + return data.getVariables().getVarDouble(path); + } + + } + + @Override + public boolean getInfoBoolean(String entryName, String path, boolean isGroup) { + + if (isGroup) { + Group data = ph.getGroup(entryName); + if (data == null) { + return false; + } + return data.getVariables().getVarBoolean(path); + } else { + User data = ph.getUser(entryName); + if (data == null) { + return false; + } + return data.getVariables().getVarBoolean(path); + } + } + + @Override + public void addUserInfo(String name, String path, Object data) { + + ph.getUser(name).getVariables().addVar(path, data); + } + + @Override + public void removeUserInfo(String name, String path) { + + ph.getUser(name).getVariables().removeVar(path); + } + + @Override + public void addGroupInfo(String name, String path, Object data) { + + ph.getGroup(name).getVariables().addVar(path, data); + } + + @Override + public void removeGroupInfo(String name, String path) { + + ph.getGroup(name).getVariables().removeVar(path); + } +} diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/BukkitPermissions.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/BukkitPermissions.java new file mode 100644 index 0000000000..a4f68864f0 --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/BukkitPermissions.java @@ -0,0 +1,500 @@ +/* + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +package org.anjocaido.groupmanager.permissions; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; + +import org.anjocaido.groupmanager.GroupManager; +import org.anjocaido.groupmanager.data.User; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerChangedWorldEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.server.PluginDisableEvent; +import org.bukkit.event.server.PluginEnableEvent; +import org.bukkit.permissions.Permission; +import org.bukkit.permissions.PermissionAttachment; +import org.bukkit.permissions.PermissionAttachmentInfo; +import org.bukkit.plugin.PluginManager; + +/** + * + * BukkitPermissions overrides to force GM reponses to Superperms + * + * @author ElgarL + */ +public class BukkitPermissions { + + protected WeakHashMap attachments = new WeakHashMap(); + protected LinkedHashMap registeredPermissions = new LinkedHashMap(); + protected GroupManager plugin; + protected boolean dumpAllPermissions = true; + protected boolean dumpMatchedPermissions = true; + private boolean player_join = false; + + /** + * @return the player_join + */ + public boolean isPlayer_join() { + + return player_join; + } + + /** + * @param player_join the player_join to set + */ + public void setPlayer_join(boolean player_join) { + + this.player_join = player_join; + } + + private static Field permissions; + + // Setup reflection (Thanks to Codename_B for the reflection source) + static { + try { + permissions = PermissionAttachment.class.getDeclaredField("permissions"); + permissions.setAccessible(true); + } catch (SecurityException e) { + e.printStackTrace(); + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } + } + + public BukkitPermissions(GroupManager plugin) { + + this.plugin = plugin; + this.reset(); + this.registerEvents(); + + + GroupManager.logger.info("Superperms support enabled."); + } + + public void reset() { + + /* + * collect new permissions + * and register all attachments. + */ + this.collectPermissions(); + this.updateAllPlayers(); + } + + private void registerEvents() { + + PluginManager manager = plugin.getServer().getPluginManager(); + + manager.registerEvents(new PlayerEvents(), plugin); + manager.registerEvents(new BukkitEvents(), plugin); + } + + public void collectPermissions() { + + registeredPermissions.clear(); + + for (Permission perm : Bukkit.getPluginManager().getPermissions()) { + registeredPermissions.put(perm.getName().toLowerCase(), perm); + } + + } + + public void updatePermissions(Player player) { + + this.updatePermissions(player, null); + } + + /** + * Push all permissions which are registered with GM for this player, on + * this world to Bukkit and make it update for the child nodes. + * + * @param player + * @param world + */ + public void updatePermissions(Player player, String world) { + + if (player == null || !GroupManager.isLoaded()) { + return; + } + + String name = player.getName(); + + // Reset the User objects player reference. + User user = plugin.getWorldsHolder().getWorldData(player.getWorld().getName()).getUser(name); + if (user != null) + user.updatePlayer(player); + + PermissionAttachment attachment; + + // Find the players current attachment, or add a new one. + if (this.attachments.containsKey(name)) { + attachment = this.attachments.get(name); + } else { + attachment = player.addAttachment(plugin); + this.attachments.put(name, attachment); + } + + if (world == null) { + world = player.getWorld().getName(); + } + + // Add all permissions for this player (GM only) + // child nodes will be calculated by Bukkit. + List playerPermArray = new ArrayList(plugin.getWorldsHolder().getWorldData(world).getPermissionsHandler().getAllPlayersPermissions(name, false)); + LinkedHashMap newPerms = new LinkedHashMap(); + + // Sort the perm list by parent/child, so it will push to superperms + // correctly. + playerPermArray = sort(playerPermArray); + + Boolean value = false; + for (String permission : playerPermArray) { + value = (!permission.startsWith("-")); + newPerms.put((value ? permission : permission.substring(1)), value); + } + + /* + * Do not push any perms to bukkit if... + * We are in offline mode + * and the player has the 'groupmanager.noofflineperms' permission. + */ + if (!Bukkit.getServer().getOnlineMode() + && (newPerms.containsKey("groupmanager.noofflineperms") && (newPerms.get("groupmanager.noofflineperms") == true))) { + removeAttachment(name); + return; + } + + + /** + * This is put in place until such a time as Bukkit pull 466 is + * implemented https://github.com/Bukkit/Bukkit/pull/466 + */ + try { // Codename_B source + synchronized (attachment.getPermissible()) { + + @SuppressWarnings("unchecked") + Map orig = (Map) permissions.get(attachment); + // Clear the map (faster than removing the attachment and + // recalculating) + orig.clear(); + // Then whack our map into there + orig.putAll(newPerms); + // That's all folks! + attachment.getPermissible().recalculatePermissions(); + + } + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + + GroupManager.logger.finest("Attachment updated for: " + name); + } + + /** + * Sort a permission node list by parent/child + * + * @param permList + * @return List sorted for priority + */ + private List sort(List permList) { + + List result = new ArrayList(); + + for (String key : permList) { + /* + * Ignore stupid plugins which add empty permission nodes. + */ + if (!key.isEmpty()) { + String a = key.charAt(0) == '-' ? key.substring(1) : key; + Map allchildren = GroupManager.BukkitPermissions.getAllChildren(a, new HashSet()); + if (allchildren != null) { + + ListIterator itr = result.listIterator(); + + while (itr.hasNext()) { + String node = (String) itr.next(); + String b = node.charAt(0) == '-' ? node.substring(1) : node; + + // Insert the parent node before the child + if (allchildren.containsKey(b)) { + itr.set(key); + itr.add(node); + break; + } + } + } + if (!result.contains(key)) + result.add(key); + } + } + + return result; + } + + /** + * Fetch all permissions which are registered with superperms. + * {can include child nodes) + * + * @param includeChildren + * @return List of all permission nodes + */ + public List getAllRegisteredPermissions(boolean includeChildren) { + + List perms = new ArrayList(); + + for (String key : registeredPermissions.keySet()) { + if (!perms.contains(key)) { + perms.add(key); + + if (includeChildren) { + Map children = getAllChildren(key, new HashSet()); + if (children != null) { + for (String node : children.keySet()) + if (!perms.contains(node)) + perms.add(node); + } + } + } + + } + return perms; + } + + /** + * Returns a map of ALL child permissions registered with bukkit + * null is empty + * + * @param node + * @param playerPermArray current list of perms to check against for + * negations + * @return Map of child permissions + */ + public Map getAllChildren(String node, Set playerPermArray) { + + LinkedList stack = new LinkedList(); + Map alreadyVisited = new HashMap(); + stack.push(node); + alreadyVisited.put(node, true); + + while (!stack.isEmpty()) { + String now = stack.pop(); + + Map children = getChildren(now); + + if ((children != null) && (!playerPermArray.contains("-" + now))) { + for (String childName : children.keySet()) { + if (!alreadyVisited.containsKey(childName)) { + stack.push(childName); + alreadyVisited.put(childName, children.get(childName)); + } + } + } + } + alreadyVisited.remove(node); + if (!alreadyVisited.isEmpty()) + return alreadyVisited; + + return null; + } + + /** + * Returns a map of the child permissions (1 node deep) as registered with + * Bukkit. + * null is empty + * + * @param node + * @return Map of child permissions + */ + public Map getChildren(String node) { + + Permission perm = registeredPermissions.get(node.toLowerCase()); + if (perm == null) + return null; + + return perm.getChildren(); + + } + + /** + * List all effective permissions for this player. + * + * @param player + * @return List of permissions + */ + public List listPerms(Player player) { + + List perms = new ArrayList(); + + /* + * // All permissions registered with Bukkit for this player + * PermissionAttachment attachment = this.attachments.get(player); + * + * // List perms for this player perms.add("Attachment Permissions:"); + * for(Map.Entry entry : + * attachment.getPermissions().entrySet()){ perms.add(" " + + * entry.getKey() + " = " + entry.getValue()); } + */ + + perms.add("Effective Permissions:"); + for (PermissionAttachmentInfo info : player.getEffectivePermissions()) { + if (info.getValue() == true) + perms.add(" " + info.getPermission() + " = " + info.getValue()); + } + return perms; + } + + /** + * force Bukkit to update every OnlinePlayers permissions. + */ + public void updateAllPlayers() { + + for (Player player : Bukkit.getServer().getOnlinePlayers()) { + updatePermissions(player); + } + } + + /** + * force Bukkit to update this Players permissions. + */ + public void updatePlayer(Player player) { + + if (player != null) + this.updatePermissions(player, null); + } + + /** + * Force remove any attachments + * + * @param player + */ + private void removeAttachment(String playerName) { + + if (attachments.containsKey(playerName)) { + attachments.get(playerName).remove(); + attachments.remove(playerName); + } + } + + /** + * Remove all attachments in case of a restart or reload. + */ + public void removeAllAttachments() { + + /* + * Remove all attachments. + */ + for (String key : attachments.keySet()) { + attachments.get(key).remove(); + } + attachments.clear(); + } + + /** + * Player events tracked to cause Superperms updates + * + * @author ElgarL + * + */ + protected class PlayerEvents implements Listener { + + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerJoin(PlayerJoinEvent event) { + + + + setPlayer_join(true); + Player player = event.getPlayer(); + + GroupManager.logger.finest("Player Join event: " + player.getName()); + + /* + * Tidy up any lose ends + */ + removeAttachment(player.getName()); + + // force GM to create the player if they are not already listed. + plugin.getWorldsHolder().getWorldData(player.getWorld().getName()).getUser(player.getUniqueId().toString(), player.getName()); + + setPlayer_join(false); + updatePermissions(event.getPlayer()); + + setPlayer_join(false); + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerChangeWorld(PlayerChangedWorldEvent event) { // has changed worlds + + updatePermissions(event.getPlayer(), event.getPlayer().getWorld().getName()); + } + + /* + * Trigger at highest so we tidy up last. + */ + @EventHandler(priority = EventPriority.HIGHEST) + public void onPlayerQuit(PlayerQuitEvent event) { + + if (!GroupManager.isLoaded()) + return; + + Player player = event.getPlayer(); + + /* + * force remove any attachments as bukkit may not + */ + removeAttachment(player.getName()); + } + } + + protected class BukkitEvents implements Listener { + + @EventHandler(priority = EventPriority.NORMAL) + public void onPluginEnable(PluginEnableEvent event) { + + if (!GroupManager.isLoaded()) + return; + + collectPermissions(); + updateAllPlayers(); + } + + @EventHandler(priority = EventPriority.NORMAL) + public void onPluginDisable(PluginDisableEvent event) { + + collectPermissions(); + // updateAllPlayers(); + } + } + +} diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/PermissionsReaderInterface.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/PermissionsReaderInterface.java new file mode 100644 index 0000000000..69f098949e --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/permissions/PermissionsReaderInterface.java @@ -0,0 +1,252 @@ +package org.anjocaido.groupmanager.permissions; + +//import java.util.Collection; +//import java.util.Map; +//import java.util.Set; +import java.util.List; +import java.util.Set; + +import org.anjocaido.groupmanager.data.Group; +//import org.anjocaido.groupmanager.data.User; +import org.bukkit.entity.Player; + +/** + * Made by Nijikokun. Changed by Gabriel Couto + * + * This class is intended to *read* permissions from a single world. + * + * @author Nijikokun + * @author Gabriel Couto + * @author ElgarL + */ +public abstract class PermissionsReaderInterface { + + /** + * + * @param player + * @param string + * @return true if has permission + */ + public abstract boolean has(Player player, String string); + + /** + * + * @param player + * @param string + * @return true if has permission + */ + public abstract boolean permission(Player player, String string); + + /** + * + * @param userName + * @return group name for this player. + */ + public abstract String getGroup(String userName); + + /** + * + * @param userName + * @param groupName + * @return true if in group + */ + public abstract boolean inGroup(String userName, String groupName); + + /** + * + * @param groupName + * @return String of prefix + */ + public abstract String getGroupPrefix(String groupName); + + /** + * + * @param groupName + * @return String of suffix + */ + public abstract String getGroupSuffix(String groupName); + + /** + * + * @param groupName + * @return true if can build + */ + public abstract boolean canGroupBuild(String groupName); + + /** + * + * @param groupName + * @param node + * @return String value + */ + public abstract String getGroupPermissionString(String groupName, String node); + + /** + * + * @param groupName + * @param node + * @return integer value + */ + public abstract int getGroupPermissionInteger(String groupName, String node); + + /** + * + * @param groupName + * @param node + * @return boolean value + */ + public abstract boolean getGroupPermissionBoolean(String groupName, String node); + + /** + * + * @param groupName + * @param node + * @return double value + */ + public abstract double getGroupPermissionDouble(String groupName, String node); + + /** + * + * @param userName + * @param node + * @return String value + */ + public abstract String getUserPermissionString(String userName, String node); + + /** + * + * @param userName + * @param node + * @return integer value + */ + public abstract int getUserPermissionInteger(String userName, String node); + + /** + * + * @param userName + * @param node + * @return boolean value + */ + public abstract boolean getUserPermissionBoolean(String userName, String node); + + /** + * + * @param userName + * @param node + * @return double value + */ + public abstract double getUserPermissionDouble(String userName, String node); + + /** + * + * @param userName + * @param node + * @return String value + */ + public abstract String getPermissionString(String userName, String node); + + /** + * + * @param userName + * @param node + * @return integer value + */ + public abstract int getPermissionInteger(String userName, String node); + + /** + * + * @param userName + * @param node + * @return boolean value + */ + public abstract boolean getPermissionBoolean(String userName, String node); + + /** + * + * @param userName + * @param node + * @return double value + */ + public abstract double getPermissionDouble(String userName, String node); + + ///////////////////////////// + /** + * Gets the appropriate prefix for the user. + * This method is a utility method for chat plugins to get the user's prefix + * without having to look at every one of the user's ancestors. + * Returns an empty string if user has no parent groups. + * + * @param user Player's name + * @return Player's prefix + */ + public abstract String getUserPrefix(String user); + + /** + * Gets the appropriate suffix for the user. + * This method is a utility method for chat plugins to get the user's suffix + * without having to look at every one of the user's ancestors. + * Returns an empty string if user has no parent groups. + * + * @param user Player's name + * @return Player's suffix + */ + public abstract String getUserSuffix(String user); + + /** + * Returns the group object representing the default group of the given + * world. + * This method will return null if the object does not exist or the world + * has no default group. + * + * @return Group object representing default world, or null if it doesn't + * exist or is not defined. + */ + public abstract Group getDefaultGroup(); + + /** + * Gets a array of the names of all parent groups in the same world. + * + * @param name Target user's name + * @return An array containing the names of all parent groups (including + * ancestors) that are in the same world + */ + public abstract String[] getGroups(String name); + + public abstract String getInfoString(String entryName, String path, boolean isGroup); + + //public abstract String getInfoString(String entryName, String path, boolean isGroup, Comparator comparator); + + public abstract int getInfoInteger(String entryName, String path, boolean isGroup); + + //public abstract int getInfoInteger(String entryName, String path, boolean isGroup, Comparator comparator); + + /** + * Gets a double from the Info node without inheritance. + * + * @param entryName + * @param path + * @param isGroup + * @return -1 if not found + */ + public abstract double getInfoDouble(String entryName, String path, boolean isGroup); + + //public abstract double getInfoDouble(String entryName, String path, boolean isGroup, Comparator comparator); + + public abstract boolean getInfoBoolean(String entryName, String path, boolean isGroup); + + //public abstract boolean getInfoBoolean(String entryName, String path, boolean isGroup, Comparator comparator); + + public abstract void addUserInfo(String name, String path, Object data); + + public abstract void removeUserInfo(String name, String path); + + public abstract void addGroupInfo(String name, String path, Object data); + + public abstract void removeGroupInfo(String name, String path); + + ////////////////////////////// + + public abstract List getAllPlayersPermissions(String userName); + + public abstract Set getAllPlayersPermissions(String userName, Boolean includeChildren); +} diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/GMLoggerHandler.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/GMLoggerHandler.java new file mode 100644 index 0000000000..de5348b17c --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/GMLoggerHandler.java @@ -0,0 +1,27 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.anjocaido.groupmanager.utils; + +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.LogRecord; + +/** + * + * @author gabrielcouto + */ +public class GMLoggerHandler extends ConsoleHandler { + + @Override + public void publish(LogRecord record) { + + String message = "GroupManager - " + record.getLevel() + " - " + record.getMessage(); + if (record.getLevel().equals(Level.SEVERE) || record.getLevel().equals(Level.WARNING)) { + System.err.println(message); + } else { + System.out.println(message); + } + } +} diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/GroupManagerPermissions.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/GroupManagerPermissions.java new file mode 100644 index 0000000000..19d8d5ed07 --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/GroupManagerPermissions.java @@ -0,0 +1,56 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.anjocaido.groupmanager.utils; + +/** + * Just a list of commands for this plugin + * + * @author gabrielcouto + */ +public enum GroupManagerPermissions { + + manuadd, + manudel, + manuaddsub, + manudelsub, + mangadd, + mangdel, + manuaddp, + manudelp, + manuclearp, + manulistp, + manucheckp, + mangaddp, + mangdelp, + mangclearp, + manglistp, + mangcheckp, + mangaddi, + mangdeli, + manuaddv, + manudelv, + manulistv, + manucheckv, + mangaddv, + mangdelv, + manglistv, + mangcheckv, + manwhois, + tempadd, + tempdel, + templist, + tempdelall, + mansave, + manload, + listgroups, + manpromote, + mandemote, + mantogglevalidate, + mantogglesave, + manworld, + manselect, + manclear, + mancheckw +} diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/PermissionCheckResult.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/PermissionCheckResult.java new file mode 100644 index 0000000000..eb66338634 --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/PermissionCheckResult.java @@ -0,0 +1,67 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.anjocaido.groupmanager.utils; + +import org.anjocaido.groupmanager.data.DataUnit; + +/** + * + * @author gabrielcouto + */ +public class PermissionCheckResult { + + /** + * It should be the owner of the access level found. + * + * Use instanceof to find the owner type + */ + public DataUnit owner; + /** + * The permission node found in the DataUnit. + */ + public String accessLevel; + /** + * The full name of the permission you are looking for + */ + public String askedPermission; + /** + * The result conclusion of the search. + * It determines if the owner can do, or not. + * + * It even determines if it has an owner. + */ + public Type resultType = Type.NOTFOUND; + + /** + * The type of result the search can give. + */ + public enum Type { + + /** + * If found a matching node starting with '+'. + * It means the user CAN do the permission. + */ + EXCEPTION, + /** + * If found a matching node starting with '-'. + * It means the user CANNOT do the permission. + */ + NEGATION, + /** + * If just found a common matching node. + * IT means the user CAN do the permission. + */ + FOUND, + /** + * If no matchin node was found. + * It means the user CANNOT do the permission. + * + * owner field and accessLevel field should not be considered, + * when type is + * NOTFOUND + */ + NOTFOUND + } +} diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/StringPermissionComparator.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/StringPermissionComparator.java new file mode 100644 index 0000000000..5a56cd9fca --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/StringPermissionComparator.java @@ -0,0 +1,52 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.anjocaido.groupmanager.utils; + +import java.util.Comparator; + +/** + * + * @author gabrielcouto + */ +public class StringPermissionComparator implements Comparator { + + @Override + public int compare(String permA, String permB) { + + boolean ap = permA.startsWith("+"); + boolean bp = permB.startsWith("+"); + boolean am = permA.startsWith("-"); + boolean bm = permB.startsWith("-"); + if (ap && bp) { + return 0; + } + if (ap && !bp) { + return -1; + } + if (!ap && bp) { + return 1; + } + if (am && bm) { + return 0; + } + if (am && !bm) { + return -1; + } + if (!am && bm) { + return 1; + } + return permA.compareToIgnoreCase(permB); + } + + private static StringPermissionComparator instance; + + public static StringPermissionComparator getInstance() { + + if (instance == null) { + instance = new StringPermissionComparator(); + } + return instance; + } +} diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/Tasks.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/Tasks.java new file mode 100644 index 0000000000..d75737c662 --- /dev/null +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/utils/Tasks.java @@ -0,0 +1,175 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.anjocaido.groupmanager.utils; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.List; + +import org.anjocaido.groupmanager.GroupManager; +import org.anjocaido.groupmanager.data.Group; + +/** + * + * @author gabrielcouto + */ +public abstract class Tasks { + + /** + * Gets the exception stack trace as a string. + * + * @param exception + * @return stack trace as a string + */ + public static String getStackTraceAsString(Exception exception) { + + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + exception.printStackTrace(pw); + return sw.toString(); + } + + public static void copy(InputStream src, File dst) throws IOException { + + InputStream in = src; + OutputStream out = new FileOutputStream(dst); + + // Transfer bytes from in to out + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + out.close(); + try { + in.close(); + } catch (Exception e) { + } + } + + public static void copy(File src, File dst) throws IOException { + + InputStream in = new FileInputStream(src); + copy(in, dst); + } + + /** + * Appends a string to a file + * + * @param data + * @param file + */ + public static void appendStringToFile(String data, String file) throws IOException { + + FileWriter outStream = new FileWriter("." + System.getProperty("file.separator") + file, true); + + BufferedWriter out = new BufferedWriter(outStream); + + data.replaceAll("\n", System.getProperty("line.separator")); + + out.append(new SimpleDateFormat("yyyy-MM-dd HH-mm").format(System.currentTimeMillis())); + out.append(System.getProperty("line.separator")); + out.append(data); + out.append(System.getProperty("line.separator")); + + out.close(); + } + + public static void removeOldFiles(GroupManager gm, File folder) { + + if (folder.isDirectory()) { + long oldTime = System.currentTimeMillis() - (((long) gm.getGMConfig().getBackupDuration() * 60 * 60) * 1000); + for (File olds : folder.listFiles()) { + if (olds.isFile()) { + if (olds.lastModified() < oldTime) { + try { + olds.delete(); + } catch (Exception e) { + } + } + } + } + } + } + + public static String getDateString() { + + GregorianCalendar now = new GregorianCalendar(); + String date = ""; + date += now.get(Calendar.DAY_OF_MONTH); + date += "-"; + date += now.get(Calendar.HOUR); + date += "-"; + date += now.get(Calendar.MINUTE); + return date; + } + + public static String getStringListInString(List list) { + + if (list == null) { + return ""; + } + String result = ""; + for (int i = 0; i < list.size(); i++) { + result += list.get(i); + if (i < list.size() - 1) { + result += ", "; + } + } + return result; + } + + public static String getStringArrayInString(String[] list) { + + if (list == null) { + return ""; + } + String result = ""; + for (int i = 0; i < list.length; i++) { + result += list[i]; + if (i < ((list.length) - 1)) { + result += ", "; + } + } + return result; + } + + public static String getGroupListInString(List list) { + + if (list == null) { + return ""; + } + String result = ""; + for (int i = 0; i < list.size(); i++) { + result += list.get(i).getName(); + if (i < list.size() - 1) { + result += ", "; + } + } + return result; + } + + public static String join(String[] arr, String separator) { + + if (arr.length == 0) + return ""; + String out = arr[0].toString(); + for (int i = 1; i < arr.length; i++) + out += separator + arr[i]; + return out; + } + +} diff --git a/EssentialsGroupManager/src/plugin.yml b/EssentialsGroupManager/src/plugin.yml new file mode 100644 index 0000000000..ea4b12b154 --- /dev/null +++ b/EssentialsGroupManager/src/plugin.yml @@ -0,0 +1,184 @@ +name: GroupManager +version: GMBuildVer (Phoenix) +main: org.anjocaido.groupmanager.GroupManager +website: http://ess.khhq.net/wiki/Group_Manager +description: Provides on-the-fly system for permissions system created by Nijikokun. But all in memory, and with flat-file saving schedule. +authors: + - AnjoCaido + - Gabriel Couto + - ElgarL +commands: + manuadd: + description: Moves a player to desired group (Adds to the file if does not exist). + usage: / | optional [world] + permissions: groupmanager.manuadd + manudel: + description: Removes any user specific configuration and make them default group. + usage: / + permissions: groupmanager.manudel + manuaddsub: + description: Adds a group to a user's subgroup list. + usage: / + permissions: groupmanager.manuaddsub + manudelsub: + description: Removes a group from a user's subgroup list. + usage: / + permissions: groupmanager.manudelsub + mangadd: + description: Adds a group to the system. + usage: / + permissions: groupmanager.mangadd + mangdel: + description: Removes a group from the system (all its users become default). + usage: / + permissions: groupmanager.mangdel + manuaddp: + description: Adds permissions directly to the user. + usage: / [permission2] [permission3].. + permissions: groupmanager.manuaddp + manudelp: + description: Removes permissions directly from the user. + usage: / [permission2] [permission3].. + permissions: groupmanager.manudelp + manuclearp: + description: Removes all permissions from a user. + usage: / + permissions: groupmanager.manuclearp + manulistp: + description: Lists all permissions of a user. + usage: / + permissions: groupmanager.manulistp + manucheckp: + description: Verifies if user has a permission, and where it comes from. + usage: / + permissions: groupmanager.manucheckp + mangaddp: + description: Adds permissions to a group. + usage: / [permission2] [permission3].. + permissions: groupmanager.mangaddp + mangdelp: + description: Removes permissions from a group. + usage: / [permission2] [permission3].. + permissions: groupmanager.mangdelp + mangclearp: + description: Removes all permissions from a group. + usage: / + permissions: groupmanager.mangclearp + manglistp: + description: Lists all permissions of a group. + usage: / + permissions: groupmanager.manglistp + mangcheckp: + description: Checks if group has a permission and where it comes from. + usage: / + permissions: groupmanager.mangcheckp + mangaddi: + description: Adds a group to another group inheritance list. + usage: / + permissions: groupmanager.mangaddi + mangdeli: + description: Removes a group from another group inheritance list. + usage: / + permissions: groupmanager.mangdeli + manuaddv: + description: Adds or replaces a variable of a user (like prefix or suffix). + usage: / + permissions: groupmanager.manuaddv + manudelv: + description: Removes a variable from a user. + usage: / + permissions: groupmanager.manudelv + manulistv: + description: Lists variables of a user (like prefix or suffix). + usage: / + permissions: groupmanager.manulistv + manucheckv: + description: Verifies a value of a variable of a user, and where it comes from. + usage: / + permissions: groupmanager.manucheckv + mangaddv: + description: Adds or replaces a variable of a group (like prefix or suffix). + usage: / + permissions: groupmanager.mangaddv + mangdelv: + description: Removes a variable from a group. + usage: / + permissions: groupmanager.mangdelv + manglistv: + description: Lists variables of a group (like prefix or suffix). + usage: / + permissions: groupmanager.manglistv + mangcheckv: + description: Verifies a value of a variable of a group, and where it comes from. + usage: / + permissions: groupmanager.mangckeckv + manwhois: + description: Lists groups and other data of a user. + usage: / + permissions: groupmanager.manwhois + tempadd: + description: Creates a temporary permissions copy for a user. + usage: / + permissions: groupmanager.tempadd + tempdel: + description: Removes the temporary permissions copy for a user. + usage: / + permissions: groupmanager.tempdel + templist: + description: Lists users in overload-permissions mode made by command /tempadd. + usage: / + permissions: groupmanager.templist + tempdelall: + description: Removes all overrides made by command /tempadd. + usage: / + permissions: groupmanager.tempdelall + mansave: + description: Saves all permissions from server to file. + usage: / + permissions: groupmanager.mansave + manload: + description: Reloads current world and config.yml, or loads given world from file to server. + usage: / [world] + permissions: groupmanager.manload + listgroups: + aliases: [manlistg] + description: Lists the groups available. + usage: / + permissions: groupmanager.listgroups + manpromote: + description: Promotes a user in the same heritage line to a higher rank. + usage: / + permissions: groupmanager.manpromote + mandemote: + description: Demotes a user in the same heritage line to a lower rank. + usage: / + permissions: groupmanager.mandemote + mantogglevalidate: + description: Toggles on/off the validating if user is online. + usage: / + permissions: groupmanager.mantogglevalidate + mantogglesave: + description: Toggles on/off the autosave. + usage: / + permissions: groupmanager.mantogglesave + manworld: + description: Prints the selected world name. + usage: / + permissions: groupmanager.manworld + manselect: + description: Selects a world to work with commands. + usage: / + permissions: groupmanager.manselect + manclear: + description: Clears world selection. Commands will work on your current world. + usage: / + permissions: groupmanager.manclear + mancheckw: + description: Obtains the path to each file a world is storing its data in (users/groups). + usage: / + permissions: groupmanager.mancheckw + +Permissions: + groupmanager.op: + description: User is treated as an op when using the GroupManager commands. + default: false diff --git a/EssentialsGroupManager/src/users.yml b/EssentialsGroupManager/src/users.yml new file mode 100644 index 0000000000..eaea6232d5 --- /dev/null +++ b/EssentialsGroupManager/src/users.yml @@ -0,0 +1,18 @@ +# "For a more advanced configuration example utilizing the advanced features of GroupManager, see http://pastebin.com/a8ZA0j5G" +users: + snowleo: + group: Builder + subgroups: [] + permissions: + - groupmanager.noofflineperms + KHobbits: + group: Moderator + subgroups: [] + permissions: + - groupmanager.noofflineperms + ElgarL: + group: Moderator + subgroups: [] + permissions: + - groupmanager.noofflineperms + diff --git a/EssentialsProtect/pom.xml b/EssentialsProtect/pom.xml new file mode 100644 index 0000000000..47da06ad7b --- /dev/null +++ b/EssentialsProtect/pom.xml @@ -0,0 +1,51 @@ + + 4.0.0 + + + net.ess3 + EssentialsParent + 2.x-SNAPSHOT + + + EssentialsProtect + + 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/ + + + + + net.ess3 + Essentials + ${project.version} + + + \ No newline at end of file diff --git a/EssentialsProtect/src/com/earth2me/essentials/protect/EmergencyListener.java b/EssentialsProtect/src/com/earth2me/essentials/protect/EmergencyListener.java new file mode 100644 index 0000000000..5f9253c551 --- /dev/null +++ b/EssentialsProtect/src/com/earth2me/essentials/protect/EmergencyListener.java @@ -0,0 +1,58 @@ +package com.earth2me.essentials.protect; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockBurnEvent; +import org.bukkit.event.block.BlockFromToEvent; +import org.bukkit.event.block.BlockIgniteEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.event.player.PlayerJoinEvent; + + +public class EmergencyListener implements Listener +{ + @EventHandler(priority = EventPriority.LOW) + public void onBlockBurn(final BlockBurnEvent event) + { + event.setCancelled(true); + } + + @EventHandler(priority = EventPriority.LOW) + public void onBlockIgnite(final BlockIgniteEvent event) + { + event.setCancelled(true); + } + + @EventHandler(priority = EventPriority.LOW) + public void onBlockFromTo(final BlockFromToEvent event) + { + event.setCancelled(true); + } + + @EventHandler(priority = EventPriority.LOW) + public void onBlockBreak(final BlockBreakEvent event) + { + event.setCancelled(true); + } + + @EventHandler(priority = EventPriority.LOW) + public void onPlayerJoin(final PlayerJoinEvent event) + { + event.getPlayer().sendMessage("Essentials Protect is in emergency mode. Check your log for errors."); + } + + @EventHandler(priority = EventPriority.LOW) + public void onEntityExplode(final EntityExplodeEvent event) + { + event.setCancelled(true); + } + + @EventHandler(priority = EventPriority.LOW) + public void onEntityDamage(final EntityDamageEvent event) + { + event.setCancelled(true); + } +} diff --git a/EssentialsProtect/src/com/earth2me/essentials/protect/EssentialsConnect.java b/EssentialsProtect/src/com/earth2me/essentials/protect/EssentialsConnect.java new file mode 100644 index 0000000000..58290a8b84 --- /dev/null +++ b/EssentialsProtect/src/com/earth2me/essentials/protect/EssentialsConnect.java @@ -0,0 +1,57 @@ +package com.earth2me.essentials.protect; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.IConf; +import net.ess3.api.IEssentials; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.bukkit.plugin.Plugin; + + +public class EssentialsConnect +{ + private static final Logger LOGGER = Logger.getLogger("Minecraft"); + private final IEssentials ess; + private final IProtect protect; + + public EssentialsConnect(Plugin essPlugin, Plugin essProtect) + { + if (!essProtect.getDescription().getVersion().equals(essPlugin.getDescription().getVersion())) + { + LOGGER.log(Level.WARNING, tl("versionMismatchAll")); + } + ess = (IEssentials)essPlugin; + protect = (IProtect)essProtect; + ProtectReloader pr = new ProtectReloader(); + pr.reloadConfig(); + ess.addReloadListener(pr); + } + + public IEssentials getEssentials() + { + return ess; + } + + private class ProtectReloader implements IConf + { + @Override + public void reloadConfig() + { + for (ProtectConfig protectConfig : ProtectConfig.values()) + { + if (protectConfig.isList()) + { + protect.getSettingsList().put(protectConfig, ess.getSettings().getProtectList(protectConfig.getConfigName())); + } + else if (protectConfig.isString()) + { + protect.getSettingsString().put(protectConfig, ess.getSettings().getProtectString(protectConfig.getConfigName())); + } + else + { + protect.getSettingsBoolean().put(protectConfig, ess.getSettings().getProtectBoolean(protectConfig.getConfigName(), protectConfig.getDefaultValueBoolean())); + } + } + } + } +} \ No newline at end of file diff --git a/EssentialsProtect/src/com/earth2me/essentials/protect/EssentialsProtect.java b/EssentialsProtect/src/com/earth2me/essentials/protect/EssentialsProtect.java new file mode 100644 index 0000000000..1e90134086 --- /dev/null +++ b/EssentialsProtect/src/com/earth2me/essentials/protect/EssentialsProtect.java @@ -0,0 +1,93 @@ +package com.earth2me.essentials.protect; + +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.java.JavaPlugin; + + +public class EssentialsProtect extends JavaPlugin implements IProtect +{ + private static final Logger LOGGER = Logger.getLogger("Minecraft"); + private final Map settingsBoolean = new EnumMap(ProtectConfig.class); + private final Map settingsString = new EnumMap(ProtectConfig.class); + private final Map> settingsList = new EnumMap>(ProtectConfig.class); + private EssentialsConnect ess = null; + + @Override + public void onEnable() + { + final PluginManager pm = this.getServer().getPluginManager(); + final Plugin essPlugin = pm.getPlugin("Essentials"); + if (essPlugin == null || !essPlugin.isEnabled()) + { + enableEmergencyMode(pm); + return; + } + ess = new EssentialsConnect(essPlugin, this); + + final EssentialsProtectBlockListener blockListener = new EssentialsProtectBlockListener(this); + pm.registerEvents(blockListener, this); + + final EssentialsProtectEntityListener entityListener = new EssentialsProtectEntityListener(this); + pm.registerEvents(entityListener, this); + + final EssentialsProtectWeatherListener weatherListener = new EssentialsProtectWeatherListener(this); + pm.registerEvents(weatherListener, this); + } + + private void enableEmergencyMode(final PluginManager pm) + { + final EmergencyListener emListener = new EmergencyListener(); + pm.registerEvents(emListener, this); + + for (Player player : getServer().getOnlinePlayers()) + { + player.sendMessage("Essentials Protect is in emergency mode. Check your log for errors."); + } + LOGGER.log(Level.SEVERE, "Essentials not installed or failed to load. Essenials Protect is in emergency mode now."); + } + + @Override + public EssentialsConnect getEssentialsConnect() + { + return ess; + } + + @Override + public Map getSettingsBoolean() + { + return settingsBoolean; + } + + @Override + public Map getSettingsString() + { + return settingsString; + } + + @Override + public Map> getSettingsList() + { + return settingsList; + } + + @Override + public boolean getSettingBool(final ProtectConfig protectConfig) + { + final Boolean bool = settingsBoolean.get(protectConfig); + return bool == null ? protectConfig.getDefaultValueBoolean() : bool; + } + + @Override + public String getSettingString(final ProtectConfig protectConfig) + { + final String str = settingsString.get(protectConfig); + return str == null ? protectConfig.getDefaultValueString() : str; + } +} diff --git a/EssentialsProtect/src/com/earth2me/essentials/protect/EssentialsProtectBlockListener.java b/EssentialsProtect/src/com/earth2me/essentials/protect/EssentialsProtectBlockListener.java new file mode 100644 index 0000000000..70ae90e035 --- /dev/null +++ b/EssentialsProtect/src/com/earth2me/essentials/protect/EssentialsProtectBlockListener.java @@ -0,0 +1,94 @@ +package com.earth2me.essentials.protect; + +import net.ess3.api.IEssentials; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.*; + + +public class EssentialsProtectBlockListener implements Listener +{ + final private IProtect prot; + final private IEssentials ess; + + public EssentialsProtectBlockListener(final IProtect parent) + { + this.prot = parent; + this.ess = prot.getEssentialsConnect().getEssentials(); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBlockIgnite(BlockIgniteEvent event) + { + if (event.getBlock().getType() == Material.OBSIDIAN + || event.getBlock().getRelative(BlockFace.DOWN).getType() == Material.OBSIDIAN) + { + event.setCancelled(prot.getSettingBool(ProtectConfig.prevent_portal_creation)); + return; + } + + if (event.getCause().equals(BlockIgniteEvent.IgniteCause.SPREAD)) + { + event.setCancelled(prot.getSettingBool(ProtectConfig.prevent_fire_spread)); + return; + } + + if (event.getCause().equals(BlockIgniteEvent.IgniteCause.FLINT_AND_STEEL)) + { + event.setCancelled(prot.getSettingBool(ProtectConfig.prevent_flint_fire)); + return; + } + + if (event.getCause().equals(BlockIgniteEvent.IgniteCause.LAVA)) + { + event.setCancelled(prot.getSettingBool(ProtectConfig.prevent_lava_fire_spread)); + return; + } + if (event.getCause().equals(BlockIgniteEvent.IgniteCause.LIGHTNING)) + { + event.setCancelled(prot.getSettingBool(ProtectConfig.prevent_lightning_fire_spread)); + return; + } + + if (event.getCause().equals(BlockIgniteEvent.IgniteCause.FIREBALL)) + { + event.setCancelled(prot.getSettingBool(ProtectConfig.prevent_fireball_fire)); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBlockFromTo(final BlockFromToEvent event) + { + final Block block = event.getBlock(); + + if (block.getType() == Material.WATER || block.getType() == Material.STATIONARY_WATER) + { + event.setCancelled(prot.getSettingBool(ProtectConfig.prevent_water_flow)); + return; + } + + if (block.getType() == Material.LAVA || block.getType() == Material.STATIONARY_LAVA) + { + event.setCancelled(prot.getSettingBool(ProtectConfig.prevent_lava_flow)); + return; + } + + if (block.getType() == Material.AIR) + { + event.setCancelled(prot.getSettingBool(ProtectConfig.prevent_water_bucket_flow)); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBlockBurn(final BlockBurnEvent event) + { + if (prot.getSettingBool(ProtectConfig.prevent_fire_spread)) + { + event.setCancelled(true); + } + } +} diff --git a/EssentialsProtect/src/com/earth2me/essentials/protect/EssentialsProtectEntityListener.java b/EssentialsProtect/src/com/earth2me/essentials/protect/EssentialsProtectEntityListener.java new file mode 100644 index 0000000000..111751c2d9 --- /dev/null +++ b/EssentialsProtect/src/com/earth2me/essentials/protect/EssentialsProtectEntityListener.java @@ -0,0 +1,340 @@ +package com.earth2me.essentials.protect; + +import com.earth2me.essentials.User; +import net.ess3.api.IEssentials; +import java.util.Locale; +import org.bukkit.entity.*; +import org.bukkit.entity.minecart.ExplosiveMinecart; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.*; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.entity.EntityTargetEvent.TargetReason; +import org.bukkit.event.hanging.HangingBreakByEntityEvent; +import org.bukkit.event.hanging.HangingBreakEvent; + + +public class EssentialsProtectEntityListener implements Listener +{ + private final IProtect prot; + private final IEssentials ess; + + public EssentialsProtectEntityListener(final IProtect prot) + { + this.prot = prot; + this.ess = prot.getEssentialsConnect().getEssentials(); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onEntityDamage(final EntityDamageEvent event) + { + final Entity target = event.getEntity(); + + if (target instanceof Villager && prot.getSettingBool(ProtectConfig.prevent_villager_death)) + { + event.setCancelled(true); + return; + } + + User user = null; + if (target instanceof Player) + { + user = ess.getUser((Player)target); + } + + final DamageCause cause = event.getCause(); + + if (event instanceof EntityDamageByBlockEvent) + { + if (prot.getSettingBool(ProtectConfig.disable_contactdmg) + && cause == DamageCause.CONTACT + && !(target instanceof Player && shouldBeDamaged(user, "contact"))) + { + event.setCancelled(true); + return; + } + if (prot.getSettingBool(ProtectConfig.disable_lavadmg) + && cause == DamageCause.LAVA + && !(target instanceof Player && shouldBeDamaged(user, "lava"))) + { + event.setCancelled(true); + return; + } + if (prot.getSettingBool(ProtectConfig.prevent_tnt_explosion) + && cause == DamageCause.BLOCK_EXPLOSION + && !(target instanceof Player && shouldBeDamaged(user, "tnt"))) + { + event.setCancelled(true); + return; + } + } + + if (event instanceof EntityDamageByEntityEvent) + { + final EntityDamageByEntityEvent edEvent = (EntityDamageByEntityEvent)event; + final Entity eAttack = edEvent.getDamager(); + + User attacker = null; + if (eAttack instanceof Player) + { + attacker = ess.getUser((Player)eAttack); + } + + //Creeper explode prevention + if (eAttack instanceof Creeper + && (prot.getSettingBool(ProtectConfig.prevent_creeper_explosion) + || prot.getSettingBool(ProtectConfig.prevent_creeper_playerdmg)) + && !(target instanceof Player && shouldBeDamaged(user, "creeper"))) + { + event.setCancelled(true); + return; + } + + if ((event.getEntity() instanceof Fireball || event.getEntity() instanceof SmallFireball) + && prot.getSettingBool(ProtectConfig.prevent_fireball_playerdmg) + && !(target instanceof Player && shouldBeDamaged(user, "fireball"))) + { + event.setCancelled(true); + return; + } + + if (event.getEntity() instanceof WitherSkull + && prot.getSettingBool(ProtectConfig.prevent_witherskull_playerdmg) + && !(target instanceof Player && shouldBeDamaged(user, "witherskull"))) + { + event.setCancelled(true); + return; + } + + if (eAttack instanceof TNTPrimed && prot.getSettingBool(ProtectConfig.prevent_tnt_playerdmg) + && !(target instanceof Player && shouldBeDamaged(user, "tnt"))) + { + event.setCancelled(true); + return; + } + + if (eAttack instanceof ExplosiveMinecart && prot.getSettingBool(ProtectConfig.prevent_tntminecart_playerdmg) + && !(target instanceof Player && shouldBeDamaged(user, "tnt-minecart"))) + { + event.setCancelled(true); + return; + } + + // PVP Settings + if (target instanceof Player && eAttack instanceof Player + && prot.getSettingBool(ProtectConfig.disable_pvp) + && !user.getName().equalsIgnoreCase(attacker.getName()) + && (!user.isAuthorized("essentials.protect.pvp") || !attacker.isAuthorized("essentials.protect.pvp"))) + { + event.setCancelled(true); + return; + } + + if (edEvent.getDamager() instanceof Projectile + && target instanceof Player + && ((prot.getSettingBool(ProtectConfig.disable_projectiles) && !shouldBeDamaged(user, "projectiles")) + || (((Projectile)edEvent.getDamager()).getShooter() instanceof Player + && prot.getSettingBool(ProtectConfig.disable_pvp) + && (!user.isAuthorized("essentials.protect.pvp") + || !ess.getUser((Player)((Projectile)edEvent.getDamager()).getShooter()).isAuthorized("essentials.protect.pvp"))))) + { + event.setCancelled(true); + return; + } + } + + if (target instanceof Player) + { + if (cause == DamageCause.FALL + && prot.getSettingBool(ProtectConfig.disable_fall) + && !shouldBeDamaged(user, "fall")) + { + event.setCancelled(true); + return; + } + + if (cause == DamageCause.SUFFOCATION + && prot.getSettingBool(ProtectConfig.disable_suffocate) + && !shouldBeDamaged(user, "suffocation")) + { + event.setCancelled(true); + return; + } + if ((cause == DamageCause.FIRE || cause == DamageCause.FIRE_TICK) + && prot.getSettingBool(ProtectConfig.disable_firedmg) + && !shouldBeDamaged(user, "fire")) + { + event.setCancelled(true); + return; + } + if (cause == DamageCause.DROWNING + && prot.getSettingBool(ProtectConfig.disable_drown) + && !shouldBeDamaged(user, "drowning")) + { + event.setCancelled(true); + return; + } + if (cause == DamageCause.LIGHTNING + && prot.getSettingBool(ProtectConfig.disable_lightning) + && !shouldBeDamaged(user, "lightning")) + { + event.setCancelled(true); + return; + } + if (cause == DamageCause.WITHER + && prot.getSettingBool(ProtectConfig.disable_wither) + && !shouldBeDamaged(user, "wither")) + { + event.setCancelled(true); + } + } + } + + private boolean shouldBeDamaged(final User user, final String type) + { + return (user.isAuthorized("essentials.protect.damage.".concat(type)) + && !user.isAuthorized("essentials.protect.damage.disable")); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onEntityExplode(final EntityExplodeEvent event) + { + if (event.getEntity() == null) + { + return; + } + Entity entity = event.getEntity(); + final int maxHeight = ess.getSettings().getProtectCreeperMaxHeight(); + + if (entity instanceof EnderDragon + && prot.getSettingBool(ProtectConfig.prevent_enderdragon_blockdmg)) + { + event.setCancelled(true); + if (prot.getSettingBool(ProtectConfig.enderdragon_fakeexplosions)) + { + event.getLocation().getWorld().createExplosion(event.getLocation(), 0F); + } + return; + } + if (entity instanceof Wither + && prot.getSettingBool(ProtectConfig.prevent_wither_spawnexplosion)) + { + event.setCancelled(true); + } + else if (entity instanceof Creeper + && (prot.getSettingBool(ProtectConfig.prevent_creeper_explosion) + || prot.getSettingBool(ProtectConfig.prevent_creeper_blockdmg) + || (maxHeight >= 0 && event.getLocation().getBlockY() > maxHeight))) + { + //Nicccccccccce plaaacccccccccce.. + event.setCancelled(true); + event.getLocation().getWorld().createExplosion(event.getLocation(), 0F); + } + else if (entity instanceof TNTPrimed + && prot.getSettingBool(ProtectConfig.prevent_tnt_explosion)) + { + event.setCancelled(true); + + } + else if ((entity instanceof Fireball || entity instanceof SmallFireball) + && prot.getSettingBool(ProtectConfig.prevent_fireball_explosion)) + { + event.setCancelled(true); + + } + else if ((entity instanceof WitherSkull) + && prot.getSettingBool(ProtectConfig.prevent_witherskull_explosion)) + { + event.setCancelled(true); + } + else if ((entity instanceof ExplosiveMinecart) + && prot.getSettingBool(ProtectConfig.prevent_tntminecart_explosion)) + { + event.setCancelled(true); + } + + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onCreatureSpawn(final CreatureSpawnEvent event) + { + if (event.getEntity() instanceof Player) + { + return; + } + final EntityType creature = event.getEntityType(); + if (creature == null) + { + return; + } + final String creatureName = creature.toString().toLowerCase(Locale.ENGLISH); + if (creatureName == null || creatureName.isEmpty()) + { + return; + } + if (ess.getSettings().getProtectPreventSpawn(creatureName)) + { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onEntityTarget(final EntityTargetEvent event) + { + if (!(event.getTarget() instanceof Player)) + { + return; + } + final User user = ess.getUser((Player)event.getTarget()); + if ((event.getReason() == TargetReason.CLOSEST_PLAYER + || event.getReason() == TargetReason.TARGET_ATTACKED_ENTITY + || event.getReason() == TargetReason.PIG_ZOMBIE_TARGET + || event.getReason() == TargetReason.RANDOM_TARGET + || event.getReason() == TargetReason.DEFEND_VILLAGE + || event.getReason() == TargetReason.TARGET_ATTACKED_OWNER + || event.getReason() == TargetReason.OWNER_ATTACKED_TARGET) + && prot.getSettingBool(ProtectConfig.prevent_entitytarget) + && !user.isAuthorized("essentials.protect.entitytarget.bypass")) + { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onExplosionPrime(ExplosionPrimeEvent event) + { + if ((event.getEntity() instanceof Fireball || event.getEntity() instanceof SmallFireball) + && prot.getSettingBool(ProtectConfig.prevent_fireball_fire)) + { + event.setFire(false); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onEntityChangeBlock(EntityChangeBlockEvent event) + { + if (event.getEntityType() == EntityType.ENDERMAN && prot.getSettingBool(ProtectConfig.prevent_enderman_pickup)) + { + event.setCancelled(true); + return; + } + if (event.getEntityType() == EntityType.WITHER && prot.getSettingBool(ProtectConfig.prevent_wither_blockreplace)) + { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onPaintingBreak(HangingBreakByEntityEvent event) + { + if ((event.getCause() == HangingBreakEvent.RemoveCause.ENTITY) + && ((event.getRemover() instanceof Creeper) && prot.getSettingBool(ProtectConfig.prevent_creeper_explosion) + || (((event.getRemover() instanceof Fireball) || (event.getRemover() instanceof SmallFireball)) && prot.getSettingBool(ProtectConfig.prevent_fireball_explosion)) + || ((event.getRemover() instanceof TNTPrimed) && prot.getSettingBool(ProtectConfig.prevent_tnt_explosion)) + || ((event.getRemover() instanceof WitherSkull) && prot.getSettingBool(ProtectConfig.prevent_witherskull_explosion)))) + { + event.setCancelled(true); + } + } +} diff --git a/EssentialsProtect/src/com/earth2me/essentials/protect/EssentialsProtectWeatherListener.java b/EssentialsProtect/src/com/earth2me/essentials/protect/EssentialsProtectWeatherListener.java new file mode 100644 index 0000000000..ed621a6757 --- /dev/null +++ b/EssentialsProtect/src/com/earth2me/essentials/protect/EssentialsProtectWeatherListener.java @@ -0,0 +1,48 @@ +package com.earth2me.essentials.protect; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.weather.LightningStrikeEvent; +import org.bukkit.event.weather.ThunderChangeEvent; +import org.bukkit.event.weather.WeatherChangeEvent; + + +public class EssentialsProtectWeatherListener implements Listener +{ + private final IProtect prot; + + public EssentialsProtectWeatherListener(final IProtect prot) + { + this.prot = prot; + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onWeatherChange(final WeatherChangeEvent event) + { + if (prot.getSettingBool(ProtectConfig.disable_weather_storm) + && event.toWeatherState()) + { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onLightningStrike(final LightningStrikeEvent event) + { + if (prot.getSettingBool(ProtectConfig.disable_weather_lightning)) + { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onThunderChange(final ThunderChangeEvent event) + { + if (prot.getSettingBool(ProtectConfig.disable_weather_thunder) + && event.toThunderState()) + { + event.setCancelled(true); + } + } +} diff --git a/EssentialsProtect/src/com/earth2me/essentials/protect/IProtect.java b/EssentialsProtect/src/com/earth2me/essentials/protect/IProtect.java new file mode 100644 index 0000000000..e3acaabce8 --- /dev/null +++ b/EssentialsProtect/src/com/earth2me/essentials/protect/IProtect.java @@ -0,0 +1,21 @@ +package com.earth2me.essentials.protect; + +import java.util.List; +import java.util.Map; +import org.bukkit.plugin.Plugin; + + +public interface IProtect extends Plugin +{ + boolean getSettingBool(final ProtectConfig protectConfig); + + String getSettingString(final ProtectConfig protectConfig); + + EssentialsConnect getEssentialsConnect(); + + Map getSettingsBoolean(); + + Map getSettingsString(); + + Map> getSettingsList(); +} diff --git a/EssentialsProtect/src/com/earth2me/essentials/protect/ProtectConfig.java b/EssentialsProtect/src/com/earth2me/essentials/protect/ProtectConfig.java new file mode 100644 index 0000000000..2faef22edb --- /dev/null +++ b/EssentialsProtect/src/com/earth2me/essentials/protect/ProtectConfig.java @@ -0,0 +1,110 @@ +package com.earth2me.essentials.protect; + + +public enum ProtectConfig +{ + disable_contactdmg("protect.disable.contactdmg", false), + disable_lavadmg("protect.disable.lavadmg", false), + disable_pvp("protect.disable.pvp", false), + disable_projectiles("protect.disable.projectiles", false), + disable_fall("protect.disable.fall", false), + disable_suffocate("protect.disable.suffocate", false), + disable_firedmg("protect.disable.firedmg", false), + disable_lightning("protect.disable.lightning", false), + disable_drown("protect.disable.drown", false), + disable_wither("protect.disable.wither", false), + disable_weather_storm("protect.disable.weather.storm", false), + disable_weather_lightning("protect.disable.weather.lightning", false), + disable_weather_thunder("protect.disable.weather.thunder", false), + prevent_fire_spread("protect.prevent.fire-spread", true), + prevent_flint_fire("protect.prevent.flint-fire", false), + prevent_lava_fire_spread("protect.prevent.lava-fire-spread", true), + prevent_lightning_fire_spread("protect.prevent.lightning-fire-spread", true), + prevent_water_flow("protect.prevent.water-flow", false), + prevent_lava_flow("protect.prevent.lava-flow", false), + prevent_water_bucket_flow("protect.prevent.water-bucket-flow", false), + prevent_portal_creation("protect.prevent.portal-creation", false), + prevent_block_on_rail("protect.protect.prevent-block-on-rails", false), + prevent_tnt_explosion("protect.prevent.tnt-explosion", false), + prevent_tnt_playerdmg("protect.prevent.tnt-playerdamage", false), + prevent_tntminecart_explosion("protect.prevent.tnt-minecart-explosion", false), + prevent_tntminecart_playerdmg("protect.prevent.tnt-minecart-playerdamage", false), + prevent_fireball_explosion("protect.prevent.fireball-explosion", false), + prevent_fireball_fire("protect.prevent.fireball-fire", false), + prevent_fireball_playerdmg("protect.prevent.fireball-playerdamage", false), + prevent_witherskull_explosion("protect.prevent.witherskull-explosion", false), + prevent_witherskull_playerdmg("protect.prevent.witherskull-playerdamage", false), + prevent_wither_spawnexplosion("protect.prevent.wither-spawnexplosion", false), + prevent_wither_blockreplace("protect.prevent.wither-blockreplace", false), + prevent_creeper_explosion("protect.prevent.creeper-explosion", true), + prevent_creeper_playerdmg("protect.prevent.creeper-playerdamage", false), + prevent_creeper_blockdmg("protect.prevent.creeper-blockdamage", false), + prevent_enderman_pickup("protect.prevent.enderman-pickup", false), + prevent_villager_death("protect.prevent.villager-death", false), + prevent_enderdragon_blockdmg("protect.prevent.enderdragon-blockdamage", true), + prevent_entitytarget("protect.prevent.entitytarget", false), + enderdragon_fakeexplosions("protect.enderdragon-fakeexplosions", false); + private final String configName; + private final String defValueString; + private final boolean defValueBoolean; + private final boolean isList; + private final boolean isString; + + private ProtectConfig(final String configName) + { + this(configName, null, false, true, false); + } + + private ProtectConfig(final String configName, final String defValueString) + { + this(configName, defValueString, false, false, true); + } + + private ProtectConfig(final String configName, final boolean defValueBoolean) + { + this(configName, null, defValueBoolean, false, false); + } + + private ProtectConfig(final String configName, final String defValueString, final boolean defValueBoolean, final boolean isList, final boolean isString) + { + this.configName = configName; + this.defValueString = defValueString; + this.defValueBoolean = defValueBoolean; + this.isList = isList; + this.isString = isString; + } + + /** + * @return the configName + */ + public String getConfigName() + { + return configName; + } + + /** + * @return the default value String + */ + public String getDefaultValueString() + { + return defValueString; + } + + /** + * @return the default value boolean + */ + public boolean getDefaultValueBoolean() + { + return defValueBoolean; + } + + public boolean isString() + { + return isString; + } + + public boolean isList() + { + return isList; + } +} diff --git a/EssentialsProtect/src/plugin.yml b/EssentialsProtect/src/plugin.yml new file mode 100644 index 0000000000..bf7389a913 --- /dev/null +++ b/EssentialsProtect/src/plugin.yml @@ -0,0 +1,9 @@ +# This determines the command prefix when there are conflicts (/name:home, /name:help, etc.) +name: EssentialsProtect +main: com.earth2me.essentials.protect.EssentialsProtect +# Note to developers: This next line cannot change, or the automatic versioning system will break. +version: TeamCity +website: http://tiny.cc/EssentialsCommands +description: Provides protection for various parts of the world. +authors: [Zenexer, ementalo, Aelux, Brettflan, KimKandor, snowleo, ceulemans, Xeology, KHobbits] +softdepend: [Essentials] \ No newline at end of file diff --git a/EssentialsSpawn/pom.xml b/EssentialsSpawn/pom.xml new file mode 100644 index 0000000000..194496dfc7 --- /dev/null +++ b/EssentialsSpawn/pom.xml @@ -0,0 +1,51 @@ + + 4.0.0 + + + net.ess3 + EssentialsParent + 2.x-SNAPSHOT + + + EssentialsSpawn + + 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/ + + + + + net.ess3 + Essentials + ${project.version} + + + \ No newline at end of file diff --git a/EssentialsSpawn/src/com/earth2me/essentials/spawn/Commandsetspawn.java b/EssentialsSpawn/src/com/earth2me/essentials/spawn/Commandsetspawn.java new file mode 100644 index 0000000000..15d2ca2ab2 --- /dev/null +++ b/EssentialsSpawn/src/com/earth2me/essentials/spawn/Commandsetspawn.java @@ -0,0 +1,23 @@ +package com.earth2me.essentials.spawn; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.User; +import com.earth2me.essentials.commands.EssentialsCommand; +import org.bukkit.Server; + + +public class Commandsetspawn extends EssentialsCommand +{ + public Commandsetspawn() + { + super("setspawn"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + final String group = args.length > 0 ? getFinalArg(args, 0) : "default"; + ((SpawnStorage)module).setSpawn(user.getLocation(), group); + user.sendMessage(tl("spawnSet", group)); + } +} diff --git a/EssentialsSpawn/src/com/earth2me/essentials/spawn/Commandspawn.java b/EssentialsSpawn/src/com/earth2me/essentials/spawn/Commandspawn.java new file mode 100644 index 0000000000..34a4eb6bd4 --- /dev/null +++ b/EssentialsSpawn/src/com/earth2me/essentials/spawn/Commandspawn.java @@ -0,0 +1,71 @@ +package com.earth2me.essentials.spawn; + +import com.earth2me.essentials.CommandSource; +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Console; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import com.earth2me.essentials.commands.EssentialsCommand; +import com.earth2me.essentials.commands.NoChargeException; +import com.earth2me.essentials.commands.NotEnoughArgumentsException; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + + +public class Commandspawn extends EssentialsCommand +{ + public Commandspawn() + { + super("spawn"); + } + + @Override + public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + { + final Trade charge = new Trade(this.getName(), ess); + charge.isAffordableFor(user); + if (args.length > 0 && user.isAuthorized("essentials.spawn.others")) + { + final User otherUser = getPlayer(server, user, args, 0); + respawn(user.getSource(), user, otherUser, charge); + if (!otherUser.equals(user)) + { + otherUser.sendMessage(tl("teleportAtoB", user.getDisplayName(), "spawn")); + } + } + else + { + respawn(user.getSource(), user, user, charge); + } + throw new NoChargeException(); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + final User user = getPlayer(server, args, 0, true, false); + respawn(sender, null, user, null); + user.sendMessage(tl("teleportAtoB", Console.NAME, "spawn")); + + } + + private void respawn(final CommandSource sender, final User teleportOwner, final User teleportee, final Trade charge) throws Exception + { + final SpawnStorage spawns = (SpawnStorage)this.module; + final Location spawn = spawns.getSpawn(teleportee.getGroup()); + sender.sendMessage(tl("teleporting", spawn.getWorld().getName(), spawn.getBlockX(), spawn.getBlockY(), spawn.getBlockZ())); + if (teleportOwner == null) + { + teleportee.getTeleport().now(spawn, false, TeleportCause.COMMAND); + } + else + { + teleportOwner.getTeleport().teleportPlayer(teleportee, spawn, charge, TeleportCause.COMMAND); + } + } +} diff --git a/EssentialsSpawn/src/com/earth2me/essentials/spawn/EssentialsSpawn.java b/EssentialsSpawn/src/com/earth2me/essentials/spawn/EssentialsSpawn.java new file mode 100644 index 0000000000..d076373038 --- /dev/null +++ b/EssentialsSpawn/src/com/earth2me/essentials/spawn/EssentialsSpawn.java @@ -0,0 +1,94 @@ +package com.earth2me.essentials.spawn; + +import static com.earth2me.essentials.I18n.tl; +import net.ess3.api.IEssentials; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.event.Event; +import org.bukkit.event.EventException; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerRespawnEvent; +import org.bukkit.plugin.EventExecutor; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.java.JavaPlugin; + + +public class EssentialsSpawn extends JavaPlugin implements IEssentialsSpawn +{ + private static final Logger LOGGER = Bukkit.getLogger(); + private transient IEssentials ess; + private transient SpawnStorage spawns; + + @Override + public void onEnable() + { + final PluginManager pluginManager = getServer().getPluginManager(); + ess = (IEssentials)pluginManager.getPlugin("Essentials"); + if (!this.getDescription().getVersion().equals(ess.getDescription().getVersion())) + { + LOGGER.log(Level.WARNING, tl("versionMismatchAll")); + } + if (!ess.isEnabled()) + { + this.setEnabled(false); + return; + } + + spawns = new SpawnStorage(ess); + ess.addReloadListener(spawns); + + final EssentialsSpawnPlayerListener playerListener = new EssentialsSpawnPlayerListener(ess, spawns); + pluginManager.registerEvent(PlayerRespawnEvent.class, playerListener, ess.getSettings().getRespawnPriority(), new EventExecutor() + { + @Override + public void execute(final Listener ll, final Event event) throws EventException + { + ((EssentialsSpawnPlayerListener)ll).onPlayerRespawn((PlayerRespawnEvent)event); + } + }, this); + pluginManager.registerEvent(PlayerJoinEvent.class, playerListener, ess.getSettings().getRespawnPriority(), new EventExecutor() + { + @Override + public void execute(final Listener ll, final Event event) throws EventException + { + ((EssentialsSpawnPlayerListener)ll).onPlayerJoin((PlayerJoinEvent)event); + } + }, this); + } + + @Override + public void onDisable() + { + } + + @Override + public boolean onCommand(final CommandSender sender, final Command command, final String commandLabel, final String[] args) + { + return ess.onCommandEssentials(sender, command, commandLabel, args, EssentialsSpawn.class.getClassLoader(), "com.earth2me.essentials.spawn.Command", "essentials.", spawns); + } + + @Override + public void setSpawn(Location loc, String group) + { + if (group == null) + { + throw new IllegalArgumentException("Null group"); + } + spawns.setSpawn(loc, group); + } + + @Override + public Location getSpawn(String group) + { + if (group == null) + { + throw new IllegalArgumentException("Null group"); + } + return spawns.getSpawn(group); + } +} diff --git a/EssentialsSpawn/src/com/earth2me/essentials/spawn/EssentialsSpawnPlayerListener.java b/EssentialsSpawn/src/com/earth2me/essentials/spawn/EssentialsSpawnPlayerListener.java new file mode 100644 index 0000000000..d637014ebb --- /dev/null +++ b/EssentialsSpawn/src/com/earth2me/essentials/spawn/EssentialsSpawnPlayerListener.java @@ -0,0 +1,171 @@ +package com.earth2me.essentials.spawn; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.Kit; +import com.earth2me.essentials.OfflinePlayer; +import com.earth2me.essentials.User; +import com.earth2me.essentials.textreader.IText; +import com.earth2me.essentials.textreader.KeywordReplacer; +import com.earth2me.essentials.textreader.SimpleTextPager; +import net.ess3.api.IEssentials; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerRespawnEvent; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + + +public class EssentialsSpawnPlayerListener implements Listener +{ + private static final Logger LOGGER = Bukkit.getLogger(); + private final transient IEssentials ess; + private final transient SpawnStorage spawns; + + public EssentialsSpawnPlayerListener(final IEssentials ess, final SpawnStorage spawns) + { + super(); + this.ess = ess; + this.spawns = spawns; + } + + public void onPlayerRespawn(final PlayerRespawnEvent event) + { + final User user = ess.getUser(event.getPlayer()); + + if (user.isJailed() && user.getJail() != null && !user.getJail().isEmpty()) + { + return; + } + + if (ess.getSettings().getRespawnAtHome()) + { + Location home; + final Location bed = user.getBase().getBedSpawnLocation(); + if (bed != null) + { + home = bed; + } + else + { + home = user.getHome(user.getLocation()); + } + if (home != null) + { + event.setRespawnLocation(home); + return; + } + } + final Location spawn = spawns.getSpawn(user.getGroup()); + if (spawn != null) + { + event.setRespawnLocation(spawn); + } + } + + public void onPlayerJoin(final PlayerJoinEvent event) + { + ess.runTaskAsynchronously(new Runnable() + { + @Override + public void run() + { + delayedJoin(event.getPlayer()); + } + }); + } + + public void delayedJoin(Player player) + { + if (player.hasPlayedBefore()) + { + LOGGER.log(Level.FINE, "Old player join"); + return; + } + + final User user = ess.getUser(player); + + if (!"none".equalsIgnoreCase(ess.getSettings().getNewbieSpawn())) + { + ess.scheduleSyncDelayedTask(new NewPlayerTeleport(user), 1L); + } + + ess.scheduleSyncDelayedTask(new Runnable() + { + @Override + public void run() + { + if (!user.getBase().isOnline()) { + return; + } + + //This method allows for multiple line player announce messages using multiline yaml syntax #EasterEgg + if (ess.getSettings().getAnnounceNewPlayers()) + { + final IText output = new KeywordReplacer(ess.getSettings().getAnnounceNewPlayerFormat(), user.getSource(), ess); + final SimpleTextPager pager = new SimpleTextPager(output); + + for (String line : pager.getLines()) + { + ess.broadcastMessage(user, line); + } + } + + final String kitName = ess.getSettings().getNewPlayerKit(); + if (!kitName.isEmpty()) + { + try + { + final Kit kit = new Kit(kitName.toLowerCase(Locale.ENGLISH), ess); + kit.expandItems(user); + } + catch (Exception ex) + { + LOGGER.log(Level.WARNING, ex.getMessage()); + } + } + + LOGGER.log(Level.FINE, "New player join"); + } + }, 2L); + } + + + private class NewPlayerTeleport implements Runnable + { + private final transient User user; + + public NewPlayerTeleport(final User user) + { + this.user = user; + } + + @Override + public void run() + { + if (user.getBase() instanceof OfflinePlayer || !user.getBase().isOnline()) + { + return; + } + + try + { + final Location spawn = spawns.getSpawn(ess.getSettings().getNewbieSpawn()); + if (spawn != null) + { + user.getTeleport().now(spawn, false, TeleportCause.PLUGIN); + } + } + catch (Exception ex) + { + Bukkit.getLogger().log(Level.WARNING, tl("teleportNewPlayerError"), ex); + } + } + } +} diff --git a/EssentialsSpawn/src/com/earth2me/essentials/spawn/IEssentialsSpawn.java b/EssentialsSpawn/src/com/earth2me/essentials/spawn/IEssentialsSpawn.java new file mode 100644 index 0000000000..a7c43bcb01 --- /dev/null +++ b/EssentialsSpawn/src/com/earth2me/essentials/spawn/IEssentialsSpawn.java @@ -0,0 +1,27 @@ +package com.earth2me.essentials.spawn; + +import org.bukkit.Location; +import org.bukkit.plugin.Plugin; + + +public interface IEssentialsSpawn extends Plugin +{ + + /** + * Sets the spawn for a given group to a given location. + * + * @param loc The location to set the spawn to + * @param group The group to set the spawn of, or 'default' for the default spawn + * @throws IllegalArgumentException If group is null + */ + public void setSpawn(Location loc, String group); + + /** + * Gets the spawn location for a given group. + * + * @param group The group to get the spawn of, or 'default' for the default spawn + * @return The spawn location set for the given group + * @throws IllegalArgumentException If group is null + */ + public Location getSpawn(String group); +} diff --git a/EssentialsSpawn/src/com/earth2me/essentials/spawn/SpawnStorage.java b/EssentialsSpawn/src/com/earth2me/essentials/spawn/SpawnStorage.java new file mode 100644 index 0000000000..36b6f96626 --- /dev/null +++ b/EssentialsSpawn/src/com/earth2me/essentials/spawn/SpawnStorage.java @@ -0,0 +1,100 @@ +package com.earth2me.essentials.spawn; + +import com.earth2me.essentials.IEssentialsModule; +import com.earth2me.essentials.settings.Spawns; +import com.earth2me.essentials.storage.AsyncStorageObjectHolder; +import net.ess3.api.IEssentials; +import java.io.File; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import org.bukkit.Location; +import org.bukkit.World; + + +public class SpawnStorage extends AsyncStorageObjectHolder implements IEssentialsModule +{ + public SpawnStorage(final IEssentials ess) + { + super(ess, Spawns.class); + reloadConfig(); + } + + @Override + public File getStorageFile() + { + return new File(ess.getDataFolder(), "spawn.yml"); + } + + @Override + public void finishRead() + { + } + + @Override + public void finishWrite() + { + } + + public void setSpawn(final Location loc, final String group) + { + acquireWriteLock(); + try + { + if (getData().getSpawns() == null) + { + getData().setSpawns(new HashMap()); + } + getData().getSpawns().put(group.toLowerCase(Locale.ENGLISH), loc); + } + finally + { + unlock(); + } + + if ("default".equalsIgnoreCase(group)) + { + loc.getWorld().setSpawnLocation(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); + } + } + + public Location getSpawn(final String group) + { + acquireReadLock(); + try + { + if (getData().getSpawns() == null || group == null) + { + return getWorldSpawn(); + } + final Map spawnMap = getData().getSpawns(); + String groupName = group.toLowerCase(Locale.ENGLISH); + if (!spawnMap.containsKey(groupName)) + { + groupName = "default"; + } + if (!spawnMap.containsKey(groupName)) + { + return getWorldSpawn(); + } + return spawnMap.get(groupName); + } + finally + { + unlock(); + } + } + + private Location getWorldSpawn() + { + for (World world : ess.getServer().getWorlds()) + { + if (world.getEnvironment() != World.Environment.NORMAL) + { + continue; + } + return world.getSpawnLocation(); + } + return ess.getServer().getWorlds().get(0).getSpawnLocation(); + } +} diff --git a/EssentialsSpawn/src/plugin.yml b/EssentialsSpawn/src/plugin.yml new file mode 100644 index 0000000000..21f77db788 --- /dev/null +++ b/EssentialsSpawn/src/plugin.yml @@ -0,0 +1,18 @@ +# This determines the command prefix when there are conflicts (/name:home, /name:help, etc.) +name: EssentialsSpawn +main: com.earth2me.essentials.spawn.EssentialsSpawn +# Note to developers: This next line cannot change, or the automatic versioning system will break. +version: TeamCity +website: http://tiny.cc/EssentialsCommands +description: Provides spawn control commands, utilizing Essentials. +authors: [Zenexer, ementalo, Aelux, Brettflan, KimKandor, snowleo, ceulemans, Xeology, KHobbits] +depend: [Essentials] +commands: + setspawn: + description: Set the spawnpoint to your current position. + usage: / + aliases: [esetspawn] + spawn: + description: Teleport to the spawnpoint. + usage: / [player] + aliases: [espawn] \ No newline at end of file diff --git a/EssentialsXMPP/pom.xml b/EssentialsXMPP/pom.xml new file mode 100644 index 0000000000..dfb9b459f3 --- /dev/null +++ b/EssentialsXMPP/pom.xml @@ -0,0 +1,82 @@ + + 4.0.0 + + + net.ess3 + EssentialsParent + 2.x-SNAPSHOT + + + EssentialsXMPP + + 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/ + + + + + net.ess3 + Essentials + ${project.version} + + + org.igniterealtime.smack + smack + 3.2.1 + + + + + + + org.apache.maven.plugins + maven-shade-plugin + 2.1 + + + package + + shade + + + + + + + org.igniterealtime.smack:smack + + + + + + + + \ No newline at end of file diff --git a/EssentialsXMPP/src/com/earth2me/essentials/xmpp/Commandsetxmpp.java b/EssentialsXMPP/src/com/earth2me/essentials/xmpp/Commandsetxmpp.java new file mode 100644 index 0000000000..c4f66097eb --- /dev/null +++ b/EssentialsXMPP/src/com/earth2me/essentials/xmpp/Commandsetxmpp.java @@ -0,0 +1,27 @@ +package com.earth2me.essentials.xmpp; + +import com.earth2me.essentials.User; +import com.earth2me.essentials.commands.EssentialsCommand; +import com.earth2me.essentials.commands.NotEnoughArgumentsException; +import org.bukkit.Server; + + +public class Commandsetxmpp extends EssentialsCommand +{ + public Commandsetxmpp() + { + super("setxmpp"); + } + + @Override + protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws NotEnoughArgumentsException + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + EssentialsXMPP.getInstance().setAddress(user.getBase(), args[0]); + user.sendMessage("XMPP address set to " + args[0]); + } +} diff --git a/EssentialsXMPP/src/com/earth2me/essentials/xmpp/Commandxmpp.java b/EssentialsXMPP/src/com/earth2me/essentials/xmpp/Commandxmpp.java new file mode 100644 index 0000000000..f30efc5146 --- /dev/null +++ b/EssentialsXMPP/src/com/earth2me/essentials/xmpp/Commandxmpp.java @@ -0,0 +1,41 @@ +package com.earth2me.essentials.xmpp; + +import com.earth2me.essentials.CommandSource; +import com.earth2me.essentials.Console; +import com.earth2me.essentials.commands.EssentialsCommand; +import com.earth2me.essentials.commands.NotEnoughArgumentsException; +import org.bukkit.Server; + + +public class Commandxmpp extends EssentialsCommand +{ + public Commandxmpp() + { + super("xmpp"); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws NotEnoughArgumentsException + { + if (args.length < 2) + { + throw new NotEnoughArgumentsException(); + } + + final String address = EssentialsXMPP.getInstance().getAddress(args[0]); + if (address == null) + { + sender.sendMessage("§cThere are no players matching that name."); + } + else + { + final String message = getFinalArg(args, 1); + final String senderName = sender.isPlayer() ? ess.getUser(sender.getPlayer()).getDisplayName() : Console.NAME; + sender.sendMessage("[" + senderName + ">" + address + "] " + message); + if (!EssentialsXMPP.getInstance().sendMessage(address, "[" + senderName + "] " + message)) + { + sender.sendMessage("§cError sending message."); + } + } + } +} diff --git a/EssentialsXMPP/src/com/earth2me/essentials/xmpp/Commandxmppspy.java b/EssentialsXMPP/src/com/earth2me/essentials/xmpp/Commandxmppspy.java new file mode 100644 index 0000000000..a3f8ee83e0 --- /dev/null +++ b/EssentialsXMPP/src/com/earth2me/essentials/xmpp/Commandxmppspy.java @@ -0,0 +1,46 @@ +package com.earth2me.essentials.xmpp; + +import com.earth2me.essentials.CommandSource; +import com.earth2me.essentials.commands.EssentialsCommand; +import com.earth2me.essentials.commands.NotEnoughArgumentsException; +import java.util.List; +import org.bukkit.Server; +import org.bukkit.entity.Player; + + +public class Commandxmppspy extends EssentialsCommand +{ + public Commandxmppspy() + { + super("xmppspy"); + } + + @Override + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws NotEnoughArgumentsException + { + if (args.length < 1) + { + throw new NotEnoughArgumentsException(); + } + + final List matches = server.matchPlayer(args[0]); + + if (matches.isEmpty()) + { + sender.sendMessage("§cThere are no players matching that name."); + } + + for (Player p : matches) + { + try + { + final boolean toggle = EssentialsXMPP.getInstance().toggleSpy(p); + sender.sendMessage("XMPP Spy " + (toggle ? "enabled" : "disabled") + " for " + p.getDisplayName()); + } + catch (Exception ex) + { + sender.sendMessage("Error: " + ex.getMessage()); + } + } + } +} \ No newline at end of file diff --git a/EssentialsXMPP/src/com/earth2me/essentials/xmpp/EssentialsXMPP.java b/EssentialsXMPP/src/com/earth2me/essentials/xmpp/EssentialsXMPP.java new file mode 100644 index 0000000000..f1a2cd21d6 --- /dev/null +++ b/EssentialsXMPP/src/com/earth2me/essentials/xmpp/EssentialsXMPP.java @@ -0,0 +1,158 @@ +package com.earth2me.essentials.xmpp; + +import static com.earth2me.essentials.I18n.tl; +import com.earth2me.essentials.IEssentials; +import net.ess3.api.IUser; +import java.util.List; +import java.util.Locale; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.java.JavaPlugin; + + +public class EssentialsXMPP extends JavaPlugin implements IEssentialsXMPP +{ + private static final Logger LOGGER = Logger.getLogger("Minecraft"); + private static EssentialsXMPP instance = null; + private transient UserManager users; + private transient XMPPManager xmpp; + private transient IEssentials ess; + + public static IEssentialsXMPP getInstance() + { + return instance; + } + + @Override + public void onEnable() + { + instance = this; + + final PluginManager pluginManager = getServer().getPluginManager(); + ess = (IEssentials)pluginManager.getPlugin("Essentials"); + if (!this.getDescription().getVersion().equals(ess.getDescription().getVersion())) + { + LOGGER.log(Level.WARNING, tl("versionMismatchAll")); + } + if (!ess.isEnabled()) + { + this.setEnabled(false); + return; + } + + final EssentialsXMPPPlayerListener playerListener = new EssentialsXMPPPlayerListener(ess); + pluginManager.registerEvents(playerListener, this); + + users = new UserManager(this.getDataFolder()); + xmpp = new XMPPManager(this); + + ess.addReloadListener(users); + ess.addReloadListener(xmpp); + } + + @Override + public void onDisable() + { + if (xmpp != null) + { + xmpp.disconnect(); + } + instance = null; + } + + @Override + public boolean onCommand(final CommandSender sender, final Command command, final String commandLabel, final String[] args) + { + return ess.onCommandEssentials(sender, command, commandLabel, args, EssentialsXMPP.class.getClassLoader(), "com.earth2me.essentials.xmpp.Command", "essentials.", null); + } + + @Override + public void setAddress(final Player user, final String address) + { + final String username = user.getName().toLowerCase(Locale.ENGLISH); + instance.users.setAddress(username, address); + } + + @Override + public String getAddress(final String name) + { + return instance.users.getAddress(name); + } + + @Override + public IUser getUserByAddress(final String address) + { + String username = instance.users.getUserByAddress(address); + return username == null ? null : ess.getUser(username); + } + + @Override + public boolean toggleSpy(final Player user) + { + final String username = user.getName().toLowerCase(Locale.ENGLISH); + final boolean spy = !instance.users.isSpy(username); + instance.users.setSpy(username, spy); + return spy; + } + + @Override + public String getAddress(final Player user) + { + return instance.users.getAddress(user.getName()); + } + + @Override + public boolean sendMessage(final Player user, final String message) + { + return instance.xmpp.sendMessage(instance.users.getAddress(user.getName()), message); + } + + @Override + public boolean sendMessage(final String address, final String message) + { + return instance.xmpp.sendMessage(address, message); + } + + // @Override + public static boolean updatePresence() + { + instance.xmpp.updatePresence(); + return true; + } + + @Override + public List getSpyUsers() + { + return instance.users.getSpyUsers(); + } + + @Override + public void broadcastMessage(final IUser sender, final String message, final String xmppAddress) + { + ess.broadcastMessage(sender, message); + try + { + for (String address : getSpyUsers()) + { + if (!address.equalsIgnoreCase(xmppAddress)) + { + sendMessage(address, message); + } + } + } + catch (Exception ex) + { + // Ignore exceptions + } + } + + @Override + public IEssentials getEss() + { + return ess; + } +} diff --git a/EssentialsXMPP/src/com/earth2me/essentials/xmpp/EssentialsXMPPPlayerListener.java b/EssentialsXMPP/src/com/earth2me/essentials/xmpp/EssentialsXMPPPlayerListener.java new file mode 100644 index 0000000000..8afbbbe1eb --- /dev/null +++ b/EssentialsXMPP/src/com/earth2me/essentials/xmpp/EssentialsXMPPPlayerListener.java @@ -0,0 +1,93 @@ +package com.earth2me.essentials.xmpp; + +import com.earth2me.essentials.IEssentials; +import com.earth2me.essentials.User; +import java.util.List; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; + + +class EssentialsXMPPPlayerListener implements Listener +{ + private final transient IEssentials ess; + + EssentialsXMPPPlayerListener(final IEssentials ess) + { + super(); + this.ess = ess; + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onPlayerJoin(final PlayerJoinEvent event) + { + final User user = ess.getUser(event.getPlayer()); + + Bukkit.getScheduler().scheduleSyncDelayedTask(ess, new Runnable() + { + @Override + public void run() + { + EssentialsXMPP.updatePresence(); + } + }); + + sendMessageToSpyUsers("Player " + user.getDisplayName() + " joined the game"); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onPlayerChat(final AsyncPlayerChatEvent event) + { + final User user = ess.getUser(event.getPlayer()); + sendMessageToSpyUsers(String.format(event.getFormat(), user.getDisplayName(), event.getMessage())); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onPlayerQuit(final PlayerQuitEvent event) + { + final User user = ess.getUser(event.getPlayer()); + + Bukkit.getScheduler().scheduleSyncDelayedTask(ess, new Runnable() + { + @Override + public void run() + { + EssentialsXMPP.updatePresence(); + } + }); + + + sendMessageToSpyUsers("Player " + user.getDisplayName() + " left the game"); + } + + private void sendMessageToSpyUsers(final String message) + { + try + { + List users = EssentialsXMPP.getInstance().getSpyUsers(); + synchronized (users) + { + for (final String address : users) + { + Bukkit.getScheduler().scheduleSyncDelayedTask(ess, new Runnable() + { + @Override + public void run() + { + EssentialsXMPP.getInstance().sendMessage(address, message); + } + }); + + } + } + } + catch (Exception ex) + { + // Ignore exceptions + } + } +} diff --git a/EssentialsXMPP/src/com/earth2me/essentials/xmpp/IEssentialsXMPP.java b/EssentialsXMPP/src/com/earth2me/essentials/xmpp/IEssentialsXMPP.java new file mode 100644 index 0000000000..cdc964cb18 --- /dev/null +++ b/EssentialsXMPP/src/com/earth2me/essentials/xmpp/IEssentialsXMPP.java @@ -0,0 +1,31 @@ +package com.earth2me.essentials.xmpp; + +import com.earth2me.essentials.IEssentials; +import net.ess3.api.IUser; +import java.util.List; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + + +public interface IEssentialsXMPP extends Plugin +{ + String getAddress(final Player user); + + String getAddress(final String name); + + List getSpyUsers(); + + IUser getUserByAddress(final String address); + + boolean sendMessage(final Player user, final String message); + + boolean sendMessage(final String address, final String message); + + void setAddress(final Player user, final String address); + + boolean toggleSpy(final Player user); + + void broadcastMessage(final IUser sender, final String message, final String xmppAddress); + + IEssentials getEss(); +} diff --git a/EssentialsXMPP/src/com/earth2me/essentials/xmpp/UserManager.java b/EssentialsXMPP/src/com/earth2me/essentials/xmpp/UserManager.java new file mode 100644 index 0000000000..114cf61004 --- /dev/null +++ b/EssentialsXMPP/src/com/earth2me/essentials/xmpp/UserManager.java @@ -0,0 +1,89 @@ +package com.earth2me.essentials.xmpp; + +import com.earth2me.essentials.EssentialsConf; +import com.earth2me.essentials.IConf; +import java.io.File; +import java.util.*; + + +public class UserManager implements IConf +{ + private final transient EssentialsConf users; + private final transient List spyusers = Collections.synchronizedList(new ArrayList()); + private static final String ADDRESS = "address"; + private static final String SPY = "spy"; + + public UserManager(final File folder) + { + users = new EssentialsConf(new File(folder, "users.yml")); + reloadConfig(); + } + + public final boolean isSpy(final String username) + { + return users.getBoolean(username.toLowerCase(Locale.ENGLISH) + "." + SPY, false); + } + + public void setSpy(final String username, final boolean spy) + { + setUser(username.toLowerCase(Locale.ENGLISH), getAddress(username), spy); + } + + public final String getAddress(final String username) + { + return users.getString(username.toLowerCase(Locale.ENGLISH) + "." + ADDRESS, null); + } + + public final String getUserByAddress(final String search) + { + final Set usernames = users.getKeys(false); + for (String username : usernames) + { + final String address = users.getString(username + "." + ADDRESS, null); + if (address != null && search.equalsIgnoreCase(address)) + { + return username; + } + } + return null; + } + + public void setAddress(final String username, final String address) + { + setUser(username.toLowerCase(Locale.ENGLISH), address, isSpy(username)); + } + + public List getSpyUsers() + { + return spyusers; + } + + private void setUser(final String username, final String address, final boolean spy) + { + final Map userdata = new HashMap(); + userdata.put(ADDRESS, address); + userdata.put(SPY, spy); + users.setProperty(username, userdata); + users.save(); + reloadConfig(); + } + + @Override + public final void reloadConfig() + { + users.load(); + spyusers.clear(); + final Set keys = users.getKeys(false); + for (String key : keys) + { + if (isSpy(key)) + { + final String address = getAddress(key); + if (address != null) + { + spyusers.add(address); + } + } + } + } +} diff --git a/EssentialsXMPP/src/com/earth2me/essentials/xmpp/XMPPManager.java b/EssentialsXMPP/src/com/earth2me/essentials/xmpp/XMPPManager.java new file mode 100644 index 0000000000..a0ffd72e1a --- /dev/null +++ b/EssentialsXMPP/src/com/earth2me/essentials/xmpp/XMPPManager.java @@ -0,0 +1,407 @@ +package com.earth2me.essentials.xmpp; + +import com.earth2me.essentials.Console; +import com.earth2me.essentials.EssentialsConf; +import com.earth2me.essentials.IConf; +import net.ess3.api.IUser; +import com.earth2me.essentials.utils.FormatUtil; +import java.io.File; +import java.util.*; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import java.util.logging.SimpleFormatter; +import org.bukkit.entity.Player; +import org.jivesoftware.smack.*; +import org.jivesoftware.smack.Roster.SubscriptionMode; +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.packet.Presence; +import org.jivesoftware.smack.util.StringUtils; + + +public class XMPPManager extends Handler implements MessageListener, ChatManagerListener, IConf +{ + private static final Logger LOGGER = Logger.getLogger("Minecraft"); + private static final SimpleFormatter formatter = new SimpleFormatter(); + private final transient EssentialsConf config; + private transient XMPPConnection connection; + private transient ChatManager chatManager; + private final transient Map chats = Collections.synchronizedMap(new HashMap()); + private final transient Set logrecords = Collections.synchronizedSet(new HashSet()); + private final transient IEssentialsXMPP parent; + private transient List logUsers; + private transient Level logLevel; + private transient boolean ignoreLagMessages = true; + private transient Thread loggerThread; + private transient boolean threadrunning = true; + + public XMPPManager(final IEssentialsXMPP parent) + { + super(); + this.parent = parent; + config = new EssentialsConf(new File(parent.getDataFolder(), "config.yml")); + config.setTemplateName("/config.yml", EssentialsXMPP.class); + reloadConfig(); + } + + public boolean sendMessage(final String address, final String message) + { + if (address != null && !address.isEmpty()) + { + try + { + startChat(address); + final Chat chat; + synchronized (chats) + { + chat = chats.get(address); + } + if (chat != null) + { + if (!connection.isConnected()) + { + disconnect(); + connect(); + } + chat.sendMessage(FormatUtil.stripFormat(message)); + return true; + } + } + catch (XMPPException ex) + { + disableChat(address); + } + } + return false; + } + + @Override + public void processMessage(final Chat chat, final Message msg) + { + // Normally we should log the error message + // But we would create a loop if the connection to a log-user fails. + if (msg.getType() != Message.Type.error && msg.getBody().length() > 0) + { + final String message = msg.getBody(); + switch (message.charAt(0)) + { + case '@': + sendPrivateMessage(chat, message); + break; + case '/': + sendCommand(chat, message); + break; + default: + final IUser sender = parent.getUserByAddress(StringUtils.parseBareAddress(chat.getParticipant())); + parent.broadcastMessage(sender, "=" + sender.getBase().getDisplayName() + ": " + message, StringUtils.parseBareAddress(chat.getParticipant())); + } + } + } + + private boolean connect() + { + final String server = config.getString("xmpp.server"); + if (server == null || server.equals("example.com")) + { + LOGGER.log(Level.WARNING, "config broken for xmpp"); + return false; + } + final int port = config.getInt("xmpp.port", 5222); + final String serviceName = config.getString("xmpp.servicename", server); + final String xmppuser = config.getString("xmpp.user"); + final String password = config.getString("xmpp.password"); + final ConnectionConfiguration connConf = new ConnectionConfiguration(server, port, serviceName); + final StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("Connecting to xmpp server ").append(server).append(":").append(port); + stringBuilder.append(" as user ").append(xmppuser).append("."); + LOGGER.log(Level.INFO, stringBuilder.toString()); + connConf.setSASLAuthenticationEnabled(config.getBoolean("xmpp.sasl-enabled", false)); + connConf.setSendPresence(true); + connConf.setReconnectionAllowed(true); + connConf.setDebuggerEnabled(config.getBoolean("debug", false)); + connection = new XMPPConnection(connConf); + try + { + connection.connect(); + + connection.login(xmppuser, password, "Essentials-XMPP"); + connection.sendPacket(new Presence(Presence.Type.available, "No one online.", 2, Presence.Mode.available)); + + connection.getRoster().setSubscriptionMode(SubscriptionMode.accept_all); + chatManager = connection.getChatManager(); + chatManager.addChatListener(this); + return true; + } + catch (XMPPException ex) + { + LOGGER.log(Level.WARNING, "Failed to connect to server: " + server, ex); + return false; + } + } + + public final void disconnect() + { + if (loggerThread != null) + { + loggerThread.interrupt(); + } + if (chatManager != null) + { + chatManager.removeChatListener(this); + chatManager = null; + } + if (connection != null) + { + connection.disconnect(new Presence(Presence.Type.unavailable)); + } + + } + + public final void updatePresence() + { + final int usercount; + final StringBuilder stringBuilder = new StringBuilder(); + + usercount = parent.getEss().getOnlinePlayers().size(); + + if (usercount == 0) + { + final String presenceMsg = "No one online."; + connection.sendPacket(new Presence(Presence.Type.available, presenceMsg, 2, Presence.Mode.dnd)); + } + if (usercount == 1) + { + final String presenceMsg = "1 player online."; + connection.sendPacket(new Presence(Presence.Type.available, presenceMsg, 2, Presence.Mode.available)); + } + if (usercount > 1) + { + stringBuilder.append(usercount).append(" players online."); + connection.sendPacket(new Presence(Presence.Type.available, stringBuilder.toString(), 2, Presence.Mode.available)); + } + } + + @Override + public void chatCreated(final Chat chat, final boolean createdLocally) + { + if (!createdLocally) + { + chat.addMessageListener(this); + final Chat old = chats.put(StringUtils.parseBareAddress(chat.getParticipant()), chat); + if (old != null) + { + old.removeMessageListener(this); + } + } + } + + @Override + public final void reloadConfig() + { + LOGGER.removeHandler(this); + config.load(); + synchronized (chats) + { + disconnect(); + chats.clear(); + if (!connect()) + { + return; + } + startLoggerThread(); + } + if (config.getBoolean("log-enabled", false)) + { + LOGGER.addHandler(this); + logUsers = config.getStringList("log-users"); + final String level = config.getString("log-level", "info"); + try + { + logLevel = Level.parse(level.toUpperCase(Locale.ENGLISH)); + } + catch (IllegalArgumentException e) + { + logLevel = Level.INFO; + } + ignoreLagMessages = config.getBoolean("ignore-lag-messages", true); + } + } + + @Override + public void publish(final LogRecord logRecord) + { + try + { + if (ignoreLagMessages && logRecord.getMessage().equals("Can't keep up! Did the system time change, or is the server overloaded?")) + { + return; + } + if (logRecord.getLevel().intValue() >= logLevel.intValue()) + { + synchronized (logrecords) + { + logrecords.add(logRecord); + } + } + } + catch (Exception e) + { + // Ignore all exceptions + // Otherwise we create a loop. + } + } + + @Override + public void flush() + { + // Ignore this + } + + @Override + public void close() throws SecurityException + { + // Ignore this + } + + private void startLoggerThread() + { + loggerThread = new Thread(new Runnable() + { + @Override + public void run() + { + final Set copy = new HashSet(); + final Set failedUsers = new HashSet(); + while (threadrunning) + { + synchronized (logrecords) + { + if (!logrecords.isEmpty()) + { + copy.addAll(logrecords); + logrecords.clear(); + } + } + if (!copy.isEmpty()) + { + for (String user : logUsers) + { + try + { + XMPPManager.this.startChat(user); + for (LogRecord logRecord : copy) + { + final String message = formatter.format(logRecord); + if (!XMPPManager.this.sendMessage(user, FormatUtil.stripLogColorFormat(message))) + { + failedUsers.add(user); + break; + } + + } + } + catch (XMPPException ex) + { + failedUsers.add(user); + LOGGER.removeHandler(XMPPManager.this); + LOGGER.log(Level.SEVERE, "Failed to deliver log message! Disabling logging to XMPP.", ex); + } + } + logUsers.removeAll(failedUsers); + if (logUsers.isEmpty()) + { + LOGGER.removeHandler(XMPPManager.this); + threadrunning = false; + } + copy.clear(); + } + try + { + Thread.sleep(2000); + } + catch (InterruptedException ex) + { + threadrunning = false; + } + } + LOGGER.removeHandler(XMPPManager.this); + } + }); + loggerThread.start(); + } + + private void startChat(final String address) throws XMPPException + { + if (chatManager == null) + { + return; + } + synchronized (chats) + { + if (!chats.containsKey(address)) + { + final Chat chat = chatManager.createChat(address, this); + if (chat == null) + { + throw new XMPPException("Could not start Chat with " + address); + } + chats.put(address, chat); + } + } + } + + private void sendPrivateMessage(final Chat chat, final String message) + { + final String[] parts = message.split(" ", 2); + if (parts.length == 2) + { + final List matches = parent.getServer().matchPlayer(parts[0].substring(1)); + + if (matches.isEmpty()) + { + try + { + chat.sendMessage("User " + parts[0] + " not found"); + } + catch (XMPPException ex) + { + LOGGER.log(Level.WARNING, "Failed to send xmpp message.", ex); + } + } + else + { + final String from = "[" + parent.getUserByAddress(StringUtils.parseBareAddress(chat.getParticipant())) + ">"; + for (Player p : matches) + { + p.sendMessage(from + p.getDisplayName() + "] " + message); + } + } + } + } + + private void sendCommand(final Chat chat, final String message) + { + if (config.getStringList("op-users").contains(StringUtils.parseBareAddress(chat.getParticipant()))) + { + try + { + parent.getServer().dispatchCommand(Console.getCommandSender(parent.getServer()), message.substring(1)); + } + catch (Exception ex) + { + LOGGER.log(Level.SEVERE, ex.getMessage(), ex); + } + } + } + + private void disableChat(final String address) + { + final Chat chat = chats.get(address); + if (chat != null) + { + chat.removeMessageListener(this); + chats.remove(address); + } + } +} diff --git a/EssentialsXMPP/src/config.yml b/EssentialsXMPP/src/config.yml new file mode 100644 index 0000000000..64b9a539fd --- /dev/null +++ b/EssentialsXMPP/src/config.yml @@ -0,0 +1,19 @@ +xmpp: + server: 'example.com' + user: 'name@example.com' + password: 'password' +# servicename: 'example.com' +# port: 5222 +# sasl-enabled: false + +debug: false + +op-users: +# - 'name@example.com' + + +log-enabled: false +# Level is minimum level that should be send: info, warning, severe +log-level: warning +log-users: +# - 'name@example.com' \ No newline at end of file diff --git a/EssentialsXMPP/src/plugin.yml b/EssentialsXMPP/src/plugin.yml new file mode 100644 index 0000000000..2f65b857c6 --- /dev/null +++ b/EssentialsXMPP/src/plugin.yml @@ -0,0 +1,20 @@ +# This determines the command prefix when there are conflicts (/name:home, /name:help, etc.) +name: EssentialsXMPP +main: com.earth2me.essentials.xmpp.EssentialsXMPP +# Note to developers: This next line cannot change, or the automatic versioning system will break. +version: TeamCity +website: http://ess.khhq.net/wiki/XMPP +description: Provides xmpp communication. +authors: + - snowleo +depend: [Essentials] +commands: + setxmpp: + description: set your xmpp address + usage: /
+ xmpp: + description: send a message to a player + usage: / + xmppspy: + description: toggle xmpp spy for all messages + usage: / \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..20d40b6bce --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/README.markdown b/README.markdown new file mode 100644 index 0000000000..af9ad4598b --- /dev/null +++ b/README.markdown @@ -0,0 +1,56 @@ +Essentials Development Readme +============================= + +The official repository is at: +https://github.com/essentials/Essentials + +We use NetBeans 7.3 for development. + +Recommended NetBeans plugins: + +* Git +* PMD & FindBugs ( http://kenai.com/projects/sqe/pages/Home ) + +Building +-------- +To build with Maven, use the command +``` +mvn package dependency:copy +``` + +Jar files can then be found in the /jars folder + + +Commit Guidelines +----------------- + +Commits should fall into one of 3 areas: + +- `[Feature]`: Commits which are features should start with `[Feature]` and followed by a quick summary on the top line, followed by some extra details in the commit body. + +- `[Fix]`: Commits which fix bugs, or minor improvements to existing features should start with `[Fix]` and followed by a quick summary on the top line, followed by some extra details in the commit body. + +- Commits which fix bugs caused by previous commits (since last release), or otherwise make no functionality changes, should have no prefix. These will not be added to the project change log. + +Coding Guidelines +----------------- + + +Please follow the format guidelines that are saved in the project properties. + +Windows users, please read this: http://help.github.com/line-endings/ +The default line ending is **LF**. + +To build all jars, select the EssentialsParent project and build that. You'll find all jars inside the jars folder. + +Please only submit pull requests for the 2.x branch. + +Bugs and issues can be submitted/found at https://essentials3.atlassian.net/ + + +Other advice +----------------- + +Not all features are 'Essentials Ready'. Essentials is designed to cover the basic needs of Minecraft server administration, thus, we reject over 80% of feature requests that we deem are unsuitable. + +Before developing an Essentials feature, we would recommend speaking to a developer in the Essentials IRC channel ([#essentials on irc.esper.net](http://tiny.cc/EssentialsChat)). Click [here](irc://irc.esper.net/#essentials) if you have a IRC client. diff --git a/WebPush/apikey.php b/WebPush/apikey.php new file mode 100644 index 0000000000..59f2bf3ac0 --- /dev/null +++ b/WebPush/apikey.php @@ -0,0 +1,5 @@ + diff --git a/WebPush/index.php b/WebPush/index.php new file mode 100644 index 0000000000..56193ebf79 --- /dev/null +++ b/WebPush/index.php @@ -0,0 +1,59 @@ + + diff --git a/WebPush/nbproject/private/private.properties b/WebPush/nbproject/private/private.properties new file mode 100644 index 0000000000..8c2a80c6f0 --- /dev/null +++ b/WebPush/nbproject/private/private.properties @@ -0,0 +1,8 @@ +copy.src.files=false +copy.src.target= +index.file=index.php +remote.connection=localhost-d13e79 +remote.directory=/upload +remote.upload=ON_SAVE +run.as=REMOTE +url=http://ess.khhq.net/upload/ diff --git a/WebPush/nbproject/project.properties b/WebPush/nbproject/project.properties new file mode 100644 index 0000000000..6ffde2f50c --- /dev/null +++ b/WebPush/nbproject/project.properties @@ -0,0 +1,7 @@ +include.path=${php.global.include.path} +php.version=PHP_5 +source.encoding=UTF-8 +src.dir=. +tags.asp=false +tags.short=true +web.root=. diff --git a/WebPush/simple_html_dom.php b/WebPush/simple_html_dom.php new file mode 100644 index 0000000000..3f96f8d956 --- /dev/null +++ b/WebPush/simple_html_dom.php @@ -0,0 +1,1727 @@ +size is the "real" number of bytes the dom was created from. + * but for most purposes, it's a really good estimation. + * Paperg - Added the forceTagsClosed to the dom constructor. Forcing tags closed is great for malformed html, but it CAN lead to parsing errors. + * Allow the user to tell us how much they trust the html. + * Paperg add the text and plaintext to the selectors for the find syntax. plaintext implies text in the innertext of a node. text implies that the tag is a text node. + * This allows for us to find tags based on the text they contain. + * Create find_ancestor_tag to see if a tag is - at any level - inside of another specific tag. + * Paperg: added parse_charset so that we know about the character set of the source document. + * NOTE: If the user's system has a routine called get_last_retrieve_url_contents_content_type availalbe, we will assume it's returning the content-type header from the + * last transfer or curl_exec, and we will parse that and use it in preference to any other method of charset detection. + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice. + * + * @author S.C. Chen + * @author John Schlick + * @author Rus Carroll + * @version 1.11 ($Rev: 184 $) + * @package PlaceLocalInclude + * @subpackage simple_html_dom + */ +/** + * All of the Defines for the classes below. + * @author S.C. Chen + */ +define('HDOM_TYPE_ELEMENT', 1); +define('HDOM_TYPE_COMMENT', 2); +define('HDOM_TYPE_TEXT', 3); +define('HDOM_TYPE_ENDTAG', 4); +define('HDOM_TYPE_ROOT', 5); +define('HDOM_TYPE_UNKNOWN', 6); +define('HDOM_QUOTE_DOUBLE', 0); +define('HDOM_QUOTE_SINGLE', 1); +define('HDOM_QUOTE_NO', 3); +define('HDOM_INFO_BEGIN', 0); +define('HDOM_INFO_END', 1); +define('HDOM_INFO_QUOTE', 2); +define('HDOM_INFO_SPACE', 3); +define('HDOM_INFO_TEXT', 4); +define('HDOM_INFO_INNER', 5); +define('HDOM_INFO_OUTER', 6); +define('HDOM_INFO_ENDSPACE', 7); +define('DEFAULT_TARGET_CHARSET', 'UTF-8'); +define('DEFAULT_BR_TEXT', "\r\n"); + +// helper functions +// ----------------------------------------------------------------------------- +// get html dom from file +// $maxlen is defined in the code as PHP_STREAM_COPY_ALL which is defined as -1. +function file_get_html($url, $use_include_path = false, $context=null, $offset = -1, $maxLen=-1, $lowercase = true, $forceTagsClosed=true, $target_charset = DEFAULT_TARGET_CHARSET, $stripRN=true, $defaultBRText=DEFAULT_BR_TEXT) +{ + // We DO force the tags to be terminated. + $dom = new simple_html_dom(null, $lowercase, $forceTagsClosed, $target_charset, $defaultBRText); + // For sourceforge users: uncomment the next line and comment the retreive_url_contents line 2 lines down if it is not already done. + $contents = file_get_contents($url, $use_include_path, $context, $offset); + // Paperg - use our own mechanism for getting the contents as we want to control the timeout. +// $contents = retrieve_url_contents($url); + if (empty($contents)) + { + return false; + } + // The second parameter can force the selectors to all be lowercase. + $dom->load($contents, $lowercase, $stripRN); + return $dom; +} + +// get html dom from string +function str_get_html($str, $lowercase=true, $forceTagsClosed=true, $target_charset = DEFAULT_TARGET_CHARSET, $stripRN=true, $defaultBRText=DEFAULT_BR_TEXT) +{ + $dom = new simple_html_dom(null, $lowercase, $forceTagsClosed, $target_charset, $defaultBRText); + if (empty($str)) + { + $dom->clear(); + return false; + } + $dom->load($str, $lowercase, $stripRN); + return $dom; +} + +// dump html dom tree +function dump_html_tree($node, $show_attr=true, $deep=0) +{ + $node->dump($node); +} + +/** + * simple html dom node + * PaperG - added ability for "find" routine to lowercase the value of the selector. + * PaperG - added $tag_start to track the start position of the tag in the total byte index + * + * @package PlaceLocalInclude + */ +class simple_html_dom_node +{ + public $nodetype = HDOM_TYPE_TEXT; + public $tag = 'text'; + public $attr = array(); + public $children = array(); + public $nodes = array(); + public $parent = null; + public $_ = array(); + public $tag_start = 0; + private $dom = null; + + function __construct($dom) + { + $this->dom = $dom; + $dom->nodes[] = $this; + } + + function __destruct() + { + $this->clear(); + } + + function __toString() + { + return $this->outertext(); + } + + // clean up memory due to php5 circular references memory leak... + function clear() + { + $this->dom = null; + $this->nodes = null; + $this->parent = null; + $this->children = null; + } + + // dump node's tree + function dump($show_attr=true, $deep=0) + { + $lead = str_repeat(' ', $deep); + + echo $lead . $this->tag; + if ($show_attr && count($this->attr) > 0) + { + echo '('; + foreach ($this->attr as $k => $v) + echo "[$k]=>\"" . $this->$k . '", '; + echo ')'; + } + echo "\n"; + + foreach ($this->nodes as $c) + $c->dump($show_attr, $deep + 1); + } + + // Debugging function to dump a single dom node with a bunch of information about it. + function dump_node() + { + echo $this->tag; + if (count($this->attr) > 0) + { + echo '('; + foreach ($this->attr as $k => $v) + { + echo "[$k]=>\"" . $this->$k . '", '; + } + echo ')'; + } + if (count($this->attr) > 0) + { + echo ' $_ ('; + foreach ($this->_ as $k => $v) + { + if (is_array($v)) + { + echo "[$k]=>("; + foreach ($v as $k2 => $v2) + { + echo "[$k2]=>\"" . $v2 . '", '; + } + echo ")"; + } + else + { + echo "[$k]=>\"" . $v . '", '; + } + } + echo ")"; + } + + if (isset($this->text)) + { + echo " text: (" . $this->text . ")"; + } + + echo " children: " . count($this->children); + echo " nodes: " . count($this->nodes); + echo " tag_start: " . $this->tag_start; + echo "\n"; + } + + // returns the parent of node + function parent() + { + return $this->parent; + } + + // returns children of node + function children($idx=-1) + { + if ($idx === -1) + return $this->children; + if (isset($this->children[$idx])) + return $this->children[$idx]; + return null; + } + + // returns the first child of node + function first_child() + { + if (count($this->children) > 0) + return $this->children[0]; + return null; + } + + // returns the last child of node + function last_child() + { + if (($count = count($this->children)) > 0) + return $this->children[$count - 1]; + return null; + } + + // returns the next sibling of node + function next_sibling() + { + if ($this->parent === null) + return null; + $idx = 0; + $count = count($this->parent->children); + while ($idx < $count && $this !== $this->parent->children[$idx]) + ++$idx; + if (++$idx >= $count) + return null; + return $this->parent->children[$idx]; + } + + // returns the previous sibling of node + function prev_sibling() + { + if ($this->parent === null) + return null; + $idx = 0; + $count = count($this->parent->children); + while ($idx < $count && $this !== $this->parent->children[$idx]) + ++$idx; + if (--$idx < 0) + return null; + return $this->parent->children[$idx]; + } + + // function to locate a specific ancestor tag in the path to the root. + function find_ancestor_tag($tag) + { + global $debugObject; + if (is_object($debugObject)) + { + $debugObject->debugLogEntry(1); + } + + // Start by including ourselves in the comparison. + $returnDom = $this; + + while (!is_null($returnDom)) + { + if (is_object($debugObject)) + { + $debugObject->debugLog(2, "Current tag is: " . $returnDom->tag); + } + + if ($returnDom->tag == $tag) + { + break; + } + $returnDom = $returnDom->parent; + } + return $returnDom; + } + + // get dom node's inner html + function innertext() + { + if (isset($this->_[HDOM_INFO_INNER])) + return $this->_[HDOM_INFO_INNER]; + if (isset($this->_[HDOM_INFO_TEXT])) + return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]); + + $ret = ''; + foreach ($this->nodes as $n) + $ret .= $n->outertext(); + return $ret; + } + + // get dom node's outer text (with tag) + function outertext() + { + global $debugObject; + if (is_object($debugObject)) + { + $text = ''; + if ($this->tag == 'text') + { + if (!empty($this->text)) + { + $text = " with text: " . $this->text; + } + } + $debugObject->debugLog(1, 'Innertext of tag: ' . $this->tag . $text); + } + + if ($this->tag === 'root') + return $this->innertext(); + + // trigger callback + if ($this->dom && $this->dom->callback !== null) + { + call_user_func_array($this->dom->callback, array($this)); + } + + if (isset($this->_[HDOM_INFO_OUTER])) + return $this->_[HDOM_INFO_OUTER]; + if (isset($this->_[HDOM_INFO_TEXT])) + return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]); + + // render begin tag + if ($this->dom && $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]]) + { + $ret = $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]]->makeup(); + } + else + { + $ret = ""; + } + + // render inner text + if (isset($this->_[HDOM_INFO_INNER])) + { + // If it's a br tag... don't return the HDOM_INNER_INFO that we may or may not have added. + if ($this->tag != "br") + { + $ret .= $this->_[HDOM_INFO_INNER]; + } + } + else + { + if ($this->nodes) + { + foreach ($this->nodes as $n) + { + $ret .= $this->convert_text($n->outertext()); + } + } + } + + // render end tag + if (isset($this->_[HDOM_INFO_END]) && $this->_[HDOM_INFO_END] != 0) + $ret .= 'tag . '>'; + return $ret; + } + + // get dom node's plain text + function text() + { + if (isset($this->_[HDOM_INFO_INNER])) + return $this->_[HDOM_INFO_INNER]; + switch ($this->nodetype) + { + case HDOM_TYPE_TEXT: return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]); + case HDOM_TYPE_COMMENT: return ''; + case HDOM_TYPE_UNKNOWN: return ''; + } + if (strcasecmp($this->tag, 'script') === 0) + return ''; + if (strcasecmp($this->tag, 'style') === 0) + return ''; + + $ret = ''; + // In rare cases, (always node type 1 or HDOM_TYPE_ELEMENT - observed for some span tags, and some p tags) $this->nodes is set to NULL. + // NOTE: This indicates that there is a problem where it's set to NULL without a clear happening. + // WHY is this happening? + if (!is_null($this->nodes)) + { + foreach ($this->nodes as $n) + { + $ret .= $this->convert_text($n->text()); + } + } + return $ret; + } + + function xmltext() + { + $ret = $this->innertext(); + $ret = str_ireplace('', '', $ret); + return $ret; + } + + // build node's text with tag + function makeup() + { + // text, comment, unknown + if (isset($this->_[HDOM_INFO_TEXT])) + return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]); + + $ret = '<' . $this->tag; + $i = -1; + + foreach ($this->attr as $key => $val) + { + ++$i; + + // skip removed attribute + if ($val === null || $val === false) + continue; + + $ret .= $this->_[HDOM_INFO_SPACE][$i][0]; + //no value attr: nowrap, checked selected... + if ($val === true) + $ret .= $key; + else + { + switch ($this->_[HDOM_INFO_QUOTE][$i]) + { + case HDOM_QUOTE_DOUBLE: $quote = '"'; + break; + case HDOM_QUOTE_SINGLE: $quote = '\''; + break; + default: $quote = ''; + } + $ret .= $key . $this->_[HDOM_INFO_SPACE][$i][1] . '=' . $this->_[HDOM_INFO_SPACE][$i][2] . $quote . $val . $quote; + } + } + $ret = $this->dom->restore_noise($ret); + return $ret . $this->_[HDOM_INFO_ENDSPACE] . '>'; + } + + // find elements by css selector + //PaperG - added ability for find to lowercase the value of the selector. + function find($selector, $idx=null, $lowercase=false) + { + $selectors = $this->parse_selector($selector); + if (($count = count($selectors)) === 0) + return array(); + $found_keys = array(); + + // find each selector + for ($c = 0; $c < $count; ++$c) + { + // The change on the below line was documented on the sourceforge code tracker id 2788009 + // used to be: if (($levle=count($selectors[0]))===0) return array(); + if (($levle = count($selectors[$c])) === 0) + return array(); + if (!isset($this->_[HDOM_INFO_BEGIN])) + return array(); + + $head = array($this->_[HDOM_INFO_BEGIN] => 1); + + // handle descendant selectors, no recursive! + for ($l = 0; $l < $levle; ++$l) + { + $ret = array(); + foreach ($head as $k => $v) + { + $n = ($k === -1) ? $this->dom->root : $this->dom->nodes[$k]; + //PaperG - Pass this optional parameter on to the seek function. + $n->seek($selectors[$c][$l], $ret, $lowercase); + } + $head = $ret; + } + + foreach ($head as $k => $v) + { + if (!isset($found_keys[$k])) + $found_keys[$k] = 1; + } + } + + // sort keys + ksort($found_keys); + + $found = array(); + foreach ($found_keys as $k => $v) + $found[] = $this->dom->nodes[$k]; + + // return nth-element or array + if (is_null($idx)) + return $found; + else if ($idx < 0) + $idx = count($found) + $idx; + return (isset($found[$idx])) ? $found[$idx] : null; + } + + // seek for given conditions + // PaperG - added parameter to allow for case insensitive testing of the value of a selector. + protected function seek($selector, &$ret, $lowercase=false) + { + global $debugObject; + if (is_object($debugObject)) + { + $debugObject->debugLogEntry(1); + } + + list($tag, $key, $val, $exp, $no_key) = $selector; + + // xpath index + if ($tag && $key && is_numeric($key)) + { + $count = 0; + foreach ($this->children as $c) + { + if ($tag === '*' || $tag === $c->tag) + { + if (++$count == $key) + { + $ret[$c->_[HDOM_INFO_BEGIN]] = 1; + return; + } + } + } + return; + } + + $end = (!empty($this->_[HDOM_INFO_END])) ? $this->_[HDOM_INFO_END] : 0; + if ($end == 0) + { + $parent = $this->parent; + while (!isset($parent->_[HDOM_INFO_END]) && $parent !== null) + { + $end -= 1; + $parent = $parent->parent; + } + $end += $parent->_[HDOM_INFO_END]; + } + + for ($i = $this->_[HDOM_INFO_BEGIN] + 1; $i < $end; ++$i) + { + $node = $this->dom->nodes[$i]; + + $pass = true; + + if ($tag === '*' && !$key) + { + if (in_array($node, $this->children, true)) + $ret[$i] = 1; + continue; + } + + // compare tag + if ($tag && $tag != $node->tag && $tag !== '*') + { + $pass = false; + } + // compare key + if ($pass && $key) + { + if ($no_key) + { + if (isset($node->attr[$key])) + $pass = false; + } else + { + if (($key != "plaintext") && !isset($node->attr[$key])) + $pass = false; + } + } + // compare value + if ($pass && $key && $val && $val !== '*') + { + // If they have told us that this is a "plaintext" search then we want the plaintext of the node - right? + if ($key == "plaintext") + { + // $node->plaintext actually returns $node->text(); + $nodeKeyValue = $node->text(); + } + else + { + // this is a normal search, we want the value of that attribute of the tag. + $nodeKeyValue = $node->attr[$key]; + } + if (is_object($debugObject)) + { + $debugObject->debugLog(2, "testing node: " . $node->tag . " for attribute: " . $key . $exp . $val . " where nodes value is: " . $nodeKeyValue); + } + + //PaperG - If lowercase is set, do a case insensitive test of the value of the selector. + if ($lowercase) + { + $check = $this->match($exp, strtolower($val), strtolower($nodeKeyValue)); + } + else + { + $check = $this->match($exp, $val, $nodeKeyValue); + } + if (is_object($debugObject)) + { + $debugObject->debugLog(2, "after match: " . ($check ? "true" : "false")); + } + + // handle multiple class + if (!$check && strcasecmp($key, 'class') === 0) + { + foreach (explode(' ', $node->attr[$key]) as $k) + { + // Without this, there were cases where leading, trailing, or double spaces lead to our comparing blanks - bad form. + if (!empty($k)) + { + if ($lowercase) + { + $check = $this->match($exp, strtolower($val), strtolower($k)); + } + else + { + $check = $this->match($exp, $val, $k); + } + if ($check) + break; + } + } + } + if (!$check) + $pass = false; + } + if ($pass) + $ret[$i] = 1; + unset($node); + } + // It's passed by reference so this is actually what this function returns. + if (is_object($debugObject)) + { + $debugObject->debugLog(1, "EXIT - ret: ", $ret); + } + } + + protected function match($exp, $pattern, $value) + { + global $debugObject; + if (is_object($debugObject)) + { + $debugObject->debugLogEntry(1); + } + + switch ($exp) + { + case '=': + return ($value === $pattern); + case '!=': + return ($value !== $pattern); + case '^=': + return preg_match("/^" . preg_quote($pattern, '/') . "/", $value); + case '$=': + return preg_match("/" . preg_quote($pattern, '/') . "$/", $value); + case '*=': + if ($pattern[0] == '/') + { + return preg_match($pattern, $value); + } + return preg_match("/" . $pattern . "/i", $value); + } + return false; + } + + protected function parse_selector($selector_string) + { + global $debugObject; + if (is_object($debugObject)) + { + $debugObject->debugLogEntry(1); + } + + // pattern of CSS selectors, modified from mootools + // Paperg: Add the colon to the attrbute, so that it properly finds like google does. + // Note: if you try to look at this attribute, yo MUST use getAttribute since $dom->x:y will fail the php syntax check. +// Notice the \[ starting the attbute? and the @? following? This implies that an attribute can begin with an @ sign that is not captured. +// This implies that an html attribute specifier may start with an @ sign that is NOT captured by the expression. +// farther study is required to determine of this should be documented or removed. +// $pattern = "/([\w-:\*]*)(?:\#([\w-]+)|\.([\w-]+))?(?:\[@?(!?[\w-]+)(?:([!*^$]?=)[\"']?(.*?)[\"']?)?\])?([\/, ]+)/is"; + $pattern = "/([\w-:\*]*)(?:\#([\w-]+)|\.([\w-]+))?(?:\[@?(!?[\w-:]+)(?:([!*^$]?=)[\"']?(.*?)[\"']?)?\])?([\/, ]+)/is"; + preg_match_all($pattern, trim($selector_string) . ' ', $matches, PREG_SET_ORDER); + if (is_object($debugObject)) + { + $debugObject->debugLog(2, "Matches Array: ", $matches); + } + + $selectors = array(); + $result = array(); + //print_r($matches); + + foreach ($matches as $m) + { + $m[0] = trim($m[0]); + if ($m[0] === '' || $m[0] === '/' || $m[0] === '//') + continue; + // for browser generated xpath + if ($m[1] === 'tbody') + continue; + + list($tag, $key, $val, $exp, $no_key) = array($m[1], null, null, '=', false); + if (!empty($m[2])) + { + $key = 'id'; + $val = $m[2]; + } + if (!empty($m[3])) + { + $key = 'class'; + $val = $m[3]; + } + if (!empty($m[4])) + { + $key = $m[4]; + } + if (!empty($m[5])) + { + $exp = $m[5]; + } + if (!empty($m[6])) + { + $val = $m[6]; + } + + // convert to lowercase + if ($this->dom->lowercase) + { + $tag = strtolower($tag); + $key = strtolower($key); + } + //elements that do NOT have the specified attribute + if (isset($key[0]) && $key[0] === '!') + { + $key = substr($key, 1); + $no_key = true; + } + + $result[] = array($tag, $key, $val, $exp, $no_key); + if (trim($m[7]) === ',') + { + $selectors[] = $result; + $result = array(); + } + } + if (count($result) > 0) + $selectors[] = $result; + return $selectors; + } + + function __get($name) + { + if (isset($this->attr[$name])) + { + return $this->convert_text($this->attr[$name]); + } + switch ($name) + { + case 'outertext': return $this->outertext(); + case 'innertext': return $this->innertext(); + case 'plaintext': return $this->text(); + case 'xmltext': return $this->xmltext(); + default: return array_key_exists($name, $this->attr); + } + } + + function __set($name, $value) + { + switch ($name) + { + case 'outertext': return $this->_[HDOM_INFO_OUTER] = $value; + case 'innertext': + if (isset($this->_[HDOM_INFO_TEXT])) + return $this->_[HDOM_INFO_TEXT] = $value; + return $this->_[HDOM_INFO_INNER] = $value; + } + if (!isset($this->attr[$name])) + { + $this->_[HDOM_INFO_SPACE][] = array(' ', '', ''); + $this->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_DOUBLE; + } + $this->attr[$name] = $value; + } + + function __isset($name) + { + switch ($name) + { + case 'outertext': return true; + case 'innertext': return true; + case 'plaintext': return true; + } + //no value attr: nowrap, checked selected... + return (array_key_exists($name, $this->attr)) ? true : isset($this->attr[$name]); + } + + function __unset($name) + { + if (isset($this->attr[$name])) + unset($this->attr[$name]); + } + + // PaperG - Function to convert the text from one character set to another if the two sets are not the same. + function convert_text($text) + { + global $debugObject; + if (is_object($debugObject)) + { + $debugObject->debugLogEntry(1); + } + + $converted_text = $text; + + $sourceCharset = ""; + $targetCharset = ""; + if ($this->dom) + { + $sourceCharset = strtoupper($this->dom->_charset); + $targetCharset = strtoupper($this->dom->_target_charset); + } + if (is_object($debugObject)) + { + $debugObject->debugLog(3, "source charset: " . $sourceCharset . " target charaset: " . $targetCharset); + } + + if (!empty($sourceCharset) && !empty($targetCharset) && (strcasecmp($sourceCharset, $targetCharset) != 0)) + { + // Check if the reported encoding could have been incorrect and the text is actually already UTF-8 + if ((strcasecmp($targetCharset, 'UTF-8') == 0) && ($this->is_utf8($text))) + { + $converted_text = $text; + } + else + { + $converted_text = iconv($sourceCharset, $targetCharset, $text); + } + } + + return $converted_text; + } + + function is_utf8($string) + { + return (utf8_encode(utf8_decode($string)) == $string); + } + + // camel naming conventions + function getAllAttributes() + { + return $this->attr; + } + + function getAttribute($name) + { + return $this->__get($name); + } + + function setAttribute($name, $value) + { + $this->__set($name, $value); + } + + function hasAttribute($name) + { + return $this->__isset($name); + } + + function removeAttribute($name) + { + $this->__set($name, null); + } + + function getElementById($id) + { + return $this->find("#$id", 0); + } + + function getElementsById($id, $idx=null) + { + return $this->find("#$id", $idx); + } + + function getElementByTagName($name) + { + return $this->find($name, 0); + } + + function getElementsByTagName($name, $idx=null) + { + return $this->find($name, $idx); + } + + function parentNode() + { + return $this->parent(); + } + + function childNodes($idx=-1) + { + return $this->children($idx); + } + + function firstChild() + { + return $this->first_child(); + } + + function lastChild() + { + return $this->last_child(); + } + + function nextSibling() + { + return $this->next_sibling(); + } + + function previousSibling() + { + return $this->prev_sibling(); + } +} + +/** + * simple html dom parser + * Paperg - in the find routine: allow us to specify that we want case insensitive testing of the value of the selector. + * Paperg - change $size from protected to public so we can easily access it + * Paperg - added ForceTagsClosed in the constructor which tells us whether we trust the html or not. Default is to NOT trust it. + * + * @package PlaceLocalInclude + */ +class simple_html_dom +{ + public $root = null; + public $nodes = array(); + public $callback = null; + public $lowercase = false; + public $size; + protected $pos; + protected $doc; + protected $char; + protected $cursor; + protected $parent; + protected $noise = array(); + protected $token_blank = " \t\r\n"; + protected $token_equal = ' =/>'; + protected $token_slash = " />\r\n\t"; + protected $token_attr = ' >'; + protected $_charset = ''; + protected $_target_charset = ''; + protected $default_br_text = ""; + // use isset instead of in_array, performance boost about 30%... + protected $self_closing_tags = array('img' => 1, 'br' => 1, 'input' => 1, 'meta' => 1, 'link' => 1, 'hr' => 1, 'base' => 1, 'embed' => 1, 'spacer' => 1); + protected $block_tags = array('root' => 1, 'body' => 1, 'form' => 1, 'div' => 1, 'span' => 1, 'table' => 1); + // Known sourceforge issue #2977341 + // B tags that are not closed cause us to return everything to the end of the document. + protected $optional_closing_tags = array( + 'tr' => array('tr' => 1, 'td' => 1, 'th' => 1), + 'th' => array('th' => 1), + 'td' => array('td' => 1), + 'li' => array('li' => 1), + 'dt' => array('dt' => 1, 'dd' => 1), + 'dd' => array('dd' => 1, 'dt' => 1), + 'dl' => array('dd' => 1, 'dt' => 1), + 'p' => array('p' => 1), + 'nobr' => array('nobr' => 1), + 'b' => array('b' => 1), + ); + + function __construct($str=null, $lowercase=true, $forceTagsClosed=true, $target_charset=DEFAULT_TARGET_CHARSET, $stripRN=true, $defaultBRText=DEFAULT_BR_TEXT) + { + if ($str) + { + if (preg_match("/^http:\/\//i", $str) || is_file($str)) + $this->load_file($str); + else + $this->load($str, $lowercase, $stripRN, $defaultBRText); + } + // Forcing tags to be closed implies that we don't trust the html, but it can lead to parsing errors if we SHOULD trust the html. + if (!$forceTagsClosed) + { + $this->optional_closing_array = array(); + } + $this->_target_charset = $target_charset; + } + + function __destruct() + { + $this->clear(); + } + + // load html from string + function load($str, $lowercase=true, $stripRN=true, $defaultBRText=DEFAULT_BR_TEXT) + { + global $debugObject; + + // prepare + $this->prepare($str, $lowercase, $stripRN, $defaultBRText); + // strip out comments + $this->remove_noise("''is"); + // strip out cdata + $this->remove_noise("''is", true); + // Per sourceforge http://sourceforge.net/tracker/?func=detail&aid=2949097&group_id=218559&atid=1044037 + // Script tags removal now preceeds style tag removal. + // strip out