Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Ok, so I have noticed that there aren't very many tutorials about Forge's "Infinite Sprite Index",
- so I decided I'd try my hand. This tutorial is written with Minecraft 1.3.2, MCP 7.2, and Minecraft
- Forge 4.1.2.259 in mind, so anything earlier than that, I can't really support, and anything later
- should be fairly similar, if not exactly the same.
- I am using eclipse, and will be going off the premise that you have set up an MCP workspace, with
- Forge, and haven't added anything else yet. These steps should work for any workspace, I will
- simply be starting one new just for this tutorial. If you need help setting up a workspace, these
- two tutorials are the mainstay:
- Xain Faith's MCP Tutorial
- Minecraft Forge Installation
- For this tutorial, we'll be creating a mod that adds in a Block and an Item, that way you can see
- how both work (it's almost the same :P). We'll also recompile, reobfuscate, and distribute the mod
- in the end :)
- I guess let's just jump into some code!
- InfiniteSprite.java
- [spoiler]
- This is going to be our main mod class, and if you notice, it don't not start with "mod_". That is
- an old standard from ModLoader days, and is not necessary for Forge mods. You can name your mod
- class whatever you want, as long as you write it correctly.
- The first thing we're going to do is define our class:
- [code]
- package tutorials;
- public class InfiniteSprite {
- }
- [/code]
- Easy :) The package declaration in line 1 can simply be whatever you want. The default for most of
- the vanilla Minecraft classes is net.minecraft.src, and if you want to put your classes there,
- that's fine. I prefer mine in their own package for better organization.
- After that, we have the class declaration, which just says that our class is called InfiniteSprite.
- Now we need to add in the annotations, which let Forge know that this is our base mod class.
- [code]
- package tutorials;
- import cpw.mods.fml.common.Mod;
- import cpw.mods.fml.common.network.NetworkMod;
- @Mod(modid = "infinite_sprite", name = "Infinite Sprite", version = "1.0")
- @NetworkMod(clientSideRequired = true, serverSideRequired = false)
- public class InfiniteSprite {
- }
- [/code]
- This adds in a couple lines. The import lines simply import in the classes for the annotations
- below. If you are ever in doubt about which classes need to be imported and which ones don't,
- eclipse has a handy keyboard shortcut, Ctrl+Shift+O, which organizes your imports for you :) Bear
- in mind that if your package is net.minecraft.src, some of the imports in this tutorial won't be
- necessary, as you only have to import classes from different packages.
- Annotations are new to Forge 4.x, and give Forge a way to communicate with classes in a more
- precise manner, while allowing you to be a little more flexible with your code. There are a few
- more places we'll use these in this class as well.
- The @Mod line finally tells Forge that this is our main mod class! It also tells Forge that our
- mod's unique id is "infinite_sprite", its name is "Infinite Sprite", and it is version "1.0".
- The @NetworkMod line below that tells Forge that this mod can run on a server, but you don't need
- to have it installed on the server for it to run, only in the client. This annotation can get much
- more complicated, but for simple mods like this, this is really all you need.
- Next we need the methods that this class usually uses:
- [code]
- package tutorials;
- import cpw.mods.fml.common.Mod;
- import cpw.mods.fml.common.Mod.Init;
- import cpw.mods.fml.common.Mod.PostInit;
- import cpw.mods.fml.common.Mod.PreInit;
- import cpw.mods.fml.common.event.FMLInitializationEvent;
- import cpw.mods.fml.common.event.FMLPostInitializationEvent;
- import cpw.mods.fml.common.event.FMLPreInitializationEvent;
- import cpw.mods.fml.common.network.NetworkMod;
- @Mod(modid = "infinite_sprite", name = "Infinite Sprite", version = "1.0")
- @NetworkMod(clientSideRequired = true, serverSideRequired = false)
- public class InfiniteSprite {
- @PreInit
- public void preInit(FMLPreInitializationEvent event) {
- //loads before your mod
- }
- @Init
- public void init(FMLInitializationEvent event) {
- //loads your mod
- }
- @PostInit
- public void postInit(FMLPostInitializationEvent event) {
- //loads after your mod
- }
- }
- [/code]
- This adds in a couple more imports, all for annotations and FML events, but the meat of the issue
- is inside.
- This added in three methods, each prefaced with an annotation. The @PreInit method is run before
- anything else in your mod, so people usually use it for things like loading configuration files and
- the like. The @Init method is where most of the fun happens, in terms of registering blocks and
- such. The @PostInit method is run after your mod is loaded completely, and I don't know of many
- uses for it, except I have read that it is used especially in intregation with Equivalent Exchange.
- These methods can be named whatever you want, as long as they are prefaced with those annotations,
- and take the same parameters.
- Now for the fun stuff:
- [code]
- package tutorials;
- import net.minecraft.src.Block;
- import net.minecraft.src.Item;
- import net.minecraft.src.ItemStack;
- import cpw.mods.fml.common.Mod;
- import cpw.mods.fml.common.Mod.Init;
- import cpw.mods.fml.common.Mod.PostInit;
- import cpw.mods.fml.common.Mod.PreInit;
- import cpw.mods.fml.common.event.FMLInitializationEvent;
- import cpw.mods.fml.common.event.FMLPostInitializationEvent;
- import cpw.mods.fml.common.event.FMLPreInitializationEvent;
- import cpw.mods.fml.common.network.NetworkMod;
- import cpw.mods.fml.common.registry.GameRegistry;
- import cpw.mods.fml.common.registry.LanguageRegistry;
- @Mod(modid = "infinite_sprite", name = "Infinite Sprite", version = "1.0")
- @NetworkMod(clientSideRequired = true, serverSideRequired = false)
- public class InfiniteSprite {
- public static Block ourBlock = new SpriteBlock(200, 0);
- public static Item ourItem = new SpriteItem(450, 0);
- @PreInit
- public void preInit(FMLPreInitializationEvent event) {
- //loads before your mod
- }
- @Init
- public void init(FMLInitializationEvent event) {
- GameRegistry.registerBlock(ourBlock);
- GameRegistry.addRecipe(new ItemStack(ourBlock), new Object[] {
- "XXX", Character.valueOf('X'), Block.dirt
- });
- GameRegistry.addRecipe(new ItemStack(ourItem), new Object[] {
- "XXX", Character.valueOf('X'), Block.wood
- });
- LanguageRegistry.addName(ourBlock, "Sprite Block");
- LanguageRegistry.addName(ourItem, "Sprite Item");
- MinecraftForgeClient.preloadTexture("/tutorials/terrain.png");
- MinecraftForgeClient.preloadTexture("/tutorials/items.png");
- }
- @PostInit
- public void postInit(FMLPostInitializationEvent event) {
- //loads after your mod
- }
- }
- [/code]
- That's it! That is all the editing in this class :)
- We did add a couple imports (thank you Ctrl+Shift+O), but those are all the ones we need for this
- tutorial.
- The lines
- [code]
- public static Block ourBlock = new SpriteBlock(200, 0);
- public static Item ourItem = new SpriteItem(450, 0);
- [/code]
- actually declare our block and our item for use later on. The first parameter in each of these is
- the ID for that block/item. As of snapshot 12w36a, used block IDs end at 144, and used item IDs end
- at 399, except for music discs, which take up 2256-2266. Forge allows us to add in blocks/items for outside of these ranges, but for an up-to-date listing of vanilla IDs, check out this page.
- The 0's in those calls refer to which sprite in our image file to use.
- If this is all you've done so far, these will be giving you an error. No worries, we will fix them
- soon, the block is in the next section :)
- In the @Init method, we've added a few ***Registry calls too.
- GameRegistry is usually responsible for registering new Blocks, TileEntities, Recipes, and the
- like, and that's what we do here. The first call simply registers our SpriteBlock from earlier, so
- the game can use it.
- The GameRegistry.addRecipe() lines add in recipes for our new block and our new item, that way they
- are accessible in Survival mode. They create a new ItemStack, of the respective block/item, and
- then make a recipe. These are usable in the standard 2x2 crafting square, with two Dirt blocks
- making our Sprite Block, and two Wood blocks making our Sprite Item.
- LanguageRegistry takes care of displaying in-game names on blocks and items. These are pretty
- simple calls, just making sure that in our inventory, we see "Sprite Block" and "Sprite Item" when
- we hover over them.
- Next we have MinecraftForgeClient.preloadTexture(). This loads the image we are going to use for
- our custom textures into memory so Forge can use them to pull textures from. These should be
- 256x256 pixels, and the ones I am going to use are here:
- [spoiler]
- [img=http://i.imgur.com/TInpu.png]
- [img=http://i.imgur.com/8Aow7.png]
- Feel free to use these if you want, or make your own.
- [/spoiler]
- Please excuse my bad spriting :P I have multiple textures for the block, because I'll be showing
- you how to texture side-by-side, but you really only need one if you aren't doing something fancy.
- These images should be placed in *yourMCPfolder*\src\common\tutorials if you are using the same
- package as me, or *yourMCPfolder*\src\common\*yourpackagehere*.
- Now on to the Block!
- [/spoiler]
- SpriteBlock.java
- [spoiler]
- [code]
- package tutorials;
- import net.minecraft.src.Block;
- public class SpriteBlock extends Block {
- }
- [/code]
- This is our standard package and class definition, with a twist. This class extends Block, which
- means that, aside from having to import Block, it also inherits all the methods and fields (aka
- variables) that Block has.
- Lets add in a little more content on this block:
- [code]
- package tutorials;
- import java.util.Random;
- import net.minecraft.src.Block;
- import net.minecraft.src.CreativeTabs;
- import net.minecraft.src.Material;
- public class SpriteBlock extends Block {
- public SpriteBlock(int blockID, int spriteIndex) {
- super(blockID, spriteIndex, Material.rock);
- this.setResistance(3.0F);
- this.setHardness(3.0F);
- this.setCreativeTab(CreativeTabs.tabBlock);
- this.setBlockName("ourBlock");
- }
- @Override
- public int idDropped(int i, Random r, int j) {
- return InfiniteSprite.ourBlock.blockID;
- }
- @Override
- public int quantityDropped(Random r) {
- return 1;
- }
- }
- [/code]
- At this point, we are "done" with this block. It is usable in-game, but it will look like Stone,
- because its spriteIndex is 0, from our InfiniteSprite class.
- Aside from imports, we added a constructor and a couple method here.
- The constructor calls the standard Block constructor, passing it our blockID, our spriteIndex, and
- we are going to use Material.rock, which dictates what sound it makes when you walk on it, and what
- tools are effective against it. It also sets the Resistance (how damaged it is by explosions), the
- Hardness (how damaged it is by tools), which tab it's displayed on in the Creative inventory, and
- the block "name", which is solely in the code, and has no bearing on the ingame name. We did that
- with LanguageRegistry, remember? :)
- CreativeTabs is the vanilla class which dictates which tabs there are in the Creative inventory,
- and it contains:
- [code]tabBlock, tabDeco, tabRedstone, tabTransport, tabMisc, tabAllSearch, tabFood, tabTools,
- tabCombat, tabBrewing, tabMaterials, tabInventory[/code]
- But I don't know how tabAllSearch or tabInventory actually work in practice.
- All but the super() call can be, and frequently are, called in the main mod class, like so:
- [code]
- public static Block ourBlock = new SpriteBlock(200, 0).setResistance(3.0F).setHardness
- (3.0F).setCreativeTab(CreativeTabs.tablBlock).setBlockName("ourBlock");
- [/code]
- but I prefer it this way, as it looks a litle cleaner to me.
- The next thing to add is the texturing methods:
- [code]
- package tutorials;
- import java.util.Random;
- import net.minecraft.src.Block;
- import net.minecraft.src.CreativeTabs;
- import net.minecraft.src.Material;
- public class SpriteBlock extends Block {
- public SpriteBlock(int blockID, int spriteIndex) {
- super(blockID, spriteIndex, Material.rock);
- this.setResistance(3.0F);
- this.setHardness(3.0F);
- this.setCreativeTab(CreativeTabs.tabBlock);
- this.setBlockName("ourBlock");
- }
- @Override
- public int idDropped(int i, Random r, int j) {
- return InfiniteSprite.ourBlock.blockID;
- }
- @Override
- public int quantityDropped(Random r) {
- return 1;
- }
- @Override
- public String getTextureFile() {
- return "/tutorials/terrain.png";
- }
- @Override
- public int getBlockTextureFromSide(int side) {
- switch (side) {
- case 0:
- return 0;
- case 1:
- return 1;
- case 2:
- return 2;
- case 3:
- return 3;
- case 4:
- return 4;
- case 5:
- return 5;
- default:
- return 0;
- }
- }
- }
- [/code]
- All this added is the getTextureFile() and getBlockTextureFromSide() methods.
- The getTextureFile() method should return the same path that we preloaded in our mod class. This
- simply tells Forge which image to take the texture for this block from.
- The getBlockTextureFromSide() method, in this form, simply returns the index in our texture file
- for whichever side the game is trying to texture. This will change if your have more than one
- block, or if you try to do metadata blocks, you'll use a different method as well.
- That's it for this block! Let's do the Item now. It's almost exactly the same as the block :P
- [/spoiler]
- SpriteItem.java
- [spoiler]
- [code]
- package tutorials;
- import net.minecraft.src.Item;
- public class SpriteItem extends Item {
- }
- [/code]
- Exactly the same as SpriteBlock, except here we extend Item, so we're going to inherit the methods
- and fields that an Item has.
- I'm just going to finish it here :)
- [code]
- package tutorials;
- import net.minecraft.src.CreativeTabs;
- import net.minecraft.src.Item;
- public class SpriteItem extends Item {
- public SpriteItem(int id, int spriteIndex) {
- super(id);
- this.setIconIndex(spriteIndex);
- this.setItemName("ourItem");
- this.setTabToDisplayOn(CreativeTabs.tabTools);
- }
- @Override
- public String getTextureFile() {
- return "/tutorials/items.png";
- }
- }
- [/code]
- This one's not quite as complicated, but here we set our item's spriteIndex, Creative tab, and
- name. We also return its texture file through getTextureFile(). That's it! All the coding is done
- :)
- [/spoiler]
- Now to package this up. Go to your MCP workspace folder (for me it's H:\workspace\MakingTutorials),
- and run recompile.bat (or recompile.sh for Unix systems). This does a final build of the classes we
- just wrote. Now run reobfuscate.bat (again, or reobfuscate.sh for Unix users). This script simply
- compiles the classes from their .java source into .class program files. MCP 7.2 gives a warning:
- [code]"!! Can not find server bins, try recompiling !!"[/code]
- but this is a false alarm, a remnant of how there used to be a client and server version of all
- mods.
- Now, in the reobf folder, you should have reobf\minecraft\*yourpackagehere*, which contains all of
- the class files we just made, but there's one problem we need to deal with. There's no images in
- there! Simply go back to *yourMCPfolder*\src\common\*yourpackagehere*, and copy the images you used
- into *yourMCPfolder*\reobf\minecraft\*yourpackagehere*. Now zip up the whole *yourpackagehere*
- folder, using 7zip, WinRAR, or whatever you like, and you'll have a working mod :) You can now just
- drop this zip into your mods folder in Minecraft, or put it in the mods tab in MultiMC if you like.
- If there are any questions or suggestions, let me know :)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement