In progress: Using MassiveCraftCore and Allman indentation style and minor refactoring.

This commit is contained in:
Olof Larsson
2011-10-08 22:03:44 +02:00
parent 61998f459d
commit 0ce9cce9d3
75 changed files with 4605 additions and 2033 deletions

View File

@ -0,0 +1,9 @@
package com.massivecraft.factions.zcore;
public enum CommandVisibility
{
VISIBLE, // Visible commands are visible to anyone. Even those who don't have permission to use it or is of invalid sender type.
SECRET, // Secret commands are visible only to those who can use the command. These commands are usually some kind of admin commands.
INVISIBLE, // Invisible commands are invisible to everyone, even those who can use the command.
;
}

View File

@ -0,0 +1,429 @@
package com.massivecraft.factions.zcore;
import java.util.*;
import java.util.Map.Entry;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.massivecraft.factions.zcore.MCommand;
import com.massivecraft.factions.zcore.MPlugin;
import com.massivecraft.factions.zcore.util.TextUtil;
public abstract class MCommand<T extends MPlugin>
{
public T p;
// The sub-commands to this command
public List<MCommand<?>> subCommands;
// The different names this commands will react to
public List<String> aliases;
public boolean allowNoSlashAccess;
// Information on the args
public List<String> requiredArgs;
public LinkedHashMap<String, String> optionalArgs;
// Help info
public String helpShort;
public List<String> helpLong;
public CommandVisibility visibility;
// Some information on permissions
public boolean senderMustBePlayer;
public String permission;
// Information available on execution of the command
public CommandSender sender; // Will always be set
public Player player; // Will only be set when the sender is a player
public List<String> args; // Will contain the arguments, or and empty list if there are none.
public List<MCommand<?>> commandChain; // The command chain used to execute this command
public MCommand(T p)
{
this.p = p;
this.permission = null;
this.allowNoSlashAccess = false;
this.subCommands = new ArrayList<MCommand<?>>();
this.aliases = new ArrayList<String>();
this.requiredArgs = new ArrayList<String>();
this.optionalArgs = new LinkedHashMap<String, String>();
this.helpShort = "*Default helpShort*";
this.helpLong = new ArrayList<String>();
this.visibility = CommandVisibility.VISIBLE;
}
// The commandChain is a list of the parent command chain used to get to this command.
public void execute(CommandSender sender, List<String> args, List<MCommand<?>> commandChain)
{
// Set the execution-time specific variables
this.sender = sender;
if (sender instanceof Player)
{
this.player = (Player)sender;
}
else
{
this.player = null;
}
this.args = args;
this.commandChain = commandChain;
// Is there a matching sub command?
if (args.size() > 0 )
{
for (MCommand<?> subCommand: this.subCommands)
{
if (subCommand.aliases.contains(args.get(0)))
{
args.remove(0);
commandChain.add(this);
subCommand.execute(sender, args, commandChain);
return;
}
}
}
if ( ! validCall(this.sender, this.args))
{
return;
}
perform();
}
public void execute(CommandSender sender, List<String> args)
{
execute(sender, args, new ArrayList<MCommand<?>>());
}
// This is where the command action is performed.
public abstract void perform();
// -------------------------------------------- //
// Call Validation
// -------------------------------------------- //
/**
* In this method we validate that all prerequisites to perform this command has been met.
*/
// TODO: There should be a boolean for silence
public boolean validCall(CommandSender sender, List<String> args)
{
if ( ! validSenderType(sender, true))
{
return false;
}
if ( ! validSenderPermissions(sender, true))
{
return false;
}
if ( ! validArgs(args, sender))
{
return false;
}
return true;
}
public boolean validSenderType(CommandSender sender, boolean informSenderIfNot)
{
if (this.senderMustBePlayer && ! (sender instanceof Player))
{
if (informSenderIfNot)
{
sender.sendMessage(p.txt.get("command.sender_must_me_player"));
}
return false;
}
return true;
}
public boolean validSenderPermissions(CommandSender sender, boolean informSenderIfNot)
{
if (this.permission == null) return true;
return p.perm.has(sender, this.permission, informSenderIfNot);
}
public boolean validArgs(List<String> args, CommandSender sender)
{
if (args.size() < this.requiredArgs.size())
{
if (sender != null)
{
sender.sendMessage(p.txt.get("command.to_few_args"));
sender.sendMessage(this.getUseageTemplate());
}
return false;
}
if (args.size() > this.requiredArgs.size() + this.optionalArgs.size())
{
if (sender != null)
{
// Get the to many string slice
List<String> theToMany = args.subList(this.requiredArgs.size() + this.optionalArgs.size(), args.size());
sender.sendMessage(String.format(p.txt.get("command.to_many_args"), TextUtil.implode(theToMany, " ")));
sender.sendMessage(this.getUseageTemplate());
}
return false;
}
return true;
}
public boolean validArgs(List<String> args)
{
return this.validArgs(args, null);
}
// -------------------------------------------- //
// Help and Usage information
// -------------------------------------------- //
public String getUseageTemplate(List<MCommand<?>> commandChain, boolean addShortHelp)
{
StringBuilder ret = new StringBuilder();
ret.append(p.txt.tags("<c>"));
ret.append('/');
for (MCommand<?> mc : commandChain)
{
ret.append(TextUtil.implode(mc.aliases, ","));
ret.append(' ');
}
ret.append(TextUtil.implode(this.aliases, ","));
List<String> args = new ArrayList<String>();
for (String requiredArg : this.requiredArgs)
{
args.add("<"+requiredArg+">");
}
for (Entry<String, String> optionalArg : this.optionalArgs.entrySet())
{
String val = optionalArg.getValue();
if (val == null)
{
val = "";
}
else
{
val = "="+val;
}
args.add("["+optionalArg.getKey()+val+"]");
}
if (args.size() > 0)
{
ret.append(p.txt.tags("<p> "));
ret.append(TextUtil.implode(args, " "));
}
if (addShortHelp)
{
ret.append(p.txt.tags(" <i>"));
ret.append(this.helpShort);
}
return ret.toString();
}
public String getUseageTemplate(boolean addShortHelp)
{
return getUseageTemplate(this.commandChain, addShortHelp);
}
public String getUseageTemplate()
{
return getUseageTemplate(false);
}
// -------------------------------------------- //
// Message Sending Helpers
// -------------------------------------------- //
public void msg(String msg, boolean parseColors)
{
if (parseColors)
{
sender.sendMessage(p.txt.tags(msg));
return;
}
sender.sendMessage(msg);
}
public void msg(String msg)
{
this.msg(msg, false);
}
public void msg(List<String> msgs, boolean parseColors)
{
for(String msg : msgs)
{
this.msg(msg, parseColors);
}
}
public void msg(List<String> msgs)
{
msg(msgs, false);
}
// -------------------------------------------- //
// Argument Readers
// -------------------------------------------- //
// STRING
public String argAsString(int idx, String def)
{
if (this.args.size() < idx+1)
{
return def;
}
return this.args.get(idx);
}
public String argAsString(int idx)
{
return this.argAsString(idx, null);
}
// INT
public int argAsInt(int idx, int def)
{
String str = this.argAsString(idx);
if (str == null) return def;
try
{
int ret = Integer.parseInt(str);
return ret;
}
catch (Exception e)
{
return def;
}
}
public int argAsInt(int idx)
{
return this.argAsInt(idx, -1);
}
// Double
public double argAsDouble(int idx, double def)
{
String str = this.argAsString(idx);
if (str == null) return def;
try
{
double ret = Double.parseDouble(str);
return ret;
}
catch (Exception e)
{
return def;
}
}
public double argAsDouble(int idx)
{
return this.argAsDouble(idx, -1d);
}
// Boolean
public boolean argAsBool(int idx, boolean def)
{
String str = this.argAsString(idx);
if (str == null) return def;
str = str.toLowerCase();
if (str.startsWith("y") || str.startsWith("t") || str.startsWith("on") || str.startsWith("+") || str.startsWith("1"))
{
return true;
}
return false;
}
public boolean argAsBool(int idx)
{
return this.argAsBool(idx, false);
}
// PLAYER
public Player argAsPlayer(int idx, Player def, boolean msg)
{
Player ret = def;
String name = this.argAsString(idx);
if (name != null)
{
Player player = Bukkit.getServer().getPlayer(name);
if (player != null)
{
ret = player;
}
}
if (msg && ret == null)
{
// TODO: Fix this injection risk!
this.msg(p.txt.tags("<b>The player \"<p>"+name+"<b>\" could not be found."));
}
return ret;
}
public Player argAsPlayer(int idx, Player def)
{
return this.argAsPlayer(idx, def, true);
}
public Player argAsPlayer(int idx)
{
return this.argAsPlayer(idx, null);
}
// BEST PLAYER MATCH
public Player argAsBestPlayerMatch(int idx, Player def, boolean msg)
{
Player ret = def;
String name = this.argAsString(idx);
if (name != null)
{
List<Player> players = Bukkit.getServer().matchPlayer(name);
if (players.size() > 0)
{
ret = players.get(0);
}
}
if (msg && ret == null)
{
// TODO: Fix this injection risk!
this.msg(p.txt.tags("<b>No player match found for \"<p>"+name+"<b>\"."));
}
return ret;
}
public Player argAsBestPlayerMatch(int idx, Player def)
{
return this.argAsBestPlayerMatch(idx, def, true);
}
public Player argAsBestPlayerMatch(int idx)
{
return this.argAsPlayer(idx, null);
}
}

