Skip to content
RustPluginGenerator

OnHealingItemUse

OnHealingItemUse is called when a player uses a healing item (bandage, syringe, medkit) and the effects are about to be applied to the target. Returning a non-null value cancels the heal entirely.

Signature
object OnHealingItemUse(MedicalTool medicalTool, BasePlayer fromPlayer, IMedicalToolTarget toTarget)

Parameters

Hook parameters
ParameterTypeDescription
medicalToolMedicalToolThe MedicalTool component of the held healing item (bandage, syringe, medkit). Use it to read the base entity, owner item or skin.
fromPlayerBasePlayerThe BasePlayer using the item. Can be null in edge cases, so null-check before reading inventory or identity.
toTargetIMedicalToolTargetThe IMedicalToolTarget being healed — usually the same player, but could be another entity that implements the interface. Call toTarget.GetEntity() to get the BaseEntity.

Return value

Return null (or nothing) to let the heal proceed normally. Any non-null return stops the original code path, so the analytics event and OnMedicalToolApplied are skipped and the target receives no healing. Return false or true — both cancel, because the check only tests for null.

How it works

The hook fires inside MedicalTool.GiveEffectsTo, after the game resolves the item's ItemModConsumable component and just before it calls Analytics.OnMedUsed and toTarget.OnMedicalToolApplied. That means it runs for every successful use of a medical tool: bandages, medical syringes, anti-rad pills and medkits. It does not fire for food, water or other consumables, and it does not fire if the heal is already blocked elsewhere.

medicalTool lets you inspect the item being consumed (shortname, owner, skin). fromPlayer is the user; treat it as nullable. toTarget is the entity receiving the heal — for self-heals it is the user, but the interface also allows healing another entity, so use toTarget.GetEntity() to get a BaseEntity when you need type checks.

The hook is not typed to a specific player, so you cannot narrow it by declaring a more specific parameter type. Filter by shortname or by target entity type inside the method instead. Because it fires once per use, it is safe to run light logic here; avoid anything expensive.

Example plugin: Restrict bandages in combat

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

namespace Oxide.Plugins
{
    [Info("Combat Bandage Blocker", "RustPluginGenerator", "1.0.0")]
    [Description("Blocks healing items while a player is in combat for a configurable duration.")]
    public class CombatBandageBlocker : RustPlugin
    {
        private const string PermBypass = "combatbandageblocker.bypass";

        private PluginConfig config;
        private readonly Dictionary<ulong, float> combatUntil = new Dictionary<ulong, float>();

        private class PluginConfig
        {
            [JsonProperty("Combat duration (seconds)")]
            public float CombatDuration { get; set; } = 8f;

            [JsonProperty("Blocked item shortnames")]
            public List<string> BlockedShortnames { get; set; } = new List<string>
            {
                "bandage", "syringe.medical", "largemedkit", "antiradpills"
            };
        }

        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>
            {
                ["CombatBlocked"] = "You cannot use {0} while in combat. Wait {1:0.0}s."
            }, 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 void MarkCombat(BasePlayer player)
        {
            if (player == null || player.IsNpc) return;
            combatUntil[player.userID.Get()] = Time.realtimeSinceStartup + config.CombatDuration;
        }

        private object OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info)
        {
            if (info == null) return null;
            var attacker = info.InitiatorPlayer;
            var victim = entity as BasePlayer;
            if (attacker != null && victim != null) MarkCombat(attacker);
            if (victim != null) MarkCombat(victim);
            return null;
        }

        private object OnHealingItemUse(MedicalTool medicalTool, BasePlayer fromPlayer, IMedicalToolTarget toTarget)
        {
            if (medicalTool == null || fromPlayer == null) return null;
            if (permission.UserHasPermission(fromPlayer.UserIDString, PermBypass)) return null;

            var item = medicalTool.GetOwnerItem();
            if (item?.info == null) return null;
            if (!config.BlockedShortnames.Contains(item.info.shortname)) return null;

            float until;
            if (!combatUntil.TryGetValue(fromPlayer.userID.Get(), out until)) return null;
            float remaining = until - Time.realtimeSinceStartup;
            if (remaining <= 0f) return null;

            fromPlayer.ChatMessage(Msg("CombatBlocked", fromPlayer.UserIDString, item.info.displayName.english, remaining));
            return false;
        }

        private void Unload()
        {
            combatUntil.Clear();
        }
    }
}

The plugin blocks bandages, syringes and medkits while a player is in combat, defined as having taken or dealt damage in the last N seconds. It registers an OnEntityTakeDamage handler that records a cooldown-per-player in a Dictionary<ulong, float> for both attacker and victim, then uses OnHealingItemUse to check the timestamp. If the player is still on cooldown, it sends a localized chat message and returns false to cancel the heal, leaving the item unconsumed. Admins with a permission bypass the check. The cooldown length and the list of restricted shortnames are configurable, and entries are cleaned up in Unload.

Common use cases

  • Combat lockdowns

    Prevent players from healing mid-fight with bandages or syringes to force disengagement or punish aggressive plays.

  • Raid-only restrictions

    Allow healing normally but block it while the player is inside a building blocked zone or near a raid target.

  • Custom medical economy

    Require a resource or permission before a medical item applies its effects, then refund the item if the check fails.

Pitfalls

  • Returning a value cancels silently

    The hook only checks for null. Even returning true skips the heal — return null when you want the heal to happen.

  • The item is still consumed

    Cancelling the hook prevents OnMedicalToolApplied from running, so the heal is not applied, but the item consumption is handled by the item's own use logic. Expect the item to be removed even when blocked.

  • fromPlayer may be null

    Always null-check fromPlayer before reading UserIDString or inventory — a missing player crashes the hook and can spam the server log.

Build a plugin with OnHealingItemUse

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

Prompt: Combat lockdowns using the OnHealingItemUse 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 OnHealingItemUse

Generate