randomuserhi-KillIndicatorFix icon


A client-side mod that makes kill indicators consistent when you are not host.

Last updated a month ago
Total downloads 17298
Total rating 6 
Categories Client Mods
Dependency string randomuserhi-KillIndicatorFix-0.1.5
Dependants 24 other packages depend on this package

This mod requires the following mods to function

BepInEx-BepInExPack_GTFO-3.1.0 icon

BepInEx pack for GTFO. Preconfigured and includes Unity Base DLLs.

Preferred version: 3.1.0
randomuserhi-DamageSync-0.0.4 icon

A host only mod that syncs enemy HP with clients.

Preferred version: 0.0.4


Level up your GTFO experience - know your fight, and own the night with the KillIndicatorFix mod ʕ ᵔᴥᵔ ʔ

A client-side mod that makes kill indicators consistent when you are not host.

Recommended! Keep vanilla progress!

Requires Bepinex, but is not dependent on GTFO-API plugin, so you can remove GTFO-API.dll from plugins folder to keep vanilla rundown and progression.

Known Limitations:

  • Sentry's will not show kill indicators as it would for host (client simply won't see their own sentry's kills).
    • Host-only support added since v0.1.0!
  • Delay on kill indicator due to ping when client prediction fails.

============ Config File ============

The way this fix works is by keeping track of enemies you are shooting at:

  • If your shot is predicted to kill on client side, the kill marker is shown.
  • If a onkill event from host is received for an enemy you are shooting at then a kill marker is shown.

To prevent two kill markers from showing, the plugin keeps note of what enemies you are shooting at and what enemies it has already shown the kill marker for:

  • If the kill marker for an enemy has already been shown, it will not show it again when receiving the onkill event from host.
  • It will keep track of kill markers that have been shown in the last 3 seconds (dictated by markerLifeTime in config)

To prevent a kill marker showing on an enemy you shot 30 minutes ago, the plugin keeps track of enemies you have shot at recently within a 1 second period (dictated by tagBufferPeriod in config)

============ API Events ============

using KillIndicatorFix;

[BepInPlugin(Module.GUID, Module.Name, Module.Version)]
[BepInDependency(KillIndicatorFix.BepInEx.Module.GUID, BepInDependency.DependencyFlags.HardDependency)]
public class Plugin : BasePlugin {
    public override void Load() {
        Kill.OnKillIndicator += (Action<EnemyAgent, ItemEquippable, long>)OnKillIndicator;
    /// <summary>
    /// Is called whenever a kill indicator is shown for a given enemy.
    /// </summary>
    /// <param name="enemy">Enemy that kill indicator was shown for.</param>  
    /// <param name="item">Item used.</param>  
    /// <param name="delay">On client, if the local player made the kill, provides the delay in milliseconds from player shot to recieving death packet from host.</param>  
    private static void OnKillIndicator(EnemyAgent enemy, ItemEquippable item, long delay) {

If you have a mod that applies damage and you want KillIndicatorFix to work with it, you can alter the enemies HP value directly for clients and tag the enemy using:

/// <summary>
/// Tag an enemy for Kill Indicator Fix to handle kills.
/// </summary>
/// <param name="enemy">Enemy to tag.</param>  
/// <param name="item">Item that applied the damage for this tag. If not provided, uses currently equipped weapon.</param>  
/// <param name="localHitPosition">Where the indicator should appear. Typically this is set to the hit position for bullet hit. If not provided, uses last tag's hit position when available, otherwise uses eye position. NOTE: The position is local to the enemy, not world-space.</param>  
Kill.TagEnemy(EnemyAgent enemy, ItemEquippable? item = null, Vector3? localHitPosition = null);

Example use:

Dam_EnemyDamageLimb limb = ...;
Dam_EnemyDamageBase enemy = ...

enemy.Health -= damage;
Kill.TagEnemy(enemy); // Tag the enemy, so when it dies KIF will show kill indicator as approapriate.
if (enemy.Health <= 0) {
	limb.ShowHitIndicator(...); // Important to trigger local hit marker for KillIndicatorFix (accounts for delay due to ping)

============ Compatability Notice for other Plugin Developers ============

This plugin alters the internal hp values stored by the game (when ran as client):

[HarmonyPatch(typeof(Dam_EnemyDamageLimb), nameof(Dam_EnemyDamageLimb.BulletDamage))]
public static void BulletDamage(Dam_EnemyDamageLimb __instance, float dam, ...)
    // Apply damage modifiers (head, occiput etc...)
    float num = __instance.ApplyWeakspotAndArmorModifiers(dam, precisionMulti);
    num = __instance.ApplyDamageFromBehindBonus(num, position, direction);
    __instance.m_base.Health -= num; // Alter the internal health value


The decision to do so was done out of laziness and to avoid overcomplicating the system. As a result, if your plugin relies on these values (either through modification or by reading it) then the plugin will be incompatible with this one.

If you wish to use the health values whilst still maintaining compatability, you will need to store and manage your own health values seperately. This can be done using a dictionary of InstanceIDs to corresponding health values and manually subtracting health from damage sources:

// Dictionary storing hp values for enemies
// make sure to clear this dictionary OnRundownStart() or something to prevent leaks.
private static Dictionary<int, float> hpTracker = new Dictionary<int, float>();

[HarmonyPatch(typeof(Dam_EnemyDamageLimb), nameof(Dam_EnemyDamageLimb.BulletDamage))]
public static void BulletDamage(Dam_EnemyDamageLimb __instance, float dam, ...)
    Dam_EnemyDamageBase m_base = __instance.m_base;
    EnemyAgent owner = m_base.Owner;
    int instanceID = owner.GetInstanceID();
    // Apply damage modifiers (head, occiput etc...)
    float num = __instance.ApplyWeakspotAndArmorModifiers(dam, precisionMulti);
    num = __instance.ApplyDamageFromBehindBonus(num, position, direction);
    // Manage your own health tracker - maybe remove trackers when their hp falls below 0
    if (hpTracker.ContainsKey(instanceID))
        hpTracker[instanceID] = hpTracker[instanceID] - num;
    else hpTracker.Add(instanceID, m_base.HealthMax - num);

It should be noted that the above example only tracks changes to hp from bullet damage, you will need to extend this example to include melee damage etc...

  • Furthermore, for client side, getting health changes from Sentries is impossible since they run on host side. Unless you fundementally change how sentries work, you will not be able to determine health changes from sentries as a client.

============ Change Log ============


  • Damage patches now have priority [HarmonyPriority(Priority.Last)] for improved compatability


  • Added Tag API


  • Removed OnEnemyDead API since it causes issue with EndSkill's EXP mod


  • Fixed bug with consumable mines


  • Added API events


  • Added support for sentries
    • If both host and client have the mod, client will receive hit indicators for their sentry


  • Fixed wack damage calculation bug from previous update


  • Added note for other plugin developers when it comes to compatability.
  • Changed damage calculation to be closer to original source.


  • Fixed a bug where clients could see kill markers of bots when they melee kill an enemy.


  • Fixed a bug where clients could see kill markers of bots.


  • Fixed the "Double hit marker on kill" bug -> Used to show both the kill marker and the regular hit marker for the killing shot.
  • Added config file to edit timing values for different ping situations (In general, values should be larger for high ping, refer to notes above).


  • Made KillIndicatorFix work together with DamageSync for better indicators.


  • Added DamageSync as a dependency, so if you are hosting with DamageSync + KillIndicatorFix, clients will have slightly more consistent kill indicators if they are unmodded.


  • Changed hit marker from network sync to use your last shot location instead of EyePosition to make seeing the marker for giants clearer


  • Initial Release