How to Give Items to Players in a Rust Plugin (Oxide/Carbon)
To give an item in an Oxide plugin, create it with `ItemManager.CreateByName(shortname, amount, skin)` and pass it to `player.GiveItem(item)`, which places it in the inventory or drops it if there is no room. Use `MoveToContainer` when you need a specific container or slot, `GetAmount` and `Take` to remove items, and always null-check the created item.
5 min readUpdated Oct 26, 2026
To give an item in a Rust plugin, create it with ItemManager.CreateByName("shortname", amount, skin) and hand it to player.GiveItem(item). GiveItem puts the item in the player's inventory and drops it at the player if nothing fits. Everything else in this guide (taking, containers, skins, condition, safe iteration) builds on that pattern. The code works the same on Oxide and Carbon.
Item definitions and shortnames
Every item type in Rust has an ItemDefinition. You identify it by its shortname (a string such as wood, scrap, rifle.ak) or by its numeric itemid. Shortnames are what you put in configs, because they are readable and stable.
ItemManager.FindItemDefinition("rifle.ak")returns the definition or null.definition.shortname,definition.itemid,definition.displayName.english,definition.categoryanddefinition.stackabledescribe it.ItemManager.CreateByName(shortname, amount, skin)returns a newItem, or null if the shortname is unknown.ItemManager.CreateByItemID(itemId, amount, skin)does the same with a numeric id.
Shortnames can change in game updates, so treat any shortname coming from a config as untrusted input. Validate once at startup instead of on every give. See OnServerInitialized for the right place.
Giving items
GiveItem
GiveItem is the simplest option and the right default:
private bool GiveReward(BasePlayer player, string shortname, int amount)
{
if (player == null || !player.IsConnected) return false;
var item = ItemManager.CreateByName(shortname, amount);
if (item == null) return false;
if (!player.GiveItem(item))
{
// GiveItem could not store it; make sure it does not leak
item.Remove();
return false;
}
return true;
}Be careful with the failure branch. If GiveItem returns false and you have not dropped or removed the item, it exists in memory without a home. Either remove it as above or drop it deliberately (see below). If you prefer that overflow lands on the ground, skip the check and let the default behavior handle it.
MoveToContainer
Use item.MoveToContainer(container, slot) when the destination matters, for example giving armor directly into the wear container or a weapon into a specific belt slot:
var rifle = ItemManager.CreateByName("rifle.ak", 1);
if (rifle != null && !rifle.MoveToContainer(player.inventory.containerBelt, 0))
{
rifle.Remove();
}slot = -1 (the default) means any free slot in that container. The method returns a bool, so a full container is detectable. Moving into containerWear only works for items that are wearable, and the container enforces its own rules.
Which to choose
| Goal | Use |
|---|---|
| Give a reward, do not care where it lands | player.GiveItem(item) |
| Put it in belt, main or wear explicitly | item.MoveToContainer(container, slot) |
| Refuse when there is no space | Check free space first, then GiveItem |
| Place it in a storage entity | item.MoveToContainer(storage.inventory) |
Inventory containers
player.inventory is a PlayerInventory with three containers:
containerMain: the 24 backpack slots.containerBelt: the 6 hotbar slots.containerWear: clothing and armor slots.
Each is an ItemContainer with itemList (the items), capacity, IsFull() and GetSlot(int). A storage entity exposes its container through StorageContainer.inventory. When you edit a container by hand, call MarkDirty() on it so clients refresh.
Inventory full handling
Decide up front what should happen when there is no space. There are three reasonable policies:
- Drop it. Let
GiveItemdrop the item. Good for rewards that should never be lost. - Refuse. Count free slots and tell the player with a lang message. Good for paid purchases.
- Defer. Save the pending item in a data file and give it later.
A basic free-slot count for the refuse policy:
private int FreeSlots(BasePlayer player)
{
int used = player.inventory.containerMain.itemList.Count
+ player.inventory.containerBelt.itemList.Count;
int capacity = player.inventory.containerMain.capacity
+ player.inventory.containerBelt.capacity;
return capacity - used;
}This is an approximation: it ignores that an item could stack onto an existing one without needing a slot. For a hard guarantee when giving a bundle, compare the number of new stacks you need with the free slots and be conservative. Send the refusal through lang, as described in the localization guide.
Stacking
Items stack only when they share the same definition, skin, name and compatible state, and only up to definition.stackable. Giving 5000 wood creates one Item with amount = 5000; the game splits it across stacks when it enters a container. If you need to know the real stack limit, read item.info.stackable. Servers that change limits usually do so with the OnMaxStackable hook; see the stack sizes recipe.
Two practical consequences:
- A skinned or renamed item will not merge with a plain one, so a player can end up with several partial stacks.
- Do not assume
amountfits one slot when counting space.
Skins and condition
The third argument of CreateByName is the workshop skin id (a ulong, 0 for default):
var item = ItemManager.CreateByName("rifle.ak", 1, 10157);Condition applies to items that have durability:
if (item.hasCondition)
{
item.condition = item.maxCondition * 0.5f;
item.MarkDirty();
}Guard with hasCondition because items such as wood have no condition and the assignment is meaningless there. Setting item.name gives a custom display name. For skin-related plugins, see the default skins recipe.
If the item is a weapon and you want it loaded, you work with item.GetHeldEntity() and cast it to BaseProjectile. Check for null at each step, since the held entity may not exist until the item is active.
Counting and taking items
player.inventory.GetAmount(itemId) returns how many of an item the player holds across main, belt and wear. Take removes items and fills a list with what was removed:
private bool TryCharge(BasePlayer player, string shortname, int amount)
{
var def = ItemManager.FindItemDefinition(shortname);
if (def == null) return false;
if (player.inventory.GetAmount(def.itemid) < amount) return false;
player.inventory.Take(null, def.itemid, amount);
return true;
}Always check GetAmount first. The two calls happen in the same frame, so nothing can change between them. Passing a List<Item> as the first argument gives you the removed items, which is useful for refunds or logging; passing null discards them. This pattern is the basis of shops, as in the chat shop and sell items recipes.
Dropping items
To put an item in the world, use item.Drop(position, velocity):
var pos = player.transform.position + Vector3.up;
item.Drop(pos, player.eyes.HeadForward() * 2f);Drop at a position slightly above the ground so it does not spawn inside terrain. If an item should disappear instead, call item.Remove(). Do not use both on the same item. Dropped item lifetime is a separate concern covered in the despawn time recipe.
Iterating inventories safely
Looping over itemList while changing it throws an InvalidOperationException. Take a snapshot before removing or moving:
private int RemoveAll(BasePlayer player, string shortname)
{
int removed = 0;
var snapshot = new List<Item>(player.inventory.containerMain.itemList);
foreach (var item in snapshot)
{
if (item == null || item.info == null) continue;
if (item.info.shortname != shortname) continue;
removed += item.amount;
item.Remove();
}
return removed;
}Notes:
- Check
item.infofor null before readingshortname. - Read
item.amountbeforeRemove(), since the item is invalid afterward. - Iterating all three containers means repeating this for belt and wear, or building one combined list.
- Never iterate
BasePlayer.activePlayerListand kick or remove players inside the loop without copying it first.
For the full explanation of this exception, see the collection modified error page.
Complete example: /reward command
This plugin gives a configurable item to players with permission, reporting full inventories through lang messages.
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace Oxide.Plugins
{
[Info("Item Reward", "RustPluginGenerator", "1.0.0")]
[Description("Gives a configurable item to players with permission via /reward")]
public class ItemReward : RustPlugin
{
private const string PermUse = "itemreward.use";
private PluginConfig config;
private class PluginConfig
{
[JsonProperty("Item shortname")]
public string Shortname = "scrap";
[JsonProperty("Amount")]
public int Amount = 100;
[JsonProperty("Skin ID")]
public ulong Skin = 0;
}
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>
{
["NoPermission"] = "You do not have permission to use this command.",
["Received"] = "You received {0}x {1}.",
["Dropped"] = "Your inventory is full, the item was dropped at your feet.",
["BadItem"] = "The configured item is invalid."
}, 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(PermUse, this);
}
private void OnServerInitialized(bool initial)
{
if (ItemManager.FindItemDefinition(config.Shortname) == null)
PrintWarning($"Unknown item shortname in config: {config.Shortname}");
}
[ChatCommand("reward")]
private void CmdReward(BasePlayer player, string command, string[] args)
{
if (player == null) return;
if (!permission.UserHasPermission(player.UserIDString, PermUse))
{
SendReply(player, Msg("NoPermission", player.UserIDString));
return;
}
var item = ItemManager.CreateByName(config.Shortname, config.Amount, config.Skin);
if (item == null)
{
SendReply(player, Msg("BadItem", player.UserIDString));
return;
}
string name = item.info != null ? item.info.displayName.english : config.Shortname;
int amount = item.amount;
bool hadSpace = player.inventory.containerMain.itemList.Count < player.inventory.containerMain.capacity
|| player.inventory.containerBelt.itemList.Count < player.inventory.containerBelt.capacity;
player.GiveItem(item);
SendReply(player, Msg("Received", player.UserIDString, amount, name));
if (!hadSpace)
SendReply(player, Msg("Dropped", player.UserIDString));
}
}
}The plugin reads item.amount before giving, because after a stack merges the original object may no longer be valid. The permission follows the itemreward. prefix rule described in the permissions guide.
Common mistakes
- Using the display name as a shortname.
"Assault Rifle"returns null; userifle.ak. - Ignoring null from CreateByName. The next line throws a NullReferenceException, which shows up as a failed to call hook error or a failed command.
- Reading an item after Remove(). Capture needed values first.
- Giving items inside hot hooks without need. Hooks like OnPlayerInput or OnTick run constantly; keep inventory scans out of them. See the performance guide.
- Hard-coded item lists. Put shortnames in the config so owners can adjust after a game update.
For ready-made behavior built on these calls, look at the give items command, kits with cooldowns and starter kit recipes, or describe your own idea in the plugin generator.
FAQ
Why does ItemManager.CreateByName return null?
It returns null when the shortname does not match any item definition, usually because of a typo or an item that was renamed or removed in a Rust update. Check the result before using it, and validate configured shortnames once in OnServerInitialized with ItemManager.FindItemDefinition, logging one warning per bad entry.
Does GiveItem drop the item when the inventory is full?
BasePlayer.GiveItem(Item) tries to place the item in the player's inventory and drops it near the player if it cannot be stored. It returns a bool, so you can react to the result. If you want to refuse instead of dropping, check free slots yourself before creating the item.
How do I give an item with a custom name?
Set item.name after creating the item, for example item.name = "Starter Axe", then give it. The name is stored on the item instance, so it survives moving between containers. Keep in mind that items with different names or skins do not stack together.
Why do I get a collection modified error when removing items in a loop?
Calling Remove() or moving items while enumerating itemList changes the list during the foreach. Copy the list first with new List<Item>(container.itemList) and iterate the copy. The error is explained on the collection modified page.
Can I give an item to an offline player?
Not through the inventory API directly. An offline player is a sleeper entity found with BasePlayer.FindAwakeOrSleeping, and modifying sleepers is risky. A safer pattern is to store a pending reward in a data file and hand it out in OnPlayerConnected or OnPlayerSleepEnded.
More guides
Skip the C#: describe your plugin
Open generator