In this tutorial, I will cover how to install an API in a manner that does not require you to place the entire API directly in your project directory, how to build and package your mod independently from the API so that you are not distributing other people's mods with your own, and how to utilize an API such that your mod will still function without it, but will still be able to take advantage of the extra features when it is present.
I struggled with this myself while working on my own mod, but thanks to GotoLink's guidance and extreme patience I finally got everything working, and I figure the things I learned will be greatly beneficial to anyone else looking to hook into another mod's API.
Before we start, do note that this tutorial assumes that you are already capable of writing your own mod; I will not be providing any support here for the basics of setting up a mod. Also, this tutorial assumes that you are using the latest versions of Forge, meaning that you are also using Gradle, as the vast majority of mods with APIs all use Forge.
1. Assuming you already have your workspace set up, create a new folder named "/libs" in your project directory. That's the directory that contains your /bin, /build, /gradle, and /src folders, and now also has a /libs folder.
2. Ask the mod author(s) for a binary distributable / source file of their mod and place it in the /libs folder you just created.
3. In Eclipse, right-click on your project, select "Build Path" and then "Configure Build Path". Click the "Libraries" tab, then "Add External JARs" and find the binary file that you just placed in the /libs folder.
4. If the API author provided a source file, open the "Referenced Libraries" tree in your package explorer, find the API binary that you just referenced and right-click on it; go to "Properties" -> "External location" -> "External file" and navigate to wherever you stored the source file, preferably right next to the binary in the /libs folder.
5. Run your debug configuration and see if everything is still working; if so, great! If not, you may need to run setupDev and setupDecomp workspace one more time:
a. gradlew setupDevWorkspace
b. gradlew setupDecompWorkspace
c. gradlew eclipse // will vary depending on your IDE
Once you have the debug client working, you should see that both your mod and the API are loaded; if you start a new game, anything added by the API mod will be in that game as well and should be fully functional. This is extremely handy while developing an addon or simply testing compatibility between mods.
You are now ready to start using the API in your mod!
NOTE: Not all APIs will be able to use this setup; core mods, for example, can be tricky to work with due to their access transformers needing to modify the vanilla jar before being usable.
Let's take Battlegear2's API as an example.
1. For BG2, the binary distributable should be placed not in the project directory, but wherever you have designated as the working directory in a "/mods" folder. For most people using Eclipse, this will be your "projectDirectory/eclipse/mods", or if you followed Lex's multi-project workspace video, in "workspaceLocation/run/mods", though I recommend pointing your API-dependent mod's workspace at its own local eclipse directory instead of the /run directory so you don't have to perform all of the following steps for every single mod in your workspace.
2. Then, follow steps 3, 4, and 5 above, run the debug client, start a game and try to open the inventory. The game should crash at this point with an Illegal Access Error - that's the access transformer failing.
3. Find the "battlegear_at.cfg" file, place that in your resources directory and re-run all of the commands from step 5, then try again.
4. If it crashes again, check in your /build directory for a "deobfuscated-bin.jar" file - this is the modified Minecraft jar - and change your library reference from "forgeSrc..." to that file instead. If you don't see that file, you may need to close Eclipse and run the commands again with "--refresh-dependencies". Note that in 1.7.2, I have never found this file and it still seems to work, but in 1.6.4 it seems to be required. Your mileage may vary.
5. At this point it should work, but if it doesn't, make sure that you are using EXACTLY the same version of Forge for which the core mod was written, because if any of the fields it tries to modify have different names, the process will fail and you will most likely get an exception when attempting to access that field.
It can be very frustrating and time-consuming working with core mod APIs, sometimes requiring those same steps to be repeated over and over again even after you have successfully set it up once when, for example, you clean your project or otherwise re-reference the Forge Minecraft jar instead of the one modified by the access transformers.
Step 2: Implementing an API Interface
Our first order of business will be creating a new Item that can pick up blocks using Zelda Sword Skills' ILiftBlock interface. Simply create a new Item class and implement ILiftBlock. You should be able to import it right away, but you may need to explicitly tell Eclipse where to look, or fix your project setup if you forgot to add the API as a referenced library. Be sure to link the API source if you have it so you get readable names as method parameters, rather than arg0, d1, etc., and then let Eclipse add the unimplemented methods for you.
public class ItemLifter extends Item implements ILiftBlock {<br>public ItemLifter(int id) {<br>super(id);<br>}<br><br>@Override<br>public BlockWeight getLiftStrength(EntityPlayer player, ItemStack stack, Block block, int meta) {<br>// TODO Auto-generated method stub<br>return null;<br>}<br><br>@Override<br>public ItemStack onLiftBlock(EntityPlayer player, ItemStack stack, Block block, int meta) {<br>// TODO Auto-generated method stub<br>return null;<br>}<br>}<br>
I'll let you handle the basics of the Item and focus on the API methods. There are just two methods to implement for this interface, and the first one requires another API class, BlockWeight, which should already have been imported. Just type in BlockWeight followed by a period to see a list of options; we'll choose "EXTREME_II" just for fun, even though there aren't any blocks in that category (yet).
The second method asks us to return an ItemStack, and the java-docs explain that this is the stack that will be returned to the player when the block is placed. We want to get our item back, so we will return "stack" instead of "null", but first we will damage the stack by 1 so that it will eventually break. Now our methods look like this:
Go ahead and start up the client in Eclipse; you should have an item that picks up any solid block that you right-click on, and returns the same item but slightly damaged when you place the block down.
Now, if you were to build the mod and attempt to play it in Minecraft without Zelda Sword Skills installed, your game will crash with a No Class Definition Found error, since we are trying to access several API classes that are not present. So, before we build the mod, we will first add some code that will strip the API interface and methods if the required mod classes are not present.
Step 3: Stripping Interfaces
Luckily for us, FML is capable of stripping interfaces by using cpw's awesome @Optional.Interface annotation.
There are 3 fields we need to fill out: iface, modid, and striprefs:
1. "iface" is the complete package path of the interface we wish to strip, so it is best to simply copy the import path and paste that in to avoid any typos. If you get the path incorrect, it will not work.
2. "modid" is obviously the modid of the mod that owns the interface to strip. Again, be sure to spell it correctly.
3. "striprefs" set this to true to strip interface and method references that are not found. I don't know why anyone would ever set this to false, but I'm sure there are uses for that as well.
Add the annotation above the class declaration:
@Optional.Interface(iface="zeldaswordskills.api.item.ILiftBlock", modid="zeldaswordskills", striprefs=true)<br>public class ItemLifter extends Item implements ILiftBlock {<br>
Make sure you import "cpw.mods.fml.common.Optional" and not the google Optional class.
One last thing we should do is strip the API methods from the class, though the mod will probably still work just fine even if you do not. It's just one simple line: @Method(modid="apiModId"), and you absolutely should use it if the API method in question is not part of an interface that you are stripping.
// put this same line above all API methods:<br>@Method(modid="zeldaswordskills")<br>@Override<br>public BlockWeight getLiftStrength(EntityPlayer player, ItemStack stack, Block block, int meta) {<br>return BlockWeight.EXTREME_II;<br>}<br>
Step 4: Load Order
Once you have your API-utilizing mod all working in the debug environment, there are a few things that should be done before building and packaging the final product. The first is to make sure your mod will load after the mod whose API you are using; this is done in the mcmod.info file. Let's take a look at some of the available fields:
1. "requiredMods": [ "Forge", "someOtherMod" ],
Any mods you list here will be required for your mod to load; your mod cannot load without them. Since we want our mod to be functional even if the other mod is not present, we will not be using this field here, but it is very useful if your mod requires some other mod's functionality in order to be usable.
2. "dependencies": [ "zeldaswordskills" ],
Any mods that your mod is dependent upon will be loaded before yours; this is very important if you need to know that a mod is present or not during the pre-initialization stages, and is generally a good idea to put any mod that your mod might rely upon as a dependency, even if you do not need to do anything with it in the early stages of mod loading.
3. "dependants": [ "ModSubmodule" ]
Any mods listed here are mods that depend upon and will be loaded after your mod; useful if you make a submodule of your own mod. Note that the submodule should list the parent mod as a dependency and possibly required mod.
4. "useDependencyInformation": "true"
You MUST set this to "true" or the above three fields will be meaningless as far as mod order is concerned. If you omit this field, chances are someone will crash when your mod is installed alongside the dependency, even if you don't. This is because if our mod loads before the api, when we try to access the api methods, they will not yet exist.
For this tutorial, we will only add the "dependencies" and "useDependencyInformation" lines, ensuring that the API we want to use is loaded first if present.
For many APIs, assigning dependencies in mcmod.info should be enough to guarantee load order. This is the case for any API that does not require access during the pre-initialization stages of a mod, for example if you were using a structure generation or mob animation API. Before using any methods or classes from such APIs, it would be sufficient simply to check if the mod is loaded:
if (Loader.isModLoaded("api_modid")) {<br>// do something with the API<br>}<br><br>// If I need to access this frequently, I typically store the mod loaded state during pre-initialization:<br>public static boolean isWhateverApiLoaded;<br><br>@EventHandler<br>public void preInit(FMLPreInitializationEvent event) {<br>isWhateverApiLoaded = Loader.isModLoaded("whateverAPI");<br>// note that this only means that the mod has been recognized, not necessarily that it is fully<br>// initialized and ready to go yet; you should NOT try to use anything to do with the API<br>// until the FMLInitializationEvent at the earliest, even with dependency information sorting<br>// the load order, just to be safe<br>}<br>
However, since we require the API to be loaded in time for our new Item, we need access to a fully-functional API during our mod's pre-initialization event. The only way to load an API prior to pre-init is if the author included API markers for each of the API packages:
// filename is "package-info.java" for every one of these files<br>@API(owner = "zeldaswordskills", provides = "ZeldaAPI", apiVersion = "0.1")<br>package zeldaswordskills.api;<br><br>import cpw.mods.fml.common.API;<br>
There should be one of these files in every package that provides API features; if not, you will need to contact the API author and ask them to provide these files, or your mod is quite likely to crash if not for you, then for the majority of people using your mod. Remember, these markers are ONLY needed if you require the API during pre-initialization, such as for implementing specific interfaces in your Items or Blocks, so don't trouble the author if the API does not truly require them.
Step 5: Building the Mod
The final step is of course building the mod. Since our mod is dependent upon an API, we need to let the compiler know where to find that code during the build process or we will get lots of Class Not Found and similar errors.
To do so, simply add any dependencies to a "compile files()" method in the build.gradle file, using the full path relative to your project directory and separating each file path with a comma. Note that you can use "../" to move up a folder if, for example, you have a dependency in the working directory instead of the project directory.
"libs/zeldaswordskills-1.6.4-0.6.3.jar" -> located in /workingDirectory/projectDirectory/libs/
"../run/mods/zeldaswordskills-1.6.4-0.6.3.jar" -> located in /workingDirectory/run/mods/
version = "1.0"<br>group= "com.google.coolalias008.modwithapi"<br>archivesBaseName = "modwithapi"<br><br>dependencies {<br>compile files (<br>"libs/zeldaswordskills-1.6.4-0.6.3.jar"<br>)<br>}<br>
Once the build file is saved, open up a command console and run "gradlew build"; it should compile with no errors, but if it doesn't, double-check the file paths and make sure nothing is misspelled.
Time to load it up in Minecraft and give it a go! Try first with just your mod alone and make sure that is working, then exit the Minecraft launcher completely (just to be safe), add the API-providing mod to your /mods folder, and launch once more. If you followed the tutorial and are using my ZeldaAPI, you should now have an item that can pick up any solid block, just by implementing a single interface! Pretty awesome.
Step 6: Multiple Interfaces
Alright, you can do a single interface, but what about when you want to implement several API interfaces in a single item,
block, or other class? You cannot simply stack @Optionals on top of each other, but you can use an InterfaceList:
The individual @Optional.Interfaces are exactly the same as before, but separtated by commas and nested inside of an array, all enclosed by the @Optional.InterfaceList annotation.
Alright, so let's make a block that is both liftable AND smashable by implementing ILiftable and ISmashable. Import those two classes and let Eclipse add the unimplemented methods for you, and be sure to set up the rest of the Block class (texture, creative tab, etc.). I will only cover the API methods here.
@Method(modid="zeldaswordskills")<br>@Override<br>public BlockWeight getSmashWeight(EntityPlayer player, ItemStack stack, int meta) {<br>// let's make our block very easy to smash, since we do not have any smashing items yet, the only<br>// way to smash our block would be using one of the Zelda Hammers<br>return BlockWeight.VERY_LIGHT;<br>}<br><br>@Method(modid="zeldaswordskills")<br>@Override<br>public Result onSmashed(World world, EntityPlayer player, ItemStack stack, int x, int y, int z, int side) {<br>// for the sake of simplicity, we will just use the default smashing mechanics<br>return Result.DEFAULT;<br>}<br><br>@Method(modid="zeldaswordskills")<br>@Override<br>public BlockWeight getLiftWeight(EntityPlayer player, ItemStack stack, int meta) {<br>// we want our block to be extremely difficult to lift, giving our custom itemLifter a purpose;<br>// not even any of the items in Zelda can lift our block! mwa ha ha!<br>return BlockWeight.EXTREME_II;<br>}<br><br>@Method(modid="zeldaswordskills")<br>@Override<br>public void onLifted(World world, EntityPlayer player, ItemStack stack, int x, int y, int z, int meta) {<br>// if you need to handle a tile entity or do anything else before the block is lifted,<br>// you can do so here; however, we do not need to for our simple block<br>}<br><br>@Method(modid="zeldaswordskills")<br>@Override<br>public void onHeldBlockPlaced(World world, ItemStack stack, int x, int y, int z, int meta) {<br>// if you want to do something special when the block is placed, you can do so here,<br>// but we will leave it empty for this tutorial<br>}<br>
That's it for the API methods. Once the rest of the block is set up and registered, you can go ahead and give it a try! You should have a block that can only be lifted with the special itemLifter that we made earlier, but can be smashed even with just the wooden hammer from Zelda. If you run your mod by itself, you will still have the item and block in the game, but without the lifting and smashing mechanics provided by the API. This is great if your items and blocks have other functions that still make them useful independently.
You should now be able to work with pretty much any mod API in a manner that will still allow your mod to function independently should the API-providing mod not be present, as well as avoid including the API code in your mod directly.
Good luck! Don't forget to give GotoLink kudos if you see him around - he likes to hang out over on MinecraftForge forums, so go bump up his karma from time to time!
P.S. If you have any suggestions, clarifications or corrections to the above tutorial, please let me know and I will be sure to add them in. Cheers!
Thanks for the guide! I'm having an issue following it though. I'm trying to use CoFHCore & followed the Battlegear2 example, but I'm getting this error if I reference it from /mod or /lib: http://pastebin.com/ECCQNXMG
Hello, great tutorial! I'm having one issue though. It only seems to work if I set the "useDependencyInformation" to false in the MCMod.info. If it's set to true then I get this NullPointerException during initialization, regardless of whether or not I'm actually using the API.
I followed your tutorial, so this was using your Zelda Sword Skills API with 1.7.2 and forge 10.12.2.1127.
Hello, great tutorial! I'm having one issue though. It only seems to work if I set the "useDependencyInformation" to false in the MCMod.info. If it's set to true then I get this NullPointerException during initialization, regardless of whether or not I'm actually using the API.
I followed your tutorial, so this was using your Zelda Sword Skills API with 1.7.2 and forge 10.12.2.1127.
I tested it back in Forge 10.12.1.1024 and it worked; I wonder if they changed something with the mod loading? If you wanted to do some further testing, you could try removing all mods except for your mod and the API. Looking at my released mod's mcmod.info file, it seems I removed the 'useDependencyInformation' line entirely... curious. I'd have to look more closely at cpw's FML code to see if something funky is going on, but if your build works as it should without that line, then I would just remove it and not worry about it
Thanks for the guide! I'm having an issue following it though. I'm trying to use CoFHCore & followed the Battlegear2 example, but I'm getting this error if I reference it from /mod or /lib: http://pastebin.com/ECCQNXMG
The link has been removed; were you able to get it working, then?
I tested it back in Forge 10.12.1.1024 and it worked; I wonder if they changed something with the mod loading? If you wanted to do some further testing, you could try removing all mods except for your mod and the API. Looking at my released mod's mcmod.info file, it seems I removed the 'useDependencyInformation' line entirely... curious. I'd have to look more closely at cpw's FML code to see if something funky is going on, but if your build works as it should without that line, then I would just remove it and not worry about it
The link has been removed; were you able to get it working, then?
Yeah I had already reduced the project down to nothing but the API and my test mod. It definitely works without the line in there so I will just keep moving forward then. Thanks!
The Meaning of Life, the Universe, and Everything.
Location:
NY
Join Date:
4/15/2014
Posts:
366
Location:
A place..
Minecraft:
Drok_
PSN:
drok0920
Member Details
Hello I wasn't sure where to put this but I saw this(sadly when I read it I was very disappointed) and I though it was how to MAKE an api so can someone direct me to one(if you think this should go somewhere else I will remove my post as long as you tell me where I should put it)?
Did you read Thaumcraft's API manual, if they have one? Depending on how they made it, it may be that you just need to add the code to your project directly. If that doesn't work, try asking the Thaumcraft developer(s) for assistance.
Sorry I can't be of more help, but I don't know how every API out there is supposed to work - the tutorial is just a general guideline for a clean setup, but it requires the API developers to be willing to provide the necessary files.
??? Why do you have a project for "Minecraft"? Each project should be a mod, unless you are using MCP... What version of Forge are you using? If you are not using Gradle, you should be, and if you are, you ought to take a look at tutorial on setting up your projects.
Isn't EVERYONE using MCP? I am using forge 1.7.10-10.13.0.1207 and my mods are in the src folders src/main
Yes, but not directly. In 1.6.4, we used to have to mod with the MCP / Minecraft source directly in the project - thankfully, this is no longer the case. Anyway, I'm still confused why you have a project named "Minecraft" - each of your mods should be a separate project; you can have them all open in Eclipse at the same time, but they are each completely separate from each other and can be run independently.
So if your mod is called "MyMod", you have a project for it also named "MyMod" which encompasses all of the source, assets, build files, etc., as well as referenced libraries such as an API.
I have now set up a multi mod directory and am trying to include an API but cannot see the API's source
Can you describe in detail the steps you are taking to add it? I can't know what you are doing wrong or if it's a problem with the API if I don't know what you are doing. Do you have the deobfuscated jar of the API? Did you add it as a referenced library? Can you import classes from it? If you answer 'no' to any of those, then that's what you need to do.
I have the deobf'd jar in my libs folder, added it in as an external jar, you can import classes from it but you cannot see the source.
Ok, great. Right-click on the file from inside Eclipse and choose 'Properties' - this will bring up a menu allowing you to choose the location of the source files. If you don't have them and the deobfuscated version isn't letting you view it, then you should be able to download the src files from the mod's page and place them in an external directory, then link it through the 'Properties' menu above.
For people who are interested in a short and simple answer - any files you put in src/api should not get built out into your mod by gradle with the latest version of Forge.
Is this true? Maybe worth adding to the guide if so.
Is this true? Maybe worth adding to the guide if so.
I haven't ever tried that, but if it is true, that would save a few steps. Still, I think I prefer keeping API code out of my src folder, simply for the sake of keeping my mod src clearly separated from any external library src.
I haven't ever tried that, but if it is true, that would save a few steps. Still, I think I prefer keeping API code out of my src folder, simply for the sake of keeping my mod src clearly separated from any external library src.
Good point, src =/= lib - even for required dependencies, I've never seen libraries and sources jumbled together.
MODDING WITH APIs
In this tutorial, I will cover how to install an API in a manner that does not require you to place the entire API directly in your project directory, how to build and package your mod independently from the API so that you are not distributing other people's mods with your own, and how to utilize an API such that your mod will still function without it, but will still be able to take advantage of the extra features when it is present.
I struggled with this myself while working on my own mod, but thanks to GotoLink's guidance and extreme patience I finally got everything working, and I figure the things I learned will be greatly beneficial to anyone else looking to hook into another mod's API.
Before we start, do note that this tutorial assumes that you are already capable of writing your own mod; I will not be providing any support here for the basics of setting up a mod. Also, this tutorial assumes that you are using the latest versions of Forge, meaning that you are also using Gradle, as the vast majority of mods with APIs all use Forge.
If you would like to follow along with the tutorial step-by-step, you can download the API that I will be using here: https://github.com/coolAlias/ZeldaSwordSkills-1.6.4/releases
Step 1: Installing the API
2. Ask the mod author(s) for a binary distributable / source file of their mod and place it in the /libs folder you just created.
3. In Eclipse, right-click on your project, select "Build Path" and then "Configure Build Path". Click the "Libraries" tab, then "Add External JARs" and find the binary file that you just placed in the /libs folder.
4. If the API author provided a source file, open the "Referenced Libraries" tree in your package explorer, find the API binary that you just referenced and right-click on it; go to "Properties" -> "External location" -> "External file" and navigate to wherever you stored the source file, preferably right next to the binary in the /libs folder.
5. Run your debug configuration and see if everything is still working; if so, great! If not, you may need to run setupDev and setupDecomp workspace one more time:
a. gradlew setupDevWorkspace
b. gradlew setupDecompWorkspace
c. gradlew eclipse // will vary depending on your IDE
Once you have the debug client working, you should see that both your mod and the API are loaded; if you start a new game, anything added by the API mod will be in that game as well and should be fully functional. This is extremely handy while developing an addon or simply testing compatibility between mods.
You are now ready to start using the API in your mod!
NOTE: Not all APIs will be able to use this setup; core mods, for example, can be tricky to work with due to their access transformers needing to modify the vanilla jar before being usable.
Let's take Battlegear2's API as an example.
1. For BG2, the binary distributable should be placed not in the project directory, but wherever you have designated as the working directory in a "/mods" folder. For most people using Eclipse, this will be your "projectDirectory/eclipse/mods", or if you followed Lex's multi-project workspace video, in "workspaceLocation/run/mods", though I recommend pointing your API-dependent mod's workspace at its own local eclipse directory instead of the /run directory so you don't have to perform all of the following steps for every single mod in your workspace.
2. Then, follow steps 3, 4, and 5 above, run the debug client, start a game and try to open the inventory. The game should crash at this point with an Illegal Access Error - that's the access transformer failing.
3. Find the "battlegear_at.cfg" file, place that in your resources directory and re-run all of the commands from step 5, then try again.
4. If it crashes again, check in your /build directory for a "deobfuscated-bin.jar" file - this is the modified Minecraft jar - and change your library reference from "forgeSrc..." to that file instead. If you don't see that file, you may need to close Eclipse and run the commands again with "--refresh-dependencies". Note that in 1.7.2, I have never found this file and it still seems to work, but in 1.6.4 it seems to be required. Your mileage may vary.
5. At this point it should work, but if it doesn't, make sure that you are using EXACTLY the same version of Forge for which the core mod was written, because if any of the fields it tries to modify have different names, the process will fail and you will most likely get an exception when attempting to access that field.
It can be very frustrating and time-consuming working with core mod APIs, sometimes requiring those same steps to be repeated over and over again even after you have successfully set it up once when, for example, you clean your project or otherwise re-reference the Forge Minecraft jar instead of the one modified by the access transformers.
Step 2: Implementing an API Interface
I'll let you handle the basics of the Item and focus on the API methods. There are just two methods to implement for this interface, and the first one requires another API class, BlockWeight, which should already have been imported. Just type in BlockWeight followed by a period to see a list of options; we'll choose "EXTREME_II" just for fun, even though there aren't any blocks in that category (yet).
The second method asks us to return an ItemStack, and the java-docs explain that this is the stack that will be returned to the player when the block is placed. We want to get our item back, so we will return "stack" instead of "null", but first we will damage the stack by 1 so that it will eventually break. Now our methods look like this:
Go ahead and start up the client in Eclipse; you should have an item that picks up any solid block that you right-click on, and returns the same item but slightly damaged when you place the block down.
Now, if you were to build the mod and attempt to play it in Minecraft without Zelda Sword Skills installed, your game will crash with a No Class Definition Found error, since we are trying to access several API classes that are not present. So, before we build the mod, we will first add some code that will strip the API interface and methods if the required mod classes are not present.
Step 3: Stripping Interfaces
There are 3 fields we need to fill out: iface, modid, and striprefs:
1. "iface" is the complete package path of the interface we wish to strip, so it is best to simply copy the import path and paste that in to avoid any typos. If you get the path incorrect, it will not work.
2. "modid" is obviously the modid of the mod that owns the interface to strip. Again, be sure to spell it correctly.
3. "striprefs" set this to true to strip interface and method references that are not found. I don't know why anyone would ever set this to false, but I'm sure there are uses for that as well.
Add the annotation above the class declaration:
Make sure you import "cpw.mods.fml.common.Optional" and not the google Optional class.
One last thing we should do is strip the API methods from the class, though the mod will probably still work just fine even if you do not. It's just one simple line: @Method(modid="apiModId"), and you absolutely should use it if the API method in question is not part of an interface that you are stripping.
Step 4: Load Order
1. "requiredMods": [ "Forge", "someOtherMod" ],
Any mods you list here will be required for your mod to load; your mod cannot load without them. Since we want our mod to be functional even if the other mod is not present, we will not be using this field here, but it is very useful if your mod requires some other mod's functionality in order to be usable.
2. "dependencies": [ "zeldaswordskills" ],
Any mods that your mod is dependent upon will be loaded before yours; this is very important if you need to know that a mod is present or not during the pre-initialization stages, and is generally a good idea to put any mod that your mod might rely upon as a dependency, even if you do not need to do anything with it in the early stages of mod loading.
3. "dependants": [ "ModSubmodule" ]
Any mods listed here are mods that depend upon and will be loaded after your mod; useful if you make a submodule of your own mod. Note that the submodule should list the parent mod as a dependency and possibly required mod.
4. "useDependencyInformation": "true"
You MUST set this to "true" or the above three fields will be meaningless as far as mod order is concerned. If you omit this field, chances are someone will crash when your mod is installed alongside the dependency, even if you don't. This is because if our mod loads before the api, when we try to access the api methods, they will not yet exist.
You can learn all about how FML uses the mcmod.info file and other things that you can do with it on the wiki:
https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file
For this tutorial, we will only add the "dependencies" and "useDependencyInformation" lines, ensuring that the API we want to use is loaded first if present.
For many APIs, assigning dependencies in mcmod.info should be enough to guarantee load order. This is the case for any API that does not require access during the pre-initialization stages of a mod, for example if you were using a structure generation or mob animation API. Before using any methods or classes from such APIs, it would be sufficient simply to check if the mod is loaded:
However, since we require the API to be loaded in time for our new Item, we need access to a fully-functional API during our mod's pre-initialization event. The only way to load an API prior to pre-init is if the author included API markers for each of the API packages:
There should be one of these files in every package that provides API features; if not, you will need to contact the API author and ask them to provide these files, or your mod is quite likely to crash if not for you, then for the majority of people using your mod. Remember, these markers are ONLY needed if you require the API during pre-initialization, such as for implementing specific interfaces in your Items or Blocks, so don't trouble the author if the API does not truly require them.
Step 5: Building the Mod
To do so, simply add any dependencies to a "compile files()" method in the build.gradle file, using the full path relative to your project directory and separating each file path with a comma. Note that you can use "../" to move up a folder if, for example, you have a dependency in the working directory instead of the project directory.
"libs/zeldaswordskills-1.6.4-0.6.3.jar" -> located in /workingDirectory/projectDirectory/libs/
"../run/mods/zeldaswordskills-1.6.4-0.6.3.jar" -> located in /workingDirectory/run/mods/
Once the build file is saved, open up a command console and run "gradlew build"; it should compile with no errors, but if it doesn't, double-check the file paths and make sure nothing is misspelled.
Time to load it up in Minecraft and give it a go! Try first with just your mod alone and make sure that is working, then exit the Minecraft launcher completely (just to be safe), add the API-providing mod to your /mods folder, and launch once more. If you followed the tutorial and are using my ZeldaAPI, you should now have an item that can pick up any solid block, just by implementing a single interface! Pretty awesome.
Step 6: Multiple Interfaces
block, or other class? You cannot simply stack @Optionals on top of each other, but you can use an InterfaceList:
The individual @Optional.Interfaces are exactly the same as before, but separtated by commas and nested inside of an array, all enclosed by the @Optional.InterfaceList annotation.
Alright, so let's make a block that is both liftable AND smashable by implementing ILiftable and ISmashable. Import those two classes and let Eclipse add the unimplemented methods for you, and be sure to set up the rest of the Block class (texture, creative tab, etc.). I will only cover the API methods here.
That's it for the API methods. Once the rest of the block is set up and registered, you can go ahead and give it a try! You should have a block that can only be lifted with the special itemLifter that we made earlier, but can be smashed even with just the wooden hammer from Zelda. If you run your mod by itself, you will still have the item and block in the game, but without the lifting and smashing mechanics provided by the API. This is great if your items and blocks have other functions that still make them useful independently.
You should now be able to work with pretty much any mod API in a manner that will still allow your mod to function independently should the API-providing mod not be present, as well as avoid including the API code in your mod directly.
Good luck! Don't forget to give GotoLink kudos if you see him around - he likes to hang out over on MinecraftForge forums, so go bump up his karma from time to time!
P.S. If you have any suggestions, clarifications or corrections to the above tutorial, please let me know and I will be sure to add them in. Cheers!
Be sure to check out my other tutorials:
- EventHandler and IExtendedEntityProperties
- Custom Inventories in Items and Players
- Multi-Input/Output Furnace
- Rendering Your Custom Item Texture
- Overriding shift-click in custom Containers
- Using Potions in Crafting Recipes
- Enchanted Books and Crafting Recipes
Thanks! As long as it helped at least one other person, that's good enough for me xD
http://pastebin.com/ECCQNXMG
:3
I followed your tutorial, so this was using your Zelda Sword Skills API with 1.7.2 and forge 10.12.2.1127.
I tested it back in Forge 10.12.1.1024 and it worked; I wonder if they changed something with the mod loading? If you wanted to do some further testing, you could try removing all mods except for your mod and the API. Looking at my released mod's mcmod.info file, it seems I removed the 'useDependencyInformation' line entirely... curious. I'd have to look more closely at cpw's FML code to see if something funky is going on, but if your build works as it should without that line, then I would just remove it and not worry about it
The link has been removed; were you able to get it working, then?
Yeah I had already reduced the project down to nothing but the API and my test mod. It definitely works without the line in there so I will just keep moving forward then. Thanks!
Sorry I can't be of more help, but I don't know how every API out there is supposed to work - the tutorial is just a general guideline for a clean setup, but it requires the API developers to be willing to provide the necessary files.
Did you download the deobfuscated version of that API? Did you configure your project's build path to point to the API source code?
??? Why do you have a project for "Minecraft"? Each project should be a mod, unless you are using MCP... What version of Forge are you using? If you are not using Gradle, you should be, and if you are, you ought to take a look at tutorial on setting up your projects.
Yes, but not directly. In 1.6.4, we used to have to mod with the MCP / Minecraft source directly in the project - thankfully, this is no longer the case. Anyway, I'm still confused why you have a project named "Minecraft" - each of your mods should be a separate project; you can have them all open in Eclipse at the same time, but they are each completely separate from each other and can be run independently.
So if your mod is called "MyMod", you have a project for it also named "MyMod" which encompasses all of the source, assets, build files, etc., as well as referenced libraries such as an API.
Can you describe in detail the steps you are taking to add it? I can't know what you are doing wrong or if it's a problem with the API if I don't know what you are doing. Do you have the deobfuscated jar of the API? Did you add it as a referenced library? Can you import classes from it? If you answer 'no' to any of those, then that's what you need to do.
Ok, great. Right-click on the file from inside Eclipse and choose 'Properties' - this will bring up a menu allowing you to choose the location of the source files. If you don't have them and the deobfuscated version isn't letting you view it, then you should be able to download the src files from the mod's page and place them in an external directory, then link it through the 'Properties' menu above.
That would be a question for the API author, then, because it sounds like they did not include all of their source in the download.
Is this true? Maybe worth adding to the guide if so.
I haven't ever tried that, but if it is true, that would save a few steps. Still, I think I prefer keeping API code out of my src folder, simply for the sake of keeping my mod src clearly separated from any external library src.
Good point, src =/= lib - even for required dependencies, I've never seen libraries and sources jumbled together.