【統合版アドオン】part-1│究極の機能、ScriptAPIを徹底解説!

スポンサーリンク

初めに

こんにちは、餅わらびすとです。この記事では、ScriptAPI(gametestとも言う)というものを解説します。

ScriptAPIというのは、JavaScriptという言語を使いプログラムしていく、マイクラアドオンの機能です。
複雑な計算、イベントのデータを読み取っての処理…コマンドやJSON系の要素だけではできない機能がたくさんあり、アドオンの幅を広げてくれます。プラグインのようなことも実現可能!

少しでもお役に立つ記事となれば幸いです。

目次
  • マニフェスト
  • ベータバージョン
  • JavaScript
  • リファレンスの読み方
  • よく使われる機能
  • エラー
  • 最後に

~個人的おすすめテキストエディタ~


~前提知識~

  • JSONの構造、用語
  • 基本的な記号の名称
  • マイクラアドオンの基本的知識

マニフェスト

まず、ScriptAPIを使う際にはマニフェストを変える必要があります。

サンプルコードです。

{
    "format_version": 2,
    "header": {
        "name": "ビヘイビアテストBP",
        "description": "ビヘイビアテストBP",
        "min_engine_version": [1,21,10],
        "uuid": "d8229b16-c69a-40f3-baa6-926f96a5ca6c",
        "version": [1,0,0]
    },
    "modules": [
        {
            "type": "data",
            "uuid": "81344285-81fc-44b7-b8da-6f6f61288c4b",
            "version": [1,0,0]
        },
        {
            "type": "script",
            "language": "javascript",
            "uuid": "440ac9d1-d6f8-4eff-a5aa-29ed51b893f5",
            "entry": "scripts/main.js",
            "version": [1,0,0]
        }
    ],
    "dependencies": [
        {
            "module_name": "@minecraft/server",
            "version": "1.15.0"
        }
    ]
}

modules

ScriptAPIを使うマニフェストは、使わないマニフェストと違い、typeがdataのオブジェクトに加えて新しくtypeがscriptのオブジェクトが入っています。
新しいオブジェクトといっても、中のuuidを変える以外はほぼコピペでok。
ただ、entryは実行したいファイルの場所に合わせましょう。

dependencies

ここでは変数や関数などをまとめたモジュールというものの、種類やバージョンを指定するオブジェクトが入っています。
主に使われるモジュールは、ワールドに関する操作ができる@minecraft/server、uiに関する操作ができる@minecraft/server-uiの2つです。
バージョンは複数存在しており、その中でも今回は、最終確認時マイクラバージョン1.21.44時点で最新の安定版バージョンである1.15.0を指定しています。バージョンはアップデートに伴い増えていきますが、過去のバージョンが使えなくなるわけではないので、毎回のアップデートでバージョンを更新する必要はありません。

ベータバージョン

scriptapiには、ベータバージョンという実験段階のものがあります。安定版とは違いアップデートで毎回変更されるので注意。マイクラバージョン1.21.44では1.16.0-betaが使えます。

ベータバージョンの魅力は、実験段階の最新機能がいち早く体験できる点にあります。
ワールド内のチャットを監視できるChatSendAfterEvent(ChatSendBeforeEvent)や、ワールド参加プレイヤーのデバイスについての情報が取得できるClientSystemInfoがその一例です。

このベータバージョンは、モジュールバージョンを

<使いたいベータバージョン>-beta

とし、ワールドの実験機能の設定からベータAPIを有効にすることで利用できます。minecraft previewなどのマイクラ自体のプレビューは必要ありません。

モジュールのバージョンが追加される際はアップデートでの変更ログにその内容が記載されているので、アップデートされたらこまめに確認しておきましょう。

(2.0.0-alphaを指定すれば常に最新のベータが適応されるという術もあると聞く)

JavaScript

準備はできた、早速コードを書いていこう!と言いたい流れではありますが、その前に、ScriptAPIで使われるJavaScriptというプログラミング言語の文法を覚えておきましょう。
ScriptAPIはJSON系の要素とは違って書き方は無限にあります。最悪6種類の記号だけで書くことも可能。
つまりは、文法を覚えなければ応用活用が利かないということです。外国語を話せるようになりたいからといって、この世に存在しうる会話を全て暗記しようと考える人はまず居ないでしょう。そういうことです。

