Minecraft Modding: Event Handling

Introduction


Minecraft Forge and FML provide event "buses" that are extremely useful but not often well understood by beginning modders.  I will try to give you enough information to start your exploration of this powerful modding tool.

The general concept is that you create "event handling" methods that subscribe (using @SubscribeEvent), then register those as "listeners" to the appropriate event bus.

In this tutorial, I'll explain the basics, provide example handler classes that list all known events, and then give some tips and references on how to learn and have fun with event handling.

You may also want to check out CoolAlias' tutorial that covers similar topic:  CoolAlias' Event Handling Tutorial.

The Steps Needed To Create An Event Handler


I provide a lot of details below, but it is important to understand the general steps

Also, there are two common methods for registering your event handler, with the more common one now being the annotation method. I'll only cover that method here.

General steps:
  1. Create an event handling class, call it whatever you want.
  2. Give your class the @EventBusSubscriber annotation. By doing this you don't need to actually register it, that will happen automatically!
  3. Put public static methods in it that follow the example in my tutorial, one method for each event type you want to handle. Each method needs to have the @SubscribeEvent annotation and the parameter passed tot the event must be the type of event you're trying to handle (I list most known events at the end of the tutorial). The methods should contain your custom code to whatever you want when the event happens. 
Tip: It is important to note that the event parameter passed usually has a number of useful fields and methods to aid your custom code.

Using Event Handling To Modify Vanilla Behavior


For your own custom classes, you often don't need event handling because you already have the means of controlling their behavior. So event handling is most useful for the purpose of changing the behavior of "vanilla" blocks, items, entities, world generation, etc.

Key Point: Before implementing event handling you should first check to see if there are already public methods and fields available to you.  For example, changing a texture of a block or changing the motion of an entity can be done with public methods.  Even though events could be used for these examples, it is probably easiest to use the provided methods.

However, if there is not a public method for what you want to change, or if what you want to do spans multiple classes or across the creation and "death" of entities, then you should consider using events.

Key Point: Forge and FML have provided event buses that allow you to intercept certain activities before they are processed by vanilla code.

So if you want something special to happen when a player, for example, attacks a certain type of vanilla entity, you can subscribe to the the AttackEntityEvent and check (using instanceof) what the Entity subtype is and then process your own code accordingly.  There are other events for interacting with blocks and items, events for when an entity dies, when the player jumps, and so on.  I'll list all the available events later in this tutorial.

If you look for public methods or do event handling, you should only rarely have to use advanced techniques like reflection, access transformers, core mods, etc.

Event Handling In Custom Classes


If you make your own classes, especially as extending existing blocks, items or entities, you already have access to @Override several methods that are actually event handlers.  Many of these methods are named starting with "on", like onUpdate(). These methods are automatically called at the same time as the related events are posted and so don't need to be called or otherwise handled.

While you could use event handling, it is preferable to use these built-in methods because they are already specific to your class and it improves readability of your code to have the class-specific code all within the class.

Event Cancelation


It is especially important to understand is that certain events are "cancelable", which is usually annotated with @Cancelable. The cool thing about cancelable events is you can choose to prevent (i.e. cancel) the vanilla processing from happening at all: cancelable events allow you to fully replace the vanilla event handling with your own code!

Warning: One problem with event cancelation is that it will affect other mods as well and can cause event incompatibility. You can affect the order of handling using priority (described below) and for those at the same priority I believe the handlers will fire based on the order the mods are loaded (or more specifically in order they register the handlers which is usually during the FMLInitializationEvent so would be in order they are loaded).

Note: For those events that occur in a series (like Start & Finish or Pre & Post), canceling the earlier event usually (but not always, so inspect the code) also cancels the remainder of the sequence. So for example if you cancel RenderGameOverlay.Pre then the RenderGameOverlay.Post will never fire either. If for some reason you need to cancel the Pre but not the Post you can use the receiveCanceled option to ensure you still receive the Post event.


Un-Canceling Events


Due to the danger of other mods canceling events you might want to intercept, and also useful in some specific cases, you can force a subscribed method to still get events that have been canceled. This is by using the receiveCanceled=true parameter in the @Subscribe annotation.

Tip: To ensure other mods don't prevent your event handling, I suggest you set all your methods' subscriptions to receive cancelled events initially and then when testing with other mods if you find other mods are canceling events you care about you can adjust for better compatibility.  Ideally contact the other mod author to work through event handling conflicts.

