This tutorial will explain the basics of using the event system within Minecraft Forge in a clear way.
Common Questions About Events:
Q: What is an event?
A: Within Minecraft Forge and FM there is system of classes generally refereed to as the event system. These events are triggered by certain actions within the vanilla game, and sometimes other mods. There is an extensive list of events (over 150 of them at the time of writing this). When tapped into an event you will be able to alter the event. Some examples of these events include ItemCraftedEvent which is triggered when an item is crafted and can be used to change the outcome of a recipe or to give the player more than one item back, for example when a water bucket is used in a recipe you can give an empty bucket back rather than consuming the entire bucket. PlayerRespawnEvent which is triggered when a player respawns and can be used to alter the players health, give them potion effects or even give them some items. ItemTooltipEvent which is triggered when the inventory tooltip is viewed and can be used to add extra information onto the tooltip of a vanilla item, this also gives access to the client side version of the player, meaning you can only show certain text when the player is sneaking.
Q: How can I tell what bus to use for an event?
A: There are a few different event buses for you to use. An event bus is more or less where you register a class to have its events read. There are several types of buses that you can use and it can sometimes be confusing to figure out what bus to use. For the most part you just need to look at the events package and use some common sense. Vic_ created an awesome list of events that includes what event bus to register them with, if you're uncertain you can check it out.
Q: What is the performance impact of events?
A: For the most part events are generally light weight. As long as you're not being a goof and doing intensive code like looping through all the item ids every tick it will be fine.
Q: Can you hook into the same event multiple times?
A: Yes, just register the different classes with the bus. Many people actually prefer to split up their event hooks into specific classes, for example if you have an enchantment that makes a mob explode on hit, you could put that event in the enchantment class and then register with the correct bus in the constructor of the enchantment. The same can be said about a specific item class, if the event pertains only to that item.
How To Hook Into An Event:
Hooking into an event is a super simple thing to do and is a "skill" that every mod author should know. Being able to hook into the events offered by forge and fml will greatly increase your capabilities. To create an event you first need to make a new class to hold your event, You can also use an existing if you have an existing class if you have one you would like to use, keep in mind that it is not recommended to put events in the main mod class. In this tutorial I will be using a new class called EventHandler.
public class EventHandler {
}
To make your new event you must decide what event you would like to use and then create a method for it. An extensive list of events made by Vic_ can be found here. In this tutorial I will be using the BlockEvent.HarvestDropsEvent to add a new block drop to the mob spawner block. Once you have decided what event you will hook into you can create a new method for that event in your class. This event must use the public and void modifiers and can not be static. The name of the method does not matter and can be whatever you want. The parameters for the method can only be that event. The method must also have the @SubscribeEvent annotation above it, this annotation marks this method as an event hook, this allows the event system to find this method.
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.event.world.BlockEvent;
public class EventHandler {
@SubscribeEvent
public void onBlockDropItems(BlockEvent.HarvestDropsEvent event) {
}
}
The last thing we need to do is register our event with the correct event bus. There are a few event buses available such as the MinecraftForge.EVENT_BUS which is a general bus which most events fall under, FMLCommonHandler.bus() which is the FML bus that mainly deals with networking events, the MinecraftForge.TERRAIN_GEN_BUS which is made for hooking into world generation and MinecraftForge.ORE_GEN_BUS which is used for ore based events. If you're unsure which one to use, you can find out on Vic_'s list of forge events. This particular event uses the MinecraftForge.EVENT_BUS. There are a few ways you can do this, you can add MinecraftForge.EVENT_BUS.register(new EventHandler()); to the preInit method in your main mod class. You can also add this to the constructor of your class, this would be optimal if your event hook is inside of a class with an existing constructor such as an Item, Block or Enchantment.
Now we are going to actually start using our event to make mob spawners drop something new when dropped. Within the event parameter there are several things that you will have access to. This specific event gives us access to the player, the block and the list of items dropped by the block. I am going to make mob spawners drop bottles of experience.
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.world.BlockEvent;
public class EventHandler {
@SubscribeEvent
public void onBlockDropItems(BlockEvent.HarvestDropsEvent event) {
if (event.block == Blocks.mob_spawner) {
event.drops.add(new ItemStack(Items.experience_bottle));
}
}
}
Now whenever a mob spawner is broken it will drop an exp bottle. As this event allows us to add an ItemStack to the drop list we can get creative and add in some special data about the ItemStack. This modified version of the code will add 12 bottles of experience to the drop list, each with a custom display name set on it.
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.world.BlockEvent;
public class EventHandler {
@SubscribeEvent
public void onBlockDropItems(BlockEvent.HarvestDropsEvent event) {
if (event.block == Blocks.mob_spawner) {
ItemStack stack = new ItemStack(Items.experience_bottle, 12, 0);
stack.setStackDisplayName(EnumChatFormatting.GOLD + "Enjoy the free EXP :D");
event.drops.add(stack);
}
}
}
Contact:
If you have any questions for me you can leave them in the comments on this thread or you can contact me on Twitter or IRC on #MinecraftForgeTutorials. Please do NOT message me on Skype or Steam.
It's not really necroposting, this tutorial page is still living (in spirit).When resolving an issue like this, you are going to want to make sure that the event is being fired correctly. This can be done by adding two output messages to the console. The first would go at the start of your event method and the second would go after all of your conditions. If the first message does not printed, you didn't register your event correctly. If the second message does not print but the first one did, it means there is an issue with your conditions. If they both print but the desired action does not take place, there is something wrong with your method of accomplishing said action.
In your case, the answer is likely that you didn't register your event class. If you're not sure how to register the event class, you should read this tutorial as it's fully explained.
It's not really necroposting, this tutorial page is still living (in spirit).When resolving an issue like this, you are going to want to make sure that the event is being fired correctly. This can be done by adding two output messages to the console. The first would go at the start of your event method and the second would go after all of your conditions. If the first message does not printed, you didn't register your event correctly. If the second message does not print but the first one did, it means there is an issue with your conditions. If they both print but the desired action does not take place, there is something wrong with your method of accomplishing said action.
In your case, the answer is likely that you didn't register your event class. If you're not sure how to register the event class, you should read this tutorial as it's fully explained.
so by adding this it will work? Not sure if this will work or not.
It works. But it drops every time you break a leaf. I want it to be dropped 1 out of ten times.
Right, this can be added by coding some logic yourself. Given that you seem to be a new developer I will walk you through doing percent logic. So there are a bunch of ways to do it, the most common way of doing it is generating a random float or double that is between 0 and 1. You can then check if that float or double is less than or equal to the percent. Here is an example code snip.
//This creates an instance of Random. I would encourage you to look into how instances work, in this case it's a performance thing.
//This random instance can be used to generate a bunch of random things.
Random rnd = new Random();
//This is a generic method, it is much like your event method. In this example it's not very important.
public static void genericMethodHere() {
//This is creating a float between 0 and 1. It will be less than or equal to 0.10 about 10% of the time.
//If you were to change it to something like <= 0.45f then there would be about a 45% chance.
//You want it to happen one in every ten tries, to turn that into a percent simply devide the numerator by the denominator.
//So 1 divided by 10 = 0.10.
if (rnd.nextFloat() <= 0.10f)
System.out.println("I did a thing");
}
Edit: The reason why adding that line of code before made this work, is because it does two things. The first is registering it with the forges event bus. The event bus is basically a group of all the event methods in every mod, so when a block is broken, forge looks at the list of methods for that event and will go through and call all of them, without this, java/minecraft/forge has no idea that your code is meant to do anything and will never do anything with it. The second thing we're doing is initializing the class. This may not be so useful to you, but if you need to set some stuff up before the event is loaded, and triggered, you can use the classes constructor.
Right, this can be added by coding some logic yourself. Given that you seem to be a new developer I will walk you through doing percent logic. So there are a bunch of ways to do it, the most common way of doing it is generating a random float or double that is between 0 and 1. You can then check if that float or double is less than or equal to the percent. Here is an example code snip.
//This creates an instance of Random. I would encourage you to look into how instances work, in this case it's a performance thing.<br>//This random instance can be used to generate a bunch of random things. <br>Random rnd = new Random();<br><br>//This is a generic method, it is much like your event method. In this example it's not very important.<br>public static void genericMethodHere() {<br><br> //This is creating a float between 0 and 1. It will be less than or equal to 0.10 about 10% of the time. <br> //If you were to change it to something like <= 0.45f then there would be about a 45% chance. <br> //You want it to happen one in every ten tries, to turn that into a percent simply devide the numerator by the denominator. <br> //So 1 divided by 10 = 0.10. <br> if (rnd.nextFloat() <= 0.10f)<br> System.out.println("I did a thing");<br>}<br><br>
Edit: The reason why adding that line of code before made this work, is because it does two things. The first is registering it with the forges event bus. The event bus is basically a group of all the event methods in every mod, so when a block is broken, forge looks at the list of methods for that event and will go through and call all of them, without this, java/minecraft/forge has no idea that your code is meant to do anything and will never do anything with it. The second thing we're doing is initializing the class. This may not be so useful to you, but if you need to set some stuff up before the event is loaded, and triggered, you can use the classes constructor.
Based on what you did I can see you don't really understand the Java syntax. So, when you make a method, it does not do anything, unless is is called or in other words triggered. Right now you have a method called genericMethodHere, this is not a valid event method, nor is it being called. As for why I used it? It was just an example, adding it to your code will do nothing, although understanding it and applying the same logic to your existing code will. Right now the only method being called in this class is onBlockDropItems because it is a valid event method, so you would do stuff there.
Based on what you did I can see you don't really understand the Java syntax. So, when you make a method, it does not do anything, unless is is called or in other words triggered. Right now you have a method called genericMethodHere, this is not a valid event method, nor is it being called. As for why I used it? It was just an example, adding it to your code will do nothing, although understanding it and applying the same logic to your existing code will. Right now the only method being called in this class is onBlockDropItems because it is a valid event method, so you would do stuff there.
opps
What method would you call? I tried a few but had no luck.
Common Questions About Events:
Q: What is an event?
A: Within Minecraft Forge and FM there is system of classes generally refereed to as the event system. These events are triggered by certain actions within the vanilla game, and sometimes other mods. There is an extensive list of events (over 150 of them at the time of writing this). When tapped into an event you will be able to alter the event. Some examples of these events include ItemCraftedEvent which is triggered when an item is crafted and can be used to change the outcome of a recipe or to give the player more than one item back, for example when a water bucket is used in a recipe you can give an empty bucket back rather than consuming the entire bucket. PlayerRespawnEvent which is triggered when a player respawns and can be used to alter the players health, give them potion effects or even give them some items. ItemTooltipEvent which is triggered when the inventory tooltip is viewed and can be used to add extra information onto the tooltip of a vanilla item, this also gives access to the client side version of the player, meaning you can only show certain text when the player is sneaking.
Q: How can I tell what bus to use for an event?
A: There are a few different event buses for you to use. An event bus is more or less where you register a class to have its events read. There are several types of buses that you can use and it can sometimes be confusing to figure out what bus to use. For the most part you just need to look at the events package and use some common sense. Vic_ created an awesome list of events that includes what event bus to register them with, if you're uncertain you can check it out.
Q: What is the performance impact of events?
A: For the most part events are generally light weight. As long as you're not being a goof and doing intensive code like looping through all the item ids every tick it will be fine.
Q: Can you hook into the same event multiple times?
A: Yes, just register the different classes with the bus. Many people actually prefer to split up their event hooks into specific classes, for example if you have an enchantment that makes a mob explode on hit, you could put that event in the enchantment class and then register with the correct bus in the constructor of the enchantment. The same can be said about a specific item class, if the event pertains only to that item.
How To Hook Into An Event:
Hooking into an event is a super simple thing to do and is a "skill" that every mod author should know. Being able to hook into the events offered by forge and fml will greatly increase your capabilities. To create an event you first need to make a new class to hold your event, You can also use an existing if you have an existing class if you have one you would like to use, keep in mind that it is not recommended to put events in the main mod class. In this tutorial I will be using a new class called EventHandler.
To make your new event you must decide what event you would like to use and then create a method for it. An extensive list of events made by Vic_ can be found here. In this tutorial I will be using the BlockEvent.HarvestDropsEvent to add a new block drop to the mob spawner block. Once you have decided what event you will hook into you can create a new method for that event in your class. This event must use the public and void modifiers and can not be static. The name of the method does not matter and can be whatever you want. The parameters for the method can only be that event. The method must also have the @SubscribeEvent annotation above it, this annotation marks this method as an event hook, this allows the event system to find this method.
The last thing we need to do is register our event with the correct event bus. There are a few event buses available such as the MinecraftForge.EVENT_BUS which is a general bus which most events fall under, FMLCommonHandler.bus() which is the FML bus that mainly deals with networking events, the MinecraftForge.TERRAIN_GEN_BUS which is made for hooking into world generation and MinecraftForge.ORE_GEN_BUS which is used for ore based events. If you're unsure which one to use, you can find out on Vic_'s list of forge events. This particular event uses the MinecraftForge.EVENT_BUS. There are a few ways you can do this, you can add MinecraftForge.EVENT_BUS.register(new EventHandler()); to the preInit method in your main mod class. You can also add this to the constructor of your class, this would be optimal if your event hook is inside of a class with an existing constructor such as an Item, Block or Enchantment.
Now we are going to actually start using our event to make mob spawners drop something new when dropped. Within the event parameter there are several things that you will have access to. This specific event gives us access to the player, the block and the list of items dropped by the block. I am going to make mob spawners drop bottles of experience.
Now whenever a mob spawner is broken it will drop an exp bottle. As this event allows us to add an ItemStack to the drop list we can get creative and add in some special data about the ItemStack. This modified version of the code will add 12 bottles of experience to the drop list, each with a custom display name set on it.
Helpful Resources:
Java Tutorials by Oracle
Minecraft Forge Tutorials
List Of Events by Vic_
Contact:
If you have any questions for me you can leave them in the comments on this thread or you can contact me on Twitter or IRC on #MinecraftForgeTutorials. Please do NOT message me on Skype or Steam.
Farewell everyone o/
Awesome, glad I could help
Farewell everyone o/
When i try to register leaves dropping sticks, it doesn't actually drop. this is what i have:
package drybones967.Naturalcraft;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraftforge.event.world.BlockEvent;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
public class EventHandler {
public void onBlockDropItems(BlockEvent.HarvestDropsEvent event) {
if (event.block == Blocks.leaves) {
event.drops.add(new ItemStack(Items.stick));
}
}
Sorry to necropost but i couldn't find this online
It's not really necroposting, this tutorial page is still living (in spirit).When resolving an issue like this, you are going to want to make sure that the event is being fired correctly. This can be done by adding two output messages to the console. The first would go at the start of your event method and the second would go after all of your conditions. If the first message does not printed, you didn't register your event correctly. If the second message does not print but the first one did, it means there is an issue with your conditions. If they both print but the desired action does not take place, there is something wrong with your method of accomplishing said action.
In your case, the answer is likely that you didn't register your event class. If you're not sure how to register the event class, you should read this tutorial as it's fully explained.
Farewell everyone o/
so by adding this it will work? Not sure if this will work or not.MinecraftForge.EVENT_BUS.register(new drybones967.Naturalcraft.EventHandler());It works. But it drops every time you break a leaf. I want it to be dropped 1 out of ten times.
Right, this can be added by coding some logic yourself. Given that you seem to be a new developer I will walk you through doing percent logic. So there are a bunch of ways to do it, the most common way of doing it is generating a random float or double that is between 0 and 1. You can then check if that float or double is less than or equal to the percent. Here is an example code snip.
Farewell everyone o/
Thank you so much!package drybones967.Naturalcraft;
import java.util.Random;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.world.BlockEvent;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
public class EventHandler {
@SubscribeEvent
public void onBlockDropItems(BlockEvent.HarvestDropsEvent event) {
if (event.block == Blocks.leaves) {
event.drops.add(new ItemStack(Items.stick));
}
}
public static void genericMethodHere() {
Random rnd = new Random();
if (rnd.nextFloat() <= 0.10f)
System.out.println("I did a thing");
}
}
Farewell everyone o/
opps
What method would you call? I tried a few but had no luck.