見出し画像

Integrated Dynamicsと和解せよ: Botaniaのマナ生産を自動化してみよう

日頃からIntegrated Dynamicsと和解せよと口癖のように言ってはおりますが, 具体的な和解の方法は示しておりませんでしたので, 例としてBotaniaのマナ生産花の自動化についてここに書き連ねていこうかと存じております.

この記事を書き上げられるまでに僕に知識を付けてくれた素晴らしい投稿があるので, 先に貼っておきます

https://www.reddit.com/r/feedthebeast/comments/di8ekq/automating_botania_with_integrated_dynamics/


基礎: 前提知識

幾つか自動化するための知識を持っておきましょう. 問題に当たった時解決するための知識が無ければ問題を放棄する他ありません. 予め知っておくか調べる必要があると思われるので, 取り敢えず最低限は知っておきましょう.

また, アイテム搬出等が絡む自動化ではIntegrated Tunnelsが必須なので, 関連アドオンをまとめて導入しておくと良いでしょう.

情報取得

自動化は対象の情報を取得する所から始まります. 基本的に対象はブロックとなりますので, Block Readerを使います.

かなり簡単なレシピで作成可能 倉庫に優しい
対象ブロックへ貼り付けるようにして設置する

このように情報取得系は xxx Reader という名称が付いているため, 対象により適宜使い分けが必要です. JEI辺りを覗いて何が出来るか探してみましょう.

Block ReaderのGUI

読み取れる情報の一覧はこのように表示されます. ここへ変数カード(Variable Card)を入れる事でその情報を取得し続けるカードが作成できます.

値の加工

取得した情報は当然そのままでは使えません. 値の加工が必要となります.

Variable Cardへ書き込みを行うツール

これを(Portable) Logic Programmerで行います.

かなりお役立ち

どの変数カードが何を表すかを忘れないために名付けもしておきましょう. その時にはLabellerを使います.

情報保存

値を加工した場合, 元となった変数カードも当然ネットワーク上で使用しなければならないので, これを入れておく箱が必要となってきます. それがVariable Storeです.

45個入る

処理系統

最終的には取得した情報を元に搬出や採掘, 設置をする等処理するために必要なものは色々とありますが, 基本的にはIntegrated Tunnelsを使うため
Exporter(搬出) や Importer(搬入) 等に頼ることになります.

特にブロックやアイテムエンティティ(≒ワールド上のアイテム)へ干渉出来るものはWorld XXX Importer/Exporterという名称がついています.

水色はエネルギー系
白はアイテム系
黄色は液体系
緑はその他(block/player)を扱う

Endoflameを自動化する

Botaniaでのマナ生産において, 初期から終盤まで頼ることになる花, Endoflame.

バニラ環境でもかなり簡単に自動化出来るため, わざわざIntegrated Dynamicsでやる必要は無いですが, まあやっていきましょう.

全体像

重要な物は

  • Block Reader

  • Item Interface

  • World Item Exporter

  • Display Panel

これ位でしょうか. Display Panelも重要ですが最終的には必要なくなります.

全体の流れ

Endoflameはドロップしたアイテムとして燃料を与えると燃焼状態に入り, マナを生産し続けます.
燃焼時にはアイテムを受け付けないため, アイテムを無駄にしないよう適切なタイミングで燃料を与える機構を構築すれば自動化出来る訳です.

そのため, 全体の流れとしては
燃焼しているか確認し -> 燃焼していなければ燃料をドロップする
という簡単な工程で自動化可能です. やってみましょう.

1. 燃焼しているかを読み取る

先ず, Endoflameへ面しているBlock Readerの項目から Tile Entiry NBT を探して適当なVariable Cardへ書き込みます.

左スロットへ空のカードを入れると右へ情報を反映するように書き込まれる

これをEndoFlame.NBTと名付けておきましょう.

次に, 燃焼しているかの情報を引き出すためにその情報に対応するKeyが必要となります. これを調べるために, この変数カードを繋いだDisplay Panelへ入れます.

字が小さすぎて読めない!!!!!!!

当然読めないのでCopyを押してクリップボードへコピーしておきます.

