Jump to content
Search In
  • More options...
Find results that contain...
Find results in...

how do i add my custom tulips to a vanilla-biome?


Drachenbauer
 Share

Recommended Posts

I also think, biomes in mods may have the tulips added a bit different to the vanila-ones.

This can make it more difficult to check all biomes, that may appear in mods...

 

I also have a new question:

Can i have my block and item-registries separated into two init-classes?

In the vanila-code has a class Items, where all items are initialized.

And a class Blocks, where all blocks are initialized.

I have similar classes in my mod, too.

So i thaught, i can put the block-registrys into my blocks-class and the item-registrys in my items-class.

But now i get an error:

Quote

java.lang.NullPointerException: Registry Object not present

How can i make theese registrys work, if they are in separate classes?

 

Edit:

Now i found the solution:

Theese lines:

public static final DeferredRegister<Block> BLOCKS = new DeferredRegister<>(ForgeRegistries.BLOCKS, Reference.MOD_ID);

needed to be in the separate classes, too.

Edited by Drachenbauer
Link to comment
Share on other sites

You answered, while i edited my post:

 

Now i found the solution:

Theese lines:

public static final DeferredRegister<Block> BLOCKS = new DeferredRegister<>(ForgeRegistries.BLOCKS, Reference.MOD_ID);

and

public static final DeferredRegister<Item> ITEMS = new DeferredRegister<>(ForgeRegistries.ITEMS, Reference.MOD_ID);

needed to be in the separate classes, too.

 

Now it works.

Edited by Drachenbauer
Link to comment
Share on other sites

54 minutes ago, Drachenbauer said:

Another question:

 

how do i make bone meal spawn my tulips in theese biomes?

Have you tried anything? Have you looked anywhere to see how vanilla stuff works?

I'd start with BoneMealItem and work back from there.

Link to comment
Share on other sites

14 minutes ago, Drachenbauer said:

I looked into that item, but saw nothing about the flower-blocks there...

You can't give up so easy. Look at what happens when you use bonemeal, and follow the progression of code.

 

I did, and it lead me to notice it calls some methods from the IGrowable interface, which lead me to notice that when you bonemeal a block, the (IGrowable) block holds the code that is executed. That's as far as I got, I'll let you do the rest. :)

Link to comment
Share on other sites

There is something about DecoratedFeatureConfig.

It looks like, it get´s flowers to place, that came into the biome this way

But i don´know, how to get my tulips with DecoratedFeatureConfig into the biomes...

Actualy i use BlockClusterFeatureConfig.

Edited by Drachenbauer
Link to comment
Share on other sites

Iow i found out, that ForestFlowerBlockStateProvider and PlainFlowerBlockStateProvider use blockstate-lists, wich include the vanilla-tulips.

 

Is there any way to pass my own list:

    private static final BlockState[] TULIPS_BLOCKSTATES = new BlockState[]
    {
        Blocks.RED_TULIP.getDefaultState(),
        Blocks.ORANGE_TULIP.getDefaultState(),
        Blocks.WHITE_TULIP.getDefaultState(),
        Blocks.PINK_TULIP.getDefaultState(),
        
        MoreTulipsBlocks.BLACK_TULIP.get().getDefaultState(),
        MoreTulipsBlocks.BLUE_TULIP.get().getDefaultState(),
        MoreTulipsBlocks.BROWN_TULIP.get().getDefaultState(),
        MoreTulipsBlocks.CYAN_TULIP.get().getDefaultState(),
        MoreTulipsBlocks.GRAY_TULIP.get().getDefaultState(),
        MoreTulipsBlocks.GREEN_TULIP.get().getDefaultState(),
        MoreTulipsBlocks.LIGHT_BLUE_TULIP.get().getDefaultState(),
        MoreTulipsBlocks.LIGHT_GRAY_TULIP.get().getDefaultState(),
        MoreTulipsBlocks.LIME_TULIP.get().getDefaultState(),
        MoreTulipsBlocks.MAGENTA_TULIP.get().getDefaultState(),
        MoreTulipsBlocks.PURPLE_TULIP.get().getDefaultState(),
        MoreTulipsBlocks.YELLOW_TULIP.get().getDefaultState(),
    };

into theese providers or should i register my own BlockStateProvider

Link to comment
Share on other sites

So I was looking at some vanilla code, and noticed if you trace back from GrassBlock, you see in the grow method that there's a call to a biome getFlowers(). If you look at that method, you see it returns the biome's flowers. In Eclipse, you can right click on a method, and select "Open Call Heirarchy". This shows places where this is accessed, and doing this to the flowers field in the biome, it shows me it's accessed in the addFeature method of Biome. THIS shows me when a feature is added via addFeature, if the feature is Feature.DECORATED_FLOWER, it adds that to the list of flowers.

 

