Skip to content
RustPluginGenerator

OnStashExposed

OnStashExposed is called after a player reveals a buried StashContainer, once the stash has been switched from hidden to visible.

Signature
void OnStashExposed(StashContainer stash, BasePlayer player)

Parameters

Hook parameters
ParameterTypeDescription
stashStashContainerThe StashContainer that the player just exposed. It has already been unhidden when the hook fires, so you can read its inventory, position and owners.
playerBasePlayerThe BasePlayer whose reveal check triggered the callback. This is the player standing near and looking at the stash.

Return value

The return value is ignored; the reveal completes regardless of what your hook method returns. Return type void is the natural choice.

How it works

The hook fires inside BasePlayer.CheckStashRevealInvoke, the periodic check a player runs while looking around. When the player's aim settles on a nearby hidden stash long enough, the game calls SetHidden(false) on it, records the reveal in analytics and then invokes OnStashExposed with the stash and the looking player. It does not fire when a player opens an already visible stash, and it does not fire for other container types.

Use the parameters to react to a specific player finding a specific stash: log who found what, notify a team, apply a cooldown, or mark the stash for later handling. Because the stash is already visible, you can inspect stash.inventory and stash.OwnerID at this point.

The hook is void, so you cannot cancel the reveal by returning a value. If you need to prevent exposure, do it elsewhere (for example by intercepting the reveal check or moving the stash). Declaring a narrower type than StashContainer is not useful here since the argument is always a stash.

Example plugin: Log and announce stash finds

StashRevealAnnouncer.cs
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("Stash Reveal Announcer", "RustPluginGenerator", "1.0.0")]
    [Description("Logs and optionally announces when players expose hidden stashes")]
    public class StashRevealAnnouncer : RustPlugin
    {
        private const string PermAnnounce = "stashrevealannouncer.announce";

        private PluginConfig config;
        private readonly List<string> recentReveals = new List<string>();

        private class PluginConfig
        {
            [JsonProperty("Broadcast finds to all players")]
            public bool BroadcastFinds { get; set; } = false;

            [JsonProperty("Message the finding player")]
            public bool MessageFinder { get; set; } = true;

            [JsonProperty("Keep recent reveals in data file")]
            public int KeepRecent { get; set; } = 50;
        }

        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>
            {
                ["Reveal"] = "You exposed a stash at {0}.",
                ["Broadcast"] = "{0} exposed a stash at {1}."
            }, 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(PermAnnounce, this);
            LoadReveals();
        }

        private void Unload()
        {
            SaveReveals();
        }

        private void OnStashExposed(StashContainer stash, BasePlayer player)
        {
            if (stash == null || player == null) return;

            Vector3 pos = stash.transform.position;
            string coords = $"{pos.x:F1}, {pos.z:F1}";

            if (config.MessageFinder && player.IsConnected)
                player.ChatMessage(Msg("Reveal", player.UserIDString, coords));

            if (config.BroadcastFinds)
                Server.Broadcast(Msg("Broadcast", null, player.displayName, coords));

            recentReveals.Add($"{DateTime.UtcNow:u} {player.displayName} ({player.UserIDString}) at {coords}");
            while (recentReveals.Count > Mathf.Max(1, config.KeepRecent))
                recentReveals.RemoveAt(0);

            SaveReveals();
        }

        private void LoadReveals()
        {
            recentReveals.Clear();
            var data = Interface.Oxide.DataFileSystem.ReadObject<List<string>>(Name);
            if (data != null) recentReveals.AddRange(data);
        }

        private void SaveReveals()
        {
            Interface.Oxide.DataFileSystem.WriteObject(Name, recentReveals);
        }
    }
}

The plugin listens for OnStashExposed and records each reveal. It builds a short message with the player name and the stash position, sends it to the player through the language system and optionally broadcasts it to the server when Broadcast Finds is enabled in the config. Reveals are also appended to a rolling in-memory log and written to oxide/data/StashRevealAnnouncer so admins can review recent finds after a restart. Because the hook fires only when a player actually uncovers a stash, the log stays small and the messages are not spammed.

Common use cases

  • Admin audit trail

    Persist who exposed which stash and where, so staff can trace suspicious stash hunting or investigate reports of stashes being found in raid-protected areas.

  • Team alerts

    Notify the stash owner's team that a hidden stash was discovered, using player.currentTeam and RelationshipManager to resolve members.

  • Reward exploration

    Grant a small reward or achievement the first time a player uncovers a stash on the map, tracked per player in saved data.

Pitfalls

  • You cannot cancel the reveal

    The hook is informational and the original code path continues; returning a value does nothing. Block exposure earlier in the reveal check instead.

  • Fires for the looking player only

    The stash is already visible by the time the hook runs, so other players who walk up afterwards will not produce another call for the same stash.

  • Stash may be empty or owned

    Always null-check stash.inventory before reading items, and treat OwnerID 0 as unowned rather than assuming a player.

Build a plugin with OnStashExposed

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

Prompt: Admin audit trail using the OnStashExposed 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 OnStashExposed

Generate