関数safeBreak()がCall 1で期待どおりに実行されるのに、Call2またはCall2.1では実行されないのはなぜですか?
MinecraftBukkitプラグインToolBeltに取り組んでいます。
プラグインのツールの1つ(PickHax)を使用すると、プレーヤーは定義されたマテリアル(デフォルトはDIAMOND_PICKAXE)を保持したままブロックを削除できます。リージョン保護(WorldGuardなど)とロギング(HawkEyeなど)を提供する他のプラグインに可能な限り幅広いサポートを提供するために、BlockBreakEventを作成して呼び出します。これを行うコードは次のとおりです。
protected boolean safeBreak(Block target, Player subject, boolean applyPhysics) {
BlockBreakEvent canBreak = new BlockBreakEvent(target,subject);
server.getPluginManager().callEvent(canBreak);
if(!canBreak.isCancelled())
target.setTypeId(0, applyPhysics);
return !canBreak.isCancelled();
}
ToolBeltの現在のリリース(0.1)では、これは非常にうまく機能し、プレーヤーがサーバーのその領域(WorldGuard)に対する権限を持っていない場合、ブロックを削除しません。ターゲットのブロックをに設定しevent.getClickedBlock()
、サブジェクトのプレーヤーをevent.getPlayer()
に設定し、物理ブール値をtrue
左クリックしfalse
た場合と右クリックした場合に設定します。バージョン0.1での呼び出しは次のとおりです。
電話1
safeBreak(target,event.getPlayer(),physics);
私は現在、遠隔ブロック削除をサポートする新しいバージョンに取り組んでいます。ユーザーがしゃがんでいて範囲許可ノードを持っているかどうかに応じて、ターゲットブロックはevent.getClickedBlock()
またはによって設定されsubject.getTargetBlock(null,25)
ます。これは、1つの場合を除いて正常に機能します。
- ケース1:実際にブロック(LEFT_CLICK_BLOCK / RIGHT_CLICK_BLOCK)をクリックした場合、いずれかの物理設定で変更が表示されます。
- ケース2:範囲内でブロックを取得し、物理特性が
true
(LEFT_CLICK_AIR)の場合、変更が表示されます。 - ケース3:ただし、範囲内でブロックを取得し、物理演算が
false
(RIGHT_CLICK_AIR)である場合、クライアントでブロックの更新は表示されません。ログオフして再度ログオンすると、変更が表示されるため、変更はサーバー側で行われます。
この問題を軽減するためsubject.sendBlockChange()
に、偽のブロック変更をユーザーに送信することになっているを使用しようとしましたが、サーバーを変更することはありません。これにより、ユーザーは常に自分が行ったことを確認できます。したがって、新しいコード:
電話2
if(safeBreak(target,event.getPlayer(),physics))
subject.sendBlockChange(target.getLocation(), 0, (byte)0);
ただし、何らかの理由で、実行中safeBreak()
と実行中の変更if(safeBreak()) sendBlockChange()
により、リージョン保護(WorldGuard)が尊重されなくなります。ユーザーはWorldGuardからプリントアウトを受け取りますが、ビルド権限がないことを警告しますが、ボックは壊れます。
の説明.sendBlockChange()
が正確でなく、実際に世界を変えていない場合に備えて、「無害な」印刷メッセージで試してみました
2.1に電話する
if(safeBreak(target,event.getPlayer(),physics))
subject.sendMessage("Error still present?");
Call 2.1を実行するときに、ブロックを解除する権限がある地域にいる場合、「エラーはまだ存在しますか?」というメッセージが表示されます。メッセージですが、制限区域にいるときはしません。これはsafeBreak()
、ブロックを壊すべきかどうかについて正しい値を返しているが、どういうわけかまだブロックを壊していることを意味します。.sendBlockChange()
また、 Call 2がないため、ケース3の問題が再度発生します。
電話3
if(safeBreak(target,event.getPlayer(),physics)) {}
これで、コードはの戻り値をチェックする以外のアクションはsafeBreak()
ありませんが、制限された領域のブロックを壊します。コール1に切り替えましたが、制限区域のブロックは壊れませんでした。
これで元の質問に戻ります。ToolBelt.jarを再コンパイルできますが、唯一の違いはCall1とCall2であり、問題を確実に再現できます。コール1が設定されている場合、リージョンサポートは尊重されますが、ケース3はクライアントを更新しません。コール2が設定されている場合、クライアントは常にブロックの更新を取得しますが、任意のリージョンのブロックを削除できます。
ケース3(範囲内での物理的除去なし)を許可せず、Call 1を使用することで問題を回避できますが、ツールの機能を損なうことはありません。Call1が問題なく機能するのにCall2とCall2.1がリージョンで機能しない理由を誰かが知っていますか?
関心のあるドキュメントリンク:
ブロック:ブロックを表します。これはライブオブジェクトであり、ワールド内の特定の場所に存在できるブロックは1つだけです。
プレーヤー:接続されているかどうかに関係なく、プレーヤーを表します
.isCanceled():このイベントのキャンセル状態を取得します。キャンセルされたイベントはサーバーで実行されませんが、他のプラグインに渡されます
.sendBlockChange():ブロック変更を送信します。これは、特定の場所にいるユーザーのブロック変更パケットを偽造します。これは実際には決して世界を変えることはありません。