Your feature is of type Feature.FLOWER. What happens if you change it?

 

I showed you my trail of thought/research, in hopes it will help you with backtracing through the code to find what you're looking for. Learn how to use the features of your IDE to help you. :)

Link to comment
Share on other sites

I already used that backtracing and found, what you say, but i cannot find, where  DECORATED_FLOWER get´s the flowers from, and i found nothing there, where code in my own classes can access.

 

so i now create my own bonemeal, that manually adds my tulips, if the clicked grass-block is in one of the three vanilla-biomes with tulips.

I make it the way, how my bick blocks in the other mod add their invisible part-blocks to the world, if placed.

At first i let it find random positions in a 9x9 square around the clicked grass-blocks and find te surface of the ground there and then it should place random tulips there, if a grassblock is below and the position, itself has just air or a plant (but not a tree or a tulip).

It just needs a little bugfix and i think, i find the solution.

 

Edit:

I fixed it.

My custom bonemeal now makes alot of colorful tulips grow.

 

now i think, i can pack my mod.

 

But i have one last question:

How can i make the vanilla bonemeal use this behavior?

Edited by Drachenbauer
Link to comment
Share on other sites

This is now my
custom bonemeal class:

Spoiler

package drachenbauer32.moretulipsmod.items;

import java.util.Arrays;
import java.util.List;
import java.util.Random;

import drachenbauer32.moretulipsmod.init.MoreTulipsBlocks;
import net.minecraft.block.AirBlock;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.FlowerBlock;
import net.minecraft.block.GrassBlock;
import net.minecraft.block.IGrowable;
import net.minecraft.item.BoneMealItem;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUseContext;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.Biomes;
import net.minecraft.world.server.ServerWorld;

public class TulipsBoneMealItem extends BoneMealItem 
{
    private static final Biome[] BIOMES = new Biome[]
    {
        Biomes.PLAINS,
        Biomes.SUNFLOWER_PLAINS,
        Biomes.FLOWER_FOREST
    };
    
    private static final BlockState[] TULIPS_BLOCKSTATES = new BlockState[]
    {
        Blocks.RED_TULIP.getDefaultState(),
        Blocks.ORANGE_TULIP.getDefaultState(),
        Blocks.WHITE_TULIP.getDefaultState(),
        Blocks.PINK_TULIP.getDefaultState(),
        
        MoreTulipsBlocks.BLACK_TULIP.get().getDefaultState(),
        MoreTulipsBlocks.BLUE_TULIP.get().getDefaultState(),
        MoreTulipsBlocks.BROWN_TULIP.get().getDefaultState(),
        MoreTulipsBlocks.CYAN_TULIP.get().getDefaultState(),
        MoreTulipsBlocks.GRAY_TULIP.get().getDefaultState(),
        MoreTulipsBlocks.GREEN_TULIP.get().getDefaultState(),
        MoreTulipsBlocks.LIGHT_BLUE_TULIP.get().getDefaultState(),
        MoreTulipsBlocks.LIGHT_GRAY_TULIP.get().getDefaultState(),
        MoreTulipsBlocks.LIME_TULIP.get().getDefaultState(),
        MoreTulipsBlocks.MAGENTA_TULIP.get().getDefaultState(),
        MoreTulipsBlocks.PURPLE_TULIP.get().getDefaultState(),
        MoreTulipsBlocks.YELLOW_TULIP.get().getDefaultState(),
    };
    
    /**
     ** With this integer, the code stops searching for tulip-positions,
     ** if it fails 10 times in a row at the last method.
     ** so it cannot stuck in an infinite loop, if there are not enough
     ** valid locations around the clicked grassblock.
     **/
    private static int tries = 0;
    
    public TulipsBoneMealItem(Properties p_i50055_1_)
    {
        super(p_i50055_1_);
    }
    
    /**
     ** I copyed the whoole code of this method, because override with return super method
     ** makes it call the applyBonemeal method from the vanilla BoneMealItem and not the one from here.
     **/
    public ActionResultType onItemUse(ItemUseContext context)
    {
        World world = context.getWorld();
        BlockPos blockpos = context.getPos();
        BlockPos blockpos1 = blockpos.offset(context.getFace());
        
        if (applyBonemeal(context.getItem(), world, blockpos, context.getPlayer()))
        {
            if (!world.isRemote)
            {
                world.playEvent(2005, blockpos, 0);
            }
            
            return ActionResultType.SUCCESS;
        }
        else
        {
            BlockState blockstate = world.getBlockState(blockpos);
            boolean flag = blockstate.isSolidSide(world, blockpos, context.getFace());
            
            if (flag && growSeagrass(context.getItem(), world, blockpos1, context.getFace()))
            {
                if (!world.isRemote)
                {
                    world.playEvent(2005, blockpos1, 0);
                }
                
                return ActionResultType.SUCCESS;
            }
            else
            {
                return ActionResultType.PASS;
            }
        }
    }
    