View File

@ -0,0 +1,236 @@
package com.massivecraft.factions.zcore;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.event.Event;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.massivecraft.factions.zcore.persist.EM;
import com.massivecraft.factions.zcore.persist.SaveTask;
import com.massivecraft.factions.zcore.util.LibLoader;
import com.massivecraft.factions.zcore.util.PermUtil;
import com.massivecraft.factions.zcore.util.Persist;
import com.massivecraft.factions.zcore.util.TextUtil;
public abstract class MPlugin extends JavaPlugin
{
// Some utils
public Persist persist;
public TextUtil txt;
public LibLoader lib;
public PermUtil perm;
// Persist related
public Gson gson;
private Integer saveTask = null;
// Listeners
private MPluginSecretPlayerListener mPluginSecretPlayerListener;
private MPluginSecretServerListener mPluginSecretServerListener;
// Our stored base commands
private List<MCommand<?>> baseCommands = new ArrayList<MCommand<?>>();
public List<MCommand<?>> getBaseCommands() { return this.baseCommands; }
// -------------------------------------------- //
// ENABLE
// -------------------------------------------- //
private long timeEnableStart;
public boolean preEnable()
{
log("=== ENABLE START ===");
timeEnableStart = System.currentTimeMillis();
// Ensure basefolder exists!
this.getDataFolder().mkdirs();
// Create Utility Instances
this.perm = new PermUtil(this);
this.persist = new Persist(this);
this.lib = new LibLoader(this);
if ( ! lib.require("gson.jar", "http://search.maven.org/remotecontent?filepath=com/google/code/gson/gson/1.7.1/gson-1.7.1.jar")) return false;
this.gson = this.getGsonBuilder().create();
initTXT();
// Create and register listeners
this.mPluginSecretPlayerListener = new MPluginSecretPlayerListener(this);
this.mPluginSecretServerListener = new MPluginSecretServerListener(this);
PluginManager pm = this.getServer().getPluginManager();
pm.registerEvent(Event.Type.PLAYER_PRELOGIN, this.mPluginSecretPlayerListener, Event.Priority.Lowest, this);
pm.registerEvent(Event.Type.PLAYER_CHAT, this.mPluginSecretPlayerListener, Event.Priority.Low, this);
pm.registerEvent(Event.Type.PLAYER_COMMAND_PREPROCESS, this.mPluginSecretPlayerListener, Event.Priority.Lowest, this);
pm.registerEvent(Event.Type.SERVER_COMMAND, this.mPluginSecretServerListener, Event.Priority.Lowest, this);
// Register recurring tasks
long saveTicks = 20 * 60 * 30; // Approximately every 30 min
if (saveTask == null)
{
saveTask = Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(this, new SaveTask(), saveTicks, saveTicks);
}
return true;
}
public void postEnable()
{
log("=== ENABLE DONE (Took "+(System.currentTimeMillis()-timeEnableStart)+"ms) ===");
}
public void onDisable()
{
if (saveTask != null)
{
this.getServer().getScheduler().cancelTask(saveTask);
saveTask = null;
}
EM.saveAllToDisc();
log("Disabled");
}
public void suicide()
{
log("Now I suicide!");
this.getServer().getPluginManager().disablePlugin(this);
}
// -------------------------------------------- //
// Some inits...
// You are supposed to override these in the plugin if you aren't satisfied with the defaults
// The goal is that you always will be satisfied though.
// -------------------------------------------- //
public GsonBuilder getGsonBuilder()
{
return new GsonBuilder()
.setPrettyPrinting()
.disableHtmlEscaping()
.serializeNulls()
.excludeFieldsWithModifiers(Modifier.TRANSIENT, Modifier.VOLATILE);
}
// -------------------------------------------- //
// LANG AND TAGS
// -------------------------------------------- //
// These are not supposed to be used directly.
// They are loaded and used through the TextUtil instance for the plugin.
public Map<String, String> tags = new LinkedHashMap<String, String>();
public Map<String, String> lang = new LinkedHashMap<String, String>();
public void addLang()
{
this.lang.put("perm.forbidden", "<b>You don't have permission to %s.");
this.lang.put("perm.dothat", "do that");
this.lang.put("command.sender_must_me_player", "<b>This command can only be used by ingame players.");
this.lang.put("command.to_few_args", "<b>To few arguments. <i>Use like this:");
this.lang.put("command.to_many_args", "<b>Strange argument \"<p>%s<b>\". <i>Use the command like this:");
}
public void addTags()
{
this.tags.put("black", "§0");
this.tags.put("navy", "§1");
this.tags.put("green", "§2");
this.tags.put("teal", "§3");
this.tags.put("red", "§4");
this.tags.put("purple", "§5");
this.tags.put("gold", "§6");
this.tags.put("silver", "§7");
this.tags.put("gray", "§8");
this.tags.put("blue", "§9");
this.tags.put("white", "§f");
this.tags.put("lime", "§a");
this.tags.put("aqua", "§b");
this.tags.put("rose", "§c");
this.tags.put("pink", "§d");
this.tags.put("yellow", "§e");
this.tags.put("l", "§2"); // logo
this.tags.put("a", "§6"); // art
this.tags.put("n", "§7"); // notice
this.tags.put("i", "§e"); // info
this.tags.put("g", "§a"); // good
this.tags.put("b", "§c"); // bad
this.tags.put("h", "§d"); // highligh
this.tags.put("c", "§b"); // command
this.tags.put("p", "§3"); // parameter
}
public void initTXT()
{
this.addLang();
this.addTags();
Type type = new TypeToken<Map<String, String>>(){}.getType();
Map<String, String> langFromFile = this.persist.load(type, "lang");
if (langFromFile != null) this.lang.putAll(langFromFile);
this.persist.save(this.lang, "lang");
Map<String, String> tagsFromFile = this.persist.load(type, "tags");
if (tagsFromFile != null) this.tags.putAll(tagsFromFile);
this.persist.save(this.tags, "tags");
this.txt = new TextUtil(this.tags, this.lang);
}
// -------------------------------------------- //
// COMMAND HANDLING
// -------------------------------------------- //
public boolean handleCommand(CommandSender sender, String commandString)
{
boolean noSlash = false;
if (commandString.startsWith("/"))
{
noSlash = true;
commandString = commandString.substring(1);
}
for (MCommand<?> command : this.getBaseCommands())
{
if (noSlash && ! command.allowNoSlashAccess) continue;
for (String alias : command.aliases)
{
if (commandString.startsWith(alias) || commandString.equals(alias+" "))
{
List<String> args = new ArrayList<String>(Arrays.asList(commandString.split("\\s+")));
args.remove(0);
command.execute(sender, args);
return true;
}
}
}
return false;
}
// -------------------------------------------- //
// LOGGING
// -------------------------------------------- //
public void log(Object msg)
{
log(Level.INFO, msg);
}
public void log(Level level, Object msg)
{
Logger.getLogger("Minecraft").log(level, "["+this.getDescription().getFullName()+"] "+msg);
}
}

