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 ). We'll also recompile, reobfuscate, and distribute the mod
in the end
I guess let's just jump into some code!
InfiniteSprite.java
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:
package tutorials;
public class InfiniteSprite {
}
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.
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 {
}
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:
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
}
}
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:
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
}
}
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
public static Block ourBlock = new SpriteBlock(200, 0);
public static Item ourItem = new SpriteItem(450, 0);
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:
Feel free to use these if you want, or make your own.
Please excuse my bad spriting 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!
SpriteBlock.java
package tutorials;
import net.minecraft.src.Block;
public class SpriteBlock extends Block {
}
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:
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;
}
}
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,
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:
public static Block ourBlock = new SpriteBlock(200, 0).setResistance(3.0F).setHardness(3.0F).setCreativeTab(CreativeTabs.tablBlock).setBlockName("ourBlock");
but I prefer it this way, as it looks a litle cleaner to me.
The next thing to add is the texturing methods:
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;
}
}
}
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
SpriteItem.java
package tutorials;
import net.minecraft.src.Item;
public class SpriteItem extends Item {
}
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
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";
}
}
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
Finishing up:
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:
"!! Can not find server bins, try recompiling !!"
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
Rollback Post to RevisionRollBack
Learn some Java before you mod, and skip over the chapter on ModLoader, straight to MinecraftForge. It's better. Trust me.
I has a question actually! o: ...where do you put the .java files?
I followed the tutorial but can't get anything to work, minecraft doesn't load 'em at all... so am guessing I have them in the wrong place o.o
Have you set up MCP? Are you using eclipse? Are you reobfuscating everything, the way I explain in the tutorial?
Rollback Post to RevisionRollBack
Learn some Java before you mod, and skip over the chapter on ModLoader, straight to MinecraftForge. It's better. Trust me.
I has a question actually! o: ...where do you put the .java files?
I followed the tutorial but can't get anything to work, minecraft doesn't load 'em at all... so am guessing I have them in the wrong place o.o
if your using your own package you want them to be in the folder and zip it then drop it in the mods folder for example:
my mod(OmniaCraft)has all its files in the "OmniaCraft" package...that would be zipped(after recompile and reobfuscate) and put into minecrafts forges mod folder...
my mod(that im working on with others)has an error when i try to run the client in eclipse...im didnt use this tutorial(i looked thru an foloed it as closly as possible) but by how good this is i figure youll know whats happening...heres the error report:
2012-09-18 22:36:24 [INFO] [ForgeModLoader] Forge Mod Loader version 3.0.196.366 for Minecraft client:1.3.2, server:1.3.2 loading
2012-09-18 22:36:29 [INFO] [STDOUT] 27 achievements
2012-09-18 22:36:30 [INFO] [STDOUT] 195 recipes
2012-09-18 22:36:31 [INFO] [STDOUT] Setting user: Player434, -
2012-09-18 22:36:31 [INFO] [STDERR] Client asked for parameter: server
2012-09-18 22:36:31 [INFO] [STDOUT] LWJGL Version: 2.4.2
2012-09-18 22:36:34 [INFO] [ForgeModLoader] Attempting early MinecraftForge initialization
2012-09-18 22:36:34 [INFO] [ForgeModLoader] Completed early MinecraftForge initialization
2012-09-18 22:36:35 [INFO] [ForgeModLoader] Searching C:\Documents and Settings\Nathan1\Desktop\Gordocraft(Files)\mcp72\jars\mods for mods
2012-09-18 22:36:44 [INFO] [ForgeModLoader] Forge Mod Loader has identified 3 mods to load
2012-09-18 22:36:44 [INFO] [STDERR] Exception in thread "Minecraft main thread" java.lang.ExceptionInInitializerError
2012-09-18 22:36:44 [INFO] [STDERR] at java.lang.Class.forName0(Native Method)
2012-09-18 22:36:44 [INFO] [STDERR] at java.lang.Class.forName(Unknown Source)
2012-09-18 22:36:44 [INFO] [STDERR] at cpw.mods.fml.common.ProxyInjector.inject(ProxyInjector.java:51)
2012-09-18 22:36:44 [INFO] [STDERR] at cpw.mods.fml.common.FMLModContainer.constructMod(FMLModContainer.java:348)
2012-09-18 22:36:44 [INFO] [STDERR] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
2012-09-18 22:36:44 [INFO] [STDERR] at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
2012-09-18 22:36:44 [INFO] [STDERR] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
2012-09-18 22:36:44 [INFO] [STDERR] at java.lang.reflect.Method.invoke(Unknown Source)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.EventHandler.handleEvent(EventHandler.java:69)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.SynchronizedEventHandler.handleEvent(SynchronizedEventHandler.java:45)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.EventBus.dispatch(EventBus.java:317)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.EventBus.dispatchQueuedEvents(EventBus.java:300)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.EventBus.post(EventBus.java:268)
2012-09-18 22:36:44 [INFO] [STDERR] at cpw.mods.fml.common.LoadController.propogateStateMessage(LoadController.java:124)
2012-09-18 22:36:44 [INFO] [STDERR] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
2012-09-18 22:36:44 [INFO] [STDERR] at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
2012-09-18 22:36:44 [INFO] [STDERR] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
2012-09-18 22:36:44 [INFO] [STDERR] at java.lang.reflect.Method.invoke(Unknown Source)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.EventHandler.handleEvent(EventHandler.java:69)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.SynchronizedEventHandler.handleEvent(SynchronizedEventHandler.java:45)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.EventBus.dispatch(EventBus.java:317)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.EventBus.dispatchQueuedEvents(EventBus.java:300)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.EventBus.post(EventBus.java:268)
2012-09-18 22:36:44 [INFO] [STDERR] at cpw.mods.fml.common.LoadController.distributeStateMessage(LoadController.java:81)
2012-09-18 22:36:44 [INFO] [STDERR] at cpw.mods.fml.common.Loader.loadMods(Loader.java:458)
2012-09-18 22:36:44 [INFO] [STDERR] at cpw.mods.fml.client.FMLClientHandler.beginMinecraftLoading(FMLClientHandler.java:144)
2012-09-18 22:36:44 [INFO] [STDERR] at net.minecraft.client.Minecraft.startGame(Minecraft.java:405)
2012-09-18 22:36:44 [INFO] [STDERR] at net.minecraft.client.Minecraft.run(Minecraft.java:737)
2012-09-18 22:36:44 [INFO] [STDERR] at java.lang.Thread.run(Unknown Source)
2012-09-18 22:36:44 [INFO] [STDERR] Caused by: java.lang.NullPointerException
2012-09-18 22:36:44 [INFO] [STDERR] at OmniaCraft.CommonProxy.<clinit>(CommonProxy.java:19)
2012-09-18 22:36:44 [INFO] [STDERR] ... 29 more
2012-09-18 22:36:47 [INFO] [STDERR] Someone is closing me!
my mod(that im working on with others)has an error when i try to run the client in eclipse...im didnt use this tutorial(i looked thru an foloed it as closly as possible) but by how good this is i figure youll know whats happening...heres the error report:
2012-09-18 22:36:24 [INFO] [ForgeModLoader] Forge Mod Loader version 3.0.196.366 for Minecraft client:1.3.2, server:1.3.2 loading
2012-09-18 22:36:29 [INFO] [STDOUT] 27 achievements
2012-09-18 22:36:30 [INFO] [STDOUT] 195 recipes
2012-09-18 22:36:31 [INFO] [STDOUT] Setting user: Player434, -
2012-09-18 22:36:31 [INFO] [STDERR] Client asked for parameter: server
2012-09-18 22:36:31 [INFO] [STDOUT] LWJGL Version: 2.4.2
2012-09-18 22:36:34 [INFO] [ForgeModLoader] Attempting early MinecraftForge initialization
2012-09-18 22:36:34 [INFO] [ForgeModLoader] Completed early MinecraftForge initialization
2012-09-18 22:36:35 [INFO] [ForgeModLoader] Searching C:\Documents and Settings\Nathan1\Desktop\Gordocraft(Files)\mcp72\jars\mods for mods
2012-09-18 22:36:44 [INFO] [ForgeModLoader] Forge Mod Loader has identified 3 mods to load
2012-09-18 22:36:44 [INFO] [STDERR] Exception in thread "Minecraft main thread" java.lang.ExceptionInInitializerError
2012-09-18 22:36:44 [INFO] [STDERR] at java.lang.Class.forName0(Native Method)
2012-09-18 22:36:44 [INFO] [STDERR] at java.lang.Class.forName(Unknown Source)
2012-09-18 22:36:44 [INFO] [STDERR] at cpw.mods.fml.common.ProxyInjector.inject(ProxyInjector.java:51)
2012-09-18 22:36:44 [INFO] [STDERR] at cpw.mods.fml.common.FMLModContainer.constructMod(FMLModContainer.java:348)
2012-09-18 22:36:44 [INFO] [STDERR] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
2012-09-18 22:36:44 [INFO] [STDERR] at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
2012-09-18 22:36:44 [INFO] [STDERR] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
2012-09-18 22:36:44 [INFO] [STDERR] at java.lang.reflect.Method.invoke(Unknown Source)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.EventHandler.handleEvent(EventHandler.java:69)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.SynchronizedEventHandler.handleEvent(SynchronizedEventHandler.java:45)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.EventBus.dispatch(EventBus.java:317)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.EventBus.dispatchQueuedEvents(EventBus.java:300)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.EventBus.post(EventBus.java:268)
2012-09-18 22:36:44 [INFO] [STDERR] at cpw.mods.fml.common.LoadController.propogateStateMessage(LoadController.java:124)
2012-09-18 22:36:44 [INFO] [STDERR] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
2012-09-18 22:36:44 [INFO] [STDERR] at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
2012-09-18 22:36:44 [INFO] [STDERR] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
2012-09-18 22:36:44 [INFO] [STDERR] at java.lang.reflect.Method.invoke(Unknown Source)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.EventHandler.handleEvent(EventHandler.java:69)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.SynchronizedEventHandler.handleEvent(SynchronizedEventHandler.java:45)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.EventBus.dispatch(EventBus.java:317)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.EventBus.dispatchQueuedEvents(EventBus.java:300)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.EventBus.post(EventBus.java:268)
2012-09-18 22:36:44 [INFO] [STDERR] at cpw.mods.fml.common.LoadController.distributeStateMessage(LoadController.java:81)
2012-09-18 22:36:44 [INFO] [STDERR] at cpw.mods.fml.common.Loader.loadMods(Loader.java:458)
2012-09-18 22:36:44 [INFO] [STDERR] at cpw.mods.fml.client.FMLClientHandler.beginMinecraftLoading(FMLClientHandler.java:144)
2012-09-18 22:36:44 [INFO] [STDERR] at net.minecraft.client.Minecraft.startGame(Minecraft.java:405)
2012-09-18 22:36:44 [INFO] [STDERR] at net.minecraft.client.Minecraft.run(Minecraft.java:737)
2012-09-18 22:36:44 [INFO] [STDERR] at java.lang.Thread.run(Unknown Source)
2012-09-18 22:36:44 [INFO] [STDERR] Caused by: java.lang.NullPointerException
2012-09-18 22:36:44 [INFO] [STDERR] at OmniaCraft.CommonProxy.<clinit>(CommonProxy.java:19)
2012-09-18 22:36:44 [INFO] [STDERR] ... 29 more
2012-09-18 22:36:47 [INFO] [STDERR] Someone is closing me!
Something to do with your proxy... Post your CommonProxy.java, ClientPorxy.java, and your main mod class?
Rollback Post to RevisionRollBack
Learn some Java before you mod, and skip over the chapter on ModLoader, straight to MinecraftForge. It's better. Trust me.
Umm... Next time, try to use [code][code][/code][/code] tags... Also, basically everything in your proxy classes should be in the main class file. The ***Registry calls should be in the init() method, and the declarations should be class fields.
Rollback Post to RevisionRollBack
Learn some Java before you mod, and skip over the chapter on ModLoader, straight to MinecraftForge. It's better. Trust me.
Umm... Next time, try to use [code][code][/code][/code] tags... Also, basically everything in your proxy classes should be in the main class file. The ***Registry calls should be in the init() method, and the declarations should be class fields.
I am having isses >.<
..well POST THEM!
...Nah, ill figure it out =P
I've been staring at code for hours, having issues reading ur tut. my eyes keep skipping lines. ill be back some other time to work on this.
Umm... Next time, try to use [code][code][/code][/code] tags... Also, basically everything in your proxy classes should be in the main class file. The ***Registry calls should be in the init() method, and the declarations should be class fields.
fixed it to add the
[code][/code]
totally forgot about those and
what you said made no sense....idk if it just doesnt or that fact that geometry fried my brain...
totally forgot about those and
what you said made no sense....idk if it just doesnt or that fact that geometry fried my brain...
Thank you for the fix
The GameRegistry.whatever, LanguageRegistry.whatever, NetworkRegistry.whatever, etc... Those shouldn't really be in your proxy class, I don't think. They should be inside of the init() method of your main class file. Also, the declarations for your blocks/items; the
public static Block whatever = new BlockWhatever();
lines should be class fields in your main class, defined inside of the body of the class. Do you know Java?
Rollback Post to RevisionRollBack
Learn some Java before you mod, and skip over the chapter on ModLoader, straight to MinecraftForge. It's better. Trust me.
The GameRegistry.whatever, LanguageRegistry.whatever, NetworkRegistry.whatever, etc... Those shouldn't really be in your proxy class, I don't think. They should be inside of the init() method of your main class file. Also, the declarations for your blocks/items; the
public static Block whatever = new BlockWhatever();
lines should be class fields in your main class, defined inside of the body of the class. Do you know Java?
i know some java...and it was working how i had it befor and it was fine...nothing changed and then it crashed after the mojang screen...so i think were they are is fine altho maybe not...ill try and see what comes up...
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 ). We'll also recompile, reobfuscate, and distribute the mod
in the end
I guess let's just jump into some code!
InfiniteSprite.java
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:
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.
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:
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:
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
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:
Feel free to use these if you want, or make your own.
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!
SpriteBlock.java
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:
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:
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:
but I prefer it this way, as it looks a litle cleaner to me.
The next thing to add is the texturing methods:
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
SpriteItem.java
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
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
Finishing up:
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:
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
Have you set up MCP? Are you using eclipse? Are you reobfuscating everything, the way I explain in the tutorial?
if your using your own package you want them to be in the folder and zip it then drop it in the mods folder for example:
my mod(OmniaCraft)has all its files in the "OmniaCraft" package...that would be zipped(after recompile and reobfuscate) and put into minecrafts forges mod folder...
2012-09-18 22:36:24 [INFO] [ForgeModLoader] Forge Mod Loader version 3.0.196.366 for Minecraft client:1.3.2, server:1.3.2 loading
2012-09-18 22:36:29 [INFO] [STDOUT] 27 achievements
2012-09-18 22:36:30 [INFO] [STDOUT] 195 recipes
2012-09-18 22:36:31 [INFO] [STDOUT] Setting user: Player434, -
2012-09-18 22:36:31 [INFO] [STDERR] Client asked for parameter: server
2012-09-18 22:36:31 [INFO] [STDOUT] LWJGL Version: 2.4.2
2012-09-18 22:36:34 [INFO] [ForgeModLoader] Attempting early MinecraftForge initialization
2012-09-18 22:36:34 [INFO] [ForgeModLoader] Completed early MinecraftForge initialization
2012-09-18 22:36:35 [INFO] [ForgeModLoader] Searching C:\Documents and Settings\Nathan1\Desktop\Gordocraft(Files)\mcp72\jars\mods for mods
2012-09-18 22:36:44 [INFO] [ForgeModLoader] Forge Mod Loader has identified 3 mods to load
2012-09-18 22:36:44 [INFO] [STDERR] Exception in thread "Minecraft main thread" java.lang.ExceptionInInitializerError
2012-09-18 22:36:44 [INFO] [STDERR] at java.lang.Class.forName0(Native Method)
2012-09-18 22:36:44 [INFO] [STDERR] at java.lang.Class.forName(Unknown Source)
2012-09-18 22:36:44 [INFO] [STDERR] at cpw.mods.fml.common.ProxyInjector.inject(ProxyInjector.java:51)
2012-09-18 22:36:44 [INFO] [STDERR] at cpw.mods.fml.common.FMLModContainer.constructMod(FMLModContainer.java:348)
2012-09-18 22:36:44 [INFO] [STDERR] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
2012-09-18 22:36:44 [INFO] [STDERR] at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
2012-09-18 22:36:44 [INFO] [STDERR] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
2012-09-18 22:36:44 [INFO] [STDERR] at java.lang.reflect.Method.invoke(Unknown Source)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.EventHandler.handleEvent(EventHandler.java:69)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.SynchronizedEventHandler.handleEvent(SynchronizedEventHandler.java:45)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.EventBus.dispatch(EventBus.java:317)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.EventBus.dispatchQueuedEvents(EventBus.java:300)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.EventBus.post(EventBus.java:268)
2012-09-18 22:36:44 [INFO] [STDERR] at cpw.mods.fml.common.LoadController.propogateStateMessage(LoadController.java:124)
2012-09-18 22:36:44 [INFO] [STDERR] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
2012-09-18 22:36:44 [INFO] [STDERR] at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
2012-09-18 22:36:44 [INFO] [STDERR] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
2012-09-18 22:36:44 [INFO] [STDERR] at java.lang.reflect.Method.invoke(Unknown Source)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.EventHandler.handleEvent(EventHandler.java:69)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.SynchronizedEventHandler.handleEvent(SynchronizedEventHandler.java:45)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.EventBus.dispatch(EventBus.java:317)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.EventBus.dispatchQueuedEvents(EventBus.java:300)
2012-09-18 22:36:44 [INFO] [STDERR] at com.google.common.eventbus.EventBus.post(EventBus.java:268)
2012-09-18 22:36:44 [INFO] [STDERR] at cpw.mods.fml.common.LoadController.distributeStateMessage(LoadController.java:81)
2012-09-18 22:36:44 [INFO] [STDERR] at cpw.mods.fml.common.Loader.loadMods(Loader.java:458)
2012-09-18 22:36:44 [INFO] [STDERR] at cpw.mods.fml.client.FMLClientHandler.beginMinecraftLoading(FMLClientHandler.java:144)
2012-09-18 22:36:44 [INFO] [STDERR] at net.minecraft.client.Minecraft.startGame(Minecraft.java:405)
2012-09-18 22:36:44 [INFO] [STDERR] at net.minecraft.client.Minecraft.run(Minecraft.java:737)
2012-09-18 22:36:44 [INFO] [STDERR] at java.lang.Thread.run(Unknown Source)
2012-09-18 22:36:44 [INFO] [STDERR] Caused by: java.lang.NullPointerException
2012-09-18 22:36:44 [INFO] [STDERR] at OmniaCraft.CommonProxy.<clinit>(CommonProxy.java:19)
2012-09-18 22:36:44 [INFO] [STDERR] ... 29 more
2012-09-18 22:36:47 [INFO] [STDERR] Someone is closing me!
Something to do with your proxy... Post your CommonProxy.java, ClientPorxy.java, and your main mod class?
commonproxy.java
ClientProxy.java
BaseOmniaCraft.java
I am having isses >.<
..well POST THEM!
...Nah, ill figure it out =P
I've been staring at code for hours, having issues reading ur tut. my eyes keep skipping lines. ill be back some other time to work on this.
Did you just have a conversation with yourself? If so, that's ok. It happens to the best of us. If not, then what is going on?
fixed it to add the
totally forgot about those and
what you said made no sense....idk if it just doesnt or that fact that geometry fried my brain...
Thank you for the fix
The GameRegistry.whatever, LanguageRegistry.whatever, NetworkRegistry.whatever, etc... Those shouldn't really be in your proxy class, I don't think. They should be inside of the init() method of your main class file. Also, the declarations for your blocks/items; the
lines should be class fields in your main class, defined inside of the body of the class. Do you know Java?
i know some java...and it was working how i had it befor and it was fine...nothing changed and then it crashed after the mojang screen...so i think were they are is fine altho maybe not...ill try and see what comes up...
And see what happens. This may be trying to call stuff in proxy before it is initialized in ClientProxy. Maybe.