A lot of people seem to be very intimidated by trying to jump from ModLoader to Forge. This tutorial will, hopefully, break it down and make it easier.
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.
Universal Mods
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.
Packages
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:
package net.minecraft.src;
Change that in every file into this:
package derp;
import net.minecraft.src.*
Now, all your files will be part of their own package in their own folder, but still have access to vanilla code.
Imports
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:
package cpw.mods.fml.common.registry
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.
Load
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:
@Init
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:
@Init
public void startMod(FMLInitializationEvent event)
Or this:
@Init
public void loadDaMod(FMLInitializationEvent event)
Or even this:
@Init
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:
@PreInit
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:
@PostInit
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:
ModLoader.registerBlock(tungstenOre);
Instead of using ModLoader for that, use GameRegistry:
GameRegistry.registerBlock(tungstenOre);
Of course, to use GameRegistry, you'll need an import:
import cpw.mods.fml.common.registry.GameRegistry;
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:
and dose this tutorial work with 1.4.4? cause iv got my MCP to load properly its just I'm running every thing on 1.4.4 but im thinking it will so ill try
and dose this tutorial work with 1.4.4? cause iv got my MCP to load properly its just I'm running every thing on 1.4.4 but im thinking it will so ill try
It should, barring any catastrophic changes to the Forge API in 1.4.4.
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
When you're ready to publish your mod, you use MCP's "Reobfuscate" script to output your obfuscated .class files. Package those and any other files you need into a zip or .jar file.
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.
The point of converting to Forge is to get it to work multiuser. How do I get the server mod?
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.
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:
client_compile.log
client_deob.log
client_exc.log
client_rg.log
mcp.log
mcperr.log
server_deob.log
server_rg.log
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
(Still under construction! )
Contents
Setting Up MCP
Universal Mods
BaseMod and Annotations
Packages
Imports
Load
Registering Things
Setting Up MCP
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.
Universal Mods
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:
This is probably how your ModLoader mod looks. You can now change that to this:
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:
I'll explain Imports a little more later into the tutorial.
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.
Packages
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.
Imports
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:
Importing something into your file allows you to use it. So, if you wanted to use EntityRegistry in your code, you'd need to import it 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.
Load
In ModLoader, you had to put all your mod's main stuff in something like this:
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:
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:
Or this:
Or even this:
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:
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:
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:
Registering Things
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.
Instead of using ModLoader.addName, use LanguageRegistry:
Which also needs to be imported:
Instead of using this to add smelting recipes:
Use GameRegistry:
Instead of using ModLoader to add recipes:
Use GameRegistry:
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:
Mod Author and Owner of Blockhole
Owner of other discontinued or status frozen work: LimpCraft2, LimpCore, InventoryCalculator, VillageTech, Bitto'Color.
i just made a forum post with pictures and code etc, they helped me fix it... i forgot to add the /lib jars into the library
Mod Author and Owner of Blockhole
Owner of other discontinued or status frozen work: LimpCraft2, LimpCore, InventoryCalculator, VillageTech, Bitto'Color.
Could you be a bit more specific about what these "100 errors" are? Did you make sure to install the Forge source correctly?
It should, barring any catastrophic changes to the Forge API in 1.4.4.
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.
[INFO] Starting minecraft server version 1.4.7
[SEVERE] Encountered an unexpected exception NoClassDefFoundError
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:
client_compile.log
client_deob.log
client_exc.log
client_rg.log
mcp.log
mcperr.log
server_deob.log
server_rg.log
There isn't any server_compile.log. And server_deob.log has