package me.asofold.bpl.simplyvanish.util; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import me.asofold.bpl.simplyvanish.api.hooks.Hook; import me.asofold.bpl.simplyvanish.api.hooks.HookListener; import me.asofold.bpl.simplyvanish.api.hooks.HookPurpose; import me.asofold.bpl.simplyvanish.config.VanishConfig; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.plugin.PluginManager; /** * Auxiliary methods for hooks. * @author mc_dev * */ public class HookUtil { /** * Hooks by purpose. */ private final Map<HookPurpose, List<Hook>> usedHooks = new HashMap<HookPurpose, List<Hook>>(); private final Map<String, HookListener> usedHookListeners = new HashMap<String, HookListener>(); private final List<Hook> onLoadHooks = new ArrayList<Hook>(); /** * Registered hooks by name. */ private final Map<String, Hook> registeredHooks = new HashMap<String, Hook>(); private int maxHookId = 0; /** * */ public HookUtil(){ init(); } /** * Ensures that a list for every use is in usedHooks.<br> * NOTE: The LISTENER entry is in it too, though unused. */ private void init() { for (HookPurpose sup : HookPurpose.values()){ usedHooks.put(sup, new LinkedList<Hook>()); } } /** * Hooks added during loading of the plugin, they will be registered in on enable by calling SimplyVanishCore.addStandardHooks. * @param hook */ public void addOnLoadHook(Hook hook) { onLoadHooks.add(hook); System.out.println("[SimplyVanish] Queued hook (onLoad): "+hook.getHookName()); } public void registerOnLoadHooks(){ for (Hook hook : onLoadHooks){ addHook(hook); } } public boolean addHook(Hook hook) { boolean existed = removeHook(hook); try{ String hookName = hook.getHookName(); // add hook ! registeredHooks.put(hookName, hook); HookPurpose[] supported = hook.getSupportedMethods(); if (supported == null) supported = HookPurpose.values(); boolean hasListener = false; for (HookPurpose sup : supported){ getUsedHooks(sup).add(hook); if (sup == HookPurpose.LISTENER) hasListener = true; } if (hasListener){ HookListener listener = hook.getListener(); if (listener != null){ PluginManager pm = Bukkit.getServer().getPluginManager(); pm.registerEvents(listener, pm.getPlugin("SimplyVanish")); usedHookListeners.put(hookName, listener); } } System.out.println("[SimplyVanish] Add hook: "+hook.getHookName()); } catch (Throwable t){ Utils.warn("Disable hook ("+hook.getHookName()+") due to failure on registration: "+t.getMessage()); t.printStackTrace(); removeHook(hook); } return existed; } public boolean removeHook(Hook hook) { // TODO maybe also check for the hook itself. return removeHook(hook.getHookName()); } public boolean removeHook(String hookName) { Hook hook = registeredHooks.remove(hookName); if (hook == null) return false; HookListener listener = usedHookListeners.remove(hookName); if (listener != null){ try{ if (!listener.unregisterEvents()) Utils.warn("HookListener ("+hookName+") returns failure on unregister."); } catch (Throwable t){ Utils.warn("Failed to unregister HookListener ("+hookName+"): "+t.getMessage()); t.printStackTrace(); } } for (HookPurpose sup : usedHooks.keySet()){ List<Hook> rem = new LinkedList<Hook>(); List<Hook> present = getUsedHooks(sup); for (Hook ref : present){ if (ref==hook || ref.getHookName().equals(hookName)) rem.add(ref); // equals unnecessary ? } present.removeAll(rem); } return true; } /** * (Over cautious.) * @param purpose * @return */ public final List<Hook> getUsedHooks(final HookPurpose purpose){ List<Hook> hooks = null; if (purpose != null) hooks = usedHooks.get(purpose); if (hooks == null) return new LinkedList<Hook>(); return hooks; } public void removeAllHooks(){ List<String> names = new LinkedList<String>(); names.addAll(registeredHooks.keySet()); for ( String name : names){ removeHook(name); // TODO: maybe something more complete. } // safety: usedHookListeners.clear(); usedHooks.clear(); registeredHooks.clear(); init(); } // CALL METHODS ---------------------------------------- public void onHookCallError(HookPurpose sup, Hook hook, String playerName, Throwable t) { String msg; if (t==null) msg = "<unknown>"; else msg = t.getMessage(); Utils.warn("Error on calling "+sup+" on hook("+hook.getHookName()+") for player "+playerName+": "+msg); if (t!= null) t.printStackTrace(); } public final void callBeforeVanish(final String playerName) { final HookPurpose sup = HookPurpose.BEFORE_VANISH; for (final Hook hook : getUsedHooks(sup)){ try{ hook.beforeVanish(playerName); } catch (Throwable t){ onHookCallError(sup, hook, playerName, t); } } } public final void callAfterVanish(final String playerName) { final HookPurpose sup = HookPurpose.AFTER_VANISH; for (final Hook hook : getUsedHooks(sup)){ try{ hook.afterVanish(playerName); } catch (Throwable t){ onHookCallError(sup, hook, playerName, t); } } } public final void callBeforeSetFlags(final String playerName, final VanishConfig oldCfg, final VanishConfig newCfg) { final HookPurpose sup = HookPurpose.BEFORE_SETFLAGS; for (final Hook hook : getUsedHooks(sup)){ try{ hook.beforeSetFlags(playerName, oldCfg, newCfg); } catch (Throwable t){ onHookCallError(sup, hook, playerName, t); } } } public final void callAfterSetFlags(final String playerName) { final HookPurpose sup = HookPurpose.AFTER_SETFLAGS; for (final Hook hook : getUsedHooks(sup)){ try{ hook.afterSetFlags(playerName); } catch (Throwable t){ onHookCallError(sup, hook, playerName, t); } } } public final void callBeforeReappear(final String playerName) { final HookPurpose sup = HookPurpose.BEFORE_REAPPEAR; for (final Hook hook : getUsedHooks(sup)){ try{ hook.beforeReappear(playerName); } catch (Throwable t){ onHookCallError(sup, hook, playerName, t); } } } public final void callAfterReappear(final String playerName) { final HookPurpose sup = HookPurpose.AFTER_REAPPEAR; for (final Hook hook : getUsedHooks(sup)){ try{ hook.afterReappear(playerName); } catch (Throwable t){ onHookCallError(sup, hook, playerName, t); } } } public final boolean allowUpdateVanishState(final Player player, final int hookId) { final HookPurpose sup = HookPurpose.ALLOW_UPDATE; boolean allow = true; for (final Hook hook : getUsedHooks(sup)){ try{ allow &= hook.allowUpdateVanishState(player, hookId, allow); } catch (Throwable t){ onHookCallError(sup, hook, player.getName(), t); } } return allow; } public final boolean allowShow(final Player player, final Player canSee) { final HookPurpose sup = HookPurpose.ALLOW_SHOW; boolean allow = true; for (final Hook hook : getUsedHooks(sup)){ try{ allow &= hook.allowShow(player, canSee, allow); } catch (Throwable t){ onHookCallError(sup, hook, player.getName(), t); } } return allow; } public final boolean allowHide(final Player player, final Player canNotSee) { final HookPurpose sup = HookPurpose.ALLOW_HIDE; boolean allow = true; for (final Hook hook : getUsedHooks(sup)){ try{ allow &= hook.allowShow(player, canNotSee, allow); } catch (Throwable t){ onHookCallError(sup, hook, player.getName(), t); } } return allow; } public Hook getHook(String name) { return registeredHooks.get(name); } public int getNewHookId() { maxHookId++; return maxHookId; } }