View File

@ -0,0 +1,55 @@
package com.massivecraft.factions.zcore;
import org.bukkit.event.player.PlayerChatEvent;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.player.PlayerListener;
import org.bukkit.event.player.PlayerPreLoginEvent;
import com.massivecraft.factions.zcore.persist.EM;
import com.massivecraft.factions.zcore.persist.Entity;
import com.massivecraft.factions.zcore.persist.EntityCollection;
import com.massivecraft.factions.zcore.persist.PlayerEntityCollection;
public class MPluginSecretPlayerListener extends PlayerListener
{
private MPlugin p;
public MPluginSecretPlayerListener(MPlugin p)
{
this.p = p;
}
@Override
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event)
{
if (event.isCancelled()) return;
if (p.handleCommand(event.getPlayer(), event.getMessage()))
{
event.setCancelled(true);
}
}
@Override
public void onPlayerChat(PlayerChatEvent event)
{
if (event.isCancelled()) return;
if (p.handleCommand(event.getPlayer(), event.getMessage()))
{
event.setCancelled(true);
}
}
@Override
public void onPlayerPreLogin(PlayerPreLoginEvent event)
{
for (EntityCollection<? extends Entity> ecoll : EM.class2Entities.values())
{
if (ecoll instanceof PlayerEntityCollection)
{
ecoll.get(event.getName());
}
}
}
}

