Jump to content

Recommended Posts

Posted

I think I was successful in creating custom crops with 1.7.2.

 

I did it as follows.

 

I extended BlockCrops with my own version (I usually do this when modding to allow more control where possible, but you should be able to do this with vanilla BlockCrops): https://gist.github.com/anonymous/9797206

 

Made a blueberry bush block with: https://gist.github.com/anonymous/9796922

 

I extended ItemSeedFood with my own version (I usually do this when modding to allow more control where possible, but you should be able to do this with vanilla ItemSeedFood): https://gist.github.com/anonymous/9796951

 

I made the blueberry seed food item with: https://gist.github.com/anonymous/9796968

 

Then in my main class of the mod I registered everything with: https://gist.github.com/anonymous/9797030

 

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted

Thanks, I'll check it out. You really should add @Override to your methods though, you'll cry if you don't next time MC gets updated ;)

 

This method makes me think I won't be able to keep my current setup of multiple crops per block though:

 

    protected Item func_149866_i()

    {

        return Items.wheat_seeds;

    }

 

Ah well, I guess there's no point anymore anyway.

Posted
You really should add @Override to your methods though, you'll cry if you don't next time MC gets updated ;)

 

Actually, I usually have Eclipse set up to automatically put those in on save, but I guess when I set up Eclipse on this new computer I forgot to set the preferences.  So now I've got them in there.  Thanks.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

  • 5 months later...
Posted

I think I was successful in creating custom crops with 1.7.2.

 

I did it as follows.

<snip>

 

I tried this code out, and minecraft crashed. Apparently it was from this line?

 

return this.field_149867_a[p_149691_2_];

 

Which was inside the getIcon method in your custom BlockCrops class.

 

So I suppose it was a problem with getting the textures? How was this line supposed to go?

 

It would be very helpful if you responded. Everyone else's posts/tutorials about crops are extremely outdated.

 

Thanks!

Posted

Everyone else's posts/tutorials about crops are extremely outdated.

 

You might want to look at my tutorial on crops for 1.7.x: http://jabelarminecraft.blogspot.com/p/minecraft-forge-172-creating-custom.html

 

It's the same problem, except with more human readable names. The crash now hapens in this line:

 

return iIcon[parGrowthStage];

 

Within the getIcon method. What's going on with getIcon? Is nothing ever put in the iIcon array?

Posted

Here is a file that i use, it works great and all you have to do is just extend the file for your new crop and fill in the blanks :)

 

 

 

package your.mod;

import java.util.ArrayList;
import java.util.Random;

import net.minecraft.block.Block;
import net.minecraft.block.BlockBush;
import net.minecraft.block.IGrowable;
import net.minecraft.client.renderer.texture.IIconRegister;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.IIcon;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;