If you set your method to receive cancelled events, you can check if it was actually canceled with the isCanceled() method. This might be interesting if you want to control compatibility with other mods, as you could choose to honor the cancellation or not.

Furthermore, you can actually "un-cancel" the event with a setCanceled(false) call.  I think in most cases this would cause some mod compatibility problems because if another mod canceled the event it probably did it for a reason, but if your mod relies on the vanilla event handling you may need to let that run.

Event Handler Priority


The @Subscribe annotation includes an priority of type EventPriority which affects the sorting of all handlers that are subscribed.  This can be especially relevant if multiple mods are subscribed to same event and one cancels before other mod gets fired (as mentioned in the warning above).

It is therefore tempting for mod authors to be "selfish" and set that their event handlers to HIGHEST priority, but if you receiveCanceled then you can probably get what you need while remaining at the default NORMAL priority.

Here is the enum for the EventPriority showing all the priority levels:

public enum EventPriority
{
    /*Priority of event listeners, listeners will be sorted with respect to this priority level.
     * 
     * Note:
     *   Due to using a ArrayList in the ListenerList,
     *   these need to stay in a contiguous index starting at 0. {Default ordinal} 
     */
    HIGHEST, //First to execute
    HIGH,
    NORMAL,
    LOW,
    LOWEST //Last to execute
} 

