初心者研修編リンク
- 新規Modの作成からビルドまで
- 早速プログラムを書いてみる ← here
- デバッグを実践する
- ItemとItemStackの違い
- BlockとIBlockStateとTileEntityは一緒です(大嘘)
- イベント購読
- 音とか粒子とか
- ワールドとディメンションは何が違うんだ
- Entityを少しだけ操る
- 強敵NBT
- メインページへ戻る
はじめに
この記事では(初めての方にとっては)初めてのプログラミングとModdingを体験していただきます。
とはいっても身構える必要はありません。
全てじっくり説明しながら進めていきますので、頑張っていきましょう。
記事中でのJavaプログラミングの説明については、Moddingに必要な部分の必要最低限だけを雑に何となくで分かる説明をします。
厳密で正確なプログラミングの説明を知りたい方は別サイトで学んでください。
エディタ(Intellij IDEA)の画面の色や見た目は設定でいくらでも自分好みに変更できます。
そのため、文字の色や背景色等が自分で使っているものと画像とでは異なります。
見づらい等のお問い合わせはコメントへお願いいたします。
今回の題材
今回、Moddingとプログラミングの練習として「クラフトレシピの追加」をやっていただきます。
レシピ追加自体はリソースパックでも可能な代物1ですが、初めてModdingとプログラミングをやってみるという方には丁度良い難易度となっています。
目次
1. 準備
簡易目次
MyMod.java
を開く
まずはMyMod.java
を開きましょう。
プロジェクトビューからsrc
>main
>java
>(前回の記事で決めたパッケージ)>MyMod
をたどって開きましょう。
赤線が引かれていたり、赤い文字が含まれている
6. Build Jars
を実行していない場合は下の画像のようにエラーが出てしまいますので、6. Build Jars
を実行してください。
└赤線が引かれていたり、赤い文字が含まれている終わり
ソースコードがぶわっと出てきますが、恐れる必要はありません。
今は書いてあることを理解する必要は一切無いです。
プログラミングにおいて、「ここに何か書いてあるけどよくわからないし放っておこう」という考えは大事です。
全てを理解するまで少しも次には進まないぞ!みたいな思考で突き進もうとすると先に寿命が尽きてしまいます。
いずれ全て理解できるようになりますので、まずは
ソースコードの折り畳みを使いこなす
開いたMyMod.javaの行番号をよく見てみると……変ですね、番号が跳んでいます。
これはIntellij IDEAの機能で、まとまった部分を1行に折り畳むということが行われています。
プロジェクトビューでも、フォルダの中身を展開する・畳むということができましたが、
これと同じことをテキストに対してもやったら便利じゃね!?ということでソースコードも部分的に折り畳むことができます。
では試しに3行目のソースコードを展開してみましょう。
行番号の右にある>
(矢印)をクリックしてください。
閉じて見なかったことにしましょう。
折り畳んだときは…
として表示される2んですね。
このまましばらく封印しておきましょうか。
2. とりあえずプログラムを書いて(コピペ)動かす
では自由にプログラムを書いてください!
.
..
...
....
.....
この隠し文字に良く気づきましたね…
......
まさかダークモードではないだろうな!?
と言われても困ります。Moddingもプログラミングも初心者では手も足も出ません。経験者であってもさすがに非情な行為
なのでまずはお手本を見ましょう。
簡易目次
33行目の折り畳みを開く
プログラムを書く場所は33行目にあるregisterRecipes
というメソッド3の中です。
まずは33行目の左端の矢印からメソッドの中身を展開表示しておいてください。
ソースコードをコピペ
Moddingで使うJavaプログラミングは、基本的に中かっこ4({
と}
)に囲まれた領域にコードを書きます5。
まずは以下のコードを(最初と最後の{
}
含めて)34行目に貼り付けてください。
{
//--------------------不定形レシピの追加--------------------
// クラフト材料の設定(アイテムの指定は順不同)
NonNullList<Ingredient> ingredients = NonNullList.create();
ingredients.add(Ingredient.fromItem(Items.APPLE)); // リンゴ
ingredients.add(Ingredient.fromItem(Items.GOLD_INGOT)); // 金インゴット
// クラフト成果品の設定
ItemStack output = new ItemStack(Items.GOLDEN_APPLE, 2); // 金リンゴ×2
// レシピの作成
ShapelessRecipes recipe = new ShapelessRecipes("", output, ingredients); // groupと成果品と材料からレシピ作成
// レシピの登録
recipe.setRegistryName(new ResourceLocation(Tags.MODID, "apple_plus_gold_ingot")); // 登録時の内部レシピ名指定
event.getRegistry().register(recipe); // 登録
}
以下のようになればOKです。
57行目と58行目で中かっこが2つもあるんだがええんか!?その状態でお願いします。おう分かったで~。
もし、エラー(赤文字)だらけ6の場合は、別の行をクリックすると自動で直るはずです。
直らん!
一つひとつ直してもいいのですが、面倒なので便利な設定を施しておきましょう。
Intellijの設定を開きまして、
エディター
>一般
>自動インポート
のページを開きます。
Java
という節の中にある貼り付け時にインポートを挿入
を常時
にし、明確なインポートをオンザフライで追加する
にチェックを入れてOK
を押してください。
すると少し待つだけで自動でエラーを直してくれます。
かがくのちからってすげー!
└直らん!終わり
ソースコードを眺めてみる
説明とかいいから早く動かしたい!って人は先に実際に動かしてみるを実施しましょう。
全体
まず処理の全体が39行目の{
と58行目の}
で囲まれています。
さらにもう一段階、40行目と57行目の{}
で囲まれています。
(2重にした理由は後で分かります。)
Javaでは、中かっこを使うことでブロック(ひとまとまり)を作ることができます。
これらの中かっこも折り畳みできますので、ぜひ試してみてください。
コメントの説明と45行目の理解
41行目や43行目など、がっつり日本語で説明が書かれています。
これはプログラミング用語で「コメント」と呼びます。
Javaでは、//
(スラッシュ2つ)以降から行の終わりまでがコメントとして扱われ、何を書いても一切プログラムの動作に影響を与えません7。
大抵は書いたコードの内容を分かりやすく簡潔にコメントとして残します。
コメントは嘘さえ書かなければ害は無いので、積極的に書くことが推奨されます。
(特に数か月経った後の自分が一番恩恵を受ける8)
呪文みたいなJavaのソースコードは分からなくても、コメントを見るだけで何となく動きが分かるはずです。
例えば、45行目に着目してみましょう。
ingredients.add(Ingredient.fromItem(Items.APPLE)); // リンゴ
コメントで「リンゴ」と書いてありますが、コードをよく読むとItems.APPLE
と書かれています。
「なるほど、アイテムのリンゴを何かしら設定してるな」ということが読み取れます。
43行目には// クラフト材料の設定(アイテムの指定は順不同)
と書かれていたため、「クラフトレシピの材料の1つがリンゴなんだろうな」と想像できます。
プログラミング・Modding初心者であっても、コメントを読めば何となくコードの中身が少しずつ読めてきます。
Javaのソースコードも大半が英語由来9なので、何となくでもいいから英語さえ分かれば何とかなります。
(逆に英語に拒否反応がある場合は何とかして克服してください。)
今の時代はChatGPT等のチャットAIもありますので、このソースコードをそのままChatGPTに渡して「説明して」と頼めばいくらでも教えてくれるので便利です。(ただし嘘もかなり多いので鵜呑みにはしないようにしましょう。)
コメントから全体像の把握
先ほどは45行目だけピンポイントで何となく少しだけわかりましたが、今度はコメントを読んで全体の流れをつかんでみましょう。
41行目に不定形レシピの追加
とあるので、40~57行目全体で不定形レシピの追加を実現しているのでしょう。
43行目にはクラフト材料の設定
とあります。
44~46行目を指していそうです。
45行目と46行目にそれぞれリンゴ
と金インゴット
と書かれていますが、先ほどのクラフト材料の設定
というコメントと総合して考えると、クラフトのレシピに「リンゴ」と「金インゴット」が含まれていると予想できます。
48行目のクラフト成果品の設定
というコメントは、49行目の話をしており、金リンゴ×2
というコメントから察するにクラフトによって金リンゴが2個手に入るのでしょう。
51行目にレシピの作成
というコメントがあり、52行目のことを指していると思われます。
52行目のコメントは読んでもピンとこないので無視します10。
54行目のコメントがレシピの登録
となっているので、55~56行目がレシピの登録部分のようです。
まとめますと、
-
全体は不定形レシピの追加処理
-
処理は順に
- クラフト材料の設定
- クラフト成果品の設定
- レシピの作成
- レシピの登録
の順でおこなっている様子
-
「リンゴ」と「金インゴット」から「金リンゴ2つ」ができる不定形レシピがおそらく追加される
ということが読み取れます。
このように、呪文のようなソースコードを解読しなくとも、コメントを読むだけで処理内容とその流れが把握できます。
ソースコードの中身がよくわからない初心者であっても何とかなりそうですね!
現実にはコメントが一切書かれてない不親切なソースコードも多々あるのが悲しいところ
実際に動かしてみる
マイクラを起動してみましょう。
2. Run Client
を実行してください。
エラーになって起動できない
十中八九、MyMod.java
のファイル中に余計な文字を打ち込んでいます。(もしくは誤って削除)
Ctrl+Z
で最初まで戻せれば一番楽です。(ファイルを閉じてしまうとこれが使えなくなる。)
または見つけて直せれば良いのですが、見つからないこともしばしばあります。(全角スペースとかその代表)
コピペで増やした40行目から57行目をいったん削除し、再びコピペしなおすことで、大抵は解決するでしょう。
万が一完全に別の行を壊していた場合は、現状Modの作成からやり直ししかありません。
もしGitのバージョン管理(環境構築編で解説済み)を行っていればそれに従ってすぐに復元できるのですが…
最初からやり直しはヤダ!!!!!
今回ばかりは、ここにMyMod.java
の元のソースコードを貼っておきましょう。
こういうことが起こらないように、バージョン管理を使ってください。
(package
のある1行目だけは自分で決めたパッケージ名に合わせる必要があります。)
package my_first_mod;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.item.crafting.IRecipe;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@Mod(modid = Tags.MODID, version = Tags.VERSION, name = Tags.MODNAME, acceptedMinecraftVersions = "[1.12.2]")
public class MyMod {
public static final Logger LOGGER = LogManager.getLogger(Tags.MODID);
@EventHandler
// preInit "Run before anything else. Read your config, create blocks, items, etc. (Remove if not needed)
public void preInit(FMLPreInitializationEvent event) {
// register to the event bus so that we can listen to events
MinecraftForge.EVENT_BUS.register(this);
LOGGER.info("I am " + Tags.MODNAME + " + at version " + Tags.VERSION);
}
@SubscribeEvent
// Register recipes here (Remove if not needed)
public void registerRecipes(RegistryEvent.Register<IRecipe> event) {
}
@SubscribeEvent
// Register items here (Remove if not needed)
public void registerItems(RegistryEvent.Register<Item> event) {
}
@SubscribeEvent
// Register blocks here (Remove if not needed)
public void registerBlocks(RegistryEvent.Register<Block> event) {
}
@EventHandler
// load "Do your mod setup. Build whatever data structures you care about." (Remove if not needed)
public void init(FMLInitializationEvent event) {
}
@EventHandler
// postInit "Handle interaction with other mods, complete your setup based on this." (Remove if not needed)
public void postInit(FMLPostInitializationEvent event) {
}
@EventHandler
// register server commands in this event handler (Remove if not needed)
public void serverStarting(FMLServerStartingEvent event) {
}
}
└最初からやり直しはヤダ!!!!!終わり
└エラーになって起動できない終わり
新規ワールドを(もちろんクリエイティブで)作成して入ります。
謎のアイテムを持った状態でスポーンしますが捨てて良いです。
リンゴと金インゴット(と作業台11)を取り出し、クラフトしてみましょう。
本当に金リンゴ2つがクラフトできますね!
不定形レシピなので、どのような置き方をしても金リンゴが作れます。
JEIでレシピを見る
Moddingで用いているGregTechCEu製のBuildscriptsが初期設定でJEIを入れてくれているため、デバッグ環境でも何の苦労もすることなくJEIが使えます。
インベントリ画面の右側でページ送りして(マウスホイールが楽)リンゴを探し、右クリックしましょう。
レシピがちゃんと登録されていますね!
不定形レシピなので、それを表すアイコン(クロス矢印)が付いています。
└JEIでレシピを見る終わり
3. 少しだけ改造してみる
とりあえずコピペしたコードをそのまま動かしました。
どうせならこのコードを少しカスタマイズして、自分の思い通りに動かしたいものです。
1. 成果品の個数を変えてみる
成果品の設定を行っている49行目を見てみましょう。
ItemStack output = new ItemStack(Items.GOLDEN_APPLE, 2); // 金リンゴ×2
ここでは金リンゴが2つ作成されるように設定するプログラムコードが書かれています。
…… Javaのプログラミングを知らなくても何となく読み取れませんか?
特に個数を指定してそうな場所ありますよね?
そうです、2
が使われている唯一のここです。
(直前にamount:
と書かれていますが、これはIntellij IDEAのお節介機能12で表示しているゴーストであり、この文字列が入力されているわけではありません13。)
この部分を別の数に書き換えて保存(当然Ctrl+S
)し、マイクラを起動してみましょう。
全角数字だとエラーになります。
必ず半角数字で入力してください。
ゲーム内でアイテムを作業台に置いてみると、見事に変化していることが分かります。
これで完成品の個数を自由に設定させることができるようになりました!
└1. 成果品の個数を変えてみる終わり
2. 成果品を別アイテムにする
成果品の設定を行っている49行目をもう一度見てみます。
ItemStack output = new ItemStack(Items.GOLDEN_APPLE, 2); // 金リンゴ×2
ここでは金リンゴが2つ作成されるように設定するプログラムコードが書かれています。
…… Javaのプログラミングを知らなくても何となく読み取れませんか?
「金リンゴ」は英語でGolden Appleと呼びますが、「金リンゴ」を指定してそうな場所ありますよね?
そうです、GOLDEN_APPLE
と書かれていたらそりゃもう、それです。
ここを自由に変更!と行きたいところですが、この部分14はルールに従って書く必要があります。
例えば、GOLDEN_APPLE
ではなく、GOLD_APPLE
と書いたらどうなるか試してみます。
見事に赤字のエラーになっており、このままでは2. Run Client
も失敗します。
つまり、完璧に一字一句正しいものを書かないとエラーになります。
プログラミングでは、基本的に一字一句完全に正しく書く必要がある場合がほとんどです。
大文字小文字、全角半角、空白や_を入れる位置等を厳密に書くようにしましょう。
さて、「金リンゴ」の代わりに「ネザースター」が作成されるように改造したいとしましょう。
ですが、ネザースターの「正しい書き方15」が分からないとエラーになってしまいます。
いちいちネザースターの正しい書き方なんて憶えてられません。
そこでIntellij IDEAの機能を活用します。
まずはGOLDEN_APPLE
を消します。
(この時Items.
と,
が隣り合うはずです。消しすぎたらCtrl+Z
で戻しましょう。)
次にItems.
の直後にキャレット(≒マウスカーソル16)を置き、キーボードでCtrl+Space
(Ctrlキーとスペースキー17)を押します。
すると、正しい書き方の候補がズラッと並びます。
後はマウスホイールでスクロールし、お目当てが見つかったらダブルクリックしてください。
(候補が多すぎて探すのが面倒な場合は、欲しい選択肢に含まれるアルファベット(ネザースターならNE
など)を追加で入力すると候補を絞れます。)
Ctrl+Space
というショートカットによる候補の表示と自動入力はぜひたくさん活用してください。
これだけで何倍もプログラムを書く効率が変わります。
└2. 成果品を別アイテムにする終わり
3. 材料も別アイテムにする
今度は成果品ではなく、材料を変更してみましょう。
材料の設定は44行目から46行目です。
NonNullList<Ingredient> ingredients = NonNullList.create();
ingredients.add(Ingredient.fromItem(Items.APPLE)); // リンゴ
ingredients.add(Ingredient.fromItem(Items.GOLD_INGOT)); // 金インゴット
謎な部分もたくさんありますが、リンゴと金インゴットを指定している部分がありますね?
よく見たら、成果品の時と同じItems.(アイテム名)
という形です。
つまり成果品の時と同じ方法で変更できます。
ではここで練習問題を解いてみましょうか。
<練習問題> ネザーウォートと砂糖からクモの目が3つ作成できるレシピを登録してください。
ヒント集(ネザーウォート)
ヒント1
ネザーウォートは英語でNether Wartと書きます。
もしかしたらプログラムでも似たように書くかもしれませんね。
近いものをCtrl+Space
の候補表示で探してみましょう。
└ヒント1終わり
ヒント2
ネザーウォートはプログラムではItems.NETHER_WART
と書きます。
└ヒント2終わり
└ヒント集(ネザーウォート)終わり
ヒント集(砂糖)
ヒント1
砂糖は英語でSugarと書きます。
もしかしたらプログラムでも似たように書くかもしれませんね。
近いものをCtrl+Space
の候補表示で探してみましょう。
└ヒント1終わり
ヒント2
砂糖はプログラムではItems.SUGAR
と書きます。
└ヒント2終わり
└ヒント集(砂糖)終わり
ヒント集(クモの目)
ヒント1
クモの目は英語でSpider Eyeと書きます。
もしかしたらプログラムでも似たように書くかもしれませんね。
近いものをCtrl+Space
の候補表示で探してみましょう。
└ヒント1終わり
ヒント2
クモの目はプログラムではItems.SPIDER_EYE
と書きます。
あとは全てを組み合わせるだけです。
個数の変更を忘れないようにしましょう。
└ヒント2終わり
└ヒント集(クモの目)終わり
模範解答
コメントを書き換えるのは必須ではありませんが、嘘コメントは良くないのでちゃんと書き換えましょう。
// クラフト材料の設定(アイテムの指定は順不同)
NonNullList<Ingredient> ingredients = NonNullList.create();
ingredients.add(Ingredient.fromItem(Items.NETHER_WART)); // ネザーウォート
ingredients.add(Ingredient.fromItem(Items.SUGAR)); // 砂糖
// クラフト成果品の設定
ItemStack output = new ItemStack(Items.SPIDER_EYE, 3); // クモの目×3
└模範解答終わり
できあがったものをゲーム内で試してみると…
無事成功しました。
└3. 材料も別アイテムにする終わり
4. 材料の種類数を変更する
今まで材料は2種類固定でしたが、もうちょっと自在に設定したいものです。
今回のコードで、材料の種類が2種類になってしまうのはどの部分が関係しているでしょうか。
材料の設定をする部分を抜き出しました。
43 // クラフト材料の設定(アイテムの指定は順不同)
44 NonNullList<Ingredient> ingredients = NonNullList.create();
45 ingredients.add(Ingredient.fromItem(Items.APPLE)); // リンゴ
46 ingredients.add(Ingredient.fromItem(Items.GOLD_INGOT)); // 金インゴット
44行目はよく分からないから置いとくとして、
45行目と46行目で各行1アイテムを登録しています。
もしかしたらコードの行数を増減させるだけでうまくいくかもしれません。
46行目(金インゴットの行)をコピペして次の行に増やしちゃいましょう。
こんな感じです。
新たに47行目が増えました。
この状態でマイクラを起動してみましょうか。
今までのレシピが使えなくなりました。
そして、リンゴ、金インゴット、金インゴットの新レシピが使えるようになっています。
(同じ材料が複数あっても直感通りに動作するんですね。)
今度は行を削ってみましょう。
リンゴの行だけ残しました。(金インゴットは元からレシピがあるので却下)
これでマイクラを起動しますと、リンゴ単体で金リンゴ2つに変身するチートすぎるレシピができあがりました。
まとめると、
ingredients.add(Ingredient.fromItem(Items.ここはアイテムによって変える));
を書いた行数だけ材料が設定されるということですね。
└4. 材料の種類数を変更する終わり
5. ブロックもクラフトに含む
今までずっと隠してきたことなのですが、Items.
からアイテムを探すやり方では、ブロックを材料や完成品に指定することができません。
そこでブロックも設定できるようにする方法を伝授します。
Items.なんたら
の代わりに、
Item.getItemFromBlock(Blocks.DIAMOND_BLOCK)
を書きます。
よく見るとItems
ではなくItem
に変わっています。
紛らわしいことこの上ないですが、そういうルールと決まっているので間違えないようにしましょう。(当然間違えるとエラーです。)
Blocks.
の後ろにブロック名が来てますが、これもItems.
で説明した時と同様、正しい書き方候補をCtrl+Space
で表示できますのでぜひ活用してくださあい。
それでは実際にブロックも含めたレシピを登録してみましょう。
レシピの材料と成果品は、ブロックとアイテムを好きなように組み合わせられます。
例えば、金ブロックとダイアモンド3個ででダイアモンドブロックができる不定形レシピは、
// クラフト材料の設定(アイテムの指定は順不同)
NonNullList<Ingredient> ingredients = NonNullList.create();
ingredients.add(Ingredient.fromItem(Item.getItemFromBlock(Blocks.GOLD_BLOCK))); // 金ブロック
ingredients.add(Ingredient.fromItem(Items.DIAMOND)); // ダイアモンド
ingredients.add(Ingredient.fromItem(Items.DIAMOND)); // ダイアモンド
ingredients.add(Ingredient.fromItem(Items.DIAMOND)); // ダイアモンド
// クラフト成果品の設定
ItemStack output = new ItemStack(Item.getItemFromBlock(Blocks.DIAMOND_BLOCK), 1); // ダイアモンドブロック
のように書けます。
かっこの個数が増えるので、間違えないようにしましょう。
1個でも過不足があるとエラーになります。
Intellij IDEA上ではこんな感じです。
エラーが出ている場合は、何かしらの記述ミスが発生しています。
Ctrl+Z
するなりコードのコピペをし直すなりして画像通りの状態にしてください。
うまくいったのであれば、ちょっと練習問題でも解いてみましょう。
<練習問題>サボテン+コーラスフルーツ+コーラスフルーツ+種 → コーラスフラワーの不定形レシピを登録してください。
ヒント集(サボテン)
ヒント1
サボテンは英語でCactusと書きます。
もしかしたらプログラムでも似たように書くかもしれませんね。
└ヒント1終わり
ヒント2
サボテンはブロックです。
つまり、
Item.getItemFromBlock(Blocks.DIAMOND_BLOCK)
の形で書く必要があるでしょう。
DIAMOND_BLOCK
の部分を消し、Blocks.(ここにキャレット)
の状態でCtrl+Space
を押し、候補表示でそれっぽいものを探してみましょう。
└ヒント2終わり
ヒント3
サボテンはプログラムではItem.getItemFromBlock(Blocks.CACTUS)
と書きます。
└ヒント3終わり
└ヒント集(サボテン)終わり
ヒント集(コーラスフルーツ)
ヒント1
コーラスフルーツは英語でChorus Fruitと書きます。
もしかしたらプログラムでも似たように書くかもしれませんね。
└ヒント1終わり
ヒント2
コーラスフルーツはアイテムです。
つまり、
Items.APPLE
の形で書く必要があるでしょう。
APPLE
の部分を消し、Items.(ここにキャレット)
の状態でCtrl+Space
を押し、候補表示でそれっぽいものを探してみましょう。
└ヒント2終わり
ヒント3
コーラスフルーツはプログラムではItems.CHORUS_FRUIT
と書きます。
今回は2つ必要なので2行分書きましょう。
└ヒント3終わり
└ヒント集(コーラスフルーツ)終わり
ヒント集(種)
ヒント1
種は英語でSeedsと書きます。
ただし、プログラムでも同じように書くとは限りません…
ちなみに小麦は英語でWheatです。
└ヒント1終わり
ヒント2
種はアイテムです。
つまり、
Items.APPLE
の形で書く必要があるでしょう。
APPLE
の部分を消し、Items.(ここにキャレット)
の状態でCtrl+Space
を押し、候補表示でそれっぽいものを探してみましょう。
ただし、SEEDSで出てくるとは限りません…
└ヒント2終わり
ヒント3
種はプログラムではItems.WHEAT_SEEDS
と書きます。
「小麦の」種なので納得はできますね。
└ヒント3終わり
└ヒント集(種)終わり
ヒント集(コーラスフラワー)
ヒント1
コーラスフラワーは英語でChorus Flowerと書きます。
もしかしたらプログラムでも似たように書くかもしれませんね。
└ヒント1終わり
ヒント2
コーラスフラワーはブロックです。
つまり、
Item.getItemFromBlock(Blocks.DIAMOND_BLOCK)
の形で書く必要があるでしょう。
DIAMOND_BLOCK
の部分を消し、Blocks.(ここにキャレット)
の状態でCtrl+Space
を押し、候補表示でそれっぽいものを探してみましょう。
└ヒント2終わり
ヒント3
コーラスフラワーはプログラムではItem.getItemFromBlock(Blocks.CHORUS_FLOWER)
と書きます。
└ヒント3終わり
└ヒント集(コーラスフラワー)終わり
模範解答
コメントを書き換えるのは必須ではありませんが、嘘コメントは良くないのでちゃんと書き換えましょう。
// クラフト材料の設定(アイテムの指定は順不同)
NonNullList<Ingredient> ingredients = NonNullList.create();
ingredients.add(Ingredient.fromItem(Item.getItemFromBlock(Blocks.CACTUS))); // サボテン
ingredients.add(Ingredient.fromItem(Items.CHORUS_FRUIT)); // コーラスフルーツ
ingredients.add(Ingredient.fromItem(Items.CHORUS_FRUIT)); // コーラスフルーツ
ingredients.add(Ingredient.fromItem(Items.WHEAT_SEEDS)); // (小麦の)種
// クラフト成果品の設定
ItemStack output = new ItemStack(Item.getItemFromBlock(Blocks.CHORUS_FLOWER), 1); // コーラスフラワー
できあがったものをゲーム内で試してみると…
無事成功しました。
└模範解答終わり
└5. ブロックもクラフトに含む終わり
6. レシピを複数登録する
現状、レシピを何種類も生み出しているのに、1つしか登録されていません。
それもそのはず、レシピを追加するコードはMyMod.java
の中に1つしか書いていません。
今まではずっとその一つを使いまわしてきましたが、ついにレシピ追加コードを増殖させましょう。
最初のコードはこれでした。
{
//--------------------不定形レシピの追加--------------------
// クラフト材料の設定(アイテムの指定は順不同)
NonNullList<Ingredient> ingredients = NonNullList.create();
ingredients.add(Ingredient.fromItem(Items.APPLE)); // リンゴ
ingredients.add(Ingredient.fromItem(Items.GOLD_INGOT)); // 金インゴット
// クラフト成果品の設定
ItemStack output = new ItemStack(Items.GOLDEN_APPLE, 2); // 金リンゴ×2
// レシピの作成
ShapelessRecipes recipe = new ShapelessRecipes("", output, ingredients); // groupと成果品と材料からレシピ作成
// レシピの登録
recipe.setRegistryName(new ResourceLocation(Tags.MODID, "apple_plus_gold_ingot")); // 登録時の内部レシピ名指定
event.getRegistry().register(recipe); // 登録
}
これをMyMod.java
に1回だけコピペしてきましたが、これを複数回コピペしてみましょう。
中かっこがあるおかげで、2つそれぞれのまとまりが分かりやすくなっています。
何なら中かっこなので折り畳みも可能です。
同じレシピを二重に登録しても意味は無いので、片方のレシピを変更しておきましょう。
2つ目のレシピの材料に金インゴットを1つ増やし、完成品の個数を3個に増やしました。
これでマイクラを起動して試してみましょう18。
どうやら2つ目のレシピを登録した段階で1つ目のレシピが上書きされてしまっているようです。
「残念だけど、レシピの複数登録は無理なのかなあ…」と諦めてはいけません。
レシピ登録部分のコードを抜粋します。
// レシピの登録
recipe.setRegistryName(new ResourceLocation(Tags.MODID, "apple_plus_gold_ingot")); // 登録時の内部レシピ名指定
event.getRegistry().register(recipe); // 登録
コメントを読むと、登録時の内部レシピ名指定
と書かれています。
どうやらレシピに名前を付けているようです。
その名前はapple_plus_gold_ingot
です19。
2回コピペをし、材料や完成品を書き換えましたが、「レシピの名前」なるものを書き換えたことは一度もありません。
……もしかして同じ名前だと上書きしてしまうのでしょうか?
では名前を書き換えてみましょうか。
先ほどの変更に加えて、2つ目のレシピの名前をapple_plus_2_gold_ingots
にしてみました。
これでマイクラを起動してみましょう。
つまり、
レシピ名が重複すると上書きされる
ことが分かりました20。
今回は2レシピしか登録しませんでしたが、3レシピ以上もコピペでどんどん増やせます。
ぜひ自分好みのレシピをたくさん登録してください。
└6. レシピを複数登録する終わり
要点まとめ
成果品の個数を変更する
成果品を別アイテムにする
成果品設定の行のItems.
の直後を書き換えます。
書ける候補はItems.
の直後にキャレット(≒マウスカーソル)がある状態でCtrl+Space
を押すことで表示できます。
材料も別アイテムにする
材料の種類数を変更する
ingredients.add(Ingredient.fromItem(Items.ここはアイテムによって変える));
の行を材料の数だけ書きます。
ブロックもクラフトに含む
材料や製作品を設定する部分のItems.なんたら
の代わりに、
Item.getItemFromBlock(Blocks.DIAMOND_BLOCK)
を書きます。
レシピを複数登録する
レシピ追加コードを全体丸ごとコピペして増やします。
ただし、レシピ名はユニーク(=一意=重複しない)になるように設定します。
└要点まとめ終わり
4. 定形レシピもコピペして動かす
定形レシピもコピペで簡単に追加できます。
以下のコードをコピーしましょう。
{
//--------------------定形レシピの追加--------------------
// クラフト材料の設定
// 3×3のクラフトグリッドのどの位置にアイテムを置くかを番号で示す
// 0 1 2
// 3 4 5
// 6 7 8
int width = 3;
int height = 3;
NonNullList<Ingredient> ingredients = NonNullList.withSize(width * height, Ingredient.EMPTY);
ingredients.set(1, Ingredient.fromItem(Items.DIAMOND)); // ダイアモンド
ingredients.set(3, Ingredient.fromItem(Items.IRON_INGOT)); // 鉄インゴット
ingredients.set(4, Ingredient.fromItem(Items.ENDER_PEARL)); // エンダーパール
ingredients.set(5, Ingredient.fromItem(Items.GOLD_INGOT)); // 金インゴット
ingredients.set(7, Ingredient.fromItem(Items.EMERALD)); // エメラルド
// クラフト成果品の設定
ItemStack output = new ItemStack(Items.GHAST_TEAR, 4); // ガストの涙×4
// レシピの作成
ShapedRecipes recipe = new ShapedRecipes("", width, height, ingredients, output); // groupとクラフトグリッドの幅と高さと材料と成果品からレシピ作成
// レシピの登録
recipe.setRegistryName(new ResourceLocation(Tags.MODID, "craft_ghast_tear")); // 登録時の内部レシピ名指定
event.getRegistry().register(recipe); // 登録
}
マイクラを起動して見てみます。
レシピが登録されていますね。
定形レシピ追加のコードについての詳細な解説はここでは行いません。
自分なりにアレンジを加えてみると良いでしょう。
この程度の変更ではPCやゲーム、データ等は壊れません。
そんな危ないこと好き勝手やらせるわけない
2×2定形レシピの例
{
//--------------------定形レシピの追加--------------------
// クラフト材料の設定
// 2×2のクラフトグリッドのどの位置にアイテムを置くかを番号で示す
// 0 1
// 2 3
int width = 2;
int height = 2;
NonNullList<Ingredient> ingredients = NonNullList.withSize(width * height, Ingredient.EMPTY);
ingredients.set(0, Ingredient.fromItem(Item.getItemFromBlock(Blocks.COAL_BLOCK))); // 石炭ブロック
ingredients.set(2, Ingredient.fromItem(Items.STICK)); // 棒
// クラフト成果品の設定
ItemStack output = new ItemStack(Item.getItemFromBlock(Blocks.TORCH), 40); // 松明×40
// レシピの作成
ShapedRecipes recipe = new ShapedRecipes("", width, height, ingredients, output); // groupとクラフトグリッドの幅と高さと材料と成果品からレシピ作成
// レシピの登録
recipe.setRegistryName(new ResourceLocation(Tags.MODID, "torch_from_coal_block_and_stick")); // 登録時の内部レシピ名指定
event.getRegistry().register(recipe); // 登録
}
└2×2定形レシピの例終わり
5. 終わりに
初めてのModdingとプログラミングを体験していただきましたが、どうだったでしょうか。
プログラミングもModdingも「全てを理解しないとうまく動かせない」わけではありません。
何となく分かる部分をたくさんいじりながら、少しずつ分かる範囲を広げていってあげれば良いです。
自分のペースで頑張ってください。
Webページは逃げませんし、追い立てても来ません。
もっと簡潔なレシピ追加
実は、不定形レシピ21を登録するだけなら1行で済みます。
GameRegistry.addShapelessRecipe(new ResourceLocation(Tags.MODID, "apple_plus_gold_ingot"), null, new ItemStack(Items.GOLDEN_APPLE, 2), Ingredient.fromItem(Items.APPLE), Ingredient.fromItem(Items.GOLD_INGOT));
レシピの登録方法が何となく分かってきた今でこそある程度このコードの意図を理解できますが、このコードが突然1行だけ出てきて「学んでください」と言われても難しいでしょう22。
└もっと簡潔なレシピ追加終わり
初心者研修編 - デバッグを実践するに続く
-
極めればリソースパックでは実現し得ないこともできる
例えばNBT付きの成果品やレシピの自動生成等 ↩ -
この折り畳まれている、色の変化した部分をクリックするだけでも展開できる ↩
-
実はメソッド名は
registerRecipes
から変更しても動作する
31行目にある@SubscribeEvent
と引数のRegistryEvent.Register<IRecipe>
だけで正しいメソッドかどうかを判断してたりするからであるという非常にハイレベルな話
(え!?ジェネリクスの型は消去されるのにそれで大丈夫なんですか!?……なるほど、コンパイル時のメソッドの引数の型の型変数ならリフレクションで取ってこれるからそれでif挿んでるのか…とか言ってる玄人は呼んでません)↩ -
波かっことも呼ぶし、IT系ならそっちの方が多いかも ↩
-
大嘘だが、初心者にとってはこのくらい端的な方がありがたい
「↩#include
ってどういう意味なんですか?」 -
これはクラスをインポートしていないのが原因
初期設定ではコピペ時に自動でインポートを挿入してくれる…はず ↩ -
昔はsjisのダメ文字をコメントの最後に書くことで「(コメントは動作に影響を与えないはずなのに)このコメントが無いとなぜかプログラムがバグる!!」という事故が話題になったとかいう薀蓄は締め切らせていただきました ↩
-
記憶とは諸行無常である↩ -
英語圏で発明されたから仕方のないところ
日本語のプログラミング言語もあるが、結局PC上での日本語入力のしづらさもあって英語でええやん!となる
命名を英語にするかとかなんとかの議論はまた今度 ↩ -
グループと成果品と材料を引数にとってレシピのインスタンスが作成されているけど、そんなこと初心者に言われてもわからん
グループの説明は後で出てくる ↩ -
手元の2×2クラフトでも良いが、クリエイティブモードでは作業台の方が楽 ↩
-
メソッドの実引数にリテラルを与えた場合に、その仮引数の名前を表示してくれる機能 ↩
-
BackspaceやDeleteしても消えない・消せない
この部分をコピペしてもきれいさっぱり無かったことになる ↩ -
この部分はItemsクラスのstaticフィールドである ↩
-
ここでの正しい書き方とは、「Itemsクラスで」という条件が付く
つまり、別の場所ではまた違う書き方が正しい書き方となる ↩ -
マウスカーソルはマウスの位置であり、キャレットはテキストの入力位置(点滅する
|
)を指す ↩ -
普通、CtrlキーやShiftキーとの同時押しは、完全に同時というよりもCtrlやShiftのような特殊キーを先に押しっぱなしにしながら他のキーを押す ↩
-
この時点でエラーになりそうと思った方は賢い
特にどこがエラーになりそうかを言えたらそれはもう初心者ではない ↩ -
厳密にはそれの頭にModIDを付けたもの
ModIDが付いているので同名のレシピが複数Modで登録されても大丈夫 ↩ -
じゃあ別Modのレシピやバニラのレシピも上書きできるのか!?と思ったなら実際に試してみなさい
うまくやれば多分できるんじゃないかな
ただ実際のModdingでレシピを置き換えたいなと思ったときは、レシピの上書きよりも削除+追加をやる方がオーソドックス ↩ -
定形レシピなら
GameRegistry.addShapedRecipe
を使う(材料の指定方法に注意) ↩ -
1行で書く場合、引数の順番と可変長な引数の説明も同時に行う必要がある上にコメントが書きづらいので説明には不向き
ローカル変数を使えば解決するが、配列のnew時の要素数指定の説明が必要になるのでやっぱり向かない ↩