OnLootEntity
OnLootEntity is called when a player starts looting an entity, right after PlayerLoot.StartLootingEntity records the entity as the loot source. It fires for containers, corpses, dropped item containers and any other lootable entity.
void OnLootEntity(BasePlayer player, BaseEntity targetEntity)Parameters
| Parameter | Type | Description |
|---|---|---|
player | BasePlayer | The BasePlayer who is opening the loot panel. This is the PlayerLoot owner, not necessarily the owner of the container. Null-check it before use. |
targetEntity | BaseEntity | The BaseEntity being looted, e.g. a StorageContainer, LootableCorpse, DroppedItemContainer or another ILootableEntity. Cast it to the specific type you care about. |
Return value
The return value is ignored. PlayerLoot.StartLootingEntity continues regardless of what your hook returns, so returning false or null does not block the loot action. To cancel looting, hook CanLootEntity instead.
How it works
The hook fires inside PlayerLoot.StartLootingEntity, immediately after the game verifies the entity is server-side and stores it as entitySource, but before the loot panel is marked dirty and before LastLootedBy is written on the target. That means you see the loot event before the container's loot state is finalized, so changes you make here still affect the panel the player is about to see.
player is the player performing the loot action. targetEntity is the entity being opened; it is typed as BaseEntity, so cast it with as to StorageContainer, LootableCorpse, DroppedItemContainer, BaseOven, BradleyAPC and so on. Declaring a more specific type for the second parameter makes Oxide skip the call when the entity is a different type, which is useful if you only care about one kind of container. The same applies to player if you declared a narrower type, though BasePlayer is almost always correct here.
Use it for per-container rules: logging who opened what, applying loot cooldowns, populating or locking specific containers, or tracking hacking progress. Because the hook does not return a value, you cannot cancel the loot from here; use CanLootEntity for that.
Example plugin: Log container loots with player and entity details
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Loot Audit Log", "RustPluginGenerator", "1.0.0")]
[Description("Records who loots which containers and exposes the recent history to admins.")]
public class LootAuditLog : RustPlugin
{
private const string PermView = "lootauditlog.view";
private PluginConfig config;
private List<LootEntry> entries = new List<LootEntry>();
private class PluginConfig
{
[JsonProperty("Maximum stored entries")]
public int MaxEntries = 200;
[JsonProperty("Log corpses")]
public bool LogCorpses = true;
[JsonProperty("Log dropped item containers")]
public bool LogDroppedContainers = true;
}
private class LootEntry
{
[JsonProperty("steamId")]
public string SteamId;
[JsonProperty("playerName")]
public string PlayerName;
[JsonProperty("prefab")]
public string Prefab;
[JsonProperty("position")]
public string Position;
[JsonProperty("time")]
public int Time;
}
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>
{
["NoEntries"] = "No loot entries recorded yet.",
["Header"] = "Last {0} loot entries:",
["Line"] = "{0} ({1}) looted {2} at {3}",
["NoPermission"] = "You do not have permission to use this command."
}, 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(PermView, this);
}
private void OnServerInitialized()
{
var saved = Interface.Oxide.DataFileSystem.ReadObject<List<LootEntry>>(Name);
if (saved != null) entries = saved;
}
private void OnLootEntity(BasePlayer player, BaseEntity targetEntity)
{
if (player == null || targetEntity == null) return;
if (!config.LogCorpses && targetEntity is LootableCorpse) return;
if (!config.LogDroppedContainers && targetEntity is DroppedItemContainer) return;
if (!(targetEntity is StorageContainer) &&
!(targetEntity is LootableCorpse) &&
!(targetEntity is DroppedItemContainer)) return;
entries.Add(new LootEntry
{
SteamId = player.UserIDString,
PlayerName = player.displayName,
Prefab = targetEntity.ShortPrefabName,
Position = targetEntity.transform.position.ToString("F1"),
Time = Facepunch.Math.Epoch.Current
});
while (entries.Count > config.MaxEntries)
entries.RemoveAt(0);
}
[ChatCommand("lootlog")]
private void CmdLootLog(BasePlayer player, string command, string[] args)
{
if (player == null) return;
if (!permission.UserHasPermission(player.UserIDString, PermView))
{
SendReply(player, Msg("NoPermission", player.UserIDString));
return;
}
if (entries.Count == 0)
{
SendReply(player, Msg("NoEntries", player.UserIDString));
return;
}
int count = Mathf.Min(10, entries.Count);
SendReply(player, Msg("Header", player.UserIDString, count));
for (int i = entries.Count - count; i < entries.Count; i++)
{
var e = entries[i];
var ts = DateTimeOffset.FromUnixTimeSeconds(e.Time).LocalDateTime.ToString("HH:mm:ss");
SendReply(player, Msg("Line", player.UserIDString, e.PlayerName, e.SteamId, e.Prefab, ts));
}
}
private void OnServerSave()
{
Interface.Oxide.DataFileSystem.WriteObject(Name, entries);
}
private void Unload()
{
Interface.Oxide.DataFileSystem.WriteObject(Name, entries);
}
}
}The plugin writes a data file entry for every time a player opens a lootable container, recording the player's steam id, display name, the entity's prefab name, world position and a Unix timestamp. OnLootEntity is used to capture the event the moment StartLootingEntity fires, then the entry is buffered in memory. OnServerSave and Unload flush the buffer to oxide/data/LootAuditLog via Interface.Oxide.DataFileSystem, so disk writes happen rarely instead of on every loot. A /lootlog chat command (permission lootauditlog.view) prints the last 10 entries so admins can review recent container access without opening the file. Config controls how many entries the buffer keeps and whether corpses and dropped item containers are recorded.
Common use cases
Track container access for admin audits
Record every player/container pair with a timestamp so you can see who opened a locked box or took from a corpse. Keep the write in memory and flush on save to avoid disk churn.
Apply per-container loot cooldowns
Store the last loot time per entity id and, when a player opens the same box too soon, notify them via chat or drop a marker. Because the hook fires before the panel is shown, you can also clear the container here.
Restock or reseed special containers
For event boxes, insert items into the StorageContainer inventory in
OnLootEntityso the player sees the contents on the panel that is about to open, rather than after a delay.
Pitfalls
Does not cancel looting
The hook is informational; its return value is ignored. If you need to deny opening a container, use
CanLootEntitywhich is checked earlier and can return false.targetEntity is not always a container
Corpses, dropped item containers and vehicles all reach this hook. Cast with
asand null-check the result; assumingStorageContainerwill throw or silently skip on other lootable types.Fires on every loot action
Avoid Puts, PrintWarning or per-loot disk writes. Cache in memory and flush on save or shutdown to keep the server responsive during busy raids.
Plugin recipes that use OnLootEntity
- How to make a Rust first loot bonus plugin (chance-based crate bonus)This plugin hooks OnLootEntity and rolls a configurable chance to insert one bonus item from a weighted list into a loot container the first time it is opened. Each container is tracked by net ID and pays out at most one bonus.
- How to make a Rust treasure hunt plugin (Oxide/Carbon)Adds a /treasure admin command that spawns a loot crate at a random land position and announces its map grid, then announces the first player to loot it. It uses OnLootEntity to detect the winner and a timer to despawn the crate.
Build a plugin with OnLootEntity
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 OnLootEntity
Generate