Prefix and Postfix

Harmony Mods ›› Harmony ››
Parent Previous Next

As mentioned before, Harmony allows you to intercept methods, and execute your code before or after they are executed.


It's important to note that all Harmony hooks, such as Prefix and Postfix, are static.


A Prefix() will execute before the targeted method runs. It can prevent the original method from even executing.

A Postfix() will execute after the targeted method runs, regardless of any conditional logic being handled inside of the original method.


From the Harmony Wiki:

A patch must be a static method

A prefix patch has a return type of void or bool

A postfix patch has a return type of void or the return signature must match the type of the firstparameter (passthrough mode)

Patches can use a parameter named __instance to access the instance value if original method is not static

Patches can use a parameter named __result to access the returned value (prefixes get default value)

Patches can use a parameter named __state to store information in the prefix method that can be accessed again in the postfix method. Think of it as a local variable. It can be any type and you are responsible to initialize its value in the prefix

Parameter names starting with three underscores, for example ___someField, can be used to read and write (with 'ref') private fields on the instance that has the same name (minus the underscores)

Patches can define only those parameters they want to access (no need to define all)

Patch parameters must use the exact same name and type as the original method (object is ok too)

Patches can either get parameters normally or by declaring any parameter ref (for manipulation)

To allow patch reusing, one can inject the original method by using a parameter named __originalMethod


To better understand the supported parameters, here's a table from the Harmony Wiki:


// original method in class Customer
private List<string> getNames(int count, out Error error)
// prefix
// - wants instance, result and count
// - wants to change count
// - returns a boolean that controls if original is executed (true) or not (false)
static bool Prefix(Customer __instance, List<string> __result, ref int count)
// postfix
// - wants result and error
// - does not change any of those
static void Postfix(List<string> __result, Error error)


Let's do some examples of Prefix() calls. Postfix() calls are very similar, with only their execution order and return values being different.


EntityAlive.SetAttackTarget()


Vanilla Target: public void SetAttackTarget(EntityAlive _attackTargetint _attackTargetTime)


For this example, we want to access a custom method from a custom class that inherits from EntityAlive. The original method is not virtual, so while we can call it from our custom class, we cannot over-ride it. The parameters of this method are _attackTarget and _attackTargetTime, but those are not valuable to us for this case. What we want is access to the entire class to see if it's actually our custom class or not. In order to do that, we need to pass in the class type plus the special Harmony keyword "__instance".


In our Prefix, we define our Prefix as: static bool Prefix(EntityAlive __instance)


   [HarmonyPatch(typeof(EntityAlive))]

   [HarmonyPatch("SetAttackTarget")]

   public class SphereII_EntityAlive_SetAttackTarget

   {

       static bool Prefix(EntityAlive __instance)

       {

           // If a door is found, try to open it. If it returns false, start attacking it.

           EntityAliveSDX myEntity = __instance as EntityAliveSDX;

           if (myEntity)

               myEntity.RestoreSpeed();

           return true;

       }

   }


We return true since we still want the original method to run.



XUiC_TipWindow.ShowTip()


Vanilla Target: public static void ShowTip(string tipEntityPlayerLocal _localPlayerToolTipEvent closeEvent)


The below example was designed to prevent the TipWindow from showing a tip on the screen. We define that the method we want to target is in the XUiC_TipWindow class, and it's the ShowTip method. There's only one ShowTip() method in the class, so we do not need to specify the parameter signature.


   // Removes the Tool Tips for Journal

   [HarmonyPatch(typeof(XUiC_TipWindow))]

   [HarmonyPatch("ShowTip")]

   public class SphereII_ClearUI_XUiC_TipWindow

   {

       static bool Prefix()

       {

           return false;

       }

   }


This Prefix() simply returns false, which will cause the original ShowTip() method not to execute at all.



Block.PlaceBlock():


Vanilla Target: public virtual void PlaceBlock(WorldBase _worldBlockPlacement.Result _resultEntityAlive _ea)


We see that it has a WorldBase, BlockPlacement and EntityAlive as parameters. For the purpose of the mod, preventing placing blocks while in the air, we only want to access the EntityAlive. This is so we can check what the EntityAlive is actually doing at the time of the call. Rather than placing all the parameters of the method, and not using them, Harmony allows us to specify just the parameters we want to use.


   // Returns true for the default PlaceBlock code to execute. If it returns false, it won't execute it at all.

   static bool Prefix(EntityAlive _ea)

   {

       Debug.Log("Prefix PlaceBox");

       EntityPlayerLocal player = _ea as EntityPlayerLocal;

       if(player == null)

           return true;


       if(player.IsGodMode == true)

           return true;


       if(player.IsFlyMode == true)

           return true;


       if(player.IsInElevator())

           return true;


       if(player.IsInWater())

           return true;


       // If you aren't on the ground, don't place the block.

       if(!player.onGround)

           return false;


       return true;

   }


We have a mix of return types here. If we return false, then the original method will not execute. In the context of this logic, that means the block will not be placed. If it's true, then the original method will be called, and all of its logic will be applied before ultimately deciding to place the block or not.


EntityFactory.addEntityToGameObject():


Vanilla target: private static Entity addEntityToGameObject(GameObject _gameObjectstring _className)


To load custom entity's, we need to add in a hook to the EntityFactory. For this example, we are going to use a Postfix(). That is, we are going to let the original method run, look at its return type to see if it's something we want. and change it if necessary.


   static Entity Postfix(Entity __result, GameObject _gameObject, string _className)

   {

       if(__result == null)

       {

           Type type = Type.GetType(_className + ", Mods");

           if(type != null)

               return (Entity)_gameObject.AddComponent(type);

       }

       return __result;

   }


If the original method returns null, that means it could not find the entity class, and is returning null. Entity __result parameter is passed into the Postfix() method as the return value of the original method. Since it's null, we want to add the ", Mods" to allow it to look in our custom Mods assembly (mods.dll).


Because a Postfix() may return a void or the original return type, we either return our new reference, or simply return the original __result value.

Created with the Personal Edition of HelpNDoc: Benefits of a Help Authoring Tool