OnItemUse
OnItemUse is called from Item.UseItem just before the consumed amount is subtracted from the stack, and an int return value replaces how many units are consumed.
object OnItemUse(Item item, int amountToConsume)Parameters
| Parameter | Type | Description |
|---|---|---|
item | Item | The Item instance whose UseItem method is running, i.e. the stack being consumed. Use item.info.shortname or item.info.itemid to identify it and item.amount for the current stack size. |
amountToConsume | int | How many units of the stack the game is about to subtract. Return a different int to replace this value; the remaining amount is subtracted from item.amount right after the hook. |
Return value
Returning null (or anything that is not an int) leaves the game's own amountToConsume untouched. Returning an int replaces the value the game subtracts from item.amount; the original code path continues either way, so this hook cannot block the use, only change the quantity.
How it works
The hook fires inside Item.UseItem(int amountToConsume), the method the game runs when an item stack is consumed (for example a held consumable or a resource spent by a use action). At that moment the item still has its old amount; the hook is called before any subtraction so you can inspect the stack and the planned consumption. item is the live Item object, so item.info (shortname, itemid, category), item.amount, item.skin, item.parent and item.GetOwnerPlayer() are all available. amountToConsume is the count the game intends to remove. Because the hook only replaces that count, this is the right place to change consumption costs, not to veto a use entirely, since returning 0 still leaves the call going through with the new amount. Narrowing by type is useful mainly for the item category: declare Item (as given) and branch on item.info.category for things like ItemCategory.Medical. Practical uses are server-wide multipliers for consumable drain, free item usage during events, or inventory debugging. The hook fires for every stack use, including automated ones, so keep the body cheap.
Example plugin: Scale consumable use per item category
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using UnityEngine;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("Consumable Use Multiplier", "RustPluginGenerator", "1.0.0")]
[Description("Scales how many units of an item stack are consumed per category")]
public class ConsumableUseMultiplier : RustPlugin
{
private const string PermBypass = "consumableusemultiplier.bypass";
private PluginConfig config;
private class PluginConfig
{
[JsonProperty("Food multiplier")]
public float FoodMultiplier = 2f;
[JsonProperty("Medical multiplier")]
public float MedicalMultiplier = 1.5f;
[JsonProperty("Other items multiplier")]
public float DefaultMultiplier = 1f;
}
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>
{
["Usage"] = "Usage: /usemultiplier",
["Config"] = "Multipliers - Food: {0}x, Medical: {1}x, Other: {2}x"
}, 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(PermBypass, this);
}
private object OnItemUse(Item item, int amountToConsume)
{
if (item?.info == null) return null;
BasePlayer player = item.GetOwnerPlayer();
if (player != null && permission.UserHasPermission(player.UserIDString, PermBypass)) return null;
float multiplier = GetMultiplier(item.info.category);
if (Mathf.Approximately(multiplier, 1f)) return null;
int newAmount = Mathf.Max(0, Mathf.RoundToInt(amountToConsume * multiplier));
if (newAmount == amountToConsume) return null;
return newAmount;
}
private float GetMultiplier(ItemCategory category)
{
if (category == ItemCategory.Food) return Mathf.Max(0f, config.FoodMultiplier);
if (category == ItemCategory.Medical) return Mathf.Max(0f, config.MedicalMultiplier);
return Mathf.Max(0f, config.DefaultMultiplier);
}
[ChatCommand("usemultiplier")]
private void CmdUseMultiplier(BasePlayer player, string command, string[] args)
{
if (player == null) return;
if (!player.IsAdmin)
{
SendReply(player, Msg("Usage", player.UserIDString));
return;
}
SendReply(player, Msg("Config", player.UserIDString,
config.FoodMultiplier, config.MedicalMultiplier, config.DefaultMultiplier));
}
}
}The plugin keeps a config map of item categories to consumption multipliers, defaulting food and medical to 1x and everything else to 1x. In OnItemUse it looks up item.info.category, computes Mathf.Max(0, Mathf.RoundToInt(amountToConsume * multiplier)) and returns it as an int, so the game subtracts the scaled amount instead of the original. A canuse.use permission lets admins bypass the scaling entirely. Because the returned value is an int, returns are cast explicitly and the fallback is return null so untouched categories keep vanilla behaviour. A chat command prints the currently loaded multipliers so admins can verify the config without editing files.
Common use cases
Increase food and medical drain
Return a larger amount for ItemCategory.Food and ItemCategory.Medical so survival resources burn faster on a hardcore server.
Free uses during events
Return 0 for items while a server event flag is set, so players can consume items without losing stack count.
Log unexpected consumption
Track which items are consumed per player during a test and write the totals to a data file for tuning.
Pitfalls
Cannot veto usage
The hook only swaps the consumption count; returning 0 still lets the use proceed. Use OnItemAction or CanUseItem-style checks if you need to block an item entirely.
Casting the return value matters
Only an actual int is read by the game. Returning a long, float or bool silently falls back to the original amount, so always cast with (int) or return null.
High frequency, no logging
The hook runs on every stack use for every player. Avoid PrintWarning or chat replies inside it; do heavy work in timers or batched commands instead.
Build a plugin with OnItemUse
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 OnItemUse
Generate