2017-03-03 73 views
1

我在我的bukkit/spigot插件中有一個自定義事件,它擴展了PlayerInteractEvent,它嘗試在玩家周圍的附近地區打開箱子。如何查看bukkit插件中名爲setCancelled()的類/插件?

當前代碼使用此事件來確保沒有其他插件(例如,悲傷預防)反對玩家能夠打開胸部。如果玩家可以打開胸部,我的插件會嘗試將物品放入胸部。我想忽略setCancelled()如果它是由一定的插件(理想情況下)或者類中調用(作爲變通)

this question我可以看到,獲得I類可以使用

String callerClassName = new Exception().getStackTrace()[1].getClassName(); 
String calleeClassName = new Exception().getStackTrace()[0].getClassName(); 

要獲取類名。或者我可以用的東西圍繞這一呼籲:對這個問題的狀態很可能有更好的方法來做到這一點比什麼,這是做其他

StackTraceElement[] stElements = Thread.currentThread().getStackTrace(); 

然而,所有的意見。

Bukkit有沒有更好的方法來做到這一點?

供參考,這是我的自定義播放器交互事件的全部:

public class FakePlayerInteractEvent extends PlayerInteractEvent { 
    public FakePlayerInteractEvent(Player player, Action rightClickBlock, ItemStack itemInHand, Block clickedBlock, BlockFace blockFace) { 
     super(player, rightClickBlock, itemInHand, clickedBlock, blockFace); 
    } 
} 

和周圍使用事件的代碼:

PlayerInteractEvent fakeEvent = AutomaticInventory.getInstance().new FakePlayerInteractEvent(player, Action.RIGHT_CLICK_BLOCK, player.getInventory().getItemInMainHand(), block, BlockFace.UP); 
Bukkit.getServer().getPluginManager().callEvent(fakeEvent); 
if(!fakeEvent.isCancelled()){ ... do stuff } 
+0

是的,有一個更好的解決方案。只要我檢查了一些事情,我會盡快發佈更多細節。 – Frelling

回答

0

我會建議使用優先


優先順序按以下順序排列:

  1. 最低的
  2. LOW
  3. 師範大學
  4. HIGH
  5. HIGHEST
  6. MONITOR

如果您設置的事件優先HIGHESTMONITOR,您的活動會聽取事件畢竟其他優先事項都聽取了它的意見。例如,即使另一個插件試圖取消它,您仍然可以聽該事件。

注意:建議不要以MONITOR優先級更改事件的結果。它只能用於監控。

改變事件的優先級(默認:NORMAL)

@EventHandler (priority = EventPriority.HIGHEST) 
public void onEvent(Event e) { 
} 

如果你想其他插件的插件後採取行動的最終發言權,例如,如果你想世界編輯比「更強」您的插件,請將優先級設置爲LOWLOWEST。如果你希望你的插件能夠說出最後的話,那麼請增加這個優先級。

@EDIT

如果你想這樣做沒有優先級,而實際上需要確定取消插件,Comprehenix from bukkit forums have a solution for you。請記住它不建議

例如在如何做到這一點:

public class ExampleMod extends JavaPlugin implements Listener { 

private CancellationDetector<BlockPlaceEvent> detector = new CancellationDetector<BlockPlaceEvent>(BlockPlaceEvent.class); 

    @Override 
    public void onEnable() { 
     getServer().getPluginManager().registerEvents(this, this); 

     detector.addListener(new CancelListener<BlockPlaceEvent>() { 
      @Override 
      public void onCancelled(Plugin plugin, BlockPlaceEvent event) { 
       System.out.println(event + " cancelled by " + plugin); 
      } 
     }); 
    } 

    @Override 
    public void onDisable() { 
     // Incredibly important! 
     detector.close(); 
    } 

    // For testing 
    @EventHandler 
    public void onBlockPlaceEvent(BlockPlaceEvent e) { 
     e.setCancelled(true); 
    } 
} 

你可以找到CancellationDetector的混帳here

+0

事件處理程序已經設置爲'MONITOR'。問題是'我怎麼能告訴哪個班叫setCancelled',少'我怎麼知道它是否被取消' – Mitch

+0

答案的重點在於,如果你只是想知道哪個班取消了這個活動並不是真的有必要想用它反正 – Kerooker

+0

我想選擇性地使用它。如果插件A取消它,我想忽略取消,但是如果插件B取消它,我想服從取消 – Mitch

1

很好的問題!暫且讓我忽略激發 這個問題的原因。 Bukkit不會「公佈」確定事件取消源的方法。但是,您評估「 」事件的方法是正確的。

正如你已經知道或懷疑,使用堆棧跟蹤都沒有一個很好的解決方案。 生成和描述實現特定的細節可能相對昂貴,因此可能不一定保證不變。更好的方法是模仿Bukkit的事件觸發過程,當調用 callEvent()時。

儘管事件觸發過程實現不受 Bukkit API的保證,但它已穩定多年並且沒有更改 很多。這對我們的工作在過去的5年中,只需要一個小小的 重構時callEvent()分成callEvent()/fireEvent()

