OnItemDespawn
OnItemDespawn is called from DroppedItem.IdleDestroy when a dropped item entity is being removed by the server, just before the item is unregistered and registered with the buried items system.
void OnItemDespawn(Item item)Parameters
| Parameter | Type | Description |
|---|---|---|
item | Item | The Item instance that was carried by the dropped item entity and is about to be destroyed. It still has its info, amount, skin and condition populated at this point, but the owning DroppedItem may already be in the teardown path. |
Return value
The hook's return value is ignored. IdleDestroy is void and calls Interface.CallHook without inspecting the result, so returning a value changes nothing about the original despawn behavior.
How it works
The hook fires inside DroppedItem.IdleDestroy, which the server runs when a dropped item entity is destroyed while nobody is interacting with it (despawn). The call happens before the item is handed to BuriedItems.Instance.Register, so item is still a valid Item object when your hook runs. You can use it to track items that vanish naturally, clean up bookkeeping keyed by the item, or record the shortname and amount for analytics. Declaring the parameter as Item is the only supported signature; a more specific type will not match because the argument is an Item, not a subclass. Note that IdleDestroy is the despawn path, not the loot path: picking the item up runs a different method, so this hook does not fire when a player grabs the item. If you need pickup tracking, pair it with OnItemPickup. Do not assume the entity is still reachable from the item here; rely on item only. Avoid heavy work since many dropped items can despawn in the same frame during cleanup phases.
Example plugin: Report despawns of high-value dropped items
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Despawn Reporter", "RustPluginGenerator", "1.0.0")]
[Description("Announces when watched dropped items despawn on the ground")]
public class DespawnReporter : RustPlugin
{
private class PluginConfig
{
[JsonProperty("Watched shortnames")]
public List<string> WatchedShortnames = new List<string> { "scrap", "explosives", "sulfur.ore", "lowgradefuel" };
[JsonProperty("Broadcast to chat")]
public bool Broadcast = true;
[JsonProperty("Minimum seconds between messages")]
public float MinInterval = 5f;
}
private PluginConfig config;
private HashSet<string> watched;
private float lastMessageTime = -1000f;
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>
{
["Despawned"] = "A dropped {0} (x{1}) despawned on the ground."
}, this);
}
private string Msg(string key, string userId = null, params object[] args) =>
string.Format(lang.GetMessage(key, this, userId), args);
private void OnServerInitialized()
{
watched = new HashSet<string>(config.WatchedShortnames ?? new List<string>(), StringComparer.OrdinalIgnoreCase);
lastMessageTime = -1000f;
}
private void OnItemDespawn(Item item)
{
if (item == null || item.info == null || watched == null) return;
if (!config.Broadcast || !watched.Contains(item.info.shortname)) return;
float now = UnityEngine.Time.realtimeSinceStartup;
if (now - lastMessageTime < config.MinInterval) return;
lastMessageTime = now;
string text = Msg("Despawned", null, item.info.displayName.english, item.amount);
Server.Broadcast(text);
}
private void Unload()
{
watched = null;
}
}
}The plugin keeps a configurable list of watched shortnames (defaults include explosive and high-tier resources). When OnItemDespawn fires, it checks item.info.shortname against the watched list, respects an optional per-minute rate limit so a mass despawn does not flood chat, and broadcasts a summary of what was lost. Watched values are read once at startup into a HashSet<string> for fast lookups inside the hook. The example also shows safe null-checking of item and item.info, uses language messages for the output text, and cleans up its rate-limit counter in Unload.
Common use cases
Track loss of valuable items on the ground
Log or broadcast when watched shortnames such as explosives or scrap despawn, which can indicate a raid that was interrupted or items left out too long.
Clean up per-item bookkeeping
If you attach metadata to dropped items (for example an owner map keyed by item), remove those entries here so records do not leak when the entity is destroyed.
Feed despawn data to server analytics
Aggregate counts of despawned items by shortname over time and write totals to oxide/data on unload for offline review.
Pitfalls
It is not a pickup hook
DroppedItem.IdleDestroyis the natural despawn path. Picking the item up or looting it takes a different code path, so do not rely on this hook to know when a player took an item.Items can be null or partially detached
The hook only guarantees the
Itemobject is non-null at the call site. Do not assume the owningDroppedItementity can be resolved from it or that its container/parent is meaningful.This fires a lot during cleanup
Bulk entity cleanup can invoke the hook many times in a short window. Avoid chat spam, blocking calls, or expensive allocations; guard output with a rate limit.
Build a plugin with OnItemDespawn
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 OnItemDespawn
Generate