はじめに
Minecraft のコマンドやデータパックを書いていると、
- 条件は合っているはずなのに動かない
- なぜか 1tick 遅れる
- 同じ処理なのに、状況によって挙動が変わる
といった「原因が分かりにくいバグ」に遭遇することがあります。
その多くは 1tick 内での処理順 を把握できていないことが原因です。
この記事では、実際の挙動から分かる範囲で 1tick の処理順 を整理し、
バグに遭遇したときの考え方を共有します。
1tickの中の大まかな処理順
※この記事の内容は、公式仕様として明言されたものではありません。
実際の挙動を元にした 経験則と推測に基づく整理 です。
1tick 内では、概ね次の順で処理されているように見えます。
-
function tick
-
minecraft:tags/function/tick.jsonに登録された function
-
-
block tick
- コマンドブロックなど、ブロック由来の処理
-
entity tick
- 進捗
- チャット欄からのコマンド実行
- エンティティ由来の各種処理
-
enchant tick
- エンチャントの
run_function
- エンチャントの
entity tick 内での処理順について
entity tick では、すべてのエンティティが同時に処理されるわけではありません。
処理順は、エンティティがワールドに読み込まれた順になっているように見えます。
具体的には、
- ワールド起動時やチャンク読み込み時点ですでに存在していたエンティティ
- プレイヤーがログインする前に読み込まれていたエンティティ
が先に処理されます。
その後に、
- ログインしたプレイヤー自身
- そのプレイヤーがログインした「後」に召喚・生成されたエンティティ
が処理されます。
このため、
- プレイヤーがログインしたあとに召喚したエンティティは
そのプレイヤーより後に entity tick が実行される - その後プレイヤーがリログ(再ログイン)すると、
プレイヤーの処理順が最後になり、以前と順番が変わる
といったことが起こり得ます。
処理順に依存したコマンドを書いている場合、
プレイヤーのリログやエンティティの再召喚によって挙動が変わる原因になるため注意が必要です。
よくあるハマり例①
進捗で変更したものを function tick で検知できない
進捗の処理は、内部的には entity tick のタイミングで行われます。
一方、tick.json に登録された function は それより前 に実行されます。
そのため、
- 同じ tick 内で
- 進捗でスコアや状態を変更
- function tick でそれを検知する
ということは できません。
なぜか
- function tick は「その tick の最初」に実行される
- 進捗による変更は、その後に反映される
対策例
- 進捗で実行される function の中だけで処理を完結させる
- 次の tick で、進捗を達成したプレイヤーを対象に処理する
- スコアなどでフラグを立てて、処理を 1tick 遅延させる
よくあるハマり例②
進捗のブロック条件は「変化後」しか検知できない
進捗の default_block_use などの条件は、
- プレイヤーがブロックにインタラクト
- ブロック側の処理が実行される
- 進捗の条件判定が行われる
という順で処理されているように見えます。
そのため、
- 右クリック「する前」のブロック
- 変更「される前」のブロック
は検知できず、
変化後のブロックのみが条件判定に使用されます。
処理順を知らないと、
「進捗の条件が壊れている」と勘違いしやすいポイントです。
よくあるハマり例③
エンチャントは装備した瞬間には発動しない
エンチャントの run_function は enchant tick で実行されますが、
-
enchant tick に入る前、
entity tick のどのエンティティを処理対象にするかを決定する段階で、- 「この tick で処理されるエンティティ」
- 「各エンティティが所持している装備・エンチャント」
がまとめて判定・確定しているように見えます。
そのため、
- 進捗などの entity tick 内で実行される処理 で
- エンチャント付きアイテムを持ったエンティティを召喚
- 同じ tick 内で
- そのエンチャントを発動させる
ということはできず、次の tick に持ち越されます。
バグに遭遇したときに考えてほしいこと
コマンドがうまく動かないときは、まず
- execute の条件が間違っていないか
- セレクターが正しく対象を取得できているか
- NBT やスコアが想定どおり取得できているか
- スペルミス(スコア名・タグ名など)がないか
といった 基本的なミス を疑うのが大切です。
それらを確認しても原因が見つからない場合に、
次の視点として
「そもそも同じ tick 内で検知できる処理なのか?」
を考えてみてください。
また、entity tick が関係する処理では、
「エンティティ間の処理順が前後していないか」
という点も、原因切り分けの重要なヒントになります。
おわりに
コマンドを書く際には、
- 「何を書くか」だけでなく
- 「いつ・どの順番で実行されるか」
を意識することが重要です。
処理順を理解できるようになると、
原因不明のバグに悩まされる時間は大きく減ります。
これからコマンドを書く人が、
同じ罠にハマらないための参考になれば幸いです。