0

関数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():ブロック変更を送信します。これは、特定の場所にいるユーザーのブロック変更パケットを偽造します。これは実際には決して世界を変えることはありません。

4

2 に答える 2

3

問題は私が投稿したよりも高いレベルでした。十分なデータが含まれていないことをお詫び申し上げます。元のケース1の呼び出しは次のとおりです。

if(isUseEvent())
    safeBreak(target,event.getPlayer(),physics);
else {
    target.setTypeId(0,physics);
    subject.sendBlockChange(target.getLocation(), 0, (byte)0);
}

ケース2の呼び出しは

if(isUseEvent())
    if(safeBreak(target,event.getPlayer(),physics))
        subject.sendBlockChange(target.getLocation(), 0, (byte)0);
else {
    target.setTypeId(0,physics);
    subject.sendBlockChange(target.getLocation(), 0, (byte)0);
}

ただし、inを{}でラップしなかったため、elseが最も内側のステートメントif(safeBreak()) doStuff;と並んでいることを意味します。if()したがって、適切なフォーマットは次のようになります。

if(isUseEvent())
    if(safeBreak(target,event.getPlayer(),physics))
        subject.sendBlockChange(target.getLocation(), 0, (byte)0);
    else {
        target.setTypeId(0,physics);
        subject.sendBlockChange(target.getLocation(), 0, (byte)0);
    }

これは、ばかげたショートカットをとらず、適切にラップすることで簡単に解決できます。if() {doStuff;}

if(isUseEvent()) {
    if(safeBreak(target,event.getPlayer(),physics)) {
        subject.sendBlockChange(target.getLocation(), 0, (byte)0);
    }
}else {
    target.setTypeId(0,physics);
    subject.sendBlockChange(target.getLocation(), 0, (byte)0);
}
于 2012-04-01T00:13:19.140 に答える
0

l値をチェックしても、 l値を生成したコードには影響しません。これは、ifステートメントの「then」セクションのコードが原因である可能性が高いことを意味します。

統合するサードパーティのコードがどのように設計されているかによっては、例外などがロールバックのような動作を引き起こす可能性があります。

(「無害な印刷メッセージ」ではなく)ifブロックで簡単なステートメントを使用してみてください。これを自分で検証できるはずです。

if(safeBreak(target,event.getPlayer(),physics))
{
}
于 2012-03-31T23:35:21.660 に答える