Block predicateとBlock state provider とは？

# はじめに
Block predicateもBlock,state providerも元々はカスタムfeatureで使われていたものでり、[featureの作り方](https://qiita.com/noir_kokumin/items/e9cadb13b388dd7cc044)の中で説明していました。
しかし、1.21で実装されたカスタムエンチャントでも使用されるようになり、本要素の需要が高まったのではないでしょうか？
その為、改めてあちらから分離して書くことにします。

# Block predicateとは
ブロックを生成する為の条件です。
predicateのlocation_checkのblocksに似ていますがあちらよりも色々出来ます。
例えば、「そこにあるブロックが水なら氷ブロックを生成する」、「下が草ブロックでかつ、空気中の場合、草を生やす」、「右クリックで置き換えられるブロックを別のブロックにする」、「そのブロックが自壊しなければ生成する」等々…。
書き方は以下のようになります。

```
{
    "type": type,
    typeによって変化
}
```

## type
Block predicateのタイプです。ここの記述によって後の項目が変化します。

### minecraft:matching_blocks
指定したブロックを条件とします。
predicateのlocation_checks.block.blocksに似ています。
書き方はこんな感じ。
```
{
    "blocks": ブロックID/ブロックタグ/ブロックIDのリスト,
    "offset": [
        X,
        Y,
        Z
    ]
}
```
#### blocks
条件とするブロックです。
IDを直接書いたり、複数指定する場合はタグで指定するか、IDのリストをこんな感じで書きます。
````
[
  "minecraft:stone",
  "minecraft:dirt",
  "minecraft:grass_block"
]
````

#### offset
参照する場所をずらします。
リストですが、上からX座標分、Y座標分、Z座標分指定します。
例えば、下のように書いた場合は1つ下にあるブロックを参照します。
```
[
  0,
  -1,
  0
]
```

### minecraft:matching_block_tag
ブロックタグを条件とします。
`matching_blocks`の`blocks`が`tag`に変わった感じで、predicateのlocation_checks.block.tagに似ています。
この場合、`#`を頭につける必要はありません。
書き方はこんな感じ。
```
{
    "tag": ブロックタグ,
    "offset": [
        X,
        Y,
        Z
    ]
}
```

### minecraft:matching_fluids
流体系ブロックに触れていることを条件とします。
`matching_blocks`の`blocks`が`fluids`に変わった感じで、流体系ブロック(水とか溶岩とか)のIDか、複数ある場合はtags/fluids、もしくはIDのリストで指定します。
predicateでいえばlocation_checks.fluidに似ています。
形式はこんな感じ。
```
{
    "fluids": 流体系ブロックID/tags/ブロックIDのリスト,
    "offset": [
        X,
        Y,
        Z
    ]
}
```

### minecraft:would_survive
指定したブロックがそこに存在し続けられるかどうかを条件とします。
ブロックがそこに置け、自壊したりしないかどうか、とも言えます。
例えば、以下はオークの木の設置条件なのですが、これによって空中に木が浮遊したりすることはありません。
苗木って空中に置けないですもんね。
```
{
        "type": "minecraft:would_survive",
        "state": {
          "Name": "minecraft:oak_sapling",
          "Properties": {
            "stage": "0"
          }
    }
}
```
書き方は以下の通り。
```
{
    "state": {
        "Name": ブロックID,
        "Properties": {
            blockstates
        },
    "offset: [
        X,
        Y,
        Z
    ]
}
```
#### state
条件としたいブロックのIDとblockstatesを指定します。
NameにIDを、Propertiesにblockstatesを指定します。省略可能でその場合はデフォルトの値が使われます。

### minecraft:has_sturdy_face
その面に対して、松明とかボタンとかのブロックをくっつけられるかどうかを条件とします。
大雑把なフルブロック面検知みたいに使えます。
書き方はこんな感じ。
```
{
    "direction": "east"/"north"/"south"/"west"/"up"/"down",
    "offset": [
        X,
        Y,
        Z
    ]
}
```
#### direction
検知したい面を指定します。

### minecraft:solid
固体ブロックかどうかを条件とします。

### minecraft:replaceable
空気や水など、そこにブロックを持った状態で右クリックしたときに手持ちのブロックで置き換えられるものを条件とします。

### minecraft:inside_world_bounds
ワールドの限界高度範囲内にあるかどうかを条件とします。
offsetのみ指定可能です。

### minecraft:unobstructed
そこにエンティティがいないことを条件とします。
ワールド生成というよりもエンチャント用であり、氷渡りで使用されています。
`offset`のみ追加されます。


### minecraft:all_of/minecraft:any_of
所謂AND条件やOR条件で、`all_of`がAND、`any_of`がORにあたります。
predicatesというリストが追加され、複数のpredicateを指定できます。

### minecraft:not
所謂NOT条件であり、`predicate`で指定した条件を反転させます。

### minecraft:true
常時満たします。これといって指定するものはありません。

# Block state providerとは
実際に生成するブロックを指定します。
単純にブロック状態込みでブロックを指定するよりも細かくブロックを指定することができます。例えば、複数の中からランダムで指定したり、数値系のblockstatesであればランダムに指定したり…等です。

書き方は以下のようになります。
```
{
    "type": Block state providerのtype,
    typeに応じて変化
}
```
## type
Block state providerのtypeです。
以下にあげるものの中から選びます。
ここの値によって後の項目が変化します。

### minecraft:simple_state_provider
シンプルに1つ指定します。
この場合、追加項目は以下のようになります。
```
{
    "state": {
                "Name": ブロックID,
                "Properties": {
                    blockstates
    }
}
```

### minecraft:rotated_block_provider 
向き付きブロックが対象で、向きが回転します。
simple_state_providerと同じように書きますが、どうせ向きが変わるからか、Propertiesの指定はなくても大丈夫。

### minecraft:weighted_state_provider
複数の指定の中からランダムで選びます。
この場合の追加項目はこちら。
```
{
    "data": {
                "Name": ブロックID,
                "Properties": {
                     blockstates
            },
    "weight": 整数
}
```
dataでブロックの指定をします。weightが大きいほど選ばれやすくなります。

### minecraft:randomized_int_state_provider
数値系のblockstatesをもつものに有効で、ランダムに数値が選ばれます。
選出ルールとかは、先のInt providerを使います。
書き方は以下のようになります。

```
{
    "property: blockstatesの名前,
    "values": 整数/Int provider,
    "source": Block state provider
}
```

propertyは数値をランダムにしたいblockstatesを指定します。
どういう風に選ぶかは、その後のvaluesで指定します。

### minecraft:noise_provider
ノイズの値次第でどのブロックを使うかをランダムで決めます。
書き方は以下のようになります。

```
{
  "type": "minecraft:noise_provider", 
  "noise": {
    "firstOctave": 整数値,
    "amplitudes": Double型の数値のリスト
  },
  "seed": Long型の数値,
  "scale": float型の数値,
  "states": [
    {
      "Name": ブロックID,
      "Properties": {
         blockstates property,
         blockstates property,
         ...
      }
    },
    ...
  ]
}
```

#### noise
ノイズを**オブジェクトで**指定します。
`worldgen/noise`から指定することは**できない**ので注意してください。
`amplitudes`で指定した数値と`firstOctave`からサブノイズなるものが各要素ごとに算出されます。そのサブノイズの合計やリストの長さ等から最終的なノイズが計算されているのですが、当方、Octave含めまだあまり理解しきっておらず、[misode氏のジェネレーター](https://misode.github.io/worldgen/noise/)頼りになっているため、[wiki](https://minecraft.wiki/w/Custom_world_generation/noise)をご覧ください。

#### seed
ノイズの算出のシード値です。

#### scale
ノイズの(横方向の)倍率です。正数で指定します。

#### states
実際に生成するブロックです。

### minecraft:dual_noise_provider 
`noise_provider`と同様ノイズによってランダムで使うブロックを決めるのですが、こちらはノイズを2つ使います。
書き方は以下のようになります。

```
{
  "type": "minecraft:dual_noise_provider", 
  "noise": {
    "firstOctave": 整数値,
    "amplitudes": Double型の数値のリスト
  },
  "scale": float型の数値,
  "slow_noise": {
    "firstOctave": 整数値,
    "amplitudes": Double型のリスト
  },
  "slow_scale": float型の数値,
  "variety": 数値かオブジェクトかリスト,
  "states": [
    {
      "Name": ブロックID,
      "Properties": {
        blockstate property,
        blockstate property,
        ...
      },
    },
    ...
  ]
}
```
見ての通り、基本的には`noise_provider `と同じなのですが、`slow_noise`とその関連の項目が増えています。
このtypeは生成処理が2段階に分かれており、`slow_noise`から先に処理されます。
`variety`は`slow_noise`から選出されるblockstatesの数です。整数値1つにすることも、幅を持たせることもできます。後者の場合は`pack.mcmeta`の`supported_formats`のようにオブジェクトかリストで指定します。
オブジェクトの場合は以下のようになります。
```
{
  "min_inclusive": 整数値,
  "max_inclusive": 整数値
}
```

リストの場合は以下のようになります。
```
[
  最小値(整数),
  最大値(整数)
]
```

### minecraft:noise_threshold_provider
こちらもノイズを使うタイプで、指定した基準値(threshold)より大きいか小さいかによって生成するブロックを使い分けます。
書き方は以下のようになります。
```
{
  "type": "minecraft:noise_threshold_provider", 
  "noise": {
    "firstOctave": 整数値,
    "amplitudes": Double型の数値のリスト
  },
  "scale": float型の数値,
  "threshold": float型の数値,
  "default_state": {
     "Name": ブロックID,
     "Properties": {
       blockstate property,
       blockstate property,
       ...
     },
     "low_states": [
        {
          "Name": ,ブロックID,
          "Properties": {
            blockstate property,
            blockstate property,
            ...
          }
        },
        ...
     ],
     "high_chance": float型の数値,
     "high_states": [
        {
          "Name": ,ブロックID,
          "Properties": {
            blockstate property,
            blockstate property,
            ...
          }
        },
        ...
     ]
  }
}
```

#### threshold 
基準値を-1.0から1.0の間で指定します。
ここより低い場合は`low_states`から選出され、ここより高い場合は`high_states`もしくは`default_state`から選出されます。
`high_chance`は`high_states`から選出される確率になります。

# 参考サイト
* [Custom world generation/noise](https://minecraft.wiki/w/Custom_world_generation/noise)
* [MINECRAFT SNAPSHOT 24W18A(スナップショットの公式アナウンス)](https://www.minecraft.net/ja-jp/article/minecraft-snapshot-24w18a)