JSONの利用

概要

Forge式記法の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.minecraft.world.storage.loot.LootTableList;
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", updateJSON =
        "https://raw.githubusercontent.com/TNTModders/aluminiummod/master/version/aluminiumVersionCheck" + ".json")
public class AluminiumMod {
    public static final Item ALUMINIUM = new ItemAluminium();
    public static final Block ALUMINIUM_BLOCK = new BlockAluminium();
    public static final Item ALUMINIUM_ROD = new ItemAluminiumRod();
    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);
        LootTableList.register(new ResourceLocation("aluminiummod:chests/aluminium_chest"));
        LootTableList.register(new ResourceLocation("aluminiummod:entities/aluminium_get"));
    }

    //アイテムを登録するイベント。 旧preinitのタイミングで発火する。
    @SubscribeEvent
    public void registerItems(RegistryEvent.Register event) {
        event.getRegistry().register(ALUMINIUM);
        event.getRegistry().register(ALUMINIUM_ROD);
        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"));
        ModelLoader.setCustomModelResourceLocation(ALUMINIUM_ROD, 0,
                new ModelResourceLocation(new ResourceLocation("aluminiummod", "aluminium_rod"), "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());
        }
    }
}

ItemAluminiumRod.java

package com.tntmodders.tutorial;

import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.tileentity.TileEntityChest;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;

public class ItemAluminiumRod extends Item {

    public ItemAluminiumRod() {
        super();
        //レジストリに保存する名称を登録する。大文字禁止。
        this.setRegistryName("aluminiummod", "aluminium_rod");
        //クリエイティブタブを設定する。
        this.setCreativeTab(CreativeTabs.MATERIALS);
        //翻訳名を登録する。大文字非推奨。
        this.setUnlocalizedName("aluminium_rod");
    }

    @Override
    public EnumActionResult onItemUse(EntityPlayer player, World worldIn, BlockPos pos, EnumHand hand,
            EnumFacing facing, float hitX, float hitY, float hitZ) {
        worldIn.setBlockState(pos.offset(facing), Blocks.CHEST.getDefaultState());
        if (worldIn.getTileEntity(pos.offset(facing)) instanceof TileEntityChest) {
            ((TileEntityChest) worldIn.getTileEntity(pos.offset(facing))).setLootTable(
                    new ResourceLocation("aluminiummod:chests/aluminium_chest"), player.getRNG().nextLong());
        }
        return super.onItemUse(player, worldIn, pos, hand, facing, hitX, hitY, hitZ);
    }
}

アセット

長いので格納

進捗

root.json

{
  "display": {
    "icon": {
      "item": "aluminiummod:aluminium_block"
    },
    "title": {
      "translate": "advancements.aluminiummod.root.title"
    },
    "description": {
      "translate": "advancements.aluminiummod.root.desc"
    },
    "background": "aluminiummod:textures/blocks/aluminium_block.png",
    "show_toast": false,
    "announce_to_chat": false
  },
  "criteria": {
    "tick": {
      "trigger": "minecraft:tick"
    }
  }
}

get_aluminium.json

{
  "display": {
    "icon": {
      "item": "aluminiummod:aluminium"
    },
    "title": {
      "translate": "advancements.aluminiummod.get.title"
    },
    "description": {
      "translate": "advancements.aluminiummod.get.desc"
    }
  },
  "parent": "aluminiummod:root",
  "rewards": {
    "loot": [
      "aluminiummod:entities/aluminium_get"
    ],
    "experience": 500
  },
  "criteria": {
    "get_aluminium": {
      "trigger": "minecraft:inventory_changed",
      "conditions": {
        "items": [
          {
            "item": "aluminiummod:aluminium"
          }
        ]
      }
    },
    "get_aluminium_block": {
      "trigger": "minecraft:inventory_changed",
      "conditions": {
        "items": [
          {
            "item": "aluminiummod:aluminium_block"
          }
        ]
      }
    }
  },
  "requirements": [
    [
      "get_aluminium",
      "get_aluminium_block"
    ]
  ]
}

