Minecraft Forge: Quick Tips For Setting Up Workspace And Eclipse

Setting Up Java For Minecraft Forge


See my tutorial on this topic: Setting Up Java For Modding

Install The Eclipse Java IDE


An IDE is an Integrated Development Environment used by programmers to help them develop and test computer code. It is possible to write Java using simple text editors but a good IDE like Eclipse will make you much more productive by helping you look up available methods quickly and warning you about mistakes in the code.

Forge most easily supports Eclipse and another IDE called IntelliJ. Both are worthy editors and there is a lot of debate about which is better, but I personally use Eclipse so my instructions here are for that.

Eclipse can be used with many different programming languages so you want to install the setup that is already optimized for Java.

You should download and install the Eclipse Java IDE from the Eclipse download page.

Installing The Forge Files


Warning: The "Forge" that developers need to install is different than the one that players use -- developers need the whole decompilation and mapping environment files. This requires downloading the MDK not the Installer as explained below.

Tip: It is highly recommended to check for updates regularly. Forge is updated frequently. There are major upgrades when new versions of Minecraft come out (1.7.10, 1.8.2 and so forth) but there are also lots of fixes in between.

The first decision you need to make is which version of Minecraft you want to modify. With Forge you can go all the way back to versions like 1.6.4. However, it is highly recommended that you work with either the latest or second most recent versions as the Forge team no longer maintains anything older plus the programming interface is much more powerful and easy to use in later versions.

Then you need to go to the Forge Download page and select the MDK (not the Installer!) file that matches the version you want to use.

After downloading the MDK you need to extract it (it will be compressed in ZIP format) and copy it to your disk location that you will be using for your Eclipse workspace. I usually rename the folder to be the name of my mod as well (something like CoolMod-1.12) since someday you'll probably have lots of mods in progress and need to keep them organized!

Important: Make sure the SRG mappings are up-to-date before continuing (see section below on updating the mappings).

Next you need to run the Gradle commands that will download additional necessary files from the Internet, decompile and map the Minecraft source files, and otherwise set up the project to be ready for programming in Eclipse. To do this you need to:
  1. Open a command window in the directory.
  2. execute the command gradlew setupDecompWorkspace
  3. execute the command gradlew eclipse
If you get any errors during these commands, follow the information that is displayed to correct the error and try again (it doesn't hurt to rerun these commands, even after you've started programming your mod).

Next you need to go into Eclipse and import the project. It should be ready to go after that. You can test it by using the built-in Run Configurations to check that it compiles and executes.

Using Latest MCP / SRG Mappings


Mojang doesn't officially publish a modding source, so the vanilla source that we use in modding has to be deobfuscated. But even then the names (called SRG names) of the methods and fields are not easily human-readable (you'll see some of these like a field called f_234353_b and things like that).

To make modding easier, the MCP project has created mappings from the SRG names to human-readable methods and fields.

This mapping is done automatically for you when you set up your Forge workspace using gradlew setupDecompWorkspace and then back again when you actually build your mod. However, it is important to know about MCP mappings for several reasons:
  1. Sometimes the mappings in the build.gradle file are old and you may be missing some or even have ones with errors. Therefore, I highly recommend that every time you update your workspace or build your mod that you use the latest mapping. You do this by editing the build.gradle so that the Minecraft{} block contains a line like this (include the quotation marks):
    • For 1.8 use snapshot: mappings = "snapshot_20150808"Key Point: Since snapshots are made daily, you should change the last part of this to be your current date (or at least a recent date) every time you setup or update the workspace.
    • For 1.7.10 and earlier use stable release as listed on MCP project site. For example: mappings = 'stable_12'
  2. It helps you understand porting mods to the next version because it always takes a while for them to figure out the updated mappings. So if you start modding on 1.9 when it first comes out on Forge, you might have to deal with a lot of SRG names for a while.
  3. You can contribute to the mappings to make it better. You can log an issue at the MCP project suggesting a mapping or correction to a mapping.
