Skip to content
RustPluginGenerator

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

GiveCommand.cs
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.

GiveCommand.json
{
  "Default Amount": 1,
  "Max Amount": 1000,
  "Maximum Stacks": 10
}

Commands and permissions

Chat and console commands
CommandWhat it doesPermission
/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
Permissions
PermissionGrants
givecommand.useAllows the holder to use /give and the givecommand.items console command.

How the code works

  1. Config shape

    The PluginConfig class holds Default Amount, Max Amount and Maximum Stacks. Default Amount is used when the player omits the amount, Max Amount rejects requests above a hard ceiling before anything is created, and Maximum Stacks stops one command from filling a large part of a container. LoadConfig catches a broken file and falls back to LoadDefaultConfig, then rewrites the file with SaveConfig.

  2. Registering the commands and permission

    Init calls permission.RegisterPermission for givecommand.use. The chat half is wired up with [ChatCommand("give")], the console half with [ConsoleCommand("givecommand.items")]. The console handler uses arg.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 single GiveTo method, so validation lives in one place.

  3. 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.FindAwakeOrSleeping accepts 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.

  4. 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 against config.MaxAmount; anything above it is rejected with a message naming the cap. Both checks happen inside GiveTo before any items exist, so a bad command never leaves half a stack in an inventory.

  5. Creating and delivering stacks

    GiveTo loops while items remain and fewer than config.MaximumStacks stacks have been created. Each pass creates a stack with ItemManager.CreateByName, sized at no more than the definition's stackable value, and passes it to player.GiveItem, which puts it into the inventory when there is room and drops it at the player's feet otherwise. GiveItem returning false stops the loop and counts the remaining amount as failed.

  6. Logging each give

    After the loop the plugin writes one line with PrintWarning naming 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 local Reply function as a chat message or a console reply, so they see what was handed out.

Install it on your server

  1. Save GiveCommand.cs

    Keep the file name exactly as the class name. Oxide matches them.
  2. 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.
  3. Edit the config if you want

    On first load the default config is written to oxide/config/GiveCommand.json (Carbon: carbon/configs/GiveCommand.json). After editing, reload it:oxide.reload GiveCommand c.reload GiveCommand # Carbon
  4. Grant the permission

    Give it to every player, or swap default for a group such as vip: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 version
  • Give 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 version
  • Discord 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.

Prompt: Create a Rust Oxide plugin named GiveCommand with a permission-gated /give chat command and a givecommand.items console command; config has Default Amount 1, Max Amount 1000, Maximum Stacks 10, and every give is logged with PrintWarning.
Customize for my server

Edit the prompt on the next screen. 2 free plugins a month, no card.

Last updated Oct 26, 2026.

Customize give items command

Customize