OnPlayerAddModifiers
OnPlayerAddModifiers is called when a player consumes an item that grants a player modifier, right before the game adds that modifier to the player.
object OnPlayerAddModifiers(BasePlayer player, Item item, ItemModConsumable consumable)Parameters
| Parameter | Type | Description |
|---|---|---|
player | BasePlayer | The player consuming the item. Always set when the hook fires from ItemModConsume.DoAction. |
item | Item | The item being consumed; use item.info.shortname, item.amount or item.skin to tell food, tea and other consumables apart. |
consumable | ItemModConsumable | The ItemModConsumable component of the item, which holds the modifier(s) the game is about to apply (e.g. Max Health, Radiation). |
Return value
Returning null lets the game proceed and add the modifier to the player. Returning any non-null value stops the original code path, so the modifier is not applied at all; the value itself is discarded because the patched method returns void.
How it works
The hook fires inside ItemModConsume.DoAction, after the item's eat/drink effects and metabolism changes have been applied, and immediately before player.modifiers.Add(consumable.modifiers) runs. It only fires when the consumed item actually has an ItemModConsumable with modifiers and the player has a modifiers component, so plain food that only restores calories or hydration usually does not reach it.\n\nplayer is the consumer, item is the stack entry that was consumed, and consumable is the component holding the modifier values. Use it to veto or replace modifier gains: block a tea entirely, restrict which players may receive a bonus, or read the modifier values to log or price consumption.\n\nYou can narrow the hook to a specific item type by declaring the second parameter as a more specific type, for example Item is the base type, so declare exactly Item unless you know a subclass flows in; Oxide skips the call when an argument is not an instance of your parameter type. The hook runs on the server thread as part of the consume action, so keep it fast.
Example plugin: Block tea modifiers while combat-blocked
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("No Tea In Combat", "RustPluginGenerator", "1.0.0")]
[Description("Blocks tea and modifier consumables while the player was recently damaged by another player")]
public class NoTeaInCombat : RustPlugin
{
private const string PermBypass = "noteaincombat.bypass";
private PluginConfig config;
private readonly Dictionary<ulong, DateTime> lastDamage = new Dictionary<ulong, DateTime>();
private Timer sweepTimer;
private class PluginConfig
{
[JsonProperty("Combat window in seconds")]
public double CombatWindow = 15.0;
[JsonProperty("Refund blocked items")]
public bool Refund = true;
}
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>
{
["Blocked"] = "You cannot use {0} while in combat.",
["Refunded"] = "The {0} has been returned to your inventory."
}, 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);
sweepTimer = timer.Every(30f, Sweep);
}
private void Unload()
{
sweepTimer?.Destroy();
lastDamage.Clear();
}
private void Sweep()
{
DateTime cutoff = DateTime.UtcNow.AddSeconds(-Math.Max(config.CombatWindow, 1.0) * 4);
var stale = new List<ulong>();
foreach (var entry in lastDamage)
{
if (entry.Value < cutoff) stale.Add(entry.Key);
}
foreach (ulong id in stale) lastDamage.Remove(id);
}
private void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info)
{
if (info == null) return;
var victim = entity as BasePlayer;
if (victim == null || victim.IsNpc) return;
if (info.InitiatorPlayer == null || info.InitiatorPlayer == victim) return;
lastDamage[victim.userID.Get()] = DateTime.UtcNow;
}
private object OnPlayerAddModifiers(BasePlayer player, Item item, ItemModConsumable consumable)
{
if (player == null || item == null || item.info == null || consumable == null) return null;
if (permission.UserHasPermission(player.UserIDString, PermBypass)) return null;
DateTime stamp;
if (!lastDamage.TryGetValue(player.userID.Get(), out stamp)) return null;
if ((DateTime.UtcNow - stamp).TotalSeconds > config.CombatWindow) return null;
string shortname = item.info.shortname;
if (shortname == null || !shortname.StartsWith("tea")) return null;
string displayName = item.info.displayName != null ? item.info.displayName.english : shortname;
player.ChatMessage(Msg("Blocked", player.UserIDString, displayName));
if (config.Refund)
{
Item replacement = ItemManager.CreateByItemID(item.info.itemid, 1, item.skin);
if (replacement != null && player.inventory.GiveItem(replacement))
{
player.ChatMessage(Msg("Refunded", player.UserIDString, displayName));
}
}
return true;
}
}
}The plugin records a timestamp for each player whenever they take damage from another player, using OnEntityTakeDamage. When OnPlayerAddModifiers fires, it checks whether the consumed item's shortname starts with tea and whether the player took player damage within the configured window. If both are true, it returns a non-null value to suppress the modifier, notifies the player through a localized message and refunds the tea as a new item. A timer.Every sweep clears stale timestamps and is destroyed in Unload; all player-facing text goes through the language file.
Common use cases
Combat restrictions
Deny tea and other modifier consumables while a player is in combat, and give the item back so consumption is not punished.
Permission-based bonuses
Return a value to block modifiers for players without a VIP permission, or gate specific consumables behind a permission.
Audit/logging
Record which modifier items players consume and how often, using item.info.shortname and the consumable's modifier list, without blocking anything.
Pitfalls
Only modifiers are affected
The hook fires after metabolism effects are applied. Blocking it stops the modifier gain but not the hydration, calories or the consumed item removal.
Item is already consumed
By the time the hook runs the stack has been reduced. If you want the player to keep the item, create a fresh one with ItemManager.CreateByName and GiveItem it back.
No modifiers, no call
Food that only restores calories or hydration never reaches this hook. Use OnPlayerMetabolize or OnItemUse for broader consume tracking.
Build a plugin with OnPlayerAddModifiers
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 OnPlayerAddModifiers
Generate