The default priority (i.e. if you don't specify a priority) will be NORMAL.

So, for example, to set your handler priority to HIGHEST you would use something like @Subscribe(priority=EventPriority.HIGHEST) to annotate your handling methods.


Using Tick Event Handling For General Game Control


When programming one of the architectural decisions you need to make is whether your processing is distributed across many classes that run independently (and need to be synced up), or whether you have a centralized "game controller" or "main loop" that does most of the processing.

If you want a class that has broad overview of everything happening in game, a centralized approach is usually preferable.

For example, let's say your mod was implementing a team-oriented multi-player feature where if the players on a team killed a certain number of skeletons that something special happened.  In that case, where would you put the code that tracks the number of skeletons killed by each team?  You don't really want to put it in the player entities because each player class is not really aware of the kills by other players, and you don't want to put it in the skeleton class because the instances will disappear once each one is killed.  So if you want to process across several instances in the game, I suggest you use a "tick" event handler.

Tip: A "tick" simply means one processing step through all the game logic, and in Minecraft a tick usually represents 1/20 of a second of real time. The ServerTickEvent being especially useful for game logic that spans multiple players.

Warning: Each tick event has a START and END phase, meaning the tick event happens twice per tick. If the number of ticks matters (like if you're decrementing a counter) you should check the phase field value (passed with the event parameter) before decrementing. In most cases it doesn't matter whether you process the START or END, but you'll want to pick one.

Using Event Handling With Overriding Methods In Your Custom Classes


Most of the vanilla classes have methods that are essentially also event handlers.  The method names often start with "on" (like onLivingUpdate() method).  You don't have to call these events, as they will be called automatically when the related event occurs.  If you extend a class that inherits such methods, you don't need to subscribe to the related event but can just override the method with your code.  But it is also possible to use the event bus for these (i.e. @Subscribe to the LivingUpdateEvent), the choice is up to you, but stylistically most modders use the method in the class if available.

How Event Buses Work


Any code can "post" an event to a bus.  Your own custom code can actually post events, either built-in events or even custom events you make by extending Event classes or subclasses!  Some event classes like FluidSpillEvent are actually intended for mods' use and not fired in vanilla. I will try to write an additional tutorial on posting events, but for now we're just talking about handling events that are already posted.

Each bus also has "listeners" or "handlers" which are custom classes that are registered that may contain subscribing methods.  Multiple handlers may be subscribed to each bus, but I tend to collect all my handling into one class per bus.

When an event is posted to a bus, the code will go through all the registered listener classes and look for any methods that are subscribed (using the @Subscribe annotation) to the event type posted.

Tip: The name of the method doesn't matter (I call all my methods onEvent()), what matters is only that the parameter passed to it matches the posted event type.

There are three game-related event buses, networking event buses (registered to each "channel"), plus a special type of event that uses @EventHandler and doesn't need bus registration.  It is a good idea in every mod to register handler classes for each, even if you don't initially plan to use them all because almost always in the course of any significant mod you'll find a reason to handle some events.

The @EventHandler FML Life Cycle Events


There is a set of events that don't require bus registration.  They are called FML life cycle events, and include the familiar events that people often call preInit(), init(), and postInit().

The FML life cycle events simply need @EventHandler annotation before the handling method.  For completeness I usually have all these events handled with the following in my main mod class:

@EventHandler
// preInit "Run before anything else. Read your config, create blocks, items, 
// etc, and register them with the GameRegistry."
public void fmlLifeCycleEvent(FMLPreInitializationEvent event) 
{    
    // DEBUG
    System.out.println("preInit()"+event.getModMetadata().name);
        
    proxy.fmlLifeCycleEvent(event);
}

@EventHandler
// load "Do your mod setup. Build whatever data structures you care about. Register recipes."
public void fmlLifeCycleEvent(FMLInitializationEvent event) 
{
     
    // DEBUG
    System.out.println("init()");
        
    proxy.fmlLifeCycleEvent(event);
}


@EventHandler
// postInit "Handle interaction with other mods, complete your setup based on this."
public void fmlLifeCycle(FMLPostInitializationEvent event)
{
    // DEBUG
    System.out.println("postInit()");
        
    proxy.fmlLifeCycleEvent(event);
}

@EventHandler
public void fmlLifeCycle(FMLServerAboutToStartEvent event)
{
    // DEBUG
    System.out.println("Server about to start");
        
    proxy.fmlLifeCycleEvent(event);
}

@EventHandler
// register server commands in this event handler
public void fmlLifeCycle(FMLServerStartingEvent event)
{
    // DEBUG
    System.out.println("Server starting");
        
    proxy.fmlLifeCycleEvent(event);
}

@EventHandler
public void fmlLifeCycle(FMLServerStartedEvent event)
{
    // DEBUG
    System.out.println("Server started");
        
    proxy.fmlLifeCycleEvent(event);
}

@EventHandler
public void fmlLifeCycle(FMLServerStoppingEvent event)
{
    // DEBUG
    System.out.println("Server stopping");
        
    proxy.fmlLifeCycleEvent(event);
}

@EventHandler
public void fmlLifeCycle(FMLServerStoppedEvent event)
{
    // DEBUG
    System.out.println("Server stopped");
        
    proxy.fmlLifeCycleEvent(event);
}

Registering Handlers To The Event Buses


In later builds of 1.10.2 Forge, an annotation was added, @Mod.EventBusSubscriber, which can be used instead of the older registration methods described below. This actually causes the events to be subscribed during the construction of the mod which can help with some issues of timing during start-up. To use this, you place the annotation before the class declaration for every class that contains standard event bus handling methods.

Warning: If you use the annotation method (recommended) you MUST use static methods. Conversely if you use the older registration method you must use instance/default methods.

In earlier versions of Forge, in your mod main class or in your commonProxy class, during the init() phase (or whatever handles the FMLInitializationEvent in your mod) of FML life cycle, have a method something like this that you call:

public void registerEventListeners() 
{
    // DEBUG
    System.out.println("Registering event listeners");

    MinecraftForge.EVENT_BUS.register(new WildAnimalsEventHandler());
    MinecraftForge.TERRAIN_GEN_BUS.register(new WildAnimalsTerrainGenEventHandler());
    MinecraftForge.ORE_GEN_BUS.register(new WildAnimalsOreGenEventHandler());        

    // some events, especially tick, are handled on FML bus
    FMLCommonHandler.instance().bus().register(new WildAnimalsFMLEventHandler());
}

And obviously you should create the various classes for your event handlers (I'll give examples below) that are registered.

Which Event Bus Does Each Event Get Fired On?


Warning: It is very important to know that if you register your handler to the wrong bus it will not be triggered. This is a very common mistake.  But how do you know?

Tip: You can follow (using Eclipse or IntelliJ) the call hierarchy of the event and you should find the Minecraft Forge post to an event bus.  Generally, you can guess the event bus an event fires on is by looking at the package that the event class belongs to, although there are a couple that don't follow that rule. 

Some examples:
  • The EntityStruckByLightningEvent is in net.minecraftforge.event.entity so should be registered to the MinecraftForge.EVENT_BUS.
  • The PlayerTickEvent is in cpw.mods.fml.common.gameevent.TickEvent so should be registered to the FMLCommonHandler.instance().bus().
  • The SaplingGrowTreeEvent is in net.minecraftforge.event.terraingen so should be registered to the MinecraftForge.TERRAIN_GEN_BUS.
  • And so on...

Why Are There Multiple Event Buses?


Thanks to diesieben07 for this explanation.

Forge and FML are independent projects, therefore they have their own EventBus. As to why Forge doesn't use the FML bus: Forge had the event system first and it was only later moved to FML. They are still separate for compatibility reasons.

Forge then has two more buses, the ORE_GEN_BUS and the TERRAIN_GEN_BUS. Events for terrain and ore generation are fired on a different bus to not put strain on the main bus. The main bus usually has quite a lot of listeners. If the terrain and ore-gen events (which are fired a lot during terrain gen) would fire on the main bus it would have to check all those "normal" event listeners every time, which could be quite the performance hit. This way only the handlers that actually want the terrain gen events are checked for them.

What Is The Full List Of Available Events?


If you want to use events effectively, it is good to know what is available for use, but the classes are actually not all in one place, the wiki isn't complete, and some of the classes are only parents for the actual classes that get fired.  So to help myself and others I have tried to go through and find all the events and put them into the correct handlers (if you find any mistakes, let me know -- I'll be continuing to update this).

Also See: Vic_'s List Of Events

Tip: Each of my classes below has what should be a complete list of available events for the related bus.  If you really know you won't use an event, feel free to delete the method from your handler, but it really doesn't do much harm to leave the empty methods as is.

Event Classes: Parents And Subclasses


You'll notice that many events extend other events.  For example there is a Start event which extends PlayerUseItemEvent extends PlayerEvent which extends LivingEvent which extends EntityEvent which extends Event.  It is possible to handle the player's use of an item at any of these levels, however it is preferable to handle it at the most specific subclass because each level provides additional built-in fields that are helpful.  For example, if you use PlayerUseItemEvent.Start you'll get fields for entityPlayer and item and of course you'll be confident that it is first tick (the "start") of the item's use.

Important: Use the most specific event subclass suitable to your need as you'll get more useful built-in fields and methods.

Making Custom Events


It is actually possible to make your own custom event. Basically the idea is that you make a class that extends the Event class, then you post the event to the bus (you can pick either FML or Forge bus) when it makes sense, and you would also have a event handler method registered to the bus just like normal.

Warning: Because of the way that the mod loading processes the @SubscribeEvent annotation, custom event class must not be excluded from the access transformer step of loading. See this thread in which diesieben07 explains.

Events On MinecraftForge.EVENT_BUS 


Example Method In Handler Class


Here is an example of  the structure of a method for handling an event on this bus:

@EventBusSubscriber
public class WildAnimalsEventHandler 
{

    @SubscribeEvent(priority=EventPriority.NORMAL, receiveCanceled=true)
public static void onEvent(EntityConstructing event) { // Register extended entity properties if (event.entity instanceof IWildAnimalsEntity) {
            event.entity.registerExtendedProperties("ExtendedPropertiesWildAnimals"
                  new ExtendedPropertiesWildAnimals());
        }
    }  
} 

Tip: Note that it is okay to name all your event-handling methods the same (I name all mine "onEvent") because from Java compiler point of view they are still unique based on the event parameter passed to them.

List of Events On EVENT_BUS


Tip: It is useful to familiarize yourself with available events.  They can even inspire ideas for new mod features!

Here is list of the events that are fired on the EVENT_BUS that I'm aware of (let me know what I've missed). The list is organized by package, then alphabetically (although in cases where a sequence is implied I'll order them in sequence, like Pre and Post):

Client events (net.minecraftforge.client.event):
  • CameraSetupEvent -- New in release 1473+
  • ClientChatReceivedEvent
  • DrawBlockHighlightEvent
  • FogColors -- New in release 1117+
  • FogDensity -- New in release 1117+
  • RenderFogEvent -- New in release 1189+
  • FOVUpdateEvent
  • GuiOpenEvent
  • GuiScreenEvent.ActionPerformedEvent
  • GuiScreenEvent.DrawScreenEvent
  • GuiScreenEvent.InitGuiEvent
  • GuiScreenEvent.KeyboardInputEvent -- New in release 1459+
  • GuiScreenEvent.MouseInputEvent -- New in release 1459+
  • MouseEvent -- does not fire if GUI that pauses game is open
  • ModelBakeEvent -- New in release 1296+
  • RenderBlockOverlayEvent -- New in release 1174+
  • RenderGameOverlayEvent.Chat
  • RenderGameOverlayEvent.Pre
  • RenderGameOverlayEvent.Post
  • RenderGameOverlayEvent.Text
  • RenderHandEvent
  • RenderItemInFrameEvent-- New in release 1160+
  • RenderLivingEvent.Pre
  • RenderLivingEvent.Post
  • RenderPlayerEvent.Pre
  • RenderPlayerEvent.Post
  • RenderPlayerEvent.SetArmorModel
  • RenderWorldEvent.Pre
  • RenderWorldEvent.Post
  • RenderWorldLastEvent
  • TextureStitchEvent.Pre
  • TextureStitchEvent.Post
Miscellaneous events (net.minecraftforge.event):
  • ForceChunkEvent
  • UnforceChunkEvent
  • AnvilUpdateEvent
  • CommandEvent
  • ServerChatEvent
Brewing events (net.minecraftforge.event.brewing)
  • PotionBrewedEvent.Pre -- New in release 1296+
  • PotionBrewedEvent.Post -New in release 1296+
Entity events (net.minecraftforge.event.entity)
  • EnteringChunk
  • EntityConstructing (useful for registering extended entity properties, but fired at beginning of constructor so most fields like position unlikely to be initialized at this point)
  • EntityJoinWorldEvent
  • EntityMountEvent -- New in release 1338+
  • EntityStruckByLightningEvent
  • PlaySoundAtEntityEvent
Item events (net.minecraftforge.event.entity.item)
  • ItemExpireEvent
  • ItemTossEvent
EntityLiving events (net.minecraftforge.event.entity.living):
  • LivingJumpEvent
  • LivingUpdateEvent
  • EnderTeleportEvent
  • LivingAttackEvent e.g. Check if the damage source is explosion damage. If so, cancel the event to make immune from explosions (maybe based on potion or armor).
  • LivingDeathEvent
  • LivingDropsEvent. See Jabelar's Drop Event Tutorial
  • LivingExperienceDropsEvent -- New in release 1443+
  • LivingFallEvent -- canceling this will prevent fall damage
  • LivingHealEvent -- New in release 1296+
  • LivingHurtEvent -- the damage amount passed is before armor and potion effects are calculated
  • LivingPackSizeEvent
  • LivingSetAttackTargetEvent
  • LivingSpawnEvent -- this isn't really fired separately, but rather fires for any child.  Not as useful as you'd suspect.  If you want to do something when entity "arrives" try to use EnteringChunk or EntityJoinWorld event.
  • ZombieEvent
  • CheckSpawn -- this doesn't fire during world gen, only during game, and also for some reason this doesn't seem to fire for EntityAnimal or its subclasses.
  • SpecialSpawn
  • AllowDespawn -- setting the result to anything other than Result.DEFAULT will override the canDespawn() method for the entity. For example, Result.ALLOW will forceably despawn it no matter what.
Player events (net.minecraftforge.event.entity.player)
  • AchievementEvent
  • AnvilRepairEvent
  • ArrowLooseEvent
  • ArrowNockEvent
  • AttackEntityEvent
  • BonemealEvent
  • BreakSpeed
  • Clone
  • EntityInteractEvent
  • EntityItemPickupEvent
  • FillBucketEvent
  • HarvestCheck
  • ItemTooltipEvent
  • NameFormat
  • LoadFromFile
  • PlayerDestroyItemEvent
  • PlayerDropsEvent
  • PlayerFlyableFallEvent
  • PlayerInteractEvent -- LEFT_CLICK_BLOCK only fires on server side, RIGHT_CLICK_BLOCK fires on both sides, RIGHT_CLICK_AIR only fires on client side (and gives block position of 0, 0, 0). Use packets to notify other side if needed. Some items like bucket are quirky and to cancel the behavior completely you need to send a S23PacketBlockChange to the client.
  • PlayerOpenContainerEvent
  • PlayerPickupXpEvent
  • PlayerSleepInBedEvent
  • PlayerUseItemEvent.Start
  • PlayerUseItemEvent.Tick
  • PlayerUseItemEvent.Finish
  • PlayerUseItemEvent.Stop
  • PlayerWakeUpEvent -- New in release 1225+
  • SaveToFile
  • StartTracking -- useful for performance optimization as it allows you to only process entities (including players) that are within range to be tracked.
  • StopTracking -- useful for performance optimization as it allows you to only process entities (including players) that are within range to be tracked.
  • UseHoeEvent
Minecart events (net.minecraftforge.event.entity.minecart)
  • MinecartCollisionEvent
  • MinecartInteractEvent
  • MinecartUpdateEvent
 Block events (net.minecraftforge.event.world)
  • BreakEvent
  • HarvestDropsEvent -- note this is actual harvest (a block like BlockLeaves cannot be harvested) with an appropriate tool.  If you're trying to create a "harvest" that normally doesn't trigger, use the BlockEvent.BreakEvent instead.
  • MultiPlaceEvent
  • NeighborNotifyEvent -- New in release 1333+
  • NoteBlockEvent.Change
  • NoteBlockEvent.Play
  • PlaceEvent

World events (net.minecraftforge.event.world)
  • CreateSpawnPosition -- New in release 1296+
  • ExplosionEvent.Start -- New in release 1296+
  • ExplosionEvent.Detonate -- New in release 1296+. This event passes a list parameter that contains all entities affected by the explosion. You can remove entities that you want to make immune.
  • WorldEvent.Load
  • PotentialSpawns
  • WorldEvent.Unload
Chunk events (net.minecraftforge.event.world)
  • ChunkEvent.Save
  • ChunkEvent.Unload
  • ChunkDataEvent.Load
  • ChunkDataEvent.Save
  • ChunkWatchEvent.Watch
  • ChunkWatchEvent.UnWatch
Fluid events (net.minecraftforge.fluids):
  • FluidContainerRegisterEvent
  • FluidDrainingEvent
  • FluidFillingEvent
  • FluidMotionEvent
  • FluidRegisterEvent
  • FluidSpilledEvent
Ore registry events (net.minecraftforge.oredict)
  • OreRegisterEvent
Populate chunk events (net.minecraftforge.event.terraingen)

Note: The PopulateChunkEvent events which are in the same package are actually fired on the EVENT_BUS.
  • PopulateChunkEvent.Pre
  • PopulateChunkEvent.Populate
  • PopulateChunkEvent.Post


Events On FMLCommonHandler.instance().bus()


The methods that subscribe to FML events should be structured much the same as the example above -- just put them in a class registered as a handler for FML events.  Here is a list all the known FML events (except life cycle events which I discussed above that use @EventHandler instead).

List Of Events On FML Bus


User input events (cpw.mods.fml.common.gameevent.InputEvent):

Warning: These input events do NOT fire when a GUI that pauses the game is open, so in particular you cannot use these to intercept keys during chat (you can of course modify the contents of the chat or command when it is actually sent using other events related to chat and commands) or mouse when container GUI is open.
  • InputEvent
  • KeyInputEvent
  • MouseInputEvent
Player events (cpw.mods.fml.common.gameevent.PlayerEvent):
  • PlayerEvent
  • ItemCraftedEvent
  • ItemPickupEvent
  • ItemSmeltedEvent
  • PlayerChangedDimensionEvent
  • PlayerLoggedInEvent
  • PlayerLoggedOutEvent
  • PlayerRespawnEvent
  • PlayerWakeUpEvent -- New
Config GUI Events (New!)
Tick Events (cpw.mods.fml.common.gameevent.TickEvent):
  • ClientTickEvent -- fires twice per tick (START and END phase). Note that it may tick even if a world is not running so you should check if (!Minecraft.getMinecraft().isGamePaused() && Minecraft.getMinecraft().thePlayer != null) if you want to confirm a world is running.
  • PlayerTickEvent -- fires twice per tick (START and END phase).
  • WorldTickEvent  -- fires twice per tick (START and END phase) per dimension. So in most cases it will fire six times (Overworld, Nether, and End). Note it is only fired on server side.
  • RenderTickEvent -- fires twice per tick (START and END phase).
  • ServerTickEvent  -- fires twice per tick (START and END phase).
Networking Events:
    • ClientConnectedToServerEvent
    • ClientDisconnectionFromServerEvent
    • ServerConnectionFromClientEvent
    • ServerDisconnectionFromClientEvent
    • CustomPacketRegistrationEvent
    • ClientCustomPacketEvent
    • ServerCustomPacketEvent
    • CustomNetworkEvent


    Events On MinecraftForge.TERRAIN_GEN_BUS


    For some reason, Forge breaks off some events onto separate buses.  The terrain generation events have their own handler.  Here is list all the known terrain generation events.

    List Of Events On TERRAIN_GEN_BUS


    Terrain generation events:
    • BiomeEvent
    • BiomeColor
    • CreateDecorator
    • GetGrassColor
    • GetFoliageColor
    • GetVillageBlockID
    • GetVillageBlockMeta
    • GetWaterColor
    • ChunkProviderEvent
    • InitNoiseField
    • ReplaceBiomeBlocks
    • DecorateBiomeEvent.Decorate
    • DecorateBiomeEvent.Pre
    • DecorateBiomeEvent.Post
    • InitMapGenEvent
    • SaplingGrowTreeEvent
    • WorldTypeEvent.BiomeSize
    • WorldTypeEvent.InitBiomeGens
    Note: The PopulateChunkEvent events which are in the same package are actually fired on the EVENT_BUS.

    Events On MinecraftForge.ORE_GEN_BUS


    The ore generation events have their own handler.  Here is list of all the known ore generation events.

    List Of Events On ORE_GEN_BUS

    • GenerateMinable
    • OreGenEvent.Pre
    • OreGenEvent.Post


    Get To Know Each Event's Fields And Methods


    Each event is passed into the handler method, and you can access the fields and methods for the event within your handler method.  It is very important to check out the event classes to familiarize yourself with the fields and methods you can use.

    For example, all EntityEvent subclasses have a field called entity, all LivingEvent subclasses have a field called entityLiving, all PlayerEvent classes have a field called entityPlayer.  There are many other useful fields appropriate to each event.

    Tip: Cancelable events have the useful method called setCanceled(true) which will cancel the vanilla event processing.  Not all events are cancelable, and any attempt to cancel an event that can't be will result in a IllegalArgumentException.

    Warning: You can check if it is cancelable with the isCancelable() method but really you should only cancel events you know are cancelable -- otherwise you probably will have some unexpected side effect (i.e. you think you've canceled when you haven't).

    Check them out the fields in methods in other events by following their declarations in Eclipse or by navigating the classes in the package explorer window of Eclipse!

    Now Let's Have Fun

    Gain Confidence In Handling Events


    The easiest way to get confidence in how the events work is to add console statements in the handling methods, then watch the console to see the events fire.

    Practice Example #1: Print "Boing" To Console When Player Jumps

    For example, try updating the method that handles the LivingJumpEvent to:
    @SubscribeEvent(priority=EventPriority.HIGHEST, receiveCanceled=true)
    
    public void onEvent(LivingJumpEvent event)
    {
        // DEBUG
        if (event.entity instanceof EntityPlayer)
        {
            System.out.println("Boing");
        }
            
    }
    

    Then run the mod and jump around (press <SPACE>) while looking at the Eclipse console window.  You should see "Boing" in the console log each time you jump.  In fact you will see it twice, because this particular event fires on both client and server side.

    Tip: Fool around by adding console messages to other events then run the mod and do whatever activity you think will trigger the event in game.  It's actually quite fun but importantly is the best way to get understanding on each actual event trigger.

    Tip: Some events fire on both client and server side, some events fire on just one side.  If they fire on both sides you need to think carefully about whether you want to limit the processing to just one side.  For the GUI related events, I have used the @SideOnly(Side.CLIENT) annotation because it is likely that if you actually put in custom code for handling them you will probably call on classes and methods that are likewise @SideOnly(Side.CLIENT).

    Practice Example #2: Change The Way Your Friends' Usernames Display

    There is an event called NameFormat that is posted to set the way a user's name is displayed in game. You can have fun with your friends who might play your mod by appending funny titles or modifications to your or their display name. For example, use something like the following method (replacing the user name with the ones you want to modify):

    if (event.username == "myUserName") // put your user name in the string
    {
        event.displayname = event.username+" the Great and Powerful";
    }        
    else if (event.username == "myFriendsUserName") // put your friend's user name in the string
    {
        event.displayname = event.username+" the Wise";
    }    
    else if (event.username == "myGirlFriendsUserName") // put your significant other's user name in the string
    {
        event.displayname = event.username+" the Beautiful";
    }    
    else
    {
        event.displayname = event.username+" the Ugly"; // for everyone else            
    }
    

    Practice Example #3: Use FogDensity Event To Create Effect When Flying In Clouds

    There are some new events related to creating fog effects.  You can change the density of the fog (FogDensity event) and the color (FogColors event).  Here I give an example where if you fly or climb up to the cloud level you get a fog that makes it seem like you're in the clouds.  I used this for a mod I made where I had a magic beanstalk that grew to the clouds and as you climbed this sort of fog sets in -- it is pretty cool I think.

    Important: Sea level in Minecraft has a Y value of 63 and the clouds are at Y value of 127 and top of sky is 255.  So I wanted the fog density to increase significantly near Y value of 127.  You'll see these numbers used in the math in the code below.

    Tip: The FogDensity.density field takes a float value between 0.0F and 1.0F, where 1.0F is totally thick fog.  Values between 0.3F and 0.5F seem to create a realistic fog thickness.

    Anyway, here an example where fog will lightly set in as you gain very high altitude and then be quite thick at cloud level and above.  The math is just a way I adjusted it such that it will be 0.0F at sea level, 1.0F at top of sky, and I played around with using powers to get an accelerating increase in density that I liked.

    Note: Technically with the formula I used the fog will also increase if you go very deep underground, but that shouldn't matter in practice since you'd have to go at least 100 blocks underground to notice. But if it is problem you can clamp it to 0.0F when underground.

    @SideOnly(Side.CLIENT)
    @SubscribeEvent(priority=EventPriority.NORMAL, receiveCanceled=true)
    public void onEvent(FogDensity event)
    {
        event.density = (float) Math.abs(Math.pow(((event.entity.posY-63)/(255-63)),4));
        event.setCanceled(true); // must be canceled to affect the fog density 
    }
    

    Practice Example #4: Changing The Drops Of Vanilla Entities

    See my supplementary tutorial: Jabelar's Tutorial on Changing Drops of Vanilla Entities

    13 comments:

    1. this really helped me gain and understanding of some verry basic minecraft code i hope to one day become fluent in java and this is a great place to start

      ReplyDelete
    2. This comment has been removed by a blog administrator.

      ReplyDelete
    3. Hi, Im making a custom minecart, I've finished model, entity and the render class. The problem is, when I tried to place my cart to th world, It hadnt been spawned but the Empty Minecart had been spawned instead. Can u help me to fix it up or tell me the way to do it? Thank you.

      ReplyDelete
    4. And here is my E-mail:jjklmn@sina.cn
      Thanks a lot.:)

      ReplyDelete
    5. Hey Julian I have a question about replacing a vanilla block in 1.7.10 if you could shot me an email at og.kloud@gmail.com I would appreciate it.

      ReplyDelete
    6. Hey Julian I have a question about replacing a vanilla block in 1.7.10 if you could shot me an email at og.kloud@gmail.com I would appreciate it.

      ReplyDelete
    7. Thanks for making this page. I have found it to be insanely helpful and comprehensive. One question though, PlayerWakeUpEvent is on two buses. Which one is better to use?

      ReplyDelete
    8. This comment has been removed by the author.

      ReplyDelete



    9. Ježek PlayzSeptember 16, 2016 at 11:23 AM

      Could you please help me? I want to do that when i hit some living entity, it will do an explosion. I think that i´ve done it well(no errors in eclipse), it doesnt work. Here is the code:

      package cz.shadow.motoolsmod.items;

      import net.minecraft.entity.Entity;
      import net.minecraft.entity.EntityLiving;
      import net.minecraft.entity.monster.EntityCreeper;
      import net.minecraft.entity.player.EntityPlayer;
      import net.minecraft.item.ItemSword;
      import net.minecraft.world.World;
      import net.minecraftforge.event.entity.living.LivingEvent.LivingJumpEvent;
      import net.minecraftforge.event.entity.player.AttackEntityEvent;
      import net.minecraftforge.event.world.ExplosionEvent;
      import cpw.mods.fml.common.eventhandler.EventPriority;
      import cpw.mods.fml.common.eventhandler.SubscribeEvent;

      public class ItemSuperSword extends ItemSword{


      public ItemSuperSword(ToolMaterial material) {
      super(material);
      this.setUnlocalizedName("itemSuperSword");
      this.getUnlocalizedName();
      }


      @SubscribeEvent(priority=EventPriority.HIGHEST, receiveCanceled=true)


      public void onEvent(AttackEntityEvent event,Entity target, World world)
      {
      target.setFire(5);
      System.out.println("BOOOOM!");
      world.createExplosion(target, target.posX, target.posY, target.posZ, 2.0F, true);



      }




      }


      ReplyDelete
    10. what i Need to test that is an item in the left Hand ?

      ReplyDelete
    11. LOSYCO ist ein kompetentes, Handling spezialisiertes Unternehmen im Bereich der Produktions-Logistik. Konzipiert und realisiert werden Lean-Produktions-Systeme aus einer Hand.

      Visit Now - http://losyco.com/landingpages/handling.html

      ReplyDelete