diff --git a/plugin.yml b/plugin.yml index 75826f15..8f95ef11 100755 --- a/plugin.yml +++ b/plugin.yml @@ -1,6 +1,6 @@ name: mcore version: 1.0.0 -main: com.massivecraft.core.MCore +main: com.massivecraft.core.plugin.MCore authors: [Olof Larsson] softdepend: [Vault, Spout] commands: diff --git a/src/com/massivecraft/core/persist/Persist.java b/src/com/massivecraft/core/persist/Persist.java index 1adc87d1..122bf5e1 100755 --- a/src/com/massivecraft/core/persist/Persist.java +++ b/src/com/massivecraft/core/persist/Persist.java @@ -1,209 +1,17 @@ package com.massivecraft.core.persist; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.Map; -import java.util.Timer; public class Persist { - private Map, IClassManager> classManagers = new HashMap, IClassManager>(); - public void setManager(Class clazz, IClassManager manager) + private static Map realms = new HashMap(); + public static Map getRealms() { return realms; } + public static PersistRealm getRealm(Object realmOwner) { return realms.get(realmOwner); } + public static void createRealm(Object realmOwner) { - this.classManagers.put(clazz, manager); - }; - public Map, IClassManager> getClassManagers() - { - return this.classManagers; - } - - protected Timer timer = new Timer(); - - private Map, SaveTask> classSaveTasks = new HashMap, SaveTask>(); - @SuppressWarnings("unchecked") - public void setSaveInterval(Class clazz, long interval) - { - // Fetch the task or create a new one. - SaveTask task = (SaveTask) this.classSaveTasks.get(clazz); - if (task == null) - { - task = new SaveTask(this, clazz); - this.classSaveTasks.put(clazz, task); - } - else - { - task.cancel(); - } - - // Schedule the task - timer.scheduleAtFixedRate(task, interval, interval); - }; - - - @SuppressWarnings("unchecked") - public IClassManager getManager(Class clazz) - { - return (IClassManager) this.classManagers.get(clazz); - } - - @SuppressWarnings("unchecked") - public IClassManager getManager(T entity) - { - return (IClassManager) this.getManager(entity.getClass()); - } - - // -------------------------------------------- // - // SAVE ALL - // -------------------------------------------- // - - public void saveAll() - { - for (IClassManager m : this.classManagers.values()) - { - m.saveAll(); - } - } - - // -------------------------------------------- // - // UTILS - // -------------------------------------------- // - - public static void write(File file, String content) throws IOException - { - BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, false), "UTF8")); - out.write(content); - out.close(); - } - - public static String read(File file) throws IOException - { - BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8")); - String ret = new String(new byte[0], "UTF-8"); - - String line; - while ((line = in.readLine()) != null) - { - ret += line; - } - - in.close(); - return ret; - } - - public static boolean writeCatch(File file, String content) - { - try - { - write(file, content); - return true; - } - catch (Exception e) - { - return false; - } - } - - public static String readCatch(File file) - { - try - { - return read(file); - } - catch (IOException e) - { - return null; - } - } - - public static ArrayList uglySQL(Collection items, Predictate where, Comparator orderby, Integer limit, Integer offset) - { - ArrayList ret = new ArrayList(items.size()); - - // WHERE - for (T item : items) - { - if (where.apply(item)) - { - ret.add(item); - } - } - - // ORDERBY - Collections.sort(ret, orderby); - - // LIMIT AND OFFSET - // Parse args - int fromIndex = 0; - if (offset != null) - { - fromIndex = offset; - } - - int toIndex = ret.size()-1; - if (limit != null) - { - toIndex = offset+limit; - } - - // Clean args - if (fromIndex < 0) - { - fromIndex = 0; - } - else if (fromIndex > ret.size()-1) - { - fromIndex = ret.size()-1; - } - - if (toIndex < fromIndex) - { - toIndex = fromIndex; - } - else if (toIndex > ret.size()-1) - { - toIndex = ret.size()-1; - } - - // No limit? - if (fromIndex == 0 && toIndex == ret.size()-1) return ret; - return new ArrayList(ret.subList(fromIndex, toIndex)); - } - - public static String getBestCIStart(Collection candidates, String start) - { - String ret = null; - int best = 0; - - start = start.toLowerCase(); - int minlength = start.length(); - for (String candidate : candidates) - { - if (candidate.length() < minlength) continue; - if ( ! candidate.toLowerCase().startsWith(start)) continue; - - // The closer to zero the better - int lendiff = candidate.length() - minlength; - if (lendiff == 0) - { - return candidate; - } - if (lendiff < best || best == 0) - { - best = lendiff; - ret = candidate; - } - } - return ret; + if (realms.containsKey(realmOwner)) return; + realms.put(realmOwner, new PersistRealm()); } + public static void removeRealm(Object realmOwner) { realms.remove(realmOwner); } } diff --git a/src/com/massivecraft/core/persist/PersistRealm.java b/src/com/massivecraft/core/persist/PersistRealm.java new file mode 100755 index 00000000..1db24989 --- /dev/null +++ b/src/com/massivecraft/core/persist/PersistRealm.java @@ -0,0 +1,209 @@ +package com.massivecraft.core.persist; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.Timer; + +public class PersistRealm +{ + private Map, IClassManager> classManagers = new HashMap, IClassManager>(); + public void setManager(Class clazz, IClassManager manager) + { + this.classManagers.put(clazz, manager); + }; + public Map, IClassManager> getClassManagers() + { + return this.classManagers; + } + + protected Timer timer = new Timer(); + + private Map, SaveTask> classSaveTasks = new HashMap, SaveTask>(); + @SuppressWarnings("unchecked") + public void setSaveInterval(Class clazz, long interval) + { + // Fetch the task or create a new one. + SaveTask task = (SaveTask) this.classSaveTasks.get(clazz); + if (task == null) + { + task = new SaveTask(this, clazz); + this.classSaveTasks.put(clazz, task); + } + else + { + task.cancel(); + } + + // Schedule the task + timer.scheduleAtFixedRate(task, interval, interval); + }; + + + @SuppressWarnings("unchecked") + public IClassManager getManager(Class clazz) + { + return (IClassManager) this.classManagers.get(clazz); + } + + @SuppressWarnings("unchecked") + public IClassManager getManager(T entity) + { + return (IClassManager) this.getManager(entity.getClass()); + } + + // -------------------------------------------- // + // SAVE ALL + // -------------------------------------------- // + + public void saveAll() + { + for (IClassManager m : this.classManagers.values()) + { + m.saveAll(); + } + } + + // -------------------------------------------- // + // UTILS + // -------------------------------------------- // + + public static void write(File file, String content) throws IOException + { + BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, false), "UTF8")); + out.write(content); + out.close(); + } + + public static String read(File file) throws IOException + { + BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8")); + String ret = new String(new byte[0], "UTF-8"); + + String line; + while ((line = in.readLine()) != null) + { + ret += line; + } + + in.close(); + return ret; + } + + public static boolean writeCatch(File file, String content) + { + try + { + write(file, content); + return true; + } + catch (Exception e) + { + return false; + } + } + + public static String readCatch(File file) + { + try + { + return read(file); + } + catch (IOException e) + { + return null; + } + } + + public static ArrayList uglySQL(Collection items, Predictate where, Comparator orderby, Integer limit, Integer offset) + { + ArrayList ret = new ArrayList(items.size()); + + // WHERE + for (T item : items) + { + if (where.apply(item)) + { + ret.add(item); + } + } + + // ORDERBY + Collections.sort(ret, orderby); + + // LIMIT AND OFFSET + // Parse args + int fromIndex = 0; + if (offset != null) + { + fromIndex = offset; + } + + int toIndex = ret.size()-1; + if (limit != null) + { + toIndex = offset+limit; + } + + // Clean args + if (fromIndex < 0) + { + fromIndex = 0; + } + else if (fromIndex > ret.size()-1) + { + fromIndex = ret.size()-1; + } + + if (toIndex < fromIndex) + { + toIndex = fromIndex; + } + else if (toIndex > ret.size()-1) + { + toIndex = ret.size()-1; + } + + // No limit? + if (fromIndex == 0 && toIndex == ret.size()-1) return ret; + return new ArrayList(ret.subList(fromIndex, toIndex)); + } + + public static String getBestCIStart(Collection candidates, String start) + { + String ret = null; + int best = 0; + + start = start.toLowerCase(); + int minlength = start.length(); + for (String candidate : candidates) + { + if (candidate.length() < minlength) continue; + if ( ! candidate.toLowerCase().startsWith(start)) continue; + + // The closer to zero the better + int lendiff = candidate.length() - minlength; + if (lendiff == 0) + { + return candidate; + } + if (lendiff < best || best == 0) + { + best = lendiff; + ret = candidate; + } + } + return ret; + } +} diff --git a/src/com/massivecraft/core/persist/SaveTask.java b/src/com/massivecraft/core/persist/SaveTask.java index 61225f8d..e17ed719 100755 --- a/src/com/massivecraft/core/persist/SaveTask.java +++ b/src/com/massivecraft/core/persist/SaveTask.java @@ -4,18 +4,18 @@ import java.util.TimerTask; public class SaveTask extends TimerTask { - private Persist persist; + private PersistRealm persist; private Class clazz; public Class getToBeSavedClass() { return clazz; } - public SaveTask(Persist persist, Class clazz) + public SaveTask(PersistRealm persist, Class clazz) { this.persist = persist; this.clazz = clazz; } - public SaveTask(Persist persist) + public SaveTask(PersistRealm persist) { this(persist, null); } diff --git a/src/com/massivecraft/core/persist/gson/GsonClassManager.java b/src/com/massivecraft/core/persist/gson/GsonClassManager.java index 851b4520..cbb2a1f2 100755 --- a/src/com/massivecraft/core/persist/gson/GsonClassManager.java +++ b/src/com/massivecraft/core/persist/gson/GsonClassManager.java @@ -13,7 +13,7 @@ import java.util.concurrent.CopyOnWriteArraySet; import com.massivecraft.core.lib.gson2.Gson; import com.massivecraft.core.persist.IClassManager; -import com.massivecraft.core.persist.Persist; +import com.massivecraft.core.persist.PersistRealm; import com.massivecraft.core.persist.Predictate; public abstract class GsonClassManager implements IClassManager @@ -259,7 +259,7 @@ public abstract class GsonClassManager implements IClassManager { String json = this.getGson().toJson(entity); File file = this.fileFromId(id); - return Persist.writeCatch(file, json); + return PersistRealm.writeCatch(file, json); } this.removeFile(id); return true; @@ -305,7 +305,7 @@ public abstract class GsonClassManager implements IClassManager if (entity != null) return entity; if ( ! this.containsId(id)) return null; File file = this.fileFromId(id); - String json = Persist.readCatch(file); + String json = PersistRealm.readCatch(file); if (json == null) return null; entity = this.getGson().fromJson(json, this.getManagedClass()); this.attach(entity, id, true); @@ -415,25 +415,25 @@ public abstract class GsonClassManager implements IClassManager @Override public Collection getAll(Predictate where) { - return Persist.uglySQL(this.entities, where, null, null, null); + return PersistRealm.uglySQL(this.entities, where, null, null, null); } @Override public Collection getAll(Predictate where, Comparator orderby) { - return Persist.uglySQL(this.entities, where, orderby, null, null); + return PersistRealm.uglySQL(this.entities, where, orderby, null, null); } @Override public Collection getAll(Predictate where, Comparator orderby, Integer limit) { - return Persist.uglySQL(this.entities, where, orderby, limit, null); + return PersistRealm.uglySQL(this.entities, where, orderby, limit, null); } @Override public Collection getAll(Predictate where, Comparator orderby, Integer limit, Integer offset) { - return Persist.uglySQL(this.entities, where, orderby, limit, offset); + return PersistRealm.uglySQL(this.entities, where, orderby, limit, offset); } @Override @@ -452,7 +452,7 @@ public abstract class GsonClassManager implements IClassManager public T getBestMatch(Object oid) { String start = this.idFix(oid); - String id = Persist.getBestCIStart(this.ids, start); + String id = PersistRealm.getBestCIStart(this.ids, start); return this.get(id); } } diff --git a/src/com/massivecraft/core/plugin/MCore.java b/src/com/massivecraft/core/plugin/MCore.java new file mode 100755 index 00000000..073ab270 --- /dev/null +++ b/src/com/massivecraft/core/plugin/MCore.java @@ -0,0 +1,58 @@ +package com.massivecraft.core.plugin; + +import org.bukkit.Bukkit; +import org.bukkit.event.Event.Priority; +import org.bukkit.event.Event.Type; +import org.bukkit.plugin.java.JavaPlugin; + +import com.massivecraft.core.persist.Persist; +import com.massivecraft.core.persist.PersistRealm; +import com.massivecraft.core.plugin.listener.PluginPlayerListener; +import com.massivecraft.core.plugin.listener.PluginServerListener; +import com.massivecraft.core.plugin.listener.PluginServerListenerMonitor; + +public class MCore extends JavaPlugin +{ + PluginServerListener serverListener; + PluginServerListenerMonitor serverListenerMonitor; + PluginPlayerListener playerListener; + + public static MCore p; + public static PersistRealm persist; + + public MCore() + { + p = this; + Persist.createRealm(this); + persist = Persist.getRealm(this); + this.serverListener = new PluginServerListener(this); + this.serverListenerMonitor = new PluginServerListenerMonitor(this); + this.playerListener = new PluginPlayerListener(this); + } + + public static PersistRealm getPersist() + { + return Persist.getRealm(p); + } + + @Override + public void onDisable() + { + // Avoid memleak by clearing ??? + // Or will this trigger errors??? + //Persist.getRealms().clear(); + } + + @Override + public void onEnable() + { + // This is safe since all plugins using Persist should bukkit-depend this plugin. + Persist.getRealms().clear(); + + // Register events + //Bukkit.getPluginManager().registerEvent(Type.PLUGIN_ENABLE, this.serverListener, Priority.Lowest, this); // Dangerous!?!?! + //Bukkit.getPluginManager().registerEvent(Type.PLUGIN_DISABLE, this.serverListenerMonitor, Priority.Monitor, this); // Dangerous!?!?! + Bukkit.getPluginManager().registerEvent(Type.PLAYER_JOIN, this.playerListener, Priority.Lowest, this); + } + +} diff --git a/src/com/massivecraft/core/plugin/listener/PluginPlayerListener.java b/src/com/massivecraft/core/plugin/listener/PluginPlayerListener.java new file mode 100755 index 00000000..61416e9c --- /dev/null +++ b/src/com/massivecraft/core/plugin/listener/PluginPlayerListener.java @@ -0,0 +1,36 @@ +package com.massivecraft.core.plugin.listener; + +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerListener; +import org.bukkit.event.player.PlayerLoginEvent; + +import com.massivecraft.core.persist.IClassManager; +import com.massivecraft.core.persist.Persist; +import com.massivecraft.core.persist.PersistRealm; +import com.massivecraft.core.plugin.MCore; + +public class PluginPlayerListener extends PlayerListener +{ + MCore p; + + public PluginPlayerListener(MCore p) + { + this.p = p; + } + + @Override + public void onPlayerLogin(PlayerLoginEvent event) + { + Player player = event.getPlayer(); + + for (PersistRealm realm : Persist.getRealms().values()) + { + for (IClassManager manager : realm.getClassManagers().values()) + { + if (manager.idFix(player) == null) continue; + if (manager.containsId(player)) continue; + manager.create(player); + } + } + } +} diff --git a/src/com/massivecraft/core/plugin/listener/PluginServerListener.java b/src/com/massivecraft/core/plugin/listener/PluginServerListener.java new file mode 100755 index 00000000..18b62b76 --- /dev/null +++ b/src/com/massivecraft/core/plugin/listener/PluginServerListener.java @@ -0,0 +1,24 @@ +package com.massivecraft.core.plugin.listener; + +import org.bukkit.event.server.PluginEnableEvent; +import org.bukkit.event.server.ServerListener; + +import com.massivecraft.core.persist.Persist; +import com.massivecraft.core.plugin.MCore; + +public class PluginServerListener extends ServerListener +{ + MCore p; + + public PluginServerListener(MCore p) + { + this.p = p; + } + + @Override + public void onPluginEnable(PluginEnableEvent event) + { + // TODO: Is this run after or before??? + Persist.createRealm(event.getPlugin()); + } +} diff --git a/src/com/massivecraft/core/plugin/listener/PluginServerListenerMonitor.java b/src/com/massivecraft/core/plugin/listener/PluginServerListenerMonitor.java new file mode 100755 index 00000000..7e155079 --- /dev/null +++ b/src/com/massivecraft/core/plugin/listener/PluginServerListenerMonitor.java @@ -0,0 +1,31 @@ +package com.massivecraft.core.plugin.listener; + +import org.bukkit.event.server.PluginDisableEvent; +import org.bukkit.event.server.PluginEnableEvent; +import org.bukkit.event.server.ServerListener; + +import com.massivecraft.core.persist.Persist; +import com.massivecraft.core.plugin.MCore; + +public class PluginServerListenerMonitor extends ServerListener +{ + MCore p; + + public PluginServerListenerMonitor(MCore p) + { + this.p = p; + } + + @Override + public void onPluginDisable(PluginDisableEvent event) + { + Persist.removeRealm(event.getPlugin()); + } + + @Override + public void onPluginEnable(PluginEnableEvent event) + { + // TODO: Is this run after or before??? + Persist.createRealm(event.getPlugin()); + } +} diff --git a/src/com/massivecraft/core/text/TextDesign.java b/src/com/massivecraft/core/text/TextDesign.java new file mode 100755 index 00000000..674b4903 --- /dev/null +++ b/src/com/massivecraft/core/text/TextDesign.java @@ -0,0 +1,119 @@ +package com.massivecraft.core.text; + +import java.util.HashMap; +import java.util.Map; + +import org.bukkit.ChatColor; + +// TODO: Add some more cool stuff.. like titelization design. +// TODO: Should they be color-parsed? or cashed color parsed? + +public class TextDesign +{ + public TextDesign() + { + + } + + // -------------------------------------------- // + // TITLE DESIGN + // -------------------------------------------- // + private String titleLeftInner; + public String getTitleLeftInner() { return this.titleLeftInner; } + public void setTitleLeftInner(String val) { this.titleLeftInner = val; } + + private String titleLeftOuter; + public String getTitleLeftOuter() { return this.titleLeftOuter; } + public void setTitleLeftOuter(String val) { this.titleLeftOuter = val; } + + private String titleRightInner; + public String getTitleRightInner() { return this.titleRightInner; } + public void setTitleRightInner(String val) { this.titleRightInner = val; } + + private String titleRightOuter; + public String getTitleRightOuter() { return this.titleRightOuter; } + public void setTitleRightOuter(String val) { this.titleRightOuter = val; } + + // -------------------------------------------- // + // COLOR THEME + // -------------------------------------------- // + private ChatColor logo = ChatColor.DARK_GREEN; + public ChatColor getColorLogo() { return this.logo; } + public void setColorLogo(ChatColor val) { this.logo = val; this.updateTag2Color(); } + + private ChatColor art = ChatColor.GOLD; + public ChatColor getColorArt() { return this.art; } + public void setColorArt(ChatColor val) { this.art = val; this.updateTag2Color(); } + + private ChatColor notice = ChatColor.GRAY; + public ChatColor getColorNotice() { return this.notice; } + public void setColorNotice(ChatColor val) { this.notice = val; this.updateTag2Color(); } + + private ChatColor info = ChatColor.YELLOW; + public ChatColor getColorInfo() { return this.info; } + public void setColorInfo(ChatColor val) { this.info = val; this.updateTag2Color(); } + + private ChatColor good = ChatColor.GREEN; + public ChatColor getColorGood() { return this.good; } + public void setColorGood(ChatColor val) { this.good = val; this.updateTag2Color(); } + + private ChatColor bad = ChatColor.RED; + public ChatColor getColorBad() { return this.bad; } + public void setColorBad(ChatColor val) { this.bad = val; this.updateTag2Color(); } + + private ChatColor hightlight = ChatColor.LIGHT_PURPLE; + public ChatColor getColorHighlight() { return this.hightlight; } + public void setColorHightlight(ChatColor val) { this.hightlight = val; this.updateTag2Color(); } + + private ChatColor command = ChatColor.AQUA; + public ChatColor getColorCommand() { return this.command; } + public void setColorCommand(ChatColor val) { this.command = val; this.updateTag2Color(); } + + private ChatColor parameter = ChatColor.DARK_AQUA; + public ChatColor getColorParameter() { return this.parameter; } + public void setColorParameter(ChatColor val) { this.parameter = val; this.updateTag2Color(); } + + private Map tag2color = null; + public Map getTags() + { + if (tag2color == null) + { + this.updateTag2Color(); + } + return this.tag2color; + } + + private void updateTag2Color() + { + if (tag2color == null) + { + this.tag2color = new HashMap(); + } + this.tag2color.put("", this.getColorLogo().toString()); + this.tag2color.put("", this.getColorLogo().toString()); + + this.tag2color.put("", this.getColorArt().toString()); + this.tag2color.put("", this.getColorArt().toString()); + + this.tag2color.put("", this.getColorNotice().toString()); + this.tag2color.put("", this.getColorNotice().toString()); + + this.tag2color.put("", this.getColorInfo().toString()); + this.tag2color.put("", this.getColorInfo().toString()); + + this.tag2color.put("", this.getColorGood().toString()); + this.tag2color.put("", this.getColorGood().toString()); + + this.tag2color.put("", this.getColorBad().toString()); + this.tag2color.put("", this.getColorBad().toString()); + + this.tag2color.put("", this.getColorHighlight().toString()); + this.tag2color.put("", this.getColorHighlight().toString()); + + this.tag2color.put("", this.getColorCommand().toString()); + this.tag2color.put("", this.getColorCommand().toString()); + + this.tag2color.put("

", this.getColorParameter().toString()); + this.tag2color.put("", this.getColorParameter().toString()); + } +} diff --git a/src/com/massivecraft/core/text/TextUtil.java b/src/com/massivecraft/core/text/TextUtil.java new file mode 100755 index 00000000..28bbcf2a --- /dev/null +++ b/src/com/massivecraft/core/text/TextUtil.java @@ -0,0 +1,343 @@ +package com.massivecraft.core.text; + +import java.util.*; +import java.util.Map.Entry; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.craftbukkit.TextWrapper; + +import com.massivecraft.core.plugin.MCore; + +public class TextUtil +{ + private TextDesign design = null; + public TextDesign getDesign() + { + if (design != null) return design; + return MCore.persist.getManager(TextDesign.class).get("default"); + // TODO: The default should not have the name default. + // The default is set somewhere... as a static field?... in the MCore plugin??? + } + public void setDesign(TextDesign design) + { + this.design = design; + } + + // -------------------------------------------- // + // Top-level parsing functions. + // -------------------------------------------- // + + public String parse(String str, Object... args) + { + return String.format(this.parse(str), args); + } + + public String parse(String str) + { + return this.parseTags(parseColor(str)); + } + + // -------------------------------------------- // + // Tag parsing + // -------------------------------------------- // + + public String parseTags(String str) + { + return replaceTags(str, this.getDesign().getTags()); + } + + public static final transient Pattern patternTag = Pattern.compile("<([a-zA-Z0-9_]*)>"); + public static String replaceTags(String str, Map tags) + { + StringBuffer ret = new StringBuffer(); + Matcher matcher = patternTag.matcher(str); + while (matcher.find()) + { + String tag = matcher.group(1); + String repl = tags.get(tag); + if (repl == null) + { + matcher.appendReplacement(ret, "<"+tag+">"); + } + else + { + matcher.appendReplacement(ret, repl); + } + } + matcher.appendTail(ret); + return ret.toString(); + } + + // -------------------------------------------- // + // Color parsing + // -------------------------------------------- // + + public static String parseColor(String string) + { + string = parseColorAmp(string); + string = parseColorAcc(string); + string = parseColorTags(string); + return string; + } + + public static String parseColorAmp(String string) + { + string = string.replaceAll("(ยง([a-z0-9]))", "\u00A7$2"); + string = string.replaceAll("(&([a-z0-9]))", "\u00A7$2"); + string = string.replace("&&", "&"); + return string; + } + + public static String parseColorAcc(String string) + { + return string.replace("`e", "") + .replace("`r", ChatColor.RED.toString()) .replace("`R", ChatColor.DARK_RED.toString()) + .replace("`y", ChatColor.YELLOW.toString()) .replace("`Y", ChatColor.GOLD.toString()) + .replace("`g", ChatColor.GREEN.toString()) .replace("`G", ChatColor.DARK_GREEN.toString()) + .replace("`a", ChatColor.AQUA.toString()) .replace("`A", ChatColor.DARK_AQUA.toString()) + .replace("`b", ChatColor.BLUE.toString()) .replace("`B", ChatColor.DARK_BLUE.toString()) + .replace("`p", ChatColor.LIGHT_PURPLE.toString()) .replace("`P", ChatColor.DARK_PURPLE.toString()) + .replace("`k", ChatColor.BLACK.toString()) .replace("`s", ChatColor.GRAY.toString()) + .replace("`S", ChatColor.DARK_GRAY.toString()) .replace("`w", ChatColor.WHITE.toString()); + } + + public static String parseColorTags(String string) + { + return string.replace("", "") + .replace("", "\u00A70") + .replace("", "\u00A71") + .replace("", "\u00A72") + .replace("", "\u00A73") + .replace("", "\u00A74") + .replace("", "\u00A75") + .replace("", "\u00A76") + .replace("", "\u00A77") + .replace("", "\u00A78") + .replace("", "\u00A79") + .replace("", "\u00A7a") + .replace("", "\u00A7b") + .replace("", "\u00A7c") + .replace("", "\u00A7d") + .replace("", "\u00A7e") + .replace("", "\u00A7f"); + } + + // -------------------------------------------- // + // Standard utils like UCFirst, implode and repeat. + // -------------------------------------------- // + + public static String upperCaseFirst(String string) + { + return string.substring(0, 1).toUpperCase()+string.substring(1); + } + + public static String repeat(String s, int times) + { + if (times <= 0) return ""; + else return s + repeat(s, times-1); + } + + public static String implode(List list, String glue) + { + StringBuilder ret = new StringBuilder(); + for (int i=0; i list, String comma, String and) + { + if (list.size() == 0) return ""; + if (list.size() == 1) return list.get(0); + + String lastItem = list.get(list.size()-1); + String nextToLastItem = list.get(list.size()-2); + String merge = nextToLastItem+and+lastItem; + list.set(list.size()-2, merge); + list.remove(list.size()-1); + + return implode(list, comma); + } + public static String implodeCommaAnd(List list) + { + return implodeCommaAnd(list, ", ", " and "); + } + + // -------------------------------------------- // + // Material name tools + // -------------------------------------------- // + + public static String getMaterialName(Material material) + { + return material.toString().replace('_', ' ').toLowerCase(); + } + + public static String getMaterialName(int materialId) + { + return getMaterialName(Material.getMaterial(materialId)); + } + + // -------------------------------------------- // + // Paging and chrome-tools like titleize + // -------------------------------------------- // + + private final static String titleizeLine = repeat("_", 52); + private final static int titleizeBalance = -1; + public String titleize(String str) + { + String center = ".[ "+ parseTags("") + str + parseTags("")+ " ]."; + int centerlen = ChatColor.stripColor(center).length(); + int pivot = titleizeLine.length() / 2; + int eatLeft = (centerlen / 2) - titleizeBalance; + int eatRight = (centerlen - eatLeft) + titleizeBalance; + + if (eatLeft < pivot) + return parseTags("")+titleizeLine.substring(0, pivot - eatLeft) + center + titleizeLine.substring(pivot + eatRight); + else + return parseTags("")+center; + } + + public ArrayList getPage(List lines, int pageHumanBased, String title) + { + ArrayList ret = new ArrayList(); + int pageZeroBased = pageHumanBased - 1; + int pageheight = 9; + int pagecount = (lines.size() / pageheight)+1; + + ret.add(this.titleize(title+" "+pageHumanBased+"/"+pagecount)); + + if (pagecount == 0) + { + ret.add(this.parseTags("Sorry. No Pages available.")); + return ret; + } + else if (pageZeroBased < 0 || pageHumanBased > pagecount) + { + ret.add(this.parseTags("Invalid page. Must be between 1 and "+pagecount)); + return ret; + } + + int from = pageZeroBased * pageheight; + int to = from+pageheight; + if (to > lines.size()) + { + to = lines.size(); + } + + ret.addAll(lines.subList(from, to)); + + return ret; + } + + // -------------------------------------------- // + // Describing Time + // -------------------------------------------- // + + /** + * Using this function you transform a delta in milliseconds + * to a String like "2 weeks from now" or "7 days ago". + */ + public static final long millisPerSecond = 1000; + public static final long millisPerMinute = 60 * millisPerSecond; + public static final long millisPerHour = 60 * millisPerMinute; + public static final long millisPerDay = 24 * millisPerHour; + public static final long millisPerWeek = 7 * millisPerDay; + public static final long millisPerMonth = 31 * millisPerDay; + public static final long millisPerYear = 365 * millisPerDay; + + public static Map unitMillis; + + static + { + unitMillis = new LinkedHashMap(); + unitMillis.put("years", millisPerYear); + unitMillis.put("months", millisPerMonth); + unitMillis.put("weeks", millisPerWeek); + unitMillis.put("days", millisPerDay); + unitMillis.put("hours", millisPerHour); + unitMillis.put("minutes", millisPerMinute); + unitMillis.put("seconds", millisPerSecond); + } + + public static String getTimeDeltaDescriptionRelNow(long millis) + { + String ret = ""; + + double millisLeft = (double) Math.abs(millis); + + List unitCountParts = new ArrayList(); + for (Entry entry : unitMillis.entrySet()) + { + if (unitCountParts.size() == 3 ) break; + String unitName = entry.getKey(); + long unitSize = entry.getValue(); + long unitCount = (long) Math.floor(millisLeft / unitSize); + if (unitCount < 1) continue; + millisLeft -= unitSize*unitCount; + unitCountParts.add(unitCount+" "+unitName); + } + + if (unitCountParts.size() == 0) return "just now"; + + ret += implodeCommaAnd(unitCountParts); + ret += " "; + if (millis <= 0) + { + ret += "ago"; + } + else + { + ret += "from now"; + } + + return ret; + } + + // -------------------------------------------- // + // String comparison + // -------------------------------------------- // + + public static String getBestCIStart(Collection candidates, String start) + { + String ret = null; + int best = 0; + + start = start.toLowerCase(); + int minlength = start.length(); + for (String candidate : candidates) + { + if (candidate.length() < minlength) continue; + if ( ! candidate.toLowerCase().startsWith(start)) continue; + + // The closer to zero the better + int lendiff = candidate.length() - minlength; + if (lendiff == 0) + { + return candidate; + } + if (lendiff < best || best == 0) + { + best = lendiff; + ret = candidate; + } + } + return ret; + } + + // -------------------------------------------- // + // Wrapping the Craftbukkit TextWrapper + // -------------------------------------------- // + public static ArrayList wrapText(final String text) + { + return new ArrayList(Arrays.asList(TextWrapper.wrapText(text))); + } +}