注目キーワード

【革命】オリジナルのコマンドを作る方法を徹底解説 – ScriptAPIでアドオン制作【マイクラ統合版】

はじめに

マインクラフトには、「コマンド」と呼ばれる機能が存在します。コマンドとは、ゲーム内で特定のテキストをチャット欄に打ち込むことで、ゲームを制御できる機能のことを指します。一般的にはチャットウィンドウを表示し、スラッシュから始まる一連の文字列を打ち込むことでコマンドは発動します。あるいは、コマンドプロンプトや各種アドオンの.mcfunctionファイルによって実行することもできます。コマンドは大変便利なもので、マインクラフトのプレイヤーなら一度は触ったことはあるのではないでしょうか?

これは、コマンドの一例で、giveコマンドと呼ばれるものです。このようにマインクラフトには多種多様なコマンドが予め用意されていて、それぞれのコマンドに合わせて正しい構文を入力することによって、ゲームをスクリプト上で改変することができます。

コマンドについての詳細はMinecraft Wikiが詳しいです。

コマンドの欠点

このようにコマンドは大変便利なものである一方で、欠点もあります。それは、予め定義されているコマンドしか使えないということです。勿論、デフォルトで定義されているコマンドは非常に多いので、これが問題になることはあまりないのですが、ちょっと凝ったことをしようとするとこれが問題になり得ます。できることなら、自分でコマンドを作って自由度を上げたいものです。本稿では、ScriptAPIを用いてコマンドを自作する方法について一から徹底解説します。

本ページについて

本ページの前半では、ScriptAPIを使用する上での環境構築について言及したうえで、後半ではコマンドを自作する方法について解説します。既に環境構築についてご存じの場合は、この節を飛ばしてください。以下の目次をクリックすることでジャンプできます。

また、本記事について解説したYoutube動画を作成しました。こちらより視聴できます。

環境構築

そもそも、ScriptAPIとはマインクラフトの統合版において、プログラミング言語(Javascript)を用いてゲームシステムをカスタマイズできる機能のことを指します。Javascriptの知識さえあれば、マインクラフトのシステムをある程度いじることができるんです。ScriptAPIに関する詳細についてはこちらの記事が詳しいです:

さて、このページではScriptAPIを使用する上での環境構築を行っていくわけですが、まずは必要となる用語の説明から入ります。

用語の定義

これらが私が独自の解釈によって説明したものですので、もし間違っている場合にはご指摘ください。

用語 意味
関数 ある入力に応じて一意の出力を行うプログラム
モジュール プログラムを動作させるための要素・部品
JavaScript プログラミング言語の一種で、主にWebページ上で用いられる

必要なソフト

まず、環境構築にあたって必要なものを提示します。以下のリンクよりそれぞれをダウンロードできます。

必要なソフト名 ダウンロード先 備考
Minecraft amazon 言わずと知れたゲームソフト。Win10版が望ましい。
vscode https://code.visualstudio.com/ コードの記述に特化したテキストエディタ(無料)。既に別のテキストエディタを持っている場合は不要。
node.js https://nodejs.org/ javascriptをパソコン上で実行するためのツール(無料)。ダウンロード後、msiファイルを実行。

必要なソフトのうち、Minecraftのみ有料で、その他は無料です。テキストエディタ(vscode)はなくても最悪できますが、あったほうが断然望ましいです。また、ScriptAPIはjavascriptに依存するので、このjavascriptをPC上で実行するためのnode.jsは必須です。

node.jsについては、別の方の記事ですが、こちらが非常に参考になりました。一応紹介いたします。

https://qiita.com/non_cal/items/a8fee0b7ad96e67713eb

以下では、これらのインストールを前提に、手順について説明します。

手順

まず、com.mojangフォルダ内のdevelopment_behavior_packs内に移動し、新規にフォルダを作成します(名前は何でもいいです)。これがアドオンの作業フォルダとなります。com.mojangフォルダの場所については以下で説明します。既にご存じの場合は読み飛ばしてください。

com.mojangの場所

フォルダcom.mojangは

C:\Users\(ユーザー名)\AppData\Local\Packages\Microsoft.MinecraftUWP_8wekyb3d8bbwe\LocalState\games\com.mojang

に存在します。エクスプローラー上で、「AppData」というファイルは隠しファイルなので、これを選択するためには、エクスプローラーの「表示」設定から隠しファイルのチェックをオンにしてください。または、「ファイル名を指定して実行」というアプリを起動し、
%LocalAppData%\Packages\Microsoft.MinecraftUWP_8wekyb3d8bbwe\LocalState\games\com.mojang
と入力することでも開けます。

このcom.mojangの中にdevelopment_behavior_packsフォルダが存在するので、これを開いて新規にフォルダを作成してください。

manifest.jsonの作成

次に、新規に作成したアドオンのフォルダ内に移動し、「manifest.json」というjsonファイルを新規作成してください。右クリックして「新規作成」→「テキストドキュメント」を選択し、作成されるファイルの名前を「manifest.json」に変更すればOKです。

「manifest.json」はこのアドオンの要項(名前やidなど)を記述したファイルで、これによってマインクラフトがアドオンを認識できるようになります