ルートテーブル

aluminium_chest.json

{
  "pools": [
    {
      "name": "aluminiummod:aluminium_chest",
      "rolls": {
        "min": 4,
        "max": 10
      },
      "entries": [
        {
          "type": "item",
          "name": "minecraft:diamond",
          "weight": 5,
          "functions": [
            {
              "function": "set_count",
              "count": {
                "min": 2,
                "max": 7
              }
            }
          ]
        },
        {
          "type": "item",
          "name": "minecraft:iron_ingot",
          "weight": 10,
          "functions": [
            {
              "function": "set_count",
              "count": {
                "min": 6,
                "max": 15
              }
            }
          ]
        },
        {
          "type": "item",
          "name": "minecraft:gold_ingot",
          "weight": 15,
          "functions": [
            {
              "function": "set_count",
              "count": {
                "min": 2,
                "max": 7
              }
            }
          ]
        },
        {
          "type": "item",
          "name": "minecraft:emerald",
          "weight": 10,
          "functions": [
            {
              "function": "set_count",
              "count": {
                "min": 2,
                "max": 6
              }
            }
          ]
        },
        {
          "type": "item",
          "name": "minecraft:diamond_sword",
          "weight": 3,
          "functions": [
            {
              "function": "enchant_with_levels",
              "treasure": true,
              "levels": {
                "min": 30,
                "max": 59
              }
            }
          ]
        },
        {
          "type": "item",
          "name": "minecraft:diamond_boots",
          "weight": 3,
          "functions": [
            {
              "function": "enchant_with_levels",
              "treasure": true,
              "levels": {
                "min": 30,
                "max": 59
              }
            }
          ]
        },
        {
          "type": "item",
          "name": "minecraft:diamond_chestplate",
          "weight": 3,
          "functions": [
            {
              "function": "enchant_with_levels",
              "treasure": true,
              "levels": {
                "min": 30,
                "max": 59
              }
            }
          ]
        },
        {
          "type": "item",
          "name": "minecraft:diamond_leggings",
          "weight": 3,
          "functions": [
            {
              "function": "enchant_with_levels",
              "treasure": true,
              "levels": {
                "min": 30,
                "max": 59
              }
            }
          ]
        },
        {
          "type": "item",
          "name": "minecraft:diamond_helmet",
          "weight": 3,
          "functions": [
            {
              "function": "enchant_with_levels",
              "treasure": true,
              "levels": {
                "min": 30,
                "max": 59
              }
            }
          ]
        },
        {
          "type": "item",
          "name": "minecraft:diamond_pickaxe",
          "weight": 3,
          "functions": [
            {
              "function": "enchant_with_levels",
              "treasure": true,
              "levels": {
                "min": 30,
                "max": 59
              }
            }
          ]
        },
        {
          "type": "item",
          "name": "minecraft:diamond_shovel",
          "weight": 3,
          "functions": [
            {
              "function": "enchant_with_levels",
              "treasure": true,
              "levels": {
                "min": 30,
                "max": 59
              }
            }
          ]
        },
        {
          "type": "item",
          "name": "minecraft:iron_sword",
          "weight": 3,
          "functions": [
            {
              "function": "enchant_with_levels",
              "treasure": true,
              "levels": {
                "min": 30,
                "max": 59
              }
            }
          ]
        },
        {
          "type": "item",
          "name": "minecraft:iron_boots",
          "weight": 3,
          "functions": [
            {
              "function": "enchant_with_levels",
              "treasure": true,
              "levels": {
                "min": 30,
                "max": 59
              }
            }
          ]
        },
        {
          "type": "item",
          "name": "minecraft:iron_chestplate",
          "weight": 3,
          "functions": [
            {
              "function": "enchant_with_levels",
              "treasure": true,
              "levels": {
                "min": 30,
                "max": 59
              }
            }
          ]
        },
        {
          "type": "item",
          "name": "minecraft:iron_leggings",
          "weight": 3,
          "functions": [
            {
              "function": "enchant_with_levels",
              "treasure": true,
              "levels": {
                "min": 30,
                "max": 59
              }
            }
          ]
        },
        {
          "type": "item",
          "name": "minecraft:iron_helmet",
          "weight": 3,
          "functions": [
            {
              "function": "enchant_with_levels",
              "treasure": true,
              "levels": {
                "min": 30,
                "max": 59
              }
            }
          ]
        },
        {
          "type": "item",
          "name": "minecraft:iron_pickaxe",
          "weight": 3,
          "functions": [
            {
              "function": "enchant_with_levels",
              "treasure": true,
              "levels": {
                "min": 30,
                "max": 59
              }
            }
          ]
        },
        {
          "type": "item",
          "name": "minecraft:iron_shovel",
          "weight": 3,
          "functions": [
            {
              "function": "enchant_with_levels",
              "treasure": true,
              "levels": {
                "min": 30,
                "max": 59
              }
            }
          ]
        }
      ]
    }
  ]
}

