メモのつづきとBlock Statesを少し今回はやります。

 

Minecraft 1.8以降では、ブロックとメタデータ値の直接操作が抽象化されて、ブロックステートと呼ばれるものになりました。 システムの前提は、説明がなく意味のないメタデータ番号の使用と操作を削除することです。このメタデータの代わりにブロック自体のsemantics(意味論)から

保存の詳細を抽象化するシステムを使用することの提案とIProperty <?>の推奨。

各ブロックには、これらのオブジェクトのセットが0個以上あり、当然のことながら、ブロックが持つプロパティを記述します。 この例には、色(IProperty <EnumDyeColor>)、向き(IProperty <EnumFacing>)、整数値、ブール値などがあります。各プロパティは、IPropertyによってパラメーター化されたタイプの値を持つことができます。たとえば、それぞれのサンプルプロパティに対して、値EnumDyeColor.WHITE、EnumFacing.EAST、1、またはfalseを指定できます。

次に、これに続いて、すべての一意のトリプル(ブロック、プロパティのセット、それらのプロパティの値のセット)が、ブロックとメタデータの適切な抽象化された置換であることがわかります。 これで、「minecraft:stone_button meta 9」の代わりに、「minecraft:stone_button [faceing = east、powered = true]」ができました。( このドキュメントを書いている方がmetaの数値よりもトリプル(プロパティと値)方がより意味のあるものと提案されています。)

このトリプルをIBlockStateという。

実際の方法の部分に移りましょう。Blockクラスで、Blockが持つすべてのプロパティに対して静的なfinal IProperty <>オブジェクトを作成します。

Vanillaは、いくつかの便利な実装を提供します。

PropertyInteger:IProperty <Integer>を実装します。

PropertyInteger.create(““ 、、);を呼び出すことによって作成されます。

PropertyBool:IProperty <Boolean>を実装します。 

PropertyBool.create(““);を呼び出すことによって作成されます。

PropertyEnum <E extends Enum <E >>:IProperty <E>を実装し、Enumクラスの値をとることができるプロパティを定義します。 

PropertyEnum.create(“ name”、);を呼び出すことによって作成されます。

Enum値のサブセットのみを使用することもできます(たとえば、16個のEnumDyeColorのうち4個のみを使用できます。PropertyEnum.createの他のオーバーロードを確認してください)

PropertyDirection:これはPropertyEnum <EnumFacing>の便利な実装です。
いくつかの便利な述語も提供されています。

たとえば、基本的な方向を表すプロパティを取得するには、PropertyDirection.create( "<name>"、EnumFacing.Plane.HORIZONTAL)を呼び出します。

または、X方向を取得するには、PropertyDirection.create( "<name>"、EnumFacing.Axis.X)

独自のIProperty <>実装を自由に作成できますが、その方法についてはこの記事では説明していません。さらに、必要に応じて、異なるブロック間で同じIPropertyオブジェクトを共有できることに注意してください。 バニラは一般的にブロックごとに別々のものを持っていますが、それは単に個人的な好みです。

modにAPIがある場合、または他のmodから操作することを意図している場合は、代わりにIProperty(および値として使用されるクラス)をAPIに配置することを強くお勧めします。 そうすれば、人々は以前のように任意の数に悩まされることなく、プロパティと値を使用して世界にブロックを設定できます。
IProperty <>オブジェクトを作成したら、BlockクラスでcreateBlockStateをオーバーライドします。 そのメソッドでは、return new BlockState()と書くだけです。

BlockStateコンストラクターを最初にBlock、thisに渡し、次に宣言するすべてのIPropertyを渡します。1.9以降では、BlockStateクラスの名前がBlockStateContainerに変更され、このクラスが実際に行うこととより一致していることに注意してください。

作成したばかりのオブジェクトはかなり魔法のようなものです-それは上記のすべてのトリプルの生成を管理します。つまり、各プロパティのすべての値のすべての可能な組み合わせを生成します(数学指向の人の場合、各プロパティの可能な値のセットを取得し、それらのセットのデカルト積を計算します)。したがって、可能なすべての一意(ブロック、プロパティ、値)、つまり指定されたプロパティで可能なすべてのIBlockStateを生成します。

これらのIBlockStateのいずれかをブロックの「デフォルト」状態として機能するように設定しない場合は、いずれかが選択されます。

おそらくこれは望ましくないので(ほとんどの場合、奇妙なことが起こります)、Blockのコンストラクターの最後にsetDefaultState()を呼び出し、デフォルトにしたいIBlockStateを渡します。 this.blockState.getBaseState()を使用して選択したものを取得し、withPropertyを使用してすべてのプロパティに値を設定します

IBlockStateは不変で事前生成されているため、IBlockState.withProperty(<PROPERTY>、<NEW_VALUE>)を呼び出すと、新しいIBlockStateを作成する代わりに、BlockState / BlockStateContainerに移動し、必要な値のセットを使用してIBlockStateを要求します。

このことから、基本的なIBlockStateは起動時に固定セットに生成されるため、参照比較(==)を使用して、それらが等しいかどうかを確認することができ、推奨されます。

