[ScriptAPI参考書] 始め方 #1

# 目次
- [はじめに](#はじめに)
- [ScriptAPIとは](#scriptapiとは)
- [始め方](#始め方)
    - [VSCodeのインストール](#vscodeのインストール)
    - [Node.jsのインストール](#nodejsのインストール)
    - [アドオンの作成](#アドオンの作成)
- [ScriptAPIのコーディング](#scriptapiのコーディング)
    - [プログラムの作成](#プログラムの作成)
    - [解説](#解説)
    - [実行](#実行)
    - [応用](#応用)
- [最後に](#最後に)

# はじめに
この「ScriptAPI参考書」シリーズではマインクラフト統合版のScriptAPIについて基礎から応用、例文まで詳細に解説し、ScriptAPI開発者や、ScriptAPIの開発を始めようと思っている人の助けになることを目的としています。

また、このシリーズを読むにあたって、ある程度のマインクラフトとJavaScriptの事前知識が必要になってくることがあります。

*注意: このシリーズではMinecraft Bedrock Editionを省略してマインクラフトと表記しています。*

次回: [ScriptAPIの情報まとめ](https://qiita.com/yuki2825624/items/2730a3f420f45c7c7eef)

# ScriptAPIとは
ScriptAPIとは、マインクラフトのアドオンの中でもビヘイビアパックの中に分類される物の一部です。JavaScriptを利用して、コマンドなどには無い様々な事が出来るようになります。
ScriptAPIの[公式のリファレンス](https://learn.microsoft.com/en-us/minecraft/creator/scriptapi/?view=minecraft-bedrock-stable)や[NPM](https://www.npmjs.com/package/@minecraft/server)なども公開されています。

# 始め方
ScriptAPIのコーディングをするには色々と前準備が必要です。早速始めて行きましょう。

## VSCodeのインストール
まずはVSCodeというエディタをダウンロード、インストールしていきます。
ディレクトリの階層の確認やJavaScriptファイルの操作、編集が便利なので、このシリーズでは一般的にVSCodeを採用しています。
既にVSCodeのインストールを完了している方は[Node.jsのインストール](#nodejsのインストール)まで読み飛ばしてください。

### 手順1 
下記のURLにアクセスし、VSCodeのインストーラーをダウンロード、実行してください。

https://code.visualstudio.com/Download

以下のような画面が表示されるはずです。
使用許諾契約書に同意し、次に進みます。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/29209e93-46ae-6cf2-e928-cb822540df55.png)

### 手順2
「デスクトップ上にアイコンを作成する」にチェックを入れておくと、アクセスが便利です。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/90f69eec-f967-5c75-2975-65021344bbaf.png)

### 手順3
インストールを押し、インストールが完了するまでお茶でも飲みながら待ちましょう。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/70bf62a2-b48c-7a1d-4f75-bccc27f886ca.png)

### 手順4
インストールが完了したら、VSCodeを開いてください。以下のような画面が表示されるはずです。
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/de98c001-d95c-6665-d7cc-6ccac0751c1d.png)

### 手順5
次に、日本語化をするための拡張機能をインストールします。
左の選択バーにあるExtensionsを押してください。

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/96cc5942-b404-2934-6586-41c2be408d20.png)

上の入力バーに「Japanese」まで入力すれば一番上に候補として表示されます。これをインストールしましょう。

![5-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/4371c704-0654-ab74-8fda-d23ca6d77624.png)

### 手順6
インストールが完了されると、右下にポップアップが出てくるので、「Change Language and Restart」ボタンを押します。すると、VSCodeが再起動され、日本語化が成功しているはずです。
ここまでが成功しなかった場合、[手順4](#手順4)からもう一度やり直してみてください。

![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/5b141fd3-8533-2a93-6508-b6be29a6e8ef.png)

## Node.jsのインストール
JavaScriptの実行環境、Node.jsをインストールしていきます。これをインストールすることによってコーディングの際に補完 (型定義) が使えるようになるモジュール (NPM) をインストールすることができるようになります。
既にNode.jsと`@minecraft/server`モジュールのインストールを完了している方は[アドオンの作成](#アドオンの作成)まで読み飛ばしてください。

### 手順1
下記のURLにアクセスし、Node.jsをダウンロード、実行してください。

https://nodejs.org/en

以下のような画面が表示されるはずです。
Nextを押し次に進みましょう

![2-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/0ce873e5-6786-bcc9-1cf6-b8b9c2bf940b.png)

### 手順2
ライセンスに同意し、次に進みます。

![2-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/faf44552-bd43-03ac-ddbb-5690186bde6f.png)

### 手順3
ここからは、特にNext連打で構いません。

![2-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/26ff93b5-4f20-ea3c-0f1d-14c35dc450c3.png)

### 手順4
Installを押し、インストールが完了するまで今晩の夕食でも眺めていましょう。

![2-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/6e2a5ded-8f97-9d5a-c326-740345dd763f.png)

### 手順5
インストールが完了したら、コマンドプロンプトを起動してください。
`win + R`でショートカット機能を起動し、「cmd」と入力し実行するとコマンドプロンプトを開くことができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/e298226a-e6ac-e694-1e61-34659ce7f6a2.png)

コマンドプロンプトに下記のコマンドを入力し、結果が出力されていれば正常にNode.jsがインストールできています。
正常に出力されなかった場合、[手順1](#手順1-1)からもう一度やり直してみてください。
```cmd:cmd
node --version
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/d4547b2b-fc4b-c5e1-184b-c39a9b50df96.png)

### 手順6
コーディングで使用するScriptAPIのモジュールをインストールします。下記のコマンドをコマンドプロンプトで実行してください。
```cmd:cmd
npm i @minecraft/server@2.0.0-beta.1.21.70-stable -g
```
:::note info
**説明**
`@minecraft/server`のバージョンを`@minecraft/server`の後に@と繋げて書くとバージョンを指定することができます。
2025/03/26時点のベータ版では`2.0.0-beta.1.21.70-stable`が最新です。([ここ](https://www.npmjs.com/package/@minecraft/server?activeTab=versions)で最新の公開されているバージョンを確認することができます。)
:::

## アドオンの作成
ここからはアドオンの本体を作成していきます。

### 手順1

まずは以下のディレクトリにアクセスしてください。

`C:\Users\%username%\AppData\Local\Packages\Microsoft.MinecraftUWP_8wekyb3d8bbwe\LocalState\games\com.mojang`

このディレクトリは、マインクラフトの様々データが保存されている場所で、ワールドのデータなどもこのディレクトリに保存されています。

今後頻繁にアクセスすることがあるので、デスクトップなど分かりやすい場所にショートカットを作成しておくことをお勧めします。

### 手順2

ScriptAPIはビヘイビアパックに分類されるので、development_behavior_packsの中にアドオンのフォルダを作成します。

`C:\Users\%username%\AppData\Local\Packages\Microsoft.MinecraftUWP_8wekyb3d8bbwe\LocalState\games\com.mojang\development_behavior_packs`

![img](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/877175dd-a1a7-dc23-5724-b32868dd4074.png)

![img](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/03010e2a-aa50-202e-ebce-fb059702ab85.png)

`Test`という名前にしましたが、ここは任意なので好きな名前でも大丈夫です。

### 手順3

では、先ほどインストールしたVSCodeでフォルダを開いてみましょう。

![img.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/1e07cee3-e0e4-7a7b-fb02-7d2545cff165.png)
![img](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/8e4a413e-e743-b1a8-69d5-3e047e48f723.png)
![img](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/904bad68-637e-efe5-fa52-48292ac08b2f.png)


### 手順4
ここにアドオンを作成していきます。

ディレクトリに、以下の階層になるようにファイルなどを作成してください。
```:development_behavior_packs
Test (作成したフォルダ)
├ scripts
│ └ index.js (名前は任意。ただし、拡張子は.jsにすること)
├ manifest.json
└ pack_icon.png (画像は任意。ただし、名前はpack_iconにすること)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/b4c70864-d4c5-f56e-ba7b-a33fc7b8f4ba.png)

:::note info
**説明**
- **scripts**
ScriptAPIの実行ファイルを保存しておくフォルダ
- **index.js**
ScriptAPIの実行ファイル
- **manifest.json**
アドオンの情報などを入力するファイル
- **pack_icon.png**
アドオンのアイコン画像ファイル (内容は任意)
:::

### 手順5
次に、まずは`manifest.json`から作成していきます。

以下のコードを全て`manifest.json`にコピー&ペーストしてください。

```json:manifest.json
{
    "format_version": 2,
    "header": {
        "name": "Test",
        "description": "ScriptAPI Test Behavior Pack",
        "uuid": "<UUID1>",
        "version": [1, 0, 0],
        "min_engine_version": [1, 21, 0]
    },
    "modules": [
        {
            "description": " ",
            "type": "script",
            "entry": "scripts/index.js",
            "uuid": "<UUID2>",
            "version": [1, 0, 0]
        }
    ],
    "dependencies": [
        {
            "module_name": "@minecraft/server",
            "version": "2.0.0-beta"
        }
    ]
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/f6015942-b8ed-72c2-b12c-f675a46fffe4.png)

:::note info
**説明**
- **format_version**
このアドオンのフォーマット(形式)バージョン
> **header** - アドオンのメイン情報
- **name**
このアドオンの名前
- **description**
このアドオンの説明
- **uuid**
このアドオンの識別ID
- **version**
このアドオンのバージョン
- **min_engine_version**
このアドオンが対応するマインクラフトのバージョン
> **modules** - アドオンの定義
- **description**
このモジュールの説明
- **type**
このモジュールのタイプで、`script`にすることでScriptAPIが利用できる
- **entry**
このモジュールの実行ファイルパス (適宜変更)
- **uuid**
このモジュールの識別ID
- **version**
このモジュールのバージョン
> **dependencies** - アドオンで使用するモジュール
- **module_name**
このアドオンで使用するモジュールの名前 (適宜変更)
過去の名前は`Minecraft`、`mojang-minecraft`等でしたが、現在は`@minecraft/server`に変更されています。
`@minecraft/server`のほかに`@minecraft/server-ui`、`@minecraft/server-gametest`等がありますが、今回は使用しません。
- **version**
このアドオンで使用するモジュールのバージョン (適宜変更)

*※以上の他にも入力できる要素はありますが、通常この情報だけで十分です。*
:::

コピー&ペーストが出来たら、次にUUIDの設定をします。
UUIDとは、アドオンの識別をするためのIDで、アドオン事に別々のUUIDにしなければ別のアドオンと見なされません。

例えば、UUIDが1111のアドオンとUUIDが1112のアドオン同士は正常に動作しますが、UUIDが1111のアドオンとUUIDが1111のアドオンとではアドオン同士の判別が出来ず、正常に動作しません。

UUIDの取得に、まずは下記のURLにアクセスしてください。

https://www.uuidgenerator.net/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/68165a2c-ae0b-6a97-216e-7ae4856be0f8.png)

「Copy」を押すとクリップボードにコピーされるので、それを`manifest.json`上の`<UUID1>`に張り付けて下さい。
UUIDを更新し、もう一度同じように`<UUID2>`にも張り付けてください。保存も忘れずに。

:::note warn
UUID1とUUID2で別のUUIDにしなければならないことに注意してください。
:::

```json:manifest.json
{
    "format_version": 2,
    "header": {
        "name": "Test",
        "description": "ScriptAPI Test Behavior Pack",
        "uuid": "e67b6fe8-8bea-469d-9b0c-7704535c4718",
        "version": [1, 0, 0],
        "min_engine_version": [1, 21, 0]
    },
    "modules": [
        {
            "description": " ",
            "type": "script",
            "entry": "scripts/index.js",
            "uuid": "1a1559f8-e930-47a8-95c6-06e233f204b9",
            "version": [1, 0, 0]
        }
    ],
    "dependencies": [
        {
            "module_name": "@minecraft/server",
            "version": "2.0.0-beta"
        }
    ]
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/61dc93bb-0de7-87c5-125d-8b89daaf12d6.png)

### 手順6
これでアドオンが完成しました。実際に確認してみましょう。既にマインクラフトを起動してる場合、再起動する必要があります。

![img](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/7a2dbbc1-c8c9-9bd6-e95c-f56c24904308.png)
このようにアドオンが表示されていれば成功です。もし追加がされていない場合、以下の点を確認してみてください。
1. フォルダやファイルの保存をしているか
2. ディレクトリのパス、階層が間違っていないか
3. フォルダやファイルの名前や拡張子が間違っていないか

# ScriptAPIのコーディング
ようやくセットアップが完了したので、ここからは実際のコーディングをしていきます。

プログラミングが初めての方向けに1から説明していきます。

今回は、初心者向けにカスタムコマンドの実装を例に実践していきます。初心者でも分かるような説明を目的としているので、コード等に非効率な部分もあるかもしれませんが、予めご了承ください。

### プログラムの作成

まずは[アドオンの作成-手順4](#手順4-2)で作成した`index.js`を編集します。

以下のコードを全て`index.js`にコピー&ペーストしてください。プログラムの練習のために見ながら手打ちするのもいいかもしれませんね。

このコードは、チャットで「`!lobby`」と入力すると、`(0, 0, 0)`にテレポートするというものです。

```js:index.js
import { world, system } from "@minecraft/server";

world.beforeEvents.chatSend.subscribe((ev) => {
    const { sender, message } = ev;
    
    if (message.startsWith("!")) {
        ev.cancel = true;

        system.runTimeout(() => {
            const args = message.slice(1).split(" ");

            if (args[0] === "lobby") {
                sender.teleport({ x: 0, y: 0, z: 0 });
                sender.sendMessage("ロビーにテレポートしました。");
            }
        }, 0);
    }
});
```

### 解説

それでは解説していきます。初めから全て理解する必要はないので、何となくこういう風に記述するんだな、と漠然に思ってくれれば大丈夫です。

[Node.jsのインストール-手順6](#手順6-1)でインストールした`@minecraft/server`を読みこみ、その中の`world`と`system`を使用するということを宣言しています。
```js:index.js
import { world, system } from "@minecraft/server";
```

プレイヤーがチャットを送信したときにこの中の関数が呼び出され、`ev`にイベントのデータが渡されます。
```js:index.js
world.beforeEvents.chatSend.subscribe((ev) => {

});
```

上で示した関数の中身で、主な処理部分になっています。少し複雑なのでコード内に説明を書きこみました。
```js:index.js
// sender - チャットを送信したプレイヤー
// message - チャットに送信したメッセージ
const { sender, message } = ev; // evからsenderとmessageを取り出す
    
if (message.startsWith("!")) { // メッセージが"!"から始まっているなら実行
    ev.cancel = true; // チャットの送信を取り消す
    
    system.runTimeout(() => { // 処理に遅延を挟む (beforeEventsを使用する場合、ScriptAPIの仕様で何らかの処理を実行するときに遅延が必要)
        const args = message.slice(1).split(" "); // メッセージから"!"を消し、空白ごとに区切り配列に格納する
        // 例) "!tp 1 2 3" -> [ "tp", "1", "2", "3" ]
        
        if (args[0] === "lobby") { // 最初の文字列(つまりコマンドの名前)が"lobby"なら実行
            sender.teleport({ x: 0, y: 0, z: 0 }); // プレイヤーを(0, 0, 0)にテレポート
            sender.sendMessage("ロビーにテレポートしました。"); // プレイヤーに成功したメッセージを送信
        }
    }, 0);
}
```

### 実行

仕組みが分かったところで、実際に動くのか確かめてみましょう。

まずはアドオンを有効にします。

![3-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/ce7ca1d9-3ddf-f90f-2072-6b6029434f32.png)

次に、「実験」の「ベータAPI」を有効にします。

:::note warn
この設定をONにしなければ、ベータ版としてScriptAPIが動いてくれません。
:::


![3-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/2b24c46d-1e25-719a-55ef-83b8efb8f2f5.png)

ワールドを作成し、チャット欄で「`!lobby`」と送信してみましょう。

![3-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/f428267b-5f3f-e083-9e51-adee53910708.png)

`(0, 0, 0)`にテレポートし、メッセージが送信されていれば成功です。

### 応用
今のままではコマンドが一つしかないので、teleportコマンドを追加してみましょう。

このように追加します。

```js:index.js
import { world, system } from "@minecraft/server";

world.beforeEvents.chatSend.subscribe((ev) => {
    const { sender, message } = ev;
    
    if (message.startsWith("!")) {
        ev.cancel = true;

        system.runTimeout(() => {
            const args = message.slice(1).split(" ");

            if (args[0] === "lobby") {
                sender.teleport({ x: 0, y: 0, z: 0 });
                sender.sendMessage("ロビーにテレポートしました。");
            }

            if (args[0] === "teleport" || args[0] === "tp") { // コマンド名が"teleport"、若しくは"tp"なら実行
                const x = Number(args[1]); // 1つ目の値(x座標)を数値に変換し格納
                const y = Number(args[2]); // 2つ目の値(y座標)を数値に変換し格納
                const z = Number(args[3]); // 3つ目の値(z座標)を数値に変換し格納
                sender.teleport({ x: x, y: y, z: z }); // プレイヤーを指定した(x, y, z)座標にテレポート
                sender.sendMessage(`(${x}, ${y}, ${z})にテレポートしました。`); // // プレイヤーに成功したメッセージを送信
            }
        }, 0);
    }
});
```

ここで、実際に追加できているのか確認したいところですが、まずはScriptAPIを更新しなければいけません。
ScriptAPIを更新するときは、`/reload`コマンドを使用します。

:::note warn
コードを編集したときは、都度`/reload`コマンドを実行するように心がけましょう。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/badb85b9-2c56-38fa-da63-f6012ff4182d.png)

更新が出来たら、実行してみましょう。

`!teleport 10 -60 10`と送信してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637082/32a5722b-e092-8965-7e78-b3268dda4053.png)

しっかりとテレポートに成功したことが分かりますね。

`!teleport`ではなく、`!tp`にしても実行されると思います。

ある程度理解が出来たら、ご自身でもコマンドを追加してみるのも楽しいですよ。


# 最後に
いかがでしたでしょうか。
私の初めての記事でもあるので、至らない部分も多いかもしれませんが、誰かの参考になればとても嬉しいです。
この記事を通して、ScriptAPIに少しでも面白さや便利さを感じてもらえれば幸いです。
これから、このような形式で記事を投稿していきますので、今後ともよろしくお願い致します。