ただ、ここで伝えるのはあくまでも最低限の基礎なので、これで完璧なコードを書けるようになるかと言えば微妙です。少し複雑な処理をしたい時や今回紹介したことのもっと詳しい仕様を知りたいという時は、サイトやYouTube、生成AIなんかに聞きましょう。(生成AIにScriptAPIはほとんど書けないので、生成AIを使うときはScriptAPIとしてではなくJavaScriptとしての質問をするのがおすすめ)

1. コメント

jsでは、コメントは

//このようにスラッシュをコメントにしたいところから2つつけるか、

/* スラッシュとアスタリスクで囲むとできます。 */

/*
このコメントの場合は、
複数行にわたって
書くこともできます
*/

コメントをするとコメントをした範囲がコードとして認識されなくなるため、処理のメモに使えます。

2. データ型

プログラミングにおいて、データには種類があります。ScriptAPIで主なものを5つ挙げると、

・string(文字列)
・number(数値)
・boolean(真偽値)
・object(オブジェクト)
・undefined(未定義)

があります。


stringは、“このようにダブルクォーテーションか,シングルクォーテーションで囲むことにより”   表すことができます。

+で2つの文字列を合わせる、といったことも可能です。(例:”あいさつは” + “大事だよ”)


numberは、そのまま0や100のようにして表せます。

+(加算) -(減算) *(乗算) /(除算)などの演算子で計算ができます。(例: 1 + 2 は3を返す式)


booleanは、trueとfalseで表すことができます。

分かりやすく言うと[はい、いいえ]のようなものです。


objectは、[]で囲まれたものと{}で囲まれたものがあります。

[]のほうはArray(配列)と呼ばれ、複数のデータをコンマで区切って入れることができます。(例:[“一つ目のデータ”, 2, 3])そして、その中のデータを要素と呼びます。
それら要素は、オブジェクトの名前[番号]で取り出せます。しかし番号は0から始まるので、頭の中ではオブジェクトの名前[番号 – 1]と考えると楽。

{}のほうは、「プロパティ」というものにデータを入れることができます。

//例
{ 
    apple: "red",
    grape: function() {
        world.sendMessage("purple");
    }
}
//こうでもok
{ apple: "red", grape: function() { world.sendMessage("purple"); } }

appleがプロパティの名前で、grapeがメソッド(プロパティに関数(後に説明)を入れたもの)の名前です。

プロパティは、オブジェクト名.プロパティ名で取得でき、メソッドはオブジェクト名.メソッド名()で呼び出せます。
ピリオドで繋げる他にも、オブジェクト名[文字列でプロパティ名]という書き方もあります。


undefinedは、値が定義されていないものなどに入ったりする値です。

例えば、未定義の変数などにはundefinedが入っています。

3. 定数・変数

データを自分の決めた名前で保存することができます。

//定数の宣言
const 定数の名前 = 入れたいデータ;

//変数の宣言
let 変数の名前 = 入れたいデータ;

こんな感じ。

大抵の命名に当てはまりますが、定数変数を日本語で命名するのは非推奨です。初めに数字をつけるのもNG。

変数は、定義した以降に 変数の名前 = 入れたいデータ、とすると再代入できます。

変数、定数はどんなときに使うかというと、

object.red.fruit.apple

例えばこんな、「objectというオブジェクトのredというプロパティのオブジェクトのfruit(以下略)…」のように場所が複雑な値があるとします。
これを毎回このまんま書くのは長ったらしいし面倒。

しかし、定数(変数)を使うと

const apple = object.red.fruit.apple;

これからはappleと書くだけであの長いコードと同じ意味になります。嬉しい。

4. 関数

関数とは、いくつかの処理を1つにまとめたものです。値を入れたら特定の値が返ってくるものとも言えます。コマンドをまとめたfunctionというものがありますよね。そんなものです。

関数は、

function 関数名(仮引数) {
    処理
}

と書いて定義できます。
呼び出すときは、関数の名前(引数) で出来ます。

まずは関数名です。JavaScriptの命名規則に則っているのならば自由。

