どんなfeature なのか
オーバーワールドの地下を探索していると、このような球状のものが見つかることがあります。


これが「アメジストジオード」で、このfeature type によって生成されています。
ただし!
$$\boldsymbol{\huge{\textsf{geodeはジオードを生成するfeatureではない}}}$$
って思いますよね。
というのも、設定次第ではこういうのも出来ちゃうんですよ。
アメジストジオード(疑惑)
今回は、このfeatureについて説明しようと思います。
で、どういうfeatureなのよ?
では、どういうfeatureなのかと言いますと、
指定した範囲内に一定のノイズを生成し、そこにブロックを配置するfeatureです。
このノイズはfirstOctaveが-4、amplitudes:[1.0]に固定されています。
配置されるブロックは、後述する「チェックポイント」との距離で使い分けされています。
JSONの書き方
JSONのフォーマットは以下のようになっています。
{
"type": "minecraft:geode",
"config": {
"blocks": {
"filling_provider": Block state provider,
"inner_layer_provider": Block state provider,
"alternate_inner_layer_provider": Block state provider,
"middle_layer_provider": Block state provider,
"outer_layer_provider": Block state provider,
"inner_placements": List,
"cannot_replace": ブロックタグ,
"invalid_blocks": ブロックタグ
},
"layers": {
"filling": Double,
"inner_layer": Double,
"middle_layer": Double,
"outer_layer": Double
},
"crack": {
"generate_crack_chance": Double
"base_crack_size": Double,
"crack_point_offset": int,
},
"min_gen_offset": int,
"max_gen_offset": int,
"distribution_points": int / Object,
"outer_wall_distance": int / Object,
"point_offset": int / Object,
"invalid_blocks_threshold": int,
"noise_multiplier": Double,
"use_potential_placements_chance": Double,
"use_alternate_layer0_chance": Double,
"placements_require_layer0_alternate": Boolean
}
}
この通り、設定項目がめちゃくちゃ多く、とても複雑です。
1つ1つ説明していきますね。
blocks
blocksでは、使用するブロックを設定します。
その中でも以下の設定は構成するブロックの設定になっています。
filling_providerinner_layer_provideralternate_inner_layer_providermiddle_layer_providerouter_layer_providerinner_placements
上5つは「ジオード」そのものを構成するブロックです。これらのうち、inner_layer_providerは確率でalternate_inner_layer_providerが代わりに使われます(この確率は設定可能です)。
アメジストジオードではそれぞれ空気、アメジストブロック、芽生えたアメジスト、方解石、滑らかな玄武岩にあたります。
inner_placementsはinner_layerの上に生えてくるブロックで、アメジストジオードではアメジストの芽に相当します。
cannot_replaceは「ジオード」によって置き換えられないブロックをタグかIDを列記して指定します。1個だけ指定することもできます。ブロックタグを指定する場合は頭に#をつけてください。
言い換えると、ここに指定したブロックを避けるように「ジオード」が生成されます。
アメジストジオードでは#minecraft:features_cannot_replaceになっています。
invalid_blocksはジオードの範囲内に「存在してはいけないブロック」をブロックタグかIDを列記して指定します。こちらも1個だけ指定することもできます。
こちらもタグで指定する場合は頭に#が必要です。
アメジストジオードでは#minecraft:geode_invalid_blocksになっています。
これに加えて、空気も「存在してはいけないブロック」として扱われます。
これらが後述する許容個数を超えてしまうと生成自体が失敗になります。
layers
「ジオード」は4層のブロックによって構成されています。それらのブロックを使い分ける為の「閾値」のようなものです。
filling、inner_layer、middle_layer、outer_layerそれぞれ指定します。
デフォルトだとそれぞれ、1.7、2.2、3.2、4.2です。
ただし、この値がそのまま使われるわけではなく、ここで指定した値に裂け目を加味した値(crackSizeAdjustment)の逆平方根が使われます。
crack
クラック、文字通り「裂け目」の設定です。
generate_crack_chanceは裂け目が発生する確率、base_crack_sizeは裂け目の基本サイズを表します。
ただし、base_crack_sizeは素の状態では使われません。
crack_point_offsetは裂け目専用の「チェックポイント」です。以後、勝手に「クラックポイント」と呼びます。
全て省略可能です。
min_gen_offset、max_gen_offset
「ジオード」を生成する範囲です。
min_gen_offsetは始点、max_gen_offsetは終点です。
具体的には、生成予定地から見て(~min_gen_offset ~min_gen_offset ~min_gen_offset)の座標から(~max_gen_offset ~max_gen_offset ~max_gen_offset)までのキューブ状の範囲内にノイズが生成され、ブロックが配置されます。
どちらも省略可能で、その場合はそれぞれデフォルトの-16と16として扱われます。
outer_wall_distance、distribution_points、invalid_blocks_threshold
outer_wall_distance
outer_wall_distanceは、invalid_blocksで指定したブロックか、空気がないかどうかをチェックする範囲です。
xyzそれぞれでここの値分ずらした場所でチェックします。
最大20まで指定できます。
基本はint型ですが、オブジェクトにすることもでき、その場合は値に幅を持たせることができます。
以後、このチェックを勝手に「エラーチェック」、そしてこのチェックを行う場所をこれまた勝手に「チェックポイント」と呼ばせていただきます。
そして、この「チェックポイント」が後にブロックを配置する為の基準点となります。
ここが大きいほど、filling_providerで指定したブロックの占める部分が大きくなりやすいです。
省略可能で、その場合はデフォルトの4~5のuniformとして扱われます。
distribution_points
「エラーチェック」を行う回数です。
最大20まで指定できます。
こちらも基本はint型ですが、オブジェクトにして値に幅を持たせることができます。
ここが大きいほど、チェックポイントの数が多くなり、「ジオード」が大きくなります。
省略可能で、その場合はデフォルトの3~4のuniformとして扱われます。
前述のcrackSizeAdjustmentはランダムなouter_wall_distance / distribution_pointsのmax_inclusiveから算出されます。
invalid_blocks_threshold
invalid_blocksが許容される回数です。
「エラーチェック」でこの数を超えてしまった場合、生成自体が失敗します。
こちらは20を超えても大丈夫です。
アメジストジオードが絶対に埋没しているのはここが1になっているためです。
point_offset
「チェックポイント」への補正値です。
省略可能で、その場合はデフォルトの1~2のuniformとして扱われます。
noise_multiplier
ノイズへの係数で、ノイズの値の変化率になります。
1.0まで指定できます。
1.0のままだと最初にあげた画像のような歪なものになり、ブロックが配置される幅が小さくなります。
球状に丸めたり、ブロックの幅を大きくしたければ小さくしておきましょう。
実際、アメジストジオードでは0.05に指定されています。
省略可能で、その場合はデフォルトの0.05として扱われます。
use_potential_placements_chance
inner_placementsで指定したブロックが生えてくる確率です。
省略可能で、その場合はデフォルトの0.35として扱われます。
use_alternate_layer0_chance
alternate_inner_layer_providerで指定したブロックが使われる確率です。
省略可能で、その場合はデフォルトの0.0として扱われます。
placements_require_layer0_alternate
ここをtrueにしておけば、inner_placementsをalternate_inner_layerにのみ生やすことができます。
省略可能で、その場合はデフォルトのtrueとして扱われます。
生成のしくみ
ブロック配置用の閾値を決める
先程ちらっと言いましたが、layerのうちfillingはそのまま、それ以外はそれにcrackSizeAdjustmentの値を加えた物の逆平方根をとります。
ソースだとこういう風に書かれています。
filling
innerAir = 1.0 / Math.sqrt(layerSettings.filling);
inner_layer
innermostBlockLayer = 1.0 / Math.sqrt(layerSettings.innerLayer + crackSizeAdjustment);
middle_layer
innerCrust = 1.0 / Math.sqrt(layerSettings.middleLayer + crackSizeAdjustment);
outer_layer
outerCrust = 1.0 / Math.sqrt(layerSettings.outerLayer + crackSizeAdjustment);
裂け目のサイズ決め、発生可否
裂け目のサイズは、基本サイズに、ランダムなdouble値の半分を足したものの逆平方根をとります。
ただし、distribution_pointsでとった値が3を超えた場合はcrackSizeAdjustmentを加えたものの逆平方根をとります。
ソースにはこう書かれています。
crackSize = 1.0 / Math.sqrt(crackSettings.baseCrackSize + random.nextDouble() / 2.0 + (numPoints > 3 ? crackSizeAdjustment : 0.0));
(numPoints=distribution_points)
この後に、generate_crack_chanceの確率で裂け目が発生するかどうかのフラグを立てます。
「エラーチェック」
まず、「エラー回数」を初期化します。
その後に「エラーチェック」を行います。
「エラーチェック」では、生成予定地からxyzそれぞれouter_wall_distance分ずらし、そこがinvalid_blocksであるかどうかをチェックします
outer_wall_distanceを範囲指定した場合、x、y、zそれぞれ別でランダムになります。
ここでinvalid_blocksだった場合、カウンタnumInvalidPoints(以後、「エラー回数」と呼びます)にカウントします。
これがinvalid_blocks_thresholdを超えた場合、その時点で処理が打ち切りとなり、生成が失敗します。
越えていなければ、その地点の座標とpoint_offsetからランダムに選ばれた数値の組み合わせを連結リストに保存します。(これは後で使います)
これをdistribution_pointsだけ繰り返します。
crackPoint(裂け目の「チェックポイント」)を決める
裂け目発生フラグが立っている場合に処理されます。
以下の4種類の中からランダムに決まり、連結リストに保存します。
crackOffsetはdistribution_points * 2 + 1で算出されます。
- ~crackOffset ~7 ~0, ~crackOffset ~5 ~0, ~crackOffset ~ 1 0
- ~0 ~7 ~crackOffset, ~0 ~5 ~crackOffset, ~0 ~ 1 crackOffset
- ~crackOffset ~7 ~crackOffset, ~crackOffset ~5 ~crackOffset, ~crackOffset ~ 1 crackOffset
- ~0 ~7 ~0, ~0 ~5 ~0, ~0 ~ 1 0
ブロックの配置
いよいよブロックを配置します。
ブロックの配置は、xyz軸それぞれmin_gen_offset分ずらした地点(~min_gen_offset ~min_gen_offset ~min_gen_offset)からmax_gen_offsetずらした地点(~max_gen_offset ~maz_gen^offset ~maz_gen_offset)まで、以下の処理がfor文で再帰して行われます。
ノイズの取得
その地点のノイズの値を取得します。このとき、noise_multiplierの値をかけて補正します。
「チェックポイント」への距離+αにノイズの値を足して総計する
「チェックポイント」への距離に、+αとしてpoint_offsetの値を足した後、ノイズの値を加算します。
これを全てのチェックポイントに対して行い、合計します。
この合計値をソースではdistSumShellと記述されているため、以後、そう呼びます。
クラックポイントへの距離+αにノイズの値を足して総計する
裂け目に対しても似たような処理を行います。
先ほど求めた「クラックポイント」への距離に+αとしてcrack_point_offsetの値をランダムに選び、それを足します。そこに更にノイズの値を加算します。
これを全てのクラックポイントに対して行い、合計します。
この合計値をソースではdistSumCrackと記述されているため、以後そう呼びます。
裂け目の発生
裂け目発生フラグが立っており、distSumShellがouterCrustとinnerAirよりも小さく、distSumCrackがcrackSizeより大きい場合、裂け目として空気が生成されます。
ブロックの配置
distSumShellがouterCrust以上のとき、
以下のようにlayersの値を順々に比較し、ブロックを配置します。
- innerAir以上→filling_provider
- innerostBlockLayer以上→inner_layer_provider
- innerCrust以上→middle_layer_provider
- outerCrust以上→outer_layer_provider
また、inner_layerはuse_potential_placements_chanceの確率でinner_placementsで指定したブロックが生成されます。これはたとえ空気だろうと、inner_layerの判定が出たら生えてきます。
ここで指定したブロックにfacingのblockstatesがある場合、隣接するブロックに応じて向きが変わり、waterloggedのblockstates を持っている場合、水没時、自動的にtrueになります。
また、use_alternate_layer0_chanceの確率でalternate_inner_layerで指定したブロックが使用されます。
参考資料
今回は経験だけでなく、こちらのサイトから、ソースコードを頑張って解読したものを基にしています。


