マインクラフト統合版には、コマンドを自作できるシステムが存在します。それも1つや2つではなく、ScriptAPIを用いたものからWebSocketServer、果てには外部ライブラリを用いたものまで、様々です。コマンドの自作としては代表的なものとしては、CustomCommandが知られていますが、広義の意味でのカスタムコマンドというのは、それにとどまりません。
コマンドを、
作りたーい!
ご存じの通り、マインクラフトにはホンマぎょうさんコマンドあるやん?
ホント、覚えられないくらいには。
でもさ、これ微妙に痒いところに手が届かへんのも事実。
あー、分かるかも。コマンド触れば触るほど、「こんなコマンドがあればいいのに」って思うことあるよね
で、一般的にはそんなのをfunctionとかコマンドの組み合わせとかで無理やり実装するところやけど、
実はこんなコマンドって自作できるのってあんまり知られてへんよな
確かに?界隈の人以外はね..
ってことで、この動画ではコマンドを自作する方法をいくつかまとめてみよう、って趣旨。
そういえばコマンド自作する方法ってどんなのがあったっけ?
パッとあげると、こんな感じ。
まだまだあるかもしれへんけど、ここらへんの方法が王道かもな
で、基本的にコマンドの自作には「ScriptAPI」といってJavaScriptでゲームシステムをいじる機能が必要になるから、
その部分の解説を含めた、こんな構成でお届けします…
要はコマンド自作の総集編ってことね
で、まず解説に入る前にそもそも「自作のコマンドって何なん?」っていう疑問が払拭されへんとモチベーションもわかんと思うから、
まずは完成品を見せるわ
一目で分かる例が、こちら
「test」?
確かにカスタムコマンドだね
あとは、こんな感じのチャット欄に指定の語句があれば何かを実行するようなシンプルなやつとか、
後半部分では日本語で何らかのコマンドを実行するような例もやっていくで
さて、概要の解説はこれくらいにして、まずはこの動画の核となるScriptAPIについて話すわ
まずは必要なものがいくつかあるからこれをインストールしよう
詳細は概要欄を見てね
なんかソフトの一覧にマインクラフトが入ってるんだけど
このチャンネルの視聴者の大多数は持ってると思うから解説は省くわ
次のvscodeはプログラミングに特化したテキストエディタで、
必須ではないけどあったほうが断然楽やで
概要欄に貼ってあるリンクからダウンロードできるで
ゲーム制作で使ったやつだ
汎用性が高いよな
最後にnode.js。
これはあんまり聞かないなぁ
本来javascriptっていう言語は
Webページ上で動作するスクリプトなんやけど、
これをパソコン上で使えるようにするのがnode.jsの役割。
ふーん…
これも概要欄からアクセス可能。
ダウンロードボタンを押して、
msiファイルをダブルクリックして実行すれば完了。
今回解説する工程ではnode.jsは必須やで
これがダウンロードできたら次に進もう
まずはいつも通り、com.mojangフォルダを開こう
実はこの場所、例の1.21.120のアップデートで
変更になってるから気つけてな
結構奥の方…
せやな、迷いやすいから注意。
開けたらdevelopment_behavior_packsを開こう
そしたら右クリックしてフォルダを新規作成。
フォルダの名前はお好みで。
今回はtestとしたで
そしたらこれを開いてmanifest.jsonを作ろう
右クリックして新規作成からテキストドキュメントを選択。
するとテキストファイルが作成されるから、これを改名して
manifest.jsonとしよう
聞いたことあるな…
これはアドオンの要項を記述する、必須のファイルだから
本チャンネルでも何回か取り上げてるで
これをvscodeで開いて、編集しよう
内容はこのサイトに書いてある通りで、コピー&ペーストすればOK。
何点か補足すると、
ここでアドオンの名前と説明を定義しているので、
アレンジはお好みで。
これがそのまま表示名になるで
このuuidはアドオン固有の文字列。
これはそのまま使うというよりも、
uuidジェネレーターとかを使って生成・変更するのがええかもな
そのまま使うとどうなるの?
このアドオン自体は動くんやけど、配布するときにちょっと面倒なことになるな
最後にminecraft/serverのバージョンについて。
動画作成時点で有効なバージョンはこんな感じで、
基本的に最新のバージョンになればなるほどいろんな機能が使えるようになるんやけど
ベータ版は挙動が安定しないから使用には注意が必要やな
それが完了したらフォルダを新規作成して
scriptsと改名しよう
たしかここにスクリプトを書いていくんだっけ?
せやな、scriptsフォルダを開いて
新規作成からテキストドキュメントを選んで
これをmain.jsに改名しよう
これをvscodeで開いたら、
上のメニュー欄からTerminal、New Terminalの順に選択。
するとターミナルが開くので、
まずはこのアドオンがあるフォルダに移動しよう
続いてnpmコマンドでマインクラフトのモジュールをインストール。
こんな感じになれば成功。
ちなみにこの一連の操作はコマンドプロンプトでもできるで
もはやマイクラの動画とは思えない…
ちょっと専門的すぎたな…
でも事前準備はこれで終わり。
あとはmain.jsに何かスクリプトを書いていこう
スクリプトの内容については前回の動画でお話ししているので
この動画では割愛。
こんな感じで簡単にスクリプトが書けたら保存して、
アドオンの有効化を行ってからゲームをロードすると…
無事、メッセージ欄がHelloで埋め尽くされるで
manifest.jsonのversionについてなんやけど、
ここをベータ版にすると最新の機能、
例えば自作のコマンドの制作なんかができるようになるんやけど
その場合はベータAPIをオンにする必要があるから注意な
以上が、大まかなScriptAPIの全体像。
続いて、この環境構築に基づいてチャット検知をやってみるで
で、ここが重要やねんけど、
今回チャット欄の監視を行うにあたって
ここがベータ版じゃないと動かへんのよ
最新機能なんだ
せやで
で、ここのバージョンは頻繁に変わるから、
公式のリファレンスでバージョンを確認してね
1.21.120以降は単に「beta」と指定することもできるで
あと、ベータ版を使う場合はワールド起動時に「ベータAPI」を
オンにする必要があるのも注意。
忘れそうだ…
後でもう一回話すで
それが完了したら、フォルダを新規作成して、
scriptsという名前のフォルダを作るで
これを開いて、テキストファイルを新規作成。
main.jsとするで
これを開いて、スクリプトを書いていこう!
ようやくコマンドが作れるのね…
せやな、
大まかな流れはこんな感じで、
何らかのメッセージが送信されたときにそれを検知して
処理につなげていくという流れやな
まずは簡単な例を書いていくで
まずは、いつも通りモジュールの呼び出しから
これでマイクラの世界に干渉できるようになるで
続いて、チャットが送信されたときに発火する関数を定義。
chatSendなんてあるんだ
これで、チャットの送信を監視できんねん
便利やからめっちゃ使うで!
subscribeで関数の実行を予約したら、
この関数の名前をevとするで
ev.messageでメッセージの内容を取得して、
もしこのメッセージが「!killall」だったら、
このメッセージの送信者、ev.senderのもとで
runCommand関数でコマンドを実行。
これを保存して、
さっき言ったようにベータAPIをオンにしたら、
ゲーム内で「!killall」が使えるようになるはずやで
実際に使ってみよう
あ、モブが倒された
こんな感じでちゃんと機能するな
さっき書いたスクリプトはうp主のサイトにもあるから、
コピー&ペーストするのが早いで
ここではrunCommand関数を使って処理を行ったけど、
sendMessage関数を使ってメッセージを送信することもできるで
これを実行すると、こんな感じでメッセージが返ってくるで
山びこ山みたい
それ以外にも前回紹介したやり方でUIを出すとか、
色んなスクリプトが考えられるな
面白そう!
みんなもオリジナルのコマンドを作ってみよう!
で、普通のブログとか動画はここで終わるところやけど、
ここで終わらないのが当チャンネル。
普通のコマンドだとこんな感じでオプションの設定、
いわゆる引数を付けられるんやけど、
オリジナルのコマンドにもこれを実装してみよう、という話。
なるほど
説明に入る前に、前提知識から。
例えばこんな感じに文章があったとするやん?
ぶん、しょう?
オレンジのところに文字が入って、白は空白。
なるほど
で、こんな文章について、
javascriptに標準搭載されてるsplit関数を使って
空白で分割すると、
こんな感じになんねん
それぞれの文字に番号が振られるのか
せやで、そしてそれぞれを配列に格納。
これは空白に限らずいろんな文字で分割出来て、
この文章を点で分割するとこんな感じになるな
このsplit関数を使うと引数を取得出来て、
その例はこんな感じ。
これは何?
足し算を行うaddコマンドを実装する例。
実際に使ってみるで
引数の数字を2つ入力すると・・・
あ、足し算ができてる!
もちろん、他の数字でも・・・
これも大丈夫そう
小数の足し算もOK
ということでこれの解説を。
一行目はさっきと変わらないね
せやな
だけど2行目はstartsWithが使われてるな
ほんとだ。これは何?
これは、文字列が指定の語句から始まっているかどうかを判定する、
javascriptの標準ライブラリの関数。
今回は、メッセージが「!add」から始まっている時にtrueを返すで
3行目ではさっき話したsplit関数を使って、
空白でメッセージを分割して配列に格納。
4行目で足し算を行う、という流れやな
この辺の詳しい流れはうp主のサイトにも書いてるで
そしてこれを応用すると、
引数を無限に増やすことができんねん
え、すご!
実際に使ってみるで
今回はこんな感じで5つの引数を置いてみよう
あ、合計が出た
こんな感じで引数の数に関わらず
コマンドを実行することができんねん
さっきと違うのは、引数の処理でfor文を使ってるところやな
このlengthで配列の要素の数を取得してるで
なるほど、面白いね!
みんなもカスタマイズして遊んでみてね!
で、さらに応用するとこんな感じで
コマンドの中で任意のコマンドを実行できるんよ
え、どういうこと?
executeコマンドをイメージすると分かりやすいかも
なるほど
これはwaitコマンドといって、
コマンドの実行を遅らせるコマンドやねん
試しにこれを使ってみるで
こんな感じのコマンドを実行すると・・・
ちょっと遅れてメインのコマンドが発動すんねん
これは任意のコマンドについて有効で・・・
giveコマンドを遅延させることもできるな
ここでは実行が60ティック、3秒遅れるで
すごい!
今回の場合、空白で分割するのはあかんのよ
というと?
giveコマンドの中にも空白があるやろ?
ああ、waitコマンドの引数とgiveコマンドの引数を
区別しなきゃいけないのか…
せやな、
今回はこういう感じで分割したいから、
for文でコマンド部分の文字列を合体してるで
なるほど…
ここまで色々コマンドの作成方法について話したけど、
チャット欄に依存する以上、
コマンドブロックを使った実行の自動化が難しいんだよね
確かに…
この問題の解決策はおよそ2種類あって、
続いて、そのうちの1つの方法について話すわ
前回はチャット欄を監視してコマンドを自作したけど、
それやとコマンドブロックが使えへんから、
自動化が難しいんよ
せやけど、今回解説する方法はチャット欄に依存せえへんから
コマンドブロックが使えるというメリットがあんねん
なるほど…
で、その方法なんやけど…
タイトルにも書いてあるし、何ならここにもあるよ?
せやな、鍵を握るのがこのscripteventコマンド。
でも、そんなのあったっけ?
それがあんねん
こんな感じでヘルプにも出てくるんやけど、
影が薄いのか、あまり知られてへんみたいやな
だって説明見てもよく分かんないこと書いてあるし…
せめて「コマンドを自作できます」とか書かれていればいいのに…
ま、その辺分かりづらいのはあるよな
まずはこのコマンドがどういうものなのかを話すわ
お願いします!
そもそも、scripteventコマンドの構文はこんな感じ。
最初にコマンド名であるscripteventをおいて、
その後にidを、
そして最後にメッセージを書くで
このidって何? あらかじめ決まってるの?
いや、自分で決められんねん
どういうこと?
このidだったらこういう処理をする…
っていうのを、あらかじめ自分で決めんねん
へぇ…
百聞は一見に如かずやな、実際にコマンドを使ってみるで
今回はあらかじめ、killallというidを入力すると
killコマンドが発動するようにしてるで
そしてこのコマンドを実行すると…
モブが倒されたね
こんな感じで機能するわけやな
このidの部分には名前空間が必要やから注意
これ、どうやってidを定義するの?
ここで必要になるのが、ScriptAPI。
このチャンネルでは何回か取り上げてるけど、
プログラミングをしてゲームのシステムをいじる機能やな
環境構築についてはこの動画とかあの動画とか
前回の動画とかうp主のブログで詳しく説明してるから、
そっちをご覧ください
いつも通りmain.jsにアクセスして
モジュールを呼び出したら、
こんな感じでスクリプトを書いていくで
まずは、scripteventが発火したときにトリガーする関数を定義。
関数の引数はevとするで
ev.idで送信されたscripteventのidを取得して
もしこれがkillallやったら、
scripteventの送信者、ev.sourceEntityのもとで
runCommand関数でコマンドを実行。
これで完成?
もうちょっとやりたいことがあんねんけど、
とりあえず、このスクリプトの挙動を確認してみよう!
scripteventコマンドを実行するで
ちゃんと動くね!
次にコマンドブロックで動くか見てみるで
同じようにscripteventコマンドを入力。
そしてコマンドを実行すると…
え、killallが効いてない…
こんな感じでエラーが発生すんねん
え、scripteventはコマンドブロックでも使えるんじゃないの?
無条件で使えるわけとちゃうねん
考えてみれば当たり前のことで、
今回、コマンドを実行したエンティティについて
runCommand関数で処理を行ってるけど、
ブロックはエンティティとちゃうからエラーが発生するわけやな
スクリプトがコマンドブロックに対応してないのか…
せやな、
じゃあ、どうすればいいの?
実行者を場合分けして、
それぞれについて処理を行っていくで
ev.sourceTypeでコマンドの実行元を取得して、
それがentityだったら普通に処理を実行。
そうでなくて、実行元がBlockやった場合、
ev.sourceBlockで実行元のブロックを取得して、
そのブロックのディメンション内でrunCommandを実行。
回りくどいね
しゃーなしやな
実際に動かしてみるで
コマンドブロックを起動すると…
あ、モブが倒されてる
エラーも発生してへんな
え、これを応用すると足し算コマンドが作れんねん
足し算?
実際に使ってみるで
今回は、idとしてaddを入力。
そして次のメッセージ欄に、足し算する数字を入力。
今回は、小数の入った2つの数字を足し算するで
そしてコマンドを実行すると…
結果がでてるね
こんな感じで機能するわけやな
さっきと違うのは、このev.messageで
メッセージ部分の文字を取得してるとこやな
ホントだ
これをsplit関数を使って空白で分割して、
それらの数字を使って足し算をしてるで
後半部分はさっきとあまり変わらへんのやけど、
この辺の流れだけちょっとちゃうな
ホントだ、どういうこと?
sendMessage関数はクラスがプレイヤーじゃないと使えへんから、
そのブロックがあるディメンションにいるプレイヤーを取得して、
各プレイヤーについてメッセージ送信してんねん
へぇ…
こんな感じで、scripteventを使えば
コマンドを「自作」できんねん
結構、面白いね
せやろ、これを使えば自由度がかなり上がると思うわ
コマンドブロックが使えるのもええよな
で、これとは別にコマンドそのものを自作する方法もあるから、
そっちも解説するわ
できることならこんな感じで、直接実行するタイプのオリジナルコマンド、作りたいやんか
あー、まあ確かにね。でもそんなの聞いたことないよ?
それができんねん。これ見てほしいんやけど、
アップデート?
せやで。この前の1.21.80のアプデで、CustomCommandが追加されてんねん
CustomCommand?
文字通り、自分でオリジナルのコマンドを作れるシステムやな。楽しそうやろ?
え、それすごいじゃん!
でも何で誰も何も言わないんだろう?
まあ、アップデートのTechnical Updatesの部分なんて普通の人は注目せえへんからな
確かに統合版スーパーフラットのインパクトが強すぎて。
ただ、ScriptAPI触っている人の中ではある程度知れ渡っているのか、高度なアドオンとかだとカスタムコマンドは少し見かけるかな?
ま、早速オリジナルのコマンド作っていくわ
まずは今回やりたいことを見せるわ
こんな感じで、「lq:test」という自作のコマンドを定義して、
それを実行したらこんな感じでメッセージを表示する、っていう簡単なコマンドを作っていくわ
スラッシュから始まる普通のコマンドを作るんだね
せやな、その辺がscripteventとはちゃうところやし、
ビックリマークから始まる、「疑似コマンド」とも当然一線を画すところやな
正真正銘の「オリジナルコマンド」だ
そういうこと!
で、カスタムコマンドを使うのにあたって必要なものがいくつかあるんやけど、
まずは、当然やけどScriptAPIの環境。
まあ、スクリプト書いて定義するんだから当然だよね
で、ちょっと気をつけて億点として、従来はこのカスタムコマンド、ベータ版の機能やったんよ
元動画もベータ版として解説してたよね
それが、1.21.120のアップデートで正式版として実装されるようになったから、
カスタムコマンドの定義にベータAPIとかは特に不要。
それは大きいね
ということで、まずはScriptAPIの環境を整えよう
それが準備できたらアドオンのフォルダ内にscriptsフォルダを作って、
その中にmain.jsを作って、テキストエディタで開こう
そしたらここにコードを記述。
まずはいつも通り、import文でマイクラのモジュールを呼び出してそれを変数serverとしよう
続いてカスタムコマンドを定義するスクリプトを記述。
serverのsystemモジュールのbeforeEvents、startupクラスを使って、ワールド初期時に発火する関数を定義
この関数の引数をevとして、registerCommand関数でカスタムコマンドを登録。
続いてこのカスタムコマンドの概要を定義していくわ
まずはname。言うまでもなく、このコマンドの名前やな
これって名前空間が必要なの?
せやねん、(名前空間):(コマンド名)の形で定義。公式リファレンスにさりげなく書いてるで
続いて、description。これもそのままの意味で、コマンドの説明文を定義。
今回は「これはテスト用のコマンドです」という説明にしておこう
コマンド名の右側に出てくるこの文章のこと?
せやな。アドオンを配布する場合はあったほうがええと思うわ
次に、permissionLevel。これはいわゆるコマンドの「権限レベル」の設定やな
CommandPermissionLevelクラスを設定することになってて、有効なのはこんな感じ。
今回は誰でも使える「Any」を設定しておこう
mandatoryParametersとoptionalParametersは後で話すわ
続いて、このカスタムコマンドがゲーム内で実行されたときに何が起きるかを定義していこう
コマンドの実行起点であるoriginと、これは後で話すんやけどargを引数にとって、発火する関数を定義。
試しに実行したエンティティを起点にsendMessage関数で「テスト用文章」というメッセージを表示してみよう
これが終わったらあとはゲーム内で挙動を確認するだけやな
マイクラを起動して、このアドオンを有効化しよう
ということでゲーム内でさっき定義したコマンドを入力してみると..
あ、ちゃんとコマンド一覧に登録されてる
説明文もOKやな
そしてこれを実行すると…
メッセージが出てるね
こんな感じでちゃんとスクリプトが動いてることが分かるな
これってメッセージの表示以外にもコマンドの実行とかできるのかな?
試してみよっか
sourceEntityの下でrunCommand関数でコマンドを実行してみよう
この状態でさっきと同じように、「lq:test」を実行。
なんかエラーが出てるよ
実はrunCommand関数、beforeEventsプロパティと一緒には使えへんのよ
あ、そうなんだ。ちょっと不便。
どうしても使いたい場合、runTImeout関数を使って意図的に関数の実行を遅延させるっていう手があるな
実際にスクリプトを書くとしたら、こんな感じ。
この関数、遅延させるティック数を引数にとる必要があるから、何らかの数値を指定しよう
これでコマンドを実行させると…
あ、コマンドが実行されてる
一応、こんな感じで使う方法はあるにはある、っていう感じやな
でもそれ、functionとどう違うの?
functionは予め定義しておいた一連のコマンド群を順々に実行するっていう処理過程しかとらないけど、
今回使ったCustomCommandはScriptAPIを介したプログラミング機構を持ってるから
条件分岐とか繰り返し処理がだいぶやりやすいっていう利点があるな
あー、確かに。似てるようで全然違うんだ
単純な処理はfunctionに任せて、複雑なことがやりたいならCustomCommandを使うのがええかもしれへん
最後に、引数について。
あー、そういえばこのコマンドに引数ってなかったね
そう、今回定義したのは「lq:test」で完結する簡単なコマンドやったけど、
これも設定出来たらだいぶ自由度が上がると思うわ
で、この引数の鍵を握るのが、さっきスルーしたmandatoryParametersとoptionalParameters。
楽しそう
あと、さっき使わなかった関数の引数argも引数の設定になると関わってくる感じやな
次はこのあたりの説明をしていくわ
まずは今回やりたいことを見せるわ
前回追加したオリジナルのコマンドに、
適当な文字列を追加すると、
その入力にあった文字が出力されるっていう仕組みを作っていくわ
それが引数になるんだ
そういうことやな
で、そもそも引数って何?っちゅう話なんやけど…
あれでしょ?コマンドの後ろにつくやつ。
マイクラ上やとそうなんやけど、より一般的に説明するならコマンドや関数を実行する際にそれに与える値のことやな
で、カスタムコマンドにそれを実装して、よりコマンドの自由度を上げようっていうのがこの動画の趣旨。
さて、スクリプトなんやけど、前回軽く説明した通り、mandatoryParametersは必須となる引数の設定で、
optionalParametersは任意の引数の設定。どっちもlist形式で指定することになっとるな
つまり、上のやつはないとエラーを吐くけど、下のやつはなくてもいいってこと?
そういうことやな。まずは必須となる引数から設定していくわ
引数の設定にあたって必要となる要素は、nameとtypeの2つ。
この2つの要素を持ったObject型を、中かっこを用いて記述しよう
nameの部分は、この引数の名前。適当な文字列でOK
名前空間も要らないんだ
続いて、typeはserverモジュールのCustomCommandParamTypeを指定することになっとるから注意しよう
有効な引数のtypeはこんな感じ。
そしてよく使う引数のtypeと、その意味、例を表にするとこんな感じ。
結構色々あるんだね
もちろんこれ以外にもあって、詳しいことは公式のリファレンスにも書いてあるから見てみるとええかもな
今回は簡単な例として、String、つまり文字列を引数のtypeとするわ
これで設定は終わりかな?
このカスタムコマンドが受け入れる引数の設定はそう。あともう一つやることがあって、
この引数をもとに「何を実行するか」っていうのを改めて定義する必要があんねん
そのカギを握るのが、前回スルーした、この変数arg。
あー、定義するだけしておいて、一切使ってなかったから何でだろうって思ってた
ってことで今回は簡単な例として、この引数を受け入れてその引数をそのまま表示するプログラムを書いていこう
とはいっても特に難しいことはなくて、このargに引数の情報が含まれているから、それをsendMessageで表示するだけやな
このStringっていう関数は?
これは、ある型の変数を、強制的に文字列型に変換する関数。sendMessage関数は文字列型しか受け入れへんから、一応書いてるって感じ
この「型」っていう概念が後々重要になるから、覚えておくとええかも
ってことで、これを保存してゲーム内での挙動を見てみよう
チャット欄を開いて、前回定義したコマンドに新しく文字列を引数として挿入してみよう
なんかコマンドの説明部分も引数の存在が前提となってるね
せやねん、これは後で話すんやけど「このコマンドはどうやって使うのか」っていうのが一目で明確になるのが
このカスタムコマンドのええ所やと思うわ
で、これを実行すると
あ、引数が表示されてる
ちゃんと引数の設定ができることが確認できるな
次に、OptionalParameters、つまり任意の引数の設定もやってみよう
引数の設定の方法はさっきと同じかな?
せやな、nameとtypeの両方が必要。
さっきと違う名前にしとくと区別がついて分かりやすいかもしれへん
二つ目の引数のtypeは、さっきとちゃうLocation、つまり座標にしてみよう
あー、fillコマンドとかで見る~ ~ ~みたいなやつか
同じようにこの引数を受け取って何が実行されるかを定義していくんやけど、
複数の引数を設定するときは、registerCommand側の引数を増やさなあかんねん
あ、そうやって定義するんだ
変数argは既に使われてるから、ここではarg2を2つ目の引数を格納する変数として新たに定義しよう
そんで同じように、座標の情報を含むarg2を使った処理を行っていこう
座標のx座標を取得して、それを出力する例はこんな感じ。
y座標やz座標も同じ。
ちなみにこれ自体は数値型やから、String関数がないとエラーを吐くで
ゲーム内で挙動を確認してみよう
まずは一つ目の引数、文字列を入力して、その次に任意の引数、座標を入力。
あ、数字が出力されてる
これが現在のx座標に相当するな
ただ、このままやと小数点の入った数字で使いづらいと思うから、多くの場合Math.floor関数で処理をしたほうがええと思うわ
あと、PlayerSelectorでターゲットセレクターを引数にとれんねんけど、
この場合argにはObject型が入って、String型しか受け付けへんsendMessageとは相性が悪いから、
そういう場合、JSON.stringifyで無理やりObject型をString型に変換できるっていうのは覚えとくとええかも
あ、こんな感じで中身を直接見れるんだね
これはカスタムコマンドに限らず、ScriptAPI全般について言えることやな
というところで引数の解説はおしまい。
さっき説明したように、CustomCommandの場合、入力時にヒントが表示されるからプレイヤーに優しいっていうメリットがあるし
これがScripteventや疑似コマンドにはない、唯一無二の魅力となってる面があるな
元来ベータ版として運用されてきたけど、これが正式版として気楽に使えるようになったのも追い風やと思うわ
このカスタムコマンドだけどさ、名前空間が必要なんだよね…
でさ、巷の凄いアドオン見てるとさ、カスタムコマンドはコマンドでもこんな感じで名前空間内やつ見るんだよ
あー、たまにあるよなぁ
これさ、どうやって作ってるのかお姉ちゃん知ってる?
あー、これ、意外と解説されない事項やから、ちょっとこれを機にスクリプト解説するわ
あ、お姉ちゃん知ってるんだ、お願いしますっ!
まずは何をやりたいのかってことを話すわ
こんな感じでコマンド一覧を開くと、
名前空間がない、単なる「test」というコマンドがあるのが分かる?
あー、あるね、こういうのが欲しい
これこそ、今回追加していくコマンド。
そして、これを実行すると、こんな感じで何らかのアクションを起こす、という一連の流れまでを実装するわ
ということで、早速スクリプトを書いていくわ
名前空間がないとは言っても、基本的な部分は普通のカスタムコマンドと一緒。
まずはimport文を普通に定義して…
system、beforeEventsのstartupを用いてワールド起動時にカスタムコマンドを登録する処理を記述。
で、後々のことを考えてちょっと書き方を変えるんやけど
まずは登録したいコマンドについて仮で良いので名前空間を定義
え?どういうこと?名前空間はないんじゃないの?
この事情については後で話すわ
で、続いて登録したいコマンドの名前を定義。
これは「test」とか適当な文字列にしておこう
さらにこの登録するコマンドについて、説明文を宣言。
これはそのまま、コマンドの入力画面で表示される文言になるで
でも今回は、これらをコマンドの登録する過程で決めるんじゃなくて先に定数で置いちゃうんだね
実は、これが「名前空間なし」のコマンドとちょっと関わってくんねん
さて、これらの宣言が終わったら、続いて同じようにコマンドを実行したときに発火する関数も予め定義しておこう
ここではこのコマンドの関数を「commandCallback」とでもして、引数にoriginを設定。
このコマンドの実行者をさっき決めた引数、origin.sourceEntityを用いて取得。
このエンティティが存在しないことも考慮して、一応if文を挟んでおこう
あー、コマンドブロックで実行することもあるもんね
それが終わったら、んー、適当にそのエンティティについてコマンドを実行する感じでええかな
say testとでもしておこう
シンプルぅ!
さて、これで発火する関数の定義は終わり。最後にこれらを結び付けてカスタムコマンドの登録処理をやっていこう
そうそう、どうやって名前空間なくすんだろう、普通にやるとエラーになるし…
まずは普通にカスタムコマンドを登録する処理を記述。これはこのまえやったのと殆ど変わらへんな
このカスタムコマンドの名前についてだけど、まずは普通にさっき決めた名前空間ごと定義してしまおう
あー、結局名前空間入ったコマンドは作るんだ
せやな、名前空間は後程無くしていくで
descriptionもさっき決めた定数をそのまま代入。
permissionLevel、つまり権限もお好みで。
今回はこれは本題ではないので、簡単に使えるようAnyに設定。
引数も特にええかな
で、これが終わったら実行時に発火する関数を定義。これはさっき記述したので、それを入れよう
んー、一応それっぽいスクリプトはできたけど、これは前回のスクリプトの書き方変えただけで本質的には一緒だよね?
どうやって名前空間なくすの?
実は、これと同じようなスクリプトをもう一個書けばええねん
え、どういうこと?
でもただ書くといってもな、今度は名前空間なしで登録。
つまり、nameの部分はcommandNameだけ。
description以下は同様。
え、つまり2つ書くということ?
せやな、こうやって書くことで、1つ目はコマンドの正式版として、そして2つ目はそのコマンドの短縮版として認識されんねん
で、このように書く意図があるからこそ、最初にコマンドの名前とか説明とか複数回書くことが予想される部分は定数にしたってこと
以上でスクリプトの全文は終了。ちなみに、このスクリプトについては、概要欄のリンクからコピペできるから参考にしてみてね
で、実際にこれを書いてゲームを実行すると、こんな感じで名前空間がない、シンプルな「test」というコマンドが登録されてることが分かる?
あー、あるね…、そしてよく見ると下にも名前空間付きのやつがある…
せやな、つまり名前空間無しのコマンドを登録しようとした場合、必然的に名前空間つきのものもできてしまう、って感じやな
まぁ実用上はどっちか好きなほう実行すればええんやし、あんまり問題ないと思うわ
で、これを実行したときの結果は冒頭の通り。ちゃんとコマンドが登録されて実行されることが分かるな
名前空間がないコマンドを作れると、アドオン使う方もだいぶ使いやすくなるし、洗練された印象があるから
是非一度作ってみるとええかもしれへんな
これできると、だいぶ上級者って感じするよね
そして、以上がCustomCommandに関する概要。
ScriptAPIでサポートされているオリジナルコマンドのシステムというのは、大体これくらいで、
次は外部のライブラリに依存した、カスタムコマンドのやり方についても話すわ
というと?
その代表的な例は、冒頭で見せたような日本語でコマンドを実行するようなシステムの構築。
こういうのはScriptAPIだけじゃだめで、外部のライブラリを使わなあかんのやけど、
そのための知識を話す必要があるから、次にその話をするわ
楽しそう!
日本語でのコマンド実行だけど、後述する通りマイクラが公式にサポートしてるわけじゃないから、
現実的にはAIを呼び出して、文脈に応じた処理を自動実行する必要があるわけ。
ということで、マイクラ内にAIを呼び出さないと始まらへんから、先にAIを呼び出すシステムを構築しよう
先に挙動を見せるわ
メッセージ欄にこんな感じでメッセージを送信すると、
AIからの返答が返ってくるっていう感じやな
え、すごい!
勿論、簡単な挨拶だけじゃなくて、
「エンドラを討伐したい」と入力すると…
ちゃんとしたアドバイスが返ってくるし、
クリーパーに拠点を爆破されたという愚痴にも…
いい感じのアドバイスが返ってくるで
「コマンドブロックが欲しい」と入力すると…
こんな感じで入力するべきコマンドを教えてくれんねん
へえ、有能じゃん
ここらへんは流石AIって感じやな
当然、「あなたはだあれ?」みたいな何でもない質問にも
ちゃんとした回答が返ってくるで
頼りになるサポーターって感じだね
サバイバルはもちろんクリエイティブでも役立つし、
何より話し相手として機能するのは強いよな
これって最近流行りのChatGPTなのかな?
せやで、chatGPTをそのままminecraftに持ってきた感じやな
今回はこのAIチャットBotの作り方を解説するで
いつものようにScriptAPIを使うのかな?
ホントはそれがええんやけど、今回はちょっと問題があんねん
え、問題?
ScriptAPIだと普通、importでマイクラのモジュールを持ってくるんやけど
今回みたいな完全に外部のモジュールを
importするのはできへんのよ
つまりScriptAPIは使えへんってわけ
え、じゃあムリってこと?
さっき実際にできたやろ
じゃあ、どうやるんだろう?
結論から言うとこれはアドオンじゃなくて、
WebSocketServerという仕組みを使ってんねん
どういうこと?
今回はマインクラフトとサーバーとの間で
リアルタイムで常時情報のやり取りをしている感じやな
具体的にはチャット欄に文字が送信されたときに、
その情報をサーバーに送ったうえで、
サーバー側でAIの返答を用意してそれを返す、という仕組み
まずはこのサーバーの部分を作っていこう!
まず必要なものはこんな感じ。
何らかのテキストエディタと、node.jsを前提に解説するで
え、node.jsっているの?
今回はjavascriptでサーバーを構築していくから必須やけど、
当然pythonとかCとか他の言語で構築する場合は不要やな
概要欄にそれぞれのリンクがあるで
まずは適当な作業フォルダを作って、それを開こう
これは何でもいいの?
せやで、自分で分かりやすいパスやとええかもな
このフォルダ内で右クリックしてファイルを作成しよう
名前は何でもええんやけど、今回はmain.jsとするで
これを開いたらファイルメニューを選択して
中にあるopen folderを選択。
この作業フォルダを選択しよう
次にTerminalからnew terminalを選択して、
ターミナルを表示しよう
そしてここにnpm initと入力。
色々出てくるけど、全部エンターでOK
ちなみにこの処理にはnode.jsが要るから注意な
続いてnpm install ws uuidと入力
これはどういう意味?
今回必要になる二つのモジュールをインストールするコマンドやねん
これが完了したら、色々ファイルが生成されるで
これを確認したら、早速スクリプトを書いていこう
どんなスクリプトを書くの?
まずはサーバーを構築して、マイクラとの交信を可能にするで
まずはさっきinstallした二つのモジュールを読み込み、
WebSocketServerを作っていこう
定数を頭文字からとってwssとして、
port番号を定義。
次にサーバーへ接続したときに発火する関数を定義しよう
引数をsocketとして、
接続成功時にメッセージを送信。
これで無事接続できたかどうか分かるわけやな
これって実際に動くのかな?
じゃあ、ちょっとやってみようか
その前に一つやることがあって、
コマンドプロンプトを起動してこんなコマンドを入力しよう
何この暗号…
これでマイクラがlocalhostと接続できるようになんねん
マイクラを起動して、適当にワールドを作成。
今回はコマンドを使うから、チートはオンにしよう
vscode側でF5キーを押して、Node.jsを選択しよう
そしてこの緑のマークを押すとこのスクリプトを実行できるで
ワールドの起動が完了したら、チャット欄を開いて
connectコマンドを使ってさっき作ったサーバーと接続。
ポート番号はさっき設定したものと同じにしよう
なんか出てきたよ?
ちゃんと接続できたことが分かるな
サーバー側の表示もOK
今回はプレイヤーのチャット欄を監視するわけやけど、
このイベントを予めsubscribeしてマイクラ側に送信しよう
送信するときのフォーマットは決まってるから
この通りに書いていこう
messageTypeはcommandRequest、
messagePurposeはsubscribeとしよう
そしてこのJsonObjectをsend関数で送信。
続いてプレイヤーがmessageを送信したときに発火する関数を定義
rawDataとisBinaryを引数として
まずはJson形式で送られてきたrawDataを変換。
これを定数dataに格納しよう
続いてコマンドとして出力するためのオブジェクトを定義。
このフォーマットも大体決まってるからその通りに記述。
これでコマンドの実行をマイクラ側に指示することができんねん
結構大事だ
せやねん
具体的なコマンドの内容はこんな感じで記述しよう
今回はテストとしてsayコマンドで試してみるで
最後にこのオブジェクトをJson形式に変換して、
send関数を使ってマイクラ側に送信しよう
一旦このスクリプトを動かして、
試しになにかメッセージを送信すると…
なんか出てきた
こんな感じでsayコマンドが自動実行されるわけやな
続いて今回のメイン、aiを呼び出す関数を作っていこう
まずは非同期実行の関数、open aiを宣言。
引数はaiに送信するメッセージとしよう
続いてchatGPTを外部から呼び出すのに必要な、
apiキーをここで設定。
apiキーはこのサイトで入手できるし、
方法について検索すると結構色々出てくるで
ここにapiキーを入力したら、
fetch関数を使ってchatGPTからの返答を取得しよう
URLはこちら
続いてこのURLにリクエストを送信。
内容はある程度決まってるから、この通りに書こう
一応補足すると、これは呼び出すchatGPTのモデル。
GPT 4oがおススメかな…
そしてこれはシステムとして送信するメッセージ。
要は、あなたはマイクラのアドバイザーですよ、といってるわけやな
これが終わったらjson形式で返答を取得して、
messageのcontent部分を抽出したものを取得し、
最後にreturnしてこの関数部分は終了
続いてさっきの部分に戻って、
マイクラで送信されたメッセージを取得。
どんなメッセージに対しても無条件でaiの返答が返ってきたら困るから
どりあえずメッセージがはてなで終わるものに制限して、
さっき作った関数を呼び出し。
これが非同期実行であることを考慮して、
aiの返答、responseを引数として発火する関数を定義
とりあえずこの返答をコントロールに表示してみよう
他の部分もif文の中に入れてしまおう
そしてマイクラでメッセージを送信すると
あ、コンソールに返答が表示されてる
あとはこれをマイクラ内で表示するだけやな
今回はtellrawコマンドで表示していくんやけど、
長すぎる文章は表示できへんみたいやから、
点や改行で分割してそれぞれについて表示していくわ
なるほど
いまやってるのはaiの返答を分割するところやな
for文を使ってそれぞれについてtellrawを実行していこう
ちなみにメッセージの送信者はbody.senderで取得できるで
実際にマイクラでメッセージを送信すると…
あ、ちゃんと返答が表示されてる
もちろん、他の文章でもOK
これ、実際に動くと結構楽しいのでみんなもやってみてね
これってアドオンじゃないんだよね…
せやねん、だけどアドオンじゃないからこそ、
本来できなかったことができるようになるという点で、
かなり自由度が上がんねん
WebSocketServer、みんなも触ってみてね
そしてこの方法を用いて、実際に日本語でコマンドを実行できるシステムを作っていこう!
ホントにそんなことできるの?
百聞は一見に如かずやな、ここに「ダイアモンドが欲しい」と入力するやろ?
そしたら実際にダイアモンドが手に入んねん
確かにインベントリ内にもダイアモンドが入ってるな
同じように、エメラルドが欲しいと入力すると…
ちゃんとgiveコマンドが実行されてエメラルドが手に入んねん
コマンドの実行結果もOK
すごいね、どうやってるんだろう?構文解析?
その辺の事情は後で話すわ
実はgiveコマンド以外も使うことができて、例えばここに「ゾンビを倒したい」と入力すると…
あ、ゾンビが倒されて腐肉が落ちてる
同じように、アイテムを消去したいと入力すると…
あ、きれいになくなった!
コマンド自体の実行結果もOK
こんな感じで、発言に応じて意図をくみ取ったコマンドを実行できんねん
最後に、ここにいる村人に、毒の効果を付けてみよう
え、そんなこともできるの?
それができんねん、とりあえず「村人を毒にしたい」と入力
すると実際にコマンドが実行されて、
村人が毒になってることが分かるな
いろいろできるんだね
次はこのやり方について話すわ
で、おそらく方法はいくつかあるんやけど、まずパッと思いつくのが葵もさっき言ってた構文解析的なやり方
要は日本語の文章を解析して、「欲しい」という単語があったら機械的にgiveコマンドに変換するっていう感じやな
それが自然に見えるけど…
だけど「欲しい」じゃなくて「入手したい」とか「得たい」とか別の語句だった時にはこの方法は使えへん
そうじゃなくても、例えば「頭が赤い魚を食べる猫」っていう文章があったとするやん?
有名な文章だね
たったこれだけ文章なのにいくつかの解釈ができんねん
日本語って難しい…
で、それを踏まえると統計学的手法、とりわけニューラルネットワークを用いた方法が取り得るわけやな
今回はchatGPTの力を借りてこれを実装してみよう
そういえばこの前、chatGPTをマインクラフト内で呼び出す方法について解説してたよね
せやな、あそこで使ったスクリプトをちょっと変えて、自然言語でコマンドを実行できるようにしてみよ!
基本的にこの前のスクリプトのうち、大きく変えるのはsystemに与えるmessage部分かな
あ、これをコマンド生成に特化させなきゃいけないのか
とはいえ、それを長々と書くのは無理があるので、ここでは引数としてsystemにmessageを送るにとどめておこう
そういうのは別のファイルにまとめておくといいのかな?
せやな、それを踏まえてまずはfsモジュールをもってこよう
require関数で定数fsを定義。
続いてファイル名を引数としてその中身を取り出す関数を作っていこう
関数名はreadFileContent、引数名はfilePath
定数dataを宣言して、ここに非同期実行であることを考慮しながらファイルの中身を格納しよう
最後にtoString関数でこれをstring型にしたら、それをreturn。
一応、try catch文で予期せぬエラーにも対応しておこう
それが完了したら、aiを呼び出す前にreadFileContent関数を呼び出し。
とりあえずファイル名をsystem.txtとして、その内容を取得して引数に代入しよう
これでaiにそのメッセージが送れるのね
せやで、最後に送られてきたコマンドをそのままcommandLineに入れてコマンドを実行。
send関数でマイクラに送信するのも忘れずに。
最後にAIに送信するメッセージを定義して、これをsystem.txtとしよう
なんか、思ったより長いね
まあ、どうしてもaiにマイクラのコマンドについて教えなあかんからしゃーなしやな
最初に役割と制約を与えて、次にマイクラの主要なコマンドの例を教えてる感じ。
確かにずらっとコマンドが並んでるね
chatGPTのapiがknowledgeに対応していたら楽なんやけどな
最後に各種ターゲットセレクターについての基本的な知識を与えて、終了。
さて、実際にこのweb socket serverと接続してみよう
やり方は前回と同じ。
続いて「ダイアが欲しい」とこちらの意思を伝えると…
あ、コマンドが実行されてる
こんな感じで、日本語のメッセージからコマンドが実行されてることが分かるな
ちょっと変わったメッセージも試してみよう
villagerを上空に移動させたいと入力すると…
へー、すごい。色々できるんだね
でも、これが実用化したら世の中のコマンド解説者の立つ瀬がなくなると思うんだけど…
まあ、まだ大丈夫なんとちゃう?
たぶんexecuteとかscoreboardとかはまだムリやろ
教えるだけでは…
こんな感じで、外部ライブラリ使えばチャット欄の検知から日本語でのコマンド実行も可能になんねん
外部ライブラリつながりで、もう一つ面白い方法があるから紹介するわ
ちょっとこの画面見てほしいんやけど..
なんか左上に表示されてるね?破壊したブロック?
せやで、こんな感じで破壊したブロックとプレイヤーを表示したり、
チャット欄を監視して、特定の語句があったら何かを実行する、
カスタムコマンドみたいなことをやりたくなること、あらへん?
あー、イベントをトリガーして何かを実行するやつね。それってコマンドでできないの?
マインクラフトのコマンドシステムって、プログラミングとちゃうから条件分岐とか制御構文は苦手やねん
じゃあ、カスタムコマンドとかブロックの破壊をトリガーするのはムリなのか..
あれは? ScriptAPI。こういうときこそ、出番でしょ?
確かにこれはJavaScriptというプログラミング的アプローチをとるからそういうのも可能ではあるんやけど…
ちょっと複雑なこと…例えば外部のAPIとかライブラリを用いた発展的なことをやろうとすると案外力不足なんよ…
で、今回の動画はタイトルにもある通り、ScriptAPIとは別の方法でイベントのトリガーと実行をやってみよう、って話。
結論を言うと、鍵を握るのがbedrockpy。
なにそれ?アップルパイの仲間?
食べ物の話してどうすんねん…
これは、Pythonっちゅうプログラミング言語のライブラリの1つで、
簡単に言えばPythonを用いてゲームに干渉し、いろんなイベントをトリガーすることが可能になんねん
え、Pythonでゲームを動かせるの?
そういうことになるな
冒頭の映像も、実はPythonでコマンドを実行して作ってんねん
へー、ScriptAPIじゃないんだ。
でもさ、Pythonでゲームを動かして何が楽しいの?
一番大きいのは外部のライブラリを使える点やろうな
例えばChatGPTのAPIを使うことでマイクラ内でAIと会話できるシステムをPythonで構築したり
ファイルの読み書きも可能になるから、データの保存とか、あるいはデータベースを参照してワールドに変化を加えることもできるかも
面白そう。ScriptAPIじゃできないところだね
百聞は一見に如かずということで、まずは簡単なスクリプトを書いてみよう
で、まず必要になるのがPythonの開発環境。
このチャンネルでPython触るの初めてかな?
せやな、まだインストールしてへん人はまずはこのページからインストールしよう
Pythonは今はやりの言語やし、何かとあると便利かも。
で、あともう一つはこのライブラリそのもの。
Pythonが使える環境ではpipも使えると思うから、ターミナルでこのコマンドを実行してインストールしよう
そしたら適当な場所を開いてpythonのファイルを新規作成。
(適当な名前).pyという名前であればOK。
そしたらこれをVSCodeのようなテキストエディタで開いて
最小構成となるスクリプトを書こう
まずは先ほどインストールしたライブラリから必要なmoduleをimport。
続いてServerオブジェクトを作成して、それを変数appに格納
最後にapp.startでサーバーを起動。今回は公式リファレンスに沿ってポート番号を6464としてみよう
スクリプト全文はこんな感じ。概要欄にあるサイトからコピペできるで
これで終わり?何か特別なことをしているようには見えないけど。
スクリプトの最小構成としては、そう。まずはちゃんと動くか見てみよう
ターミナルを開いてこのコマンドを実行するか、
VSCode右上の矢印マークを押せばOK。
ターミナルの方には何も表示されてへんとは思うけど、
マインクラフトのゲーム内で、こんな感じのconnectコマンドを実行して…
「サーバーへの接続を確立しました」と表示されれば成功。
それが分かれば一旦実行中のターミナルを中止して…
次にイベントをトリガーするスクリプトを書いてみよう
どんなスクリプトを書くの?
まずはさっき見せたように、簡単にブロックの破壊をトリガーして、メッセージとしてそれを送信する例。
非同期で実行する関数block_brokenを定義して、引数をctxとしよう
続いてブロックを破壊したプレイヤー名を取得してそれを変数に格納。
プレイヤー名はこんな感じで取得できるで
なんでそんなの分かるの?
この事情は後で話すわ
同じように、破壊されたブロックも取得して変数に格納
今回は、ctx.id。
次に、これらの変数を元に出力する機構を作っていこう
ctx.server.runで任意のコマンドを実行出来て、
この引数にsayコマンドを指定する感じでええかな
あ、f文字列だ
Pythonらしいよな
そしたらこれを保存して、同じように実行しよう
接続が切断されているので、再度connectコマンドを実行するのも忘れずに…
これでブロックを壊すとメッセージが送信されてるのが分かるやろ?
ホントだ。sayコマンドが実行されてるのかな?
こんな感じでPythonを使ってゲームに干渉できてることが分かるな
同じように、プレイヤーのメッセージを監視してそれに応じて何らかの処理を行う関数も書いてみよう
非同期で実行する関数、player_messageを定義して、引数をctxに設定。
さっきも使ったctx.server.runでダイアモンドを1つ与えるコマンドを実行してみよう
ここでメッセージを送信すると…
あ、ダイアモンドが増えてる
これはメッセージの文言によらず、メッセージの送信をトリガーしたら必ず特定の処理を行う例やな
これを応用してカスタムコマンドを作りたいね
やってみよっか
さっきの関数に戻って、まずは送信されたメッセージ自体を取得して変数に格納しておこう
これはctx.messageなんだ
そしてif文を用いてもしこのメッセージが「?」で始まるなら…
このコマンドを実行するよう定義すると、
例えば「?テスト」というメッセージだとコマンドは実行されるし、
「test」だと実行されへん
メッセージに応じて処理を変えることもできるんだね
で、このif文の中身を変えてメッセージが「?diamond」であるかどうかを判定するようにすると…
完全一致で「はてなdiamond」というメッセージでないとダイアモンドはもらえへん
これが事実上のカスタムコマンドとして動作するんだね
せやな
他にもこんなのをトリガーできるよ、という例として…
アイテムを右クリックして使用したことを検知してみよう
ScriptAPIで簡単にできるよ…?
Pythonでやるからええんよ..
ここでは非同期関数、item_usedを定義しよう
で、ここでアイテムを使用したプレイヤーとか、使用したアイテム名を取得したいなあ、って思うやん?
もちろん。どうするの?
それが分からへんのよ…
ダメじゃん
で、そんなときにどうすればええのか、って話。
まずはprint(ctx.data)と書いてみよう
データを出力するのかな?
そういうこと。
で、ゲーム内でなんでもいいから使えるものを手に取って
右クリックして使った後にターミナルを見ると…
なんか色々表示されてるね
ここに表示されてるObjectを元にこれを解析すればええことが分かるな
ということで、改めてスクリプトを書き直そう
使用したアイテムは、さっきのdataのitemというキーのidに保存されていることが分かるから、このようにして取得。
同じように、player名も取得して変数に代入しよう
これはさっきと同じだね
このprintは要らんから削除して、代わりにこれらの変数からコマンドを実行するスクリプトを書いてみよう
この状態でくもの目を使うと…
あ、左上にメッセージが出てきたね
カスタムアイテムのチョコミントアイスも…
あ、こっちも表示されてる。名前空間はない感じかな?
たしかdataにnamespaceが含まれてたと思うから、そこから抽出することで名前空間も表示できそうやな
で、最後に何がトリガーできるの?という問題。
これに関してはbedrockpyの公式リファレンスにほとんど書いてて、他にもブロックの設置とかワールドへの参加とかトリガーできるみたいやで
割とできること多そう
これと外部のライブラリを組み合わせたらだいぶ自由度が広がると思うわ
うp主もこれを使ったプロジェクトを2つほど計画中だったり。
ということで、Pythonを使ってマイクラを操作できるbedrockpyの紹介でした
ScriptAPIと使い分けつつ…って感じかな?
それもええかもな。ただ、これ自体はアドオンじゃない点には注意。
結構楽しいので、皆も触ってみてね!
でもさ、ここで定義した疑似カスタムコマンドって普通にScriptAPIで定義するのとどう違うの?
これについてはさっきも軽く触れたけど、大元がPythonなんよ、
だから、本来ScriptAPIではできひんかったこと、例えばAIの導入とかDiscord、XのAPIと組み合わせて何かやるみたいな、
より複雑で外部のライブラリを呼び出すようなカスタムコマンドを定義できるっていうのは強みかもしれへんな
あー、それはだいぶ自由度が高いね
という感じで、カスタムコマンドの概要についてはこんなところかな
ここで話したことはあくまで基礎で、これを使って色々試してみることでオリジナルのアドオンだったりソフトだったりができると思うわ
こうしてみると、コマンドって奥が深いんだね、
普通に色々コマンドを実行して遊ぶのも楽しいけど、自分でコマンドを作るという分野も結構興味深いものがある…
みんなもオリジナルのコマンドを定義して遊んでみてね!
ということで、今回の動画はこれでおしまい
ここまでのご視聴、お疲れ様です
質問や雑談のためのDiscordチャンネルもあるので、是非覗いてみてください!
それじゃー、
ばいばーい
ばいばーい