2017-03-03 17 views
1

私はbukkit/spigotプラグインにカスタムイベントを持っています。これは、PlayerInteractEventを拡張して、プレイヤーの近くの近くにある胸を開こうとします。bukkitプラグインでsetCancelled()というクラス/プラグインを確認するにはどうすればいいですか?

現在、このコードではこのイベントを使用して、プレーヤーに胸を開くことができる他のプラグイン(たとえば、悲嘆防止など)オブジェクトがないことを確認しています。プレーヤーが胸を開くことができる場合、私のプラグインはアイテムを胸に入れようとします。私がすることが

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

を使用することができ、私はクラスを取得するためにそれを見ることができますthis questionから

(周りの仕事として)特定のプラグイン(理想的には)またはクラスによって呼び出されます場合、私はsetCancelled()を無視したいと思いますクラス名を取得する。これが何をしているか以外に、しかし、それを行うには良い方法がありそうであることをその質問の状態に関するすべてのコメントを

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. LOWEST
  2. LOW
  3. NORMAL
  4. HIGH
  5. HIGHEST
  6. MONITOR

あなたがHIGHESTまたはMONITORにあなたのイベントの優先順位を設定した場合、あなたのイベントは、イベントに耳を傾けます他のすべての優先事項がそれに耳を傾けた後。たとえば、他のプラグインがキャンセルしようとしても、そのイベントを聞くことができます。

注:イベントの結果をMONITOR優先度に変更することはお勧めしません。モニタリングにのみ使用する必要があります。

イベントの優先度(デフォルト:NORMAL)を変更するあなたは他のプラグインは、言うファイナルにあなたのプラグインの後に行動したい場合、たとえば、あなたがしたい場合世界の編集がより「強い」ことを

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

をプラグインを使用する場合は、優先度をLOWまたはLOWESTに設定します。あなたのプラグインに最終的な発言をしたい場合は、その優先順位を上げてください。

@EDIT

あなたは優先順位なしでそれをしたい、と実際にキャンセルするプラグイン、Comprehenix from bukkit forums have a solution for youを特定する必要がある場合。あなたがCancellationDetectorのgitのhere

+0

イベントハンドラはすでに 'MONITOR'に設定されています。質問はもっと「どのようにsetCancelledと呼ばれるクラスを教えてもらえませんか?そして、それがキャンセルされたかどうか教えてもらうにはどうすればいいのですか?」 – Mitch

+0

あなたがちょうどイベントをキャンセルしたクラスを知ることは本当に必要でないことを示す答えのポイントとにかくそれを使いたい – Kerooker

+0

私はそれを選択的にやりたい。プラグインAがそれをキャンセルした場合、私はそのキャンセルを無視したいが、プラグインBがそれをキャンセルすると、そのキャンセルに従うことになる。 – Mitch

1

優秀な質問を見つけることができます

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); 
    } 
} 

:それはそれを行う方法についてのお勧めできません

例だ覚えておいてください!今のところ私は この質問を拍手した理由を無視させてください。 Bukkitは、イベントキャンセルのソースを決定する手段を「公開」していません。しかし、 イベントを「評価する」アプローチは適切なトラックにあります。

スタックトレースを使用することは良い解決策ではありません。 これらは、生成するのが比較的高価であり、実装固有の 詳細を示していますが、必ずしも同じであることが保証されているとは限りません。より良い のアプローチは、 callEvent()を呼び出すときに使用されるBukkitのイベント発生プロセスを模倣することです。

Bukkit APIでイベント発射プロセスの実装が保証されているわけではありませんが、何年も安定しており、 はそれほど変更されていません。私たちの過去5年間の仕事ですが、callEvent()callEvent()/fireEvent()に分割したときには、リファクタリングが1回だけ必要です。

EventUtilsヘルパークラス全体を教えてもらいたいと思いますが、私は を著作権の問題のために修正する必要がありました。私はこの がクラスを減らしたことが適切なユニットテストに合格したことを確認しました。あなたまたは他の誰かが このコードを見た目に自由に使うことができます。そのコメントは の操作を詳しく説明しています。 ドキュメントの生成には、JavaDocではなくDoxygenを使用することに注意してください。

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); 
    } 
} 
関連する問題