Skip to content
RustPluginGenerator

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.

Signature
object OnItemUnlock(Item item)

Parameters

Hook parameters
ParameterTypeDescription
itemItemThe 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

LockedEventItems.cs
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 OnItemSkinChange to keep a locked item's appearance fixed while it is held by a player.

Pitfalls

  • Not every unlock goes through this path

    Only Item.LockUnlock triggers the hook. Code that sets BaseEntity.Flags.IsLocked directly or removes the item bypasses it entirely.

  • Returning false still blocks

    The patcher ignores the value's meaning and only checks for null. Returning false cancels the unlock just like true does.

  • 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.

Prompt: Protect event reward items using the OnItemUnlock hook, with a config file and a permission
Generate this plugin

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