View File

@ -0,0 +1,26 @@
package com.massivecraft.factions.zcore;
import org.bukkit.event.server.ServerCommandEvent;
import org.bukkit.event.server.ServerListener;
public class MPluginSecretServerListener extends ServerListener
{
private MPlugin p;
public MPluginSecretServerListener(MPlugin p)
{
this.p = p;
}
// This method is not perfect. It says unknown console command.
@Override
public void onServerCommand(ServerCommandEvent event)
{
if (event.getCommand().length() == 0) return;
if (p.handleCommand(event.getSender(), event.getCommand()))
{
event.setCommand("");
}
}
}

View File

@ -0,0 +1,74 @@
package com.massivecraft.factions.zcore.persist;
import java.util.*;
import com.massivecraft.factions.zcore.persist.Entity;
import com.massivecraft.factions.zcore.persist.EntityCollection;
public class EM
{
public static Map<Class<? extends Entity>, EntityCollection<? extends Entity>> class2Entities = new LinkedHashMap<Class<? extends Entity>, EntityCollection<? extends Entity>>();
@SuppressWarnings("unchecked")
public static <T extends Entity> EntityCollection<T> getEntitiesCollectionForEntityClass(Class<T> entityClass)
{
return (EntityCollection<T>) class2Entities.get(entityClass);
}
public static void setEntitiesCollectionForEntityClass(Class<? extends Entity> entityClass, EntityCollection<? extends Entity> entities)
{
class2Entities.put(entityClass, entities);
}
// -------------------------------------------- //
// ATTACH AND DETACH
// -------------------------------------------- //
@SuppressWarnings("unchecked")
public static <T extends Entity> void attach(T entity)
{
EntityCollection<T> ec = (EntityCollection<T>) getEntitiesCollectionForEntityClass(entity.getClass());
ec.attach(entity);
}
@SuppressWarnings("unchecked")
public static <T extends Entity> void detach(T entity)
{
EntityCollection<T> ec = (EntityCollection<T>) getEntitiesCollectionForEntityClass(entity.getClass());
ec.detach(entity);
}
@SuppressWarnings("unchecked")
public static <T extends Entity> boolean attached(T entity)
{
EntityCollection<T> ec = (EntityCollection<T>) getEntitiesCollectionForEntityClass(entity.getClass());
return ec.attached(entity);
}
@SuppressWarnings("unchecked")
public static <T extends Entity> boolean detached(T entity)
{
EntityCollection<T> ec = (EntityCollection<T>) getEntitiesCollectionForEntityClass(entity.getClass());
return ec.detached(entity);
}
// -------------------------------------------- //
// DISC
// -------------------------------------------- //
public static void saveAllToDisc()
{
for (EntityCollection<? extends Entity> ec : class2Entities.values())
{
ec.saveToDisc();
}
}
public static void loadAllFromDisc()
{
for (EntityCollection<? extends Entity> ec : class2Entities.values())
{
ec.loadFromDisc();
}
}
}

View File