そして処理。
return 値 をつけると、処理の中で出した値などを、関数を呼び出した場所に入れることができます(値が返ってくるという)。そのときに関数内で以降の処理が実行されないので、returnの値は設定せず「特定の条件で処理を止める」といった処理にも使われます。この場合関数はundefinedを返します。

仮引数は、関数名(引数) で関数が呼び出されるとき、引数に渡された値が入るというものです。

//関数を定義
function plus10(number) {
    const n = number + 10;
    return n;
}

//関数の呼び出し
world.sendMessage(plus10(20)); //ワールドに30とチャットされる

こんな関係。
仮引数はコンマをつけて増やすことができます(引数側も同じ)。

アロー関数という書き方もあります。こちらは、

const 関数変数名 = (仮引数) => {
    処理
};

で書けます。
これは関数に名前を付けているだけであって、関数自体は() => {}だけ。なので、関数が無名でいいときなどによく使われます。

5. if・for

if文は名前から大体予想がつくかもしれませんが、条件です。

if (条件) {
    処理
}

if文の中の処理は、()の中にtrueが入ったときに実行されます。
例えば、1 === 1を入れると、1 === 1trueを返す式なので処理が実行されます。

結果は、!をつけると反転できます。trueがfalseになったりfalseがtrueになったり、、、if (!(1 === 1))、if (1 !== 1)

条件は&&でどちらもtrueならという条件にできif (true && true)、||でどちらかがtrueならという条件にできますif (true || false)

for文は反復処理ができます。

for (let i = 0; i <= 実行したい数; i++) {
    処理
}

for (constof 配列) {
    処理
}

for (constin オブジェクト) {
    処理
}

1つ目は、let i = 0; で変数の定義、i <= 実行した数; でループが終わる条件、i++でループの中のひと処理が終わったら実行されるコード(今回の場合、iの値を1上げている)となっています。
2つ目は、配列の要素1つ1つに処理を行います。executeコマンドで言うと、as @e の@eが 配列 、その後の@sが 名 の部分。
3つ目は、オブジェクトに存在するプロパティの名前がそれぞれ 名 の部分に入り、処理が行われます。

6. クラス・インスタンス

よく言われる例えで、クラスは設計図、インスタンスは設計図に基づいて生成されたオブジェクト。

始めのほうは自分で作らなくともコードは書けるので、詳しい説明は省略します。使いたくなったときに調べてください。

リファレンスの読み方

一通り基礎は分かったところで、一旦コードを書いてみましょう。
まず、ビヘイビアのフォルダscriptsというフォルダを作ってください。

作り終えたら、その中にmain.jsというファイルを作ってください。jsonとjsでは違うので注意。ちなみに、jsonは「JavaScript Object Notation」の略だそうです。長い。

そうしたら、このコードを写してみてください。
(末尾に書いてある;はコロンではなくセミコロンなので注意)

import { world, system } from "@minecraft/server";

system.runInterval(function() {
    for (const player of world.getPlayers()) {
        const playerName = player.name;
        player.sendMessage(playerName);
    }
},20);

そうしたら、ファイルを保存してワールドでアドオンを使ってみてください。

いかがでしょうか。1秒ごとに自分の名前がチャットに送られていると思います。
それではコードが実際にどんな動作をするかを確認したところで、このコードの各部分が何を意味しているかを解説していきます。

注意

この解説のクラスのリンクなどは、少し経ったらバージョンが古くなっています。
そのため、こちらの公式サイトから常にその時の新しいバージョンのものを確認してください。リファレンスの読み方は変わりません。
ちなみに、個人的に見やすいページとして非公式ですがこのようなものもあります。今回はこちらのサイトを使い解説します。

import { world, system } from “@minecraft/server”;

ここでは、@minecraft/serverモジュールから、Worldクラスのworldというオブジェクト、Systemクラスのsystemというオブジェクトの2つをインポートしています。

system.runInterval(function() {…},20);

ここでは、インポートしたsystemを使用しています。
systemはSystemクラスのオブジェクトなので、Systemクラスのメソッドが使えます。
runIntervalというメソッドを見てみましょう。

%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88-2024-03-10-222142.png

始めに、Remarksという、その機能の説明を見てみます。
翻訳すると、「インターバルで一連のコードを実行する。」と書いてあるようです。
聞き慣れない言葉はインターバルぐらいですかね。意味は、繰り返し一連のコードを実行する、ということです。

