New enum cached, lazy generated KeywordReplacer

This runs before the pager, so keywords on other pages will still be parsed.
This commit is contained in:
KHobbits 2013-08-31 23:01:47 +01:00
parent 9908eb0619
commit 36c61eaa06

View File

@ -20,8 +20,13 @@ import org.bukkit.plugin.Plugin;
import static com.earth2me.essentials.I18n._; import static com.earth2me.essentials.I18n._;
import com.earth2me.essentials.PlayerList; import com.earth2me.essentials.PlayerList;
import static com.earth2me.essentials.PlayerList.getMergedList; import static com.earth2me.essentials.textreader.KeywordType.DISPLAYNAME;
import static com.earth2me.essentials.textreader.KeywordType.PLAYER;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class KeywordReplacer implements IText public class KeywordReplacer implements IText
@ -31,6 +36,9 @@ public class KeywordReplacer implements IText
private final transient IEssentials ess; private final transient IEssentials ess;
private final transient boolean extended; private final transient boolean extended;
private transient ExecuteTimer execTimer; private transient ExecuteTimer execTimer;
private final static Pattern KEYWORD = Pattern.compile("\\{([^\\{\\}]+)\\}");
private final static Pattern KEYWORDSPLIT = Pattern.compile("\\:");
private final EnumMap<KeywordType, Object> keywordCache = new EnumMap<KeywordType, Object>(KeywordType.class);
public KeywordReplacer(final IText input, final CommandSender sender, final IEssentials ess) public KeywordReplacer(final IText input, final CommandSender sender, final IEssentials ess)
{ {
@ -52,161 +60,269 @@ public class KeywordReplacer implements IText
private void replaceKeywords(final CommandSender sender) private void replaceKeywords(final CommandSender sender)
{ {
String displayName, ipAddress, balance, mails, world;
String worlds, online, unique, onlineList, date, time;
String worldTime12, worldTime24, worldDate, plugins;
String userName, version, address, tps, uptime;
String coords;
execTimer = new ExecuteTimer(); execTimer = new ExecuteTimer();
execTimer.start(); execTimer.start();
User user = null;
if (sender instanceof Player) if (sender instanceof Player)
{ {
final User user = ess.getUser(sender); user = ess.getUser(sender);
//This is just so any displayname lookups below show the correct nickname
user.setDisplayNick(); user.setDisplayNick();
displayName = user.getDisplayName();
ipAddress = user.getAddress() == null || user.getAddress().getAddress() == null ? "" : user.getAddress().getAddress().toString();
address = user.getAddress() == null ? "" : user.getAddress().toString();
execTimer.mark("User Grab");
balance = NumberUtil.displayCurrency(user.getMoney(), ess);
execTimer.mark("Economy");
mails = Integer.toString(user.getMails().size());
final Location location = user.getLocation();
world = location == null || location.getWorld() == null ? "" : location.getWorld().getName();
worldTime12 = DescParseTickFormat.format12(user.getWorld() == null ? 0 : user.getWorld().getTime());
worldTime24 = DescParseTickFormat.format24(user.getWorld() == null ? 0 : user.getWorld().getTime());
worldDate = DateFormat.getDateInstance(DateFormat.MEDIUM, ess.getI18n().getCurrentLocale()).format(DescParseTickFormat.ticksToDate(user.getWorld() == null ? 0 : user.getWorld().getFullTime()));
coords = _("coordsKeyword", location.getBlockX(), location.getBlockY(), location.getBlockZ());
} }
else execTimer.mark("User Grab");
{
displayName = address = ipAddress = balance = mails = world = worldTime12 = worldTime24 = worldDate = coords = "";
}
execTimer.mark("Player variables");
Map<String, List<User>> playerList = PlayerList.getPlayerLists(ess, extended);
userName = sender.getName();
int playerHidden = 0;
for (Player p : ess.getServer().getOnlinePlayers())
{
if (ess.getUser(p).isHidden())
{
playerHidden++;
}
}
online = Integer.toString(ess.getServer().getOnlinePlayers().length - playerHidden);
unique = Integer.toString(ess.getUserMap().getUniqueUsers());
execTimer.mark("Player list");
final StringBuilder worldsBuilder = new StringBuilder();
for (World w : ess.getServer().getWorlds())
{
if (worldsBuilder.length() > 0)
{
worldsBuilder.append(", ");
}
worldsBuilder.append(w.getName());
}
worlds = worldsBuilder.toString();
final StringBuilder playerlistBuilder = new StringBuilder();
for (Player p : ess.getServer().getOnlinePlayers())
{
if (ess.getUser(p).isHidden())
{
continue;
}
if (playerlistBuilder.length() > 0)
{
playerlistBuilder.append(", ");
}
playerlistBuilder.append(p.getDisplayName());
}
onlineList = playerlistBuilder.toString();
final StringBuilder pluginlistBuilder = new StringBuilder();
for (Plugin p : ess.getServer().getPluginManager().getPlugins())
{
if (pluginlistBuilder.length() > 0)
{
pluginlistBuilder.append(", ");
}
pluginlistBuilder.append(p.getDescription().getName());
}
plugins = pluginlistBuilder.toString();
execTimer.mark("List builders");
date = DateFormat.getDateInstance(DateFormat.MEDIUM, ess.getI18n().getCurrentLocale()).format(new Date());
time = DateFormat.getTimeInstance(DateFormat.MEDIUM, ess.getI18n().getCurrentLocale()).format(new Date());
version = ess.getServer().getVersion();
tps = Double.toString(ess.getTimer().getAverageTPS());
uptime = DateUtil.formatDateDiff(ManagementFactory.getRuntimeMXBean().getStartTime());
execTimer.mark("Server Dates");
for (int i = 0; i < input.getLines().size(); i++) for (int i = 0; i < input.getLines().size(); i++)
{ {
String line = input.getLines().get(i); String line = input.getLines().get(i);
final Matcher matcher = KEYWORD.matcher(line);
line = line.replace("{PLAYER}", displayName); while (matcher.find())
line = line.replace("{DISPLAYNAME}", displayName);
line = line.replace("{USERNAME}", userName);
line = line.replace("{BALANCE}", balance);
line = line.replace("{MAILS}", mails);
line = line.replace("{WORLD}", world);
line = line.replace("{ONLINE}", online);
line = line.replace("{UNIQUE}", unique);
line = line.replace("{WORLDS}", worlds);
line = line.replace("{PLAYERLIST}", onlineList);
line = line.replace("{TIME}", time);
line = line.replace("{DATE}", date);
line = line.replace("{WORLDTIME12}", worldTime12);
line = line.replace("{WORLDTIME24}", worldTime24);
line = line.replace("{WORLDDATE}", worldDate);
line = line.replace("{COORDS}", coords);
line = line.replace("{TPS}", tps);
line = line.replace("{UPTIME}", uptime);
if (extended)
{ {
line = line.replace("{IP}", ipAddress); final String fullMatch = matcher.group(0);
line = line.replace("{ADDRESS}", address); final String keywordMatch = matcher.group(1);
line = line.replace("{PLUGINS}", plugins); final String[] matchTokens = KEYWORDSPLIT.split(keywordMatch);
line = line.replace("{VERSION}", version); line = replaceLine(line, fullMatch, matchTokens, user);
for (String groupName : playerList.keySet())
{
final List<User> groupUsers = playerList.get(groupName);
if (groupUsers != null && !groupUsers.isEmpty())
{
line = line.replaceAll("\\{PLAYERLIST\\:" + groupName.toUpperCase() + "(?:\\:([^\\{\\}]*))?\\}",
PlayerList.listUsers(ess, groupUsers, " "));
}
}
boolean doReplace = true;
while (doReplace)
{
final String newLine = line.replaceAll("\\{PLAYERLIST\\:\\w*(?:\\:([^\\{\\}]*))?\\}", "$1");
if (newLine.equals(line))
{
doReplace = false;
}
line = newLine;
}
} }
replaced.add(line); replaced.add(line);
} }
execTimer.mark("String replace");
execTimer.mark("Text Replace");
final String timeroutput = execTimer.end(); final String timeroutput = execTimer.end();
if (ess.getSettings().isDebug()) if (ess.getSettings().isDebug())
{ {
ess.getLogger().log(Level.INFO, "Keyword Replacer " + timeroutput); 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];
}
if (keywordCache.containsKey(validKeyword))
{
Map<String, String> values = (Map<String, String>)keywordCache.get(validKeyword);
if (values.containsKey(subKeyword))
{
replacer = values.get(subKeyword);
}
}
}
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:
if (user != null)
{
final Location location = user.getLocation();
replacer = location == null || location.getWorld() == null ? "" : location.getWorld().getName();
}
break;
case ONLINE:
int playerHidden = 0;
for (Player p : ess.getServer().getOnlinePlayers())
{
if (ess.getUser(p).isHidden())
{
playerHidden++;
}
}
replacer = Integer.toString(ess.getServer().getOnlinePlayers().length - 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<String, String> outputList;
if (keywordCache.containsKey(validKeyword))
{
outputList = (Map<String, String>)keywordCache.get(validKeyword);
}
else
{
//First lets build the per group playerlist
final Map<String, List<User>> playerList = PlayerList.getPlayerLists(ess, extended);
outputList = new HashMap<String, String>();
for (String groupName : playerList.keySet())
{
final List<User> 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.getServer().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]))
{
replacer = outputList.get(matchTokens[1]);
}
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 = _("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.getAddress() == null || user.getAddress().getAddress() == null ? "" : user.getAddress().getAddress().toString();
}
break;
case ADDRESS:
if (user != null)
{
replacer = user.getAddress() == null ? "" : user.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 @Override
@ -227,3 +343,48 @@ public class KeywordReplacer implements IText
return input.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),
ONLINE(KeywordCachable.CACHEABLE),
UNIQUE(KeywordCachable.CACHEABLE),
WORLDS(KeywordCachable.CACHEABLE),
PLAYERLIST(KeywordCachable.SUBVALUE),
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),
ADDRESS(KeywordCachable.CACHEABLE),
PLUGINS(KeywordCachable.CACHEABLE),
VERSION(KeywordCachable.CACHEABLE);
private final KeywordCachable type;
KeywordType(KeywordCachable type)
{
this.type = type;
}
public KeywordCachable getType()
{
return type;
}
}
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
}