@ -0,0 +1,65 @@
package com.massivecraft.factions.zcore.persist;
public abstract class Entity
{
public Entity()
{
}
protected transient String id = null;
public String getId()
{
return id;
}
protected void setId(String id)
{
this.id = id;
}
public boolean shouldBeSaved()
{
return true;
}
// -------------------------------------------- //
// ATTACH AND DETACH
// -------------------------------------------- //
public void attach()
{
EM.attach(this);
}
public void detach()
{
EM.detach(this);
}
public boolean attached()
{
return EM.attached(this);
}
public boolean detached()
{
return EM.detached(this);
}
// -------------------------------------------- //
// EVENTS
// -------------------------------------------- //
public void preDetach()
{
}
public void postDetach()
{
}
}

View File

@ -0,0 +1,250 @@
package com.massivecraft.factions.zcore.persist;
import java.io.File;
import java.lang.reflect.Type;
import java.util.*;
import java.util.Map.Entry;
import com.google.gson.Gson;
import com.massivecraft.factions.zcore.util.DiscUtil;
public abstract class EntityCollection<E extends Entity>
{
// -------------------------------------------- //
// FIELDS
// -------------------------------------------- //
// These must be instantiated in order to allow for different configuration (orders, comparators etc)
private Collection<E> entities;
private Map<String, E> id2entity;
// If the entities are creative they will create a new instance if a non existent id was requested
private boolean creative;
public boolean isCreative() { return creative; }
public void setCreative(boolean creative) { this.creative = creative; }
// This is the auto increment for the primary key "id"
private int nextId;
// This ugly crap is necessary due to java type erasure
private Class<E> entityClass;
public abstract Type getMapType(); // This is special stuff for GSON.
// Info on how to persist
private Gson gson;
public Gson getGson() { return gson; }
public void setGson(Gson gson) { this.gson = gson; }
private File file;
public File getFile() { return file; }
public void setFile(File file) { this.file = file; }
// -------------------------------------------- //
// CONSTRUCTORS
// -------------------------------------------- //
public EntityCollection(Class<E> entityClass, Collection<E> entities, Map<String, E> id2entity, File file, Gson gson, boolean creative)
{
this.entityClass = entityClass;
this.entities = entities;
this.id2entity = id2entity;
this.file = file;
this.gson = gson;
this.creative = creative;
this.nextId = 1;
EM.setEntitiesCollectionForEntityClass(this.entityClass, this);
}
public EntityCollection(Class<E> entityClass, Collection<E> entities, Map<String, E> id2entity, File file, Gson gson)
{
this(entityClass, entities, id2entity, file, gson, false);
}
// -------------------------------------------- //
// GET
// -------------------------------------------- //
public Collection<E> get()
{
return entities;
}
public Map<String, E> getMap()
{
return this.id2entity;
}
public E get(String id)
{
if (this.creative) return this.getCreative(id);
return id2entity.get(id);
}
public E getCreative(String id)
{
E e = id2entity.get(id);
if (e != null) return e;
return this.create(id);
}
public boolean exists(String id)
{
return id2entity.get(id) != null;
}
// -------------------------------------------- //
// CREATE
// -------------------------------------------- //
public E create()
{
return this.create(this.getNextId());
}
public E create(String id)
{
if ( ! this.isIdFree(id)) return null;
E e = null;
try
{
e = this.entityClass.newInstance();
} catch (Exception ignored) {}
e.setId(id);
this.entities.add(e);
this.id2entity.put(e.getId(), e);
this.updateNextIdForId(id);
return e;
}
// -------------------------------------------- //
// ATTACH AND DETACH
// -------------------------------------------- //
public void attach(E entity)
{
if (entity.getId() != null) return;
entity.setId(this.getNextId());
this.entities.add(entity);
this.id2entity.put(entity.getId(), entity);
}
public void detach(E entity)
{
entity.preDetach();
this.entities.remove(entity);
this.id2entity.remove(entity.getId());
entity.postDetach();
}
public void detach(String id)
{
E entity = this.id2entity.get(id);
if (entity == null) return;
this.detach(entity);
}
public boolean attached(E entity)
{
return this.entities.contains(entity);
}
public boolean detached(E entity)
{
return ! this.attached(entity);
}
// -------------------------------------------- //
// DISC
// -------------------------------------------- //
public boolean saveToDisc()
{
Map<String, E> entitiesThatShouldBeSaved = new HashMap<String, E>();
for (E entity : this.entities)
{
if (entity.shouldBeSaved())
{
entitiesThatShouldBeSaved.put(entity.getId(), entity);
}
}
return this.saveCore(entitiesThatShouldBeSaved);
}
private boolean saveCore(Map<String, E> entities)
{
return DiscUtil.writeCatch(this.file, this.gson.toJson(entities));
}
public boolean loadFromDisc()
{
Map<String, E> id2entity = this.loadCore();
if (id2entity == null) return false;
this.entities.clear();
this.entities.addAll(id2entity.values());
this.id2entity.clear();
this.id2entity.putAll(id2entity);
this.fillIds();
return true;
}
private Map<String, E> loadCore()
{
if ( ! this.file.exists())
{
return new HashMap<String, E>();
}
String content = DiscUtil.readCatch(this.file);
if (content == null)
{
return null;
}
Type type = this.getMapType();
return this.gson.fromJson(content, type);
}
// -------------------------------------------- //
// ID MANAGEMENT
// -------------------------------------------- //
public String getNextId()
{
this.nextId += 1;
return "" + (nextId - 1);
}
public boolean isIdFree(String id)
{
return ! this.id2entity.containsKey(id);
}
protected void fillIds()
{
this.nextId = 1;
for(Entry<String, E> entry : this.id2entity.entrySet())
{
String id = entry.getKey();
E entity = entry.getValue();
entity.id = id;
this.updateNextIdForId(id);
}
}
protected void updateNextIdForId(String id)
{
try
{
int idAsInt = Integer.parseInt(id);
if (this.nextId < idAsInt)
{
this.nextId = idAsInt + 1;
}
} catch (Exception ignored) {}
}
}