Tip: Thanks to shadowfacts for this tip! If you private message MCPBot_Reborn on EsperNet, you can use !gc!gm!gf, and !gp (get class, get method, get field, and get parameter) to find more information.

Setting Up Revision Control Using git-based SourceTree

When programming it is very likely that you may make a mistake or corrupt a file in a way that you wish you could go back to an earlier time when it was still working. Revision control is a system for doing this where you can regularly "check in" your code and then later restore it to the earlier checked-in version.

Revision control is also very useful if you have multiple people contributing code to the same project since it helps synchronize your code across the different computers.

Lastly, even if you're the only programmer you may want to work on the same project from multiple computers (for example I sometimes program on a desktop and when I'm traveling I program on my laptop). Revision control will help you synchronize the code across all your computers.

f you already are familiar with setting up a revision control using something like Git you should do that now. If you're not familiar with how to do that, I suggest you use the graphical front-end for git called SourceTree: See my tutorial on this topic: SourceTree Set-Up For Minecraft Forge.

Warning: A revision control system is only useful if you check-in your code regularly! I suggest at a minimum to check it in at the end of every programming session, and I personally also check-in multiple times while programming whenever I achieve a successful change.

Make Sure You Edit the eula.txt File To Accept


One thing that people can run into is that you need to accept the End User License Agreement ("EULA") in order to run a Minecraft server. To do this, you need to go into your working directory and search for the eula.txt file. Open that file and edit it so that it says true.

Recommended: Set Up Your IDE For UTF-8 Text Encoding


To ensure cross-platform compatibility and to ensure things like your language localization files work with accented languages like Portuguese, it is highly advised that you set up your IDE to use UTF-8 encoding everywhere possible.

Here is a tutorial on how to set this up for Eclipse: UTF-8 In Your Eclipse Java Projects.

Run Configurations


In Eclipse it is important to set up your Run Configurations properly.  For modding it is good to have a run configuration for Server and one for the integrated Client-Server (often called "client" but includes server too).

Setting Up The "Client" Run Configuration

In recent versions of Forge, some of the below steps may be already set up (during the gradlew eclipse command), but it is still worthwhile going through each field to double-check it is filled in correctly.
  1. In Eclipse, from the Run menu select Run Configurations
  2. In the Run Configurations window, right-click on the Java Applications and select New
  3. In the Name field, enter a name that is meaningful to you.  I usually use the mod name plus "Client".
  4. In the Main tab, in the Project field select the project from list of available projects.
  5. In the Main tab, in the Main Class field select Search and then select "GradleStart"
  6. In the Arguments tab, in the Program Arguments field enter:
    • For 1.8.8 use " --version 1.8 --accessToken accessToken --userProperties={} --assetIndex 1.8 --assetsDir C:/Users/<your username>/.gradle/caches/minecraft/assets" (where you replace <your username> with your computer username, not Minecraft username)
    • For 1.8 use " --version 1.8 --tweakClass net.minecraft.fml.common.launcher.FMLTweaker --accessToken accessToken --userProperties={} --assetIndex 1.8 --assetsDir C:/Users/<your username>/.gradle/caches/minecraft/assets" (where you replace <your username> with your computer username, not Minecraft username)
    • For 1.7.10 use " --version 1.7 --tweakClass cpw.mods.fml.common.launcher.FMLTweaker --accessToken accessToken --userProperties={} --assetIndex 1.7.10 --assetsDir C:/Users/<your username>/.gradle/caches/minecraft/assets" (where you replace <your username> with your computer, not Minecraft, user name)
    • For 1.7.2 use " --version 1.7 --tweakClass cpw.mods.fml.common.launcher.FMLTweaker --accessToken accessToken"
  7. Optionally: These run configurations will log you in as a random player (with a username like Player1364) with default skin. If you want to log in consistently (this is important for testing mods that remember a player, like a custom tamed mob) or want to download your personal skin, you should further add these arguments:
    • "--username=<your e-mail address> --password=<your password>" where you put in your Minecraft login credentials.
  8. In the Arguments tab, in the VM Arguments field enter "-Xmx4G -Xms4G -Dfml.ignoreInvalidMinecraftCertificates=true"
  9. In the Arguments tab, in the Workspace section choose what is appropriate.  In my case I choose Other and enter in "${workspace_loc}\run" because I use LexManos' suggestion for multi-mod development environment (where he recommends creating a shared run folder in the workspace).
  10. Usually the rest of the tabs (JRE, Classpath) should be filled out correctly by default.  If you're using workspace with multiple mods interacting with each other, you may need to do more with the classpath and libraries.

