OnRackedWeaponSwapped
OnRackedWeaponSwapped is called after a player swaps a weapon into a weapon rack slot, once the item is mounted on the rack and network updates have been sent.
void OnRackedWeaponSwapped(Item item, WeaponRackSlot weaponAtIndex, BasePlayer player, WeaponRack weaponRack)Parameters
| Parameter | Type | Description |
|---|---|---|
item | Item | The Item that was moved out of the player's inventory and mounted into the rack slot. |
weaponAtIndex | WeaponRackSlot | The WeaponRackSlot the weapon was placed into, carrying the slot index and rotation used on the rack. |
player | BasePlayer | The BasePlayer whose weapon was swapped into the rack. |
weaponRack | WeaponRack | The WeaponRack entity that received the weapon. |
Return value
Returning a value has no effect. The hook is called after the swap and network update finish, and the original method returns void, so Oxide ignores whatever your method returns and the game continues normally.
How it works
This hook fires at the end of WeaponRack.SwapPlayerWeapon. By the time it runs the Item has already been removed from its container, the previous weapon in that slot has been given back to the player, the new item has been mounted at bestPlacementCellIndex with the chosen rotation, and the rack has been network-updated. It fires only for the swap path, not for a plain load or take, so it is the right place to react to a player exchanging one racked weapon for another.
Use player and weaponRack to identify who acted and which rack changed. weaponAtIndex tells you the target slot and its rotation, useful for UI or per-slot rules. item is the weapon now on display; read item.info.shortname or a custom item.name to classify it.
Declaring player as a more specific type (for example BasePlayer) does not narrow anything here because the game always passes a real player for switches. The hook is read-only in practice: the swap is already complete and the rack already re-sent, so changes must be applied afterwards.
Example plugin: Announce and log high-tier weapon swaps on racks
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("Rack Swap Announcer", "RustPluginGenerator", "1.0.0")]
[Description("Announces and logs when players swap notable weapons onto weapon racks")]
public class RackSwapAnnouncer : RustPlugin
{
private const string PermShow = "rackswapannouncer.show";
private PluginConfig config;
private class PluginConfig
{
[JsonProperty("Weapons to report (shortnames)")]
public List<string> WatchedShortnames = new List<string> { "rifle.ak", "l96", "rifle.bolt", "lmg.m249" };
[JsonProperty("Broadcast to all players")]
public bool BroadcastToAll = true;
}
private readonly Dictionary<ulong, string> lastSwap = new Dictionary<ulong, string>();
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>
{
["Racked"] = "You placed {0} into rack slot {1}.",
["Broadcast"] = "{0} placed {1} on a weapon rack.",
["LastSwap"] = "{0} last placed {1} on a rack at {2}.",
["NoSwap"] = "No recent rack swap recorded for that player.",
["NoPermission"] = "You do not have permission to use this command."
}, 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(PermShow, this);
}
private void OnRackedWeaponSwapped(Item item, WeaponRackSlot weaponAtIndex, BasePlayer player, WeaponRack weaponRack)
{
if (item == null || item.info == null || player == null || weaponRack == null)
return;
if (!config.WatchedShortnames.Contains(item.info.shortname))
return;
int slotIndex = weaponAtIndex != null ? weaponAtIndex.InventoryIndex : -1;
player.ChatMessage(Msg("Racked", player.UserIDString, item.info.displayName.english, slotIndex));
if (config.BroadcastToAll)
Server.Broadcast(Msg("Broadcast", null, player.displayName, item.info.displayName.english));
lastSwap[player.userID] = item.info.displayName.english + " @ " + DateTime.UtcNow.ToString("HH:mm:ss") + " UTC";
}
[ChatCommand("rackswap.show")]
private void CmdShow(BasePlayer player, string command, string[] args)
{
if (player == null) return;
if (!permission.UserHasPermission(player.UserIDString, PermShow))
{
player.ChatMessage(Msg("NoPermission", player.UserIDString));
return;
}
BasePlayer target = player;
if (args != null && args.Length > 0)
{
target = BasePlayer.FindAwakeOrSleeping(args[0]);
}
if (target == null)
{
player.ChatMessage(Msg("NoSwap", player.UserIDString));
return;
}
string record;
if (!lastSwap.TryGetValue(target.userID, out record))
{
player.ChatMessage(Msg("NoSwap", player.UserIDString));
return;
}
player.ChatMessage(Msg("LastSwap", player.UserIDString, target.displayName, record, string.Empty));
}
private void Unload()
{
lastSwap.Clear();
}
}
}The plugin watches OnRackedWeaponSwapped and checks the item shortname against a configurable list of high-tier weapons such as rifle.ak or l96.
When a listed weapon is racked, it sends a message to the swapping player with the rack position, then broadcasts a short notice to all players if BroadcastToAll is enabled. A record of the last swap is stored per player and can be reviewed through the rackswap.show chat command, which requires the rackswapannouncer.show permission. Messages live in the language file so server owners can translate them, and the weapon list is editable in the config without recompiling.
Common use cases
Notify admins of stashed military weapons
Broadcast when a player racks a rifle or sniper so staff can watch for loot-stashing or trading behaviour around base racks.
Audit weapon swaps per player
Record the last swap timestamp and weapon for each player and expose it through a staff command for quick checks.
Reward display pieces
Grant a small bonus or achievement when a player mounts a specific collectible weapon on a rack.
Pitfalls
Do not try to cancel the swap
The weapon is already mounted and the rack already sent its update before the hook fires, so returning a value or modifying the item here cannot prevent it.
Verify the item is not null
Treat
itemanditem.infodefensively and checkweaponRack/playerbefore using them, since this runs from patched game code and unexpected states should not throw.Keep output cheap
Racks are swapped rarely, but avoid heavy per-swap work such as full entity scans; store lightweight data and run cleanup on timers or in Unload.
Build a plugin with OnRackedWeaponSwapped
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 OnRackedWeaponSwapped
Generate