データパック考察、エンティティ←→ブロックエンティティ間での複雑な値の受け渡しを考えてみる【マインクラフト】

ようこそぷっこ村へ、ししゃもだよ

(・∀・)ノ

今回も質問を頂いたので、コマンドについて考えてみようと思います。後、すいませんが初心者向きではないです。

今回のお題はかまどとホッパーの連携

さて今回基本としたいのは、かまどとホッパーの連携をいかにするかみたいな感じです。

  • エンティティブロックのスロットを検知してエンティティのスコアボード値を弄る方法
  • エンティティ間でスコアボードの値を受け渡しする方法

についてです。さらに細かく言うと「かまどに石炭を入れたらスコアボードの値が200ずつ増え、上限が400である。スコアボードの値を基に、隣接するホッパーに張り付けた額縁のスコアボードを弄り中の内容を連動させたい。」

えーと、超ニッチやね。わかりにくいんで図にすると、

Minecrafterししゃもがマインクラフトのコマンドでエンティティ←→ブロックエンティティ間での複雑な値の受け渡しを考えてみる1

これでもちょっと分かりにくいかなぁ。まぁとりあえず解説していってみましょう。

アルゴリズム?的なものを考える

まぁ、大体上の画像通りなんですが、もう少し文章で整理してみます。

  1. プレイヤーがかまどの燃料スロットに石炭を入れる
  2. 上に貼った額縁(Aとする)がかまど内の石炭を検知
  3. Aは自身のスコア(EPとする)が200以下であれば、1つ石炭を消して自身のEPを200加算
  4. 隣接したホッパーに貼り付けられた額縁(Bとする)がAのスコアを監視
  5. BはAのEPが10以上あれば、AのEPを10減算、自身のEPを1加算
  6. Bのスコアボードの値と同数のアイテムをホッパー内に排出後、自身のEPを0に

と言った流れです。では、順に作ってみましょっか~(・∀・)b

必要な基礎知識を考える

まずは必要な基礎知識を考えてみましょう。

かまどとホッパーのスロットについて

前回のホッパー弄りの時に出てきましたが、各スロットには番号が振られており、/data コマンドで情報を取得できます。かまどの場合は加工素材のスロットが0、燃料が1、生成物スロットが2となってます。

Minecrafterししゃもがマインクラフトのコマンドでエンティティ←→ブロックエンティティ間での複雑な値の受け渡しを考えてみる2
かまどのスロット番号

↑みたいな感じ。
ホッパーは左から0から4まででしたね。

Minecrafterししゃもがマインクラフトのコマンドでエンティティ←→ブロックエンティティ間での複雑な値の受け渡しを考えてみる3
ホッパーのスロット番号

かまどの画像の状態で上に立ち、

/data get block ~ ~-0.5 ~ Items[{Slot:1b}].Count

を実行すると 3b が帰ってきます。3個入ってるよってことですね。Items[{Slot:1b}].Count はパスと呼ばれ、情報が階層状に細分化されて書き込まれています。試しに.Count を無くして実行すると Slot:1b に何が何個入ってるかが帰ってきます。できるだけ多く触れて、概念を理解しときましょう。とにかく触れることです、それが近道。

ブロックエンティティのスロットを監視する方法を考える

では、ブロックエンティティのスロットを監視する方法を考えてみましょう。監視するためのエンティティが必要になりますので、今回は額縁を貼るよ。で、監視者をどういう風に決めようかな~ってのがその人の個性になると思います。前回言いましたが、見えないアマスタでもいいし、後光が差したおっさんでもいいんです。今回は質問者さんがやりたい、額縁にしました。

ただの額縁だと他と被るんで、上向きで、且つ中に Thermal_power_generator と表示され、内部的に TPG と言う名前を持ったグローストーンが入った額縁のみ、下のかまどを監視する(わかりにくいなぁ……)、という条件にします。図だと

Minecrafterししゃもがマインクラフトのコマンドでエンティティ←→ブロックエンティティ間での複雑な値の受け渡しを考えてみる4

