mirror of
https://github.com/EssentialsX/Essentials.git
synced 2024-11-17 08:05:30 +01:00
Implement Command Cooldowns. Resolves #110
This commit is contained in:
parent
864dadab80
commit
09acbcdb05
@ -4,6 +4,7 @@ import com.earth2me.essentials.textreader.IText;
|
|||||||
import com.earth2me.essentials.textreader.KeywordReplacer;
|
import com.earth2me.essentials.textreader.KeywordReplacer;
|
||||||
import com.earth2me.essentials.textreader.TextInput;
|
import com.earth2me.essentials.textreader.TextInput;
|
||||||
import com.earth2me.essentials.textreader.TextPager;
|
import com.earth2me.essentials.textreader.TextPager;
|
||||||
|
import com.earth2me.essentials.utils.DateUtil;
|
||||||
import com.earth2me.essentials.utils.LocationUtil;
|
import com.earth2me.essentials.utils.LocationUtil;
|
||||||
import net.ess3.api.IEssentials;
|
import net.ess3.api.IEssentials;
|
||||||
import org.bukkit.GameMode;
|
import org.bukkit.GameMode;
|
||||||
@ -26,11 +27,15 @@ import org.bukkit.inventory.InventoryHolder;
|
|||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import static com.earth2me.essentials.I18n.tl;
|
import static com.earth2me.essentials.I18n.tl;
|
||||||
|
|
||||||
@ -399,10 +404,48 @@ public class EssentialsPlayerListener implements Listener {
|
|||||||
broadcast = false;
|
broadcast = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
final User user = ess.getUser(player);
|
||||||
if (update) {
|
if (update) {
|
||||||
final User user = ess.getUser(player);
|
|
||||||
user.updateActivity(broadcast);
|
user.updateActivity(broadcast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ess.getSettings().isCommandCooldownsEnabled() && pluginCommand != null) {
|
||||||
|
int argStartIndex = event.getMessage().indexOf(" ");
|
||||||
|
String args = argStartIndex == -1 ? event.getMessage() // No arguments present
|
||||||
|
: event.getMessage().substring(argStartIndex); // arguments start at argStartIndex; substring from there.
|
||||||
|
String fullCommand = pluginCommand.getName() + " " + args;
|
||||||
|
|
||||||
|
// Used to determine whether a user already has an existing cooldown
|
||||||
|
// If so, no need to check for (and write) new ones.
|
||||||
|
boolean cooldownFound = false;
|
||||||
|
|
||||||
|
// Iterate over a copy of getCommandCooldowns in case of concurrent modifications
|
||||||
|
for (Entry<Pattern, Long> entry : new HashMap<>(user.getCommandCooldowns()).entrySet()) {
|
||||||
|
// Remove any expired cooldowns
|
||||||
|
if (entry.getValue() <= System.currentTimeMillis()) {
|
||||||
|
user.clearCommandCooldown(entry.getKey());
|
||||||
|
// Don't break in case there are other command cooldowns left to clear.
|
||||||
|
} else if (entry.getKey().matcher(fullCommand).matches()) {
|
||||||
|
// User's current cooldown hasn't expired, inform and terminate cooldown code.
|
||||||
|
if (entry.getValue() > System.currentTimeMillis()) {
|
||||||
|
String commandCooldownTime = DateUtil.formatDateDiff(entry.getValue());
|
||||||
|
user.sendMessage(tl("commandCooldown", commandCooldownTime));
|
||||||
|
cooldownFound = true;
|
||||||
|
event.setCancelled(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cooldownFound) {
|
||||||
|
Entry<Pattern, Long> cooldownEntry = ess.getSettings().getCommandCooldownEntry(fullCommand);
|
||||||
|
|
||||||
|
if (cooldownEntry != null) {
|
||||||
|
Date expiry = new Date(System.currentTimeMillis() + cooldownEntry.getValue());
|
||||||
|
user.addCommandCooldown(cooldownEntry.getKey(), expiry, ess.getSettings().isCommandCooldownPersistent(fullCommand));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.NORMAL)
|
@EventHandler(priority = EventPriority.NORMAL)
|
||||||
|
@ -10,7 +10,9 @@ import org.bukkit.event.EventPriority;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
|
||||||
public interface ISettings extends IConf {
|
public interface ISettings extends IConf {
|
||||||
@ -247,4 +249,12 @@ public interface ISettings extends IConf {
|
|||||||
boolean isSpawnOnJoin();
|
boolean isSpawnOnJoin();
|
||||||
|
|
||||||
boolean isTeleportToCenterLocation();
|
boolean isTeleportToCenterLocation();
|
||||||
|
|
||||||
|
boolean isCommandCooldownsEnabled();
|
||||||
|
|
||||||
|
long getCommandCooldownMs(String label);
|
||||||
|
|
||||||
|
Entry<Pattern, Long> getCommandCooldownEntry(String label);
|
||||||
|
|
||||||
|
boolean isCommandCooldownPersistent(String label);
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,11 @@ import org.bukkit.Location;
|
|||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
|
||||||
public interface IUser {
|
public interface IUser {
|
||||||
@ -138,6 +140,14 @@ public interface IUser {
|
|||||||
Map<String, Object> getConfigMap();
|
Map<String, Object> getConfigMap();
|
||||||
|
|
||||||
Map<String, Object> getConfigMap(String node);
|
Map<String, Object> getConfigMap(String node);
|
||||||
|
|
||||||
|
Map<Pattern, Long> getCommandCooldowns();
|
||||||
|
|
||||||
|
Date getCommandCooldownExpiry(String label);
|
||||||
|
|
||||||
|
void addCommandCooldown(Pattern pattern, Date expiresAt, boolean save);
|
||||||
|
|
||||||
|
boolean clearCommandCooldown(Pattern pattern);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PlayerExtension
|
* PlayerExtension
|
||||||
|
@ -16,10 +16,13 @@ import org.bukkit.inventory.ItemStack;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import static com.earth2me.essentials.I18n.tl;
|
import static com.earth2me.essentials.I18n.tl;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.regex.PatternSyntaxException;
|
||||||
|
|
||||||
|
|
||||||
public class Settings implements net.ess3.api.ISettings {
|
public class Settings implements net.ess3.api.ISettings {
|
||||||
@ -532,6 +535,7 @@ public class Settings implements net.ess3.api.ISettings {
|
|||||||
customQuitMessage = _getCustomQuitMessage();
|
customQuitMessage = _getCustomQuitMessage();
|
||||||
isCustomQuitMessage = !customQuitMessage.equals("none");
|
isCustomQuitMessage = !customQuitMessage.equals("none");
|
||||||
muteCommands = _getMuteCommands();
|
muteCommands = _getMuteCommands();
|
||||||
|
commandCooldowns = _getCommandCooldowns();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Integer> itemSpawnBl = new ArrayList<Integer>();
|
private List<Integer> itemSpawnBl = new ArrayList<Integer>();
|
||||||
@ -1173,4 +1177,89 @@ public class Settings implements net.ess3.api.ISettings {
|
|||||||
public boolean isTeleportToCenterLocation() {
|
public boolean isTeleportToCenterLocation() {
|
||||||
return config.getBoolean("teleport-to-center", true);
|
return config.getBoolean("teleport-to-center", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Map<Pattern, Long> commandCooldowns;
|
||||||
|
|
||||||
|
private Map<Pattern, Long> _getCommandCooldowns() {
|
||||||
|
if (!config.isConfigurationSection("command-cooldowns")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ConfigurationSection section = config.getConfigurationSection("command-cooldowns");
|
||||||
|
Map<Pattern, Long> result = new LinkedHashMap<>();
|
||||||
|
for (String cmdEntry : section.getKeys(false)) {
|
||||||
|
Pattern pattern = null;
|
||||||
|
|
||||||
|
/* ================================
|
||||||
|
* >> Regex
|
||||||
|
* ================================ */
|
||||||
|
if (cmdEntry.startsWith("^")) {
|
||||||
|
try {
|
||||||
|
pattern = Pattern.compile(cmdEntry.substring(1));
|
||||||
|
} catch (PatternSyntaxException e) {
|
||||||
|
ess.getLogger().warning("Command cooldown error: " + e.getMessage());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Escape above Regex
|
||||||
|
if (cmdEntry.startsWith("\\^")) {
|
||||||
|
cmdEntry = cmdEntry.substring(1);
|
||||||
|
}
|
||||||
|
String cmd = cmdEntry
|
||||||
|
.replaceAll("\\*", ".*"); // Wildcards are accepted as asterisk * as known universally.
|
||||||
|
pattern = Pattern.compile(cmd + "( .*)?"); // This matches arguments, if present, to "ignore" them from the feature.
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================
|
||||||
|
* >> Process cooldown value
|
||||||
|
* ================================ */
|
||||||
|
Object value = section.get(cmdEntry);
|
||||||
|
if (!(value instanceof Number) && value instanceof String) {
|
||||||
|
try {
|
||||||
|
value = Double.parseDouble(value.toString());
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!(value instanceof Number)) {
|
||||||
|
ess.getLogger().warning("Command cooldown error: '" + value + "' is not a valid cooldown");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
double cooldown = ((Number) value).doubleValue();
|
||||||
|
if (cooldown < 1) {
|
||||||
|
ess.getLogger().warning("Command cooldown with very short " + cooldown + " cooldown.");
|
||||||
|
}
|
||||||
|
|
||||||
|
result.put(pattern, (long) cooldown * 1000); // convert to milliseconds
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCommandCooldownsEnabled() {
|
||||||
|
return commandCooldowns != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getCommandCooldownMs(String label) {
|
||||||
|
Entry<Pattern, Long> result = getCommandCooldownEntry(label);
|
||||||
|
return result != null ? result.getValue() : -1; // return cooldown in milliseconds
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Entry<Pattern, Long> getCommandCooldownEntry(String label) {
|
||||||
|
if (isCommandCooldownsEnabled()) {
|
||||||
|
for (Entry<Pattern, Long> entry : this.commandCooldowns.entrySet()) {
|
||||||
|
// Check if label matches current pattern (command-cooldown in config)
|
||||||
|
if (entry.getKey().matcher(label).matches()) {
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCommandCooldownPersistent(String label) {
|
||||||
|
// TODO: enable per command cooldown specification for persistence.
|
||||||
|
return config.getBoolean("command-cooldown-persistence", true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package com.earth2me.essentials;
|
|||||||
|
|
||||||
import com.earth2me.essentials.utils.NumberUtil;
|
import com.earth2me.essentials.utils.NumberUtil;
|
||||||
import com.earth2me.essentials.utils.StringUtil;
|
import com.earth2me.essentials.utils.StringUtil;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
import net.ess3.api.IEssentials;
|
import net.ess3.api.IEssentials;
|
||||||
import net.ess3.api.InvalidWorldException;
|
import net.ess3.api.InvalidWorldException;
|
||||||
import net.ess3.api.MaxMoneyException;
|
import net.ess3.api.MaxMoneyException;
|
||||||
@ -13,6 +14,8 @@ import org.bukkit.inventory.ItemStack;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import static com.earth2me.essentials.I18n.tl;
|
import static com.earth2me.essentials.I18n.tl;
|
||||||
|
|
||||||
@ -85,6 +88,7 @@ public abstract class UserData extends PlayerExtension implements IConf {
|
|||||||
ignoredPlayers = _getIgnoredPlayers();
|
ignoredPlayers = _getIgnoredPlayers();
|
||||||
logoutLocation = _getLogoutLocation();
|
logoutLocation = _getLogoutLocation();
|
||||||
lastAccountName = _getLastAccountName();
|
lastAccountName = _getLastAccountName();
|
||||||
|
commandCooldowns = _getCommandCooldowns();
|
||||||
}
|
}
|
||||||
|
|
||||||
private BigDecimal money;
|
private BigDecimal money;
|
||||||
@ -792,6 +796,89 @@ public abstract class UserData extends PlayerExtension implements IConf {
|
|||||||
return new HashMap<String, Object>();
|
return new HashMap<String, Object>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pattern, Date. Pattern for less pattern creations
|
||||||
|
private Map<Pattern, Long> commandCooldowns;
|
||||||
|
|
||||||
|
private Map<Pattern, Long> _getCommandCooldowns() {
|
||||||
|
if (!config.isConfigurationSection("timestamps.command-cooldowns")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// See saveCommandCooldowns() for deserialization explanation
|
||||||
|
List<Map<?, ?>> section = config.getMapList("timestamps.command-cooldowns");
|
||||||
|
HashMap<Pattern, Long> result = new HashMap<>();
|
||||||
|
for (Map<?, ?> map : section) {
|
||||||
|
Pattern pattern = Pattern.compile(map.get("pattern").toString());
|
||||||
|
long expiry = ((Number) map.get("expiry")).longValue();
|
||||||
|
result.put(pattern, expiry);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Pattern, Long> getCommandCooldowns() {
|
||||||
|
if (this.commandCooldowns == null) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableMap(this.commandCooldowns);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCommandCooldownExpiry(String label) {
|
||||||
|
if (commandCooldowns != null) {
|
||||||
|
for (Entry<Pattern, Long> entry : this.commandCooldowns.entrySet()) {
|
||||||
|
if (entry.getKey().matcher(label).matches()) {
|
||||||
|
return new Date(entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addCommandCooldown(Pattern pattern, Date expiresAt, boolean save) {
|
||||||
|
if (this.commandCooldowns == null) {
|
||||||
|
this.commandCooldowns = new HashMap<>();
|
||||||
|
}
|
||||||
|
this.commandCooldowns.put(pattern, expiresAt.getTime());
|
||||||
|
if (save) {
|
||||||
|
saveCommandCooldowns();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean clearCommandCooldown(Pattern pattern) {
|
||||||
|
if (this.commandCooldowns == null) {
|
||||||
|
return false; // false for no modification
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.commandCooldowns.remove(pattern) != null) {
|
||||||
|
saveCommandCooldowns();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveCommandCooldowns() {
|
||||||
|
// Serialization explanation:
|
||||||
|
//
|
||||||
|
// Serialization is done as a map list instead of a config section due to limitations.
|
||||||
|
// When serializing patterns (which commonly include full stops .) Bukkit/Essentials config framework
|
||||||
|
// interprets it as a path separator, thus it breaks up the regex into sub nodes causing invalid syntax.
|
||||||
|
// Thus each command cooldown is instead stored as a Map of {pattern: .., expiry: ..} to work around this.
|
||||||
|
List<Object> serialized = new ArrayList<>();
|
||||||
|
for (Entry<Pattern, Long> entry : this.commandCooldowns.entrySet()) {
|
||||||
|
// Don't save expired cooldowns
|
||||||
|
if (entry.getValue() < System.currentTimeMillis()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<?, ?> map = ImmutableMap.builder()
|
||||||
|
.put("pattern", entry.getKey().pattern())
|
||||||
|
.put("expiry", entry.getValue())
|
||||||
|
.build();
|
||||||
|
serialized.add(map);
|
||||||
|
}
|
||||||
|
config.setProperty("timestamps.command-cooldowns", serialized);
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
public UUID getConfigUUID() {
|
public UUID getConfigUUID() {
|
||||||
return config.uuid;
|
return config.uuid;
|
||||||
}
|
}
|
||||||
|
@ -484,6 +484,24 @@ send-fly-enable-on-join: true
|
|||||||
# Give someone permission to teleport to a world with essentials.time.world.<worldname>.
|
# Give someone permission to teleport to a world with essentials.time.world.<worldname>.
|
||||||
world-time-permissions: false
|
world-time-permissions: false
|
||||||
|
|
||||||
|
# Specify cooldown for both Essentials commands and external commands as well.
|
||||||
|
# All commands do not start with a Forward Slash (/). Instead of /msg, write msg
|
||||||
|
#
|
||||||
|
# Wildcards are supported. E.g.
|
||||||
|
# - '*i*': 50
|
||||||
|
# adds a 50 second cooldown to all commands that include the letter i
|
||||||
|
#
|
||||||
|
# EssentialsX supports regex by starting the command with a caret ^
|
||||||
|
# For example, to target commands starting with ban and not banip the following would be used:
|
||||||
|
# '^ban([^ip])( .*)?': 60 # 60 seconds /ban cooldown.
|
||||||
|
# Note: If you have a command that starts with ^, then you can escape it using backslash (\). e.g. \^command: 123
|
||||||
|
command-cooldowns:
|
||||||
|
# feed: 100 # 100 second cooldown on /feed command
|
||||||
|
# '*': 5 # 5 Second cooldown on all commands
|
||||||
|
|
||||||
|
# Whether command cooldowns should be persistent past server shutdowns
|
||||||
|
command-cooldown-persistence: true
|
||||||
|
|
||||||
############################################################
|
############################################################
|
||||||
# +------------------------------------------------------+ #
|
# +------------------------------------------------------+ #
|
||||||
# | EssentialsHome | #
|
# | EssentialsHome | #
|
||||||
|
@ -573,3 +573,4 @@ msgEnabled=\u00a76Receiving messages \u00a7cenabled\u00a76.
|
|||||||
msgEnabledFor=\u00a76Receiving messages \u00a7cenabled \u00a76for \u00a7c{0}\u00a76.
|
msgEnabledFor=\u00a76Receiving messages \u00a7cenabled \u00a76for \u00a7c{0}\u00a76.
|
||||||
msgIgnore=\u00a7c{0} \u00a74has messages disabled.
|
msgIgnore=\u00a7c{0} \u00a74has messages disabled.
|
||||||
minimumPayAmount=\u00a7cThe minimum amount you can pay is {0}.
|
minimumPayAmount=\u00a7cThe minimum amount you can pay is {0}.
|
||||||
|
commandCooldown=\u00a7cYou cannot type that command for {0}.
|
||||||
|
@ -561,4 +561,5 @@ createdKit=\u00a76Created kit \u00a7c{0} \u00a76with \u00a7c{1} \u00a76entries a
|
|||||||
spectator=spectator
|
spectator=spectator
|
||||||
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
||||||
kitItem=\u00a76- \u00a7f{0}
|
kitItem=\u00a76- \u00a7f{0}
|
||||||
invalidBanner=\u00a74Invalid banner syntax.
|
invalidBanner=\u00a74Invalid banner syntax.
|
||||||
|
commandCooldown=\u00a7cYou cannot type that command for {0}.
|
||||||
|
@ -561,4 +561,5 @@ createdKit=\u00a76Created kit \u00a7c{0} \u00a76with \u00a7c{1} \u00a76entries a
|
|||||||
spectator=spectator
|
spectator=spectator
|
||||||
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
||||||
kitItem=\u00a76- \u00a7f{0}
|
kitItem=\u00a76- \u00a7f{0}
|
||||||
invalidBanner=\u00a74Invalid banner syntax.
|
invalidBanner=\u00a74Invalid banner syntax.
|
||||||
|
commandCooldown=\u00a7cYou cannot type that command for {0}.
|
||||||
|
@ -566,3 +566,4 @@ spectator=Zuschauer
|
|||||||
kitContains=\u00a76Ausr\u00fcstung \u00a7c{0} \u00a76enth\u00e4lt:
|
kitContains=\u00a76Ausr\u00fcstung \u00a7c{0} \u00a76enth\u00e4lt:
|
||||||
kitItem=\u00a76- \u00a7f{0}
|
kitItem=\u00a76- \u00a7f{0}
|
||||||
invalidBanner=\u00a74Ung\u00fcltige Banner-Syntax.
|
invalidBanner=\u00a74Ung\u00fcltige Banner-Syntax.
|
||||||
|
commandCooldown=\u00a7cYou cannot type that command for {0}.
|
||||||
|
@ -566,3 +566,4 @@ msgDisabled=\u00a76Receiving messages \u00a7cdisabled\u00a76.
|
|||||||
msgDisabledFor=\u00a76Receiving messages \u00a7cdisabled \u00a76for \u00a7c{0}\u00a76.
|
msgDisabledFor=\u00a76Receiving messages \u00a7cdisabled \u00a76for \u00a7c{0}\u00a76.
|
||||||
msgEnabled=\u00a76Receiving messages \u00a7cenabled\u00a76.
|
msgEnabled=\u00a76Receiving messages \u00a7cenabled\u00a76.
|
||||||
msgEnabledFor=\u00a76Receiving messages \u00a7cenabled \u00a76for \u00a7c{0}\u00a76.
|
msgEnabledFor=\u00a76Receiving messages \u00a7cenabled \u00a76for \u00a7c{0}\u00a76.
|
||||||
|
commandCooldown=\u00a7cYou cannot type that command for {0}.
|
||||||
|
@ -561,4 +561,5 @@ createdKit=\u00a76Created kit \u00a7c{0} \u00a76with \u00a7c{1} \u00a76entries a
|
|||||||
spectator=spectator
|
spectator=spectator
|
||||||
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
||||||
kitItem=\u00a76- \u00a7f{0}
|
kitItem=\u00a76- \u00a7f{0}
|
||||||
invalidBanner=\u00a74Invalid banner syntax.
|
invalidBanner=\u00a74Invalid banner syntax.
|
||||||
|
commandCooldown=\u00a7cYou cannot type that command for {0}.
|
||||||
|
@ -561,4 +561,5 @@ createdKit=\u00a76Created kit \u00a7c{0} \u00a76with \u00a7c{1} \u00a76entries a
|
|||||||
spectator=spectator
|
spectator=spectator
|
||||||
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
||||||
kitItem=\u00a76- \u00a7f{0}
|
kitItem=\u00a76- \u00a7f{0}
|
||||||
invalidBanner=\u00a74Invalid banner syntax.
|
invalidBanner=\u00a74Invalid banner syntax.
|
||||||
|
commandCooldown=\u00a7cYou cannot type that command for {0}.
|
||||||
|
@ -561,4 +561,5 @@ createdKit=\u00a76Created kit \u00a7c{0} \u00a76with \u00a7c{1} \u00a76entries a
|
|||||||
spectator=spectator
|
spectator=spectator
|
||||||
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
||||||
kitItem=\u00a76- \u00a7f{0}
|
kitItem=\u00a76- \u00a7f{0}
|
||||||
invalidBanner=\u00a74Invalid banner syntax.
|
invalidBanner=\u00a74Invalid banner syntax.
|
||||||
|
commandCooldown=\u00a7cYou cannot type that command for {0}.
|
||||||
|
@ -567,3 +567,4 @@ msgDisabled=\u00a76R\u00e9ception des messages \u00a7cd\u00e9sactiv\u00e9e\u00a7
|
|||||||
msgDisabledFor=\u00a76R\u00e9ception des messages \u00a7cd\u00e9sactiv\u00e9e \u00a76pour \u00a7c{0}\u00a76.
|
msgDisabledFor=\u00a76R\u00e9ception des messages \u00a7cd\u00e9sactiv\u00e9e \u00a76pour \u00a7c{0}\u00a76.
|
||||||
msgEnabled=\u00a76R\u00e9ception des messages \u00a7cactiv\u00e9e\u00a76.
|
msgEnabled=\u00a76R\u00e9ception des messages \u00a7cactiv\u00e9e\u00a76.
|
||||||
msgEnabledFor=\u00a76R\u00e9ception des messages \u00a7cactiv\u00e9e \u00a76pour \u00a7c{0}\u00a76.
|
msgEnabledFor=\u00a76R\u00e9ception des messages \u00a7cactiv\u00e9e \u00a76pour \u00a7c{0}\u00a76.
|
||||||
|
commandCooldown=\u00a7cYou cannot type that command for {0}.
|
||||||
|
@ -561,4 +561,5 @@ createdKit=\u00a76Created kit \u00a7c{0} \u00a76with \u00a7c{1} \u00a76entries a
|
|||||||
spectator=spectator
|
spectator=spectator
|
||||||
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
||||||
kitItem=\u00a76- \u00a7f{0}
|
kitItem=\u00a76- \u00a7f{0}
|
||||||
invalidBanner=\u00a74Invalid banner syntax.
|
invalidBanner=\u00a74Invalid banner syntax.
|
||||||
|
commandCooldown=\u00a7cYou cannot type that command for {0}.
|
||||||
|
@ -561,4 +561,5 @@ createdKit=\u00a76Created kit \u00a7c{0} \u00a76with \u00a7c{1} \u00a76entries a
|
|||||||
spectator=spectator
|
spectator=spectator
|
||||||
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
||||||
kitItem=\u00a76- \u00a7f{0}
|
kitItem=\u00a76- \u00a7f{0}
|
||||||
invalidBanner=\u00a74Invalid banner syntax.
|
invalidBanner=\u00a74Invalid banner syntax.
|
||||||
|
commandCooldown=\u00a7cYou cannot type that command for {0}.
|
||||||
|
@ -561,4 +561,5 @@ createdKit=\u00a76Created kit \u00a7c{0} \u00a76with \u00a7c{1} \u00a76entries a
|
|||||||
spectator=spectator
|
spectator=spectator
|
||||||
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
||||||
kitItem=\u00a76- \u00a7f{0}
|
kitItem=\u00a76- \u00a7f{0}
|
||||||
invalidBanner=\u00a74Invalid banner syntax.
|
invalidBanner=\u00a74Invalid banner syntax.
|
||||||
|
commandCooldown=\u00a7cYou cannot type that command for {0}.
|
||||||
|
@ -561,4 +561,5 @@ createdKit=\u00a76Created kit \u00a7c{0} \u00a76with \u00a7c{1} \u00a76entries a
|
|||||||
spectator=spectator
|
spectator=spectator
|
||||||
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
||||||
kitItem=\u00a76- \u00a7f{0}
|
kitItem=\u00a76- \u00a7f{0}
|
||||||
invalidBanner=\u00a74Invalid banner syntax.
|
invalidBanner=\u00a74Invalid banner syntax.
|
||||||
|
commandCooldown=\u00a7cYou cannot type that command for {0}.
|
||||||
|
@ -561,4 +561,5 @@ createdKit=\u00a76Created kit \u00a7c{0} \u00a76with \u00a7c{1} \u00a76entries a
|
|||||||
spectator=spectator
|
spectator=spectator
|
||||||
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
||||||
kitItem=\u00a76- \u00a7f{0}
|
kitItem=\u00a76- \u00a7f{0}
|
||||||
invalidBanner=\u00a74Invalid banner syntax.
|
invalidBanner=\u00a74Invalid banner syntax.
|
||||||
|
commandCooldown=\u00a7cYou cannot type that command for {0}.
|
||||||
|
@ -561,4 +561,5 @@ createdKit=\u00a76Created kit \u00a7c{0} \u00a76with \u00a7c{1} \u00a76entries a
|
|||||||
spectator=spectator
|
spectator=spectator
|
||||||
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
||||||
kitItem=\u00a76- \u00a7f{0}
|
kitItem=\u00a76- \u00a7f{0}
|
||||||
invalidBanner=\u00a74Invalid banner syntax.
|
invalidBanner=\u00a74Invalid banner syntax.
|
||||||
|
commandCooldown=\u00a7cYou cannot type that command for {0}.
|
||||||
|
@ -561,4 +561,5 @@ createdKit=\u00a76Created kit \u00a7c{0} \u00a76with \u00a7c{1} \u00a76entries a
|
|||||||
spectator=spectator
|
spectator=spectator
|
||||||
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
||||||
kitItem=\u00a76- \u00a7f{0}
|
kitItem=\u00a76- \u00a7f{0}
|
||||||
invalidBanner=\u00a74Invalid banner syntax.
|
invalidBanner=\u00a74Invalid banner syntax.
|
||||||
|
commandCooldown=\u00a7cYou cannot type that command for {0}.
|
||||||
|
@ -561,4 +561,5 @@ createdKit=\u00a76Created kit \u00a7c{0} \u00a76with \u00a7c{1} \u00a76entries a
|
|||||||
spectator=spectator
|
spectator=spectator
|
||||||
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
||||||
kitItem=\u00a76- \u00a7f{0}
|
kitItem=\u00a76- \u00a7f{0}
|
||||||
invalidBanner=\u00a74Invalid banner syntax.
|
invalidBanner=\u00a74Invalid banner syntax.
|
||||||
|
commandCooldown=\u00a7cYou cannot type that command for {0}.
|
||||||
|
@ -561,4 +561,5 @@ createdKit=\u00a76Created kit \u00a7c{0} \u00a76with \u00a7c{1} \u00a76entries a
|
|||||||
spectator=spectator
|
spectator=spectator
|
||||||
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
||||||
kitItem=\u00a76- \u00a7f{0}
|
kitItem=\u00a76- \u00a7f{0}
|
||||||
invalidBanner=\u00a74Invalid banner syntax.
|
invalidBanner=\u00a74Invalid banner syntax.
|
||||||
|
commandCooldown=\u00a7cYou cannot type that command for {0}.
|
||||||
|
@ -561,4 +561,5 @@ createdKit=\u00a76Created kit \u00a7c{0} \u00a76with \u00a7c{1} \u00a76entries a
|
|||||||
spectator=spectator
|
spectator=spectator
|
||||||
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
||||||
kitItem=\u00a76- \u00a7f{0}
|
kitItem=\u00a76- \u00a7f{0}
|
||||||
invalidBanner=\u00a74Invalid banner syntax.
|
invalidBanner=\u00a74Invalid banner syntax.
|
||||||
|
commandCooldown=\u00a7cYou cannot type that command for {0}.
|
||||||
|
@ -561,4 +561,5 @@ createdKit=\u00a76Created kit \u00a7c{0} \u00a76with \u00a7c{1} \u00a76entries a
|
|||||||
spectator=spectator
|
spectator=spectator
|
||||||
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
||||||
kitItem=\u00a76- \u00a7f{0}
|
kitItem=\u00a76- \u00a7f{0}
|
||||||
invalidBanner=\u00a74Invalid banner syntax.
|
invalidBanner=\u00a74Invalid banner syntax.
|
||||||
|
commandCooldown=\u00a7cYou cannot type that command for {0}.
|
||||||
|
@ -561,4 +561,5 @@ createdKit=\u00a76Created kit \u00a7c{0} \u00a76with \u00a7c{1} \u00a76entries a
|
|||||||
spectator=spectator
|
spectator=spectator
|
||||||
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
||||||
kitItem=\u00a76- \u00a7f{0}
|
kitItem=\u00a76- \u00a7f{0}
|
||||||
invalidBanner=\u00a74Invalid banner syntax.
|
invalidBanner=\u00a74Invalid banner syntax.
|
||||||
|
commandCooldown=\u00a7cYou cannot type that command for {0}.
|
||||||
|
@ -561,4 +561,5 @@ createdKit=\u00a76Created kit \u00a7c{0} \u00a76with \u00a7c{1} \u00a76entries a
|
|||||||
spectator=spectator
|
spectator=spectator
|
||||||
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
||||||
kitItem=\u00a76- \u00a7f{0}
|
kitItem=\u00a76- \u00a7f{0}
|
||||||
invalidBanner=\u00a74Invalid banner syntax.
|
invalidBanner=\u00a74Invalid banner syntax.
|
||||||
|
commandCooldown=\u00a7cYou cannot type that command for {0}.
|
||||||
|
@ -561,4 +561,5 @@ createdKit=\u00a76Created kit \u00a7c{0} \u00a76with \u00a7c{1} \u00a76entries a
|
|||||||
spectator=spectator
|
spectator=spectator
|
||||||
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
||||||
kitItem=\u00a76- \u00a7f{0}
|
kitItem=\u00a76- \u00a7f{0}
|
||||||
invalidBanner=\u00a74Invalid banner syntax.
|
invalidBanner=\u00a74Invalid banner syntax.
|
||||||
|
commandCooldown=\u00a7cYou cannot type that command for {0}.
|
||||||
|
@ -561,4 +561,5 @@ createdKit=\u00a76Created kit \u00a7c{0} \u00a76with \u00a7c{1} \u00a76entries a
|
|||||||
spectator=spectator
|
spectator=spectator
|
||||||
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
kitContains=\u00a76Kit \u00a7c{0} \u00a76contains:
|
||||||
kitItem=\u00a76- \u00a7f{0}
|
kitItem=\u00a76- \u00a7f{0}
|
||||||
invalidBanner=\u00a74Invalid banner syntax.
|
invalidBanner=\u00a74Invalid banner syntax.
|
||||||
|
commandCooldown=\u00a7cYou cannot type that command for {0}.
|
||||||
|
Loading…
Reference in New Issue
Block a user