Setting Up The "Server" Run Configuration

In recent versions of Forge, some of the below steps may be already set up (during the gradlew eclipse command), but it is still worthwhile going through each field to double-check it is filled in correctly.
    1. In Eclipse, from the Run menu select Run Configurations
    2. In the Run Configurations window, right-click on the Java Applications and select New
    3. In the Name field, enter a name that is meaningful to you.  I usually use the mod name plus "Server".
    4. In the Main tab, in the Project field select the project from list of available projects.
    5. In the Main tab, in the Main Class field select Search and then select "GradleServerStart"
    6. In the Arguments tab, in the Program Arguments leave it blank.
    7. In the Arguments tab, in the VM Arguments field enter "-Xmx4G -Xms4G -Dfml.ignoreInvalidMinecraftCertificates=true"
    8. In the Arguments tab, in the Workspace section choose what is appropriate.  In my case I choose Other and enter in "${workspace_loc}\run" because I use LexManos' suggestion for multi-mod development environment (where he recommends creating a shared run folder in the workspace).
    9. Usually the rest of the tabs (JRE, Classpath) should be filled out correctly by default.  If you're using workspace with multiple mods interacting with each other, you may need to do more with the classpath and libraries.

    Using Custom Asset Resources In Your Project


    As a modder you're probably familiar with various standard assets, such as textures, sounds and lang files.  However, you may have a need to create your own asset.  For example, you could have a file that contains a map or schematic for a castle structure.  

    You cannot use Java file I/O (like FileReader) because this asset will be contained within the JAR of the mod, which is compressed and not directly readable and also the location may change.  Therefore, instead you need the getResourceAsStream() of the ClassLoader which can find files within the classpath including within the JAR.

    Another issue is that you will want to be able to read values (strings, ints, booleans, etc.) from the file and so need to get the information into a format that has such methods.  The BufferedReader class is suitable.

    So, assuming you have your custom data file in a package such as assets.yourmodid.yourassettype (replace yourmodid and yourassettype to suit your needs) then you can get the data into a BufferedReader via an InputStreamReader with following code:

    readIn = new BufferedReader(new InputStreamReader(getClass()
          .getClassLoader()
          .getResourceAsStream("assets/yourmodid/yourassettype/"+fileName), 
                "UTF-8"));
    

    NotefileName should hold the string value of the file name, including the file extension (e.g. "my_file.txt").

    Note: Like most I/O operations, your IDE (like Eclipse) will require you to surround the code with a try-catch construct because file system errors are common and need to be handled.  Just accept the suggested fix that Eclipse provides.

    Next, to read values from the stream you can use the methods that BufferedReader provides, such as readLine() and other various read() methods.  If you know the length of the file, you can use a for loop to get through the data, otherwise you should use the standard I/O practice of doing a while loop which checks for the readLine() returning null (indicating end of the file) or other similar methods for detecting end of the data stream.

    Setting Your Mod To Output Debug Level Logger Info


    In modding it is useful to confirm proper operation of your code by printing out statements to the console. This can help you track values in real time, indicate code paths where some problem was encountered, etc.

    While it is possible to use System.out.println() to print to console, it is considered better programming practice to use a Logger which lets you select the level of console output you want. So then if you don't want to see debug statements you can turn it off, then turn it on again later. This is particularly important when multiple people are working on same mod as you won't always want your console messed up with other people's debug statements.

    For a logger, it is recommended to use the Apache log4j system. In that system there are multiple levels of output possible, such as INFO and DEBUG. You create an instance of this in your main mod class, then you can call it with something like MyMod.logger.debug("put your debug info here").

    However, there is a problem: Minecraft Forge has the logger level hard-coded at INFO and so the regular methods of using arguments or XML files to configure the output level won't work.

    The good news is there is a work-around (thanks to WorldsEnder for this tip). You can edit the configuration file directly in the Minecraft JAR in your workspace. Here are the steps:

    1. Find the JAR that was downloaded by gradle when you built the workspace. It should be in a location something like this: <your user profile>\.gradle\caches\minecraft\net\minecraftforge\forge\1.8-11.14.3.1450\snapshot\20150903. Note that the exact version and snapshot will change each time you update Forge, but just make sure it is the right one based on your build.gradle file for your mod. In that folder, the JAR should have name something like: forgeSrc-1.8-11.14.3.1450.jar.
    2. Open or extract the JAR with an unzipping program. In recent Windows versions you can open it directly, otherwise you'll need something like 7-Zip or WinZip.
    3. Edit the logger configuration file. There should be a file named log4j2.xml in there, open it and edit the line where it says <AppenderRef ref="FmlSysOut" level="INFO" /> to <AppenderRef ref="FmlSysOut" level="DEBUG" />
    4. Save and override the file in the jar. Next time you run your mod should now see debug output on your console!
    Warning: You'll have to redo this every time you update your Forge version.

    Setting The Target Java Version Compatibility


    As Java progresses, new features are available that you might use in your code. If you don't specify, you may get build errors if the build defaults to an older version that doesn't support your code. 

    To fix this, if for example you use features from Java 1.7 or later you would put the following in your build.gradle file:
         sourceCompatibility = 1.7
      targetCompatibility = 1.7

    Updating Forge Version On An Existing Workspace


    Forge is constantly updating, sometimes by a couple versions per day, and it is usually (not always) a good idea to keep up with the latest version.  You will be warned that you're out of date when you run your mod and the launcher will usually have some text indicating the version you're running and the latest version available.

    In any case, whether you're keeping up with the latest version or occasionally updating based on the recommended version, you will have to update forge on an existing project.

    Tip: You don't have to download the new Forge source manually. Instead, you just have to edit the build.gradle file for Forge to reference the new version and it will download it for you.

    Here are the steps:
    1. Make sure you backup your workspace.  You've been warned! Either using a version control system (like git), or by simply copying the entire workspace folder to somewhere else on your hard drive.  This is important because the steps below will automatically overwrite a lot of the workspace files and it will be difficult to recover if things go wrong.  Also, occasionally the new Forge version has bugs and you'll want to revert to your previous version.
    2. Make sure Eclipse is closed and any other files you may have been editing have been saved and closed.
    3. For every one of your projects:
      1. Edit the build.gradle file by overwriting the line that specifies the Minecraft version.  For example it might look like:  minecraft {version = "1.7.2-10.12.0.997"}You want to edit this with the new version number (this is usually listed on the Forge download page).
      2. Edit the build.gradle file so that the Minecraft section has an entry for MCP mappings that points to recent snapshot. This will give you the best SRG name mappings. Something like mappings = "snapshot_20150411" where you can change the date to the same day you're editing it.
      3. Open a command window in the project top folder.(Shift-Right-Click on project folder)
        • Enter “gradlew setupDecompWorkspace” and wait for the process to complete (may take a few minutes)
        • Enter “gradlew eclipse” and wait for the process to complete (may take a few minutes)
    Note: Occasionally the distribution will change the gradle wrapper version -- if this happens you'll get an error about this when running the gradlew commands.  If that happens you need to update the gradle-wrapper.properties file as well.  I usually do that by downloading the source and copying the gradle-wrapper.properties file on top of the old one (found in the gradle/wrapper/ folder).

    Tip: Remember you need to update Forge in each of your projects.  Repeat the steps above for each project, and the nice thing is that the gradlew commands should execute much faster each time.

    Warning: If you have Eclipse open when you do the update, it might take some time before it "sees" the update. To force Eclipse to recognize the update, you can right-click on the project and select Refresh.

    Library "Shading" Using Gradle


    In some cases you need to ensure a library is available at run-time that is not among the guaranteed libraries (e.g. GSON). To do that you can use Gradle "shading". Mor more information check out the Official Library Shading Tutorial.


    Development Environment For Mods That Depend On Each Other


    After you've been modding for a while, you might decide that you'd like your mods to work together. Or you might want to use an API of some other modder's mod.

    In Eclipse, there are a few similar but distinct methods (libraries, required "dependency" projects, linked source, etc.) indicating that other project code should be accessible to the current project. However, you need to be aware that while all of these methods are pretty straight-forward in the development environment (i.e. when run from Eclipse), unless you know the exact differences they may not work when deployed (i.e. when someone downloads both mods separately and installs them into Minecraft Forge.

    To have projects work together in Eclipse, generally you need source for them all (and build them all together) or you need an API designed to let them work together even if built separately.

    If you just want to interact with another mod (which would be a dependency for your mod), you need to deobfuscate the mod first. Either the mod author is providing you with a deobfuscated version already or you do it yourself using BON2. Then put the mod in mods folder. Later if you publish your mod, the users will have to download the other mod(s) in their obfuscated form.

    For more information:

    Using JUnit With Eclipse For Unit Testing


    It is good programming practice to "architect" the API of your classes before actually implementing them. In other words, you should think through all the ways other code needs to interact with your class and prototype (list the names, parameters and return values) for each method.

    Once you've done that, it is also good practice to create "automatic" testing to ensure that your code behaves the way it should after implementation. This is particularly helpful in testing for "regressions" (which means introduced errors when you later change the code). Such testing is called "unit testing". Ideally you'd unit test every class in your code every time you plan to release your mod.

    Java programmers use a common unit testing library called JUnit. Here is a tutorial on using JUnit with Eclipse.

    To use JUnit effectively, you'll need to initialize and clean-up which you can do by adding @Before and @After annotations.

    You should examine all the capabilities of JUnit as contained in the JUnit wiki. Be sure not to miss Exception Testing, Theories, Rules and Categories.

    However, with modding unit testing is not so simple because most classes (including custom classes you write) will depend on many other existing classes. Therefore, you are likely to need to create "mock" classes for those dependencies used in the unit test. Here is a good overview of when and how you can use mocking in unit testing.

    Note: Some people use unit testing simple-mindedly as a per-method test scheme. You don't actually need to have a test for every method for every class, rather you need a test that covers a "unit" of functionality which may encompass multiple classes.

    Key Point: Be smart about your testing and make sure it is really trying to find things that could go wrong, rather than just confirm what should go right. Your unit test should stress the code by putting in weird values of input, etc. This article gives good direction on how to test smartly.

    Detect Whether You're Running From Development Environment


    Thanks to diesieben07 for this tip.

    boolean developmentEnvironment = (Boolean)Launch.blackboard.get("fml.deobfuscatedEnvironment");
    

    This will be true when running in "decompiled gradle code" mode.

    Running Obfuscated Mods In Dev Environment


    Put CodeChickenCore (either obfuscated or dev version) in the mods folder you can run obfuscated mods in the deobfuscated environment.  You can find out more here: CodeChickenCore

    Organizing Sound Assets


    See my supplementary tutorial: Jabelar's Sound Assets Tutorial

    No comments:

    Post a Comment