概要
ソースコード
残念!ソースコードの追加実装などいらないのだよ!!
あくまでも前のチュートリアルまで実装できていればだが、レシピの実装はjson側で行うため追加コードは必要ない。
アセット
- aluminium_block.json[recipe]
src/main/resources/assets/aluminiummod/recipes/に配置する
{
"type": "minecraft:crafting_shaped",
"pattern": [
"###",
"###",
"###"
],
"key": {
"#": {
"item": "aluminiummod:aluminium"
}
},
"result": {
"item": "aluminiummod:aluminium_block"
}
}
{
"type": "minecraft:crafting_shapeless",
"ingredients": [
{
"item": "aluminiummod:aluminium_block"
}
],
"result": {
"item": "aluminiummod:aluminium",
"count":9
}
}
解説
MC1.12より、今までのレシピの登録方法が非推奨となり、代わりにjson形式でレシピを登録することになった。
その為、バニラにレシピを追加するだけの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を下のように変更すれば良い。
+
|
... |
"key": {
"#": {
"item": "aluminiummod:aluminium"
},
"A": {
"item": "minecraft:skull",
"data": 4
},
"ingredients": [
{
"item": "aluminiummod:aluminium_block"
},
{
"item": "minecraft:skull",
"data": 4
],
|
レシピ追加通知
MC1.12からの新機能として、「レシピブック」がある。
また、バニラのアイテムは入手したとき右上に「新規レシピ追加」という通知が出る。
今回はアイテムを大量に追加するMOD用に「レシピブック」とイベントを使って通知を出す。
(進捗のシステムを使ってレシピを出すことも出来るが、書くべきjsonファイル数が多くなる。そのやり方は進捗の追加チュートリアルで記載予定。)
+
|
... |
AluminiumMod.java
クラス末尾に追加する。
@Mod.Instance("aluminiummod")
public static AluminiumMod aluminiumInstance;
@Mod.EventHandler
public void init(FMLInitializationEvent event) {
HOLDER.register();
}
//アイテムを拾ったときのイベント。
@SubscribeEvent
public void onPickupItem(EntityItemPickupEvent event) {
this.aluminiumUnlockRecipes(event.getItem().getItem(), event.getEntityPlayer());
}
//コンテナを閉じたとき(チェストやプレイヤーインベントリなど)のイベント。
@SubscribeEvent
public void onCloseContainer(PlayerContainerEvent.Close event) {
for (ItemStack itemStack : event.getEntityPlayer().inventoryContainer.getInventory()) {
this.aluminiumUnlockRecipes(itemStack, 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 (!this.HOLDER.map.isEmpty() && this.HOLDER.map.containsKey(itemStack)) {
List<ResourceLocation> list = this.HOLDER.map.get(itemStack);
//player.unlockRecipes(ResourceLocation[] locations)でレシピブックに追加する。
player.unlockRecipes(list.toArray(new ResourceLocation[list.size()]));
}
}
}
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<ItemStack, List<ResourceLocation>> map = new ItemStackHashMap();
public void register() {
if (FMLCommonHandler.instance().getSide().isClient()) {
//assets/<modid>/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<JarEntry> 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 = null;
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<File> list = this.getListFile(path);
if (list.size() > 0) {
for (File recipe : list) {
InputStream stream = null;
try {
stream = new FileInputStream(recipe);
this.readStream(stream, recipe.getName());
stream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
//ファイルを全て取得する。これもjarか否かによって変わる。
private List<File> getListFile(String path) {
List<File> 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<JarEntry> 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;
}
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<ResourceLocation> locations = map.containsKey(stack) ? map.get(stack) : new ArrayList<ResourceLocation>();
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<ResourceLocation> locations = map.containsKey(stack) ? map.get(stack) : new ArrayList<ResourceLocation>();
locations.add(location);
map.put(stack, locations);
}
}
//ItemStackを使ったマップを定義する。
public static class ItemStackHashMap<K extends ItemStack, V extends List<ResourceLocation>> extends HashMap<K, V> {
public V get(Object key) {
if (key instanceof ItemStack && this.containsKey(key)) {
for (Map.Entry<K, V> 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;
}
}
}
|
コメント
この項目に関する質問などをどうぞ。
最終更新:2017年08月13日 23:30