Skip to content
RustPluginGenerator

OnRandomItemAward

OnRandomItemAward is called from RandomItemDispenser.TryAward before the game rolls the chance for a single item entry. Returning a non-null value cancels that roll and makes TryAward return false.

Signature
object OnRandomItemAward(RandomItemDispenser randomItemDispenser, RandomItemDispenser.RandomItemChance itemChance, BasePlayer forPlayer, Vector3 distributorPosition)

Parameters

Hook parameters
ParameterTypeDescription
randomItemDispenserRandomItemDispenserThe RandomItemDispenser entity (for example a food box or other dispenser) that is trying to hand out an item. Useful for its position, net ID and owner checks.
itemChanceRandomItemDispenser.RandomItemChanceThe RandomItemDispenser.RandomItemChance entry about to be rolled. It carries the item definition/shortname and the Chance value the game compares against a random float.
forPlayerBasePlayerThe BasePlayer who triggered the award, usually the one pressing use on the dispenser. Can be null in edge cases, so guard it before reading user IDs or permissions.
distributorPositionVector3World position of the dispenser, already resolved by the caller. Handy for distance checks or effects without touching the entity transform.

Return value

Returning null keeps default behavior: the random roll runs and the item may be awarded. Returning any non-null value stops the code path for that entry and TryAward returns false, so that item is skipped for this call.

How it works

The hook fires inside RandomItemDispenser.TryAward, once for each candidate entry the dispenser evaluates when a player uses it. The game passes the dispenser entity, the specific RandomItemChance entry about to be tested, the triggering player and the dispenser's world position. Because it is called per entry before the random float is generated, it is the right place to veto individual item types rather than the whole dispenser.

Each parameter is useful on its own: itemChance tells you which item is being considered (its shortname and configured chance), forPlayer lets you apply permission or team rules, and distributorPosition supports distance or zone checks. Declaring forPlayer as a more specific type is not useful here since it is already BasePlayer, but you can still null-check it before reading UserIDString.

This hook fires on every use of a random dispenser and can be called several times per interaction, so keep the body cheap and never print to console inside it. Return null to let the normal chance roll proceed.

Example plugin: Restrict random dispenser items by permission

RandomDispenserPermissions.cs
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("Random Dispenser Permissions", "RustPluginGenerator", "1.0.0")]
    [Description("Restricts specific random dispenser items behind permissions.")]
    public class RandomDispenserPermissions : RustPlugin
    {
        private const string PermBypass = "randomdispenserpermissions.bypass";

        private PluginConfig config;

        private class PluginConfig
        {
            [JsonProperty("Item shortname to permission")]
            public Dictionary<string, string> ItemPermissions = new Dictionary<string, string>
            {
                ["rifle.ak"] = "randomdispenserpermissions.ak",
                ["explosive.timed"] = "randomdispenserpermissions.c4"
            };
        }

        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);

        private void Init()
        {
            permission.RegisterPermission(PermBypass, this);
            if (config == null) return;
            foreach (var perm in config.ItemPermissions.Values)
            {
                if (!string.IsNullOrEmpty(perm)) permission.RegisterPermission(perm, this);
            }
        }

        private object OnRandomItemAward(RandomItemDispenser randomItemDispenser, RandomItemDispenser.RandomItemChance itemChance, BasePlayer forPlayer, Vector3 distributorPosition)
        {
            if (itemChance.Item == null || config == null || config.ItemPermissions == null) return null;
            if (forPlayer == null || !forPlayer.IsConnected) return null;

            var definition = itemChance.Item;
            if (string.IsNullOrEmpty(definition.shortname)) return null;

            string requiredPerm;
            if (!config.ItemPermissions.TryGetValue(definition.shortname, out requiredPerm) || string.IsNullOrEmpty(requiredPerm))
                return null;

            if (forPlayer.IsAdmin || permission.UserHasPermission(forPlayer.UserIDString, PermBypass))
                return null;

            if (!permission.UserHasPermission(forPlayer.UserIDString, requiredPerm))
                return false;

            return null;
        }
    }
}

The plugin reads a config map of item shortnames to permission names. When OnRandomItemAward fires, it checks the entry's shortname against the map and, if a permission is configured, verifies the player has it. If the player is not an admin and lacks randomdispenserpermissions.bypass and the required permission, the hook returns false, so that item is skipped for the roll. Players with the permission, unconfigured items, a disconnected player and admin/bypass holders fall through with null. The bypass permission is registered in Init along with every configured item permission, and the config is loaded and saved through the standard Oxide pattern so admins can edit item-to-permission pairs on disk.

Common use cases

  • VIP-only loot

    Limit premium items inside random dispensers to players holding a VIP permission while letting everyone else roll the common entries.

  • Zone-based restrictions

    Veto certain items when distributorPosition falls inside a PvP zone or monument area, keeping high-tier loot out of contested spots.

  • Event balancing

    Temporarily block specific entries during a server event by toggling flags in the plugin, without editing the map's dispenser configuration.

Pitfalls

  • Called many times per interaction

    TryAward runs once per candidate entry, so a single use can trigger the hook several times. Avoid heavy lookups, LINQ allocations or logging in the body.

  • Vetoing cancels only one entry

    Returning a value makes TryAward return false for that entry, not for the whole dispenser. Other entries are still evaluated and may be awarded.

  • Null player on some paths

    Do not assume forPlayer is connected or non-null. Guard it and treat a null player as a denial or an allow deliberately, depending on your policy.

Build a plugin with OnRandomItemAward

Describe what should happen and get a compiled plugin that uses this hook.

Prompt: VIP-only loot using the OnRandomItemAward hook, with a config file and a permission
Generate this plugin

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 OnRandomItemAward

Generate