こんな感じ。ここではそんな条件を持つグローストーンの生成は省きます。中に件のグローストーンをぶち込み

/execute as @e[type=item_frame,nbt={Facing:1b,Item:{id:"minecraft:glowstone",tag:{display:{Name:'{"text":"Thermal_power_generator","color":"aqua","italic":false}',ItemName:TPG}}}}] at @s run data get block ~ ~-0.5 ~ Items[{Slot:1b}].Count

と入れてみましょう。さっきのかまどだと 3b が帰ってきました。

Minecrafterししゃもがマインクラフトのコマンドでエンティティ←→ブロックエンティティ間での複雑な値の受け渡しを考えてみる5

後は毎tickなり、条件付きなり何でもいいので、任意のタイミングで実行すればいいわけです。これで execute と data の組み合わせで、監視ができそうですね。さて、このままだと「何個か」まではわかりますが「何が」がわかりません。何が入っていても3個なら 3b です。ここでは燃料として使えるのは石炭だけとした場合について考えます。

/execute as @e[type=item_frame,nbt={Facing:1b,Item:{id:"minecraft:glowstone",tag:{display:{ItemName:TPG}}}}] at @s if block ~ ~-0.5 ~ minecraft:furnace{Items:[{Slot:1b,id:"minecraft:coal"}]} run data get block ~ ~-0.5 ~ Items[{Slot:1b}].Count

今度は上記のようにして実行してみましょう。これで燃料スロットが石炭の時だけ結果が帰るようになります。コマンドの長さの都合で、display:Nameは省きました。execute と if block を組み合わせれば、すごいこともできそうですね。ここまで来れたら後はどうにでもなるはずです。次にスコアボードとの連携を考えてみましょう。

かまどとスコアボードの連携を考える

かまどに石炭が入っていたら、1つ減らして額縁のスコアボードを200増やしてみましょう。燃料用のボードの他に石炭の数を保存するボードも必要になります。さらに、スロット内の数をスコアボードとリンクさせたい場合は、execute store result を使うんでしたね。これは、ボード←→スロット間で使える方法の多分一番簡単なやつです。わからん輩は前回を読んでね

/scoreboard objectives add EP dummy ←燃料用
/scoreboard objectives add Count dummy ←石炭の数用
/scoreboard players set @e[type=item_frame] EP 0
/scoreboard players set @e[type=item_frame] Count 0

/execute if entity @e[type=item_frame,scores={EP=..200},nbt={Facing:1b,Item:{id:"minecraft:glowstone",tag:{display:{Name:'{"text":"Thermal_power_generator","color":"aqua","italic":false}',ItemName:TPG}}}}] as @e[type=item_frame,scores={EP=..200},nbt={Facing:1b,Item:{id:"minecraft:glowstone",tag:{display:{Name:'{"text":"Thermal_power_generator","color":"aqua","italic":false}',ItemName:TPG}}}}] at @s if block ~ ~-0.5 ~ minecraft:furnace{Items:[{Slot:1b,id:"minecraft:coal"}]} store result score @e[type=item_frame,scores={EP=..200},limit=1,sort=nearest,nbt={Facing:1b,Item:{id:"minecraft:glowstone",tag:{display:{Name:'{"text":"Thermal_power_generator","color":"aqua","italic":false}',ItemName:TPG}}}}] Count run data get block ~ ~-0.5 ~ Items[{Slot:1b}].Count
/execute as @e[type=item_frame,scores={Count=1..},nbt={Facing:1b,Item:{id:"minecraft:glowstone",tag:{display:{Name:'{"text":"Thermal_power_generator","color":"aqua","italic":false}',ItemName:TPG}}}}] run scoreboard players remove @s Count 1
/execute as @e[type=item_frame,nbt={Facing:1b,Item:{id:"minecraft:glowstone",tag:{display:{Name:'{"text":"Thermal_power_generator","color":"aqua","italic":false}',ItemName:TPG}}}}] at @s store result block ~ ~-0.5 ~ Items[{Slot:1b}].Count int 1 run scoreboard players get @e[type=item_frame,nbt={Facing:1b,Item:{id:"minecraft:glowstone",tag:{display:{Name:'{"text":"Thermal_power_generator","color":"aqua","italic":false}',ItemName:TPG}}}},limit=1,sort=nearest] Count

