Minecraft Modding 1.12.2
Mod development of Minecraft is difficult to understand due to small differences not only in the large version but also in the small version. So I don't know if it will help the users who arrived at this article, but I hope it will be a hint.
If you want to check the source code directly, please refer to Github.
I am planning to create the following contents at any time.
--Proxy function --Adding items --Addition of food --Addition of fish --Addition of crops --Addition of creative tab
I myself am still studying, so if you find any mistakes in the explanation, please comment.
Please build the development environment by referring to here.
Create a jp / artan / tm
directory in the src / main / java
directory and create a `TutorialMod.java'in it.
src/main/java/jp/artan/tm/TutorialMod.java
package jp.artan.tm;
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.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import org.apache.logging.log4j.Logger;
@Mod(modid = TutorialMod.MODID, name = TutorialMod.NAME, version = TutorialMod.VERSION)
public class TutorialMod
{
public static final String MODID = "tm";
public static final String NAME = "Tutorial Mod";
public static final String VERSION = "1.0";
public static Logger logger;
@Mod.EventHandler
public void construct(FMLConstructionEvent event) {
}
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
logger = event.getModLog();
logger.info("TutorialMod.preInit");
}
@Mod.EventHandler
public void init(FMLInitializationEvent event) {
logger.info("TutorialMod.init");
}
@Mod.EventHandler
public void postInit(FMLPostInitializationEvent event) {
logger.info("TutorialMod.postInit");
}
}
All java files to be created from now on will be explained based on src / main / java / jp / artan / tm
.
In addition, png data such as textures and json data will be explained based on src / main / assets / tm
.
Proxy is a mechanism to determine whether the mod is called the client / server and automatically call the appropriate event. The reason why this mechanism is necessary is that the Model information required for the items explained below should not be executed on the server.
Now, create the following file.
proxy/CommonProxy.java
package jp.artan.tm.proxy;
import jp.artan.tm.TutorialMod;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
@Mod.EventBusSubscriber(modid = TutorialMod.MODID)
public abstract class CommonProxy {
public void preInit(FMLPreInitializationEvent event) {
TutorialMod.logger.info("CommonProxy.preInit");
}
public void init(FMLInitializationEvent event) {
TutorialMod.logger.info("CommonProxy.init");
}
public void postInit(FMLPostInitializationEvent event) {
TutorialMod.logger.info("CommonProxy.postInit");
}
}
proxy/ClientProxy.java
package jp.artan.tm.proxy;
import jp.artan.tm.TutorialMod;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
public class ClientProxy extends CommonProxy {
@Override
public void preInit(FMLPreInitializationEvent event) {
super.preInit(event);
TutorialMod.logger.info("ClientProxy.preInit");
}
}
proxy/ServerProxy.java
package jp.artan.tm.proxy;
public class ServerProxy extends CommonProxy {
//I will not explain the server this time, so I will not describe anything
//Create and use preinit etc. as needed.
}
Describe the common processing for the client / server in CommonProxy
, and describe the processing to be performed only by each in ClientProxy
and ServerProxy
.
Then, ClientProxy
andServerProxy'are automatically selected, and the process for calling them is described in
TutorialMod.java`.
The place where it is written as an additional note in the comment is the one added this time.
TutorialMod.java
package jp.artan.tm;
import jp.artan.tm.proxy.CommonProxy;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.FMLConstructionEvent;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import org.apache.logging.log4j.Logger;
@Mod(modid = TutorialMod.MODID, name = TutorialMod.NAME, version = TutorialMod.VERSION)
public class TutorialMod
{
public static final String MODID = "tm";
public static final String NAME = "Tutorial Mod";
public static final String VERSION = "1.0";
public static Logger logger;
public static final String CLIENT_PROXY = "jp.artan." + MODID + ".proxy.ClientProxy"; //Postscript
public static final String SERVER_PROXY = "jp.artan." + MODID + ".proxy.ServerProxy"; //Postscript
@SidedProxy(clientSide = CLIENT_PROXY, serverSide = SERVER_PROXY) //Postscript
public static CommonProxy proxy; //Postscript
@Mod.EventHandler
public void construct(FMLConstructionEvent event) {
MinecraftForge.EVENT_BUS.register(proxy); //Postscript
}
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
logger = event.getModLog();
logger.info("TutorialMod.preInit");
proxy.preInit(event); //Postscript
}
@Mod.EventHandler
public void init(FMLInitializationEvent event) {
logger.info("TutorialMod.init");
proxy.init(event); //Postscript
}
@Mod.EventHandler
public void postInit(FMLPostInitializationEvent event) {
logger.info("TutorialMod.postInit");
proxy.postInit(event); //Postscript
}
}
I will explain by excerpting a part.
.java
public static final String CLIENT_PROXY = "jp.artan." + MODID + ".proxy.ClientProxy";
public static final String SERVER_PROXY = "jp.artan." + MODID + ".proxy.ServerProxy";
@SidedProxy(clientSide = CLIENT_PROXY, serverSide = SERVER_PROXY)
public static CommonProxy proxy;
The annotation SidedProxy
attached to the variable proxy
is important.
By specifying this annotation, an instance is automatically generated based on the specified file directory information of clientSide
and serverSide
and stored in a variable.
** * The path specified at this time will be the path based on src / main / java
**
If you start the client and server at this stage, you can see that each instance is automatically prepared.
runClient.log
[17:25:39] [Client thread/INFO] [tm]: TutorialMod.preInit
[17:25:39] [Client thread/INFO] [tm]: CommonProxy.preInit
[17:25:39] [Client thread/INFO] [tm]: ClientProxy.preInit
[17:25:44] [Client thread/INFO] [tm]: TutorialMod.init
[17:25:44] [Client thread/INFO] [tm]: CommonProxy.init
[17:25:44] [Client thread/INFO] [tm]: TutorialMod.postInit
[17:25:44] [Client thread/INFO] [tm]: CommonProxy.postInit
runServer.log
[17:33:43] [Server thread/INFO] [tm]: TutorialMod.preInit
[17:33:43] [Server thread/INFO] [tm]: CommonProxy.preInit
[17:33:43] [Server thread/INFO] [tm]: TutorialMod.init
[17:33:43] [Server thread/INFO] [tm]: CommonProxy.init
[17:33:44] [Server thread/INFO] [tm]: TutorialMod.postInit
[17:33:44] [Server thread/INFO] [tm]: CommonProxy.postInit
Next, I would like to implement an item that has no function. Before that, we will create a mechanism to register items in the geméRegistry and ModelLoder at once.
event/IItemRegisterEvent.java
package jp.artan.tm.event;
import net.minecraft.item.Item;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.event.RegistryEvent;
public interface IItemRegisterEvent {
/**
* Register Item
*
* @param event
*/
void registerItem(RegistryEvent.Register<Item> event);
/**
* Register Model
*
* @param event
*/
void registerModel(ModelRegistryEvent event);
}
init/ItemInit.java
package jp.artan.tm.init;
import jp.artan.tm.event.IItemRegisterEvent;
import java.util.ArrayList;
import java.util.List;
public class ItemInit {
public static final List<IItemRegisterEvent> ITEMS = new ArrayList<IItemRegisterEvent>();
}
proxy/CommonProxy.java
package jp.artan.tm.proxy;
import jp.artan.tm.TutorialMod;
import jp.artan.tm.init.ItemInit;
import net.minecraft.item.Item;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.fml.common.Mod;
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.eventhandler.SubscribeEvent;
@Mod.EventBusSubscriber(modid = TutorialMod.MODID)
public abstract class CommonProxy {
public void preInit(FMLPreInitializationEvent event) {
TutorialMod.logger.info("CommonProxy.preInit");
}
public void init(FMLInitializationEvent event) {
TutorialMod.logger.info("CommonProxy.init");
}
public void postInit(FMLPostInitializationEvent event) {
TutorialMod.logger.info("CommonProxy.postInit");
}
//Added below
@SubscribeEvent
public void registerItems(RegistryEvent.Register<Item> event) {
TutorialMod.logger.info("CommonProxy.registerItems");
ItemInit.ITEMS.forEach(f -> f.registerItem(event));
}
//Addition above
}
proxy/ClientProxy.java
package jp.artan.tm.proxy;
import jp.artan.tm.TutorialMod;
import jp.artan.tm.init.ItemInit;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
public class ClientProxy extends CommonProxy {
@Override
public void preInit(FMLPreInitializationEvent event) {
super.preInit(event);
TutorialMod.logger.info("ClientProxy.preInit");
}
//Added below
@SubscribeEvent
public void registerModels(ModelRegistryEvent event) {
TutorialMod.logger.info("ClientProxy.registerModels");
ItemInit.ITEMS.forEach(f -> f.registerModel(event));
}
//Addition above
}
Objects that inherit IItemRegisterEvent are collectively managed by ITEMS and registered one by one in geméRegistry and ModelLoder. ** * The registerModels event should be executed only on the client. ** **
Now, I would like to register the item for the main subject.
item/TutorialItem.java
package jp.artan.tm.item;
import jp.artan.tm.TutorialMod;
import jp.artan.tm.event.IItemRegisterEvent;
import jp.artan.tm.init.ItemInit;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.event.RegistryEvent;
public class TutorialItem extends Item implements IItemRegisterEvent {
private final String name;
public TutorialItem(String name) {
super();
this.name = name;
this.setUnlocalizedName(this.name);
this.setRegistryName(TutorialMod.MODID, this.name);
this.setCreativeTab(CreativeTabs.MISC);
ItemInit.ITEMS.add(this);
}
@Override
public void registerItem(RegistryEvent.Register<Item> event) {
event.getRegistry().register(this);
}
public void registerModel(ModelRegistryEvent event) {
ModelLoader.setCustomModelResourceLocation(this, 0,
new ModelResourceLocation(new ResourceLocation(TutorialMod.MODID, this.name), "inventory"));
}
}
After creating the TutorialItem, create an instance with ItemInit.
init/ItemInit.java
package jp.artan.tm.init;
import jp.artan.tm.event.IItemRegisterEvent;
import jp.artan.tm.item.TutorialItem;
import net.minecraft.item.Item;
import java.util.ArrayList;
import java.util.List;
public class ItemInit {
public static final List<IItemRegisterEvent> ITEMS = new ArrayList<IItemRegisterEvent>();
public static final Item TUTORIAL_ITEM = new TutorialItem("tutorial_item"); //Postscript
}
If you execute it with this, the item will be registered in the Other
tab as shown below.
As it is, it is difficult to read and the texture is not set, so it cannot be said that it is a very usable situation. So, let's set the texture and language.
This time, we are creating an instance like new TutorialItem ("tutorial_item ")
, so the item name is tutorial_item
.
models/item/tutorial_item.json
{
"parent": "item/generated",
"textures": {
"layer0": "tm:items/tutorial_item"
}
}
textures/items/tutorial_item.png [] ** * Please note that the image will not be read correctly unless it is 16 pixels x 16 pixels. ** **
lang/en_us.lang
# English Language File
# Items
item.tutorial_item.name=Tutorial Item
lang/ja_jp.lang
#Japanese language file
# Items
item.tutorial_item.name=Tutorial item
** * Depending on the version of Forge, ʻen_us.lang,
ja_jp.lang must be specified as ʻen_US.lang
, ja_JP.lang
. ** **
There is no problem if there is data as shown in the following image.
Items and blocks that I created are a certain group, and I would like to register them in the creative tab. This time I would like to create a tutorial tab.
I would like to set the item created above to the icon of the creative tab.
tab/TutorialTab.java
package jp.artan.tm.tab;
import jp.artan.tm.init.ItemInit;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.ItemStack;
public class TutorialTab extends CreativeTabs {
public TutorialTab() {
super("tutorial_tab");
}
@Override
public ItemStack getTabIconItem() {
return new ItemStack(ItemInit.TUTORIAL_ITEM);
}
}
Be sure to pass the string passed to the CreativeTabs constructor in lowercase letters. Also, the name specified here will be the character string used in the writing language setting.
lang/en_us.lang
# English Language File
# Tabs
itemGroup.tutorial_tab=Tutorial Tab
# Items
item.tutorial_item.name=Tutorial Item
lang/ja_jp.lang
#Japanese language file
# Tabs
itemGroup.tutorial_tab=Tutorial tab
# Items
item.tutorial_item.name=Tutorial item
TutorialMod.java
package jp.artan.tm;
import jp.artan.tm.proxy.CommonProxy;
import jp.artan.tm.tab.TutorialTab;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.FMLConstructionEvent;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import org.apache.logging.log4j.Logger;
@Mod(modid = TutorialMod.MODID, name = TutorialMod.NAME, version = TutorialMod.VERSION)
public class TutorialMod
{
public static final String MODID = "tm";
public static final String NAME = "Tutorial Mod";
public static final String VERSION = "1.0";
public static Logger logger;
public static final String CLIENT_PROXY = "jp.artan." + MODID + ".proxy.ClientProxy";
public static final String SERVER_PROXY = "jp.artan." + MODID + ".proxy.ServerProxy";
@SidedProxy(clientSide = CLIENT_PROXY, serverSide = SERVER_PROXY)
public static CommonProxy proxy;
public static CreativeTabs creativeTabs = new TutorialTab(); //Postscript
@Mod.EventHandler
public void construct(FMLConstructionEvent event) {
MinecraftForge.EVENT_BUS.register(proxy);
}
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
logger = event.getModLog();
logger.info("TutorialMod.preInit");
proxy.preInit(event);
}
@Mod.EventHandler
public void init(FMLInitializationEvent event) {
logger.info("TutorialMod.init");
proxy.init(event);
}
@Mod.EventHandler
public void postInit(FMLPostInitializationEvent event) {
logger.info("TutorialMod.postInit");
proxy.postInit(event);
}
}
Now that the creative tab has been created, change the registration destination of the item created above to the tab created from the Other
tab.
item/TutorialItem.java
package jp.artan.tm.item;
import jp.artan.tm.TutorialMod;
import jp.artan.tm.event.IItemRegisterEvent;
import jp.artan.tm.init.ItemInit;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.event.RegistryEvent;
public class TutorialItem extends Item implements IItemRegisterEvent {
private final String name;
public TutorialItem(String name) {
super();
this.name = name;
this.setUnlocalizedName(this.name);
this.setRegistryName(TutorialMod.MODID, this.name);
this.setCreativeTab(TutorialMod.creativeTabs); //Change
ItemInit.ITEMS.add(this);
}
@Override
public void registerItem(RegistryEvent.Register<Item> event) {
event.getRegistry().register(this);
}
public void registerModel(ModelRegistryEvent event) {
ModelLoader.setCustomModelResourceLocation(this, 0,
new ModelResourceLocation(new ResourceLocation(TutorialMod.MODID, this.name), "inventory"));
}
}
If it looks like the image below, it is successful.
I used to have a banana icon, but I couldn't eat it because the item I made earlier was a non-functional item. Next, I would like to add edible items. Also, for the texture of this item, I will use the texture of vanilla apple.
imte/TutorialFood.java
package jp.artan.tm.item;
import jp.artan.tm.TutorialMod;
import jp.artan.tm.event.IItemRegisterEvent;
import jp.artan.tm.init.ItemInit;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.item.Item;
import net.minecraft.item.ItemFood;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.event.RegistryEvent;
public class TutorialFood extends ItemFood implements IItemRegisterEvent {
private final String name;
public TutorialFood(String name, int amount, float saturation) {
super(amount, saturation, false);
this.name = name;
this.setUnlocalizedName(this.name);
this.setRegistryName(TutorialMod.MODID, this.name);
this.setCreativeTab(TutorialMod.creativeTabs);
ItemInit.ITEMS.add(this);
}
@Override
public void registerItem(RegistryEvent.Register<Item> event) {
event.getRegistry().register(this);
}
@Override
public void registerModel(ModelRegistryEvent event) {
ModelLoader.setCustomModelResourceLocation(this, 0,
new ModelResourceLocation(new ResourceLocation(TutorialMod.MODID, this.name), "inventory"));
}
}
The arguments of the ItemFood constructor are as follows. 1st argument amount The amount of recovery when eaten 2nd argument saturation Amount of recovery of hidden satiety when eaten 3rd argument isWolfFood Whether to make wolf food
init/ItemInit.java
package jp.artan.tm.init;
import jp.artan.tm.event.IItemRegisterEvent;
import jp.artan.tm.item.TutorialFood;
import jp.artan.tm.item.TutorialItem;
import net.minecraft.item.Item;
import java.util.ArrayList;
import java.util.List;
public class ItemInit {
public static final List<IItemRegisterEvent> ITEMS = new ArrayList<IItemRegisterEvent>();
public static final Item TUTORIAL_ITEM = new TutorialItem("tutorial_item");
public static final Item TUTORIAL_FOOD = new TutorialFood("tutorial_food", 1, 1.0F); //Postscript
}
lang/en_us.lang
# English Language File
# Tabs
itemGroup.tutorial_tab=Tutorial Tab
# Items
item.tutorial_item.name=Tutorial Item
item.tutorial_food.name=Tutorial Food
lang/ja_jp.lang
#Japanese language file
# Tabs
itemGroup.tutorial_tab=Tutorial tab
# Items
item.tutorial_item.name=Tutorial item
item.tutorial_food.name=Tutorial food
models/item/tutorial_food.json
{
"parent": "item/generated",
"textures": {
"layer0": "minecraft:items/apple"
}
}
If you execute it with this, it will be as follows.
Next, I would like to add crops in the field. You will need three items, a seed item, a crop item, and a crop block, to create a crop.
First, set up so that blocks can be registered in a batch in the same way as the item batch registration process.
event/IBlockRegisterEvent.java
package jp.artan.tm.event;
import net.minecraft.block.Block;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.event.RegistryEvent;
public interface IBlockRegisterEvent {
/**
* Register Block
*
* @param event
*/
void registerBlock(RegistryEvent.Register<Block> event);
/**
* Register Model
*
* @param event
*/
void registerModel(ModelRegistryEvent event);
}
init/BlockInit.java
package jp.artan.tm.init;
import jp.artan.tm.block.TutorialPlant;
import jp.artan.tm.event.IBlockRegisterEvent;
import net.minecraft.block.BlockCrops;
import java.util.ArrayList;
import java.util.List;
public class BlockInit {
public static final List<IBlockRegisterEvent> BLOCKS = new ArrayList<IBlockRegisterEvent>();
}
proxy/CommonProxy.java
package jp.artan.tm.proxy;
import jp.artan.tm.TutorialMod;
import jp.artan.tm.init.BlockInit;
import jp.artan.tm.init.ItemInit;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.fml.common.Mod;
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.eventhandler.SubscribeEvent;
@Mod.EventBusSubscriber(modid = TutorialMod.MODID)
public abstract class CommonProxy {
public void preInit(FMLPreInitializationEvent event) {
TutorialMod.logger.info("CommonProxy.preInit");
}
public void init(FMLInitializationEvent event) {
TutorialMod.logger.info("CommonProxy.init");
}
public void postInit(FMLPostInitializationEvent event) {
TutorialMod.logger.info("CommonProxy.postInit");
}
@SubscribeEvent
public void registerItems(RegistryEvent.Register<Item> event) {
TutorialMod.logger.info("CommonProxy.registerItems");
ItemInit.ITEMS.forEach(f -> f.registerItem(event));
}
@SubscribeEvent
public void registerBlocks(RegistryEvent.Register<Block> event) { //Postscript
TutorialMod.logger.info("CommonProxy.registerBlocks");
BlockInit.BLOCKS.forEach(f -> f.registerBlock(event));
}
}
proxy/ClientProxy.java
package jp.artan.tm.proxy;
import jp.artan.tm.TutorialMod;
import jp.artan.tm.init.BlockInit;
import jp.artan.tm.init.ItemInit;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
public class ClientProxy extends CommonProxy {
@Override
public void preInit(FMLPreInitializationEvent event) {
super.preInit(event);
TutorialMod.logger.info("ClientProxy.preInit");
}
@SubscribeEvent
public void registerModels(ModelRegistryEvent event) {
TutorialMod.logger.info("ClientProxy.registerModels");
ItemInit.ITEMS.forEach(f -> f.registerModel(event));
BlockInit.BLOCKS.forEach(f -> f.registerModel(event)); //Postscript
}
}
Crop blocks and seed items are each within an instance, and the other instance is used. In addition, you need an instance of a crop block to instantiate a seed item.
First, place each instance in BlockInit and ItemInit. The class names are TutorialPlant and TutorialSeed, respectively.
init/BlockInit.java
package jp.artan.tm.init;
import jp.artan.tm.block.TutorialPlant;
import jp.artan.tm.event.IBlockRegisterEvent;
import net.minecraft.block.BlockCrops;
import java.util.ArrayList;
import java.util.List;
public class BlockInit {
public static final List<IBlockRegisterEvent> BLOCKS = new ArrayList<IBlockRegisterEvent>();
public static final BlockCrops TUTORIAL_PLANT = new TutorialPlant("tutorial_plant");
}
init/ItemInit.java
package jp.artan.tm.init;
import jp.artan.tm.event.IItemRegisterEvent;
import jp.artan.tm.item.TutorialFood;
import jp.artan.tm.item.TutorialItem;
import jp.artan.tm.item.TutorialSeed;
import net.minecraft.item.Item;
import net.minecraft.item.ItemFood;
import net.minecraft.item.ItemSeeds;
import java.util.ArrayList;
import java.util.List;
public class ItemInit {
public static final List<IItemRegisterEvent> ITEMS = new ArrayList<IItemRegisterEvent>();
public static final Item TUTORIAL_ITEM = new TutorialItem("tutorial_item");
public static final ItemFood TUTORIAL_FOOD = new TutorialFood("tutorial_food", 1, 1.0F);
public static final ItemSeeds TUTORIAL_SEED = new TutorialSeed("tutorial_seed");
}
Now that we have placed each instance, we will create a TutorialPlant and a TutorialSeed.
block/TutorialPlant.java
package jp.artan.tm.block;
import jp.artan.tm.TutorialMod;
import jp.artan.tm.event.IBlockRegisterEvent;
import jp.artan.tm.init.BlockInit;
import jp.artan.tm.init.ItemInit;
import net.minecraft.block.Block;
import net.minecraft.block.BlockCrops;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.item.Item;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.event.RegistryEvent;
public class TutorialPlant extends BlockCrops implements IBlockRegisterEvent {
protected final String Name;
public TutorialPlant(String name) {
super();
this.Name = name;
this.setUnlocalizedName(this.Name);
this.setRegistryName(TutorialMod.MODID, this.Name);
BlockInit.BLOCKS.add(this);
}
@Override
public Item getSeed() {
return ItemInit.TUTORIAL_SEED;
}
@Override
public Item getCrop() {
return ItemInit.TUTORIAL_FOOD;
}
@Override
public void registerBlock(RegistryEvent.Register<Block> event) {
event.getRegistry().register(this);
}
@Override
public void registerModel(ModelRegistryEvent event) {
ModelLoader.setCustomModelResourceLocation(Item.getItemFromBlock(this), 0,
new ModelResourceLocation(new ResourceLocation(TutorialMod.MODID, this.Name), "inventory"));
}
}
Specify the seed item to drop when destroying a crop block with getSeed
Specify the crop item to drop when destroying a crop block with getCrop
item/TutorialSeed.java
package jp.artan.tm.item;
import jp.artan.tm.TutorialMod;
import jp.artan.tm.event.IItemRegisterEvent;
import jp.artan.tm.init.BlockInit;
import jp.artan.tm.init.ItemInit;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemSeeds;
import net.minecraft.item.ItemStack;
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.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.common.EnumPlantType;
import net.minecraftforge.event.RegistryEvent;
public class TutorialSeed extends ItemSeeds implements IItemRegisterEvent {
private final String name;
public TutorialSeed(String name) {
super(BlockInit.TUTORIAL_PLANT, Blocks.FARMLAND);
this.name = name;
this.setUnlocalizedName(this.name);
this.setRegistryName(TutorialMod.MODID, this.name);
this.setCreativeTab(TutorialMod.creativeTabs);
ItemInit.ITEMS.add(this);
}
@Override
public EnumActionResult onItemUse(EntityPlayer player, World worldIn, BlockPos pos, EnumHand hand,
EnumFacing facing, float hitX, float hitY, float hitZ) {
ItemStack stack = player.getHeldItem(hand);
IBlockState state = worldIn.getBlockState(pos);
if (facing == EnumFacing.UP && player.canPlayerEdit(pos.offset(facing), facing, stack)
&& state.getBlock().canSustainPlant(state, worldIn, pos, EnumFacing.UP, this)
&& worldIn.isAirBlock(pos.up())) {
worldIn.setBlockState(pos.up(), BlockInit.TUTORIAL_PLANT.getDefaultState());
if (player.capabilities.isCreativeMode || !worldIn.isRemote) {
stack.shrink(1);
}
return EnumActionResult.SUCCESS;
}
return EnumActionResult.FAIL;
}
@Override
public EnumPlantType getPlantType(IBlockAccess world, BlockPos pos) {
return EnumPlantType.Crop;
}
@Override
public IBlockState getPlant(IBlockAccess world, BlockPos pos) {
return BlockInit.TUTORIAL_PLANT.getDefaultState();
}
@Override
public void registerItem(RegistryEvent.Register<Item> event) {
event.getRegistry().register(this);
}
@Override
public void registerModel(ModelRegistryEvent event) {
ModelLoader.setCustomModelResourceLocation(this, 0,
new ModelResourceLocation(new ResourceLocation(TutorialMod.MODID, this.name), "inventory"));
}
}
Next, set the language and texture.
lang/en_us.lang
# English Language File
# Tabs
itemGroup.tutorial_tab=Tutorial Tab
# Items
item.tutorial_item.name=Tutorial Item
item.tutorial_food.name=Tutorial Food
item.tutorial_seed.name=Tutorial Seed
lang/ja_jp.lang
#Japanese language file
# Tabs
itemGroup.tutorial_tab=Tutorial tab
# Items
item.tutorial_item.name=Tutorial item
item.tutorial_food.name=Tutorial food
item.tutorial_seed.name=Tutorial species
models/item/tutorial_seed.json
{
"parent": "item/generated",
"textures": {
"layer0": "tm:items/tutorial_seed"
}
}
models/item/tutorial_plant.json
{
"parent": "block/cube_all",
"textures": {
"all": "tm:blocks/tutorial_plant"
}
}
blockstates/tutorial_plant.json
{
"variants": {
"age=0": {
"model": "tm:tutorial_plant0"
},
"age=1": {
"model": "tm:tutorial_plant1"
},
"age=2": {
"model": "tm:tutorial_plant2"
},
"age=3": {
"model": "tm:tutorial_plant3"
},
"age=4": {
"model": "tm:tutorial_plant4"
},
"age=5": {
"model": "tm:tutorial_plant5"
},
"age=6": {
"model": "tm:tutorial_plant6"
},
"age=7": {
"model": "tm:tutorial_plant7"
}
}
}
In the above file, you can specify the json file that stores the texture information corresponding to the 7 stages of crop growth. Since only the data of the initial state that has not grown is described below, create 8 json data from 0 to 7.
models/block/tutorial_plant0.json
{
"parent": "block/crop",
"textures": {
"crop": "tm:blocks/tutorial_plant0"
}
}
Crop items and seed items specified in the Tutorial Plant should be dropped when destroyed after maximum growth.
From the left, it is a block when growth is the 0th stage, growth is the 3rd stage, and growth is the 6th stage.