OnLootPlayer
OnLootPlayer is called when a player opens another player's corpse loot panel, after the containers have been attached to the looter's loot state but before the loot panel is sent to the client.
void OnLootPlayer(BasePlayer player, BasePlayer player2)Parameters
| Parameter | Type | Description |
|---|---|---|
player | BasePlayer | The BasePlayer whose corpse inventory is being opened, i.e. the owner of the dying player entity that is being looted. |
player2 | BasePlayer | The BasePlayer who is doing the looting; this is the player whose client receives the loot panel. |
Return value
The return value is ignored at this injection site; the original code continues and the loot panel is always sent. To block or alter looting use the CanLootPlayer hook instead, which is checked before any container work.
How it works
Fires inside BasePlayer.RPC_LootPlayer on the corpse entity (the this in the injection), which is why the first argument is the dead player and the second is the looter. The game reaches this point only after CanInteract, CanBeLooted and StartLootingEntity have all succeeded and the main, wear and belt containers have been added to the looter's inventory.loot state. Use player2 to identify the looter (permissions, team checks, combat-blocked rules) and player for the corpse owner, which is useful for death/raid bookkeeping. Declaring the first parameter as BasePlayer is required by the existing signature; declaring a narrower type than BasePlayer would make Oxide skip the call for any other argument, so leave both as BasePlayer. Because the hook fires before SendImmediate and the player_corpse RPC, state changes made here (strip, flags, CUI) are visible to the client on the first frame the panel opens. It does not fire for boxes, dropped item containers or NPC corpses.
Example plugin: Block looting enemy corpses while combat-blocked
using UnityEngine;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("Combat Loot Block", "RustPluginGenerator", "1.0.0")]
[Description("Blocks looting of player corpses while the looter is in combat.")]
public class CombatLootBlock : RustPlugin
{
private const string PermBypass = "combatlootblock.bypass";
private class PluginConfig
{
[JsonProperty("Combat window (seconds)")]
public float CombatWindow { get; set; } = 10f;
[JsonProperty("Allow looting teammates")]
public bool AllowTeammates { get; set; } = true;
}
private PluginConfig config;
private readonly Dictionary<string, float> lastCombat = new Dictionary<string, float>();
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"] = "You cannot loot a player corpse while in combat."
}, 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);
}
private void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info)
{
if (info == null || entity == null) return;
var attacker = info.InitiatorPlayer;
var victim = entity as BasePlayer;
if (attacker == null || victim == null || attacker == victim) return;
if (attacker.IsNpc || victim.IsNpc) return;
lastCombat[attacker.UserIDString] = UnityEngine.Time.realtimeSinceStartup;
}
private void OnLootPlayer(BasePlayer player, BasePlayer looter)
{
if (player == null || looter == null || looter.IsNpc) return;
if (permission.UserHasPermission(looter.UserIDString, PermBypass)) return;
float last;
if (!lastCombat.TryGetValue(looter.UserIDString, out last)) return;
if (UnityEngine.Time.realtimeSinceStartup - last > config.CombatWindow) return;
if (config.AllowTeammates && player.currentTeam != 0 && player.currentTeam == looter.currentTeam) return;
looter.inventory.loot.Clear();
looter.inventory.loot.SendImmediate();
looter.ChatMessage(Msg("Blocked", looter.UserIDString));
}
private void Unload()
{
lastCombat.Clear();
}
}
}The plugin records when each player last damaged another player in OnEntityTakeDamage and stores it in a dictionary keyed by the looter's UserIDString. When OnLootPlayer fires it looks up the looter's last damage timestamp and, if it is within the configured window and the corpse is not a teammate, it closes the loot panel and sends a language message. Because the containers are attached before the hook runs, the plugin empties the player's loot state so nothing can be taken, then destroys any open UI and returns. Permission combatlootblock.bypass exempts admins and staff, and the config controls the combat window length.
Common use cases
Anti-raid looting cooldowns
Prevent players who just took damage from looting player corpses for a few seconds, cutting down on combat logging and body-sniping.
Corpse access permissions
Restrict corpse looting to teammates or permission holders while leaving regular boxes and NPC corpses untouched.
Loot logging and telemetry
Record who looted which corpse and when, using the two BasePlayer arguments to build a persistent log for admin review.
Pitfalls
Wrong argument order
The first parameter is the corpse's owner, not the looter. Swapping them leads to permission checks running against a dead player.
Does not stop the panel
The return value at this injection is ignored, so the loot UI still opens. Clear
player2.inventory.lootcontainers and callSendImmediateyourself if you need to close it.Narrow parameter types
Changing
playerorplayer2to a subclass makes Oxide skip the hook call, so the plugin silently stops working. Keep both asBasePlayer.
Build a plugin with OnLootPlayer
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 OnLootPlayer
Generate