それでは、上から見ていきましょう。初めに、runInterval(callback, tickInterval?): number

とあります。この文から、引数が最大2つ使え、そして2つ目の引数の最後に?がついているため、tickIntervalという引数は、なくても使えることが分かります。

callbackという引数の説明には、callback: (() => void)とあります。ここには関数が入るということです。下の文は、翻訳すると、「このインターバルが発生したときに実行される関数コード。」とあります。

続いて、tickIntervalという引数の説明を見ていきましょう。
こちらには、Optional tickInterval: numberとあります。Optionalからも、tickIntervalがなくとも良いことがわかりました。そして、tickIntervalにはnumberを入れれば良いことも分かりました。
下の文も翻訳して、見てみると「コールバックが呼び出される間隔。」らしいです。名前がtickのintervalなのでtick単位で時間を入れればよさそうです。

そしてReturnを見ると、このメソッドを実行したときに返ってくる値はnumberで、説明によると「この関数の実行をインターバルで停止させるためにclearRunメソッドで使用できる不透明なハンドル。」みたいです。繰り返しをやめるメソッドを使用するのに必要ということです。

つまり、system.runInterval(function() {…},20);は、20ティックごとに{}の中身を実行するという意味だったということ。

for (const player of world.getPlayers()) {…}

ここでは、インポートしたworldを使っています。
worldは、WorldクラスのオブジェクトなのでWorldクラスのメソッドが使えます。
WorldクラスのgetPlayersというメソッドを見てみましょう。

%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88-2024-03-10-231015.png

今回も初めに、Remarksを見ていきます。
このメソッドは、「フィルタ条件の EntityQueryOptions セットを介して定義された一連の条件に基づくプレーヤーのセットを返します。」らしいです。

それでは、上から見ていきましょう。初めに、
getPlayers(options?): Player[]

とあります。これから、引数にはoptionsというものが入れられるということが分かります。これも?があるため無くとも使えます。

options引数の説明には、options: EntityQueryOptionsとあります。EntityQueryOptionsとは何でしょうか?となって、クリックしてページへ飛んでみると、

%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88-2024-03-10-232942.png

色々出てきました。EntityQueryOptionsとはエンティティを取得する際、条件を付けられるインターフェイスのようです。とりあえずはインターフェースはクラスのような概念(設計図)であり、オブジェクトのような実態はないものと考えてください。このページは、まだ下に続いています。

%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88-2024-03-10-233514.png

1つ例を見てみます。このclosestというプロパティには、numberが入るようです。
Remarksを翻訳すると、「返すエンティティの数を制限し、このプロパティで指定された最も近いN個のエンティティを選ぶ。location 値もクエリオプションオブジェクトで指定する必要があります。」になります。ここでlocationも設定して、比較の中心を決める必要もあるようです。コマンドのセレクターで言うcのようなものみたいですね。

こういうわけで、EntityQueryOptionsを引数に入れた場合のメソッドの例は、以下のようになります。

world.getPlayers({location: {x: 0, y: 0, z: 0}, closest: 1});

話をgetPlayersに戻します。

optionsの次には、Return、つまり返ってくる値が書かれています。
見てみると、どうやらPlayer[]が返ってくるようです。
これは、Playerクラスのオブジェクトが入った配列ということです。

つまりfor (const player of world.getPlayers()) {…}は、playerにgetPlayersで取得した配列の各要素を代入し、{}の中でその個々の要素に処理を行っているという意味だったということです。

forの処理の中

const playerName = player.name;
player.sendMessage(playerName);

恐らくここまで読めたならばなんとなくやってることは分かると思うので、詳しいところは省略します。

%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88-2024-03-11-001810.png

nameプロパティを見ると、Readonlyと書かれていますね。これは値を再代入できない、ということです。

nameTagとかなら再代入して名前を変えることができます。

そして、sendMessage。これはまんまで、メッセージを送れます。

%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88-2024-03-11-002635.png

messageに入れられる値がいろいろごちゃってますが、これはstring,RawMessage,(string,RawMessage)[]のどれでも入れられるという意味です。

つまりこのコードは、プレイヤーの名前を本人にチャットで送るという処理だったといぅことです。