View File

@ -0,0 +1,44 @@
package com.massivecraft.factions.zcore.persist;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
public class PlayerEntity extends Entity
{
public Player getPlayer()
{
return Bukkit.getPlayer(this.getId());
}
public boolean isOnline()
{
return this.getPlayer() != null;
}
public boolean isOffline()
{
return ! isOnline();
}
// -------------------------------------------- //
// Message Sending Helpers
// -------------------------------------------- //
public void sendMessage(String msg)
{
Player player = this.getPlayer();
if (player == null) return;
player.sendMessage(msg);
}
public void sendMessage(List<String> msgs)
{
for(String msg : msgs)
{
this.sendMessage(msg);
}
}
}

View File

@ -0,0 +1,46 @@
package com.massivecraft.factions.zcore.persist;
import java.io.File;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import com.google.gson.Gson;
/**
* The PlayerEntityCollection is an EntityCollection with the extra features
* a player skin usually requires.
*
* This entity collection is not only creative. It even creates the instance for the player
* when the player logs in to the server.
*
* This way we can be sure that PlayerEntityCollection.get() will contain
* all entities in PlayerEntityCollection.getOnline()
*/
public abstract class PlayerEntityCollection<E extends Entity> extends EntityCollection<E>
{
public PlayerEntityCollection(Class<E> entityClass, Collection<E> entities, Map<String, E> id2entity, File file, Gson gson)
{
super(entityClass, entities, id2entity, file, gson, true);
}
public E get(Player player)
{
return this.get(player.getName());
}
public Set<E> getOnline()
{
Set<E> entities = new HashSet<E>();
for (Player player : Bukkit.getServer().getOnlinePlayers())
{
entities.add(this.get(player));
}
return entities;
}
}

View File

@ -0,0 +1,9 @@
package com.massivecraft.factions.zcore.persist;
public class SaveTask implements Runnable
{
public void run()
{
EM.saveAllToDisc();
}
}

View File

@ -0,0 +1,51 @@
package com.massivecraft.factions.zcore.util;
import java.io.File;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
public class ClassLoadHack {
private static URLClassLoader sysloader = (URLClassLoader)ClassLoader.getSystemClassLoader();
public static boolean load(String filename)
{
return load(new File(filename));
}
public static boolean load(File file)
{
try
{
return load(file.toURI().toURL());
}
catch (MalformedURLException e)
{
return false;
}
}
public static boolean load(URL url)
{
// If the file already is loaded we can skip it
for (URL otherUrl : sysloader.getURLs())
{
if (otherUrl.sameFile(url)) return true;
}
try
{
Method addURLMethod = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{ URL.class });
addURLMethod.setAccessible(true);
addURLMethod.invoke(sysloader, new Object[]{ url });
return true;
}
catch (Exception e)
{
return false;
}
}
}

View File

@ -0,0 +1,78 @@
package com.massivecraft.factions.zcore.util;
import java.io.*;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
public class DiscUtil
{
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 boolean downloadUrl(String urlstring, File file)
{
try
{
URL url = new URL(urlstring);
ReadableByteChannel rbc = Channels.newChannel(url.openStream());
FileOutputStream fos = new FileOutputStream(file);
fos.getChannel().transferFrom(rbc, 0, 1 << 24);
return true;
}
catch (Exception e)
{
e.printStackTrace();
return false;
}
}
public static boolean downloadUrl(String urlstring, String filename)
{
return downloadUrl(urlstring, new File(filename));
}
}

View File

@ -0,0 +1,50 @@
package com.massivecraft.factions.zcore.util;
import java.io.File;
import com.massivecraft.factions.zcore.MPlugin;
public class LibLoader
{
MPlugin p;
public LibLoader(MPlugin p)
{
this.p = p;
new File("./lib").mkdirs();
}
public boolean require(String filename, String url)
{
if ( ! include(filename, url))
{
p.log("Failed to load the required library "+filename);
p.suicide();
return false;
}
return true;
}
public boolean include (String filename, String url)
{
File file = getFile(filename);
if ( ! file.exists())
{
p.log("Downloading library "+filename);
if ( ! DiscUtil.downloadUrl(url, file))
{
p.log("Failed to download "+filename);
return false;
}
}
return ClassLoadHack.load(file);
}
private static File getFile(String filename)
{
return new File("./lib/"+filename);
}
}

View File

