データパックを見やすくするためのフォルダ分け

執筆開始:2022-12-20 16:50:31
# 目次
- [データパックを見やすくするためのフォルダ分け](#データパックを見やすくするためのフォルダ分け)
- [目次](#目次)
- [目的・前提](#目的前提)
- [データパックのフォルダ構造](#データパックのフォルダ構造)
- [関数フォルダ](#関数フォルダ)
  - [簡単に言うと](#簡単に言うと)
  - [外部から呼び出す関数](#外部から呼び出す関数)
  - [処理グループ](#処理グループ)
- [ルートテーブルフォルダ](#ルートテーブルフォルダ)
- [進捗フォルダ](#進捗フォルダ)
- [最後に](#最後に)

# 目的・前提
データパックの``functions``や``loot_tables``など、多く作るファイルのフォルダ階層をどう決めているかをメモしたかっただけ。文体と敬体が余裕で混ざっています。
固定のルールとかは聞いたことがないのでりっとーの自由な作り方を明文化しようということです。
前提知識として関数を作ったことがある程度の知識を要します。


# データパックのフォルダ構造
いいのがあったのでお借りしました
```
datapacks
└── (データパック名)
    ├── pack.mcmeta
    └── data
        ├── minecraft
        │   ├── loot_tables
        │   │   └── entities
        │   └── tags
        │       └── functions
        └── （名前空間）
            ├── advancements
            │   └── xxx.json
            ├── functions
            │   └── xxx.mcfunction
            ├── item_modifier
            │   └── xxx.json
            ├── loot_tables
            │   └── xxx.json
            ├── predicates
            │   └── xxx.json
            ├── recipes
            │   └── xxx.json
            ├── structures
            │   └── xxx.nbt
            :
```
引用元(一部改変):https://micrapap.fc2.net/blog-entry-2.html

※厳密には``minecraft``も名前領域のひとつとなりますが、この名前領域は他と違う挙動をするものがあるので分離して考えます。
メインテーマは``functions``フォルダ内のことを取り上げますが、json形式のフォルダの代表例として``loot_tables``と、他と違う特殊な例として``advancement``を紹介します。

# 関数フォルダ
データパックの目玉である関数。
その中身の整理をどうしているかを紹介します。
```
functions
├── 処理グループ1
│   ├── main.mcfunction
│   ├── tick.mcfunction
│   └── その他関数名.mcfunction
├── tick.mcfunction
├── load.mcfunction
└── その他呼び出し用関数名.mcfunction
```
私が関数を作るときはだいたいこういうフォルダ構造になっています(もちろん必要に応じてさらに子どもフォルダを作成することもある)。

## 簡単に言うと
1.  外部受付を一番上で行う
2.  受け付けられた関数をざっくりとした環境・条件ごとにフォルダに振り分ける
3.  フォルダの入り口を``main``か``tick``が担い、フォルダ内の関数振り分ける
4.  必要に応じて2と3を繰り返す

## 外部から呼び出す関数
外部から呼び出す関数は``functions``直下に設置します。これにはいくつか目的があります。
-   チャット欄から呼び出しやすくなるため
-   処理のトレースをしやすくするため

ゲームなどのデバッグで恣意的にあるプレイヤーにイベントを起こさせたいときに、この構造にしておくと関数名が長くなりすぎず楽。
そして、かならず入り口は名前領域直下のファイルから実行されるのでデバッグしやすくなると思います。

ただし、この｢外部｣必ずしもデータパックの外という意味ではなく、``functions``より外のフォルダとはから呼び出される場合をすべて外部ととらえています。
例えば、
-   ``tick.mcfunction``
-   ``load.mcfunction``
> このふたつはmcDatapackUtilityの機能として最初にデータパックを作成した時に生成されます(設定次第)。

私がこのファイルを毎tickもしくはリロード時に呼び出されるタグ関数として``functions``直下に設置に設置します。
このほかにも
1.   ``/tellraw``の``clickEvent``で受け付ける関数
2.   看板の``clickEvent``で受け付ける関数
3.   進捗の報酬関数
4.   コマンドで受け付ける関数
5.   他のデータパックから受け付ける関数

も``functions``直下に設置に設置しています。
ただ、特に2や3は多くなってしまいがちなので、その場合はsignフォルダやadvancementフォルダなどを作る場合もあります。

## 処理グループ
前述のとおりすべての関数はかならず[名前領域直下の関数](#外部から呼び出す関数)を通過して通ってきます。この関数だけでデータパックが作れれば楽ちんですが、そこそこ大きめのデータパックを作り始めた時点でこの関数内では行いたい処理を直接書くことは少ないと思います。

なぜならだいたい処理の前に、``execute``などを使って環境を変更したり条件分岐をしたりするからです。
``execute``関数をそうやって書いた場合は私の頭の中ではこんな風に考えています。
-   その条件や環境で複数の処理をしないなら``exeucute..run (chainedcommand)...``とそのまま処理を書く
-   その条件や環境で2つ以上の処理を想定する場合
    -   その条件や環境を通過してくる処理がtickレベルで(1秒間に1回を超えて)何度も繰り返すなら``今の関数名/tick.mcfunction``というファイルに処理を回す。
    -   その条件や環境を通過してくる処理が何度も繰り返さないなら``今の関数名/main.mcfunction``というファイルに処理を回す。

main関数や、tick関数に来た時点で、複数の環境が想定される場合はどんどん絞り込んでいきますが、フォルダを増やさず、同じフォルダに増やしていく形になります。
それでも絞り切れないときにのみ、関数を増やします

# ルートテーブルフォルダ
私がルートテーブルを使う目的は主に二つあります。
1.  アイテムを再現性ある形で配れるようにするため
2.  確率の含む配布をできるようにするため
3.  チェストのコンテナなど、置く場所を決めて複数のアイテムを配置したいとき
```
loot_tables
├── 素材フォルダ
│   ├── c.json
│   ├── d.json
│   └── e.json
├── a.json
└── b.json
```

ほとんどの場合は1の目的で利用します。したがって私が何かを作る時は``/give``や``/item replace``などは全て``/loot``コマンドで事が足りてしまいます。

-   1の目的で使うルートテーブルは、一番上のフォルダにだーっと並べます(``a.json``や``b.json``のように)。
-   2や3の目的で使うルートテーブルは、以下のようにします
    -   選ばれる候補となるアイテムをかならず全てルートテーブルとして記述し適当な名前を付けたフォルダに格納(``a.json``,``b.json``,``c.json``)
    -   上のルートテーブルを複数参照し確率や、配置などを設定したルートテーブルを一番上のフォルダに配置(``a.json``や``b.json``のように)
いずれの場合にしても必ず**アイテム1つにつき1つのルートテーブル**を作成します。
ルートテーブルのファイルに直接複数のアイテムを入れてしまうと、個別で欲しい時に不便になってしまうからですね。
# 進捗フォルダ
私が進捗を使う目的は主に二つあります。
1.  関数のトリガーとして使いたい場合
2.  目に見える進捗として使いたい場合

ぶっちゃけ2で使ったこと過去に一回しかありません笑
ほぼほぼすべて1として使います。この場合であれば目に見えることはないし進捗同士の関係性が一切生まれないので親フォルダに全て並べるのみとなります。
ただし、2の場合と併用する場合はみやすさのためトリガー用のフォルダを作成しそのなかに格納します。

2の目的の場合は、少し事情が異なり、進捗同士の親子関係が生まれます。
-   親の進捗を一番上のフォルダに置きます。
-   進捗画面においてタブが分かれるのでそのタブごと(つまり親の進捗)にフォルダを作成します。
-   フォルダ内には子の進捗を取得する順に数を付けて上から順に並ぶようにします。

> なお、進捗の縦の表示順やタブの表示順は厳密にはhashCodeの順番に名前領域と進捗名を並べれば制御できるそうですが非常に煩わしいのでやっていません。hashCodeの順番と字面だけ聞いたことがあるだけなので正直なんのことだかわかってない・・・

# 最後に
あくまでも、自分の分け方の参考でした。
別にみんながこうしてるってわけではないかなぁと思っています。
進捗やルートテーブルはファイル数が多くないので、正直適当でもいいかなぁと思っている節があります。
関数の場合はデータパックでゲームを作る身なので、外部受付の関数は多くなく、逆に毎tick動かす関数の役割が重たいこともあって関数同士を繋げながら作っています。
逆に、脱出マップを作る方などは比較的外部受付の関数が多くなると思うのでそちらのフォルダ分けのほうが大事になってくるのかもしれないのかなと書いている途中で気づきました。
つまり、何を作るかによってもこういうのって変わってくると思うので、本当に参考までに、と。
執筆終わり
2022-12-22 03:04:40