OnDispenserBonus
OnDispenserBonus is called during ResourceDispenser.AssignFinishBonus, right after the game creates the bonus item for a player who finished a resource node. Return a different Item to substitute the reward, or return null to keep it.
object OnDispenserBonus(ResourceDispenser resourceDispenser, BasePlayer player, Item item)Parameters
| Parameter | Type | Description |
|---|---|---|
resourceDispenser | ResourceDispenser | The ResourceDispenser entity (tree, ore node, animal carcass, etc.) that awarded the bonus. Useful for reading its position, prefab name, or owner. |
player | BasePlayer | The BasePlayer whose gather bonus is being applied. This is the player who hit the resource last and receives the finish bonus item. |
item | Item | The freshly created Item holding the scaled bonus amount. Replace it by returning a different Item instance; the game then applies ownership to whatever item is current. |
Return value
Return null to let the game keep the Item it already created. Return a different Item instance and the game replaces the working item with yours before ApplyItemOwnership runs, so your item gets the correct owner. Any other return type is ignored.
How it works
This hook fires inside ResourceDispenser.AssignFinishBonus, the method that hands out the extra resource item when a player depletes a resource node (tree, ore, carcass). By this point the game has already computed the base finish bonus, applied the gather bonus from held items, scaled the amount and created an Item via ItemManager.Create.
Parameters:
resourceDispenseris the node being depleted. It carries the prefab, position and any owner ID you might want to inspect.playeris the receiver of the bonus. It is the player whose gather bonus scaled the amount, so it can be null in unusual flows but is normally set.itemis the created item and its final amount. Readitem.info.shortnameanditem.amountto see what is being granted.
The hook fires once per completed resource node, so it is a low-frequency place to add multipliers, event rewards or logging. Returning a non-null Item replaces the game's item before ownership is applied, which is why you can safely build a brand-new Item (or re-use the passed one after changing amount).
There is no way to cancel the award from this hook; to block or alter gather amounts use OnDispenserGather. Declaring BasePlayer for the second parameter is the exact type already, so no narrowing is needed.
Example plugin: Double finish bonus during a server event
using System.Collections.Generic;
using System;
using Newtonsoft.Json;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("Dispenser Bonus Booster", "RustPluginGenerator", "1.0.0")]
[Description("Multiplies the finish bonus awarded when a player depletes a resource node during a timed event.")]
public class DispenserBonusBooster : RustPlugin
{
private const string PermBoost = "dispenserbonusbooster.boost";
private PluginConfig config;
private bool boostActive;
private Timer boostTimer;
private class PluginConfig
{
[JsonProperty("Bonus multiplier")]
public float Multiplier { get; set; } = 2f;
[JsonProperty("Event duration (seconds)")]
public float Duration { get; set; } = 60f;
}
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 System.Collections.Generic.Dictionary<string, string>
{
["NoPerm"] = "You do not have permission to start the bonus event.",
["Started"] = "Resource finish bonus is now x{0} for {1} seconds.",
["Ended"] = "Resource finish bonus event has ended."
}, 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(PermBoost, this);
}
[ChatCommand("bonusboost")]
private void CmdBoost(BasePlayer player, string command, string[] args)
{
if (player == null) return;
if (!permission.UserHasPermission(player.UserIDString, PermBoost))
{
SendReply(player, Msg("NoPerm", player.UserIDString));
return;
}
if (boostTimer != null) boostTimer.Destroy();
boostActive = true;
Server.Broadcast(Msg("Started", null, config.Multiplier, config.Duration));
boostTimer = timer.Once(config.Duration, () =>
{
boostActive = false;
boostTimer = null;
Server.Broadcast(Msg("Ended"));
});
}
private object OnDispenserBonus(ResourceDispenser resourceDispenser, BasePlayer player, Item item)
{
if (!boostActive || item == null || item.info == null) return null;
if (player == null || player.IsNpc) return null;
int boosted = (int)Math.Ceiling(item.amount * config.Multiplier);
if (boosted <= item.amount) return null;
Item replacement = ItemManager.Create(item.info, boosted, item.skin);
if (replacement == null) return null;
return replacement;
}
private void Unload()
{
if (boostTimer != null)
{
boostTimer.Destroy();
boostTimer = null;
}
boostActive = false;
}
}
}The plugin tracks an active bonus window. OnDispenserBonus fires once per depleted resource node; while the window is open it reads the item's amount, doubles it, and returns a fresh Item created with the new amount so the player receives the boosted stack. The returned item is the one ownership is applied to, so no duplication happens. A small chat command starts a one-minute boost, a timer clears the flag, and the timer is destroyed in Unload. The config exposes the multiplier and event duration.
Common use cases
Weekend double-resource events
Return an item with a scaled amount when a scheduled event flag is active, giving players a visible gather reward without touching base gather rates.
Rare bonus drops from depleted nodes
Swap the returned item for a rarer resource (or a separate item) based on the dispenser prefab, effectively turning node depletion into a loot table.
Per-team bonus tracking
Read
player.currentTeamto determine whether to multiply the amount, giving organised groups an incentive to deplete nodes together.
Pitfalls
Returning the passed item is not required
Returning the same instance you were given works but is pointless; just return null unless you actually want to change the item. Returning something of a different type (e.g. a string) is silently ignored.
This is not the gather hook
OnDispenserBonus fires once at node completion, not on every hit. If you want per-hit scaling or cancellation, use OnDispenserGather instead.
Destroying the item breaks the flow
If you call
item.Remove()before returning null the game will still callApplyItemOwnershipon a removed item. Return a replacement item or leave the original alone.
Plugin recipes that use OnDispenserBonus
- How to make a Rust auto smelt on gather plugin (ore to fragments)Converts gathered metal ore into metal fragments, sulfur ore into sulfur and optionally wood into charcoal for players with a permission, using OnDispenserGather and OnDispenserBonus.
- How to make a Rust gather rate plugin (per-resource multipliers)Scales resources from trees, ore nodes, corpses and world pickups with per-resource multipliers and a VIP bonus. Uses OnDispenserGather, OnDispenserBonus and OnCollectiblePickup.
Build a plugin with OnDispenserBonus
Describe what should happen and get a compiled plugin that uses this hook.
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 OnDispenserBonus
Generate