カスタムストラクチャーの基本

# はじめに
![2023-05-01_22.29.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3591568/68ff566d-2935-b572-c394-b4ec6b155f67.png)

### ストラクチャーについて
マイクラにおける「ストラクチャー(構造物)」とは何でしょうか？

マイクラの世界を歩いていると、村や前哨基地、古代都市といった建造物が最初から存在していたりします。
こういうものを「ストラクチャー」と呼びます(ネザー化石のように建造物じゃなさそうなものもありますが)。

カスタムストラクチャーでは、更に自分の好きなストラクチャーを**追加**することができます。言ってしまえば自分の好きなダンジョンを追加することが出来るということ。ロマンがあるでしょう？

今回はそのやり方をざっと説明いたします。

#### 「ストラクチャー」という用語について
マイクラでは、「ストラクチャー」と言うと、先程の建造物系のものの他に、それらを構成するパーツを指すことがあります。
後者はゲーム内では「ストラクチャーテンプレート」とも呼ばれているのですが、分かりやすくするために本稿では前者のみ「ストラクチャー」と呼び、後者は「パーツ」と呼ぶことにします。
## ストラクチャーの種類
一口に「ストラクチャー」と言っても様々な種類に分かれています。具体的には以下の通り。

<table style="width:10%;">
 <caption>ストラクチャーの種類一覧</caption>
 <thead>
  <tr>
   <th>種類ID</th><th>説明</th>
  </tr>
 </thead>
 <tr>
  <td>buried_treasure</td><td>埋もれた宝</td>
 </tr>
 <tr>
  <td>desert_pyramid</td><td>ピラミッド。砂漠の寺院とも言う</td>
 </tr>
 <tr>
  <td>end_city</td><td>エンドシティ</td>
 </tr>
 <tr>
  <td>fortress</td><td>ネザー要塞</td>
 </tr>
 <tr>
  <td>igloo</td><td>イグルー</td>
 </tr>
 <tr>
  <td>jigsaw</td><td>ジグソーブロックを使ったもの。<br>自分でパーツを追加したり組み替えたりできる為、<b>カスタムストラクチャーではこれ一択</b></td>
 </tr>
 <tr>
  <td>jungle_temple</td><td>ジャングルの寺院</td>
 </tr>
 <tr>
  <td>mineshaft</td>
  <td>廃坑。普通のものかメサ廃坑かを選べる</td>
 </tr>
 <tr>
  <td>nether_fossil</td>
  <td>ネザー化石。ソウルサンドの谷に点在してるアレ。<br>こう見えてストラクチャーである。生成される高さが設定可能</td>
 </tr>
 <tr>
  <td>ocean_monument$\hspace{2em}$</td>
  <td>海底神殿</td>
 </tr>
 <tr>
  <td>ocean_ruin</td>
  <td>海底遺跡。<br>暖かい海タイプか寒い海タイプかを選べる他、大型になる確率とかが設定可能</td>
 </tr>
 <tr>
  <td>ruined_portal</td>
  <td>荒廃したポータル。<br>ジグソー以外のものの中では比較的自由度が高く、配置パターン(接地してるか、埋没してるか等)の他にどれくらい古びた雰囲気を出すか(どのくらい苔石レンガとかに置換するか)とか、蔦やジャングルの葉で生い茂ってるかとか、ブラックストーン等に置き換えるかとか、寒冷バイオーム版にするかとかが設定できます</td>
 </tr>
 <tr>
  <td>shipwreck</td>
  <td>難破船。<br>座礁してるかどうかが設定できます。木材や向きはランダムかも</td>
 </tr>
 <tr>
  <td>stronghold</td>
  <td>要塞。エンドに行けるやつです</td>
 </tr>
 <tr>
  <td>swamp_hut</td>
  <td>魔女の小屋</td>
 </tr>
 <tr>
  <td>woodland_mansion</td>
  <td>森の洋館</td>
 </tr>
</table>

