Hook Reference

Hooks are the main way of interacting with Hollow Knights code, and we can use them to wait for an event to happen in game, then intercept data related to that event and trigger some code and potentially return different data to what we recieved.

Hooks are set up like so ModHooks.Instance.SetPlayerBoolHook += MyCodeThatRunsWhenPlayerDataBoolsAreSet if put this code in public override void Initialize() your MyCodeThatRunsWhenPlayerDataBoolsAreSet function will be ran everytime the game tries to set any of the bool variables in PlayerData


Visual Studio and most other IDEs will autocomplete hook functions for you, in Visual Studio you just need to write ModHooks.Instance.SetPlayerBoolHook += and then press tab and it’ll create a function with the correct type signature.


ModHooks.Instance.SetPlayerBoolHook += PlayerBoolSet

public void PlayerBoolSet( string target, bool val )

This code can be used to check when certain events happen in game such as obtaining a charm by checking if target == "gotCharm_X" where X is the id of the charm


ModHooks.Instance.GetPlayerBoolHook += PlayerBoolGet

public bool PlayerBoolGet( string target )

This can be used to override the games request for bools stored in saves, such as charm equipped states.

//This snippet makes Wayward Compass be permanently equipped.
public bool PlayerBoolGet( string target ){
    if( "target" == "equippedCharm_1") return true;
    return PlayerData.instance.InternalBoolGet(target);


If you use PlayerData.instance.GetBool, instead of InternalBoolGet you’ll call your function again and crash the game.


ModHooks.Instance.SetPlayerIntHook += PlayerIntSet

public void PlayerIntSet( string target, int val )

See SetPlayerBool, but with an int instead of a bool.


ModHooks.Instance.GetPlayerIntHook += PlayerIntGet

public bool PlayerIntGet( string target )

See SetPlayerInt, but with an int instead of a bool.


ModHooks.Instance.NewPlayerDataHook += NewPlayerData

public void NewPlayerData( PlayerData instance )


Do Not Use - Due to a bug in the game this is called way too often.


ModHooks.Instance.BlueHealthHook += BlueHPRestored

public int BlueHPRestored()

This is called whenever PlayerData.UpdateBlueHealth() is called, which handles lifeblood heart/core, but DOES NOT handle Joni’s or lifeblood bugs.

//This snippet makes the lifeblood charms twice as effective.
public int BlueHPRestored(){
    int retValue = 0;
    if(PlayerData.instance.GetBool("equippedCharm_8")) retValue += 2;
    if(PlayerData.instance.GetBool("equippedCharm_9")) retValue += 4;
    return retValue;


It’s important to note here the use of PlayerData.instance.GetBool(“equippedCharm_8”) instead of the simpler PlayerData.instance.equippedCharm_8 this is to maximize mod compatibility. If another mod overrides the equippedCharm_8 for whatever reason we want to respect that.


ModHooks.Instance.TakeHealthHook += TakeDamage

public int TakeDamage( int damage )

This is called whenver the Knight takes damage via the HeroController.TakeHealth function.

//This snippet doubles all damage dealt to the Knight
public int TakeDamage( int damage ){
    return damage*2;
//This snippet forces the Knight to die if he takes any damage.
public int TakeDamage( int damage ){
    PlayerData.instance.health = 0;
    return damage;


ModHooks.Instance.AfterTakeDamageHook += AfterTakeDamage

public int AfterTakeDamage( int hazardType, int damageAmount )

This is called in HeroController.TakeDamage after invincibility is accounted for, but before damage is applied.


Invincibility in this case doesn’t include Baldur Shell, so that could negate damage after this hook is called.


ModHooks.Instance.BeforePlayerDeadHook += BeforePlayerDied

public void BeforePlayerDied()

Called at the beginning of the GameManger.PlayerDead function.


ModHooks.Instance.AfterPlayerDeadHook += AfterPlayerDied

public void AfterPlayerDied()

Called at the end of the GameManger.PlayerDead function.


ModHooks.Instance.AttackHook += OnAttack

public void OnAttack( AttackDirection dir )

Called whenever the Knight attacks, this is called at the beginning of HeroController.Attack.


ModHooks.Instance.DoAttackHook += OnDoAttack

public void OnDoAttack()

Called whenever the Knight attacks, this is called at the beginning of HeroController.DoAttack, effectively identical to AttackHook except its called before attack_cooldown is set.


ModHooks.Instance.AfterAttackHook += AfterAttack

public void AfterAttackHook( AttackDirection dir )

Called whenever the Knight attacks, this is called at the end of HeroController.Attack, this is called after all the objects related to the slash have been created, possible uses include recolouring/resizing the Knights slash SFX or conditionally setting nail damage.


ModHooks.Instance.SlashHitHook += OnSlashHit

public void OnSlashHit( Collider2D otherCollider, GameObject gameObject )

Called whenever the nail hits anything with a collider, this includes doors, levers, npcs and of course enemies. Potential uses include overriding the 0 damage feature the game has to allow 0 damage nail mods to hit levers.


ModHooks.Instance.CharmUpdateHook += OnCharmUpdate

public void OnCharmUpdate()

This is called after any charm is equipped and if that charms effects are done in code (Which at the time of writing are Nailmaster’s Glory, Fragile Heart, Joni’s Blessing and Carefree Melody) it’ll be called after their effects run.

//This snippet buffs Joni's Blessing back to 1.5x max HP and also fixes it to use PlayerData.instance.GetBool()
public void OnCharmUpdate() {
    if (PlayerData.instance.GetBool("equippedCharm_27")){
        PlayerData.instance.SetInt("joniHealthBlue", (int)((float)PlayerData.instance.GetInt("maxHealthBase") * 1.5f));


ModHooks.Instance.HeroUpdateHook += OnHeroUpdate

public void OnHeroUpdate()

This is called everyframe, as long as the Knight exists. Useful for running code every frame during gameplay without having to create a monobehaviour.


ModHooks.Instance.BeforeAddHealthHook += BeforeAddHealth

public int BeforeAddHealth( int amount )

This is called before health is added to the Knights health pool, amount is the amount to be added to the health pool.

//This snippet makes healing cost 100 geo.
public int BeforeAddHealth( int amount ) {
    if( PlayerData.instance.GetBool("geo") > 100 ){
        PlayerData.instance.geo -= 100;
        return amount;
    return 0;


ModHooks.Instance.HeroUpdateHook += OnHeroUpdate

public void OnHeroUpdate()

This is called everyframe, as long as the Knight exists. Useful for running code every frame during gameplay without having to create a monobehaviour.


ModHooks.Instance.FocusCostHook += FocusCostCalc

public float FocusCostCalc()

This is called when you begin to heal, and returns a float that multiplies how much soul is drained.

//This snippet makes focusing use all your soul.
//note to make this work with less than 33 soul, you will need to change the focus MP amount
public float FocusCostCalc(){
    return (float)PlayerData.instance.GetInt("MPCharge") / 33.0f;


ModHooks.Instance.SoulGainHook += GainSoul

public int GainSoul( int amount )

This is called whenever the Knight gains souls from hitting an enemy with his nail, it passes it the amount it would gain and returns how much it will gain.

//This snippet doubles soul gain from nail hits whenever the knight is on 1 hp.
public int GainSoul( int amount ){
    if( PlayerData.instance.GetInt("health") == 1 )
       return amount * 2;
    return amount;


ModHooks.Instance.DashVectorHook += ChangeDashVel

public Vector2 ChangeDashVel( Vector2 velocity )

Sets the velocity of a dash, called every frame.

//This snippet makes you accelerate during dashes
public Vector2 ChangeDashVel( Vector2 velocity ){
    return velocity * (1 + (2*time.deltaTime));


ModHooks.Instance.DashPressedHook += DashPressed

public bool DashPressed()

Called whenever dash is pressed, return overrides vanilla inputs: true to not dash, false to dash.

//This snippet makes it only possible to dash if you are also rising in your jump.
public bool DashPressed(){
    return !HeroController.instance.cState.jumping;


It might seem weird to NOT dash if you return true, but the intended functionality is for modded implementations of the entire dash, in which case you’d want to disable vanilla code entirely, and becaue of this you return true if you have a modded implementation.


ModHooks.Instance.SavegameLoadHook += SaveLoaded

public void SaveLoaded( int id )

Called directly after a save is loaded, id is the save slot of the loaded file.


ModHooks.Instance.SavegameSaveHook += SaveSaved

public void SaveSaved( int id )

Called directly after a save is saved, id is the save slot of the saved file.


ModHooks.Instance.NewGameHook += NewGameStarted

public void NewGameStarted( int id )

Called directly after a new game is started, id is the save slot of the created file.


ModHooks.Instance.SavegameClearHook += SaveDeleted

public void SaveDeleted( int id )

Called directly before a save is deleted, id is the save slot of the file to be deleted.


ModHooks.Instance.AfterSavegameLoadHook += AfterSaveLoaded

public void AfterSaveLoaded( Patches.SaveGameData data )

Called directly after a save is loaded, however gives you access to the SaveGameData.


ModHooks.Instance.BeforeSavegameSaveHook += BeforeSave

public void BeforeSave( Patches.SaveGameData data )

Called directly before a save is saved and allows you to edit the data that will be written to the save file.


ModHooks.Instance.GetSaveFileNameHook += SaveName

public string SaveName( int saveSlot )

Used to have custom filenames, designed to allow per mod savefiles but can also be used to disable saves or add more saveslots.

public string SaveName( int saveSlot ){
    return "myModName" + saveSlot.toString() + ".dat";


ModHooks.Instance.AfterSaveGameClearHook += AfterSaveCleared

public void AfterSaveCleared( int saveSlot )

Called after a save has been deleted, saveSlot is the slot of the deleted save.


ModHooks.Instance.LanguageGetHook += LanguageGet

public string LanguageGet( string key, string sheet )

Called whenever a localized string is requested, useful for injecting custom text into the game

public string LanguageGet( string key, string sheet )
    if( key == "myKey" )
        return "some profound text";
    return Language.GetInternal(key, sheet);
public string LanguageGet( string key, string sheet )
    return "KEY: " + key + " displays this text: " + Language.GetInternal(key, sheet);


To find out what keys point to what strings of text, you can either use a unity asset extractor such as UABE and look for EN_*.txt, or putting logging inside your hook.


ModHooks.Instance.SceneChanged += SceneLoaded

public void SceneLoaded( string targetScene )

Called after a scene is loaded, scene is unity’s internal name for levels and is any area in game aswell as several cutscenes and the main menu.


It’s recommended to use the internal SceneLoaded hook instead of the the api’s by using UnityEngine.SceneManagement.SceneManager.sceneLoaded However you’ll probably want to delay this by a frame by using a coroutine.


ModHooks.Instance.BeforeSceneLoadHook += BeforeSceneLoad

public string BeforeSceneLoad( string sceneName )

Called directly before a scene starts to load, returning a different string will load a different scene.


If you transition normally, the game expects a scene the Knight could possibly access from that direction, i.e. if you left a room on the right the new scene requires an entrance on the left, dreamgating is glitchy as expected, and going into dreams requires a scene with an object to say where to spawn.


ModHooks.Instance.CursorHook += Cursor

public void Cursor()

Called whenever the game tries to show the cursor.


ModHooks.Instance.ColliderCreateHook += ColliderCreated

public void ColliderCreated( GameObject go )

Called whenever a gameobject is created with both a PlayMakerFSM and a Collider2D, useful for obtaining references to gameplay objects.


ModHooks.Instance.ObjectPoolSpawnHook += ObjectCreated

public GameObject OnObjectPoolSpawn( GameObject go )

Called whenever the game attempts to create a gameobject.


This happens a lot and you should be careful about the complexity of code contained in your hook.


ModHooks.Instance.OnGetEventSenderHook += SpellCreated

public GameObject SpellCreated( GameObject go, HutongGames.PlayMaker.Fsm fsm )

Called whenever OnGetEvent fsm action is ran, this action only exists inside of attacks/spells so is a decent way to get references to them.


This has several issues with the games global object pool, and anything you try to do will likely not work how you intend to without major work arounds.


ModHooks.Instance.ApplicationQuitHook += ApplicationQuit

public void ApplicationQuit()

Called when the game is closed, probably no general use for this, it was implemented for the PlayerDataTracker so a websocket message could be sent whenever the game was closed.


This code won’t run if the game unexpectedly terminates.


ModHooks.Instance.SetFontHook += FontSet

public void FontSet()

Called whenever the game changes language with a different font.


ModHooks.Instance.TextDirectionHook += GetTextDirection

public bool GetTextDirection( bool direction )

Called when the text renderer requests write/read direction of text. Useful for fan translations to RTL languages.


ModHooks.Instance.HitInstanceHook += HitInstanceCreated

public HitInstance HitInstanceCreated( HutongGames.PlayMaker.Fsm owner, HitInstance hitInst )

Called whenever a hit instance is created, hit instances are used to set the damage and damage type of any collisions that occur, so you can override this to set damage on awkward to adjust values such as flukenest damage.


ModHooks.Instance.DrawBlackBordersHook += BlackBordersDrawn

public void BlackBordersDrawn( List<GameObject> borders )

Called when the SceneManager loads a scene, specifically as it calls DrawBlackBorders, passes references to all the objects used to create the border. Useful to delete the vignette if its not your style.


ModHooks.Instance.OnEnableEnemyHook += EnemyEnabled

public bool EnemyEnabled( GameObject enemy, bool isDead )

Called whenever an enemy attempts to spawn, if isDead is true this enemy is persistent and has already been killed, return isDead to mimic default behaviour.

//This snippet will make all enemies spawn regardless of if they have been previously defeated (except bosses).
public bool EnemyEnabled( GameObject enemy, bool isDead )
    return false;


ModHooks.Instance.OnRecieveDeathEventHook += EnemyDied

public void EnemyDied( EnemyDeathEffects enemyDeathEffects, bool eventAlreadyRecieved,
                       ref float? attackDirection, ref bool resetDeathEvent,
                       ref bool spellBurn, ref bool isWatery )

Called whenever an enemy dies.


Possibly triggered multiple times per death, be careful not to trigger code more often than expected.


ModHooks.Instance.OnRecordKillForJournalHook += RecordJournalKill

public void RecordJournalKill( EnemyDeathEffects enemyDeathEffects, string playerDataName,
                               string killedBoolPlayerDataLookupKey, string killCountIntPlayerDataLookupKey,
                               string newDataBoolPlayerDataLookupKey )

Called whenever an enemy dies, and it’s recorded to the journal. The strings are lookup values you can use with PlayerData.GetBool()/PlayerData.GetInt() to obtain relevant data from the save data.