manifest.jsonの内容は以下の通りです。作成したmanifest.jsonを、先ほどダウンロードしたvscodeなどを用いて開き、以下をコピー&ペーストしてみましょう。

{
    "format_version": 2,
    "header": {
      "name": "オリジナルのコマンドを追加するアドオン",
      "description": "コマンドを追加します",
      "uuid": "b1ef9620-a18e-4fa3-bdca-f5f1d3c71c31",
      "version": [0, 1, 0],
      "min_engine_version": [1, 20, 0]
    },
    "modules": [
      {
        "type": "script",
        "language": "javascript",
        "uuid": "b1ef9620-a18e-4fa3-bdca-f5f1d3c71c32",
        "entry": "scripts/main.js",
        "version": [0, 1, 0]
      }
    ],
    "capabilities": ["script_eval"],
    "dependencies": [
      {
        "module_name": "@minecraft/server",
        "version": "1.15.0-beta"
      }
    ]
  }

上のnameやdescriptionはこのアドオンの名前・説明文です。この部分をアレンジしてお使いください。また、2か所あるuuidはアドオン固有の文字列で、重複すると面倒なことになるので以下のジェネレーターを用いて生成・変更することをお勧めします。

https://www.uuidgenerator.net

また、本アドオンにおいては重要なことが一つあります。それは、モジュール「@minecraft/server」のバージョンがベータ版でないと動かないということです。執筆時点で最新のバージョンは1.15.0-betaなのでこのように記載していますが、このバージョンはアップデートによって頻繁に変わります。こちらの公式リファレンスを参考に、適宜最新のベータ版バージョンを入力しください:

https://learn.microsoft.com/ja-jp/minecraft/creator/scriptapi/minecraft/server/minecraft-server?view=minecraft-bedrock-experimental

また、今回はベータ版を使用するので、ワールドの起動時に実験的な機能の「ベータAPI」をオンにする必要があります。

「@minecraft/server」のインストール

続いて、本アドオンでお世話になる「@minecraft/server」モジュールのインストールを行います。タスクバーの検索欄に「cmd」と入力してコマンドプロンプトを起動するか、vscodeのターミナルを起動しましょう。そして、

cd (作業フォルダのパス)

というコマンドを入力します。cdコマンドは、ディレクトリを指定することでディレクトリを移動することができるコマンドです。例えば、アドオンのフォルダ(manifest.jsonがあるフォルダ)が、

C:\Users\User\AppData\Local\packages\Microsoft.MinecraftUWP_8wekyb3d8bbwe\LocalState\games\com.mojang\development_behavior_packs\test_pack

であった場合は、

cd C:\Users\User\AppData\Local\packages\Microsoft.MinecraftUWP_8wekyb3d8bbwe\LocalState\games\com.mojang\development_behavior_packs\test_pack

となります。フォルダの場所(特にユーザー名)は各自異なるので、ご自身でパスを確認してください。エクスプローラーの上部欄より確認できます。

上記のコマンドの入力が完了したら、続いて以下のコマンドの入力を行いましょう。

npm install @minecraft/server

コマンド「npm」に関してエラーが発生した場合、node.jsのインストールが完了していない可能性があります。エラーが発生している場合はこの点を確認してみることをお勧めします。

main.jsの作成

以上が完了したら、アドオンのフォルダ内で「scripts」というフォルダを作成しましょう。そしてその中に「main.js」というjavascriptのファイルを作成します。ここにスクリプトを記述することになります。このjsファイルは、vscodeを始めとするテキストエディタで開くことができます。

コマンドを自作

いよいよ準備が整いました。次に、コマンドを自作するためのスクリプトを書いていきます。

コンセプト

コマンドを自作とは言いましたが、本記事ではスラッシュ記号から始まる正規のコマンドを作成するわけではありません。チャット欄を監視し、メッセージに特定のフレーズが含まれていたら何かを実行するという、「疑似的なコマンド」を作成することになります。というのも、正規のコマンドを追加するのはAPIScript上では(現状)不可能だからです。

上記の理由により、今回は、「!」から始まるメッセージが発信されたとき、それを疑似コマンドとみなして何かを実行することにしましょう。

基本編1

まずは、チャット欄を監視して何かを実行する、シンプルな例を示します。

server.world.afterEvents.chatSend.subscribe(ev => {
    if (ev.message == "!killall"){
        ev.sender.runCommand("kill @e[type=!player]");
    }
});

これは、すべてのエンティティをkillする、「killall」というコマンドを追加する例です。afterEventsプロパティのchatSendプロパティは、常にチャット欄を監視し、何らかのメッセージが発せられたときに発火する関数を定義します。

次のif文ではそのメッセージが「!killall」であった場合に処理するスクリプトを定義しています。ここでは、メッセージの発動者(ev.sender)を基に「killコマンド」を実行しています。

実際にこのスクリプトを有効化してワールドを起動すると、「!killall」というメッセージによってモブがすべてkillされることが確認できるでしょう。このように、既存のコマンドの実行を定義づけることができます。

基本編2