    /**
     ** I placed the modification to check for specific biomes,
     ** and use the following methods, into a copy of the vanilla applyBonemeal-method,
     ** because it has a return-type and i cannot override static methods.
     **/
    public static boolean applyBonemeal(ItemStack stack, World worldIn, BlockPos pos, net.minecraft.entity.player.PlayerEntity player)
    {
        BlockState blockstate = worldIn.getBlockState(pos);
        int hook = net.minecraftforge.event.ForgeEventFactory.onApplyBonemeal(player, worldIn, pos, blockstate, stack);
        
        if (hook != 0)
        {
            return hook > 0;
        }
        
        if (blockstate.getBlock() instanceof IGrowable)
        {
            IGrowable igrowable = (IGrowable)blockstate.getBlock();
            if (igrowable.canGrow(worldIn, pos, blockstate, worldIn.isRemote))
            {
                if (worldIn instanceof ServerWorld)
                {
                    if (igrowable.canUseBonemeal(worldIn, worldIn.rand, pos, blockstate))
                    {
                        igrowable.grow((ServerWorld)worldIn, worldIn.rand, pos, blockstate);
                        
                        Biome biome = player.world.getBiome(pos);
                        
                        if(Arrays.asList(BIOMES).contains(biome))
                        {
                            int i = 0;
                                    
                            while (i < 2)
                            {
                                tries = 0;
                                findRandomPos(worldIn, pos);
                                i++;
                            }
                            
                            if(biome == Biomes.FLOWER_FOREST)
                            {
                                while (i < 10)
                                {
                                    tries = 0;
                                    findRandomPos(worldIn, pos);
                                    i++;
                                }
                            }
                        }
                    }
                    
                    stack.shrink(1);
                }
                
                
                return true;
            }
        }
        
        return false;
    }
    
    /**
     ** This method finds random positions on ground in a 9x9 square
     ** with the clicked Grassblock in the center.
     **/
    private static void findRandomPos(World worldIn, BlockPos pos)
    {
        BlockPos position = pos;
        
        int rnd_n_s = new Random().nextInt(9);
        int rnd_e_w = new Random().nextInt(9);
        
        position = position.north(rnd_n_s - 4);
        position = position.east(rnd_e_w - 4);
        
        while (worldIn.getBlockState(position).isOpaqueCube(worldIn, position))
        {
            position = position.up();
        }
        
        if (!canGrowTulips(worldIn, position))
        {
            while (!worldIn.getBlockState(position.down()).isOpaqueCube(worldIn, position.down()))
            {
                position = position.down();
            }
            
            if (!canGrowTulips(worldIn, position))
            {
                if (tries < 10)
                {
                    findRandomPos(worldIn, position);
                    tries++;
                }
            }
        }
    }
    
    /**
     ** this method places a random tulip,
     ** if the block below the passed position is a grassblock
     ** and at the posithon is air or a plant (but not a tree or a tulip).
     **/
    private static boolean canGrowTulips(World worldIn, BlockPos pos)
    {
        BlockState blockstate_1 = worldIn.getBlockState(pos.down());
        BlockState blockstate_2 = worldIn.getBlockState(pos);
        
        int rnd = new Random().nextInt(TULIPS_BLOCKSTATES.length);
        BlockState tulip_blockstate = TULIPS_BLOCKSTATES[rnd];
        
        if (blockstate_1.getBlock() instanceof GrassBlock && (blockstate_2.getBlock() instanceof AirBlock || blockstate_2.getBlock() instanceof FlowerBlock))
        {
            if (Arrays.asList(TULIPS_BLOCKSTATES).contains(blockstate_2))
            {
                return false;
            }
            
            worldIn.setBlockState(pos, tulip_blockstate);
            worldIn.setBlockState(pos.up(), Blocks.AIR.getDefaultState());
            return true;
        }
        else
        {
            return false;
        }
    }
}

How can i make the vanilla BoneMealItem-class use my custom methods and the custom added part of the applyBonemeal-method here after it´s normal rightclick-behavior?

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share



×
×
  • Create New...

Important Information

By using this site, you agree to our Privacy Policy.