この記事は、Minecraft Command Advent Calendar 2024 13日目の記事です。
目次
はじめに
データパックって何?
知らない人はいないほど有名になったゲームなMinecraft。ブロック積んだりするサンドボックスゲームなのですが、ゲーム内にコマンドというものが実装されており、これで色々指示を出したりすることで、既存のMinecraft(以下、バニラ)にはないアイテムやモブを作ったり、ミニゲームやRPGが遊べるワールドを作ることができます。
そしてこのコマンド、何気にgithubではmcfunctionとして一つのプログラミング言語扱いされています。完全にMinecraftでしか出てこない言語にも関わらずです!
そんなコマンドの詰め合わせがデータパックで、これはMinecraftのワールドに導入することで動作し、これが内部のコマンドを実行することで、アイテムを動作させたりします。
Minecraftには統合版とJava版が存在し、ちょっと記述ルールが違ったり、片方にはあってもう片方にはないコマンドが存在していたりしますが、コマンドの概念自体はどちらのエディションにも存在します。そして、今回この記事で扱う「データパック」はJava版のシステムです。統合版では「アドオン」と呼ばれるまた別のものになります。
そして、そんなコマンドを扱う人たちのことは、マイクラの界隈ではもっぱら「コマンド勢」って呼ばれてることが多いので、この記事でもそう呼びます。(でも他の言語ではJava勢とか呼ばないような…)
…詳しく書くともーっと長くなりますが、大体こんなものです。
Modとデータパックって、何が違うの?
(Modそのものに関する説明はここでは割愛します。マイクラ内だけで収まる話ではなくなってくるので!)
Minecraft Java Editionは、その名前が示す通り、Java言語で記述されています。
なのでModも当然Javaで記述されます。
また、Minecraftの開発元であるMojangから公式にサポートされているわけではなく、ModローダーAPIであるForgeやFabricはMojangとは全然関係のないところが作っているものです。
データパックはバニラでサポートされているので導入もワールドフォルダの中にある"datapacks"ってフォルダにダウンロードしてきたデータパックを放り込むだけで動作しますが、Modはバニラのマイクラではサポートされていないので、Modを読み込めるようにするModローダー(前提Modなどとも呼ばれます)を導入して、更にそこから目当てのMODを入れる感じになるので、若干導入が手間です。
大雑把に言えば、データパックはバニラの機能で作られたもので、MODは違う、くらいの認識でいいはず。
コマンドにはできないこと
大体この辺ができない、ニガテ
- 完全に新規のものを作ることはできない
- バニラで実装されているものを変更することはできない
- クライアント側の処理をいじることはできない
- 結局コマンドの限界には縛られる
もっとある気もしますが、とりあえずそれぞれを解説してきます。
コマンドでは、完全に新規のものを作ることはできない
「待てよ、データパックで新しいアイテム作ったり、新しいモブ作ってるの見たことあるぞ」って思った人もいるでしょう。
ですがアレ、実はバニラのMinecraftに既にあるものを作って…誤解を恐れずに言うなら、それっぽく見せているだけに過ぎません。
例えば…自分の動画の宣伝みたいになってしまうのですが、私はこういうものをコマンドで作りました。
弾丸を発射する銃で、変形して剣にもなります。今回は例として銃弾の発射処理について触れます。
このアイテムも、結局バニラにあるものの見た目や名前を変えたものでしかありません。このアイテムはこういうふうに見えていますが…
アイテムの見た目を変えたりするリソースパックをオフにし、ついでにアイテムのIDを表示するとこの通り
銃に見えていたものは実はMinecraftに既にあるクロスボウの名前や見た目を変えたものであることが分かると思います。
コマンドにはスコアボードと呼ばれる特定の場合に増えたりする変数的なものが存在するので、このアイテムの場合は「特定のタグが付与されているクロスボウを手に持っている」とき、「クロスボウを発射した時に増えるスコアボードが1以上だったら」という条件の場合に弾を発射しています。本当はもっと散らかった処理ではあるのですが、わかりやすく言うとこうです。
モブなどの場合も、透明化させたモブにリソースパックで増やしたモデルを追従させたり被せたりすることで新しいモブの追加を実現しているので、中身のモブの特性を引き継いだりしてしまいます。ゾンビだったらアンデッド特攻が効く、といった感じで。
完全に新規の動作をしているものを見たことがあるかもしれませんが、あれもモブのAIを完全にオフにした上で、移動や攻撃といったAIを完全にコマンドで作ることで実現しています。
今回の場合だと、飛んでいく弾丸はmarkerと呼ばれる完全に透明で当たり判定すらないエンティティに、パーティクルを出しながら前方にテレポートし続け、眼の前にブロックがあったら消える、他のモブがいたらダメージ処理に移行する、といった処理を全部コマンドで実行させることで実現しています。矢みたいな感じで弾丸ってエンティティを新しく作ったわけではないのです。
コマンドは、バニラで実装されているものを変更することはできない
先述のものに近いのですが、バニラの処理をコマンドで変えることはできません。
モブなんかを例にすると、スケルトンは弓を使えるけど、ゾンビは弓を使えませんよね?
ゾンビに弓を持たせたときの動作を全部コマンドで書けば使わせられないこともないですが、それでも結局ゾンビのAIに弓を使わせているわけではないでしょう?
さっきのアイテムの場合だと、装填されたクロスボウを持つと腕を前方に構えるのですが、その特性は他のアイテムには与えられないのでわざわざクロスボウを使っていました。
コマンドは、クライアント側の処理を変更することはできない
少々ややこしい話になるので詳しくは割愛しますが、Minecraftの処理はクライアントとサーバーに分かれています。
すごく大雑把に言えば、クライアントで完結している処理は他人には見えないくらいの解釈でもOKです。
全員に見えるようにするためには、サーバーにその処理の情報を送らないといけないのですが、逆に言えばそのプレイヤーにだけ見えてればいいものは、サーバーに送らなくていいわけです。
分かりやすいものだと、望遠鏡を使うと画面がズームする、といった処理は実はクライアント側で完結しています。プレイヤーが他のプレイヤーを見たとして、その人の一人称視点がどうなっているかは知る必要がない(というか知る由もない)ので、サーバーには送っていないわけです。そして、そういうものはコマンドでは変更ができません。
コマンドはとりあえず書かれた指令を一回サーバーに送ってから実行しているので、クライアント側にだけ見える!みたいなものを作ることは苦手としています。一部例外は存在しており、例えば、煙やキラキラしたエフェクトを出すのに使うparticleコマンドは、そのパーティクルが誰に見えるかを指定することが可能ですが、これも結局サーバーに「そのコマンドが実行された」というパケットが送信されているようです。
コマンドは、結局コマンドの限界に縛られる
身も蓋もなさすぎる
最終的には開発が用意してくれたコマンドの限界は超えられません。
コマンドを扱う人たちはまるで魔法のようにいろんなことをしていますが、アレも結局コマンドの限界は超えていません。
プログラミング出来る人向けに言うなら、コマンドにおいては基本的な計算(1+1とか)をするのすらちょっと面倒だったりします。この手の計算はこれまたスコアボードを使って行うのですが、計算に使う数値を一々定義しないといけなかったりします。
また、コマンドではプレイヤーのデータを直接書き換えることができません。基本的にあらゆるものがデータ駆動なMinecraftではこれは致命的といってもいいでしょう。
書き換えられないと何ができないかと言うと、たとえば周囲のモブを炎上させる処理を作ったとして、その場合はプレイヤーには火がつけられません。
マイクラではモブの動きはMotionというデータで管理されているので、これを書き換えると大ジャンプさせたりできるのですが、プレイヤーにはそれができません。(ちなみにこれについては、去年ちょっと解説しました)
プレイヤーの扱いには何かと苦労するのがコマンドです。データ書き換えコマンドにプレイヤーを対象にできないのはMojangがあえてそういう制限をかけているからで、技術的には可能です。セキュリティの観点だっけ…なんで対象にできないんだろう?
無論、Javaに限界がないって言うわけではないのですが、意外と限界が近いというか妙なところで制限がかかるのがコマンドだと思っています。
MODにできること
…大体のこと全部?
当然Javaにも限界があると思うので、そこには縛られますが、とりあえずさっき言った「コマンドにできないこと」くらいならModはできます。
Modは、完全に新規のものを作ることが出来る
また私の動画で申し訳ないのですが、私はこんなModを作りました
遠距離武器をいくつか追加するModです。やってることだけ見るとコマンド製の銃とあんまり変わりがないように見えると思いますが…
このModに登場するアイテムは見た目や名前を変えたバニラのアイテムではなく、最初からそういう機能を持って作られた完全新規のアイテムです。(遊ぶ人にとってはどちらでも同じではあるけど…)
あと見た目もModのファイル内に同梱されてるのでリソースパックを入れずともこの見た目になります。
あとこのModではパーティクルを増やしたりもしています。
このModではやっていませんが、新規のエンティティを作ることも当然できます。
例えば新しい矢を作ってそれを発射するとか。
Modは、バニラで実装されているものを変更することができる
バニラのソースコードにMixinという機能で…書き足し?割り込み?を行うことで、バニラに実装されているものの処理を変更することも可能です。
私のModの場合だと、バニラの矢を撃ちたいけどその矢で敵の無敵時間を貫通したいな…と思ったので、バニラの発射体に新規のNBTを追加し、そのNBTがTrueならヒット時の無敵時間を無視するようにしたりしています。
コマンドやってる方なら、バニラの矢はこんなNBTを持ってないし、エンティティに自由なNBTを持たせることもできないということはご存知だと思います。
Modは、クライアントの処理を変更することができる
このModだと、弓を構えた際の移動速度低下を無効化して、通常の速度で移動しながら構えたり、構えると強くズームしたり、意外なところだとクロスボウのように構える、といったところが該当します。
地味なところですが、コマンドでは基本的には不可能です。裏技じみた方法で実装することもできますが、そんなの健全じゃないよね(?)
また、世界がどのように見えているか、もクライアント側の処理です。
マイクラの世界に美しいシェーディングを追加する、俗に言う影Modなんかは、そこを変更しているものだったりします。だから影Mod入れてもバニラサーバーに参加できるし、他の人に影響もないわけですね。
世界がどのように見えているか、にはモブの見た目や自分の見た目も該当するので、Modなら既に存在するモブの見た目をモデルごと変えたりすることもできます。モブ全部人間にするとか。他人にはModを入れていないと見えないのですけどね。幻覚みたい
Modは、コマンドの限界に縛られない
何を言っているんだ?
ふざけているようで、コマンドと比較した場合はそうなのだから仕方ない。
プレイヤーのデータを変えることもできるので、プレイヤーを好きな方向にかっ飛ばしたりできます。バニラだとトライデントなどがやっているやつです。
その気になれば、自分で新しいコマンドを作ることもできるはずですし、一部コマンドにかけられているプレイヤーを対象とできない制限も外せるでしょう。見てるかコマンド勢のみんな!
コマンドとMod両方やって思ったこと
コマンドだと簡単だったことが難しいよ~!
コマンドではできないことができるのは嬉しいものです。
ですが、いいことばっかりでもないなとは感じています。
例えば、コマンドだとすぐできることが、Javaだと長いコードになることがあったりしました。
例えば以下は目線の先のちょっと横にパーティクルを出す処理なのですが…
コマンドだとこう
execute anchored eyes run particle minecraft:explosion ^-1 ^ ^3
Modで実装したときはこんな感じです
void shootParticle(World world, LivingEntity player) {
// プレイヤーの視線方向を取得
Vec3d lookDirection = player.getRotationVec(1.0F);
// オフセット
double offsetRight;
double offsetUp = -0.1; // 上に0.1ブロック分オフセット
// 使用した手側にずらす
Hand activeHand = player.getActiveHand();
if (activeHand == Hand.MAIN_HAND) {
offsetRight = 0.3; // 右に0.3ブロック分オフセット
}
else {
offsetRight = -0.3; // 左にに0.// 3ブロック分オフセット
}
// 右方向のベクトルを取得する(視線ベクトルとY軸の外積)
Vec3d horizontalDirection = lookDirection.crossProduct(new Vec3d(0, 1, 0)).normalize();
Vec3d verticalDirection = horizontalDirection.crossProduct(lookDirection).normalize();
// 複数のパーティクルを発生させるループ
for (int i = 0; i < 1; i++) {
double distanceToTarget = 0.7; // プレイヤーから目標地点までの距離
double particleX = player.getX() + lookDirection.x * distanceToTarget
+ horizontalDirection.x * offsetRight
+ verticalDirection.x * offsetUp;
double particleY = player.getEyeY() + lookDirection.y * distanceToTarget
+ horizontalDirection.y * offsetRight
+ verticalDirection.y * offsetUp;
double particleZ = player.getZ() + lookDirection.z * distanceToTarget
+ horizontalDirection.z * offsetRight
+ verticalDirection.z * offsetUp;
double offsetX = 0;
double offsetY = 0;
double offsetZ = 0;
// 視線の先にパーティクルを追加
world.addParticle(ModParticleTypes.SHOOT,
particleX, particleY, particleZ,
offsetX, offsetY, offsetZ);
}
}
正直自分でもいまいちやってることは理解できていないのですが、とりあえず計算とかして目線先ちょっと横の座標を求めて、そこにパーティクルを出しています。
コマンドはこういう長ったらしいことを簡単にできるようにしたものだと思うので、それに頼らない以上は自分でやる必要が出てくるのでしょう(Modにもライブラリとかあるかもだけど)
結局アップデートに追いかけ回される
コマンドとアップデート
Minecraftは定期的にアップデートが入るゲームで、そしてコマンドなどの、通常のプレイでは基本的に使わないような、技術的な面も頻繁にアップデートされます。
そうするとできることが増えたりスマートな実装になったりするのですが、
光があれば、そこにはまた闇もあるのです。
この手の更新には破壊的な変更がつきもので、アップデートによって、以前のコマンドが動かなくなった!なんてことが頻繁に発生します。私もアップデートで動かなくなり、更新が追いつかなくなったデータパックを大量に抱えています。
比較的最近の話だと、1.20.4→1.20.5の更新で、アイテムのデータがNBTからコンポーネントというデータの管理に変更され、それ以前のアイテムに関するコマンドは全部滅ぶという凄まじい出来事が起きました。私の抱えているデータパックも、1.20.5への更新を諦めたものが多いです。
もちろん悪いことばかりではなく、できることは凄まじく増えました。
創造の前には、破壊があるのです
MinecraftのアップデートとMod
…おっと、Modの話でした。Modの場合はJavaで記述するので、無論コマンドへの更新の影響は受けないのですが、当然Minecraftのアップデートによる実装の変更の影響は受けます。
例えば「アイテムのデータがNBTからコンポーネントというデータの管理になった」と先述しましたが、これによってModも当然実装の変更を迫られます。Modのアイテムも、根本的にはマイクラバニラのアイテムと同じ実装をしているわけなので、結局バニラ側のルールが変われば、Modのアイテムも実装を変えざるを得ないのです。
また、コマンドなどの変更があった場合は、Minecraftのアップデートログにそのことが記載されますが、内部コードの変更があったとしてもアップデートログには記載されません。まぁ当然です。一般プレイヤーが知る必要ないことですし。
コマンドがアップデートで動かなくなった!となっても、公式のアップデートログを見れば何がどう変わったかが書いてあるので、以前のコマンドを修正する場合もそれを頼りにできるのですが、Modの場合はソースコードがどう変わったかなんて公式は教えてくれないので、アップデートによって動かなくなったのなら、なぜ動かなくなったのかを、ソースコードから自分で読んで判断する必要があります。まぁ、FabricやForgeの開発チームなんかも「破壊的な変更があったよ」とか、「このメソッドは古いから廃止したよ」といったことは教えてくれるので、全てが自力になるわけでもないのですけどね。
また、データパックは基本的にはコマンドの詰め合わせではあるのですが、コマンドが全てではないのです。
例えば、アイテムのレシピ、進捗などといったものはコマンドではなくjsonで記述します。こういったものもデータパックに含まれており、Modもこの辺はデータパックで実装します。つまり、Modの中にはデータパックが入ってることがあります。なので、ルートテーブルや進捗やタグなど、コマンド以外のデータパックの変更が入った場合は結局、コマンドを使うデータパックと同じ対応が必要となります。
…つまり、結局何にせよアプデには追われます。
結局完成品がコマンドのときとあんま変わらない
私はデータパックをメインとして数年間データパックを作ってきました。Mod作り始めたのは4ヶ月ほど前です。
そんでもって私はJavaが全くわからない状況からMod開発を始めるという無茶な行為に出たのもあってか、完成品がなんだか…地味なんですよね。
新しいことを学ぼう、というつもりでMod開発をはじめたとはいえ、結局コマンド使ってた時と完成品の出来があまり変わらないのであれば、一体なんのためにMod開発にしたんだ?と思うことがあります。
そして完成品の出来が変わらないとなると、それを遊ぶ側の印象は「あれ?コイツ前より作るもん地味になったな」とかになりかねないんですよね。ユーザー側にとっては何で作られてるかななんて気にしませんからね。
データパック専用のリソースパックいらないの楽
コマンド製のデータパックでは、バニラにない見た目のアイテムなどを増やしたい場合、リソースパックを使うことになります。基本的にはバニラのコンテンツのテクスチャやモデルを変更するのに使うのですが、「特定のデータを持っているアイテムはこの見た目になる」といった設定が可能です。
ですが、データパックとリソースパックは別であり、データパックを導入してリソースパックも導入する、という手間が発生します。私は慣れてるのですが、慣れていないユーザーは両者をごっちゃにするパターンや、リソースパックを忘れて見た目が変わらないとか、そういうことを起こしがちなようでした。
ワールド単位で配布するならリソースパックは同梱して自動読み込みさせられるのですが、好きなワールドに導入可能なデータパックだとそうもいかないのですよね。
コマンド勢向けの説明にはなりますが、現在はアイテムのモデルをパスで指定可能なので、リソースパック複数入れてると違うCustomModelDataを参照して全然違う見た目になる、といった問題が起きづらくなりましたが、マルチプレイ時にサーバーでリソースパックを用意しないといけない場合、リソースパックは一個しか送れないので、違う作者のデータパックを遊びたい、でも全部別のリソースパックが必要だな…となった場合、サーバー側でリソースパックを合成しないといけないですよね?こんなの手間じゃん?
統合版Minecraftはアドオン内にリソースパック入れられるようで、マルチプレイ時もそれを送ってるからJava版もそうしてくれればいいのにね
Modは内部にアセットも入れられるからこの辺の心配がなくていいのは嬉しいです。…でも、マルチプレイだと参加者側もModを入れないといけないことを考えると、なんか結局手間が別のところに移動しているだけな気もしてきた。マズイネ!
Modだとハック的な実装をしなくていい
…少なくとも現状はModでそういう実装をする必要には迫られていません…多分。多分凝るとヤバい実装登場したりするんでしょうけど、そのヤバい実装はプログラミングのルール的な感じでヤバいみたいな感じだと思うので。
私がここで言うものは、コマンドだと普通の方法ではできないことを裏技的な方法で実装することがあるのですが、それって変じゃね?っていう位の話です。以下は私がもっと普通にやらせてくれって思ってるコマンドあるあるです。
プレイヤーを任意の方向に移動させたい場合、じゃあモブをめちゃくちゃ圧縮して押し出し判定で飛ばそうだとか、クリーパーの爆発を当ててふっとばそう!
(クリーパーの爆風でプレイヤーを飛ばすライブラリに関しては、私の記事で触れています)
プレイヤーを燃やしたい場合は、じゃあ火属性エンチャントの武器を持った見えないモブを、プレイヤーの位置に一瞬だけ出してそいつに殴って着火させよう!
(@Mononobe氏の記事がちょうどこれについて触れています)
プレイヤーの手持ちアイテムのデータを変えたい場合は、一回シュルカーボックスにプレイヤーの手持ちアイテムを放り込んで、そのボックスに入っているアイテムのデータを変更してから、それをプレイヤーの手持ちに戻す!
(@crops121氏の記事で応用技として紹介されています)
…まだまだありますが、この辺にしておきます。コマンドって、基本的にプレイヤーのデータを直接変更することができないので、なんかこういう方法を使う必要に迫られます。特に3つ目、一回別のものを経由したらOKなの、なんか三店方式みたいだよな
Modだと当然こんなことしなくていいので、個人的には気持ちが楽です。例えば手持ちのアイテムのデータを変えたいなら、アイテム内にそう書けばいいのですから。
以下はModで追加したBurstStackというコンポーネントを加算していく処理です。アイテム内にこれ直接書けるのうれし~。
// サーバーのみ
if (world instanceof ServerWorld) {
// チャージカウントが進む
if (useTick == 10 | useTick == 15 |useTick == 20 | useTick == 35 | useTick == 40 | useTick == 45 | useTick == 60 | useTick == 65 |useTick == 70 ) {
int count = stack.getOrDefault(ModComponents.BURST_STACK, 0);
stack.set(ModComponents.BURST_STACK, ++count);
}
}
ただ、私Javaのことまだ分からないことだらけで、友人やChatGPTに聞きまくって作ってるので、自分でも分かっていないコードを書いていることがあります。そういやなんかMixin周りで凄い事してた記憶があるな…。
データパック作りで学んだことがちゃんと活かせている
先述の通り、データパックはコマンドだけではなく、いろんなものも内包しています。
なのでレシピや進捗といったものや、アイテムの見た目の設定方法といったものは、以前の知識をそのまま活かせました。
今までのことが無駄になっていない!嬉しいね。
俺は強くなっているぞ
プログラミングなんて全然やったことなかった私にとって、Modのソースコードなんてものは魔法と同じ、何が書いてあるのか分かったもんじゃない、といった感じだったのですが、自分で作るようになってからはある程度読めるようになってきました。まだまだわかんない点も多いのですが、オープンソースのModを見に行って参考にできるようになったというのだいぶ進歩したなと思っています。
あと、Minecraftのソースコードを見るようになった関係で、バニラだとどうやって実装されているのかが理解できるようになりました。バニラのソース読んでみるとなかなか興味深かったです。
最後に
できることで言ったらまぁModのほうが多いんですが、今のMinecraftは度重なるアップデートで、コマンドだけでも
どんどんできることが増えています。リソースパックなくてもアイテムの色が変わるなんて、昔じゃ考えられないネ。
コマンド、Java共に経験0の状態からMinecraftのコンテンツを作りたい!という方は、個人的にはJavaはModの開発以外にも、それこそお仕事なんかにも役に立つので、個人的にはJavaをオススメします。
だけど、Java…というかMod開発は成果物がなかなか出来上がらないので、正直モチベーションに繋がりづらいというのはあります。そういう点ではコマンドのほうが成果物がすぐできるので、モチベーションに繋がりやすく、続けやすいとも思います。チャットコマンドから一発で実行できる短いコマンドだけでも、結構面白いことできますからね。
/execute at @e[type=!player,distance=..10] run summon tnt
例えば、これを実行するだけで半径10ブロック内のモブを爆殺できますし、これだけでも魔法みたいで面白いと思います。子供の頃とかはこういうアホなのが楽しかったし、今でも面白いときがある
そして、このコマンドをアイテムから実行できるようにしたいとか、そのアイテムの使用時に音を追加したいよね、って感じでどんどんステップアップしやすいのはModだと思います。初歩的なものだとゲーム内でコマンドブロックを置いて実装が可能なので、実行順の関係などが分かりやすいと思いますし。
…まぁつまり、あなたのモチベーションや目的に合わせて好きな方を選びましょう。なんだかんだ両者共にクオリティの高いものを作ることはできます。できることが多いけど大変なのはModで、できることに制限はちょっとあるけど手軽なのはコマンドです。