OnItemUnlock
OnItemUnlock is called when an item's IsLocked flag is about to be cleared by Item.LockUnlock(false). Returning a non-null value cancels the unlock and the item stays locked.
object OnItemUnlock(Item item)Parameters
| Parameter | Type | Description |
|---|---|---|
item | Item | The item instance being unlocked. Read its info.shortname, skin, parent container and GetOwnerPlayer() to decide whether the unlock should be allowed. |
Return value
Returning null lets the original code continue: IsLocked is cleared and the item is marked dirty. Returning any non-null value (commonly true) skips that block entirely, so the item remains locked and no network update is sent.
How it works
The hook fires from Item.LockUnlock(bool) inside the branch that handles unlocking. Oxide calls it only when the item is currently locked and the new state is false, so a call means the game is actually about to clear BaseEntity.Flags.IsLocked and mark the item dirty. The single item parameter is the live Item whose flag would change; from it you can reach the owning player via GetOwnerPlayer(), the container via parent, and the shortname/skin for identification. There is no way to narrow the dispatch by type here because there is only one version of the hook. Return a non-null value to block the change: the flag is left set, MarkDirty is not called, and the item stays locked until something unlocks it again. Typical uses are protecting admin-granted event items, keeping a key item locked inside a container, or logging unlock attempts for auditing. Note that this runs as part of the item flag update, so keep the body cheap and never call Puts or PrintWarning here.
Example plugin: Keep special event items locked
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("Locked Event Items", "RustPluginGenerator", "1.0.0")]
[Description("Prevents configured items from being unlocked by Item.LockUnlock.")]
public class LockedEventItems : RustPlugin
{
private const string PermAdmin = "lockedeventitems.admin";
private PluginConfig config;
private class PluginConfig
{
[JsonProperty("Protected shortnames")]
public List<string> Shortnames = new List<string> { "supply.signal" };
[JsonProperty("Only protect this skin (0 = any)")]
public ulong Skin = 0UL;
}
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>
{
["Protected"] = "{0} is on the protected list.",
["Unprotected"] = "{0} was removed from the protected list.",
["NotOnList"] = "{0} is not on the protected list.",
["List"] = "Protected shortnames: {0}"
}, 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(PermAdmin, this);
}
private object OnItemUnlock(Item item)
{
if (item?.info == null) return null;
if (!config.Shortnames.Contains(item.info.shortname)) return null;
if (config.Skin != 0UL && item.skin != config.Skin) return null;
return true;
}
[ChatCommand("lockitem")]
private void CmdLockItem(BasePlayer player, string command, string[] args)
{
if (player == null) return;
if (!permission.UserHasPermission(player.UserIDString, PermAdmin))
{
player.ChatMessage("You do not have permission to use this command.");
return;
}
if (args == null || args.Length < 1)
{
SendReply(player, Msg("List", player.UserIDString, string.Join(", ", config.Shortnames)));
return;
}
string shortname = args[0].ToLowerInvariant();
if (ItemManager.FindItemDefinition(shortname) == null)
{
player.ChatMessage("Unknown shortname: " + shortname);
return;
}
if (config.Shortnames.Contains(shortname))
{
config.Shortnames.Remove(shortname);
SendReply(player, Msg("Unprotected", player.UserIDString, shortname));
}
else
{
config.Shortnames.Add(shortname);
SendReply(player, Msg("Protected", player.UserIDString, shortname));
}
SaveConfig();
}
}
}The plugin keeps a configurable list of shortnames (and one skin filter) that must never be unlocked. In OnItemUnlock it checks item.info and the skin, then returns true for protected items so Item.LockUnlock(false) leaves IsLocked set. A chat command lets admins add or remove shortnames from the list and persists the change through the config file. The hook itself does no logging or UI work, so it stays cheap even if items are unlocked frequently.
Common use cases
Protect event reward items
Mark rewards from an event as permanently locked so players cannot move or use them until the event ends.
Audit unlock attempts
Record which player tried to unlock a protected item by reading
item.GetOwnerPlayer()before returning a blocking value.Prevent skin swaps on locked items
Combine with
OnItemSkinChangeto keep a locked item's appearance fixed while it is held by a player.
Pitfalls
Not every unlock goes through this path
Only
Item.LockUnlocktriggers the hook. Code that setsBaseEntity.Flags.IsLockeddirectly or removes the item bypasses it entirely.Returning false still blocks
The patcher ignores the value's meaning and only checks for null. Returning
falsecancels the unlock just liketruedoes.Owner can be null
Items in world containers or dropped on the ground have no owning player, so always null-check
GetOwnerPlayer()before using it.
Build a plugin with OnItemUnlock
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 OnItemUnlock
Generate