Skip to content
RustPluginGenerator

OnCollectiblePickedup

OnCollectiblePickedup is called when a player picks a resource from a CollectibleEntity, right before the game gives the resulting item to that player.

Signature
void OnCollectiblePickedup(CollectibleEntity collectibleEntity, BasePlayer reciever, Item item)

Parameters

Hook parameters
ParameterTypeDescription
collectibleEntityCollectibleEntityThe CollectibleEntity the player just picked from (hemp, mushroom, berry bush, pumpkin, corn and similar world spawns). Use its prefab name, position or net ID to identify the resource type.
recieverBasePlayerThe BasePlayer receiving the item. The hook fires before the item is handed over, so the item is still not in the player's inventory at this point.
itemItemThe Item instance that will be given to the player. You can read info.shortname, amount and skin, and you can modify amount or remove it before it reaches the inventory.

Return value

The return value is ignored. The game continues and always calls reciever.GiveItem with the item after the hook fires, so you cannot cancel a pickup by returning anything. To change what the player receives, mutate the item argument (amount, skin) instead.

How it works

The hook fires inside CollectibleEntity.DoPickup, after the game has built the item for the pickup and after it decides that a receiver exists, but before GiveItem is invoked. Only world collectibles use this path (hemp, mushrooms, berries, pumpkins, corn, seeds and similar), not ore nodes, trees or corpse loot. collectibleEntity identifies the source, reciever is the player and item is what is about to be handed over, so item.amount and item.skin can be changed here and the inventory receives the modified version.

Declaring reciever as BasePlayer is already the most specific useful type and does not narrow anything meaningful, since the game only calls this hook when a receiver exists; the drop branch without a receiver calls a different path. Because the hook runs on every pick, keep the body cheap: check shortnames against a small set rather than iterating the whole entity list, and avoid Puts or PrintWarning here. Cancelling is not possible: the hook's return value is ignored, so you influence the outcome only through the item object.

Example plugin: Bonus yield for hemp and berry pickups

CollectibleBonusYield.cs
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;

namespace Oxide.Plugins
{
    [Info("Collectible Bonus Yield", "RustPluginGenerator", "1.0.0")]
    [Description("Gives permissioned players extra yield from collectible pickups like hemp and berries.")]
    public class CollectibleBonusYield : RustPlugin
    {
        private const string PermBonus = "collectiblebonusyield.bonus";

        private PluginConfig config;

        public class PluginConfig
        {
            [JsonProperty("Bonus multiplier")]
            public float Multiplier = 2f;

            [JsonProperty("Extra amount per collectible (optional override)")]
            public int FlatBonus = 0;

            [JsonProperty("Report bonus in chat")]
            public bool NotifyPlayer = true;

            [JsonProperty("Affected shortnames")]
            public List<string> Shortnames = new List<string> { "hemp", "corn", "pumpkin", "clone.berry.blue", "clone.berry.green", "clone.berry.red", "clone.berry.white" };
        }

        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>
            {
                ["Bonus"] = "Bonus yield: +{0}x {1}"
            }, 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(PermBonus, this);
        }

        private void OnCollectiblePickedup(CollectibleEntity collectibleEntity, BasePlayer reciever, Item item)
        {
            if (collectibleEntity == null || reciever == null || item == null || item.info == null) return;
            if (!permission.UserHasPermission(reciever.UserIDString, PermBonus)) return;
            if (!config.Shortnames.Contains(item.info.shortname)) return;

            int original = item.amount;
            int extra = config.FlatBonus > 0 ? config.FlatBonus : (int)Math.Round(original * (config.Multiplier - 1f));
            if (extra <= 0) return;

            item.amount = original + extra;
            if (config.NotifyPlayer)
                reciever.ChatMessage(Msg("Bonus", reciever.UserIDString, extra, item.info.displayName.english));
        }
    }
}

The plugin keeps a config table mapping collectible shortnames (hemp, berry bushes, corn, pumpkin) to an extra amount. In OnCollectiblePickedup it checks the source prefab name, looks up the shortname in the config, and if a bonus is configured it multiplies the item's amount before the game gives it to the player. Players with the permission collectiblebonusyield.bonus get the extra yield; everyone else receives the normal stack. A chat message tells the player how many extra items they gained, sent through the language file so it can be translated. Since the hook fires before GiveItem, the increased amount ends up in the inventory directly rather than being dropped on the ground.

Common use cases

  • Server-wide harvest rate

    Multiply item.amount for selected collectibles to double or triple the gathering rate on a farming-focused server, without touching ore dispensers or trees.

  • VIP bonus pickups

    Check permission.UserHasPermission(reciever.UserIDString, ...) inside the hook and raise the amount only for permitted players.

  • Resource tracking

    Read collectibleEntity.ShortPrefabName and item.info.shortname to accumulate per-player statistics or feed a quest/economy plugin without changing the item.

Pitfalls

  • This is not OnCollectiblePickup

    Oxide also exposes a OnCollectiblePickup hook with a different signature. Use the one whose parameters match your intent; declaring the wrong set means the method is never called for this pickup.

  • Null check the item and entity

    collectibleEntity, reciever and item are normally set, but item.info can still be a surprise if the entity was replaced; guard item.info before reading shortname to avoid exceptions during pickups.

  • Not for ore, trees or loot

    Mining nodes, chopping trees and looting containers do not reach this hook. Use OnDispenserBonus/OnDispenserGather for ore and OnGrowableGather for planted crops instead.

Build a plugin with OnCollectiblePickedup

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

Prompt: Server-wide harvest rate using the OnCollectiblePickedup 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 OnCollectiblePickedup

Generate