メインコンテンツまでスキップ

マクロ / Macro

マクロとは?

「マクロ」 は、Commander APIが提供する便利すぎる魔法のような機能のひとつです。
面倒だった長いコマンドも、マクロを使えばスッキリ簡潔に。ほら、コマンド職人たちの肩こりも軽くなってきた気がしますね。

試しに、マクロが何者なのか見てみましょう。

/titleraw @a actionbar {"rawtext":[{"selector":"*"},{"text":"'s money: "},{"score":{"objective":"money","name":"*"}}]}

このコマンドは、Commander API を使わずに実行でき、例えば money スコアが 100 の Notch に対しては Notch's money: 100 と表示されます。 正直なところ、長くて見にくい…まるで古代の呪文のようです。魔法使いも苦労しそうなこの冗長さ、誰が望んだのでしょうか?

では、実際に実行してみましょう。

Nano191225's money

あっ、借金!? たぶん投資に失敗しただけです。


さあ、これをマクロで書き直してみましょう。

/execute as @a run scriptevent capi:actionbar <!name>'s money: <!score=money>

このように、マクロのおかげでコマンドが短く、見やすくなりました。

<!name><!score=money> のようなマクロが使われています。
これで長くて複雑だったコマンドも、圧倒的に読みやすく・書きやすくなります。

とはいえ、execute のおかげで結局コマンドが長くなってない?と一瞬不安になりますが、
実際には自由度が増えて管理もしやすくなるので、全然アリです。

これも実行してみました。

Nano191225&#39;s money

あら不思議、マクロを使えば借金も肩こりも無くなりましたね。

構文

マクロは以下のような構文で記述します。

<!{macro_name}>
  • <! で始まり、> で終わる部分がマクロです。
  • macro_name には使用するマクロの名前を記述します。
  • 値を必要としないマクロ(例:name マクロなど)はこの形式で使えます。

値が必要な場合は、次のように記述します。

<!{macro_name}={value}>
  • macro_name の後に = を付け、値を指定します。
  • 例:<!score=money> のように、スコア名を明示できます。
  • {value} には ESON を使用可能です。
マクロの内部動作(技術的な話)

マクロの基本動作

マクロは必ず <! で始まり、> で終わります。

<!if=[0<<!calc=<!score=money>+100>,<!name>はお金持ちだ!,<!name>は借金している!]>

マクロは決してただ左から右に評価するわけではありません。 深いものから評価されていきます。
実際に前述したマクロがどのように評価されていくのかトレースしてみましょう。

  1. score=money が評価され、スコアが -120 だとします。
<!if=[0<<!calc=-120+100>,<!name>はお金持ちだ!,<!name>は借金している!]>
  1. calc が評価され、-120+100 が計算されます。
<!if=[0<200,<!name>はお金持ちだ!,<!name>は借金している!]>
  1. name が評価され、Notch だとします。
<!if=[0<200,Notchはお金持ちだ!,Notchは借金している!]>
  1. if が評価され、0<-20 が負であるため、Notchは借金している! が選択されます。
Notchは借金している!

実際に経過を表示しました。
トレース結果
このような結果は、設定 > 基本設定 > デバッグ を有効にすることで誰でも確認することができます。
鋭い方はお気づきかもしれませんが、Nameマクロは一度の評価で済んでいます。
これは、評価されたマクロを文字列に置き換えるとき、同じ <!name> を全て置き換えるためです。
例えば文字列内に <!tag=rank> が 100 個あった場合、<!tag=rank> の評価は一度のみ行われ、<!tag=rank> が 100 個全て Example に置き換えられます。

マクロのパース

内部的には、マクロは2種類に分けられます。

  • 値を必要としないマクロ<!name> のように、値を必要としないマクロです。
  • 値を必要とするマクロ<!score=money> のように、値を必要とするマクロです。

値を必要としないマクロ

この場合は単純です。 <!name> のように、<! で始まり、> で終わる部分がマクロとして認識されます。
値を必要としないマクロは原則としてパースされません。

値を必要とするマクロ

<!...> の内側は ESON で記述することができます。
実は、ESON は必ずしも {} で囲む必要はありません。
つまり、下の2つは同義です。

{string=example string, number=123, boolean=true, array=[1,2,3], object={key=value}}
string=example string, number=123, boolean=true, array=[1,2,3], object={key=value}

これを <!...> で囲んだものがマクロというわけです。

<!score=money>

このScoreマクロは {score=money} という ESON として処理されます。

// これは JavaScript のコードです
const macro = "<!score=money>";
const object = ESON.parse(macro.slice(2, -1));
const score = object.score;
console.log(score);

実際はこんな単純ではありませんが、マクロは概ねこのように動作しています。
マクロのコードは src/lib/Macro.ts にありますので、興味がある方はぜひ見てみてください。

マクロを活用することで、より柔軟で保守性の高いコマンドを書くことができます。

おわりに

マクロは Commander API の中でも非常に基本的かつ強力な機能です。
使いこなすことで、より効率的なコマンド記述が可能になります。

慣れてくると「マクロがない世界には戻れない…」なんて声も聞きます。