OnItemAction
OnItemAction is called when a player client sends an item action command (PlayerInventory.ItemCmd) with an item UID and an action string. Returning a non-null value cancels the original handling of that command.
object OnItemAction(Item item, string text, BasePlayer player)Parameters
| Parameter | Type | Description |
|---|---|---|
item | Item | The Item instance resolved from the UID sent by the client. Use item.info.shortname, item.skin or item.parent to identify it. Never null when the hook fires, because the game returns early before calling the hook if the item lookup fails. |
text | string | The action string the client sent with the item command, for example a skin-change or clothing/action identifier. Treat it as untrusted client input. |
player | BasePlayer | The BasePlayer who issued the command (msg.player). Use it to check permissions or ownership. It can be null when the command does not come from a connected player, so guard before use. |
Return value
Returning null lets the command continue through the game's normal checks (ownership, locks, CanMoveItemsFrom). Returning any non-null value makes the patched method return immediately, dropping that item action without further processing. The original method returns void, so the value itself is only used as a cancel signal.
How it works
The hook fires inside PlayerInventory.ItemCmd, which runs when the client sends an ItemCmd network message containing an item UID and a text payload. The game first reads the UID and string, resolves the item with FindItemByUID, and bails out early if the item does not exist. That means item is never null when your hook runs. The original code path that follows validates ownership, locks and CanMoveItemsFrom before acting on the action, so this hook sits before all of those checks.
text is whatever action identifier the client chose to send and player is the sending connection. You can inspect item.info.shortname, item.skin, item.parent and player.UserIDString to decide whether to intervene. Declaring a more specific player type is not useful here since only BasePlayer is passed; narrowing to a subclass would only cause Oxide to skip calls when the sender is not that type.
There is a single injection site, so the hook has one behaviour: a non-null return stops the command from being processed further. Use it for moderation of specific item actions rather than routine per-tick logic.
Example plugin: Block skin actions on non-permitted items
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("Item Action Guard", "RustPluginGenerator", "1.0.0")]
[Description("Blocks item action commands on configured items unless the player has a bypass permission")]
public class ItemActionGuard : RustPlugin
{
private const string PermBypass = "itemactionguard.bypass";
private PluginConfig config;
private class PluginConfig
{
[JsonProperty("Blocked item shortnames")]
public List<string> BlockedShortnames = new List<string> { "rifle.ak", "rifle.lr300" };
[JsonProperty("Log blocked actions")]
public bool LogBlocked = true;
}
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"] = "That action is not allowed on this item."
}, 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 object OnItemAction(Item item, string text, BasePlayer player)
{
if (item == null || item.info == null)
return null;
if (player == null || player.IsNpc || player.IsAdmin)
return null;
if (!config.BlockedShortnames.Contains(item.info.shortname))
return null;
if (permission.UserHasPermission(player.UserIDString, PermBypass))
return null;
if (config.LogBlocked)
{
PrintWarning($"Blocked action '{text}' on {item.info.shortname} for {player.displayName} ({player.UserIDString})");
}
player.ChatMessage(Msg("Blocked", player.UserIDString));
return false;
}
}
}The plugin holds a configurable set of shortnames whose actions should be restricted, plus a permission that exempts staff. In OnItemAction it checks the sender is valid and is not an admin or NPC, then looks at item.info.shortname. If the item is in the protected list and the player lacks the bypass permission, it logs a short warning once and returns a non-null value, which drops the command before the game touches the item. Normal actions on unprotected items return null, so default behaviour is untouched. The config and messages use the standard Oxide patterns, and the permission is registered in Init.
Common use cases
Restrict skin changes
Cancel action strings on expensive items unless the player has a permission, so skins cannot be swapped on locked-down loot.
Audit suspicious commands
Record the shortname, skin and player id for unusual action strings to spot client-side exploit attempts.
Event-only item rules
During an event, block actions on event items for players not on the event team by returning a non-null value.
Pitfalls
text is client-controlled
Do not trust the action string for security decisions. Match against known item shortnames and player permissions instead.
player can be null
The hook receives
msg.player, which may be null for non-player senders. Always null-check before readingUserIDString.Cancelling does not remove items
Returning non-null only stops this command. If you need to remove or modify the item, do it explicitly with
item.Remove()or container calls.
Build a plugin with OnItemAction
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 OnItemAction
Generate