同様にして、sendMessage()関数を用いてコマンドの実行時にメッセージを表示することもできます。

server.world.afterEvents.chatSend.subscribe(ev => {
    if (ev.message == "!hello"){
        ev.sender.sendMessage("おはよう!");
    }
});

これは、メッセージ欄に「!hello」と入力すると「おはよう!」というメッセージが返ってくる例です。

このように、様々な処理を行うことができます。

応用編1

これまではチャット欄のメッセージがある文言と完全に一致している場合のみ処理を行う例でした。これでは、引数(オプション設定)を付加することができません。例えば、既存のgiveコマンドは、「give」だけでなく、様々な引数から構成されています

次は、このような引数を設定する方法を示します。

server.world.afterEvents.chatSend.subscribe(ev => {
    if (ev.message.startsWith("!add")){
        let args = ev.message.split(" ");
        ev.sender.sendMessage(`${args[1]} + ${args[2]} = ${Number(args[1]) + Number(args[2])} です`);
    }
});

これは、数字2つを引数としてそれらの足し算を行う「addコマンド」を定義する例です。

if文の中にあるstartsWith()関数は、ある文字列が指定の語句から始まっているかを判定する関数です。今回はこれを用いて、入力されたメッセージが「!add」から始まる場合に処理を行っています。

続いて、メッセージを半角空白で分割し、配列に格納した上で、それぞれの引数を定義した上で、それらの足し算を行った結果をsendMessage()関数で出力しています。

これを一般化すると以下の図のようになります。

このように文字列があったとします。ここで、split()関数を用いると、この文字列を指定の文字で分割し、配列に直すことができます。今回は半角空白で分割するので・・・

このように各文字列が分割され、0、1,2・・・とそれぞれに名前がつきます。これらは配列argsに格納されるので、それぞれはargs[0]、args[1]、args[2]・・・という形で参照できます。

例えば「僕は、山に、行った。」という文章があったとします。これを点で分割すると、「僕は」「山に」「行った。」の3つに分割されることになります。

そして、それぞれの句は0から順番に番号が付与されます。

これを用いることで、今回のように引数を定義することが可能になります。実際にゲーム内で「!add」と入力し、2つの数字を入力すると、以下のようになります。

正常に足し算が行われていることが分かりますね。

そして、これを応用すると引数を無限に増やすことができます。以下は、for文を用いて引数の数字全てを足すスクリプトです。

server.world.afterEvents.chatSend.subscribe(ev => {
    if (ev.message.startsWith("!add")){
        let sum = 0;
        let args = ev.message.split(" ");
        for (let i = 1 ; i < args.length; i++) {
            try {
                sum += Number(args[i]);
            }catch{
                //数字ではないときは何もしない
            }
        }
        ev.sender.sendMessage(`合計は ${sum} です。`);
    }
});

jsでは、「(配列名).length」で配列の要素の数を取得できます。

実際にこれを保存すると、以下のようなことが可能です:

確かに、5つの引数を全て受け入れて合計を出すスクリプトが完成していますね。このように、既存のコマンドでは不可能であったことが可能になるのです。

応用編2

これらを応用すると、「疑似コマンド」で任意のコマンドを実行することができます。デフォルトのexecuteコマンドをイメージしていただくと分かりやすいかと思います。

以下は、任意のティック数だけ遅らせた後にコマンドを実行する、「waitコマンド」を実装する例です。数値とコマンドを引数にとります。

server.world.afterEvents.chatSend.subscribe(ev => {
    if (ev.message.startsWith("!wait")){
        let args = ev.message.split(" ");
        let command = "";
        for (let i = 2; i < args.length; i++){
            command += args[i] + " ";
        }
        server.system.runTimeout(function(){
            ev.sender.runCommand(command);
        },Number(args[1]));
    }
});

チャット欄のメッセージを空白で分割して引数を取得するのは先と変わらないのですが、コマンドの取得方法が若干特殊です。というのも、コマンドそのものに空白が含まれることがあり、コマンド側の引数とwaitコマンド側の引数を区別する必要があるからですね。

これは、40ティック後にgiveコマンドを実行する例です。このような場合、giveコマンド内にある空白は無視して、スクリプト上では以下のように分割・認識する必要があります。

ここでは、for文を用いて3つ目以降の語句を合体することでこれを実装しています。

問題点

ここでは、コマンドを自作する方法について解説しました。しかし、この方法には些か問題点があります。というのも、コマンドの発動がチャット欄に依存するため、コマンドブロック・functionファイルなどを用いたコマンドの自動化が困難なのです。

この問題を解決した、コマンドブロック上で使用可能なオリジナルコマンドの作成方法についてはこちらの記事で解説しています:

上のページでは、「scripteventコマンド」と呼ばれる、コマンドブロックが利用可能な通常のコマンドを用いて、オリジナルのコマンドを作成する方法について解説しています。宜しければそちらもご覧ください。

おしまい

このように、マインクラフトではオリジナルのコマンドを作成することができ、非常に自由度が高いです。皆さんも、オリジナルのコマンドを作ってみてはいかがでしょうか?

こちらの記事もおススメです!

最新情報をチェックしよう!