CanDestroyLock
CanDestroyLock is called when a player tries to remove the lock from a modular car, letting a plugin allow or deny the action.
object CanDestroyLock(BasePlayer player, ModularCar modularCar, BaseVehicleModule viaModule)Parameters
| Parameter | Type | Description |
|---|---|---|
player | BasePlayer | The BasePlayer attempting to remove the lock from the car. Never null when the hook fires from a player action, but null-check it anyway. |
modularCar | ModularCar | The ModularCar instance the lock is attached to; use it for position checks, owner checks or module iteration. |
viaModule | BaseVehicleModule | The BaseVehicleModule that holds the lock being destroyed, for example a door or cockpit module. May be null in some paths, so null-check before reading it. |
Return value
Return null (or any non-boolean) to let the game apply its normal lock-destruction rule via CarLock.PlayerCanDestroyLock. Return a bool to override that decision: true allows destroying the lock, false blocks it.
How it works
Oxide fires CanDestroyLock inside ModularCar.PlayerCanDestroyLock, which runs when a player interacts with a car lock with the intent to remove it. The game calls this before it falls back to CarLock.PlayerCanDestroyLock for the default decision, so a returned boolean replaces that default entirely.
player is the actor trying to remove the lock, useful for permission or ownership checks. modularCar is the vehicle itself, so you can compare OwnerID, read the position or inspect mounted modules. viaModule is the vehicle module the lock lives on; it can describe a door or other lockable slot and may be null, so guard it.
Declaring a more specific type for a parameter narrows when Oxide calls your method: if you type the second parameter as ModularCar, Oxide only invokes the hook when the argument really is a modular car, which it always is here. Typing viaModule more specifically (for example as a car door type) makes Oxide skip calls where the module is a different type or null.
Because this fires on player interaction it is not a hot path, but still avoid logging on every call. Do the decision work cheaply and return quickly.
Example plugin: Restrict car lock removal to the vehicle owner
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Car Lock Owner Only", "RustPluginGenerator", "1.0.0")]
[Description("Restricts removal of modular car locks to the vehicle owner or a permitted group.")]
public class CarLockOwnerOnly : RustPlugin
{
private const string PermBypass = "carlockowneronly.bypass";
private PluginConfig config;
private class PluginConfig
{
[JsonProperty("Only owner can remove locks")]
public bool OwnerOnly { 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>
{
["NotOwner"] = "You are not the owner of this vehicle, you cannot remove its lock."
}, this);
}
private string Msg(string key, string userId = null) => lang.GetMessage(key, this, userId);
private void Init()
{
permission.RegisterPermission(PermBypass, this);
}
private object CanDestroyLock(BasePlayer player, ModularCar modularCar, BaseVehicleModule viaModule)
{
if (!config.OwnerOnly || player == null || modularCar == null) return null;
if (!player.IsConnected) return null;
ulong ownerId = modularCar.OwnerID;
// Unowned vehicles (plugin/admin spawns) keep default behavior.
if (ownerId == 0) return null;
if (player.userID.Get() == ownerId) return null;
if (permission.UserHasPermission(player.UserIDString, PermBypass)) return null;
player.ChatMessage(Msg("NotOwner", player.UserIDString));
return false;
}
}
}The plugin registers a permission on load and stores a toggle in config. When CanDestroyLock fires, it first checks whether the config option is enabled and the player is real and connected. It then looks at the car's OwnerID: if the owner ID is zero (unowned vehicle) the action is allowed so admins keep default behavior. Players holding the configured permission bypass the restriction. Everyone else who is not the owner gets a denial, a chat warning and the hook returns false so the game never hands the call to CarLock.PlayerCanDestroyLock. Messages go through the language file so they can be translated without touching code.
Common use cases
Owner-only lock removal
Block strangers from stripping locks off cars they did not place, closing a common griefing gap on PvE and mixed servers.
Permission-gated mechanic role
Allow a mechanic permission group to remove locks from any car while regular players are limited to their own vehicles.
Event or raid control
During a custom event, deny lock removal on event vehicles until the round ends, then lift the restriction by flipping a flag.
Pitfalls
viaModule can be null
Do not read members of the module without a check; some call paths pass no module, and a NullReferenceException thrown inside a hook can break the interaction.
OwnerID is zero on unowned cars
Vehicles spawned by plugins or admins often have OwnerID 0. Treat that as unowned and allow the action, otherwise nobody can ever remove the lock.
Returning false does not notify the player
The game simply cancels the action. Send a chat message yourself or the player will see nothing happen and assume it is a bug.
Build a plugin with CanDestroyLock
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 CanDestroyLock
Generate