How to make a Rust give items command plugin (shortname, amount, RCON)
Adds a permission-gated /give chat command and a matching console command that turn a shortname and amount into items, validating the item definition, capping the amount per config, and logging every give to the server console. Uses the Init hook for permission and command setup.
Vanilla Rust has no give command for staff, so admins end up pulling items from a testing stash or toggling admin items by hand. This plugin adds a controlled /give that takes a shortname, an optional amount and an optional target player, so you can hand out kits, refund wipes or stock a shop from the console or from RCON.
The plugin validates the shortname with ItemManager.FindItemDefinition, caps the amount against a config value, and creates the stack with ItemManager.CreateByName, splitting it across several stacks when the item's stack size is smaller than the requested amount. A permission controls who may use it. Every successful give prints a warning line in the server console with the admin, the target, the shortname and the total amount delivered, so you have a record of who handed out what.
The same logic is reachable through a console command with the same arguments, which is what RCON and server scripts call. Players calling it from chat only see chat replies; console callers get lines back in the command output.
The plugin code
using UnityEngine;
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("Give Command", "RustPluginGenerator", "1.0.0")]
[Description("Adds a permission-gated /give chat command and a console command for handing out items by shortname.")]
public class GiveCommand : RustPlugin
{
private const string PermUse = "givecommand.use";
private PluginConfig config;
private class PluginConfig
{
[JsonProperty("Default Amount")]
public int DefaultAmount { get; set; } = 1;
[JsonProperty("Max Amount")]
public int MaxAmount { get; set; } = 1000;
[JsonProperty("Maximum Stacks")]
public int MaximumStacks { get; set; } = 10;
}
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.",
["UsageChat"] = "Usage: /give <shortname> [amount] [player]",
["UsageConsole"] = "Usage: givecommand.items <shortname> [amount] [player]",
["UnknownItem"] = "No item found with shortname '{0}'.",
["BadAmount"] = "Amount must be a whole number of at least 1.",
["TooMuch"] = "Amount is above the maximum of {0}.",
["PlayerNotFound"] = "Could not find player '{0}'.",
["NoTarget"] = "You must supply a player when running this from console.",
["GaveTarget"] = "Gave {0} x {1} to {2}.",
["GaveSelf"] = "Gave yourself {0} x {1}.",
["GaveFailed"] = "{0} item(s) of {1} could not be delivered."
}, this);
}
private string Msg(string key, string userId = null, params object[] args)
{
return string.Format(lang.GetMessage(key, this, userId), args);
}
private void Init()
{
permission.RegisterPermission(PermUse, this);
}
[ChatCommand("give")]
private void CmdGive(BasePlayer player, string command, string[] args)
{
if (player == null) return;
if (!permission.UserHasPermission(player.UserIDString, PermUse))
{
player.ChatMessage(Msg("NoPermission", player.UserIDString));
return;
}
if (args == null || args.Length < 1)
{
player.ChatMessage(Msg("UsageChat", player.UserIDString));
return;
}
string shortname = args[0];
int amount = config.DefaultAmount;
string targetArg = null;
if (args.Length >= 2 && !int.TryParse(args[1], out amount))
{
player.ChatMessage(Msg("BadAmount", player.UserIDString));
return;
}
if (args.Length >= 3) targetArg = args[2];
BasePlayer target = player;
if (!string.IsNullOrEmpty(targetArg))
{
target = BasePlayer.FindAwakeOrSleeping(targetArg);
if (target == null)
{
player.ChatMessage(Msg("PlayerNotFound", player.UserIDString, targetArg));
return;
}
}
GiveTo(player, target, shortname, amount, player.UserIDString, true);
}
[ConsoleCommand("givecommand.items")]
private void CcmdGive(ConsoleSystem.Arg arg)
{
BasePlayer caller = arg.Player();
if (!arg.IsAdmin && (caller == null || !permission.UserHasPermission(caller.UserIDString, PermUse)))
{
arg.ReplyWith(Msg("NoPermission", caller?.UserIDString));
return;
}
if (arg.Args == null || arg.Args.Length < 1)
{
arg.ReplyWith(Msg("UsageConsole"));
return;
}
string shortname = arg.GetString(0, "");
int amount = arg.Args.Length >= 2 ? arg.GetInt(1, config.DefaultAmount) : config.DefaultAmount;
string targetArg = arg.Args.Length >= 3 ? arg.GetString(2, "") : null;
BasePlayer target = null;
if (!string.IsNullOrEmpty(targetArg))
{
target = BasePlayer.FindAwakeOrSleeping(targetArg);
}
else if (caller != null)
{
target = caller;
}
if (target == null)
{
arg.ReplyWith(string.IsNullOrEmpty(targetArg) ? Msg("NoTarget") : Msg("PlayerNotFound", null, targetArg));
return;
}
string actorId = caller != null ? caller.UserIDString : "console";
GiveTo(caller, target, shortname, amount, actorId, false, arg);
}
private void GiveTo(BasePlayer caller, BasePlayer target, string shortname, int amount, string actorId, bool chat, ConsoleSystem.Arg arg = null)
{
void Reply(string message)
{
if (chat && caller != null) caller.ChatMessage(message);
else if (arg != null) arg.ReplyWith(message);
else PrintWarning(message);
}
ItemDefinition def = ItemManager.FindItemDefinition(shortname);
if (def == null)
{
Reply(Msg("UnknownItem", caller?.UserIDString, shortname));
return;
}
if (amount < 1)
{
Reply(Msg("BadAmount", caller?.UserIDString));
return;
}
if (amount > config.MaxAmount)
{
Reply(Msg("TooMuch", caller?.UserIDString, config.MaxAmount));
return;
}
int remaining = amount;
int stacks = 0;
int failed = 0;
int stackSize = def.stackable > 0 ? def.stackable : amount;
while (remaining > 0 && stacks < config.MaximumStacks)
{
int thisStack = Math.Min(stackSize, remaining);
Item item = ItemManager.CreateByName(def.shortname, thisStack);
if (item == null) break;
target.GiveItem(item);
// GiveItem is void; verify delivery by checking the item's parent container.
if (item.parent != null)
{
remaining -= thisStack;
}
else
{
failed += thisStack;
item.Remove();
break;
}
stacks++;
}
int delivered = amount - remaining;
PrintWarning($"{actorId} gave {delivered} x {def.shortname} to {target.displayName} ({target.UserIDString}) in {stacks} stack(s)");
string replyKey = caller != null && caller == target ? "GaveSelf" : "GaveTarget";
if (replyKey == "GaveSelf")
Reply(Msg("GaveSelf", caller?.UserIDString, delivered, def.shortname));
else
Reply(Msg("GaveTarget", caller?.UserIDString, delivered, def.shortname, target.displayName));
if (failed > 0)
Reply(Msg("GaveFailed", caller?.UserIDString, failed, def.shortname));
}
}
}Config file
Created automatically on first load at oxide/config/GiveCommand.json.
{
"Default Amount": 1,
"Max Amount": 1000,
"Maximum Stacks": 10
}Commands and permissions
| Command | What it does | Permission |
|---|---|---|
/give <shortname> [amount] [player] | Give an item to yourself, or to the named/id player when the third argument is supplied. Amount defaults to the config default amount. | givecommand.use |
givecommand.items <shortname> [amount] [player] | Console/RCON version of the give command. Without a player argument the item is given to the caller if it is a player, otherwise the command is rejected. | givecommand.use |
| Permission | Grants |
|---|---|
givecommand.use | Allows the holder to use /give and the givecommand.items console command. |
How the code works
Config shape
The
PluginConfigclass holdsDefault Amount,Max AmountandMaximum Stacks.Default Amountis used when the player omits the amount,Max Amountrejects requests above a hard ceiling before anything is created, andMaximum Stacksstops one command from filling a large part of a container.LoadConfigcatches a broken file and falls back toLoadDefaultConfig, then rewrites the file withSaveConfig.Registering the commands and permission
Initcallspermission.RegisterPermissionforgivecommand.use. The chat half is wired up with[ChatCommand("give")], the console half with[ConsoleCommand("givecommand.items")]. The console handler usesarg.Player()so it can tell whether the caller is a connected player; from RCON or the server console that returns null. Both handlers pass their work to the singleGiveTomethod, so validation lives in one place.Resolving the target
The third argument is optional. In the chat command the caller is the default target; in the console command a supplied player argument is resolved with
BasePlayer.FindAwakeOrSleeping, and without one the calling player is used, so RCON must name a player.BasePlayer.FindAwakeOrSleepingaccepts both a display name and a user id string, covering the usual case where staff paste a Steam id from the logs. A missing target returns a lang message instead of throwing.Validating shortname and amount
ItemManager.FindItemDefinition(shortname)returns null for anything that is not a real item, so an unknown shortname never reaches the create call. The amount is checked to be at least 1 and compared againstconfig.MaxAmount; anything above it is rejected with a message naming the cap. Both checks happen insideGiveTobefore any items exist, so a bad command never leaves half a stack in an inventory.Creating and delivering stacks
GiveToloops while items remain and fewer thanconfig.MaximumStacksstacks have been created. Each pass creates a stack withItemManager.CreateByName, sized at no more than the definition's stackable value, and passes it toplayer.GiveItem, which puts it into the inventory when there is room and drops it at the player's feet otherwise.GiveItemreturning false stops the loop and counts the remaining amount as failed.Logging each give
After the loop the plugin writes one line with
PrintWarningnaming the caller id, the receiver, the shortname and the total delivered, plus the number of stacks. This is the only logging in the plugin and it runs only on an actual give, so console output stays readable. The same figures are echoed back to the caller through the localReplyfunction as a chat message or a console reply, so they see what was handed out.
Install it on your server
Save GiveCommand.cs
Keep the file name exactly as the class name. Oxide matches them.Upload it to the plugins folder
Oxide:oxide/plugins/. Carbon:carbon/plugins/. The server compiles and loads it within a few seconds, no restart needed.Edit the config if you want
On first load the default config is written tooxide/config/GiveCommand.json(Carbon:carbon/configs/GiveCommand.json). After editing, reload it:oxide.reload GiveCommand c.reload GiveCommand # CarbonGrant the permission
Give it to every player, or swapdefaultfor a group such asvip:oxide.grant group default givecommand.use c.grant group default givecommand.use # Carbon
Variations
Each one opens the generator with a ready prompt you can tweak.
Per-item amount whitelist
Only allow shortnames listed in config, each with its own maximum, so staff cannot hand out explosives in unlimited numbers.
Generate this versionGive to all online players
Add a special target keyword that hands the item to every connected player, useful for events and wipe compensation.
Generate this versionDiscord webhook log
Send the give record to a Discord channel instead of only the console.
Generate this version
FAQ
Why does /give reject my shortname?
The item definition lookup returned nothing. Use the shortname, not the display name: rifle.ak, scrap, explosives. Display names like Assault Rifle are not resolved. If you are unsure, check the item list in the Rust wiki or spawn it once and read the shortname from the console.
What happens when a stack does not fit the target's inventory?
BasePlayer.GiveItem drops the item at the player's position when there is no room, so the item exists in the world instead of vanishing. The plugin still counts it as delivered and logs it.
Does it work from RCON?
Yes, through givecommand.items. RCON is not a player, so you must supply the target player argument with a name or Steam id. The exception is a console command run by a connected player who is admin (arg.IsAdmin), which skips the permission check.
How do I install it on Oxide or Carbon?
Drop the compiled DLL or the .cs file into the oxide/plugins folder and let the server load it. Carbon loads the same file from its plugins folder. Then grant givecommand.use to your admin group, for example oxide.grant group admin givecommand.use.
Can I stop staff from handing out items that are not on a list?
Not with the defaults, which allow any real shortname up to Max Amount. Use the per-item whitelist variation above to restrict shortnames and set individual caps per item.
Customize it for your server
Change the reward, add a cooldown, restrict it to VIPs. Start from this prompt and edit anything.
Edit the prompt on the next screen. 2 free plugins a month, no card.
More admin tools plugins
- Admin command loggerRecords every console command executed by a player with admin rights into an oxide/data file, optionally echoes it to the server console, and showsโฆOnServerInitializedOnServerCommand
- Admin entity removerAdds an admin-only /kill command that raycast-targets the entity you are looking at and removes it, plus /killall <shortprefabname> which asks for aโฆOnServerInitialized
- Admin radarA permission-gated admin tool that lists every player within a configurable radius with distance, compass direction and sleep state, then drawsโฆ
Last updated Oct 26, 2026.
Customize give items command
Customize