Minecraft1.12.2で1.14のSweet berryのような植物ブロックを追加したメモ(サンプルコード)

#Minecraft1.12.2で1.14のSweet berryのような植物ブロックを追加したメモ(サンプルコード)
右クリックで収穫できる茂みを作るよ

##環境
- Forge MDK: forge-1.12.2-14.23.5.2768

##前提
- 追加したブロックやアイテムの登録用クラスやプロキシクラスを用意してある
    - (僕は[あゆたきさんのチュートリアル](https://ayutakimm.wp-x.jp/universal-jp/contents-tree-jp/)の通りにやりました)
- テクスチャのドット絵を用意してある

##参考にしたバニラのコード
備考: 新しい処理は何も書いていなくてバニラの変数に代入したりしただけです

- 1.12.2の
    - ItemFood.class
    - ItemSeed.class
    - BlockCrops.class
    - BlockCarrots.class
    - apple.json
    - acacia_sapling.json
    - carrots.json
- 1.14.4の
    - SweetBerryBushBlock.class

##最低限必要なコード
あんずの木(このMODのあんずを収穫)のを追加したいと思います
備考: 登録用クラスを用意しておいてね

###ファイルの配置
パッケージ名とかはバニラのマネっ子してます

####src/main/java
- FFFMItems.java(アイテムの登録用クラス)
    - oguro.fffm.init
- FFFMBlocks.java(ブロックの登録用クラス)
    - oguro.fffm.init
- BlockFruitTree.java(果物の木の特性を決めるクラス)
    - oguro.fffm.block
- BlockApricotTree.java(あんずの木独自の性質を決めるクラス)
    - oguro.fffm.block
- ItemFruit.java(果物の特性を決めるクラス)
    - oguro.fffm.item
- ItemApricot.java(あんず独自の性質を決めるクラス)
    - oguro.fffm.item
- ItemSapling.java(果物の木の苗の性質を決めるクラス)
    - oguro.fffm.item
- ItemApricotSapling.java(あんずの苗独自の性質を決めるクラス)
    - oguro.fffm.item

####src/main/resources(モデル)
備考: コマンドを使わないとインベントリに表示されることはないのでBlockApricotTreeのインベントリでの見た目のjsonを用意していないがlogにエラー出まくって鬱陶しいので適当でいいから用意したほうがいいかも(見た目が読み込めないだけなので大丈夫)

- apricot.json(あんずの見た目)
    - assets.fffm.models.item
- apricot_tree_sapling.json(あんずの苗の見た目)
    - assets.fffm.models.item
- apricot_tree(あんずの木のブロックはメタデータが違う複数のブロックだから、それぞれの見た目を記述したjsonはどれか指定するファイル)
    - assets.fffm.blockstates
- apricot_tree_stage0.json
- apricot_tree_stage1.json
- apricot_tree_stage2.json
- apricot_tree_stage3.json (あんずの木のそれぞれ成長段階ごとの見た目)
    - assets.fffm.models.block

####src/main/resources(テクスチャ)
- apricot.png(あんずのテクスチャ)
    - assets.fffm.textures.items
- apricot_tree_sapling.png(あんずの苗のテクスチャ)
    - assets.fffm.textures.items
- apricot_tree_stage0.png
- apricot_tree_stage1.png
- apricot_tree_stage2.png
- apricot_tree_stage3.png(あんずの木のテクスチャ)
    - assets.fffm.textures.blocks

###クラスのソースコード

#### FFFMItems.java
~~~
package oguro.fffm.init;

import java.util.LinkedList;
import java.util.List;

import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.item.Item;
import net.minecraft.item.ItemFood;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import oguro.fffm.FFFMRef;
import oguro.fffm.item.ItemApricot;
import oguro.fffm.item.ItemApricotTreeSapling;
import oguro.fffm.item.ItemSapling;

public class FFFMItems
{
	//アイテムを宣言する
	public static ItemSapling APRICOT_TREE_SAPLING;

	public static ItemFood APRICOT;

	//アイテムのインスタンスを生成する
	public static void init()
	{
		APRICOT_TREE_SAPLING = (ItemSapling) new ItemApricotTreeSapling(FFFMBlocks.APRICOT_TREE).setRegistryName("apricot_tree_sapling")
	            .setUnlocalizedName("apricot_tree_sapling");

		APRICOT = (ItemFood) new ItemApricot().setRegistryName("apricot")
				.setUnlocalizedName("apricot");

	}


	//アイテムを登録する
	public static void register()
	{
		registerItem(APRICOT_TREE_SAPLING);

		registerItem(APRICOT);
	}

	public static void registerItem(Item item)
	{
        RegistrationHandler.ITEMS.add(item);
    }

	//アイテムの描画を登録する
	public static void registerRenders()
	{
        registerRender(APRICOT_TREE_SAPLING);

		registerRender(APRICOT);

    }

    private static void registerRender(Item item)
    {
        ModelLoader.setCustomModelResourceLocation(item, 0,
                new ModelResourceLocation(item.getRegistryName(),"inventory"));
    }

    //内部クラスでアイテムを登録する
    @Mod.EventBusSubscriber(modid = FFFMRef.MODID)
    public static class RegistrationHandler
    {

        public static final List<Item> ITEMS = new LinkedList<>();

        @SubscribeEvent
        public static void registerItems(final RegistryEvent.Register<Item> event)
        {
            FFFMItems.init();
            FFFMItems.register();
            ITEMS.stream().forEach(item -> event.getRegistry().register(item));

        }
    }
}
~~~

####FFFMBlocks.java
~~~
package oguro.fffm.init;

import java.util.LinkedList;
import java.util.List;

import net.minecraft.block.Block;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import oguro.fffm.FFFMRef;
import oguro.fffm.block.BlockApricotTree;
import oguro.fffm.block.BlockFruitTree;

public class FFFMBlocks
{
	//登録するブロックを宣言
	public static BlockFruitTree APRICOT_TREE;

	//ブロックのインスタンスを生成
	public static void init()
	{
		APRICOT_TREE = (BlockFruitTree) new BlockApricotTree().setRegistryName("apricot_tree")
                .setUnlocalizedName("apricot_tree");
	}


	//ブロックを登録する
	public static void register()
	{
        registerBlock(APRICOT_TREE);
    }


	//ブロックの登録
	public static void registerBlock(Block block)
	{
        registerBlock(block, new ItemBlock(block));
    }

	//アイテムブロックの登録
	public static void registerBlock(Block block, ItemBlock item)
	{
        RegistrationHandler.BLOCKS.add(block);
        item.setRegistryName(block.getRegistryName());
        FFFMItems.RegistrationHandler.ITEMS.add(item);
    }

	//アイテムブロックの描画を登録する
	public static void registerRenders()
	{
        registerRender(APRICOT_TREE);
    }

    @SideOnly(Side.CLIENT)
    private static void registerRender(Block block)
    {
        ModelLoader.setCustomModelResourceLocation(Item.getItemFromBlock(block), 0,
                new ModelResourceLocation(block.getRegistryName(),"inventory"));
    }

    //内部クラスでブロックを登録する
    @Mod.EventBusSubscriber(modid = FFFMRef.MODID)
    public static class RegistrationHandler {

        public static final List<Block> BLOCKS = new LinkedList<>();

        @SubscribeEvent
        public static void registerItems(final RegistryEvent.Register<Block> event) {

            FFFMBlocks.init();
            FFFMBlocks.register();
            BLOCKS.stream().forEach(block -> event.getRegistry().register(block));
        }
    }
}
~~~
####BlockFruitTree.java
~~~
package oguro.fffm.block;

import java.util.Random;

import net.minecraft.block.Block;
import net.minecraft.block.BlockBush;
import net.minecraft.block.IGrowable;
import net.minecraft.block.SoundType;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.properties.PropertyInteger;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.init.SoundEvents;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import oguro.fffm.init.FFFMItems;

//BlockCropsを改造しつつ1.14.4のSweetBerryBushBlockから果物入手あたりの処理をパクってきた。
//新しいフルーツを追加するときは、このクラスを継承してドロップするアイテムなどの変数を書き換えることにする。
public class BlockFruitTree
extends BlockBush
implements IGrowable
{
	//作物の成長段階を作る。ここでは0から3の4段階。
	public static final PropertyInteger AGE = PropertyInteger.create("age", 0, 3);

	protected BlockFruitTree()
    {
        this.setDefaultState(this.blockState.getBaseState().withProperty(this.getAgeProperty(), Integer.valueOf(0)));
        this.setTickRandomly(true);
        this.setCreativeTab((CreativeTabs)null);
        this.setHardness(0.0F);
        this.setSoundType(SoundType.PLANT);
        this.disableStats();
    }


	public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos)
    {
        return FULL_BLOCK_AABB;
    }
	//成長に関する記述
	protected boolean canSustainBush(IBlockState state)
    {
		//設置可能(作付け可能)なブロック
		//BlockFruitTreeでは「耕地(FARMLAND)」、「草ブロック(GRASS)」、「土(DIRT)」の上に植えられるようにした。
        return state.getBlock() == Blocks.FARMLAND ||
        		state.getBlock() == Blocks.GRASS ||
        		state.getBlock() == Blocks.DIRT;
    }

    protected PropertyInteger getAgeProperty()
    {
        return AGE;
    }

    public int getMaxAge()
    {
    	//最大成長段階は今回は3
        return 3;
    }

    protected int getAge(IBlockState state)
    {
        return ((Integer)state.getValue(this.getAgeProperty())).intValue();
    }

    public IBlockState withAge(int age)
    {
        return this.getDefaultState().withProperty(this.getAgeProperty(), Integer.valueOf(age));
    }

    public boolean isMaxAge(IBlockState state)
    {
        return ((Integer)state.getValue(this.getAgeProperty())).intValue() >= this.getMaxAge();
    }

    public void updateTick(World worldIn, BlockPos pos, IBlockState state, Random rand)
    {
        super.updateTick(worldIn, pos, state, rand);

        if (!worldIn.isAreaLoaded(pos, 1)) return; // Forge: prevent loading unloaded chunks when checking neighbor's light
        if (worldIn.getLightFromNeighbors(pos.up()) >= 9)
        {
            int i = this.getAge(state);

            if (i < this.getMaxAge())
            {
                float f = getGrowthChance(this, worldIn, pos);

                if(net.minecraftforge.common.ForgeHooks.onCropsGrowPre(worldIn, pos, state, rand.nextInt((int)(25.0F / f) + 1) == 0))
                {
                    worldIn.setBlockState(pos, this.withAge(i + 1), 2);
                    net.minecraftforge.common.ForgeHooks.onCropsGrowPost(worldIn, pos, state, worldIn.getBlockState(pos));
                }
            }
        }
    }

    public void grow(World worldIn, BlockPos pos, IBlockState state)
    {
        int i = this.getAge(state) + this.getBonemealAgeIncrease(worldIn);
        int j = this.getMaxAge();

        if (i > j)
        {
            i = j;
        }

        worldIn.setBlockState(pos, this.withAge(i), 2);
    }

    protected int getBonemealAgeIncrease(World worldIn)
    {
        return MathHelper.getInt(worldIn.rand, 2, 5);
    }

    protected static float getGrowthChance(Block blockIn, World worldIn, BlockPos pos)
    {
        float f = 4.0F;
        BlockPos blockpos = pos.down();

        for (int i = -1; i <= 1; ++i)
        {
            for (int j = -1; j <= 1; ++j)
            {
                float f1 = 0.0F;
                IBlockState iblockstate = worldIn.getBlockState(blockpos.add(i, 0, j));

                if (iblockstate.getBlock().canSustainPlant(iblockstate, worldIn, blockpos.add(i, 0, j), net.minecraft.util.EnumFacing.UP, (net.minecraftforge.common.IPlantable)blockIn))
                {
                    f1 = 4.0F;

                    if (iblockstate.getBlock().isFertile(worldIn, blockpos.add(i, 0, j)))
                    {
                        f1 = 5.2F;
                    }
                }

                if (i != 0 || j != 0)
                {
                    f1 /= 6.0F;
                }

                f += f1;
            }
        }

        BlockPos blockpos1 = pos.north();
        BlockPos blockpos2 = pos.south();
        BlockPos blockpos3 = pos.west();
        BlockPos blockpos4 = pos.east();
        boolean flag = blockIn == worldIn.getBlockState(blockpos3).getBlock() || blockIn == worldIn.getBlockState(blockpos4).getBlock();
        boolean flag1 = blockIn == worldIn.getBlockState(blockpos1).getBlock() || blockIn == worldIn.getBlockState(blockpos2).getBlock();

        if (flag && flag1)
        {
            f /= 2.0F;
        }
        else
        {
            boolean flag2 = blockIn == worldIn.getBlockState(blockpos3.north()).getBlock() || blockIn == worldIn.getBlockState(blockpos4.north()).getBlock() || blockIn == worldIn.getBlockState(blockpos4.south()).getBlock() || blockIn == worldIn.getBlockState(blockpos3.south()).getBlock();

            if (flag2)
            {
                f /= 4.8F;
            }
        }

        return f;
    }

    //破壊したときに落とす「苗アイテム」の設定
    //このクラスはどの果樹からも直接呼び出されない予定なのでとりあえずあんずの苗にしておく。
    protected Item getSapling()
    {
        return FFFMItems.APRICOT_TREE_SAPLING;
    }

  //破壊したときに落とす「果物」とその個数の設定
    //このクラスはどの果樹からも直接呼び出されない予定なのでとりあえずあんずを2個にしておく。
    protected Item getFruit()
    {
    	return Items.APRICOT;
    }

    protected int getHowManyPickUp()
    {
    	return 2;
    }

    //ドロップするようにする
    public Item getItemDropped(IBlockState state, Random rand, int fortune)
    {
        return this.getSapling();
    }

    public ItemStack getItem(World worldIn, BlockPos pos, IBlockState state)
    {
        return new ItemStack(this.getSapling());
    }

    public boolean onBlockActivated(World worldIn, BlockPos pos, IBlockState state, EntityPlayer playerIn, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ)
    {
    	int i = this.getAge(state);
        boolean flag = i == 3;
        if (!flag && playerIn.getHeldItem(hand).getItem() == Items.DYE) {
           return false;
        }
      //age=2(準最大成長)のときに収穫する処理
        else if (i == 2)
        {
           //収穫できる個数
           //getHowManyPickUpで設定した収穫個数だけ収穫できる設定にしてある。
           int j = getHowManyPickUp();
           spawnAsEntity(worldIn, pos, new ItemStack(getFruit(), j + (flag ? 1 : 0)));
           //収穫時に鳴らす音
           //新しい音を追加せずに「額縁からアイテムを剥ぎ取る音」にした。
           worldIn.playSound((EntityPlayer)null, pos, SoundEvents.ENTITY_ITEMFRAME_REMOVE_ITEM, SoundCategory.BLOCKS, 1.0F, 0.8F + worldIn.rand.nextFloat() * 0.4F);
           worldIn.setBlockState(pos, this.withAge(Integer.valueOf(0)), 2);
           return true;
        }
        //age=3(最大成長)のときに収穫する処理
        else if (i == 3)
        {
           //収穫できる個数
           //getHowManyPickUpで設定した収穫個数の2倍を収穫できる設定にしてある。
           int j = getHowManyPickUp() * 2;
           spawnAsEntity(worldIn, pos, new ItemStack(getFruit(), j + (flag ? 1 : 0)));
           //収穫時に鳴らす音
           //新しい音を追加せずに「額縁からアイテムを剥ぎ取る音」にした。
           worldIn.playSound((EntityPlayer)null, pos, SoundEvents.ENTITY_ITEMFRAME_REMOVE_ITEM, SoundCategory.BLOCKS, 1.0F, 0.8F + worldIn.rand.nextFloat() * 0.4F);
           worldIn.setBlockState(pos, this.withAge(Integer.valueOf(0)), 2);
           return true;
        }
        //age=2に満たないときは「収穫しない処理
        else
        {
           return super.onBlockActivated(worldIn, pos, state, playerIn, hand, facing, hitX, hitY, hitZ);
        }
     }

    //IGrowableに関する記述
	@Override
	public boolean canGrow(World worldIn, BlockPos pos, IBlockState state, boolean isClient)
	{
		return !this.isMaxAge(state);
	}

	@Override
	public boolean canUseBonemeal(World worldIn, Random rand, BlockPos pos, IBlockState state)
	{
		return true;
	}

	@Override
	public void grow(World worldIn, Random rand, BlockPos pos, IBlockState state)
	{
		this.grow(worldIn, pos, state);
	}

	//成長段階ごとのブロックをメタデータの異なるブロックとして管理
	public IBlockState getStateFromMeta(int meta)
    {
        return this.withAge(meta);
    }
	public int getMetaFromState(IBlockState state)
    {
        return this.getAge(state);
    }

    protected BlockStateContainer createBlockState()
    {
        return new BlockStateContainer(this, new IProperty[] {AGE});
    }
}
~~~
####BlockApricotTree.java
~~~
package oguro.fffm.block;

import net.minecraft.item.Item;
import oguro.fffm.init.FFFMItems;

public class BlockApricotTree
extends BlockFruitTree
{
	//苗アイテムを設定

	protected Item getSapling()
    {
        return FFFMItems.APRICOT_TREE_SAPLING;
    }

	//果物アイテムを設定

    protected Item getFruit()
    {
    	return FFFMItems.APRICOT;
    }

	//収穫できる個数を設定

    protected int getHowManyPickUp()
    {
    	return 2;
    }
}
~~~
####ItemFruit.java
~~~
package oguro.fffm.item;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.EnumAction;
import net.minecraft.item.ItemFood;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumHand;
import net.minecraft.world.World;
import oguro.fffm.creativetab.FFFMCreativeTabs;

public class ItemFruit
extends ItemFood
{

	//満腹度回復量
	protected static int getHealAmount()
	{
		return 5;
	}

	//オオカミが食べるかどうか
	protected static boolean canWolfEat()
	{
		return false;
	}

	//食べるのにかかる時間
	protected int getEatTime()
	{
		return 32;
	}

	//食べるときのアニメーション
	//デフォルトでEAT
	public EnumAction getItemUseAction(ItemStack stack)
    {
        return EnumAction.EAT;
    }

	//満腹でも食べられるか
	//デフォルトでいいえ
	protected boolean canEatAlways()
	{
		return false;
	}


    public ItemFruit()
    {
        super(getHealAmount(), canWolfEat());
        this.setCreativeTab(FFFMCreativeTabs.FFFM_FRUIT);
    }

    public int getMaxItemUseDuration(ItemStack stack)
    {
        return getEatTime();
    }


    public ActionResult<ItemStack> onItemRightClick(World worldIn, EntityPlayer playerIn, EnumHand handIn)
    {
        ItemStack itemstack = playerIn.getHeldItem(handIn);

        if (playerIn.canEat(canEatAlways()))
        {
            playerIn.setActiveHand(handIn);
            return new ActionResult<ItemStack>(EnumActionResult.SUCCESS, itemstack);
        }
        else
        {
            return new ActionResult<ItemStack>(EnumActionResult.FAIL, itemstack);
        }
    }
}

~~~
####ItemApricot.java
~~~
package oguro.fffm.item;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.EnumAction;
import net.minecraft.item.ItemFood;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumHand;
import net.minecraft.world.World;
import oguro.fffm.creativetab.FFFMCreativeTabs;

public class ItemFruit
extends ItemFood
{

	//満腹度回復量
	protected static int getHealAmount()
	{
		return 5;
	}

	//オオカミが食べるかどうか
	protected static boolean canWolfEat()
	{
		return false;
	}

	//食べるのにかかる時間
	protected int getEatTime()
	{
		return 32;
	}

	//食べるときのアニメーション
	//デフォルトでEAT
	public EnumAction getItemUseAction(ItemStack stack)
    {
        return EnumAction.EAT;
    }

	//満腹でも食べられるか
	//デフォルトでいいえ
	protected boolean canEatAlways()
	{
		return false;
	}


    public ItemFruit()
    {
        super(getHealAmount(), canWolfEat());
        this.setCreativeTab(FFFMCreativeTabs.FFFM_FRUIT);
    }

    public int getMaxItemUseDuration(ItemStack stack)
    {
        return getEatTime();
    }


    public ActionResult<ItemStack> onItemRightClick(World worldIn, EntityPlayer playerIn, EnumHand handIn)
    {
        ItemStack itemstack = playerIn.getHeldItem(handIn);

        if (playerIn.canEat(canEatAlways()))
        {
            playerIn.setActiveHand(handIn);
            return new ActionResult<ItemStack>(EnumActionResult.SUCCESS, itemstack);
        }
        else
        {
            return new ActionResult<ItemStack>(EnumActionResult.FAIL, itemstack);
        }
    }
}
~~~
####ItemSapling.java
~~~
package oguro.fffm.item;

import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.block.Block;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.IPlantable;
import oguro.fffm.block.BlockFruitTree;
import oguro.fffm.creativetab.FFFMCreativeTabs;
import oguro.fffm.init.FFFMBlocks;

//バニラのItemSeedを引っ張ってきたっぽい(覚えてない)。
//新しいフルーツを追加するときは、このクラスを継承して植える果樹などの変数を書き換えることにする。
public class ItemSapling
extends Item
implements IPlantable
{
	private final BlockFruitTree crops;
	protected Block getTree()
	{
		//植える果樹
	    //このクラスはどの果樹からも直接呼び出されない予定なのでとりあえずあんずの木にしておく。
		return FFFMBlocks.APRICOT_TREE;
	}


    public ItemSapling(BlockFruitTree fruit_tree)
    {
        this.crops = (BlockFruitTree) this.getTree();
        //クリエイティブタブ
        //私は新しく「FFFM_SAPLING」というクリエイティブタブを作ってそこに入れた。
        //バニラのクリエイティブタブをそのまま使うならthis.setCreativeTab(CreativeTabs.FOOD);とか
        this.setCreativeTab(FFFMCreativeTabs.FFFM_SAPLINGS);
    }

    public EnumActionResult onItemUse(EntityPlayer player, World worldIn, BlockPos pos, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ)
    {
        ItemStack itemstack = player.getHeldItem(hand);
        net.minecraft.block.state.IBlockState state = worldIn.getBlockState(pos);
        if (facing == EnumFacing.UP && player.canPlayerEdit(pos.offset(facing), facing, itemstack) && state.getBlock().canSustainPlant(state, worldIn, pos, EnumFacing.UP, (IPlantable) this) && worldIn.isAirBlock(pos.up()))
        {
            worldIn.setBlockState(pos.up(), this.crops.getDefaultState());

            if (player instanceof EntityPlayerMP)
            {
                CriteriaTriggers.PLACED_BLOCK.trigger((EntityPlayerMP)player, pos.up(), itemstack);
            }

            itemstack.shrink(1);
            return EnumActionResult.SUCCESS;
        }
        else
        {
            return EnumActionResult.FAIL;
        }
    }

    @Override
    public net.minecraftforge.common.EnumPlantType getPlantType(net.minecraft.world.IBlockAccess world, BlockPos pos)
    {
        return net.minecraftforge.common.EnumPlantType.Plains;
    }

    @Override
    public net.minecraft.block.state.IBlockState getPlant(net.minecraft.world.IBlockAccess world, BlockPos pos)
    {
        return this.crops.getDefaultState();
    }

}
~~~
####ItemApricotTreeSapling.java
~~~
package oguro.fffm.item;

import net.minecraft.block.Block;
import oguro.fffm.block.BlockFruitTree;
import oguro.fffm.init.FFFMBlocks;

public class ItemApricotTreeSapling extends ItemSapling {

	public ItemApricotTreeSapling(BlockFruitTree fruit_tree) {
		super(fruit_tree);
	}

        //植える果樹
	@Override
	protected Block getTree()
	{
		return FFFMBlocks.APRICOT_TREE;
	}

}
~~~

###jsonのソースコード
jsonとクラスの当たり判定いじってやれば高さ2マスにしたりできるかも

####apricot.json
~~~
{
    "parent": "item/generated",
    "textures": {
        "layer0": "fffm:items/apricot"
    }
}
~~~
####apricot_tree_sapling.json
~~~
{
    "parent": "item/generated",
    "textures": {
        "layer0": "fffm:blocks/apricot_tree_sapling"
    }
}
~~~
####apricot_tree.json
~~~
{
    "variants": {
        "age=0": { "model": "fffm:apricot_tree_stage0" },
        "age=1": { "model": "fffm:apricot_tree_stage1" },
        "age=2": { "model": "fffm:apricot_tree_stage2" },
        "age=3": { "model": "fffm:apricot_tree_stage3" }
    }
}
~~~
####apricot_tree_stage◯.json
◯の中の数字いじってくれ

~~~
{
    "parent": "block/cross",
    "textures": {
        "cross": "fffm:blocks/apricot_tree_stage◯"
    }
}
~~~