我希望我可以給你整個EventUtils幫手類,但我 必須修改它,由於版權問題。我確實證實這個減少的類通過了適當的單元測試。您或其他人是 可以免費使用此代碼。其評論詳細解釋了 中的操作。我應該注意到我們使用Doxygen而不是JavaDoc來生成 文檔。

public class EventUtils { 

    /** 
    * @brief Determine if the given event will be cancelled. 
    * 
    * This method emulates Bukkit's SimplePluginManager.fireEvent() to evaluate whether it will 
    * be cancelled. This is preferred over using callEvent() as this method can limit the scope 
    * of evaluation to only plugins of interest. Furthermore, this method will terminate as soon 
    * as the event is cancelled to minimize any *side effects* from plugins further down the event 
    * chain (e.g. mcMMO). No evaluation will be performed for events that do not 
    * implement Cancellable. 
    * 
    * The given plugin set is interpreted as either an Allow set or a Deny set, as follows: 
    * 
    * - \c allowDeny = \c false - Allow mode. Only enabled plugins included in the given plugin 
    * set will be evaluated. 
    * - \c allowDeny = \c false - Deny mode. Only enabled plugins *not* included in the given 
    * plugin set will be evaluated. 
    * 
    * @warning Care should be taken when using this method from within a plugin's event handler for 
    * the same event or event type (e.g. "faked" events). As this may result in an unending 
    * recursion that will crash the server. To prevent this situation, the event handler should 
    * (given in order of preference): 1) restrict evaluation to a specific Allow set not including 
    * its own plugin; or, 2) add its own plugin to a Deny set. See overloaded convenience methods 
    * for more details. 
    * 
    * @param evt event under test 
    * @param plugins Allow/Deny plugin set 
    * @param allowDeny \c false - evaluate using an Allow set; or \c true - evaluate using a 
    *  Deny set. 
    * @return first plugin that cancelled given event; or \c if none found/did 
    */ 

    public static Plugin willCancel(Event evt, Set<Plugin> plugins, boolean allowDeny) { 
     PluginManager piMgr = Bukkit.getPluginManager(); 

     /* 
     * 1. From SimplePluginManager.callEvent(). Check thread-safety and requirements as if this 
     * were a normal event call. 
     */ 
     if (evt.isAsynchronous()) { 
      if (Thread.holdsLock(piMgr)) { 
       throw new IllegalStateException(evt.getEventName() 
         + " cannot be triggered asynchronously from inside synchronized code."); 
      } 
      if (Bukkit.isPrimaryThread()) { 
       throw new IllegalStateException(evt.getEventName() 
         + " cannot be triggered asynchronously from primary server thread."); 
      } 
      return fireUntilCancelled(evt, plugins, allowDeny); 
     } 
     else { 
      synchronized (piMgr) { 
       return fireUntilCancelled(evt, plugins, allowDeny); 
      } 
     } 

    } 


    /** 
    * @brief See willCancel() for details. 
    * 
    * @note Scoped as `protected` method for unit testing without reflection. 
    * 
    * @param evt event under test 
    * @param plugins Allow/Deny plugin set 
    * @param allowDeny \c false - evaluate using an Allow set; or \c true - evaluate using a 
    *  Deny set. 
    * @return first plugin that cancelled given event; or \c if none found/did 
    */ 
    protected static Plugin fireUntilCancelled(Event evt, Set<Plugin> plugins, boolean allowDeny) { 

     /* 
     * 1. If event cannot be canceled, nothing will cancel it. 
     */ 

     if (!(evt instanceof Cancellable)) 
      return null; 

     /* 
     * 2. Iterate over the event's "baked" event handler list. 
     */ 

     HandlerList handlers = evt.getHandlers(); 
     for (RegisteredListener l : handlers.getRegisteredListeners()) { 

      /* 
      * A. Is associated plugin applicable? If not, move to next listener. 
      */ 

      if (!ofInterest(l.getPlugin(), plugins, allowDeny)) 
       continue; 

      /* 
      * B. Call registered plugin listener. If event is marked cancelled afterwards, return 
      * reference to canceling plugin. 
      */ 

      try { 
       l.callEvent(evt); 
       if (((Cancellable) evt).isCancelled()) 
        return l.getPlugin(); 
      } 
      catch (EventException e) { 

       /* 
       * Can be safely ignored as it is only used to nag developer about legacy events 
       * and similar matters. 
       */ 
      } 
     } 
     return null; 
    } 


    /** 
    * @brief Determine whether the given plugin is of interest. 
    * 
    * This method determines whether the given plugin is of interest. A plugin is of no interest 
    * if any of the following conditions are met: 
    * 
    * - the plugin is disabled 
    * - \c allowDeny is \c false (allow) and set does not contains plugin 
    * - \c allowDeny is \c true (deny) and set contains plugin 
    * 
    * @note Scoped as `protected` method for unit testing without reflection. 
    * 
    * @param plugin plugin to evaluate 
    * @param plugins plugin allow/deny set 
    * @param allowDeny \c false validate against allow set; \c true validate against deny set 
    * @return \c true plugin is of interest; \c false otherwise 
    */ 

    protected static boolean ofInterest(Plugin plugin, Set<Plugin> plugins, boolean allowDeny) { 
     if (!plugin.isEnabled()) 
      return false; 

     return allowDeny^plugins.contains(plugin); 
    } 
}