public abstract class BlockModCrop extends BlockBush implements IGrowable {

@SideOnly(Side.CLIENT)
private IIcon[] icons;
private int amountOfStages;
private String cropName;

public BlockModCrop(String name, int stages, String crop) {
	this.setTickRandomly(true);
	float f = 0.5F;
	this.setBlockBounds(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, 0.25F, 0.5F + f);
	this.setCreativeTab((CreativeTabs)null);
	this.setHardness(0.0F);
	this.setStepSound(soundTypeGrass);
	this.disableStats();
	GameRegistry.registerBlock(this, name);
	amountOfStages = stages;
	cropName = crop;
}


@Override
protected boolean canPlaceBlockOn(Block block) {
	return block == Blocks.farmland;
}

@Override
public void updateTick(World w, int x, int y, int z, Random r) {
	super.updateTick(w, x, y, z, r);
	if(w.getBlockLightValue(x, y + 1, z) >= 9) {
		int l = w.getBlockMetadata(x, y, z);
		if(l < amountOfStages) {
			float f = this.grow(w, x, y, z);
			if(r.nextInt((int)(25.0F / f) + 1) == 0) {
				++l;
				w.setBlockMetadataWithNotify(x, y, z, l, 2);
			}
		}
	}
}

public void boneMeal(World w, int x, int y, int z) {
	int meta = w.getBlockMetadata(x, y, z) + MathHelper.getRandomIntegerInRange(w.rand, 2, 5);
	if(meta > amountOfStages) 
		meta = amountOfStages;
	w.setBlockMetadataWithNotify(x, y, z, meta, 2);
}

private float grow(World w, int x, int y, int z) {
	float f = 1.0F;
	Block block = w.getBlock(x, y, z - 1);
	Block block1 = w.getBlock(x, y, z + 1);
	Block block2 = w.getBlock(x - 1, y, z);
	Block block3 = w.getBlock(x + 1, y, z);
	Block block4 = w.getBlock(x - 1, y, z - 1);
	Block block5 = w.getBlock(x + 1, y, z - 1);
	Block block6 = w.getBlock(x + 1, y, z + 1);
	Block block7 = w.getBlock(x - 1, y, z + 1);
	boolean flag = block2 == this || block3 == this;
	boolean flag1 = block == this || block1 == this;
	boolean flag2 = block4 == this || block5 == this || block6 == this || block7 == this;
	for(int l = x - 1; l <= x + 1; ++l) {
		for(int i1 = z - 1; i1 <= z + 1; ++i1) {
			float f1 = 0.0F;
			if(w.getBlock(l, y - 1, i1).canSustainPlant(w, l, y - 1, i1, ForgeDirection.UP, this)) {
				f1 = 1.0F;
				if (w.getBlock(l, y - 1, i1).isFertile(w, l, y - 1, i1))
					f1 = 3.0F;
			}
			if(l != x || i1 != z)
				f1 /= 4.0F;
			f += f1;
		}
	}
	if(flag2 || flag && flag1)
		f /= 2.0F;		
	return f;
}

@Override
@SideOnly(Side.CLIENT)
public IIcon getIcon(int p_149691_1_, int meta) {
	if (meta < 0 || meta > amountOfStages) meta = amountOfStages;
	return this.icons[meta];
}

@Override
public boolean func_149851_a(World w, int x, int y, int z, boolean b) {
	return w.getBlockMetadata(x, y, z) != amountOfStages;
}

@Override
public boolean func_149852_a(World w, Random r, int x, int y, int z) {
	return true;
}

@Override
public void dropBlockAsItemWithChance(World w, int x, int y, int z, int m, float f, int i) {
	super.dropBlockAsItemWithChance(w, x, y, z, m, f, 0);
}

@Override
public Item getItemDropped(int meta, Random r, int i) {
	return meta == amountOfStages ? this.getDropItem() : this.getSeeds();
}

@Override
public int quantityDropped(Random r) {
	return r.nextInt(2) + 1;
}

public abstract Item getDropItem();
public abstract Item getSeeds();

@Override
@SideOnly(Side.CLIENT)
public Item getItem(World w, int x, int y, int z) {
	return this.getSeeds();
}

@Override
@SideOnly(Side.CLIENT)
public void registerBlockIcons(IIconRegister icon) {
	this.icons = new IIcon[amountOfStages + 1];
	for(int i = 0; i < this.icons.length; ++i)
		this.icons[i] = icon.registerIcon("MODID:" + cropName + "_" + i);
}

@Override
public void func_149853_b(World w, Random r, int x, int y, int z) {
	this.boneMeal(w, x, y, z);
}

@Override
public ArrayList<ItemStack> getDrops(World world, int x, int y, int z, int metadata, int fortune) {
	ArrayList<ItemStack> ret = super.getDrops(world, x, y, z, metadata, fortune);
	if(metadata >= amountOfStages) {
		for(int i = 0; i < 3 + fortune; i++) {
			if(world.rand.nextInt(15) <= metadata)
				ret.add(new ItemStack(this.getSeeds(), 1, 0));
		}
	}
	return ret;
}
}

 

 

 

After you read the code, you should know how to use it.

Former developer for DivineRPG, Pixelmon and now the maker of Essence of the Gods

Posted

Here is a file that i use, it works great and all you have to do is just extend the file for your new crop and fill in the blanks :)

 

 

 

package your.mod;

import java.util.ArrayList;
import java.util.Random;

import net.minecraft.block.Block;
import net.minecraft.block.BlockBush;
import net.minecraft.block.IGrowable;
import net.minecraft.client.renderer.texture.IIconRegister;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.IIcon;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;