ここでは、かまどの石炭の数をCount に取り込み1減算してかまどに戻してます。スコアボードの条件 scores 値が反応しませんってよく聞かれるんですけど、スコアボードはできた時は値がなく null の状態です。「無」です。以上とか以下とかがそもそも比較できません。100と「無」を比較してどっちがでかい?みたいなこと聞かれても「???」ですね。なので状況にもよりますが、いきなり比較にさらされるなら、set 0 とかしときましょう。

それにしても、それぞれがくっっっっっっっっっっそ長いコマンドですね。ぶっちゃけ、ししゃもはこのままデータパックに組み込むことはないです。絶対にタグ付けをして、できる限り可読性を上げる努力をしましょう。そして別の mcfunction ファイルを用意してそちらに処理をかわしましょう。ここではそのような解説はしません。なぜなら、解説がどんどん長引いて、ししゃもが死んじゃうからです。タグや条件分岐は自分で応用してください、おねがいします。

とりあえず、execute if や execute store 、data や scoreboard などのコマンドで、かなり複雑な条件指定ができることを感覚として覚えておきましょう。

額縁間のスコアボードの連携を考える

もう大体わかるよね?そう、scoreboard コマンドです。今回の場合は、ホッパーに貼り付けられ、上向きで、且つ中に Capacitorと表示され、内部的に CAP と言う名前を持ったグローストーンが入った額縁のみ、隣接するThermal_power_generatorを監視する(やっぱりわかりにくいなぁ……)、という条件にします。図だと

Minecrafterししゃもがマインクラフトのコマンドでエンティティ←→ブロックエンティティ間での複雑な値の受け渡しを考えてみる6

↑こんな感じかな。じゃあやってみよう。

/execute as @e[type=item_frame,scores={Count=1..},nbt={Facing:1b,Item:{id:"minecraft:glowstone",tag:{display:{Name:'{"text":"Thermal_power_generator","color":"aqua","italic":false}',ItemName:TPG}}}}] run scoreboard players add @s EP 200
/execute as @e[type=item_frame,scores={EP=0..59},nbt={Facing:1b,Item:{id:"minecraft:glowstone",tag:{display:{Name:'{"text":"Capacitor","color":"aqua","italic":false}',ItemName:CAP}}}}] at @s if entity @e[type=item_frame,scores={EP=10..},distance=..1,nbt={Facing:1b,Item:{id:"minecraft:glowstone",tag:{display:{Name:'{"text":"Thermal_power_generator","color":"aqua","italic":false}',ItemName:TPG}}}}] run scoreboard players add @s EP 1
/execute as @e[type=item_frame,scores={EP=0..59},nbt={Facing:1b,Item:{id:"minecraft:glowstone",tag:{display:{Name:'{"text":"Capacitor","color":"aqua","italic":false}',ItemName:CAP}}}}] at @s if entity @e[type=item_frame,scores={EP=10..},distance=..1,nbt={Facing:1b,Item:{id:"minecraft:glowstone",tag:{display:{Name:'{"text":"Thermal_power_generator","color":"aqua","italic":false}',ItemName:TPG}}}}] run scoreboard players remove @e[type=item_frame,scores={EP=10..},distance=..1,nbt={Facing:1b,Item:{id:"minecraft:glowstone",tag:{display:{Name:'{"text":"Thermal_power_generator","color":"aqua","italic":false}',ItemName:TPG}}}}] EP 10

ここまで来れたなら、あまり解説はいらないでしょう。そこ!!めんどくなったんだな?とか思わない!!

