package me.asofold.bpl.simplyvanish;
import java.io.File;
import java.util.HashSet;
import java.util.Set;
import me.asofold.bpl.simplyvanish.api.events.GetVanishConfigEvent;
import me.asofold.bpl.simplyvanish.api.hooks.Hook;
import me.asofold.bpl.simplyvanish.command.SimplyVanishCommand;
import me.asofold.bpl.simplyvanish.config.Path;
import me.asofold.bpl.simplyvanish.config.Settings;
import me.asofold.bpl.simplyvanish.config.VanishConfig;
import me.asofold.bpl.simplyvanish.config.compatlayer.CompatConfig;
import me.asofold.bpl.simplyvanish.config.compatlayer.CompatConfigFactory;
import me.asofold.bpl.simplyvanish.listeners.AttackListener;
import me.asofold.bpl.simplyvanish.listeners.ChatListener;
import me.asofold.bpl.simplyvanish.listeners.CoreListener;
import me.asofold.bpl.simplyvanish.listeners.DamageListener;
import me.asofold.bpl.simplyvanish.listeners.DropListener;
import me.asofold.bpl.simplyvanish.listeners.InteractListener;
import me.asofold.bpl.simplyvanish.listeners.PickupListener;
import me.asofold.bpl.simplyvanish.listeners.TargetListener;
import me.asofold.bpl.simplyvanish.stats.Stats;
import me.asofold.bpl.simplyvanish.util.Utils;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Server;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitScheduler;
/**
* Example plugin for the vanish API as of CB 1914 !
* Vanish + God mode + No Target + No pickup.
* @author mc_dev
*
*/
public class SimplyVanish extends JavaPlugin {
static final SimplyVanishCore core = new SimplyVanishCore();
public static final String cmdNoOpArg = "??NOOP??";
public static final String cmdNoOp = "simplyvanish "+cmdNoOpArg;
public static final String msgLabel = ChatColor.GOLD+"[SimplyVanish]"+ChatColor.GRAY+" ";
public static final String msgStillInvisible = SimplyVanish.msgLabel+ChatColor.GRAY+"You are still "+ChatColor.GREEN+"invisible"+ChatColor.GRAY+" to normal players.";
public static final String msgNowInvisible = SimplyVanish.msgLabel+ChatColor.GRAY+"You are now "+ChatColor.GREEN+"invisible"+ChatColor.GRAY+" to normal players.";
public static final String msgNotifyPing = SimplyVanish.msgLabel+ChatColor.GRAY+"You are "+ChatColor.GREEN+"invisible"+ChatColor.GRAY+", right now.";
public static final String msgDefaultFlags = SimplyVanish.msgLabel+ChatColor.GRAY+"Flags are at default values.";
public static final Stats stats = new Stats(msgLabel.trim()+"[STATS]");
public static final Integer statsUpdateVanishState = stats.getNewId("UpdateVanishState");
public static final Integer statsVanish= stats.getNewId("Vanish");
public static final Integer statsReappear= stats.getNewId("Reappear");
public static final Integer statsSetFlags = stats.getNewId("SetFlags");
public static final Integer statsSave = stats.getNewId("SaveData");;
static{
stats.setLogStats(false);
}
SimplyVanishCommand cmdExe;
/**
* Constructor: set some defualt configuration values.
*/
public SimplyVanish(){
cmdExe = new SimplyVanishCommand(core);
}
@Override
public void onLoad() {
try{
// core.getHookUtil().addOnLoadHook(new ProtocolLibHook(this));
}
catch (Throwable t){
// Utils.warn(t);
}
}
@Override
public void onDisable() {
if (core.getSettings().saveVanished) core.doSaveVanished();
core.setEnabled(false);
core.setPlugin(null);
// TODO: maybe let all players see each other again?
System.out.println("[SimplyVanish] Disabled.");
}
@Override
public void onEnable() {
core.setPlugin(this);
core.setVanishedFile(new File(getDataFolder(), "vanished.dat"));
removeAllHooks();
// load settings
loadSettings(); // will also load vanished players
Server server = getServer();
// register events:
PluginManager pm = server.getPluginManager();
for ( Listener listener : new Listener[]{
new AttackListener(core),
new ChatListener(core),
new CoreListener(core),
new DamageListener(core),
new DropListener(core),
new InteractListener(core),
new PickupListener(core),
new TargetListener(core),
}){
pm.registerEvents(listener, this);
}
pm.registerEvents(cmdExe.aliasManager, this);
// finished enabling.
core.setEnabled(true);
core.addStandardHooks();
// just in case quadratic time checking:
try{
updateAllPlayers();
}
catch(Throwable t){
Utils.severe("Failed to update players in onEnable (scheduled for next tick), are you using reload?", t);
getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
@Override
public void run() {
updateAllPlayers();
}
});
}
System.out.println("[SimplyVanish] Enabled");
}
/**
* Quadratic time.
*/
private void updateAllPlayers(){
for ( Player player : getServer().getOnlinePlayers()){
core.updateVanishState(player);
// TODO: this remains a source of trouble when reloading !
}
}
/**
* Force reloading the config.
*/
public void loadSettings() {
Server server = getServer();
BukkitScheduler sched = server.getScheduler();
sched.cancelTasks(this);
CompatConfig config = CompatConfigFactory.getConfig(new File(getDataFolder(), "config.yml"));
final Path path;
// if (config.setPathSeparatorChar('/')){
// path = new Path('/');
// } else{
// // This would render some things inoperable (permissions with dot as keys).
path = new Path('.');
// }
boolean changed = false;
Settings settings = new Settings();
try{
config.load();
changed = Settings.addDefaults(config, path);
settings.applyConfig(config, path);
} catch (Throwable t){
Utils.severe("Failed to load the configuration, continue with default settings. ", t);
settings = new Settings();
}
core.setSettings(settings);
cmdExe.registerCommandAliases(config, path);
if (changed) config.save(); // TODO: maybe check for changes, somehow ?
if (settings.saveVanished) core.loadVanished();
if (settings.pingEnabled){
final long period = Math.max(settings.pingPeriod/50, 200);
sched.scheduleSyncRepeatingTask(this, new Runnable(){
@Override
public void run() {
core.onNotifyPing();
}
}, period, period);
}
if (settings.saveVanishedInterval > 0){
final long period = settings.saveVanishedInterval/50;
sched.scheduleSyncRepeatingTask(this, new Runnable(){
@Override
public void run() {
core.doSaveVanished();
}
}, period, period);
}
// Load plugins (permissions!):
PluginManager pm = server.getPluginManager();
for (String plgName : settings.loadPlugins){
Plugin plg = pm.getPlugin(plgName);
if (plg != null && !plg.isEnabled()) pm.enablePlugin(plg);
}
}
@Override
public boolean onCommand(CommandSender sender, Command command,
String label, String[] args) {
return cmdExe.onCommand(sender, command, label, args);
}
/**
* API
* @param player
* @param vanished true=vanish, false=reappear
*/
public static boolean setVanished(Player player, boolean vanished){
if (!core.isEnabled()) return false;
return core.setVanished(player.getName(), vanished);
}
/**
* API
* @param playerName
* @param vanished
*/
public static boolean setVanished(String playerName, boolean vanished){
if (!core.isEnabled()) return false;
return core.setVanished(playerName, vanished);
}
/**
* API
* @param playerName Exact player name.
* @return
*/
public static boolean isVanished(String playerName){
if (!core.isEnabled()) return false;
else return core.isVanished(playerName);
}
/**
* API
* @param player
* @return
*/
public static boolean isVanished(Player player){
if (!core.isEnabled()) return false;
else return core.isVanished(player.getName());
}
/**
* API
* Get a new Set containing the lower case names of Players to be vanished.<br>
* These are not necessarily online.<br>
* @deprecated The method signature will most likely change to Collection or List.
* @return
*/
public static Set<String> getVanishedPlayers(){
if (!core.isEnabled()) return new HashSet<String>();
else return core.getVanishedPlayers();
}
/**
* Convenience method, get default VanishConfig (copy), for checking flags.<br>
* Later on this might be useful, because default flags might be configurable.
* @return
*/
public static VanishConfig getDefaultVanishConfig(){
return new VanishConfig();
}
/**
* The create flag does in this case not force to store the configuration internally. To force that you have to use setVanishConfig.
* API
* @param playerName
* @param create
* @return A clone of the VanishConfig.
*/
public static VanishConfig getVanishConfig(String playerName, boolean create){
VanishConfig cfg = core.getVanishConfig(playerName, false);
if (cfg == null){
if (create) return getDefaultVanishConfig();
else return null;
}
else return cfg.clone();
}
/**
* Set the VanishConfig for the player, silently (no notifications), issues saving the configs.<br>
* This actually will create a new config and apply changes from the given one.<br>
* If update is true, this will bypass hooks and events.
* @param playerName
* @param cfg
* @param update
*/
public static void setVanishConfig(String playerName, VanishConfig cfg, boolean update){
core.setVanishConfig(playerName, cfg, update, false);
}
/**
* Set the VanishConfig for the player, with optional notifications, if the player is online, does issue saving the configs.<br>
* This actually will create a new config and apply changes from the given one.<br>
* If update is true, this will bypass hooks and events.
* @param playerName
* @param cfg
* @param update
* @param message
*/
public static void setVanishConfig(String playerName, VanishConfig cfg, boolean update, boolean message){
core.setVanishConfig(playerName, cfg, update, message);
}
/**
* Force an update of who sees who for this player, without notification, as if SimplyVanish would acall it internally.<br>
* @param player
* @return false, if the action was prevented by a hook, true otherwise.
*/
public static boolean updateVanishState(Player player){
return core.updateVanishState(player, false); // Mind the difference of flag to core.updateVanishState(Player).
}
/**
* Force an update of who sees who for this player, without notification.<br>
* @param player
* @param hookId To identify who calls this, 0 = as if SimplyVanish called it.
* @return false, if the action was prevented by a hook, true otherwise.
*/
public static boolean updateVanishState(Player player, int hookId){
return core.updateVanishState(player, false, hookId);
}
/**
* Force an update of who sees who for this player, with optional notification messages, as if SimplyVanish would call it internally.<br>
* @param player
* @param message If to send notifications and state messages.
* @return false, if the action was prevented by a hook, true otherwise.
*/
public static boolean updateVanishState(Player player, boolean message){
return core.updateVanishState(player, message);
}
/**
* Force an update of who sees who for this player, with optional notification messages.<br>
* @param player
* @param message
* @param hookId To identify who calls this, 0 = as if SimplyVanish called it.
* @return false, if the action was prevented by a hook, true otherwise.
*/
public static boolean updateVanishState(Player player, boolean message, int hookId){
return core.updateVanishState(player, message, hookId);
}
/**
* Get a new hook id to be passed for certain calls, to allow knwing if your own code called updateVanishState.
* API
* @return
*/
public static int getNewHookId(){
return core.getNewHookId();
}
/**
* API
* @param hook
* @return If one was already present.
*/
public static boolean addHook(Hook hook){
return core.getHookUtil().addHook(hook);
}
/**
* Get a hook if registered, the name must exactly match.
* @param name
* @return Hook or null, if not registered.
*/
public static Hook getRegisteredHook(String name){
return core.getHookUtil().getHook(name);
}
/**
* Listeners can not be removed yet.
* API
* @param hook
* @return If one was already present.
*/
public static boolean removeHook(Hook hook){
return core.getHookUtil().removeHook(hook);
}
/**
* Listeners can not be removed yet.
* API
* @param hookName
* @return If one was already present.
*/
public static boolean removeHook(String hookName){
return core.getHookUtil().removeHook(hookName);
}
/**
* Listeners can not be removed yet.
* API
*/
public static void removeAllHooks(){
core.getHookUtil().removeAllHooks();
}
/**
* Respects allow-ops, superperms and fake-permissions configuration entries.
* @param player
* @param
* @return
*/
public static final boolean hasPermission(final CommandSender sender, final String perm) {
return core.hasPermission(sender, perm);
}
/**
* Convenience method used internally.
* @return
*/
public static SimplyVanish getPluginInstance(){
return core.getPlugin();
}
/**
* Get a thread safe copy of the VanishConfig for a player.<br>
* This method will synchronize into the main server thread with an event,
* this take up to 50 milliseconds for processing, but it will return a copy
* of the VanishCOnfig instance for the player, exactly at a cxertain moment of time.<br>
*
* NOTE: This probably mostly obsolete and will likely be removed for the use of synchronized maps, but it is interesting to see (once) to use events to get some object in a thread safe way.
* @param playerName
* @param b
* @return
*/
public static VanishConfig getVanishConfigThreadSafe(String playerName, boolean create) {
// bit hacky:
GetVanishConfigEvent event = new GetVanishConfigEvent(playerName, create);
Bukkit.getPluginManager().callEvent(event);
return event.getVanishConfig();
}
}