PlayerInteractEventについて
Spigotにて、プレイヤーがクリックしたときに呼ばれるイベントです。
例えば、棒を右クリックしたときに処理が実行される場合以下のように書けます
class ItemListener(private val plugin: SamplePlugin) : Listener {
init {
plugin.server.pluginManager.registerEvents(this, plugin)
}
@EventHandler
fun ckickItem(event: PlayerInteractEvent) {
val player = event.player
if (event.action == Action.RIGHT_CLICK_AIR || event.action == Action.RIGHT_CLICK_BLOCK) {
val itemStack = player.inventory.itemInMainHand
if (itemStack.type == Material.STICK) {
// 処理を書く
event.isCancelled = true
}
}
}
}
しかし、このように書くと、処理は実行されますが、1回のクリックに付きイベントが2回呼び出されて、処理が2回実行されてしまいます。
対処方針
- プレイヤーがPlayerInteractEventを実行すると、プレイヤーにメタデータとしてフラグを持たせる
- プレイヤーにフラグが存在する場合、PlayerInteractEventをスキップするようにする
- 一定時間経過後にフラグを消す
実際のコード
以下のようなPlayerFlagというクラスを作りました
メタデータにtrueをセットし、一定時間経過後にfalseにセットします。
class PlayerFlag(val player: Player, val plugin: SamplePlugin) {
fun set() {
setMetadata(true)
object : BukkitRunnable() {
override fun run() {
setMetadata(false)
}
}.runTaskLater(plugin, 10)
}
private fun setMetadata(flag: Boolean) {
player.setMetadata("PlayerInteractEvent", FixedMetadataValue(plugin, flag))
}
fun get(): Boolean {
try {
return player.getMetadata("PlayerInteractEvent")[0].value() as Boolean
} catch (e: Exception) {
return false
}
}
}
ListenerにPlayerFlagのコードを追加します
class ItemListener(private val plugin: SamplePlugin) : Listener {
init {
plugin.server.pluginManager.registerEvents(this, plugin)
}
@EventHandler
fun ckickItem(event: PlayerInteractEvent) {
val player = event.player
//追加したところ
val playerFlag = PlayerFlag(player, plugin)
if (playerFlag.get()) {
return
}
if (event.action == Action.RIGHT_CLICK_AIR || event.action == Action.RIGHT_CLICK_BLOCK) {
val itemStack = player.inventory.itemInMainHand
if (itemStack.type == Material.STICK) {
//追加したところ
playerFlag.set()
// 処理を書く
event.isCancelled = true
}
}
}
}
このようにして2回反応してしまう現象を防げます。