Skip to content
RustPluginGenerator

CanLock

CanLock is called when a player tries to lock a CodeLock, a KeyLock or a ModularCarCodeLock after the code and whitelist checks have run. Returning a non-null value stops the lock from being applied (or overrides the permission result for car locks).

Signature
object CanLock(BasePlayer player, CodeLock codeLock)

Parameters

Hook parameters
ParameterTypeDescription
playerBasePlayerThe BasePlayer attempting to lock the entity. Check team, permission or building auth here.
codeLockCodeLockThe CodeLock (or KeyLock, or ModularCarCodeLock when called from the other injection sites) being locked. It is an entity, so you can read net.ID, position and OwnerID.

Return value

Returning null lets the original code continue, so the lock is applied normally (or the default permission check result is used for modular cars). Returning any non-null value stops the lock from being set on CodeLock and KeyLock, and for ModularCarCodeLock.HasLockPermission a returned bool becomes the result of the permission check.

How it works

The hook fires inside CodeLock.TryLock right after the player interacts, the lock is unlocked, the code is four digits and the player is whitelisted, but before the locked flag is set and the effect plays. It also fires from KeyLock.Lock (when a key/cupboard-auth player locks a key lock) and from ModularCarCodeLock.HasLockPermission, where a returned bool becomes the permission answer used by the locking code.

Use player to evaluate whether that specific player may lock this entity: check building privilege via codeLock.GetBuildingPrivilege(), team membership with player.currentTeam, a stored permission, or a cooldown you track per player. Both arguments can be null-guarded; codeLock is a BaseLock subclass so it is also a BaseEntity.

Declaring BasePlayer narrows the CodeLock and KeyLock calls. To handle only key locks, declare KeyLock; for vehicles, use the three-argument overload with ModularCar. Because the return type is object, every overload can coexist, but Oxide only dispatches to the method whose parameter types all match the arguments.

Other signatures

Oxide also calls CanLock from other places in the game with these parameter types. Declare the overload you need, or several:

  • object CanLock(BasePlayer player, KeyLock keyLock)
  • object CanLock(BasePlayer player, ModularCar owner, ModularCarCodeLock modularCarCodeLock)

Example plugin: Block locking outside your own building privilege

LockAuthGuard.cs
using System.Collections.Generic;
using System;
using Newtonsoft.Json;
using Oxide.Core;

namespace Oxide.Plugins
{
    [Info("Lock Auth Guard", "RustPluginGenerator", "1.0.0")]
    [Description("Blocks locking a CodeLock or KeyLock unless the player is authorised on the covering tool cupboard.")]
    public class LockAuthGuard : RustPlugin
    {
        private const string PermBypass = "lockauthguard.bypass";

        private PluginConfig config;

        private class PluginConfig
        {
            [JsonProperty("Require building auth to lock")]
            public bool RequireAuth { get; set; } = true;

            [JsonProperty("Allow when there is no tool cupboard")]
            public bool AllowWithoutCupboard { get; set; } = 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>
            {
                ["NotAuthorised"] = "You must be authorised on the tool cupboard covering this lock to set a code."
            }, 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);
        }

        // Handles CodeLock.TryLock and KeyLock.Lock.
        private object CanLock(BasePlayer player, CodeLock codeLock)
        {
            return Evaluate(player, codeLock);
        }

        private object CanLock(BasePlayer player, KeyLock keyLock)
        {
            return Evaluate(player, keyLock);
        }

        private object Evaluate(BasePlayer player, BaseLock baseLock)
        {
            if (!config.RequireAuth || player == null || baseLock == null) return null;
            if (permission.UserHasPermission(player.UserIDString, PermBypass)) return null;

            var privilege = baseLock.GetBuildingPrivilege();
            if (privilege == null)
            {
                // No cupboard range: either allow (default) or block locking.
                return config.AllowWithoutCupboard ? null : false;
            }

            if (privilege.IsAuthed(player)) return null;

            player.ChatMessage(Msg("NotAuthorised", player.UserIDString));
            return false;
        }
    }
}

LockAuthGuard stops players from locking a CodeLock or KeyLock when they are not authorized on the tool cupboard covering that entity. The CanLock hook fires with a BasePlayer and a BaseLock subclass; the plugin casts to BaseLock, then checks GetBuildingPrivilege() and IsAuthed(player). If there is a privilege box and the player is not on its auth list, the hook returns false to cancel the lock. A permission (lockauthguard.bypass) and a config flag let admins bypass the rule. A short chat message reuses the language file so the feedback is localized.

Common use cases

  • Require building auth before locking

    Prevent raiders who reached an unlocked box from quickly code-locking it; only players authorized on the cupboard that covers the lock may set it.

  • Limit who may lock doors on a vehicle

    Use the ModularCar owner overload to allow only the owner, or the owner's team, to set the code lock on a ModularCar.

  • Cooldown lock abuse

    Track the last lock attempt per player and return false briefly to slow down players spamming the lock button on an unlocked container.

Pitfalls

  • Returning true is not a grant

    In CodeLock and KeyLock the hook only lets the original code decide; returning a non-null value always cancels the lock, even true. Only the ModularCar overload treats a returned bool as a map result, so use the correct signature if you want to allow or deny.

  • Auth checks need a privilege box

    GetBuildingPrivilege() returns null for locks outside a cupboard range, and non-player entities such as cars have no cupboard. Decide your fallback (allow, deny or check owner) explicitly instead of relying on a null default.

  • Several overloads dispatch separately

    Declaring CanLock(BasePlayer, KeyLock) skips CodeLock calls entirely, and a signature with the wrong parameters never fires. Register one overload per lock type only if you truly need different logic.

Build a plugin with CanLock

Describe what should happen and get a compiled plugin that uses this hook.

Prompt: Require building auth before locking using the CanLock 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 CanLock

Generate