I haven't seen any tutorials on the basics of 1.7.2 yet, so I figured I'd create my own. I'm still learning how 1.7.2 works myself, so please let me know if there's better ways of doing this or if I made an mistakes and I'll adjust the tutorial.
Also, make sure you're using the latest recommended release for Forge, currently 10.12.0.1024. If you try using earlier version of Forge 1.7, many of the method names will likely not be the same. If you need help setting up your programming environment, that describes the process.
1. Add new Block and Creative Tab
First, here's a very basic mod class to begin with:
package mymod;
import net.minecraft.block.Block;
import net.minecraft.creativetab.CreativeTabs;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.registry.GameRegistry;
@Mod(modid = MyMod.MODID, version = MyMod.VERSION)
public class MyMod
{
public static final String MODID = "mymod";
public static final String VERSION = "0.1";
public static Block blockTest;
public static CreativeTabs tabMyMod = new CreativeTabsMyMod("MyMod");
@EventHandler
public void preInit(FMLPreInitializationEvent event)
{
blockTest = new BlockTest().setBlockName("blockTest");
GameRegistry.registerBlock(blockTest, blockTest.getUnlocalizedName().substring(5));
}
}
You can adjust these two lines to provide a unique Mod ID and a version for your mod. I've been told the Mod ID must be all lowercase letters now.
public static final String MODID = "mymod";
public static final String VERSION = "0.1";
This line declares the block:
public static Block blockTest;
This line sets up a new creative tab:
public static CreativeTabs tabMyMod = new CreativeTabsMyMod("MyMod");
And these two lines are used to register the block using the unlocalized name "blockTest":
blockTest = new BlockTest().setBlockName("blockTest");
GameRegistry.registerBlock(blockTest, blockTest.getUnlocalizedName().substring(5));
If you're upgrading from previous versions of MC, note that blocks must now be registered inside a FMLPreInitializationEvent, FMLInitializationEvent no longer works.
Now we need two more classes, one for the block, and one for the creative tab. I'll start with the block:
This is about as basic as you can get for a block, super(Material.ground); sets the material type for the block and this.setCreativeTab(MyMod.tabMyMod); sets which creative tab that you see the block in.
Finally, here's the code to set up a creative tab:
package mymod;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
public class CreativeTabsMyMod extends CreativeTabs {
public CreativeTabsMyMod(String tabLabel)
{
super(tabLabel);
}
@Override
@SideOnly(Side.CLIENT)
public Item getTabIconItem()
{
return Item.getItemFromBlock(Blocks.dirt);
}
}
The part you probably want to change is Item.getItemFromBlock(Blocks.dirt). The getTabIconItem() method returns an Item and uses its icon for the creative tab. I wanted to use the dirt block icon, so I used Item.getItemFromBlock() to change the dirt block (Blocks.dirt) into an Item type.
That's it for now! You may have noticed this mod is missing some rather important things, such as an icon for the block and localized names. I should be adding those to the tutorial later as I discover how to set all that up myself.
2. Language Localization
If you try running the mod, you'll notice the block and the creative tab have odd names in game. The block will be called something like tile.blockTest.name, where "blockTest" is the unlocalized name for the block. Because minecraft is translated into many many different languages, the name for the block that's used in the code doesn't use any specific language. You have to add a file to tell MC how to translate unlocalized names into whichever language the user has chosen, a process known as language localization.
Other tutorials say you're supposed to use different folders for the language files, but there's only one location I've gotten able to work with forge v1024. Within your forge directory navigate to "src\main\resources\" and create a folder named assets. Within this folder create another folder with your Mod ID as the name, and then within that folder, create a folder named "lang". Using the code from the first tutorial, it should look something like this:
The lang folder is where you'll be putting all your localization files. For instance, I speak US English, so I'll want to create a localization file named "en_US.lang". For other language codes, you can check "forge-directory\eclipse\assets\lang" for a long list of examples. Within the localization file you should have something that looks like this:
tile.blockTest.name=Test Block
itemGroup.MyMod=My Mod
tile.blockTest.name uses the unlocalized name of the block we added in the first tutorial, and "Test Block" is the name we want to display in game. itemGroup.MyMod is the unlocalized name of the creative tab, and if you're not sure about a specific unlocalized name, you can always hover your mouse over an object in game and if it hasn't been named yet, it will give you the unlocalized name.
If you've done everything correctly, you should be able to start the game now and see the new names you've set.
3. Add a texture to your block
If you've followed the tutorial so far, your block should have a magenta and black checkered pattern in game. That's the default texture that is set when MC can't find any other texture to use for the block. Setting your own texture is relatively simple, we just have to declare a new variable and override a couple methods from the Block class.
Update: If you only have a single block texture you want to use, this tutorial is a bit of overkill. To make things much simpler you can use the method setBlockTextureName(MyMod.MODID + ":" + "blockTest") when registering the block, or within your block's class constructor. If you do that, you can skip the rest of this tutorial, which sets you up for using multiple textures with a block. Thanks to Sequiturian for the tip!
First, in the BlockTest class you want to add:
@SideOnly(Side.CLIENT)
protected IIcon blockIcon;
This creates a variable called blockIcon to store the texture in. Also, notice the @SideOnly(Side.CLIENT). Minecraft separates the client and server, and since the graphics are handled on the client side, you add this line so they're only loaded on the client.
This registers the texture, and lets the client know where to find the texture. If you're using the code from the tutorial so far, it will use the following location for textures:
And it will search for a file named "blockTest.png" in that directory to use as the texture. Note that "mymod" is what I set the mod ID to in the first tutorial, and "blockTest" is the unlocalized name for the block. Finally, we need this last method:
@SideOnly(Side.CLIENT)
@Override
public IIcon getIcon(int p_149691_1_, int p_149691_2_)
{
return blockIcon;
}
This method returns the actual texture we want to use for the block, which was set in the registerBlockIcons() method. This should be all you need to get block textures working, though this only works properly for very simple blocks. Blocks with different textures per side, and blocks with different textures based upon metadata will not work properly. I believe the two parameters on the getIcon() method will give you the side and the metadata, though I'll save how to use those for another tutorial.
The class for the block we added should now look something like this:
First, I'm gonna share a quick tip on how to find out on your own how a method works. I want to know what the two parameters on getIcon(int p_149691_1_, int p_149691_2_) do, so I'll use
in the getIcon() method to output the values for each parameter to the console in Eclipse. Turns out p_149691_1_ counts from 0 to 5, while p_149691_2_ stays zero. I know the block texture can be set differently for the 6 different sides of the block, and I haven't set the metadata, so that should be zero. It should now be obvious which one I need to use to set sided textures.
Note that I'm adding '+ "Top"' to the end of the string, this means it will look for blockTestTop.png in the block texture directory.
Lastly, I need to change the getIcon() method so it returns blockIconTop for the top side of the block. I looked in the BlockGrass class to find that "1" corresponds to that side of a block. Here's my new method, and I've changed the parameters to make it easier to understand:
@SideOnly(Side.CLIENT)
@Override
public IIcon getIcon(int side, int metadata)
{
if (side == 1) {
return blockIconTop;
} else {
return blockIcon;
}
}
If you add a texture image named blockTestTop.png to your block texture directory ( forge-directory\src\main\resources\assets\mymod\textures\blocks ), you should now see that texture on the top side of the block when running MC.
Here's what my full BlockTest class looks like now:
If you understood the process of adding a block in the first tutorial, adding a new item should be cake. I'm going to use the same basic mod code I used in the first tutorial, and add this line to declare an object of the Item type named itemTest. It should go right next to where blockTest was declared.
public static Item itemTest;
Next I'll add this line inside the preInit() method. You can also just use Item() instead of ItemTest() if you don't want to use a custom class for your new item.
itemTest = new ItemTest().setUnlocalizedName("itemTest").setTextureName(MyMod.MODID + ":" + "itemTest");
I've gone over how the unlocalized name works in previous tutorials, so I'll focus upon the setTextureName() method. It takes a string in the following format "ModID:texture-name", which in this case is "mymod:itemTest". This tells minecraft where to look for your textures, "mymod" is the assets directory, and since it's looking for an item texture, its going to search within the "textures/items" directory within "mymod". Within that directory, it's going to look for an image named "itemTest.png", so the full path should be along the lines of forge-directory\src\main\resources\assets\mymod\textures\items\itemTest.png .
One more line to add to our mod file within the preInit() method:
This is what registers the item, i.e. the part that adds your item into the game itself. Finally, we need to create a new class file named ItemTest, I kept mine super-simple, all it does is set which creative tab to use.
package mymod;
import net.minecraft.item.Item;
public class ItemTest extends Item{
protected ItemTest() {
this.setCreativeTab(MyMod.tabMyMod);
}
}
And that's it! You should now have a new item in-game. Here's my full mod class now if you need to refer to it:
package mymod;
import net.minecraft.block.Block;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.registry.GameRegistry;
@Mod(modid = MyMod.MODID, version = MyMod.VERSION)
public class MyMod
{
public static final String MODID = "mymod";
public static final String VERSION = "0.1";
public static Block blockTest;
public static Item itemTest;
public static CreativeTabs tabMyMod = new CreativeTabsMyMod("MyMod");
@EventHandler
public void preInit(FMLPreInitializationEvent event)
{
blockTest = new BlockTest().setBlockName("blockTest");
itemTest = new ItemTest().setUnlocalizedName("itemTest").setTextureName(MyMod.MODID + ":" + "itemTest");
GameRegistry.registerBlock(blockTest, blockTest.getUnlocalizedName().substring(5));
GameRegistry.registerItem(itemTest, itemTest.getUnlocalizedName().substring(5));
}
}
Whoops, I seem to have forgotten something important that I covered in a previous tutorial, notice what it is? When I load up the game, my item is named item.itemTest.name, the name hasn't been localized! No worries, I just need to add this line to my language localization file: item.itemTest.name=Item Test
6. Add an entity
It takes a few lines of code to add an entity, and if you've got a lot of entities it can be a pain to write out the code over and over again. To streamline the process, I use a method to take care of all the repetitive work which I've inserted into my mod class:
public static void registerEntity(Class entityClass, String name)
{
int entityID = EntityRegistry.findGlobalUniqueEntityId();
long seed = name.hashCode();
Random rand = new Random(seed);
int primaryColor = rand.nextInt() * 16777215;
int secondaryColor = rand.nextInt() * 16777215;
EntityRegistry.registerGlobalEntityID(entityClass, name, entityID);
EntityRegistry.registerModEntity(entityClass, name, entityID, instance, 64, 1, true);
EntityList.entityEggs.put(Integer.valueOf(entityID), new EntityList.EntityEggInfo(entityID, primaryColor, secondaryColor));
}
The first line within registerEntity() is to get a unique ID for the entity. The next four lines generate random colors for the spawn egg using the entity's name as a random seed. If you want to set colors yourself, you could easily adjust the method to take the primary and secondary colors as method parameters.
These lines register the entity ID, register the entity itself, and add a spawn egg respectively. It's mostly the same as MC 1.6, though I had to change EntityEggInfo to EntityList.EntityEggInfo. You may have noticed we haven't declared the instance variable yet, so let's add this line to our mod class. Put it near the top, but underneath the MODID string declaration.
@Instance(MODID)
public static MyMod instance;
One more thing the mod class needs, and that's to actually call the method we just created. Put this line within the preInit() method:
registerEntity(EntityTest.class, "entityTest");
Okay, now we need to make the EntityTest class that I just referred to for our entity. Here's some very basic code that's simplified to the point of not really being practical:
package mymod;
import net.minecraft.entity.monster.EntityMob;
import net.minecraft.world.World;
public class EntityTest extends EntityMob{
public EntityTest(World par1World) {
super(par1World);
}
}
This class extends EntityMob, which are the hostile monster types of entities. EntityCreature, EntityAnimal, and EntityLiving are all examples of other entity types that you can extend.
Finally, we give a localized name to our new entity by putting this into our language localization file: entity.entityTest.name=Entity Test
That should be it! If you start minecraft, you should see a new spawn egg under the Miscellaneous creative tab. Using it should create a retarded white box within the game. Not very useful, but not bad to begin with! I'll add more tutorials about making entities smarter and more attractive.
7. Give entity a model
If you're not very comfortable coding Java, you may want to stick to easier things like blocks and items. These tutorials are going to start getting a bit more complicated now.
If you want to mod Minecraft properly, you have to understand how the client-server model works. All the rendering, the parts of the code that display graphics, happen on the client side. This isn't something the server needs to deal with at all. To separate the client and server code we're now going to create proxies, and then use the client proxy to give a proper model to our entity.
First, you'll need this in your main mod class:
@SidedProxy(clientSide="mymod.proxy.ClientProxy", serverSide="mymod.proxy.CommonProxy")
public static CommonProxy proxy;
This tells Forge which classes we want to use for the client and server proxies. Notice it refers to a new java package, "mymod.proxy" so go ahead and create that now. Next create the server proxy class, CommonProxy, and paste this code inside:
package mymod.proxy;
public class CommonProxy {
public void registerRenderers() {
// Nothing here as the server doesn't render graphics or entities!
}
}
Not much there since we don't need to do anything with the server side at the moment. Next create a new class named ClientProxy and paste this code inside:
package mymod.proxy;
import net.minecraft.client.model.ModelBiped;
import mymod.EntityTest;
import mymod.RenderTest;
import cpw.mods.fml.client.registry.RenderingRegistry;
public class ClientProxy extends CommonProxy{
@Override
public void registerRenderers() {
RenderingRegistry.registerEntityRenderingHandler(EntityTest.class, new RenderTest(new ModelBiped(), 0.5F));
}
}
The RenderingRegistry.registerEntityRenderingHandler() method tells MC how to render your new entity. The RenderTest class will be used to render EntityTest entities and it will use the ModelBiped class for the model. ModelBiped is the basic player model. Also, the float that's the second parameter in RenderTest determines the shadow size.
Now we'll need to add a call to registerRenderers() within our main mod class. I put this line at the end of the preInit() method:
proxy.registerRenderers();
Next, create the RenderTest class, and paste this code inside:
package mymod;
import net.minecraft.client.model.ModelBiped;
import net.minecraft.client.renderer.entity.RenderBiped;
import net.minecraft.entity.Entity;
import net.minecraft.util.ResourceLocation;
public class RenderTest extends RenderBiped {
private static final ResourceLocation textureLocation = new ResourceLocation(MyMod.MODID + ":" + "textures/models/entityTest.png");
public RenderTest(ModelBiped model, float shadowSize) {
super(model, shadowSize);
}
@Override
protected ResourceLocation getEntityTexture(Entity par1Entity)
{
return textureLocation;
}
}
The class constructor is simple enough, we just pass the parameters on to the RenderBiped class, the superclass of RenderTest. The rest of this code is used to set the texture, getEntityTexture() returns textureLocation, which *gasp* holds the location of the texture. We set it similar to the same way we set block and item textures, but we use a ResourceLocation type and I added some more information on what directory to find the texture in.
Since I'm using the same model the player uses, any player skin should work fine as a texture for my entity. I'm just testing things out, so I'm going to use the Steve skin, which will go in the location we set using ResourceLocation(MyMod.MODID + ":" + "textures/models/entityTest.png") . If you haven't tweaked your MODID, the path to the texture should be something like this: forge-directory\src\main\resources\assets\mymod\textures\models\entityTest.png
And that should be it, if you start minecraft and spawn the entity, it should now be using the basic biped model with the Steve skin.
8. Entity attributes and AI
If you used the previous tutorials to create an entity, you may have noticed that when you spawn it, it moves painfully slow. We need to set entity attributes, so go ahead and add this code to your entity's class:
This code should be fairly self-explanatory, you get the attribute, for instance maxHealth, and then use setBaseValue() to set the value. I should explain knockbackRestistance some, which ranges from 0.0D to 1.0D (the D stands for double, a primitive data type). 0.0D means 0% knockback resistance, so the entity will be knocked back every hit. 1.0D means 100% knockback resistance, so the entity will never be knocked back.
An important thing to understand abbout attributes is that they're saved per entity. This means you can do things like set them to random values or even alter an entity's attributes after it's been spawned, though I wont go in to how to do that here.
After adding attributes, it may be that you're happy with the way your entity behaves, and in that case there's no reason to add any "advanced" artifical intelligence (AI). However, if you do want more control over your entity's behavior you'll need to add this method:
public boolean isAIEnabled()
{
return true;
}
Now this method by itself will just make your entity stand there and stare straight forward. When you've got AI enabled, you have to tell your entity specifically how to behave. We'll do that by adding AI tasks to your entity's class constructor. Here's what I used:
this.tasks.addTask(1, new EntityAISwimming(this));
this.tasks.addTask(2, new EntityAIAttackOnCollide(this, EntityPlayer.class, 1.2D, false));
this.tasks.addTask(3, new EntityAIWander(this, 1.0D));
this.tasks.addTask(4, new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F));
this.tasks.addTask(5, new EntityAILookIdle(this));
this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false));
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityPlayer.class, 0, true));
The numbers that are the first parameter of the addTask method determine the priority of the task. We put EntityAISwimming as 1, since we don't want our entity to drown in water. The EntityAIAttackOnCollide is the basic attack type that mobs like zombies and spiders use. EntityAIWander tells the mob to wander around when it's not attacking. I'll let you figure out what EntityAIWatchClosest does, and EntityAILookIdle makes the mob look around when it's just standing there.
Then there's the target tasks, which lets the entity know how to choose attack targets. EntityAIHurtByTarget will target any mob that does damage to our entity, and EntityAINearestAttackableTarget will target any nearby entity that matches the second parameter, in this case EntityPlayer.class.
That should be it, if you run the game your entity should now behave like a regular mob. One thing to be careful about is any mobs that were created in your game before you changed attributes around. You'll have to spawn new entities for them to use the new attributes you set.
Hey, this is a great tutorial! I'm brand new at modding, and I actually discovered most of this on my own the hard way by following a 1.6 tutorial and messing around until I figured it out... but it's awesome to get confirmation that I did most of it correctly!
please let the next topic be about adding textures to blocks. I've tried everything. I know my textures are in the correct directory, but I'm sure that my String isn't saying what I think it's saying.
Also, what's with this substring(5) stuff that I've been seeing. After looking it up it talks about replacing text in strings?
please let the next topic be about adding textures to blocks. I've tried everything. I know my textures are in the correct directory, but I'm sure that my String isn't saying what I think it's saying.
Also, what's with this substring(5) stuff that I've been seeing. After looking it up it talks about replacing text in strings?
When you use blockTest.getUnlocalizedName() I believe it returns the string tile.blockTest . Using the substring(5) method trims the first 5 characters in the string so you just get the unlocalized named without the "tile." part.
And textures for blocks is what I plan on doing for my next tutorial, just as soon as I figure out how to get it working myself.
I haven't seen any tutorials on the basics of 1.7.2 yet, so I figured I'd create my own. I'm still learning how 1.7.2 works myself, so please let me know if there's better ways of doing this or if I made an mistakes and I'll adjust the tutorial.
Also, make sure you're using the latest recommended release for Forge, currently 10.12.0.1024. If you try using earlier version of Forge 1.7, many of the method names will likely not be the same. If you need help setting up your programming environment, that describes the process.
1. Add new Block and Creative Tab
First, here's a very basic mod class to begin with:
package mymod;
import net.minecraft.block.Block;
import net.minecraft.creativetab.CreativeTabs;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.registry.GameRegistry;
@Mod(modid = MyMod.MODID, version = MyMod.VERSION)
public class MyMod
{
public static final String MODID = "mymod";
public static final String VERSION = "0.1";
public static Block blockTest;
public static CreativeTabs tabMyMod = new CreativeTabsMyMod("MyMod");
@EventHandler
public void preInit(FMLPreInitializationEvent event)
{
blockTest = new BlockTest().setBlockName("blockTest");
GameRegistry.registerBlock(blockTest, blockTest.getUnlocalizedName().substring(5));
}
}
You can adjust these two lines to provide a unique Mod ID and a version for your mod. I've been told the Mod ID must be all lowercase letters now.
public static final String MODID = "mymod";
public static final String VERSION = "0.1";
This line declares the block:
public static Block blockTest;
This line sets up a new creative tab:
public static CreativeTabs tabMyMod = new CreativeTabsMyMod("MyMod");
And these two lines are used to register the block using the unlocalized name "blockTest":
blockTest = new BlockTest().setBlockName("blockTest");
GameRegistry.registerBlock(blockTest, blockTest.getUnlocalizedName().substring(5));
If you're upgrading from previous versions of MC, note that blocks must now be registered inside a FMLPreInitializationEvent, FMLInitializationEvent no longer works.
Now we need two more classes, one for the block, and one for the creative tab. I'll start with the block:
This is about as basic as you can get for a block, super(Material.ground); sets the material type for the block and this.setCreativeTab(MyMod.tabMyMod); sets which creative tab that you see the block in.
Finally, here's the code to set up a creative tab:
package mymod;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
public class CreativeTabsMyMod extends CreativeTabs {
public CreativeTabsMyMod(String tabLabel)
{
super(tabLabel);
}
@Override
@SideOnly(Side.CLIENT)
public Item getTabIconItem()
{
return Item.getItemFromBlock(Blocks.dirt);
}
}
The part you probably want to change is Item.getItemFromBlock(Blocks.dirt). The getTabIconItem() method returns an Item and uses its icon for the creative tab. I wanted to use the dirt block icon, so I used Item.getItemFromBlock() to change the dirt block (Blocks.dirt) into an Item type.
That's it for now! You may have noticed this mod is missing some rather important things, such as an icon for the block and localized names. I should be adding those to the tutorial later as I discover how to set all that up myself.
2. Language Localization
If you try running the mod, you'll notice the block and the creative tab have odd names in game. The block will be called something like tile.blockTest.name, where "blockTest" is the unlocalized name for the block. Because minecraft is translated into many many different languages, the name for the block that's used in the code doesn't use any specific language. You have to add a file to tell MC how to translate unlocalized names into whichever language the user has chosen, a process known as language localization.
Other tutorials say you're supposed to use different folders for the language files, but there's only one location I've gotten able to work with forge v1024. Within your forge directory navigate to "src\main\resources\" and create a folder named assets. Within this folder create another folder with your Mod ID as the name, and then within that folder, create a folder named "lang". Using the code from the first tutorial, it should look something like this:
The lang folder is where you'll be putting all your localization files. For instance, I speak US English, so I'll want to create a localization file named "en_US.lang". For other language codes, you can check "forge-directory\eclipse\assets\lang" for a long list of examples. Within the localization file you should have something that looks like this:
tile.blockTest.name=Test Block
itemGroup.MyMod=My Mod
tile.blockTest.name uses the unlocalized name of the block we added in the first tutorial, and "Test Block" is the name we want to display in game. itemGroup.MyMod is the unlocalized name of the creative tab, and if you're not sure about a specific unlocalized name, you can always hover your mouse over an object in game and if it hasn't been named yet, it will give you the unlocalized name.
If you've done everything correctly, you should be able to start the game now and see the new names you've set.
3. Add a texture to your block
If you've followed the tutorial so far, your block should have a magenta and black checkered pattern in game. That's the default texture that is set when MC can't find any other texture to use for the block. Setting your own texture is relatively simple, we just have to declare a new variable and override a couple methods from the Block class.
First, in the BlockTest class you want to add:
@SideOnly(Side.CLIENT)
protected IIcon blockIcon;
This creates a variable called blockIcon to store the texture in. Also, notice the @SideOnly(Side.CLIENT). Minecraft separates the client and server, and since the graphics are handled on the client side, you add this line so they're only loaded on the client.
This registers the texture, and lets the client know where to find the texture. If you're using the code from the tutorial so far, it will use the following location for textures:
And it will search for a file named "blockTest.png" in that directory to use as the texture. Note that "mymod" is what I set the mod ID to in the first tutorial, and "blockTest" is the unlocalized name for the block. Finally, we need this last method:
@SideOnly(Side.CLIENT)
@Override
public IIcon getIcon(int p_149691_1_, int p_149691_2_)
{
return blockIcon;
}
This method returns the actual texture we want to use for the block, which was set in the registerBlockIcons() method. This should be all you need to get block textures working, though this only works properly for very simple blocks. Blocks with different textures per side, and blocks with different textures based upon metadata will not work properly. I believe the two parameters on the getIcon() method will give you the side and the metadata, though I'll save how to use those for another tutorial.
The class for the block we added should now look something like this:
First, I'm gonna share a quick tip on how to find out on your own how a method works. I want to know what the two parameters on getIcon(int p_149691_1_, int p_149691_2_) do, so I'll use
in the getIcon() method to output the values for each parameter to the console in Eclipse. Turns out p_149691_1_ counts from 0 to 5, while p_149691_2_ stays zero. I know the block texture can be set differently for the 6 different sides of the block, and I haven't set the metadata, so that should be zero. It should now be obvious which one I need to use to set sided textures.
Note that I'm adding '+ "Top"' to the end of the string, this means it will look for blockTestTop.png in the block texture directory.
Lastly, I need to change the getIcon() method so it returns blockIconTop for the top side of the block. I looked in the BlockGrass class to find that "1" corresponds to that side of a block. Here's my new method, and I've changed the parameters to make it easier to understand:
@SideOnly(Side.CLIENT)
@Override
public IIcon getIcon(int side, int metadata)
{
if (side == 1) {
return blockIconTop;
} else {
return blockIcon;
}
}
If you add a texture image named blockTestTop.png to your block texture directory ( forge-directory\src\main\resources\assets\mymod\textures\blocks ), you should now see that texture on the top side of the block when running MC.
Here's what my full BlockTest class looks like now:
Hey, is the localization file a class in eclipse, or like a notepad file, do we have to write anything inside of the file?...I am confused, I am also new to modding. This tutorial is AWESOME!
Hey, is the localization file a class in eclipse, or like a notepad file, do we have to write anything inside of the file?...I am confused, I am also new to modding. This tutorial is AWESOME!
It's "like a notepad file". If you're using windows, you can create a new text document, then rename it to en_US.lang. Make sure you've set things up to not hide file extensions, or it will still be a text file. You must put the names you want your custom blocks, items, entities and creative tab to use inside that file, or they'll be named things like tile.blockTest.name within the game.
It's "like a notepad file". If you're using windows, you can create a new text document, then rename it to en_US.lang. Make sure you've set things up to not hide file extensions, or it will still be a text file. You must put the names you want your custom blocks, items, entities and creative tab to use inside that file, or they'll be named things like tile.blockTest.name within the game.
You can also create/edit this within your IDE. It should be included in your project workspace.
P.S. Great job on the tutorials. Thanks for taking my request. I'll have others shortly Also, would you want to post a few other snippet tutorials that I've figured out by bumbling around? I can post the code and you can do the tutorial stuffs
EDIT: Got one, World Gen. Examples of Ores and Plants. Hey, some ppl need to generate plants. lol
The ".substring(5)" Seems to make my minecraft crash when i run. I removed it and now it works. Peculiar.
It seems to me that you may have been using another name or string that didn't include the "tile." prefix. But even then you shouldn't have a crashed client over that. Maybe you were using .getUnlocalizedName() in your block initialization? That breaks stuff, but I still don't think it would crash, just error the texture.
P.S. Great job on the tutorials. Thanks for taking my request. I'll have others shortly Also, would you want to post a few other snippet tutorials that I've figured out by bumbling around? I can post the code and you can do the tutorial stuffs
EDIT: Got one, World Gen. Examples of Ores and Plants. Hey, some ppl need to generate plants. lol
Sure! I'd love to see more examples of 1.7.2 code, there's a whole lot I'm still learning myself. I'm not sure how much I'll be getting into the world gen aspects for this tutorial though. My current plan is to do block metadata, tile entities, mob entities, item creation and packet handling tutorials.
Also, where did you get this information? I've searched all over the interwebs and I couldn't find a thing!
It's been a combination of what I already knew about modding 1.5 and 1.6, searching the internet, trial and error, plus digging through the code. A lot of it I've had to figure out myself. Some of the earlier 1.7 tutorials were a good start, though you usually have to modify them some to get working.
is it the same for texturing items, I am having some problems texturing a food I made, it has the correct name and everything, but the texture doesn't work o/
is it the same for texturing items, I am having some problems texturing a food I made, it has the correct name and everything, but the texture doesn't work o/
^^that is one of my food classes, i replaced the "blockIcon" with itemIcon but that didn't work
I actually just added a tutorial on how to do this while you were writing your comment. =)
I tried adding item textures a few different ways, but the only thing that worked for me was using .setTextureName() during PreInitialization. Here's the code I used:
itemTest = new ItemTest().setUnlocalizedName("itemTest").setTextureName(MyMod.MODID + ":" + "itemTest");
Sure! I'd love to see more examples of 1.7.2 code, there's a whole lot I'm still learning myself. I'm not sure how much I'll be getting into the world gen aspects for this tutorial though. My current plan is to do block metadata, tile entities, mob entities, item creation and packet handling tutorials.
No problem. Since you seem to search and data mine as much as I do, if you find something about 1.7.2+ World Gen I'd appreciate a PM or email. I just can't seem to get my plants to generate using forge.
(P.S. I've got my generate code to run and even my debug info says that I'm generating, but I can't find anything in my worlds.)
the variable textureName gets passed into registerBlockIcons() by default and it holds the name of your texture.
Thanks for the tip! I'm going to keep the tutorial the same, since it leads up to the next tutorial about adding sided textures, but I added a link to your comment for people who only need to use one texture.
@mehBleh2 Just changed all my one-texture block classes, thanks! I knew there was a way, but no one actually mentioned the syntax. And if they did they mentioned it in an advanced programming way
Also, make sure you're using the latest recommended release for Forge, currently 10.12.0.1024. If you try using earlier version of Forge 1.7, many of the method names will likely not be the same. If you need help setting up your programming environment, that describes the process.
1. Add new Block and Creative Tab
First, here's a very basic mod class to begin with:
You can adjust these two lines to provide a unique Mod ID and a version for your mod. I've been told the Mod ID must be all lowercase letters now.
This line declares the block:
This line sets up a new creative tab:
And these two lines are used to register the block using the unlocalized name "blockTest":
If you're upgrading from previous versions of MC, note that blocks must now be registered inside a FMLPreInitializationEvent, FMLInitializationEvent no longer works.
Now we need two more classes, one for the block, and one for the creative tab. I'll start with the block:
This is about as basic as you can get for a block, super(Material.ground); sets the material type for the block and this.setCreativeTab(MyMod.tabMyMod); sets which creative tab that you see the block in.
Finally, here's the code to set up a creative tab:
The part you probably want to change is Item.getItemFromBlock(Blocks.dirt). The getTabIconItem() method returns an Item and uses its icon for the creative tab. I wanted to use the dirt block icon, so I used Item.getItemFromBlock() to change the dirt block (Blocks.dirt) into an Item type.
That's it for now! You may have noticed this mod is missing some rather important things, such as an icon for the block and localized names. I should be adding those to the tutorial later as I discover how to set all that up myself.
2. Language Localization
If you try running the mod, you'll notice the block and the creative tab have odd names in game. The block will be called something like tile.blockTest.name, where "blockTest" is the unlocalized name for the block. Because minecraft is translated into many many different languages, the name for the block that's used in the code doesn't use any specific language. You have to add a file to tell MC how to translate unlocalized names into whichever language the user has chosen, a process known as language localization.
Other tutorials say you're supposed to use different folders for the language files, but there's only one location I've gotten able to work with forge v1024. Within your forge directory navigate to "src\main\resources\" and create a folder named assets. Within this folder create another folder with your Mod ID as the name, and then within that folder, create a folder named "lang". Using the code from the first tutorial, it should look something like this:
forge-directory\src\main\resources\assets\mymod\lang
The lang folder is where you'll be putting all your localization files. For instance, I speak US English, so I'll want to create a localization file named "en_US.lang". For other language codes, you can check "forge-directory\eclipse\assets\lang" for a long list of examples. Within the localization file you should have something that looks like this:
tile.blockTest.name uses the unlocalized name of the block we added in the first tutorial, and "Test Block" is the name we want to display in game. itemGroup.MyMod is the unlocalized name of the creative tab, and if you're not sure about a specific unlocalized name, you can always hover your mouse over an object in game and if it hasn't been named yet, it will give you the unlocalized name.
If you've done everything correctly, you should be able to start the game now and see the new names you've set.
3. Add a texture to your block
If you've followed the tutorial so far, your block should have a magenta and black checkered pattern in game. That's the default texture that is set when MC can't find any other texture to use for the block. Setting your own texture is relatively simple, we just have to declare a new variable and override a couple methods from the Block class.
Update: If you only have a single block texture you want to use, this tutorial is a bit of overkill. To make things much simpler you can use the method setBlockTextureName(MyMod.MODID + ":" + "blockTest") when registering the block, or within your block's class constructor. If you do that, you can skip the rest of this tutorial, which sets you up for using multiple textures with a block. Thanks to Sequiturian for the tip!
First, in the BlockTest class you want to add:
This creates a variable called blockIcon to store the texture in. Also, notice the @SideOnly(Side.CLIENT). Minecraft separates the client and server, and since the graphics are handled on the client side, you add this line so they're only loaded on the client.
Next we add this method:
This registers the texture, and lets the client know where to find the texture. If you're using the code from the tutorial so far, it will use the following location for textures:
forge-directory\src\main\resources\assets\mymod\textures\blocks
And it will search for a file named "blockTest.png" in that directory to use as the texture. Note that "mymod" is what I set the mod ID to in the first tutorial, and "blockTest" is the unlocalized name for the block. Finally, we need this last method:
This method returns the actual texture we want to use for the block, which was set in the registerBlockIcons() method. This should be all you need to get block textures working, though this only works properly for very simple blocks. Blocks with different textures per side, and blocks with different textures based upon metadata will not work properly. I believe the two parameters on the getIcon() method will give you the side and the metadata, though I'll save how to use those for another tutorial.
The class for the block we added should now look something like this:
4. Sided block textures
First, I'm gonna share a quick tip on how to find out on your own how a method works. I want to know what the two parameters on getIcon(int p_149691_1_, int p_149691_2_) do, so I'll use
in the getIcon() method to output the values for each parameter to the console in Eclipse. Turns out p_149691_1_ counts from 0 to 5, while p_149691_2_ stays zero. I know the block texture can be set differently for the 6 different sides of the block, and I haven't set the metadata, so that should be zero. It should now be obvious which one I need to use to set sided textures.
First, I'm going to add a new IIcon object:
Then add this line in registerBlockIcons():
Note that I'm adding '+ "Top"' to the end of the string, this means it will look for blockTestTop.png in the block texture directory.
Lastly, I need to change the getIcon() method so it returns blockIconTop for the top side of the block. I looked in the BlockGrass class to find that "1" corresponds to that side of a block. Here's my new method, and I've changed the parameters to make it easier to understand:
If you add a texture image named blockTestTop.png to your block texture directory ( forge-directory\src\main\resources\assets\mymod\textures\blocks ), you should now see that texture on the top side of the block when running MC.
Here's what my full BlockTest class looks like now:
5. Add an item
If you understood the process of adding a block in the first tutorial, adding a new item should be cake. I'm going to use the same basic mod code I used in the first tutorial, and add this line to declare an object of the Item type named itemTest. It should go right next to where blockTest was declared.
Next I'll add this line inside the preInit() method. You can also just use Item() instead of ItemTest() if you don't want to use a custom class for your new item.
I've gone over how the unlocalized name works in previous tutorials, so I'll focus upon the setTextureName() method. It takes a string in the following format "ModID:texture-name", which in this case is "mymod:itemTest". This tells minecraft where to look for your textures, "mymod" is the assets directory, and since it's looking for an item texture, its going to search within the "textures/items" directory within "mymod". Within that directory, it's going to look for an image named "itemTest.png", so the full path should be along the lines of forge-directory\src\main\resources\assets\mymod\textures\items\itemTest.png .
One more line to add to our mod file within the preInit() method:
This is what registers the item, i.e. the part that adds your item into the game itself. Finally, we need to create a new class file named ItemTest, I kept mine super-simple, all it does is set which creative tab to use.
And that's it! You should now have a new item in-game. Here's my full mod class now if you need to refer to it:
Whoops, I seem to have forgotten something important that I covered in a previous tutorial, notice what it is? When I load up the game, my item is named item.itemTest.name, the name hasn't been localized! No worries, I just need to add this line to my language localization file: item.itemTest.name=Item Test
6. Add an entity
It takes a few lines of code to add an entity, and if you've got a lot of entities it can be a pain to write out the code over and over again. To streamline the process, I use a method to take care of all the repetitive work which I've inserted into my mod class:
The first line within registerEntity() is to get a unique ID for the entity. The next four lines generate random colors for the spawn egg using the entity's name as a random seed. If you want to set colors yourself, you could easily adjust the method to take the primary and secondary colors as method parameters.
These lines register the entity ID, register the entity itself, and add a spawn egg respectively. It's mostly the same as MC 1.6, though I had to change EntityEggInfo to EntityList.EntityEggInfo. You may have noticed we haven't declared the instance variable yet, so let's add this line to our mod class. Put it near the top, but underneath the MODID string declaration.
One more thing the mod class needs, and that's to actually call the method we just created. Put this line within the preInit() method:
Okay, now we need to make the EntityTest class that I just referred to for our entity. Here's some very basic code that's simplified to the point of not really being practical:
This class extends EntityMob, which are the hostile monster types of entities. EntityCreature, EntityAnimal, and EntityLiving are all examples of other entity types that you can extend.
Finally, we give a localized name to our new entity by putting this into our language localization file:
entity.entityTest.name=Entity Test
That should be it! If you start minecraft, you should see a new spawn egg under the Miscellaneous creative tab. Using it should create a retarded white box within the game. Not very useful, but not bad to begin with! I'll add more tutorials about making entities smarter and more attractive.
7. Give entity a model
If you're not very comfortable coding Java, you may want to stick to easier things like blocks and items. These tutorials are going to start getting a bit more complicated now.
If you want to mod Minecraft properly, you have to understand how the client-server model works. All the rendering, the parts of the code that display graphics, happen on the client side. This isn't something the server needs to deal with at all. To separate the client and server code we're now going to create proxies, and then use the client proxy to give a proper model to our entity.
First, you'll need this in your main mod class:
This tells Forge which classes we want to use for the client and server proxies. Notice it refers to a new java package, "mymod.proxy" so go ahead and create that now. Next create the server proxy class, CommonProxy, and paste this code inside:
Not much there since we don't need to do anything with the server side at the moment. Next create a new class named ClientProxy and paste this code inside:
The RenderingRegistry.registerEntityRenderingHandler() method tells MC how to render your new entity. The RenderTest class will be used to render EntityTest entities and it will use the ModelBiped class for the model. ModelBiped is the basic player model. Also, the float that's the second parameter in RenderTest determines the shadow size.
Now we'll need to add a call to registerRenderers() within our main mod class. I put this line at the end of the preInit() method:
Next, create the RenderTest class, and paste this code inside:
The class constructor is simple enough, we just pass the parameters on to the RenderBiped class, the superclass of RenderTest. The rest of this code is used to set the texture, getEntityTexture() returns textureLocation, which *gasp* holds the location of the texture. We set it similar to the same way we set block and item textures, but we use a ResourceLocation type and I added some more information on what directory to find the texture in.
Since I'm using the same model the player uses, any player skin should work fine as a texture for my entity. I'm just testing things out, so I'm going to use the Steve skin, which will go in the location we set using ResourceLocation(MyMod.MODID + ":" + "textures/models/entityTest.png") . If you haven't tweaked your MODID, the path to the texture should be something like this: forge-directory\src\main\resources\assets\mymod\textures\models\entityTest.png
And that should be it, if you start minecraft and spawn the entity, it should now be using the basic biped model with the Steve skin.
8. Entity attributes and AI
If you used the previous tutorials to create an entity, you may have noticed that when you spawn it, it moves painfully slow. We need to set entity attributes, so go ahead and add this code to your entity's class:
This code should be fairly self-explanatory, you get the attribute, for instance maxHealth, and then use setBaseValue() to set the value. I should explain knockbackRestistance some, which ranges from 0.0D to 1.0D (the D stands for double, a primitive data type). 0.0D means 0% knockback resistance, so the entity will be knocked back every hit. 1.0D means 100% knockback resistance, so the entity will never be knocked back.
An important thing to understand abbout attributes is that they're saved per entity. This means you can do things like set them to random values or even alter an entity's attributes after it's been spawned, though I wont go in to how to do that here.
After adding attributes, it may be that you're happy with the way your entity behaves, and in that case there's no reason to add any "advanced" artifical intelligence (AI). However, if you do want more control over your entity's behavior you'll need to add this method:
Now this method by itself will just make your entity stand there and stare straight forward. When you've got AI enabled, you have to tell your entity specifically how to behave. We'll do that by adding AI tasks to your entity's class constructor. Here's what I used:
The numbers that are the first parameter of the addTask method determine the priority of the task. We put EntityAISwimming as 1, since we don't want our entity to drown in water. The EntityAIAttackOnCollide is the basic attack type that mobs like zombies and spiders use. EntityAIWander tells the mob to wander around when it's not attacking. I'll let you figure out what EntityAIWatchClosest does, and EntityAILookIdle makes the mob look around when it's just standing there.
Then there's the target tasks, which lets the entity know how to choose attack targets. EntityAIHurtByTarget will target any mob that does damage to our entity, and EntityAINearestAttackableTarget will target any nearby entity that matches the second parameter, in this case EntityPlayer.class.
That should be it, if you run the game your entity should now behave like a regular mob. One thing to be careful about is any mobs that were created in your game before you changed attributes around. You'll have to spawn new entities for them to use the new attributes you set.
Other 1.7.2 tutorials
Here's some other tutorials to check out:
Happy modding!
Keep em coming!
Also, what's with this substring(5) stuff that I've been seeing. After looking it up it talks about replacing text in strings?
When you use blockTest.getUnlocalizedName() I believe it returns the string tile.blockTest . Using the substring(5) method trims the first 5 characters in the string so you just get the unlocalized named without the "tile." part.
And textures for blocks is what I plan on doing for my next tutorial, just as soon as I figure out how to get it working myself.
Hey, is the localization file a class in eclipse, or like a notepad file, do we have to write anything inside of the file?...I am confused, I am also new to modding. This tutorial is AWESOME!
Peculiar.
It's "like a notepad file". If you're using windows, you can create a new text document, then rename it to en_US.lang. Make sure you've set things up to not hide file extensions, or it will still be a text file. You must put the names you want your custom blocks, items, entities and creative tab to use inside that file, or they'll be named things like tile.blockTest.name within the game.
You can also create/edit this within your IDE. It should be included in your project workspace.
P.S. Great job on the tutorials. Thanks for taking my request. I'll have others shortly Also, would you want to post a few other snippet tutorials that I've figured out by bumbling around? I can post the code and you can do the tutorial stuffs
EDIT: Got one, World Gen. Examples of Ores and Plants. Hey, some ppl need to generate plants. lol
It seems to me that you may have been using another name or string that didn't include the "tile." prefix. But even then you shouldn't have a crashed client over that. Maybe you were using .getUnlocalizedName() in your block initialization? That breaks stuff, but I still don't think it would crash, just error the texture.
Also, where did you get this information? I've searched all over the interwebs and I couldn't find a thing!
Sure! I'd love to see more examples of 1.7.2 code, there's a whole lot I'm still learning myself. I'm not sure how much I'll be getting into the world gen aspects for this tutorial though. My current plan is to do block metadata, tile entities, mob entities, item creation and packet handling tutorials.
It's been a combination of what I already knew about modding 1.5 and 1.6, searching the internet, trial and error, plus digging through the code. A lot of it I've had to figure out myself. Some of the earlier 1.7 tutorials were a good start, though you usually have to modify them some to get working.
^^that is one of my food classes, i replaced the "blockIcon" with itemIcon but that didn't work
I actually just added a tutorial on how to do this while you were writing your comment. =)
I tried adding item textures a few different ways, but the only thing that worked for me was using .setTextureName() during PreInitialization. Here's the code I used:
No problem. Since you seem to search and data mine as much as I do, if you find something about 1.7.2+ World Gen I'd appreciate a PM or email. I just can't seem to get my plants to generate using forge.
(P.S. I've got my generate code to run and even my debug info says that I'm generating, but I can't find anything in my worlds.)
I've found a slightly simplified way to add textures to single-texture blocks (which you actually allude to in one of the replies to someone else)
You don't need to use the function getIcon() for a single texture block at all -
in the block's constructor, add the line:
setBlockTextureName("<the name of your texture file, without the extension>");
and then in the function registerBlockIcons():
this.blockIcon = reg.registerIcon(TestBlock.MODID + ":" + textureName);
the variable textureName gets passed into registerBlockIcons() by default and it holds the name of your texture.
Thanks for the tip! I'm going to keep the tutorial the same, since it leads up to the next tutorial about adding sided textures, but I added a link to your comment for people who only need to use one texture.