CanLootEntity
CanLootEntity is called when a player tries to open a lootable entity such as a storage box, and returning a non-null value blocks the loot panel from opening.
object CanLootEntity(BasePlayer player, StorageContainer storageContainer)Parameters
| Parameter | Type | Description |
|---|---|---|
player | BasePlayer | The BasePlayer attempting to open the container. Already validated with CanInteract by the caller in most injection sites, but check IsConnected before sending UI or chat. |
storageContainer | StorageContainer | The StorageContainer being opened. Use its inventory for item checks, OwnerID for ownership, and transform.position for distance or zone logic. |
Return value
Return null to let the container open as normal. Return any non-null value (a string or true is conventional) to stop the original open-loot code, so the player never receives the loot panel.
How it works
This hook fires from the open-loot path of each lootable type: StorageContainer.PlayerOpenLoot for boxes, LootableCorpse.RPC_LootCorpse for player and NPC corpses, ResourceContainer.StartLootingContainer for hemp and other gatherables, DroppedItemContainer.PlayerOpenLoot for dropped backpacks, ContainerIOEntity.PlayerOpenLoot for hoppers and conveyors, plus horses, industrial crafters and world items. It runs after the game's own checks (player exists, CanInteract(), corpse CanLoot) so a block here is final.
The player argument is the looter. The container argument gives you inventory for item inspection, OwnerID to compare against team or privilege data, and transform.position for distance checks. Declaring a more specific second parameter type, for example DroppedItemContainer or LootableCorpse, makes Oxide call your method only for that source;
other loot types skip your hook entirely, which is how you scope a rule to a single container class.
Because the hook fires on every open attempt, keep the body cheap: no prints, no repeated data file reads, cache what you need at load time.
Other signatures
Oxide also calls CanLootEntity from other places in the game with these parameter types. Declare the overload you need, or several:
object CanLootEntity(BasePlayer player, LootableCorpse lootableCorpse)object CanLootEntity(BasePlayer player, ResourceContainer resourceContainer)object CanLootEntity(BasePlayer player, DroppedItemContainer droppedItemContainer)object CanLootEntity(BasePlayer player, RidableHorse ridableHorse)object CanLootEntity(BasePlayer player, ContainerIOEntity containerIOEntity)object CanLootEntity(BasePlayer player, IndustrialCrafter industrialCrafter)object CanLootEntity(BasePlayer player, WorldItem worldItem)
Example plugin: Lock player corpses for the owning team
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("Corpse Team Loot Gate", "RustPluginGenerator", "1.0.0")]
[Description("Restricts corpse looting to the dead player's team and the corpse owner.")]
public class CorpseTeamLootGate : RustPlugin
{
private const string PermBypass = "corpseteamlootgate.bypass";
private PluginConfig config;
private StoredData data;
private class PluginConfig
{
[JsonProperty("Enable team-only corpse looting")]
public bool Enabled = true;
[JsonProperty("Notify blocked players in chat")]
public bool NotifyBlocked = true;
}
private class StoredData
{
[JsonProperty("Corpse teams by net id")]
public Dictionary<ulong, ulong> CorpseTeams = new Dictionary<ulong, ulong>();
}
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>
{
["Blocked"] = "This corpse belongs to another team. Only the owner's team can loot it."
}, 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(PermBypass, this);
data = Interface.Oxide.DataFileSystem.ReadObject<StoredData>(Name) ?? new StoredData();
}
private void Unload()
{
Interface.Oxide.DataFileSystem.WriteObject(Name, data);
}
private void OnEntityDeath(BaseCombatEntity entity, HitInfo info)
{
var player = entity as BasePlayer;
if (player == null || player.currentTeam == 0 || entity.net == null) return;
data.CorpseTeams[entity.net.ID.Value] = player.currentTeam;
}
private object CanLootEntity(BasePlayer player, LootableCorpse corpse)
{
if (!config.Enabled || player == null || corpse == null || corpse.net == null) return null;
ulong corpseId = corpse.net.ID.Value;
ulong teamId = 0;
if (data.CorpseTeams.TryGetValue(corpseId, out teamId))
{
// teamId was recorded at death
}
ulong owner = corpse.playerSteamID;
if (teamId == 0)
{
// Fall back to the corpse owner's current team when nothing was recorded.
var ownerPlayer = BasePlayer.FindByID(owner);
if (ownerPlayer != null) teamId = ownerPlayer.currentTeam;
}
if (player.userID.Get() == owner) return null;
if (player.IsAdmin || permission.UserHasPermission(player.UserIDString, PermBypass)) return null;
if (teamId != 0 && player.currentTeam == teamId) return null;
if (config.NotifyBlocked && player.IsConnected)
player.ChatMessage(Msg("Blocked", player.UserIDString));
return true;
}
}
}The plugin declares CanLootEntity with a LootableCorpse parameter, so it only runs for corpses and ignores boxes. When the config option Enable team-only corpse looting is true, the plugin looks up the team recorded for the corpse at death. If no team was recorded, it falls back to the corpse owner's current team when that player can be found. The corpse owner, admins, and players with corpseteamlootgate.bypass pass through with null, as do members of the recorded team. Anyone else gets a chat message from the lang file (if Notify blocked in chat is enabled) and a non-null return that blocks the panel. On OnEntityDeath, the dead player's team id is written into a data file keyed by net.ID.Value; the file is saved in Unload.
Common use cases
Team-only corpse looting
Compare the corpse owner's team with the looter's
currentTeamand block outsiders. This makes PvP deaths riskier without touching regular boxes.Raid windows on player storage
Return non-null from the
StorageContaineroverload outside configured raid hours, or when the looter is not building authed on the box'sGetBuildingPrivilege().Premium or permission-gated boxes
Check
permission.UserHasPermissionon a custom key before opening certain DroppedItemContainers, and point players to the store or a help command when denied.
Pitfalls
The hook fires per container type
Declaring
StorageContainerdoes not cover corpses, dropped backpacks or hoppers. Add one overload per type you want to police, otherwise players bypass the rule through a different loot source.Returning false still blocks
The check is for non-null, not truthiness. Returning
falsefrom a method declaredobjectstops the open just liketrue; onlynullallows looting.Corpse data goes stale
A corpse can be despawned or emptied without any hook you handle. Persist the corpse id on death, remove it when consumed or killed, and periodically prune the data file.
Plugin recipes that use CanLootEntity
- How to make a Rust corpse loot protection plugin (solo and team lock)Locks a dead player's corpse and dropped backpack to the owner and their current team for a configurable number of minutes. It watches spawned containers with OnEntitySpawned and blocks other players in CanLootEntity, with a permission-based admin bypass.
- How to make a Rust crate loot lock plugin (first opener claims it)This plugin gives the first player who opens a loot container a temporary claim on it, enforced through the CanLootEntity hook, so anyone outside their team is blocked until the lock expires.
- How to make a Rust heli and Bradley loot lock plugin (PvE ownership)Tracks damage dealt to the Patrol Helicopter and Bradley APC per player and locks the crates they drop for a configurable time, allowing only the top damager and their team to loot. Uses OnEntityTakeDamage, OnEntityDeath, OnEntitySpawned and CanLootEntity.
- How to make a Rust NPC loot lock plugin (owner + team only)Locks NPC corpses to the killer and their team for a configurable number of seconds after death, then opens them to everyone. Uses OnEntityDeath to record ownership and CanLootEntity to gate looting.
Build a plugin with CanLootEntity
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 CanLootEntity
Generate