# カスタムストラクチャーで必要なもの
少なくとも以下の4つのファイルが必要です。
(私のようにヨゴシを入れたり、featureを突っ込んだりしたりすると更に増えます。)
* パーツ(ストラクチャーテンプレート、`data/structure`)
* 構成設定(`data/worldgen/structure`)
* テンプレートプール(`data/worldgen/template_pool`）
* 配置設定(`data/worldgen/structure_set`)

それでは作っていきましょう。

# パーツを作る
これは特に難しいことはなく、セーフモード（と人によってはコーナーモード）のストラクチャーブロックを使って保存します。
保存したパーツはワールドデータの`generated/structures`に保存されています。

# 構成設定を設定する(worldgen/structure)
ストラクチャーの「中身」にあたるものです。
設定項目は次のようになっています。([]で囲ったものは省略可)

#### 基本項目
どのストラクチャーにも共通する項目です。
* type
* biomes
* step
* spawn_overrides
* [terrain_adaption]

ここから先は`type`の値次第で出てくる項目です。
#### type:minecraft:jigsawの場合
* size
* start_height
* start_pool
* max_distance_from_center
* use_expansion_hack
* [dimension_padding]
* [liquid_settings]
* [pool_aliases]

#### type:minecraft:ruined_portalの場合
* setups

#### type:minecraft:mineshaftの場合
* mineshaft_type

#### type:minecraft:nether_fossilの場合
* height

#### type:minecraft:ocean_ruinの場合
* biome_temp
* large_probability
* cluster_probability

#### type:minecraft:shipwreckの場合
* is_beached

### 各項目の説明
#### type
**データ型:string(文字列)**
ストラクチャーのタイプです。基本的に`"minecraft:jigsaw"`一択です。
なので、追加項目は`minecraft:jigsaw`のみ説明します。

#### biomes
**データ型:string/list(配列)**
ストラクチャーを生成させたいバイオームを指定します。
指定形式はstring(文字列)とlist(配列)の2通りがあり、前者はバイオームIDかタグ、後者はそれらを纏めた配列を書きます。
注意点として、**ここで指定したバイオームでしか生成がスタートしません。**
例えば、地下バイオームを設定して、heightmap適用なんてした場合、そのストラクチャーは絶対に生成されません。

#### step
**データ型:string**
どの生成段階で生成するかです。
生成段階についてはカスタムバイオームと同様で、[こちら](https://note.com/noir_kokumin/n/nb0b9f6152ed1#2d1f9852-be5c-4626-9cb5-627eb1d8bb41)で説明しています。

#### spawn_overrides
**データ型:compound(オブジェクト)**
ストラクチャー内にスポーンするmobを設定します。
各mobカテゴリごとに以下の設定をします。
* bounding_box : スポーンする範囲。`"piece"`(パーツ内のみ)か`"full"`(ストラクチャー全体)の2択
* spawns : スポーンするmob。リスト型で、指定の仕方はバイオームと一緒です。こちらもカスタムバイオームで説明してます。

<details>
<summary>記述例(ウィッチの小屋より)</summary>
<pre>
<code>
    {
    　"creature": {
      "bounding_box": "piece",
      "spawns": [
        {
          "type": "minecraft:cat",
          "maxCount": 1,
          "minCount": 1,
          "weight": 1
        }
      ]
    },
    "monster": {
      "bounding_box": "piece",
      "spawns": [
        {
          "type": "minecraft:witch",
          "maxCount": 1,
          "minCount": 1,
          "weight": 1
        }
      ]
    }
  }
</code>
</pre>
</details>


また、バイオームと同じでいい場合は`{}`、何もスポーンさせたくない場合、mobカテゴリのspawns内に空のリストを記入します。

<details>
<summary>何もスポーンさせない例(古代都市より)</summary>
<pre>
<code>
"spawn_overrides": {
    "ambient": {
      "bounding_box": "full",
      "spawns": []
    },
    "axolotls": {
      "bounding_box": "full",
      "spawns": []
    },
    "creature": {
      "bounding_box": "full",
      "spawns": []
    },
    "misc": {
      "bounding_box": "full",
      "spawns": []
    },
    "monster": {
      "bounding_box": "full",
      "spawns": []
    },
    "underground_water_creature": {
      "bounding_box": "full",
      "spawns": []
    },
    "water_ambient": {
      "bounding_box": "full",
      "spawns": []
    },
    "water_creature": {
      "bounding_box": "full",
      "spawns": []
    }
  }
</code>
</pre>
</details>


#### terrain_adaption
**データ型:string**
ストラクチャーの周囲の地形をどうするかです。
`"none"`、`"beard_thin"`、`"beard_box"`、`"bury"`、`"encapsulate"`の5通りから選びます。
各値の効果は下表のようになっています。
<table>
 <thead>
  <tr>
   <th>値</th><th>説明</th>
  </tr>
 </thead>
 <tr>
  <td>none</td><td>なにもしない</td>
 </tr>
 <tr>
  <td>beard_thin</td><td>周囲のブロックをくり抜き、ストラクチャーが水上や空中に生成された場合、地面を生成する。</td>
 </tr>
 <tr>
  <td>beard_box</td><td><code>beard_thin</code>のでかいバージョン</td>
 </tr>
 <tr>
  <td>bury</td><td>ストラクチャーの周りをブロックで覆います。</td>
 </tr>
 <tr>
  <td>encapsulate$\hspace{1em}$</td><td><code>bury</code>と似ていますが、こちらはストラクチャーの周りに地形を追加して、より覆いやすくします(完全に覆われないこともある)</td>
 </tr>
</table>

省略した場合、デフォルトの`"none"`として扱われます。

次から、`type:minecraft:jigsaw`にしたときの追加項目の説明になります。
#### size
**データ型:int(整数)**
何段階まで生成されるかを表します。1~20の整数を指定します。

#### start_height
**データ型:compound**
生成させたい高度です。**Height Provider**で指定します。
Height Providerについては[こちら](https://qiita.com/noir_kokumin/items/e9cadb13b388dd7cc044#minecraftheight_range)
をごらんください。

#### start_pool
**データ型:string**
どのパーツから始めるか、`worldgen/template_pool`から指定します。

#### max_distance_from_center
**データ型:int**
生成開始してから最大何ブロックまで生成するかを指定します。このときの距離は下図で示す、チェビシェフ距離で計算されます。`terrain_adaptation`を`none`にしていた場合、1~128まで、何かしら指定した場合は1~116まで指定できます。

![3a4f695a458cb0ac0aceaa2eb13ac2dd-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3591568/c17fe689-fd3a-2151-2b37-00d2ca471733.png)

#### use_expansion_hack
**データ型:boolean(true/false)**
パーツの中に別のパーツをネストした場合に、ネスト先のパーツに合わせてパーツの高さが拡張されます(但し、開始パーツは除く)。
通常は、きちんと元の高さに収まるようにネストする必要があるのですが、これを`true`にすることにより、気にしなくてよくなります。
ただし、拡張されるのは**一番下の方から**になります。上の方にネストしても意味がありません。
デフォルトでは村でのみ使用されています。

#### dimension_padding
ところで、ストラクチャーの生成途中で、ディメンションの上限や下限に達したらどうなるでしょうか？
答えは、**「それより上や下に行かなくなります」**。見た目としては、上下端でばっさり切れた不自然なものになります。
これを防ぐのがこの項目で、指定した分、ディメンションの端に近づかなくなります。イメージとしてはhtmlのpaddingに近い。

#### liquid_settings
**データ型:string**
カスタムストラクチャーでは生成**後**、生成される場所が水中だったり、水没可能ブロック(`waterlogged`のblockstateを持つブロック)が水源に隣接していたりすると、勝手に水没(`waterlogged=true`)してしまいます。
この項目はこれを阻止することができる項目で、以下のどちらかを指定します。
* apply_waterlogging : 水没する
* ignore_waterlogging : 水没しない

水没させたくなかったら`"ignore_waterlogging"`にしましょう。
省略した場合、デフォルトの`"apply_waterlogging"`として扱われます。

#### pool_aliases
**データ型:list**
これはなかなか難しい項目です。
指定したテンプレートプールを別のテンプレートプールに差し替えます。
これにより、生成される場所によって使うパーツが違うストラクチャーが出来たり、わざわざパーツを作らなくてもエンティティだけ変えたり、等の芸当が可能になります。
これについての説明も[note](https://note.com/noir_kokumin/n/nfc7f6c350a78)で説明しています。

<details><summary>その他の追加項目についての説明</summary>
<dim class="ruined_portal">
<h3>type:minecraft:ruined_portalの場合</h3>
<h4>setups</h4>
<b>list</b>
<p>どういうポータルを生成するかを決めます。</p>
<p>以下の項目を含んだオブジェクトの配列になっています。</p>
<ul>
<li>weight</li>
<li>placement</li>
<li>air_pocket_probability</li>
<li>mossiness</li>
<li>overgrown</li>
<li>vines</li>
<li>can_be_cold</li>
<li>replace_with_blackstone</li>
</ul>
<h5>weight</h5>
<p>選出される確率を表す<b>小数</b>で、この数字が大きいほど選ばれやすくなります。最大1.0</p>
<h5>placement</h5>
<p>string。どのように配置されるかを、以下のどれかから指定します。</p>
<ul>
<li>on_land_surface</li> 
ワールドの表面(地面)の上に生成します。heightmapのWORLD_SURFACEあたりと同じです。
<li>partly_buried</li>
砂漠のようにちょっと地面に埋まった状態で生成されます。
<li>on_ocean_floor</li>
海底など、水などの底に生成されます。heightmapのOCEAN_FLOORあたりと同じです。
<li>in_mountain</li>
y=70以上の地下<sup><a href="#注釈">[1]</a></sup>に生成されます。
<li>underground</li>
y=15以上の地下<sup><a href="#注釈">[1]</a></sup>に生成されます。
<li>in_nether</li>
ネザーに生成されます。
</ul>
<h5>air_pocket_probability</h5>
<p>float(小数)。ポータルのパーツは空気を含めて保存されていますが、その空気を何割残すかです。最大1.0</p>

<h5>mossiness</h5>
<p>float。石レンガを苔石レンガにしたりしてなんか…こう…古びた雰囲気にします。最大1.0。
実際には内部的に"block_age"というProcessorが働いています。
これについては<a href="https://note.com/noir_kokumin/n/n99b336fe95fd#94d55235-50d6-4862-b3c0-c26c56ad5a05">こちら</a>(またしてもnoteです)</p>
<h5>overgrown</h5>
<p>ブーリアン。ネザーラックの部分をジャングルの葉で覆います。</p>
<h5>vines</h5>
<p>ブーリアン。ツタを生やします。</p>
<h5>can_be_cold</h5>
<p>ブーリアン。寒冷版として扱うか。先程のProcessorの適用の仕方が変わっていきます。</p>
<h5>replace_with_blackstone</h5>
<p>ブーリアン。石レンガ系のブロックをブラックストーン等にするかどうかです。</p>
<p>内部的に"blackstone_replace"というProcessorが働いています。それも先程のnoteの中で説明しています。</p>
</dim>
<dim class="mineshaft">
<h3>type:minecraft:mineshaftの場合</h3>
<h4>mineshaft_type</h4>
<p>廃坑のタイプです。普通の"normal"とメサ廃坑の"mesa"の2択です。</p>
</dim>
<dim class="nether_fossil">
<h3>type:minecraft:nether_fossilの場合</h3>
<h4>height</h4>
<p>生成される高さです。ジグソーの<code>start_height</code>と同様、Height Providerで指定します。</p>
</dim>
<dim class="ocean_ruin">
<h3>type:minecraft:ocean_ruinの場合</h3>
<h4>biome_temp</h4>
<p>遺跡のタイプです。主に石レンガや砂利で出来た寒冷タイプの<code>cold</code>と主に砂岩と砂で出来た温暖タイプの<code>warm</code>の2択です。</p>
<h4>large_probability</h4>
<p>float。大型のパーツが使用される確率です。最大1.0。</p>
<h4>cluster_probability</h4>
<p>float。大型のパーツの周りに小さなパーツが群生する確率です。最大1.0。</p>
</dim>
<dim class="shipwreck">
<h3>type:minecraft:shipwreck</h3>
<h4>is_beached</h4>
<p>ブーリアン。座礁しているかどうか。</p>
</dim>
</details>


# テンプレートプールを作る
どのパーツを使用するかを決めるものです。
テンプレートプールの作り方は[こちら](https://note.com/noir_kokumin/n/n99b336fe95fd#f742a223-71dc-4f99-b433-38fcd26dc6d3)をご覧ください。

# 配置設定(worldgen/structure_set)
ストラクチャーをどうやってワールド内に分布されるかを決めるものです。
設定項目は以下になります。
* structures
* placement


#### structures
生成させたいストラクチャー。以下の項目を含んだオブジェクトのリストです。

* structure
生成させたいストラクチャーの名前です。先程設定した`worldgen/structure`のファイルを指定します。
* weight
int。偏り度で、複数のオブジェクトを指定した場合、これが大きいものほど選出されやすくなります。

#### placement
どういう風にストラクチャーを分布させるか。以下の項目を含んだオブジェクトです。
* type
* salt
* [frequency]
* [frequency_reduction_method]
* [exclusion_zone]
* [locate_offset]

##### type
分布のタイプです。ワールド中にランダムに分布する`minecraft:random_spread`と要塞のように座標(0, 0)を中心とした同心円状に拡がる`minecraft:concentric_rings`の2択で、それぞれ以下の項目が追加されます。

###### minecraft:random_spreadの場合
**spread_type**
ストラクチャー同士の距離の確率分布で、`linear`(線形分布)か`triangular`(三角分布)の2択です。
**separation**
ストラクチャー同士の**最小**の距離です。
**spacing**
ストラクチャー同士の**平均**的な距離です。separationより大きい必要があります。
また、ストラクチャー同士の距離の最大は`2*spacing - separation`から算出されます。

##### minecraft:concentric_ringsの場合
**distance**
同心円同士の距離です。
やや見づらいですが、下図の赤い矢印の部分の距離です。
96ブロックで1、つまり6チャンク単位になっています。
![stronghold_placement.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3591568/9a9e3860-c568-e9e8-6a2a-a78cca55d236.png)
**spread**
一番最初にいくつ生成するかを表します。例えば、要塞は3と設定されており、実際ワールドの中心に一番近いものは3つ存在します。
一番最初以外は各円ごと$ spread * \frac{N^2+3\times N+2}{6} $ 個生成されます(Nは何番目の同心円か）。
**count**
全部でいくつ生成されるかを表します。例えば、要塞は128と設定されており、実際に合計128個存在します。
**preferred_biomes**
先程設定した`biomes`のうち特に生成されやすいバイオームを指定します。指定の仕方はbiomesと同じです。


##### salt
0以上の整数。ソルト。後述する`frequency_reduction_method`で使用します。
(ソルトそのものの意味は私自身あまり理解してません)

##### frequency
実際に生成される確率
といえばそうですが、デフォルトで最大1.0のfloatで、どちらかといえば1.0より小さくすることで**生成を間引く**のに使います。

##### frequency_reduction_method
乱数の生成の仕方を`default`、 `legacy_type_1`、 `legacy_type_2`、 `legacy_type_3`から選びます。これらはシード値や座標、前述のソルトに基づいて算出されます。それぞれどれに基づいているかは次の表をご覧ください。
<table>
 <thead>
  <tr>
   <th>値</th><th>シード値</th><th>座標</th><th>salt</th>
  </tr>
 </thead>
 <tr>
  <td>default</td><td>○</td><td>○</td><td>○</td>
 </tr>
 <tr>
  <td>legacy_type_1</td><td>○</td><td>○</td><td>×</td>
 </tr>
 <tr>
  <td>legacy_type_2</td><td>○</td><td>○</td><td>○<br>(但し10387320で固定)</td>
 </tr>
 <tr>
  <td>legacy_type_3</td><td>○</td><td>○</td><td>×</td>
 </tr>
</table>

また、legacy_type_1は位置ずれ程度のランダム性になっています。

##### exclusion_zone
指定した他のストラクチャーの近くになるべく生成されないようにします。
以下の項目を含んだオブジェクトです。
* other_set
距離をおきたいストラクチャー。worldgen/structure_setから指定します。string。
* chunk_count
どれだけ離したいか。1~16の整数。
##### locate_offset
ジグソーを用いたカスタムストラクチャーは基本的にチャンク座標(0,0)(北西の角)に生成されます。
でも…ちょっとずらしたりしたい時ってありますよね？feature呼び出したらチャンクの境目で切れるし…。
そこで使うのがこれです。
これを使うことで、チャンク内で生成される位置をずらすことが出来ます。

**……と昨日までの私は思っていました**(2025年6月13日現在)。
これは`/locate`コマンドで出力される座標がずれるだけです。
位置ずらしは前哨基地の`base_plate`のようにジグソーだけのパーツを用意し、その中に生成しましょう。そしてずらした分をここで補正しましょう。
指定の仕方は長さ3のリストでそれぞれX座標、Y座標、Z座標に対応しています。

# おわりに
今回はカスタムストラクチャーの基本について説明させていただきました。しかし、このテーマなら既に解説してる人がいるはず…。
それらに負けないようになるべく知ってる限り**すべて**を説明しました。
あまり手をつけてる人を見かけない気がしますが…これが何かの参考になれば幸いです。

# 引用文献
1. 7-5. 階層型クラスター分析2 | 統計学の時間 | 統計WEB
https://bellcurve.jp/statistics/course/27193.html
2. Minecraft Wiki, "Stronghold"
https://minecraft.wiki/w/Stronghold
# 注釈
<ol>
<li id="note1">ここで言う、「地下」とは「その地点で一番高い所にあるブロックの高度」から「生成させるパーツの高さ」を引いたものです。</li>
</ol>