Minecraft mcfunction トランスコンパイラについて調べた

mcfunction で if-elseやループ、変数代わりのスコアボード等を扱ってるとハゲそうだと思う人向け。トランスコンパイラ(またはトランスパイラ、ジェネレータ、プリプロセッサ)についてです。

コマンドの知識がなくても使えるようなトランスコンパイラは現時点では存在しないので、どれを使うにせよコマンド学習はスキップできません。

これらのうち mcscript と EasyDatapacks の if-else を中心にテストしました。


mcscript

https://github.com/Stevertus/mcscript

データパック生成用の言語。Node.js が必要。

  • 関数、変数、定数
  • 配列、マップ(どちらも生成時のみ)
  • if-else/switch/for/for-each/do/while
  • 算術/比較/論理演算子
  • Raycasting
  • Modal - コマンド文字列生成テンプレートのようなものでJavascriptも使用可
  • VSCodeAtom、Notepad++ でシンタックスハイライト対応

一見良さそうに見えるが if-else によって生成されるコマンドに問題がある。

if ('entity @a[tag=test]') {
  /tag @a remove test
  /tp @a ^10 ^ ^
} else {
  /tag @a add test
  /tp @a ^ ^ ^10
}
execute if entity @a[tag=test] run tag @a remove test
execute if entity @a[tag=test] run tp @a ^10 ^ ^
execute unless entity @a[tag=test] run tag @a add test
execute unless entity @a[tag=test] run tp @a ^ ^ ^10

if の条件がブロック内部の全てのセレクタにくっついてしまうので、ブロック内のコマンドが増えるほどセレクタの条件も連続することになる。 さらに悪いことに if の結果が if ブロック内で変更された場合 else ブロックも実行されてしまう。

EasyDatapacks

https://github.com/emorgan00/EasyDatapacks

Python 風のデータパック生成言語。Python が必要。

  • 関数(エンティティ引数可)、変数
  • if-else/repeat N/for-each/while/break/continue
  • 算術/比較演算子

mcscript より機能が少ないように見えるが十分。 全コードを一つのファイルに収めることができる。 Minecraft コマンドの文法と Python 風インデント構造の相性がとても良い。

def example:
    if block 0 0 0 diamond_ore:
        tellraw @p "Yay! Diamonds!"
    else:
        tellraw @p "Maybe another time."
# example.mcfunction
execute if block 0 0 0 diamond_ore run function test:example.e0
execute unless entity @e[tag=main.example.e1.ELSE] run tellraw @p "Maybe another time."
kill @e[tag=main.example.e1.ELSE]

# example.e0.mcfunction
execute unless entity @e[tag=main.example.e1.ELSE] run summon area_effect_cloud 0 0 0 {Age:-2147483648,Duration:-1,WaitTime:-2147483648,Tags:["main.example.e1.ELSE"]}
tellraw @p "Yay! Diamonds!"

if-else のたびに mcfunction を生成するため mcscript よりも論理的に正しいコマンドを出力する。しかし summon/kill を使用するためオーバーヘッドの問題がある。

if ブロック内で再帰しようとするとエラーになるが、これは if の評価結果がスタックされないから。 しっかりエラーになるのは良いと思う。

変数の計算は EasyDatapacks がブラックボックス化したエンティティにおいてのみ可能であり、 自作エンティティのスコアボード計算には対応していない。 そのためエンティティのスコアボードを計算したい場合は通常の Minecraft コマンドで書く必要がある。

インストールに pip を使うので Windows だとハマりやすい。

Command Block Assembly

https://github.com/simon816/Command-Block-Assembly https://www.reddit.com/r/Minecraft/comments/7fnzv4/i_wrote_a_c_compiler_that_creates_minecraft/

Cまたはアセンブラ風コードを mcfunction にコンパイルする。Python または windowsバイナリで配布。

mcfunction を楽に書くというよりは Minecraft ゲーム内でテトリスなんかを再現したい人向け。 Minecraft のコマンドを使用するためにはマクロを定義していく必要がある。

PowerFunctions

https://github.com/Eisenwave/powerfunctions

mcfunction コンパイラ。制御構造は消極的で if/while 構文は Python 風。kotlin で書かれておりコンパイルが必要。

mcpp

https://www.npmjs.com/package/mcpp

mcfunction のプリプロセッサで npm からインストールする(おそらく Node.js が必要)。

機能は if/else とマクロ定数のみ。

MCJS

https://github.com/OpenMapmaking/mcjs

Javascript を使用して mcfunction を生成する。Node.js が必要。

エンティティの変数と for each、コマンド文字列のテンプレートのみ。

mcfunction の替わりに Javascript で書けるのではなく mcfunction ジェネレータを書くためのもの。

mcs (Minecraft Script)

https://github.com/PandawanFr/mcs

javascript 風のプリプロセッサでWebエディタがある‥‥という触れ込みだが作りかけで放置されている模様。