[JAVA] Minecraft Modding 1.12.2

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.

environment

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.

image.png

Proxy function

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 inTutorialMod.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

Add item

Batch registration process

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. ** **

Item implementation

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.

image.png

Texture and language settings

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 [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.

image.png

image.png

Add creative tab

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.

image.png

Add food

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.

image.png

Add crops

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.

Batch registration process

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
    }
}

Creating crop blocks and seed items

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"));
    }
}

Texture and language settings

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.

image.png

From the left, it is a block when growth is the 0th stage, growth is the 3rd stage, and growth is the 6th stage. image.png

Recommended Posts

Minecraft Modding 1.12.2
Make fat Jar with Minecraft modding
[Modding] An important Side concept in Minecraft
Site summary to be helpful in Minecraft modding 1.12.2