目次
概要
レシピを追加する。
前のチュートリアルまでと同様の部分は割愛する。
ソースコード
残念!ソースコードの実装などいらないのだよ!!
あくまでも前のチュートリアルまで実装できていればだが、レシピの実装はjson側で行うため追加コードは必要ない。
アセット
aluminium.json
{
"type": "minecraft:crafting_shapeless",
"ingredients": [
{
"item": "aluminiummod:aluminium_block"
}
],
"result": {
"item": "aluminiummod:aluminium",
"count": 9
}
}
aluminium_block.json
{
"type": "minecraft:crafting_shaped",
"pattern": [
"###",
"###",
"###"
],
"key": {
"#": {
"item": "aluminiummod:aluminium"
}
},
"result": {
"item": "aluminiummod:aluminium_block"
}
}
解説
MC1.12より、今までのレシピの登録方法が非推奨となり、代わりにjson形式でレシピを登録することになった。
その為、バニラにレシピを追加するだけのMODなら 最悪@Modをつけたクラスを作成するだけでjavaに触れるのは終わる。
その為、バニラにレシピを追加するだけのMODなら 最悪@Modをつけたクラスを作成するだけでjavaに触れるのは終わる。
名称はそのままforge側に登録され、/recipeコマンドで使われるため作られるアイテムのレジスター名にするのが最適である。
まず、type要素でクラフトタイプを指定する。"minecraft:crafting_shaped"で定形レシピ、minecraft:crafting_shapelessで不定形レシピを指定する。
次に、定形レシピではpatternでレシピの形を指定し、その文字に当てはまるアイテムをkeyで指定する。
不定形レシピではingredientsで指定する。
最後に、resultで結果を登録する。
それぞれ : で区切ってある前がMapのkey、後ろがvalueであると考えれば良い。
item要素で<modid>:<レジスター名>、count要素で個数、data要素でメタデータ(アイテムなのでblockstateは登録できない)を指定する。
アイテムの種類を増やしたいときはkey若しくはingredientsを下のように変更すれば良い。
まず、type要素でクラフトタイプを指定する。"minecraft:crafting_shaped"で定形レシピ、minecraft:crafting_shapelessで不定形レシピを指定する。
次に、定形レシピではpatternでレシピの形を指定し、その文字に当てはまるアイテムをkeyで指定する。
不定形レシピではingredientsで指定する。
最後に、resultで結果を登録する。
それぞれ : で区切ってある前がMapのkey、後ろがvalueであると考えれば良い。
item要素で<modid>:<レジスター名>、count要素で個数、data要素でメタデータ(アイテムなのでblockstateは登録できない)を指定する。
アイテムの種類を増やしたいときはkey若しくはingredientsを下のように変更すれば良い。
定形・不定形レシピ
- 定形
"key": { "#": { "item": "aluminiummod:aluminium" }, "A": { "item": "minecraft:skull", "data": 4 },
- 不定形
"ingredients": [ { "item": "aluminiummod:aluminium_block" }, { "item": "minecraft:skull", "data": 4 ],
レシピ追加通知
MC1.12からの新機能として、「レシピブック」がある。
また、バニラのアイテムは入手したとき右上に「新規レシピ追加」という通知が出る。
今回はアイテムを大量に追加するMOD用に「レシピブック」とイベントを使って通知を出す。
(進捗のシステムを使ってレシピを出すことも出来るが、書くべきjsonファイル数が多くなる。そのやり方は進捗の追加チュートリアルで記載予定。)
また、バニラのアイテムは入手したとき右上に「新規レシピ追加」という通知が出る。
今回はアイテムを大量に追加するMOD用に「レシピブック」とイベントを使って通知を出す。
(進捗のシステムを使ってレシピを出すことも出来るが、書くべきjsonファイル数が多くなる。そのやり方は進捗の追加チュートリアルで記載予定。)
追加チュートリアル
AluminiumMod.java
package com.tntmodders.tutorial;
import net.minecraft.block.Block;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.event.entity.player.EntityItemPickupEvent;
import net.minecraftforge.event.entity.player.PlayerContainerEvent;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLConstructionEvent;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import java.util.List;
@Mod(modid = "aluminiummod", version = "1.0", name = "AluminiumMod")
public class AluminiumMod {
public static final Item ALUMINIUM = new ItemAluminium();
public static final Block ALUMINIUM_BLOCK = new BlockAluminium();
private static final AluminiumRecipeHolder HOLDER = new AluminiumRecipeHolder();
@Mod.Instance("aluminiummod")
public static AluminiumMod aluminiumInstance;
@Mod.EventHandler
//この関数でMODファイル自体をイベントの発火先にする。
public void construct(FMLConstructionEvent event) {
MinecraftForge.EVENT_BUS.register(this);
}
//アイテムを登録するイベント。 旧preinitのタイミングで発火する。
@SubscribeEvent
public void registerItems(RegistryEvent.Register- event) {
event.getRegistry().register(ALUMINIUM);
event.getRegistry().register(new ItemBlock(ALUMINIUM_BLOCK).setRegistryName("aluminiummod", "aluminium_block"));
}
//ブロックを登録するイベント。 旧preinitのタイミングで発火する。
@SubscribeEvent
public void registerBlocks(RegistryEvent.Register
event) {
event.getRegistry().register(ALUMINIUM_BLOCK);
}
//モデルを登録するイベント。SideOnlyによってクライアント側のみ呼ばれる。旧preinitのタイミングで発火する。
@SubscribeEvent
@SideOnly(Side.CLIENT)
public void registerModels(ModelRegistryEvent event) {
ModelLoader.setCustomModelResourceLocation(ALUMINIUM, 0, new ModelResourceLocation(new ResourceLocation("aluminiummod", "aluminium"), "inventory"));
ModelLoader.setCustomModelResourceLocation(Item.getItemFromBlock(ALUMINIUM_BLOCK), 0, new ModelResourceLocation(new ResourceLocation("aluminiummod", "aluminium_block"), "inventory"));
}
@Mod.EventHandler
public void init(FMLInitializationEvent event) {
HOLDER.register();
}
//アイテムを拾ったときのイベント。
@SubscribeEvent
public void onPickupItem(EntityItemPickupEvent event) {
this.aluminiumUnlockRecipes(event.getItem().getItem(), event.getEntityPlayer());
}
private void aluminiumUnlockRecipes(ItemStack stack, EntityPlayer player) {
if (FMLCommonHandler.instance().getSide().isClient()) {
Item item = stack.getItem();
int meta = stack.getMetadata();
ItemStack itemStack = new ItemStack(item, 1, meta);
//もしレシピを保持するリストに合致すれば
if (!AluminiumRecipeHolder.map.isEmpty() && AluminiumRecipeHolder.map.containsKey(itemStack)) {
List list = AluminiumRecipeHolder.map.get(itemStack);
//player.unlockRecipes(ResourceLocation[] locations)でレシピブックに追加する。
player.unlockRecipes(list.toArray(new ResourceLocation[list.size()]));
}
}
}
//コンテナを閉じたとき(チェストやプレイヤーインベントリなど)のイベント。
@SubscribeEvent
public void onCloseContainer(PlayerContainerEvent.Close event) {
for (ItemStack itemStack : event.getEntityPlayer().inventoryContainer.getInventory()) {
this.aluminiumUnlockRecipes(itemStack, event.getEntityPlayer());
}
}
}
AluminiumRecipeHolder.java
package com.tntmodders.tutorial;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.stream.JsonReader;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.common.FMLCommonHandler;
import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class AluminiumRecipeHolder {
//ItemStackよりそのアイテムが鍵となるレシピを取得できるようにする。
public static final Map> map = new ItemStackHashMap();
public void register() {
if (FMLCommonHandler.instance().getSide().isClient()) {
//assets//recipes/よりリソースを取得する。
this.getResource("assets/aluminiummod/recipes/");
}
}
public void getResource(String path) {
ClassLoader loader = AluminiumMod.class.getClassLoader();
URL url = loader.getResource(path);
//jarファイル内か否かで処理が変化する。
if (url.getProtocol().equals("jar")) {
String[] strings = url.getPath().split(":");
String leadPath = strings[strings.length - 1].split("!")[0];
File f = new File(leadPath);
JarFile jarFile;
try {
//jarファイル自体を取得する。(zipファイル・jarファイルとして扱う事ができる。)
jarFile = new JarFile(f);
Enumeration enumeration = jarFile.entries();
while (enumeration.hasMoreElements()) {
JarEntry entry = enumeration.nextElement();
String s = entry.getName();
if (s != null && s.startsWith(path) && s.endsWith(".json")) {
InputStream stream;
try {
stream = loader.getResourceAsStream(s);
//inputstreamを使ってjarファイル内のjsonを読み込む。
this.readStream(stream, s);
stream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
} else {
List list = this.getListFile(path);
if (list.size() > 0) {
for (File recipe : list) {
InputStream stream;
try {
stream = new FileInputStream(recipe);
this.readStream(stream, recipe.getName());
stream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
private void readStream(InputStream stream, String name) {
//inputstreamよりJSONを読み込む。
JsonReader reader = new JsonReader(new InputStreamReader(stream));
JsonObject jsonObject = new Gson().fromJson(reader, JsonObject.class);
//文字列の中にパスが紛れ込んだ場合それを消す。また、".json"を抜いてResourceLocationとして保存する。
ResourceLocation location = new ResourceLocation("aluminiummod", name.replaceAll("assets/aluminiummod/recipes/", "")
.replaceAll(".json", ""));
//定形レシピでキーを"#"にしたアイテムを鍵とする。
if (jsonObject.has("key") && jsonObject.getAsJsonObject("key").has("#")) {
Item item = Item.getByNameOrId(jsonObject.getAsJsonObject("key").getAsJsonObject("#").get("item").getAsString());
int i = 0;
if (jsonObject.getAsJsonObject("key").getAsJsonObject("#").has("data")) {
i = jsonObject.getAsJsonObject("key").getAsJsonObject("#").get("data").getAsInt();
}
ItemStack stack = new ItemStack(item, 1, i);
List locations = map.containsKey(stack) ? map.get(stack) : new ArrayList<>();
locations.add(location);
map.put(stack, locations);
}
//不定形レシピで一番上に書いたアイテムを鍵とする。
else if (jsonObject.has("ingredients") && jsonObject.getAsJsonArray("ingredients").get(0).getAsJsonObject().has("item")) {
String s = jsonObject.getAsJsonArray("ingredients").get(0).getAsJsonObject().get("item").getAsString();
Item item = Item.getByNameOrId(s);
int i = 0;
if (jsonObject.getAsJsonArray("ingredients").get(0).getAsJsonObject().has("data")) {
i = jsonObject.getAsJsonArray("ingredients").get(0).getAsJsonObject().get("data").getAsInt();
}
ItemStack stack = new ItemStack(item, 1, i);
List locations = map.containsKey(stack) ? map.get(stack) : new ArrayList<>();
locations.add(location);
map.put(stack, locations);
}
}
//ファイルを全て取得する。これもjarか否かによって変わる。
private List getListFile(String path) {
List files = new ArrayList<>();
ClassLoader loader = AluminiumMod.class.getClassLoader();
URL url = loader.getResource(path);
if (url.getProtocol().equals("jar")) {
String[] strings = url.getPath().split(":");
String leadPath = strings[strings.length - 1].split("!")[0];
File f = new File(leadPath);
JarFile jarFile;
try {
jarFile = new JarFile(f);
Enumeration enumeration = jarFile.entries();
while (enumeration.hasMoreElements()) {
JarEntry entry = enumeration.nextElement();
String s = entry.getName();
if (s != null && s.startsWith(path) && s.endsWith(".json")) {
files.add(new File(loader.getResource(s).getPath()));
}
}
} catch (IOException e) {
e.printStackTrace();
}
} else {
File packFile = FMLCommonHandler.instance().findContainerFor(AluminiumMod.aluminiumInstance).getSource();
File newFile = new File(packFile.toURI().getPath() + path);
files = Arrays.asList(newFile.listFiles());
}
return files;
}
//ItemStackを使ったマップを定義する。
public static class ItemStackHashMap> extends HashMap {
@Override
public V get(Object key) {
if (key instanceof ItemStack && this.containsKey(key)) {
for (Map.Entry entry : this.entrySet()) {
if (entry.getKey().getItem() == ((ItemStack) key).getItem() && entry.getKey().getMetadata() == ((ItemStack) key).getMetadata()) {
return entry.getValue();
}
}
}
return null;
}
@Override
public boolean containsKey(Object key) {
if (key instanceof ItemStack) {
ItemStack itemStack = (ItemStack) key;
for (ItemStack stack : this.keySet()) {
if (stack.getItem() == itemStack.getItem() && stack.getMetadata() == itemStack.getMetadata()) {
return true;
}
}
}
return false;
}
}
}
このページの閲覧数: 5,682