すると, 次のような情報が出てきます.

{ForgeCaps:{},binding:{X:-1,Y:-59,Z:140},burnTime:0,id:"botania:endoflame",mana:0,ticksExisted:19866,x:-2,y:-59,z:140}

適切に改行すればわかりやすくなります. 内容が多すぎると理解しづらくなりますので, 手元のエディタやメモ帳へ貼り付けて改行するのが良いでしょう.

{
 ForgeCaps:{},
 binding:{X:-1,Y:-59,Z:140},
 burnTime:0,
 id:"botania:endoflame",
 mana:0,
 ticksExisted:19866,
 x:-2,
 y:-59,
 z:140
}

これらKeyのうち, 重要なのはburnTimeです. 名前で分かりづらい時もありますので, そういう時は実際に燃料を与えてDisplay Panelを見てみるのも良いでしょう.

元の状態
燃料を与えた後. burnTimeが段々と減少していく
そのため燃焼時間に関係するのはburnTimeと分かる

こうして判明したKeyは後で使うためLogic Programmerを開いてString(文字列情報)として保存しておきます.

左上が検索欄, 中奥の入力ボックスはデータ値
右下の"E"はLabellerを所持していると出てくる
"E"を押すと更に入力ボックスが出現し値の書き込みと名付けを同時に出来る

こうして書き込んだ文字列カードはString.burnTimeとしておきます.

そうして情報が揃ったので, 燃焼の情報をNBTから抜き取ります.
NBT{}.get_integerを使用して, NBTから残りの燃焼時間を取得できます.

どこに何を入れるかはカーソルを合わせれば出てくる

このNBT{}.get_Integerへ先程作成したEndoFlame.NBTとString.burnTimeを入れれば燃焼時間を整数として取得出来ます. これは適当にEndoFlame.burnTimeと名付けておきましょう.

2. 燃焼しているかどうかを出力させる

最終的な目的は非燃焼時に燃料を投下することですので, burnTimeから燃焼状態を表す真偽値(Boolean)の変数カードを作成します.

burnTimeが1未満であれば非燃焼時となりますので, 比較対象となる1の値をIntegerで作成します.

名前は規則性があれば適当で良い

そして, これら整数値を比較して真偽値にするにはRelational Less Than(<)を使います.

この辺からこんがらがってくるが名前をつけておけば大丈夫(n敗)

こうして出来た真偽値カードは燃焼時間<1で真(True)となるので, これでようやく非燃焼時を定義するカードが出来たわけです. Endoflame.isNotBurningと名付けておきましょう.

3. 非燃焼時に燃料投下

先に, ネットワーク上に燃料となるアイテムを認識させるためにItem Interfaceを燃料が入っているストレージに繋いでおきます.

チェストかなんかでもいい
画像のはStorageDrawersの物

最後に, 今回はネットワーク上は木炭を繋いだストレージしか用意していないので, World Item ExporterのPlace All Item Entitiesを使います.

ここをちゃんと設定しよう

しかし, このまま繋ぐと大惨事になりますので, 変数カードを入れる前にしっかりと各項目の設定をしておきます.

Channel, これはItem Interfaceのものと同一であれば問題ないです.
Round-Robin, ストレージのアイテムをランダムに抽出するかどうか.
Dispense, これはアイテムをディスペンサーのように発射するかどうか.
Offset N, これはアイテムが出現する座標.
Lifespan, これは(恐らく)動作周期を表します.
PickUp Delay, これは落としたアイテムがどの程度の時間が経てばプレイヤーが拾えるようになるかの時間を表します. 適当に伸ばしておけばミスで拾うこともなくなります.
Velocity, これはアイテムの発射速度です. 0でいいです.
Yaw/Pitch, これらもアイテムを発射する際に関わりますが, 設定不要です.
Item Transfer Rate, これが最重要で, デフォルト値64では一度に1スタック搬出されてしまうので1に設定しておきます.

また, 動作周期も早すぎるので右上の設定ボタンから設定を行います.

右上のそろばんみたいなアイコンのやつ