1行目の Count=1.. はかなり乱暴です。バグの元凶になるので、タグ付けなどで回避した方がいいでしょう。以上を実行すると……、

Minecrafterししゃもがマインクラフトのコマンドでエンティティ←→ブロックエンティティ間での複雑な値の受け渡しを考えてみる7

こんな感じでスコアが変わりました。後は、前回のような感じで、ホッパー内に Capacitor 側の EP の値を使ってアイテムを排出すれば出来上がりですね。尚、全体を繋げても上手くは動きませんので悪しからず、あくまで筋道を示しただけです。個別のやりたいことに汎用的に当てはまるように書くのは不可能なので、各自応用してね。

まとめると & ダウンロード

以上のことをまとめて、全体を整えてみたいと思います。
↓init.mcfunction

scoreboard objectives add EP dummy
scoreboard objectives add Count dummy

↓main.mcfunction

execute if entity @e[type=item_frame,tag=!TPG,nbt={Facing:1b,Item:{id:"minecraft:glowstone",tag:{display:{ItemName:TPG}}}}] run function tp:hoge
execute if entity @e[type=item_frame,tag=TPG] run function tp:piyo
execute if entity @e[type=item_frame,tag=!CAP,nbt={Facing:1b,Item:{id:"minecraft:glowstone",tag:{display:{ItemName:CAP}}}}] run function tp:moge
execute if entity @e[type=item_frame,tag=CAP] run function tp:poyo

↓hoge.mcfunction

tag @e[type=item_frame,nbt={Facing:1b,Item:{id:"minecraft:glowstone",tag:{display:{ItemName:TPG}}}}] add TPG
scoreboard players set @e[type=item_frame,tag=TPG] EP 0

↓piyo.mcfunction

execute as @e[type=item_frame,tag=TPG,scores={EP=..200}] at @s if block ~ ~-0.5 ~ minecraft:furnace{Items:[{Slot:1b,id:"minecraft:coal"}]} run tag @s add Recharge
execute as @e[type=item_frame,tag=Recharge] at @s store result score @s Count run data get block ~ ~-0.5 ~ Items[{Slot:1b}].Count
execute as @e[type=item_frame,tag=Recharge] run scoreboard players remove @s Count 1
execute as @e[type=item_frame,tag=Recharge] run scoreboard players add @s EP 200
execute as @e[type=item_frame,tag=Recharge] at @s store result block ~ ~-0.5 ~ Items[{Slot:1b}].Count int 1 run scoreboard players get @s Count
tag @e[type=item_frame,tag=Recharge] remove Recharge

↓moge.mcfunction

tag @e[type=item_frame,nbt={Facing:1b,Item:{id:"minecraft:glowstone",tag:{display:{ItemName:CAP}}}}] add CAP
scoreboard players set @e[type=item_frame,tag=CAP] EP 0

↓poyo.mcfunction

execute as @e[type=item_frame,tag=CAP,scores={EP=0..59}] at @s if entity @e[type=item_frame,scores={EP=10..},distance=..1,tag=TPG] run scoreboard players add @s EP 1
execute as @e[type=item_frame,tag=CAP,scores={EP=0..59}] at @s if entity @e[type=item_frame,scores={EP=10..},distance=..1,tag=TPG] run scoreboard players remove @e[type=item_frame,scores={EP=10..},distance=..1,tag=TPG] EP 10

これで、Capacitor 側までスコアが移動するようになりました。やったね!!後はホッパーに排出ですが、何回も書くけど、前回でやり方をまとめてますのでそっちを参照オナシャス。

一応今回のパックを貼っておく test_packをダウンロード

今回の内容って、電力供給をイメージしてるみたいなんですが、離れたところに遠隔でエネルギーを送るとかSFみたいなこともできますよね。テスラの時代到来やね。その他にも応用が利くと思うので自分なりに作り替えてみてはどうでしょう?

それではこの辺で、良きコマンドライフを~。お帰りの際はお気をつけて~(・∀・)ノシ

コメント

トップへ戻る
タイトルとURLをコピーしました