@ -0,0 +1,128 @@
package com.massivecraft.factions.zcore.util;
import java.util.*;
import java.util.Map.Entry;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permission;
import org.bukkit.plugin.Plugin;
import ru.tehkode.permissions.PermissionManager;
import ru.tehkode.permissions.bukkit.PermissionsEx;
import com.massivecraft.factions.zcore.MPlugin;
import com.nijiko.permissions.PermissionHandler;
import com.nijikokun.bukkit.Permissions.Permissions;
public class PermUtil {
public PermissionManager pex = null;
public PermissionHandler perm2or3 = null;
public Map<String, String> permissionDescriptions = new HashMap<String, String>();
protected MPlugin p;
public PermUtil(MPlugin p)
{
this.p = p;
this.setup();
}
public String getForbiddenMessage(String perm)
{
return p.txt.get("perm.forbidden", getPermissionDescription(perm));
}
/**
* This method hooks into all permission plugins we are supporting
*/
public void setup()
{
for(Permission permission : p.getDescription().getPermissions())
{
this.permissionDescriptions.put(permission.getName(), permission.getDescription());
}
if ( Bukkit.getServer().getPluginManager().isPluginEnabled("PermissionsEx"))
{
pex = PermissionsEx.getPermissionManager();
p.log("Will use this plugin for permissions: " + Bukkit.getServer().getPluginManager().getPlugin("PermissionsEx").getDescription().getFullName());
return;
}
if ( Bukkit.getServer().getPluginManager().isPluginEnabled("Permissions"))
{
Plugin permissionsPlugin = Bukkit.getServer().getPluginManager().getPlugin("Permissions");
perm2or3 = ((Permissions) permissionsPlugin).getHandler();
p.log("Will use this plugin for permissions: " + permissionsPlugin.getDescription().getFullName());
return;
}
p.log("No permission plugin detected. Defaulting to native bukkit permissions.");
}
public String getPermissionDescription (String perm)
{
String desc = permissionDescriptions.get(perm);
if (desc == null)
{
return p.txt.get("perm.dothat");
}
return desc;
}
/**
* This method tests if me has a certain permission and returns
* true if me has. Otherwise false
*/
public boolean has (CommandSender me, String perm)
{
if ( ! (me instanceof Player))
{
return me.hasPermission(perm);
}
if (pex != null)
{
return pex.has((Player)me, perm);
}
if (perm2or3 != null)
{
return perm2or3.has((Player)me, perm);
}
return me.hasPermission(perm);
}
public boolean has (CommandSender me, String perm, boolean informSenderIfNot)
{
if (has(me, perm))
{
return true;
}
else if (informSenderIfNot)
{
me.sendMessage(this.getForbiddenMessage(perm));
}
return false;
}
public <T> T pickFirstVal(CommandSender me, Map<String, T> perm2val)
{
if (perm2val == null) return null;
T ret = null;
for ( Entry<String, T> entry : perm2val.entrySet())
{
ret = entry.getValue();
if (has(me, entry.getKey())) break;
}
return ret;
}
}

View File

@ -0,0 +1,154 @@
package com.massivecraft.factions.zcore.util;
import java.io.File;
import java.lang.reflect.Type;
import java.util.logging.Level;
import com.massivecraft.factions.zcore.MPlugin;
// TODO: Give better name and place to differenciate from the entity-orm-ish system in "com.massivecraft.core.persist".
public class Persist {
private MPlugin p;
public Persist(MPlugin p)
{
this.p = p;
}
// ------------------------------------------------------------ //
// GET NAME - What should we call this type of object?
// ------------------------------------------------------------ //
public static String getName(Class<?> clazz)
{
return clazz.getSimpleName().toLowerCase();
}
public static String getName(Object o)
{
return getName(o.getClass());
}
public static String getName(Type type)
{
return getName(type.getClass());
}
// ------------------------------------------------------------ //
// GET FILE - In which file would we like to store this object?
// ------------------------------------------------------------ //
public File getFile(String name)
{
return new File(p.getDataFolder(), name+".json");
}
public File getFile(Class<?> clazz)
{
return getFile(getName(clazz));
}
public File getFile(Object obj)
{
return getFile(getName(obj));
}
public File getFile(Type type)
{
return getFile(getName(type));
}
// NICE WRAPPERS
public <T> T loadOrSaveDefault(T def, Class<T> clazz)
{
return loadOrSaveDefault(def, clazz, getFile(clazz));
}
public <T> T loadOrSaveDefault(T def, Class<T> clazz, String name)
{
return loadOrSaveDefault(def, clazz, getFile(name));
}
public <T> T loadOrSaveDefault(T def, Class<T> clazz, File file)
{
if ( ! file.exists())
{
p.log("Creating default: "+file);
this.save(def, file);
return def;
}
T loaded = this.load(clazz, file);
if (loaded == null)
{
p.log(Level.WARNING, "Using default as I failed to load: "+file);
return def;
}
return loaded;
}
// SAVE
public boolean save(Object instance)
{
return save(instance, getFile(instance));
}
public boolean save(Object instance, String name)
{
return save(instance, getFile(name));
}
public boolean save(Object instance, File file)
{
return DiscUtil.writeCatch(file, p.gson.toJson(instance));
}
// LOAD BY CLASS
public <T> T load(Class<T> clazz)
{
return load(clazz, getFile(clazz));
}
public <T> T load(Class<T> clazz, String name)
{
return load(clazz, getFile(name));
}
public <T> T load(Class<T> clazz, File file)
{
String content = DiscUtil.readCatch(file);
if (content == null)
{
return null;
}
T instance = p.gson.fromJson(content, clazz);
return instance;
}
// LOAD BY TYPE
public <T> T load(Type typeOfT, String name)
{
return load(typeOfT, getFile(name));
}
public <T> T load(Type typeOfT, File file)
{
String content = DiscUtil.readCatch(file);
if (content == null) {
return null;
}
return p.gson.fromJson(content, typeOfT);
}
}