IBlockStateは、私たちが今知っているように、強力なオブジェクトです。 getValue(<PROPERTY>)を呼び出して、テストするIProperty <>を渡すことにより、プロパティの値を取得できます。 異なる値のセットでIBlockStateを取得する場合は、上記のようにwithProperty(<PROPERTY>、<NEW_VALUE>)を呼び出すだけです。 これにより、要求した値を持つ、事前に生成された別のIBlockStateが返されます。

setBlockState()とgetBlockState()を使用して、IBlockStateを取得してワールドに配置できます。

悲しいことに、抽象化はその核心にあります。 私たちは、すべてのIBlockStateを0から15までの数値に変換し直す責任があります。この数値は、world中に保存され、その逆も同様です。

IPropertyを宣言する場合は、getMetaFromStateとgetStateFromMetaをオーバーライドする必要があります。

ここでは、プロパティの値を読み取り、0から15の間、またはその逆の適切な整数を返します。 読者は、バニラブロックの例を自分でチェックする必要があります。
getMetaFromStateメソッドとgetStateFromMetaメソッドは1対1である必要があります。 つまり、同じプロパティと値のセットを同じメタ値にマップして戻す必要があります。 残念ながら、これを行わなくてもクラッシュは発生しません。 すべてが非常に奇妙に動作するだけです。
一部の鋭い頭脳は、フェンスがメタへの接続を保存しないことを知っているかもしれませんが、それでもF3メニューにプロパティと値があります! この冒涜とは何ですか?

ブロックは、メタデータに保存されていないプロパティを宣言できます。 これらは通常、レンダリングの目的で使用されますが、他の便利なアプリケーションがある可能性があります。

それでも、createBlockStateでそれらを宣言し、setDefaultStateでそれらの値を設定します。 ただし、getMetaFromStateおよびgetStateFromMetaでは、これらのプロパティにはまったく触れません。代わりに、BlockクラスのgetActualStateをオーバーライドします。 ここでは、ワールドのメタデータに対応するIBlockStateを受け取り、withPropertyを使用して入力されたフェンス接続、レッドストーン接続などの情報が欠落している別のIBlockStateを返します。 これを使用して、値のタイルエンティティデータを読み取ることもできます(もちろん、適切な安全性チェックを使用してください!)。

getActualStateでタイルエンティティデータを読み取るときは、追加の安全性チェックを実行する必要があります。 デフォルトでは、getTileEntityは、タイルエンティティがまだ存在しない場合、その作成を試みます。

ただし、getActualStateとgetExtendedStateは異なるスレッドから呼び出される可能性があり、呼び出されるため、欠落しているタイルエンティティを作成しようとすると、ワールドのタイルエンティティリストがConcurrentModificationExceptionをスローする可能性があります。

したがって、IBlockAccess引数がChunkCache(代替スレッドに渡されるオブジェクト)であるかどうかを確認する必要があります。そうである場合は、getTileEntityの非書き込みバリアントをキャストして使用します。 この安全性チェックの例は、BlockFlowerPot.getActualState()にあります。world.getBlockState()をクエリすると、メタデータのみを表すIBlockStateが得られます。 したがって、返されるIBlockStateには、getActualStateからのデータが入力されません。それがコードにとって重要な場合は、必ずgetActualStateを呼び出してください。
拡張ブロック状態は、ブロックのレンダリング中に任意のデータをIBakedModelsに渡す方法です。 これらは主にレンダリングのコンテキストで使用されるため、「モデル」セクションに記載されています。

 

blockstateに関しての記事の訳は以上ですが訳してもさっぱりですね。

英語圏の言い回しもよくわからないところもあって(;´Д`)

 

かまどのブロックはどの方向から設置してもプレイヤーがいる方向に正面がくるじゃないですか

あれをやります。これをやれば少し上の記事の内容がわかると思います(-_-;)

Blockクラスを継承したサブクラスを作成します


赤枠のところがブロックを設置するのに必要なメンバです。

次にJsonファイル

itemは変わらず。

blockは正面向けたいテクスチャだけわかりやすい用に変えただけ。

北面が正面に来るようにメソッドで書いているので北。別に南でも東でも設定できるけどその場合は上のクラスのメソッドも変えないといけない。

blockstateで今まではnormalとかしてたのを↑のようにします。

modelの指定をしているので先ほどのblockのjsonファイルを指定します。

yは横回転ではないかと思います。北から東で90度北から南で180度北から西で270度

 

ブロックの登録をして実行します。(ブロックの登録クラスで登録しますが何度もやっているので

省略pngファイルは以前やったの流用なのでこれも省略)

こんなブロック要るのかと言われれば要らないんですが(-_-;)

向きの固定が気になったのでやってみました(`・ω・´)

IPropertyとかのクラス見たけどさっぱりわからんかったし( ノД`)

PropertyDirectionから手繰っていって最終的にIPropertyに辿り着く・・・。

さっぱりわからないのに何でできたのかって?かまどのクラス見てやり方を学んだのです。

ホッパーやデロッパーのクラスも見ましたよ(`・ω・´)

似たような仕様であればバニラから学ぶことは多いです。学ぶというか真似るというか(;´∀`)