First, you'll need a fresh new copy of MCP, a clean, unmodified minecraft.jar file, and a clean, unmodified copy of minecraft_server.jar. Make sure they're completely unmodified without Forge or ModLoader or anything else in them. You can get a clean download of the server from minecraft.net and a clean minecraft.jar by using Force Update from the Minecraft launcher.
Then, you'll need a current copy of Forge source. You can find the latest download here. Make sure to download the Source and not the Universal download. Universal is for installing into your actual game to play Forge mods while Source is for writing mods in MCP.
Make sure your Forge, MCP, and jars are all for the same version of Minecraft. Also make sure you're using an up-to-date version of the jdk, or Java Developer Kit. Older versions of java can run into problems when trying to recompile Forge.
Now, set up your MCP like you normally do. Put your bin and resources folders and the minecraft_server.jar into MCP's jars folder. Make sure the minecraft.jar in jars/bin is the clean unmodded one.
Then, extract the forge folder form the Forge Source zip and place it in your MCP folder. Open it up and run the install script in there, which should set everything up and decompile for you. You can now begin writing your Forge mod.
First thing you may notice about the Forge-ified MCP is that there is a common folder and a minecraft folder in src. This is because Minecraft 1.3 and up are "SMP Merged." Whenever you play a game in singleplayer, there is a "server" running in the background that you are logged into. So, the minecraft client and the minecraft server both share the same code, which is put into the "common" folder. Anything that is purely client-side, such as rendering, will be put into the "minecraft" folder. The nice thing about this is that you don't need to write a client-side and server-side mod if you're using Forge. Any mod written for Forge can potentially be used in either the client OR the server and work just fine, if written correctly. I'll explain this more further in.
BaseMod and Annotations
First of all, your main mod no longer needs to extend BaseMod. Instead, you'll use something called an Annotation. For example:
public class mod_ObsidianTools extends BaseMod
This is probably how your ModLoader mod looks. You can now change that to this:
@Mod(modid = "ObsidianTools", name = "Obsidian Tools", version = "0.1")
public class ObsidianTools
Now, instead of having to have a class with the name mod_Blah that extends BaseMod, you can get Forge ModLoader to load your mod with any class name as long as it has that @Mod setup properly before the class declaration. Little tags like @Mod with the At sign in front are called Annotations. You may be slightly familiar with Annotations from using @Override. Forge uses many different annotations, so get ready to be more familiar with them.
In order to use the @Mod annotation in your mod, you'll need to import it by putting this at the top of your mod's file:
Since the @Mod annotation includes your version in it and you're no longer using BaseMod, your mod's main file no longer needs to include a getVersion() method like the one above. If your mod includes something like that, you can safely remove it.
ForgeModLoader, or FML, can load any class file with the @Mod annotation regardless of what folder or package it's in, unlike regular ModLoader. This means that your mod's main file no longer has to get lost in the net.minecraft.src folder with all the vanilla Minecraft files.
To help organize your mod files and keep them separate from vanilla Minecraft files, you can put them in their own package. Create a folder in MCP's src/common/ folder. For the purpose of this example, lets call it derp. If you did it right, the folder should now contain cpw, net, org, and derp.
Assuming that none of your mod files overwrite any base classes, move them all into the derp folder. Now, your files may start with something like this:
Change that in every file into this:
Now, all your files will be part of their own package in their own folder, but still have access to vanilla code.
Forge's files are organized into several packages, and in order to use them in your code, you'll need to import them. Import statements are generally located at the very top of .java files and look like this:
If you don't know what package a class is in to import it, find the source for it in MCP's forge folder and look at the top. For example, EntityRegistry has this at the top of the file:
If you've been following this tutorial, your files probably import statements at the top to import net.minecraft.src.*
This allows them to reference things in vanilla Minecraft without errors. Without imports, the compiler doesn't know what files to look at other than other classes in the same package.
In ModLoader, you had to put all your mod's main stuff in something like this:
public void load()
In Forge, that's no longer the case. Forge mods have three parts, the PreInit, the Init, and the PostInit. They get ran in that order. The Init is basically what your load() was, PreInit is all the little things you want to wrap up before dealing with the main load, and PostInit is for things you want to follow up on afterwards, like hooking into other mods after they've been loaded.
So, you can change your load() method into this:
public void load(FMLInitializationEvent event)
See that @Init annotation? FML will know to run that method when it loads your mod, regardless of what the method name is as long as it has that annotation and takes an FMLInitializationEvent as an argument. For example, you could have this instead:
public void startMod(FMLInitializationEvent event)
public void loadDaMod(FMLInitializationEvent event)
Or even this:
public void purpleStrawberryAardvarkRumpus(FMLInitializationEvent event)
It won't matter what you call the method. Just make sure you have the @Init annotation before it and have it take FMLInitializationEvent as an argument.
To make a preInit method, you would do something like this:
public void beforeLoad(FMLPreInitializationEvent event)
This method will obviously run before your @Init method and is generally handy for things like loading your config file, which I'll touch on later in this tutorial.
And, of course, there's the PostInit method:
public void afterLoaded(FMLPostInitializationEvent event)
This method will run after all mods have loaded, so it's useful for things that need to make sure other mods are loaded, like if your mod has recipes that only work if another mod is also there.
To use any of those methods in your mod, you'll need to import the annotations and init events like this:
Now that you're writing for Forge and not ModLoader, it's time to clean out all the ModLoader method calls. FML includes a "phantom" ModLoader class that will take the method calls to make ML mods compatible, but if you're actually writing with Forge in mind, you're better off avoiding using those. If you leave them in, your mod won't be compatible with SMP, and there's the chance that Forge might drop such compatibility in the future.
Lets start with one you probably use a lot:
Instead of using ModLoader for that, use GameRegistry:
Of course, to use GameRegistry, you'll need an import:
Another one you probably use a lot is ModLoader.addOverride(). Well, now that you're using Forge, you should stop it, because there's a better way. Check out this tutorial to learn how to use infinite sprite indices.
ModLoader.addName(tungstenOre, "Deific Ore of Invincibility");
Instead of using ModLoader.addName, use LanguageRegistry:
LanguageRegistry.addName(tungstenOre, "Deific Ore of Invincibility");
If you're ever confused on what to replace a ModLoader method with, look at the source in the forge folder of MCP. You can find the source for FML's compatibility "ModLoader" in forge/fml/client/net/minecraft/src. Look at the source and you'll see which FML methods the ModLoader methods pass their info on to. For example, ModLoader.addRecipe() looks like this:
This was great! I got my mod converted to Forge. Thankyou thankyou thankyou thankyou!
A couple points: it was scary at first, but I stuck with it. Everything done in a single day. There were over 100 errors at first, but then I ModLoader calls to registerBlock and addName to the Forge way. Replaced all calls to addOverride with the Forge method. And I moved all such calls from the constructor to load(). One very good tutorial for ModLoader says the only way to create custom armor and tool material attributes is to directly modify base classes EnumArmorMaterial and EnumToolMaterial. I replaced that with calls to EnumHelper.addArmorMaterial. With ModLoader my custom animation had to be registered with ModLoader.addAnimation, but that call had to be made in an overrid method registerAnimation in my mod base class. With Forge you still use ModLoader.addAnimation, but that call is placed directly in load(). The constructor for my custom TileEntity was marked protected, copying what I saw in vanilla Minecraft. To work with Forge, I had to mark the constructor public.
Another big conversion from ModLoader to Forge: you have to add A LOT of import statements. Just "import net.minecraft.src.*;" is not enough. You have to add an import for every Minecraft folder that particular class uses.
Rather than directly modify the vanilla Minecraft Furnace, I added hooks by creating a new furnace which extended the vanilla one. Then to ensure players always get the new furnace, I removed the crafting recipe for the vanilla furnace. With ModLoader I did this by modifying the Minecraft base class that creates crafting recipies. But I found a way to remove a vanilla Minecraft crafting recipe, so no base class modification required. I still have a small modification to 2 Minecraft base classes, but that's necessary to add gas.
I'm putting my question in this separate post. How do I prepare my mod for upload? I can run within Eclipse, but how to I bundle it? With ModLoader, you start with the MCP batch file to recompile. I tried that, but got an error message that server source code is missing. I had placed the latest minecraft_server.jar file in the jars folder before running the Forge installation script. There's a minecraft_server.jar.backup file, so presumably it found it. If I run the MCP batch file startclient it works. When I run startserver it opens a server window, but has errors. The first two lines are:
[INFO] Starting minecraft server version 1.4.7
[SEVERE] Encountered an unexpected exception NoClassDefFoundError
Ok. That's standard MCP stuff. Before that I have to recompile. My problem is that doesn't work. Server problem.
I put minecraft.jar in folder jars/bin, but put minecraft_server.jar directly in jars. This is what the MCP script decompile requires. Is that right for Forge? Now the src folder has only one subfolder: minecraft. There is no minecraft_server. There was when used the MCP decompile script for ModLoader.
Like I explained in the OP, Forge mods are Universal. Your mod will already fit into either the client or the server. There's no need to write it twice.
That's what I was expecting. And hoping for. But...
In the logs folder I found these:
There isn't any server_compile.log. And server_deob.log has
# Warning: package net/minecraft/client not found in JAR
# Warning: package com not found in JAR
# Warning: class bbl not found in JAR
# Warning: class bbm not found in JAR
# Warning: class bbn not found in JAR
# Warning: field auq/c not found in JAR
# Warning: field auq/b not found in JAR
# Warning: unknown class Side in cpw/mods/fml/relauncher
# Warning: unknown class SideOnly in cpw/mods/fml/relauncher