aluminium_get.json

{
  "pools": [
    {
      "name": "aluminiummod:aluminium_get",
      "rolls": {
        "min": 1,
        "max": 1
      },
      "entries": [
        {
          "type": "item",
          "name": "aluminiummod:aluminium",
          "weight": 1,
          "functions": [
            {
              "function": "set_count",
              "count": {
                "min": 1,
                "max": 10
              }
            }
          ]
        }
      ]
    }
  ]
}

解説

AluminiumMod.java

42行目

LootTableList.register(new ResourceLocation("aluminiummod:chests/aluminium_chest"));
ルートテーブルを登録する。assets/loot_tablesの下に入っているルートテーブルのファイルを参照する。

ItemAluminiumRod.java

32,33行目

 ((TileEntityChest) worldIn.getTileEntity(pos.offset(facing))).setLootTable(new ResourceLocation("aluminiummod:chests/aluminium_chest"), player.getRNG().nextLong());

void setLootTable(ResourceLocation, Long)

TileEntityの関数。対応するResourceLocationにあるルートテーブルを渡し、インベントリに格納する。
乱数は第二引数にlong型で渡す。
これにより、バニラと同様のシステムで宝物入りのチェストを生成できる。

進捗

構造はこちらを参照 Minecraft wiki
まず、進捗の最初を定義する。
こちらはroot.jsonという名称で登録することが推奨される。
root.jsonで定義された進捗が達成されると進捗GUIでのタブが開放される。
display/icon要素は進捗のアイコン、display/title,display/description要素でタイトルと解説(半角スペースで改行ができる)を登録する。
また、background要素で背景を指定する。(root.jsonのみ)
criteria要素は進捗解除の条件を指定するものであり、ORで解除する(どれか一つで進捗達成にする)のであれば、

"requirements": [
    [
      "get_aluminium",
      "get_aluminium_block"
    ]
  ]
のように複数のcriteriaで指定した要素をrequirements要素のリストに入れる。

進捗を達成したときにはレシピ、ルートテーブル、経験値を与えることができる。(バニラではルートテーブルは使われていない)
rewards要素内でルートテーブルを与える場合はloots(中に登録した名称)、経験値を与える場合はexperience(中に経験値量)を記載する。

ルートテーブル

name要素は名称、rolls要素はスタック数の最小最大値を指定し、entriesリストでアイテムを入れる。
アイテムはnameで名称、weightで確率、functionsでアイテム数の最小最大値を指定したり、エンチャントを追加したりできる。
enchant_with_levelsをfunctionに設定した場合、エンチャントレベルやトレジャーエンチャントを指定できる。
トレジャーエンチャントは消滅の呪いや束縛の呪いなどがあたる。
また、実際に使う機会は少ないがこういう使い方もできる。
(1.13実装予定のトライデントなどは使えるかも)


"functions": [
            {
              "function": "enchant_with_levels",
              "treasure": true,
              "levels": {
                "min": 30,
                "max": 59
              }
            },
            {
              "function": "set_count",
              "count": {
                "min": 2,
                "max": 7
              }
            }
          ]