public abstract class BlockModCrop extends BlockBush implements IGrowable {

@SideOnly(Side.CLIENT)
private IIcon[] icons;
private int amountOfStages;
private String cropName;

public BlockModCrop(String name, int stages, String crop) {
	this.setTickRandomly(true);
	float f = 0.5F;
	this.setBlockBounds(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, 0.25F, 0.5F + f);
	this.setCreativeTab((CreativeTabs)null);
	this.setHardness(0.0F);
	this.setStepSound(soundTypeGrass);
	this.disableStats();
	GameRegistry.registerBlock(this, name);
	amountOfStages = stages;
	cropName = crop;
}


@Override
protected boolean canPlaceBlockOn(Block block) {
	return block == Blocks.farmland;
}

@Override
public void updateTick(World w, int x, int y, int z, Random r) {
	super.updateTick(w, x, y, z, r);
	if(w.getBlockLightValue(x, y + 1, z) >= 9) {
		int l = w.getBlockMetadata(x, y, z);
		if(l < amountOfStages) {
			float f = this.grow(w, x, y, z);
			if(r.nextInt((int)(25.0F / f) + 1) == 0) {
				++l;
				w.setBlockMetadataWithNotify(x, y, z, l, 2);
			}
		}
	}
}

public void boneMeal(World w, int x, int y, int z) {
	int meta = w.getBlockMetadata(x, y, z) + MathHelper.getRandomIntegerInRange(w.rand, 2, 5);
	if(meta > amountOfStages) 
		meta = amountOfStages;
	w.setBlockMetadataWithNotify(x, y, z, meta, 2);
}

private float grow(World w, int x, int y, int z) {
	float f = 1.0F;
	Block block = w.getBlock(x, y, z - 1);
	Block block1 = w.getBlock(x, y, z + 1);
	Block block2 = w.getBlock(x - 1, y, z);
	Block block3 = w.getBlock(x + 1, y, z);
	Block block4 = w.getBlock(x - 1, y, z - 1);
	Block block5 = w.getBlock(x + 1, y, z - 1);
	Block block6 = w.getBlock(x + 1, y, z + 1);
	Block block7 = w.getBlock(x - 1, y, z + 1);
	boolean flag = block2 == this || block3 == this;
	boolean flag1 = block == this || block1 == this;
	boolean flag2 = block4 == this || block5 == this || block6 == this || block7 == this;
	for(int l = x - 1; l <= x + 1; ++l) {
		for(int i1 = z - 1; i1 <= z + 1; ++i1) {
			float f1 = 0.0F;
			if(w.getBlock(l, y - 1, i1).canSustainPlant(w, l, y - 1, i1, ForgeDirection.UP, this)) {
				f1 = 1.0F;
				if (w.getBlock(l, y - 1, i1).isFertile(w, l, y - 1, i1))
					f1 = 3.0F;
			}
			if(l != x || i1 != z)
				f1 /= 4.0F;
			f += f1;
		}
	}
	if(flag2 || flag && flag1)
		f /= 2.0F;		
	return f;
}

@Override
@SideOnly(Side.CLIENT)
public IIcon getIcon(int p_149691_1_, int meta) {
	if (meta < 0 || meta > amountOfStages) meta = amountOfStages;
	return this.icons[meta];
}

@Override
public boolean func_149851_a(World w, int x, int y, int z, boolean b) {
	return w.getBlockMetadata(x, y, z) != amountOfStages;
}

@Override
public boolean func_149852_a(World w, Random r, int x, int y, int z) {
	return true;
}

@Override
public void dropBlockAsItemWithChance(World w, int x, int y, int z, int m, float f, int i) {
	super.dropBlockAsItemWithChance(w, x, y, z, m, f, 0);
}

@Override
public Item getItemDropped(int meta, Random r, int i) {
	return meta == amountOfStages ? this.getDropItem() : this.getSeeds();
}

@Override
public int quantityDropped(Random r) {
	return r.nextInt(2) + 1;
}

public abstract Item getDropItem();
public abstract Item getSeeds();

@Override
@SideOnly(Side.CLIENT)
public Item getItem(World w, int x, int y, int z) {
	return this.getSeeds();
}

@Override
@SideOnly(Side.CLIENT)
public void registerBlockIcons(IIconRegister icon) {
	this.icons = new IIcon[amountOfStages + 1];
	for(int i = 0; i < this.icons.length; ++i)
		this.icons[i] = icon.registerIcon("MODID:" + cropName + "_" + i);
}

@Override
public void func_149853_b(World w, Random r, int x, int y, int z) {
	this.boneMeal(w, x, y, z);
}

@Override
public ArrayList<ItemStack> getDrops(World world, int x, int y, int z, int metadata, int fortune) {
	ArrayList<ItemStack> ret = super.getDrops(world, x, y, z, metadata, fortune);
	if(metadata >= amountOfStages) {
		for(int i = 0; i < 3 + fortune; i++) {
			if(world.rand.nextInt(15) <= metadata)
				ret.add(new ItemStack(this.getSeeds(), 1, 0));
		}
	}
	return ret;
}
}

 

 

 

After you read the code, you should know how to use it.

 

This is pretty good. I just have to add and mess with getRenderType and it should be working fine. Also, I'm not sure why you felt the need to register the block within the custom crop class. Don't people usually do that in the main? Anyway, a bit unconventional, but it works.

 

So how do I add the texture?

 

EDIT: Oh, never mind. I saw "MODID:" in registerBlockIcons and didn't notice the quotes, so I assumed that was a variable. So I just replaced that part with my mod id and it works fine. Thanks!

Posted

You can register it either way, but i like to do it inside of the blocks/item class because it saves so much code haha

 

Oh, I know you CAN, but I've never seen anyone do that before. I figured it was against convention or something.

Anyway, thanks for the help!

Posted

You can register it either way, but i like to do it inside of the blocks/item class because it saves so much code haha

 

Oh, I know you CAN, but I've never seen anyone do that before. I figured it was against convention or something.

Anyway, thanks for the help!

 

I think the issue with registering your block (or item or entity, etc) in their own constructor is that you potentially lose control of the order of registration, or at least you have to be more conscious of how the instantiation order will affect registration order.

 

Sometimes you'll need to control the order.  For example with ItemSeeds it is important to have the related blocks registered first.  You can control it with instantiation, but many people might be tempted to still instantiate in the field declaration area of the main class.

 

Anyway, just something to keep in mind if you go the route of registering classes within their own constructors.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted

Please see this article on why it is bad to pass 'this' outside the constructor.

 

You should not call registry or any method that uses 'this' when constructing.

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
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
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.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.