CanMannequinSwap
CanMannequinSwap is called when a player requests to swap the clothing/equipment on a Mannequin, before the game checks its lock and opens the mannequin's loot. Returning a non-null value cancels the swap.
object CanMannequinSwap(Mannequin mannequin, BasePlayer player)Parameters
| Parameter | Type | Description |
|---|---|---|
mannequin | Mannequin | The Mannequin entity the player is trying to change the outfit on. Use it to read the owner (OwnerID), position, inventory or flags. |
player | BasePlayer | The BasePlayer who sent the swap request. Check permissions, team membership or distance against the mannequin here. |
Return value
Return null to let the request proceed to the mannequin's lock check and normal swap logic. Return any non-null value (for example false or a string) to stop the request immediately; the original method returns without swapping or opening loot, and the return value itself is not used for anything else.
How it works
The hook fires inside Mannequin.Server_RequestSwap, which runs server side when a player sends a swap request for a mannequin they are interacting with. It runs after the equipping guard and after the game's own CanBeLooted(player) and IsDead() checks, but before the mannequin's lock is validated and before the loot UI would open. Returning anything non-null aborts the request, so the player stays where they are with no swap.
Use player to evaluate permissions, team membership, distance to the mannequin, or combat state, and mannequin to read OwnerID, transform.position, or installed items. Because the parameters are already exact game types there is no practical narrowing to do; both arguments are always provided. Restrict frequent work here since a swap request is cheap to spam, and avoid printing inside the hook. The canceled action leaves the lock check untouched, so this is a good place for custom ownership rules on mannequins.
Example plugin: Lock mannequin swaps to the owner or their team
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Mannequin Owner Lock", "RustPluginGenerator", "1.0.0")]
[Description("Restricts mannequin outfit swaps to the owner or their team members.")]
public class MannequinOwnerLock : RustPlugin
{
private const string PermAdmin = "mannequinownerlock.admin";
private const string PermBypass = "mannequinownerlock.bypass";
private PluginConfig config;
private readonly Dictionary<ulong, float> lastWarning = new Dictionary<ulong, float>();
private class PluginConfig
{
[JsonProperty("Only owner and teammates can swap")]
public bool OwnerAndTeamOnly { get; set; } = true;
[JsonProperty("Chat warning cooldown in seconds")]
public float WarningCooldown { get; set; } = 5f;
}
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>
{
["NotAllowed"] = "This mannequin belongs to {0}. Only the owner or their team can change it.",
["Denied"] = "You are not allowed to change this mannequin."
}, 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);
permission.RegisterPermission(PermBypass, this);
}
private object CanMannequinSwap(Mannequin mannequin, BasePlayer player)
{
if (mannequin == null || player == null || !config.OwnerAndTeamOnly)
return null;
if (player.IsAdmin || permission.UserHasPermission(player.UserIDString, PermBypass))
return null;
ulong ownerId = mannequin.OwnerID;
if (ownerId == 0UL || ownerId == player.userID)
return null;
if (SharesTeam(player, ownerId))
return null;
Warn(player, ownerId);
return false;
}
private bool SharesTeam(BasePlayer player, ulong ownerId)
{
if (player.currentTeam == 0UL)
return false;
RelationshipManager.PlayerTeam team = RelationshipManager.ServerInstance.FindTeam(player.currentTeam);
if (team == null)
return false;
return team.members.Contains(ownerId);
}
private void Warn(BasePlayer player, ulong ownerId)
{
float now = UnityEngine.Time.realtimeSinceStartup;
float next;
if (lastWarning.TryGetValue(player.userID, out next) && now < next)
return;
lastWarning[player.userID] = now + Mathf.Max(1f, config.WarningCooldown);
BasePlayer owner = BasePlayer.FindByID(ownerId);
string ownerName = owner != null ? owner.displayName : "another player";
player.ChatMessage(Msg("NotAllowed", player.UserIDString, ownerName));
}
private void Unload()
{
lastWarning.Clear();
}
}
}The plugin blocks swaps on mannequins by anyone who is not the mannequin's owner or a teammate of the owner. CanMannequinSwap compares mannequin.OwnerID with player.userID; on a mismatch it resolves both players' teams through RelationshipManager.ServerInstance.FindTeam and only allows the swap when both share a non-zero team ID. Admins are exempt, and a config flag lets a server turn the whole check off. Denied players get a localized chat message with the mannequin owner's name and a throttled warning variable keeps chat spam down. Returning false cancels the request before the lock and loot logic run, so nothing is swapped and no UI opens.
Common use cases
Owner and team restrictions
Allow only the mannequin owner or their teammates to re-dress it, keeping public display mannequins protected on roleplay servers.
Raid protection during combat
Cancel swaps while the requesting player has recently taken damage or is building blocked, so raiders cannot strip gear from mannequins mid-fight.
Distance and permission gating
Require a permission node and a minimum distance check against the mannequin position to stop remote or scripted swap attempts.
Pitfalls
Not the loot gate
This hook covers swap requests only; the mannequin's storage container is opened through the loot path, so blocking here does not stop all interaction with the mannequin.
Returning false vs true
The method is void and the result is only checked for non-null, so both
trueandfalsecancel the request. Returning a boolean can mislead readers into thinking one value allows the swap; usenullfor allow.OwnerID of zero
Mannequins placed by the server or map can have an OwnerID of 0. Your ownership logic has to decide whether that means public access or a hard block, otherwise those mannequins become freely editable.
Build a plugin with CanMannequinSwap
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 CanMannequinSwap
Generate