hogepiyo

かつてはマイクラのModを作っていたがひざに矢を受けた

PlayerInteractEventの挙動

PlayerInteractEventについて

PlayerInteractEventは, EntityInteractEventと似たEventで, プレイヤーがブロックやアイテムを右クリック(左クリック)したときに割りこまれる.

このEventを使って, 特定のアイテムを持った状態で元々GUIを持つブロックを右クリックすると別のGUIが表示されるようにしたのだが, 素直に書いたコード

@ForgeSubscribe
public void interrupt(PlayerInteractEvent event) {
    if (canInteract(event.entityPlayer, event.x event.y, event.z)) {
        event.entityPlayer.openGui(...);
        event.setCanceled(true);
    }
}

条件が合えば(プレイヤーの現在持っているアイテムや, 右クリックしたブロックのIDなど), 別のGUIを開くが, GUIは開いてもインベントリ操作ができない. アイテムをつかんでも動かせなかった.

発生した問題

  • 右クリック時のブロックIDが, 想定してるIDではない
  • クライアント側しか実行されない
  • GUIが開いてもすぐ閉じてしまう

IDのずれ

アイテムを持っていないときはちゃんとしたブロックIDに, アイテムを持っていると何故かクライアントは0, サーバーは7(bedrock). PlayerInteractEventには右クリックしたときのアクションがRIGHT_CLICK_AIRとRIGHT_CLICK_BLOCKの2つがある. アイテムを持っていないと後者のみ呼ばれ, そのブロックのIDがEventに渡されるのだが, アイテムを持っているときは両方呼ばれ, 前者のほうが優先される. それを回避するために以下のコードをEventの始めに挿入.

if (event.action == PlayerInteractEvent.Action.RIGHT_CLICK_AIR) return ;

これでIDが変わる問題は解決した.

クライアント側しか実行されない

Event自体はクライアント・サーバー両方で呼ばれるが, openGuiがクライアント側しか実行されない. 原因不明だったので, 素直にサーバーにパケットを送信して, サーバー側でopenGuiを実行したらうまくいった.

GUIがすぐ閉じる

なんてことはない. Container側のcanInteractWithの条件設定が不適切だった.

まとめ

ここまでやっておいて言うのもあれだが, バニラのブロックの挙動を変える以外は素直に追加BlockのonBlockActivateでopenGuiしたほうがいいかなって.

ただ面白いので, GUIを開くのではなく, 特定のツールで右クリックするとブロックを置換する, などのアイデアに期待するEvent.