設定項目のTicks/Operationをいい感じの動作周期になるまで引き伸ばします.
目安としてはデフォルト値の6倍程度(60)でしょうか.
負荷が気になる方は他のReaderやInterfaceも下げておくと良いです. (通常は誤差程度の負荷ですが)

最後に, ここへvariable card(Endoflame.isNotBurning)を入れれば終了です.
他の花も途中に色々挟む必要がありますが, 取得から搬出という基本的には似たような機構で構成可能です.

おまけ: Gourmaryllisの自動化

Gourmaryllis(ガーマリリス)とは

https://ftbwiki.org/Gourmaryllis

大まかには食べ物を燃料とするEndoflameですが, 同じ食品を与え続けるとマナ生産量が減少していきます. これを踏まえて効率的な自動化してみましょう.
前項で力尽きたので結構雑ですが, 前項をなんとなくでも理解していれば問題ないかと思います. (ド屑)

1. 取得

複数種とはいえ食料確保は面倒ですから結局は一定の種類の食べ物をローテーションすると思いますので, 必要なのは前与えた食べ物の情報と食べ物を消費しきるまでの時間となります.
GourmaryllisはEndoflameと違い消費中に与えた食べ物も消費してしまい(それではマナを生産しない)完全に無駄になります. より慎重に情報を読み取りましょう.

試しに複数種類与えた後

必要になるのは lastFoodscooldown で, 食べ物を消費し終わると値が -1 になるので, 今度は等価比較(=)を使用することになります.

2. 与えるアイテムを決める

ここで厄介なのはlastFoodsで, 一見get_listで良いかと思えますがこいつはnest(入れ子構造)のリストなので, これをバラす必要があります.(そもそもget_listは存在しないのですが) これにはNBT{}.get_list_tagを用いれば問題ありません.

これで出力されたlistは次のようなデータとなっています.

NBTが格納されている

このリストは与えられた順に先頭からデータが格納されていくので, 先頭からn番目のアイテムを与えていけば自然と複数種をローテーションして与えられるわけです. 
ここで, 普段からコーディングをしない人にとっては少し罠なのですが, n番目の要素を指定するにはindexとして整数値n-1を与える必要があります.
listのindexは0から始まるからですね.

今回は2種のアイテムをローテーションする予定なので, (2-1=)1をindexとして与えて get していきます.

それで取得したNBTから, 先程読んだlistのデータを読むと分かるようにアイテムは id として表されているので, NBT{}.get_stringで取得します.
そして取得したidを item_by_name で加工して搬出対象となる Item を作成します.

3. 実際に搬出する

そうして作成したitemを搬出するのですが, ここで少し工夫をします.

ただitemを搬出するだけでは消費中も与え続けて無駄にしてしまうので, ここにcooldownを比較して作った真偽値を反映しなければなりません.

ここで choice (?) を使用します.

choiceはBoolean, Any, Any -> Anyのように構成されていて.
スクリーンショットを交えて説明すると

左から, boolean, item, item

今回であればこの関数の動作は, 与えた真偽値がTrueなら左のItem, Falseなら右のItemを出力するという動作になります.
ここで, 左のスロットを空のItem(または, ネットワーク上に存在しないダミーアイテム)とすることで, "搬出しない"状態を作ることが出来ます.

今回の出力はItemですので, World Item Exporterは Place Item Entity (Item) を使用します.
実は先のEndoflameもこのchoiceを噛ませることでネットワーク上に複数アイテムがある状態でも使用できます.

実際に稼働させる際はItem transfar lateやtick/operationも設定しましょう.

おわりに

今回はBotaniaの自動化を書くのに留めておきましたが, Block Readerの他にもInventory Readerを使用する等で他modの施設も案外簡単に自動化出来たりします.

今回で分かったように自動化までの流れは大抵同じですので, こういった最終的な処理対象が一つに定まる物は案外簡単です.

複数対象にする場合に絡んでくるPredicate(過去記事参照)を利用した倉庫の在庫管理システムを作った話もいつか書ければな, と思っています.
ではまた.

この記事が気に入ったらサポートをしてみませんか?