Skip to content
RustPluginGenerator

OnPlayerDigComplete

OnPlayerDigComplete is called when a player finishes digging a diggable entity, right before the game spawns the loot item or runs the flag's dug-in behavior.

Signature
object OnPlayerDigComplete(BasePlayer player, BaseDiggableEntity diggableEntity)

Parameters

Hook parameters
ParameterTypeDescription
playerBasePlayerThe BasePlayer who finished digging. Can be null on unusual paths, so guard before using it.
diggableEntityBaseDiggableEntityThe BaseDiggableEntity that was fully dug. Cast it to BaseDiggableEntity subclasses or check ShortPrefabName to tell buried stash points apart from metal detector flags.

Return value

The game only runs its default rewarded-loot path when the hook returns null. Returning any non-null value (for example false) suppresses SpawnLootListItem and the flag's dug handling, so no item is awarded and the entity keeps its state. Return null to let normal behavior proceed.

How it works

This hook fires from BaseDiggableEntity.OnFullyDug, which runs after a player has fully excavated a buried entity (stash points, buried caches) and from MetalDetectorFlag.OnFullyDug for metal detector flags. Both call sites run the hook before the original path: in the base class that path calls SpawnLootListItem to award the hidden loot, and in the flag variant it disables the flag's collision and continues its own cleanup. Because the hook receives the entity itself, you can read ShortPrefabName, owner id, position, and pick up a reference to a storage container if one is attached. You can also narrow the parameter type: declaring MetalDetectorFlag as the second parameter makes Oxide only call your hook for flag digs, while BaseDiggableEntity receives every diggable. Use it to gate loot awards, add bonus rewards, log digging activity, or drive quest and progression systems. It never fires for player-opened stashes that were already dug out, only on the completion event.

Other signatures

Oxide also calls OnPlayerDigComplete from other places in the game with these parameter types. Declare the overload you need, or several:

  • object OnPlayerDigComplete(BasePlayer player, MetalDetectorFlag metalDetectorFlag)

Example plugin: Add bonus loot to buried stashes

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

namespace Oxide.Plugins
{
    [Info("Dig Reward Bonus", "RustPluginGenerator", "1.0.0")]
    [Description("Grants a configurable bonus item when players finish digging stashes or flags.")]
    public class DigRewardBonus : RustPlugin
    {
        private PluginConfig config;
        private readonly Dictionary<ulong, int> digCount = new Dictionary<ulong, int>();

        private class PluginConfig
        {
            [JsonProperty("Bonus chance (0-100)")]
            public int BonusChance = 25;

            [JsonProperty("Bonus item shortname")]
            public string BonusItem = "scrap";

            [JsonProperty("Bonus item amount")]
            public int BonusAmount = 5;

            [JsonProperty("Prefabs that grant a bonus")]
            public List<string> PrefabWhitelist = new List<string>
            {
                "stash.small",
                "stash.large",
                "metaldetectorflag"
            };
        }

        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>
            {
                ["Bonus"] = "You dug up a bonus: {0} x {1}",
                ["Count"] = "You have finished {0} digs."
            }, this);
        }

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

        private object OnPlayerDigComplete(BasePlayer player, BaseDiggableEntity diggableEntity)
        {
            if (player == null || diggableEntity == null) return null;

            string prefab = diggableEntity.ShortPrefabName ?? string.Empty;
            if (!config.PrefabWhitelist.Contains(prefab)) return null;

            if (digCount.ContainsKey(player.userID.Get()))
                digCount[player.userID.Get()]++;
            else
                digCount[player.userID.Get()] = 1;

            if (UnityEngine.Random.Range(0, 100) >= config.BonusChance) return null;

            var item = ItemManager.CreateByName(config.BonusItem, config.BonusAmount);
            if (item == null) return null;

            player.GiveItem(item);
            player.ChatMessage(Msg("Bonus", player.UserIDString,
                item.info.displayName.english, config.BonusAmount));

            return null;
        }

        [ChatCommand("digcount")]
        private void CmdDigCount(BasePlayer player, string command, string[] args)
        {
            if (player == null) return;
            int count = 0;
            digCount.TryGetValue(player.userID.Get(), out count);
            SendReply(player, Msg("Count", player.UserIDString, count));
        }

        private void Unload()
        {
            digCount.Clear();
        }
    }
}

The plugin hooks OnPlayerDigComplete and lets the vanilla loot spawn normally (returns null), then injects extra items. In OnPlayerDigComplete each diggable is checked by ShortPrefabName; only entities listed in config with a positive chance give a bonus. A short message is sent through the language file, and the reward is created with ItemManager.CreateByName before being given with GiveItem, which drops it at the player's feet if their inventory is full. Scores are tracked per player in memory only for a chat command and are cleared on unload, keeping the plugin stateless on disk. Any invalid config value is guarded so a bad shortname never throws.

Common use cases

  • Tie digging to a quest system

    Increment a quest counter when a player digs up a stash or metal detector flag, then hand out a reward once a threshold is met. Return null so vanilla loot is unaffected.

  • Log suspicious dig activity

    Write the player id, entity prefab and position to your own data file to spot players who repeatedly dig in a small radius, without flooding server console output.

  • Block loot on flagged instances

    Return a non-null value for diggables inside a restricted zone so the player gets nothing, and send a message explaining that the spot is protected.

Pitfalls

  • Returning a value by accident

    Any non-null return skips the game's loot spawn entirely. If you only want to observe, make sure every code path returns null explicitly.

  • Both signatures fire

    MetalDetectorFlag derives from BaseDiggableEntity, so a hook declared with BaseDiggableEntity receives both. Guard with as MetalDetectorFlag if you need to treat flags differently.

  • Giving items at the wrong time

    GiveItem can drop the item at the player's position if their inventory is full. That's fine, but the hook runs before vanilla loot, so your bonus may be granted before the player sees the stash contents.

Build a plugin with OnPlayerDigComplete

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

Prompt: Tie digging to a quest system using the OnPlayerDigComplete 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 OnPlayerDigComplete

Generate