EventHooker is a coremod that can be used to painlessly inject function-based event hooks into arbitrary methods.

To use it, you just need to do two things:

1. Create a file named injector_methods.txt in your resources folder (next to mcmod.info)
   containing a list of method definitions that you wish to inject into.
   Each definition should be on one line. Here is an example definition:
   
   net/minecraft/entity/item/EntityItem, attackEntityFrom, func_70097_a, true, Z, Lnet/minecraft/util/DamageSource;, F
   
   It has six distinct parts:
      The fully-qualified name of the class that contains your desired method.                               (net/minecraft/entity/item/EntityItem)
      The deobfuscated name of the method that you wish to inject into.                                      (attackEntityFrom)
      The SRG name of the method you wish to inject into.                                                    (func_70097_a)
      A boolean, either true or false. If true, the event will be cancelable. More on that later.            (true)
      A type descriptor representing the method's return type. Use "V" for void methods.                     (Z)
      0 or more additional entries, each of which is a type descriptor representing the method's parameters. (Lnet/minecraft/util/DamageSource;,F)
   
   Each part is separated by a comma. You can have more or less whitespace between them if you want, although no newlines.
   Type descriptors are used to specify the method's return type and parameters. The descriptors for primitive values are as follows:
      "I": int
      "S": short
      "B": byte
      "C": char
      "J": long
      "F": float
      "D": double
      "Z": boolean
      "V": void      *keep in mind that void is only valid as a return type, not a parameter.
      
   In addition to the basic primitives, there are object references and arrays, although they are slightly more complicated.
   An array is specified simply by adding a "[" to the beginning of the type descriptor. Add more of them for layered arrays. 
   For example, "[[I" would be a double-layered array of ints. (I.E. int[][])
   Object references are a bit more complicated though. The are specified as follows:
      "L{Type};"
   Replace {Type} with a fully-qualified type name, such as "net/minecraft/util/DamageSource", which gives you the end result of:
      "Lnet/minecraft/util/DamageSource;"
   Finally, you can combine arrays and references together, to get things like this:
      "[Ljava/lang/String;"
   Which specifies an array of Strings.
   
   
2. Register your event-handling function(s) with the InjectionTransformer.
   You should use either registerInjectedEventHandler, registerInjectedCancelableEventHandler, or registerInjectedReturningEventHandler, depending on whether or not
   you specified it as cancelable in the injector_methods.txt, and if so, whether or not you want it to return a value calculated at
   the time of event execution or not. The method parameters are as follows:
      registerInjected(Cancelable/Returning)EventHandler(String classToInject, String methodName, Class<T> returnType, 
      Injected(Cancelable/Returning)EventHandler eventHandler, (T cancelReturnValue), Class<?>... params)
      
   Note that the cancelReturnValue parameter isn't there at all unless you are registering a cancelable (but not returning) handler.
   The parameters are as follows:
      classToInject: The fully-qualified name of the class that contains your desired method.
      methodName: The name of the method that you wish to inject into. It's up to you to ensure that you pass the correct value here!
                  If Launch.blackboard.get("fml.deobfuscatedEnvironment") is true, then pass the deobfuscated name. Otherwise, pass the SRG name.
      returnType: A Class representing the return type of the method. (I.E. int.class). This must be null for void return types.
      eventHandler: An object derived from Injected(Cancelable/Returning)EventHandler that will have its onEvent(Object, Object[]) method called whenever the event fires.
      cancelReturnValue: The value to return from the function if the event is canceled. If the function has a void return type, this must be null. 
                         This parameter only exists for cancelable (but not returning) events.
      params: A list of Classes representing the function's parameters. These cannot be null.
      
   The 'returnType' and 'params' parameters can be swapped out for String-based type descriptors like you did before, if you want.
   If you choose to do so, make sure you use "V" rather than null for the returnType.
   
   As for the Injected(Cancelable/Returning)EventHandler, simply override its
      onEvent(Object classInstance, Object[] parameters)
      
   classInstance is basically 'this' from the calling class - it's safe to cast directly to the class Type.
   Be aware that classInstance will be null if the method that the event was fired from is static.
   
   parameters is a list of Objects matching the parameters that were passed to the method.
   They are safe to directly cast to their matching parameters, but be sure to verify that they aren't null before doing so.
   
   If you are using a cancelable event, onEvent's return type will be a boolean, rather than null. Returning true will cancel the event.
   If the method had a non-void return type, it will return the previously specified cancelReturnValue to its caller.
   
   Alternatively, if you are using a returning event, onEvent's return type will be an InjectedEventReturnData
   Returning an instance of InjectedEventReturnData will cancel the event,
   and return the object passed to it in InjectedEventReturnData constructor.
   Returning null instead of an InjectedEventReturnData instance will not cancel the event, and continue execution as normal.
   
   Note that, if multiple different mods inject a cancelable/returning event into the same method, they will all share the event call.
   Handlers will get their onEvent calls in the order that they were registered.
   Additionally, even if one of the handlers cancels the event, all registered handlers will still get the event!
   There is no way to know if another handler has canceled the event, sorry.
   However, the last call to "registerInjected(Cancelable/Returning)EventHandler" decides what value gets returned,
   if multiple events cancel.

That's about it. Have fun coremodding without having to touch any actual ASM! One thing to keep in mind though: each injection does add
a minor performance cost to the method being injected into. So if possible, avoid injecting into very frequently-called methods.
This is slightly worse for cancelable and returning events, so don't use them if you don't need to.

Oh, and of course: I can't be blamed for any incompatibilities or other problems caused by this. If it's a fault in Event Hooker itself, then I will try to fix it,
but keep in mind that all this coremod actually does on its own is provide an API for hooking events with ASM. It doesn't do much on its own.

Also, I made this after teaching myself ASM in just one day, so there will probably be bugs, at least for a while.
Please let me know if you are certain that an error is the fault of Event Hooker.