マクロ / Macro
マクロとは?
「マクロ」 は、Commander APIが提供する便利すぎる魔法のような機能のひとつです。
面倒だった長いコマンドも、マクロを使えばスッキリ簡潔に。ほら、コマンド職人たちの肩こりも軽くなってきた気がしますね。
試しに、マクロが何者なのか見てみましょう。
/titleraw @a actionbar {"rawtext":[{"selector":"*"},{"text":"'s money: "},{"score":{"objective":"money","name":"*"}}]}
このコマンドは、Commander API を使わずに実行でき、例えば money スコアが 100 の Notch に対しては Notch's money: 100 と表示されます。
正直なところ、長くて見にくい…まるで古代の呪文のようです。魔法使いも苦労しそうなこの冗長さ、誰が望んだのでしょうか?
では、実際に実行してみましょう。
あっ、借金!? たぶん投資に失敗しただけです。
さあ、これをマクロで書き直してみましょう。
/execute as @a run scriptevent capi:actionbar <!name>'s money: <!score=money>
このように、マクロのおかげでコマンドが短く、見やすくなりました。
<!name> や <!score=money> のようなマクロが使われています。
これで長くて複雑だったコマンドも、圧倒的に読みやすく・書きやすくなります。
とはいえ、execute のおかげで結局コマンドが長くなってない?と一瞬不安になりますが、
実際には自由度が増えて管理もしやすくなるので、全然アリです。
これも実行してみました。
あら不思議、マクロを使えば借金も肩こりも無くなりましたね。
構文
マクロは以下のような構文で記述します。
<!{macro_name}>
<!で始まり、>で終わる部分がマクロです。macro_nameには使用するマクロの名前を記述します。- 値を必要としないマクロ(例:
nameマクロなど)はこの形式で使えます。
値が必要な場合は、次のように記述します。
<!{macro_name}={value}>
macro_nameの後に=を付け、値を指定します。- 例:
<!score=money>のように、スコア名を明示できます。 {value}には ESON を使用可能です。
マクロの内部動作(技術的な話)
マクロの基本動作
マクロは必ず <! で始まり、> で終わります。
<!if=[0<<!calc=<!score=money>+100>,<!name>はお金持ちだ!,<!name>は借金している!]>
マクロは決してただ左から右に評価するわけではありません。
深いものから評価されていきます。
実際に前述したマクロがどのように評価されていくのかトレースしてみましょう。
score=moneyが評価され、スコアが -120 だとします。
<!if=[0<<!calc=-120+100>,<!name>はお金持ちだ!,<!name>は借金している!]>
calcが評価され、-120+100が計算されます。
<!if=[0<200,<!name>はお金持ちだ!,<!name>は借金している!]>
nameが評価され、Notchだとします。
<!if=[0<200,Notchはお金持ちだ!,Notchは借金している!]>
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 の中でも非常に基本的かつ強力な機能です。
使いこなすことで、より効率的なコマンド記述が可能になります。
慣れてくると「マクロがない世界には戻れない…」なんて声も聞きます。