アドオン初心者のほとんどはプログラミング未経験者かつプログラミング(に近いこと)について全く触れたことがないということが多いです。そんなひとがJSONというものに直面して簡単に理解できるなんてよほどの天才でない限りないです。
はじめてやるプログラミングっぽいこと、JSONでくじけたりするひとが多いのでわたしは普段からアドオンをなめるな、ちょっとやり方を聞いてできる裏技程度に思って飛び込むなといっています。
だからと言ってちゃんと本を買ったりしてマジメにJSONを勉強するのも気が引けます。ゲームでやりたいことがあるだけなのにそこまでしなくても、ゲームに勉強の要素を持ち込みたくない、誰だってふつうはそう思います。
そのために、今回はアドオンで使うJSONを簡潔に理解できるようにまとめました。
● JSONの基礎
JSONは「こういうようなこと」がはじめてのひとからすればプログラミングのように見えますが、実はあれはただデータをズラッと並べているに過ぎません。複雑なのは「データの入れ子」だと思います。
◆すべての始まり
まず最初から実際に使われている、テンプレートにあるような長いJSONじゃなくて一つずつ事柄を理解しながらだんだん長いものが理解できるようにしていきましょう。
はじめに「データの入れ子」だと言いましたが、「入れ子」ができるということはそれぞれ「入れ物」が必要です。実際、JSONのすべての始まりはひとつの箱から始まります。
もっとも簡単なJSONはこれです:
{}
このカッコを使って箱を表し、この箱を入れ子にして複雑なデータを表現します。
そしてこのカッコで表された箱全体のことを「オブジェクト」と言います。
◆箱に入れるもの
箱には当然中身が存在します。まずは書き方を見てみましょう。
{ "contents": "abc" }
箱にひとつ「プロパティ」という中身を入れてみました。これでもJSONとして認識されます。
中身が何を意味しているかというと、「contents は abc だよ」と言っています。別に変数名はcontentsじゃなくてnameでもいいですし、valueでもなんでもいいです。とにかく「contents は abc だよ」というデータが格納されています。なんでもいいと言いましたが、日本語は基本よくないと思っておいてください。英語が苦手な方は──ローマ字なら書けますか??
あと、ダブルクォーテーション「”」は絶対に書き忘れないでください。書き忘れるとJSONとして認識されなくなり、不具合の原因になります。
そして基本の形はこうなります。
{ "変数名": 値 }
◆値の形
さきほどの例でいう「"abc"」の部分にはいろんな「値」が入ります。「"abc"」なら「ストリング型」という「文字列」です。何かの名前データだったり、アルファベットを含むIDを参照するときに使いますね。「”」ではさまれた値はだいたい全てストリング型です。逆に、これから紹介する「”」がいらないもの以外で「”」をつけ忘れるとエラーになるので注意してください。
{ "containts": "abc" }
また、数も入れることができます。「整数型」と「小数型」です。「整数型」は整数だけです。整数型をいれないといけないプロパティに小数をいれるとJSONとしてあっていてもマイクラ側が許してくれないのでこちらも不具合の原因となります。
「小数型」は小数と整数どちらも扱えます。「小数型」でも「1.0」を「1」と書くことができますが、どこが「小数型」しか入らないのか分からなくなるので「1.0」のように整数でも「.0」をつけて書くことをおすすめします。あと、以外と忘れがちなのが「整数型」も「小数型」もどちらも負の値(マイナス)が使えます(使えないときもあります)。
そして「”」は必要ありません。つけてしまうとストリング型だと見なされます。
{ "contents": 1 } { "contents": 0.5 }
そしてもうひとつ重要なのが「ブーリアン型」です。「はい」か「いいえ」の二択で決めるものはこの型で値を設定します。
値の種類はもちろん二つしかなく、「はい」を表す「true」と「いいえ」を表す「false」の二択です。「”」は必要ありません。
{ "contents": true } { "contents": false }
問題は次だと思います。実はオブジェクトも値として入れられるんです。
JSONが見づらいのはこのカッコの入れ子が見えていないからです。逆にこのカッコの入れ子が見えてしまえばほとんどJSONは怖くありません。
{ "contents": { "value": "abc" } }
その繋がりで説明してしまうと、アレイという「[]」で表す新しい種類の箱も値として扱えます。詳しくは後ほど説明します。
{ "contents": [ 0, 1, 2 ] }
◆プロパティを並べてデータの詳細を表現する
これからどんどん大きなJSONを扱えるようにしていきましょう。プロパティを並べるときはカンマ「,」を使います。カンマも絶対に書き忘れたり余分につけたりしないでください。
{ "contents_str": "abc", "contents_dec": 1.5, "contents_obj": { "contents_bool": true } }
これぐらいならギリギリ見切れると思いますが、少し見づらいですね。並び替えましょう。
{
"contents_str": "abc",
"contents_dec": 1.5,
"contents_obj": {
"contents_bool": true
}
}
こうして改行を用いて見やすくすることを「整形」と言います。改行や半角の空白、Tabの空白は自由に挟めるので、一部だけ整形したり改行をわざと増やしてかたまりを区別しやすくしても構いません。(上の例では見やすくするために全角の空白を使っていますが実際のJSONで使うとエラーになるので注意!)
どうですか?そろそろ本場ののJSONを見ても理解できるようになってきたんじゃないですか?
◆アレイとオブジェクト
アレイとオブジェクトはどちらも例えていうなら箱です。では、何が違うのでしょう?
アレイの中身には値のみ、オブジェクトの中身はプロパティのみしか入りません。よって次の例は間違いです:
[ "contents_a": "abc", "contents_b": "def" ]
{ "abc", 1.5, {} }
なんとなくわかりましたか?一番外側のカッコの中身同士を入れ換えれば正解になります。
[ "abc", 1.5, {} ]
{ "contents_a": "abc", "contents_b": "def" }
◆コメントアウト
どうしても英語ばっかりではじめはどこに何が書いてあるのかわからなくなったり、上級者になって複雑なものを作ったときあとで自分がみてわからなくなったりするかもしれません。そこで、ちょっとしたメモなどを書いてもエラーにならない方法があります。それがコメントアウトです。
{
"apple": { //リンゴについて
"color": "red", //色
"food": true //食べ物かどうか
}//コメントアウトは「”」の中身でなければどこでも置けます。
//スラッシュ二本のコメントアウトはスラッシュより左一行すべてを認識から除外し、
/*スラッシュとアスタリスクのコメントアウトを使うと、
閉じるまで改行をまたいで認識から除外できます*/
}
そして大事なことがひとつあります。普通、JSONではコメントアウトができないのですが、マインクラフト独自のルールで可能になっています。つまりコメントアウトがある状態でJSONチェッカー(JSONが正しいかどうかチェックするもの)に通したときに間違いだと指摘されてしまいます。
●実際に使われているものを見てみる
一気に読むJSONの大きさを大きくしていきましょう。
まずはアドオンのなかで最も複雑な、エンティティのjsonの代表として「player.json」を見てみましょう。
何が書いてあるかわかったとしても量が多いとさすがに難しいでしょう。なによりカッコの入れ子が尋常じゃありません。そこでおおまかな外形を、浅い層から見ていきましょう。
やはり基本は「{}」です。その次の層は「{ "format_version": "1.16.0", "minecraft:entity": {} }」です。
{
"format_version": "1.16.0",
"minecraft:entity": {}
}
問題はこの「"minecraft:entity"」のオブジェクトの中身です。
次の層の区分は「"description"」「"component_groups"」「"components"」「"events"」の四つに別れており、それぞれがオブジェクトを連ねているのでこれらを見つけるのに上下探し回ったことでしょう。
{
"description": {},
"component_groups": {},
"components": {},
"events": {}
}
実はあとそれぞれの中身に細かいプロパティが並んでいるだけなので、この四つが大きなかたまりであるとわかってしまうととたんにどこに何があるかなんとなくわかってくると思います。
少しだけアドオン作りの話をすると、「"components"」にあるコンポーネントでイベントを起こすと「"events"」からイベントを検索して、イベントの中身の指示にしたがって「"component_groups"」にあるコンポーネント群を付加したり消去したりします。
「"events"」の中身だけ入れ子が深いので噛み砕いた説明をしておきます。まず「"イベント名"」のプロパティがいくつか並んでおり、その中で「"add"」と「"remove"」に別れ、その中身に「"component_groups"」というアレイを値にもつプロパティがあります。
{
"イベント名": {
"add": {
"component_groups": [ "group_a" ]
},
"remove": {
"component_groups": [ "group_b" ]
}
}
}
個人的にはアレイでも値がひとつなら整形しません。整形しすぎても見づらくなることはあるのでいろいろ自分で見やすい書き方を探してください。
コンポーネントも基本は「"コンポーネント名": 値」か「"コンポーネント名": { "プロパティ名": 値 }」という形をしていますが、データが多いものだと多少複雑になるので説明を加えておきます。「player.json」の137行目あたりにある「minecraft:environment_sensor」コンポーネントはそのひとつです。わたしもいまだに「"event"」が「"triggers"」と「"filters"」のどちらと並列なのかいまいち見づらいです。
正解は「"triggers"」の中身に「"filters"」と「"event"」があるので並列しているのは「"filters"」です。「"filters"」の中身は「"all_of": [ {}, {} ]」となります。
{
"triggers": {
"filters": { "all_of": [ {}, {} ] },
"event": " "
}
}
ところが実は、「minecraft:environment_sensor」コンポーネントは条件を増やすことができ、「player.json」にあるものは条件とイベントの組がひとつしかないケースです。そこで、「bee.json」を参照してみましょう。289行目に「minecraft:environment_sensor」コンポーネントがあると思います。「"triggers"」に連なるカッコをを見てみると、どうやらオブジェクトではなくアレイを率いているようです。じつは複数の条件とイベントの組を抱えているわけではないのですが、複数ある場合の書き方で書いているようです。
そこで復習です。アレイの中身にはプロパティではなく値を連ねるんでしたね。先程と同様に「"triggers"」の中身に直接「"filters"」と「"event"」は置けません。
複数に対応できるということもあって、こういう構造をしています:
{
"triggers": [
{ "filters": {}, "event": " " },
{ "filters": {}, "event": " " }
]
}
このように「"triggers"」の中身はオブジェクトをいくつでも並べられるようになっているんですね。
これぐらいが簡単ならばもうJSONは怖くないと思います。とにかくオブジェクトのかたまりを、どこからどこまでがひとつのかたまりなのか、どれとどれが並列なのかを見極めるのがコツです。そして慣れてくればどんな形でも迷子にならないと思います。
最後に、もうひとつ入れ子が複雑なものを紹介します。loot_tables/entitiesにある「armor_set_chain.json」です。
{
"pools": [
{
"rolls": 1,
"entries": [
{
"type": "item",
"name": "minecraft:chainmail_helmet",
"weight": 1,
"functions": [
{
"function": "enchant_random_gear",
"chance": 0.25
}
],
"pools": [
{
"conditions": [
{
"condition": "random_difficulty_chance",
"default_chance": 0.50,
"peaceful": 0,
"hard": 0.6
}
],
"rolls": 1,
"entries": [
{
"type": "item",
"name": "minecraft:chainmail_chestplate",
"weight": 1,
"functions": [
{
"function": "enchant_random_gear",
"chance": 0.25
}
],
"pools": [
{
"conditions": [
{
"condition": "random_difficulty_chance",
"default_chance": 0.50,
"peaceful": 0,
"hard": 0.6
}
],
"rolls": 1,
"entries": [
{
"type": "item",
"name": "minecraft:chainmail_leggings",
"weight": 1,
"functions": [
{
"function": "enchant_random_gear",
"chance": 0.25
}
],
"pools": [
{
"conditions": [
{
"condition": "random_difficulty_chance",
"default_chance": 0.5,
"peaceful": 0,
"hard": 0.6
}
],
"rolls": 1,
"entries": [
{
"type": "item",
"name": "minecraft:chainmail_boots",
"weight": 1,
"functions": [
{
"function": "enchant_random_gear",
"chance": 0.25
}
]
}
]
}
]
}
]
}
]
}
]
}
]
}
]
}
]
}
最後のカッコ閉じが、アレイとオブジェクトあわせて19コンボです。すべての抽選が必ず行われるための工夫でしょうか。
入れ子が深いだけで特別難しいこともなく、ただただ面倒なので説明はしません。JSONがわかるようになって腕試しをしてみたいひとは挑戦してみてください。
●このサイトにおける指示
このサイトではいくつものjsonの編集を指示していくことになるので、わたしがそのときに指示したことがどういうことかわかってもらわないと正直この記事を書いた意味があんまりないわけです。例えば、これを消してと指示したときに変なところを消してjsonの構文を崩してもらっては、教える意味がありません。
◇どんな型の値を使う?
コンポーネントは、値にどんな型の値をいれればいいか決まっているので、コンポーネントを紹介する際に値の型も説明するんですが、そのために省略記号を用いて説明することがあります。
Str:ストリング型
Int:整数型
Dec(Float):小数型
Boo(Bool):ブーリアン型
Obj:オブジェクト
Vec3:アレイ[ Dec, Dec, Dec ] Vec2なら[ Dec, Dec ]
◇ますえく流呼び方
基本は上で教えた通りの名称で呼ぶと思いますが、まとめておきます。
{
"property1": "value",
"object": {
"array": [ "value", "value", "value" ],
"delate_this": "value",
"delate_those": {
"property2": "value"
}
}
}
「"property": "value"」の部分一行まるごとを「プロパティ」または「パラメータ」と呼びます。基本は「プロパティ」ですが、以下のようにコンポーネントの中身にあるプロパティ(下の例なら"value")だと「パラメータ」と呼ぶことがしばしばあります:
"minecraft:health": {
"value": 20
}
コンポーネントはブロックやエンティティなどを作る際に使うプロパティで、マインクラフト側でプロパティ名は決まっています。詳しくは、ブロックやエンティティなどを作る際に学んでください。
プロパティはプロパティでも、「"object"」のように値にオブジェクトを牽引しているプロパティは「オブジェクト」と呼ぶことがあります。なかなかないですが、アレイを牽引していれば「アレイ」と呼ぶかもしれません。
あとは単にプロパティ名でプロパティ全体を呼ぶことがあります。例えば「"array"」と呼べば「"array": [ "value", "value", "value" ]」を指します。
◇実際の使われかた
少し離れてしまったので先ほどと同じ例をまた貼っておきます。
{
"property1": "value",
"object": {
"array": [ "value", "value", "value" ],
"delate_this": "value",
"delate_those": {
"property2": "value"
}
}
}
もしこのjsonに対して「"delate_this"を(まるごと)消してください」と指示すれば、"delate_this"のプロパティすべてを消します。
{
"property1": "value",
"object": {
"array": [ "value", "value", "value" ],
"delate_those": {
"property2": "value"
}
}
}
今回は消したことが分かりやすいように隙間は開けっぱなしにしていますが、あとでそこに何か付け足す予定がない限りはその行の改行はなくしてもよいでしょう。
はじめの例に戻って、次はミスしやすいのでよく覚えておいてください。例えば「"delate_those"を消してください」と指示したら正しく消せるでしょうか? 答えはこれです。
{
"property1": "value",
"object": {
"array": [ "value", "value", "value" ],
"delate_this": "value"
}
}
間違えやすいポイントは主に二つです。
① 閉じのカッコ「}」を消し忘れていないか
② "delate_this"プロパティの右端にあるカンマを消し忘れていないか
これに気づかずアドオンを作ってしまうと、このミスを含んだjsonはすべて動きません。例えばplayer.jsonで間違えば、プレイヤーに対する変更はすべてなくなり、バニラのプレイヤーになってしまいます。
次は逆にプロパティを追加してみましょう。こちらもよくある操作です。こんなプロパティがあったとします。
"add_this": {
"property3": "value"
}
例えば「"object"の中にadd_thisプロパティを追加してください」と指示した場合はこうなります。
{
"property1": "value",
"object": {
"array": [ "value", "value", "value" ],
"delate_this": "value",
"delate_those": {
"property2": "value"
},
"add_this": {
"property3": "value"
}
}
}
"object"オブジェクトの中身にあるならば順番は自由です。そして重要なのが、追加する場所以前にプロパティがある場合はその直前のプロパティの右端にカンマを、追加した場所以後にプロパティが続く場合は追加するプロパティの右端にカンマをつけてください。両方にあるなら両方、両方ないなら新しくつけるカンマはありません。
あまりないと思いますが、オブジェクトやアレイを率いるプロパティを追加するときは閉じのカッコ「}」や「]」も忘れず追加してください。
このjsonの記事を書いたのは、こういった指示を理解してもらうためということもあるので、今後もわたしの記事を読むならばしっかり身につけてください。
最後に、JSONでくじけやすいのはここからだったりします。少し説明したようにどうしてもカンマのつけ忘れ、ダブルクォーテーションのつけ忘れ、カッコの不足・過剰はありがちです。そのために「JSONチェッカー」なるものがあり、上級者になっても多用されているものです。チェッカーがあっても何がいけないかわからなくては修正のしようがないのでちゃんと復習してください。カッコが足りないからと言って一番後ろの行にポツンとカッコを置いても、箱の層の構造がずれるのでマインクラフト側が許してくれません。
そしていざ自分でもJSONを書いてみようと思ってもミスが起こりがちなので、はじめは値をちょこちょこ変えて「変更」ができたことを楽しみ、次に大きめのオブジェクトを取り替えたり、プロパティ全体を別のjsonから移植してきたり……とだんだんレベルをあげていきましょう。
あと、上級者になっても真っ白なファイルにイチからJSONを書くということはほとんどありません。だいたいテンプレートのようにコピペしています。初心者と違うのは書き換えたり書き足したりするデータの大きさです。面倒ですからね。
それでは、アドオン作りへの初期装備は揃いました! JSONがわからないときよりも格段にアドオンを理解できるようになっていると思います! そして質問の回答者にJSONのミスを指摘されないようにしましょう!
0コメント