Skip to content
RustPluginGenerator

OnThreatLevelUpdate

OnThreatLevelUpdate is called by BasePlayer.EnsureUpdated when the game is about to recompute a player's cached threat level from their worn clothing. Returning a non-null value skips the recalculation and leaves the cached value at zero.

Signature
object OnThreatLevelUpdate(BasePlayer player)

Parameters

Hook parameters
ParameterTypeDescription
playerBasePlayerThe BasePlayer whose cached threat level is being recalculated. It is never null at this point, but the player may be sleeping or disconnected.

Return value

Returning null (or letting the method fall through) lets the game recalculate and cache the threat level from worn gear. Returning any non-null object stops EnsureUpdated immediately, so cachedThreatLevel remains at 0 and the player is treated as non-threatening.

How it works

The hook fires inside BasePlayer.EnsureUpdated, before the game reads inventory.containerWear to work out how threatening the player looks to NPCs (scientists, animals, and similar AI). EnsureUpdated is only reached when the player has not been updated since the last timestamp, so it runs periodically rather than every tick. Note that EnsureUpdated returns early before the hook when the player IsSleeping(), so sleeping players never trigger it. The single argument is the player being evaluated; use it to read equipment, team, position or permissions. Declaring the parameter as BasePlayer is the only meaningful form here since the game already passes that exact type. Returning null lets Rust compute and cache the normal threat value. Returning anything non-null aborts the whole method before the cache is filled, which effectively forces the threat level to stay at the zero value set just above the hook.

Example plugin: Keep members of a permission group non-threatening to NPCs

PassiveThreatGroup.cs
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;

namespace Oxide.Plugins
{
    [Info("Passive Threat Group", "RustPluginGenerator", "1.0.0")]
    [Description("Lets permitted players stay non-threatening to NPCs by skipping the threat level calculation.")]
    public class PassiveThreatGroup : RustPlugin
    {
        private const string PermUse = "passivethreatgroup.use";

        private PluginConfig config;
        private static readonly object StealthResult = new object();

        private class PluginConfig
        {
            [JsonProperty("Enable stealth when permission is held")]
            public bool EnableStealth { get; set; } = true;
        }

        protected override void LoadDefaultConfig() => config = new PluginConfig();

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                config = Config.ReadObject<PluginConfig>();
                if (config == null) throw new Exception();
            }
            catch
            {
                PrintWarning("Configuration file is invalid, using defaults");
                LoadDefaultConfig();
            }
            SaveConfig();
        }

        protected override void SaveConfig() => Config.WriteObject(config);

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                ["Enabled"] = "Passive mode enabled. NPCs will treat you as non-threatening.",
                ["Disabled"] = "Passive mode disabled. Your threat level is calculated normally.",
                ["Usage"] = "Usage: /passive to toggle passive mode."
            }, this);
        }

        private string Msg(string key, string userId = null, params object[] args) =>
            string.Format(lang.GetMessage(key, this, userId), args);

        private void Init()
        {
            permission.RegisterPermission(PermUse, this);
        }

        private object OnThreatLevelUpdate(BasePlayer player)
        {
            if (!config.EnableStealth || player == null || player.IsNpc)
                return null;

            if (!permission.UserHasPermission(player.UserIDString, PermUse))
                return null;

            return StealthResult;
        }

        [ChatCommand("passive")]
        private void CmdPassive(BasePlayer player, string command, string[] args)
        {
            if (player == null)
                return;

            if (!config.EnableStealth)
            {
                SendReply(player, Msg("Disabled", player.UserIDString));
                return;
            }

            if (permission.UserHasPermission(player.UserIDString, PermUse))
            {
                permission.RevokeUserPermission(player.UserIDString, PermUse);
                SendReply(player, Msg("Disabled", player.UserIDString));
            }
            else
            {
                permission.GrantUserPermission(player.UserIDString, PermUse, this);
                SendReply(player, Msg("Enabled", player.UserIDString));
            }
        }
    }
}

The plugin registers a permission and a config toggle. Each time OnThreatLevelUpdate fires, EnsureUpdated is about to derive a threat value from the player's clothing, so the plugin checks whether the player holds the passive permission. If stealth mode is enabled and the player is authorised, the hook returns a non-null placeholder object, which aborts the recalculation and leaves the cached threat level at zero. Players without the permission get null, so their threat is computed normally from armour and clothing. /passive lets players toggle their own membership through the permission API, and every change is reported back through the language file.

Common use cases

  • Stealth perks for donors

    Give a paid or trusted group reduced NPC aggression by returning a non-null value so their threat cache stays empty.

  • Disguise systems

    When a player wears a specific outfit and holds a permission, suppress their computed threat so scientists treat them as harmless.

  • PvE-friendly zones

    Combine with position checks to keep players in a designated safe area from being flagged as threats to wandering animals.

Pitfalls

  • Zero threat means zero, not controlled

    Returning non-null skips the entire calculation, so cachedThreatLevel stays at 0 rather than the specific value you might want. You cannot set an intermediate threat level with this hook.

  • Sleeping players are skipped

    EnsureUpdated returns before the hook when the player is sleeping, so a returned value never applies to offline or sleeping players until they wake and refresh again.

  • Do not waste hot-path work

    The hook can fire repeatedly as the player is re-evaluated, so keep the body to cheap permission checks and avoid logging or allocations inside it.

Build a plugin with OnThreatLevelUpdate

Describe what should happen and get a compiled plugin that uses this hook.

Prompt: Stealth perks for donors using the OnThreatLevelUpdate hook, with a config file and a permission
Generate this plugin

Edit the prompt on the next screen. 2 free plugins a month, no card.

Last updated Oct 26, 2026. Found a mistake? Email support@rustplugingenerator.com.

Build a plugin with OnThreatLevelUpdate

Generate