このように、リファレンスを見れば何をどうすればどうなるのかということが分かります。なので、なにか実装したい機能があればまずはリファレンスを見てみましょう。今説明した見方で応用も効くはずなので、リファレンスを見て使えそうな機能で遊んでみてください。分からない処理や単語はその時その時で調べてみましょう。それを繰り返したらその内ScriptAPIのコードが書けるようになっていると思います。

よく使われる機能

World
System
Dimension
Entity
ItemStack
Block

↑マイクラの基本になる機能達なので大体はこのクラスの処理

worldのafterEvents、beforeEventsが個人的に強い。イベント系はとにかく色々出来る。

マイクラ内のdevelopment_behavior_packsにアドオンフォルダを入れて、そのアドオン入りワールドで/reloadを実行するとfunctionとscriptapiのファイルが更新されるのでいちいちワールドを変えなくとも良い。

エラー

エラーは、設定にあるクリエイターという欄にあるコンテンツログGUIの有効化をONにすることで見ることができます。
ScriptAPIに限らず、様々な要素のエラーが出てくるのでONにしておいて損は無いです。

エラーは、大抵の場合は翻訳すれば言っていることが分かると思います。

最後に

ここまで読んでいただきありがとうございます!

役に立ったと思ってもらえたら嬉しいです。

なにか質問があるときはこちらのディスコードサーバーから受け付けています。どんな人も大歓迎!一応ここでも受け付けますが内容が複雑になると判断した質問はサーバーでしか受け付けません。

まだScriptAPIについて知らないことも少なくないので、間違っているところがあれば教えてほしいです。

それでは良いアドオンライフを!

>> 次回の記事

※投稿記事に含まれるファイルやリンクにより発生した被害についてクラフターズコロニーは責任を取りません
投稿通報

コメント

  1. 神ですね。ありがとうございます。

    • その言葉が嬉しいです!
      良かったです

  2. scriptAPIのオートコンプリート機能があれば使い方を教えてほしいです。コードエディタはVScodeを使っています。

    • npmをインストールし、https://www.npmjs.com/package/@minecraft/serverこのページからバージョンを選んで、パッケージのインストールのコマンドをコマンドプロンプトにコピペして実行すれば補完が出てくるようになります

  3. scriptapi最高

  4. 自分用メモ

    part-2 世界のイベントを自在にコントロールする
    https://minecraft-mcworld.com/70279/

  5. “dependencies”: [
    {
    “module_name”: “@minecraft/server”,
    “version”: “1.11.0”
    }
    ]
    のversionのbetバージョンの確認(最新アプデごとの)出来るサイト教えてほしいです。

  6. 僕はアドオンを作るときandroidタブレットを使うのですが。
    Minecraftないのファイルをいじれないので/reloadで出来ないんです。
    いちいちインポートしてあーだーこーだするのでアドオン作りがはかどりません。
    androidで利用出来るアプリ(Minecraftは確実)内のファイルをいじれるアプリありませんか?

    • ファイルマネージャーがおすすめです。

      • こんなの?
        %%https://play.google.com/store/apps/details?id=com.alphainventor.filemanager

        url%%

        • 実際に使って確かめてみるのが早いです

  7. 初めのところの
    ScriptAPI(gametestとも言う)というところの網掛けはどうやったんですか?

    • ブログエディタの文字の編集で、1番右のマークを選べば使えます。

      • 左揃えと中央揃えと一つ上に移動と削除と一つ下に移動しかないんですけどどうしたらいいですか?

        • その文字を選択したらペンみたいなマークがいくつか出てくるはずですが…

  8. “dependencies”: [
    {
    “module_name”: “@minecraft/server”,
    “version”: “1.13.0”
    }
    ]
    のversionの安定版のバージョンを確認は

    https://jaylydev.github.io/scriptapi-docs/#script-api-references

    のサイト内にありますか?
    あれば場所を教えて欲しいです。
    見つけきれません…

    • 1.13.0は安定版ですよ。合っています。

      • ありがとうございます!

        そして質問です。
        ===は何何は何何(?)
        &&&は何何と
        たけど(多分(?))
        またはってどう書くんですか?

  9. 質問です。
    ===は何何は何何(?)
    &&&は何何と
    たけど(多分(?))
    またはってどう書くんですか?

コメント通報