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.
object OnPlayerDigComplete(BasePlayer player, BaseDiggableEntity diggableEntity)Parameters
| Parameter | Type | Description |
|---|---|---|
player | BasePlayer | The BasePlayer who finished digging. Can be null on unusual paths, so guard before using it. |
diggableEntity | BaseDiggableEntity | The 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
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 MetalDetectorFlagif 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.
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