View File

@ -0,0 +1,245 @@
package com.massivecraft.factions.zcore.util;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.bukkit.ChatColor;
import org.bukkit.Material;
public class TextUtil
{
private Map<String, String> tags = new HashMap<String, String>();
private Map<String, String> lang = new HashMap<String, String>();
public TextUtil(Map<String, String> tags, Map<String, String> lang)
{
if (tags != null)
{
this.tags.putAll(tags);
}
if (lang != null)
{
this.lang.putAll(lang);
}
}
// Get is supposed to be the way we reach registered lang
// TODO: Is the parse
public String get(String name)
{
String str = lang.get(name);
if (str == null) str = name;
return this.parse(str);
}
public String get(String name, Object... args)
{
String str = lang.get(name);
if (str == null) str = name;
return this.parse(str, args);
}
// Parse is used to handle non registered text
public String parse(String str, Object... args)
{
return String.format(this.tags(str), args);
}
public String parse(String str)
{
return this.tags(str);
}
public Map<String, String> getTags()
{
return tags;
}
public Map<String, String> getLang()
{
return lang;
}
public String tags(String str)
{
return replaceTags(str, this.tags);
}
public static final transient Pattern patternTag = Pattern.compile("<([^<>]*)>");
public static String replaceTags(String str, Map<String, String> 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();
}
public static String implode(List<String> list, String glue)
{
StringBuilder ret = new StringBuilder();
for (int i=0; i<list.size(); i++)
{
if (i!=0)
{
ret.append(glue);
}
ret.append(list.get(i));
}
return ret.toString();
}
public static String repeat(String s, int times)
{
if (times <= 0) return "";
else return s + repeat(s, times-1);
}
public static String getMaterialName(Material material)
{
return material.toString().replace('_', ' ').toLowerCase();
}
public static String getMaterialName(int materialId)
{
return getMaterialName(Material.getMaterial(materialId));
}
public static String upperCaseFirst(String string)
{
return string.substring(0, 1).toUpperCase()+string.substring(1);
}
// TODO: Make part of layout configuration.
private final static String titleizeLine = repeat("_", 52);
private final static int titleizeBalance = -1;
public String titleize(String str)
{
String center = ".[ "+ tags("<l>") + str + tags("<a>")+ " ].";
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 tags("<a>")+titleizeLine.substring(0, pivot - eatLeft) + center + titleizeLine.substring(pivot + eatRight);
else
return tags("<a>")+center;
}
public ArrayList<String> getPage(List<String> lines, int pageHumanBased, String title)
{
ArrayList<String> ret = new ArrayList<String>();
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.tags("<i>Sorry. No Pages available."));
return ret;
}
else if (pageZeroBased < 0 || pageHumanBased > pagecount)
{
ret.add(this.tags("<i>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;
}
/**
* 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 String getTimeDeltaDescriptionRelNow(long millis)
{
double absmillis = (double) Math.abs(millis);
String agofromnow = "from now";
String unit;
long num;
if (millis <= 0)
{
agofromnow = "ago";
}
// We use a factor 3 below for a reason... why do you think?
// Answer: it is a way to make our round of error smaller.
if (absmillis < 3 * millisPerSecond)
{
unit = "milliseconds";
num = (long) (absmillis);
}
else if (absmillis < 3 * millisPerMinute)
{
unit = "seconds";
num = (long) (absmillis / millisPerSecond);
}
else if (absmillis < 3 * millisPerHour)
{
unit = "minutes";
num = (long) (absmillis / millisPerMinute);
}
else if (absmillis < 3 * millisPerDay)
{
unit = "hours";
num = (long) (absmillis / millisPerHour);
}
else if (absmillis < 3 * millisPerWeek)
{
unit = "days";
num = (long) (absmillis / millisPerDay);
}
else if (absmillis < 3 * millisPerMonth)
{
unit = "weeks";
num = (long) (absmillis / millisPerWeek);
}
else if (absmillis < 3 * millisPerYear)
{
unit = "months";
num = (long) (absmillis / millisPerMonth);
}
else
{
unit = "years";
num = (long) (absmillis / millisPerYear);
}
return ""+num+" "+unit+" "+agofromnow;
}
}

View File

@ -0,0 +1,39 @@
package com.massivecraft.factions.zcore.util;
import java.io.File;
import org.bukkit.Bukkit;
public class WorldUtil
{
// Previously We had crappy support for multiworld management.
// This should however be handled by an external plugin!
/*public static boolean load(String name) {
if (isWorldLoaded(name)) {
return true;
}
if ( ! doesWorldExist(name)) {
return false;
}
Environment env = WorldEnv.get(name);
if (env == null) {
P.log(Level.WARNING, "Failed to load world. Environment was unknown.");
return false;
}
P.p.getServer().createWorld(name, env);
return true;
}*/
public static boolean isWorldLoaded(String name)
{
return Bukkit.getServer().getWorld(name) != null;
}
public static boolean doesWorldExist(String name)
{
return new File(name, "level.dat").exists();
}
}