Skip to content
RustPluginGenerator

OnPlayerRecovered

OnPlayerRecovered is called when a player recovers from the wounded state via BasePlayer.RecoverFromWounded, i.e. the moment they finish getting back up after being downed. It fires once per recovery, not on ordinary damage or healing.

Signature
void OnPlayerRecovered(BasePlayer player)

Parameters

Hook parameters
ParameterTypeDescription
playerBasePlayerThe BasePlayer that just recovered from the wounded (downed) state. Already flagged as no longer incapacitated and the collider size is refreshed after this hook runs.

Return value

The return value is ignored. The original RecoverFromWounded method returns void, and this hook is injected for notification only, so returning null or any other value does not change the recovery or stop the game code.

How it works

The hook fires inside BasePlayer.RecoverFromWounded, after the game clears the Incapacitated player flag and after any active game mode's revive callback, but before RefreshColliderSize runs. That means the player is logically no longer downed at the time you receive the call, yet their collider is still being adjusted, so do not teleport them in a way that depends on a settled collider — use NextTick if you need that. Because the hook is a void injection with the return value ignored, it is a notification only: you cannot veto the recovery or change who recovers. The single argument is the recovering BasePlayer, so you can inspect position, health, team, inventory or active wounds and act on them. There is no narrower type to declare here — the parameter is already the concrete BasePlayer. Typical uses are respawn protection windows, chat or UI feedback, kill-feed announcements, logging recoveries for moderation, or triggering a short buff. Avoid heavy work or console spam since every downed player who gets back up fires this.

Example plugin: Grant a short respawn protection window after recovering

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

namespace Oxide.Plugins
{
    [Info("Recovery Protection", "RustPluginGenerator", "1.0.0")]
    [Description("Grants a short damage-reduction window to players who recover from the wounded state")]
    public class RecoveryProtection : RustPlugin
    {
        private const string PermUse = "recoveryprotection.use";

        private PluginConfig config;
        private readonly Dictionary<ulong, float> protectedUntil = new Dictionary<ulong, float>();
        private readonly Dictionary<ulong, Timer> timers = new Dictionary<ulong, Timer>();

        private class PluginConfig
        {
            [JsonProperty("Protection duration (seconds)")]
            public float Duration = 10f;

            [JsonProperty("Damage multiplier while protected")]
            public float DamageMultiplier = 0.25f;
        }

        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>
            {
                ["Protected"] = "You are protected for {0} seconds after recovering. Take it easy.",
                ["Expired"] = "Your recovery protection has ended.",
                ["NoPermission"] = "You do not have permission to use this feature."
            }, 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(PermUse, this);
        }

        private void OnPlayerRecovered(BasePlayer player)
        {
            if (player == null || player.IsNpc || !player.IsConnected) return;
            if (!permission.UserHasPermission(player.UserIDString, PermUse)) return;

            ulong id = player.userID.Get();
            protectedUntil[id] = Time.realtimeSinceStartup + config.Duration;
            player.ChatMessage(Msg("Protected", player.UserIDString, config.Duration));

            if (timers.TryGetValue(id, out Timer existing) && existing != null)
                existing.Destroy();

            timers[id] = timer.Once(config.Duration, () =>
            {
                protectedUntil.Remove(id);
                timers.Remove(id);
                if (player != null && player.IsConnected)
                    player.ChatMessage(Msg("Expired", player.UserIDString));
            });
        }

        private void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info)
        {
            if (entity == null || info == null) return;
            BasePlayer victim = entity as BasePlayer;
            if (victim == null) return;

            if (!protectedUntil.TryGetValue(victim.userID.Get(), out float expiry)) return;
            if (Time.realtimeSinceStartup > expiry) { protectedUntil.Remove(victim.userID.Get()); return; }

            info.damageTypes.ScaleAll(config.DamageMultiplier);
        }

        private void Unload()
        {
            foreach (var timer in timers.Values)
                timer?.Destroy();
            timers.Clear();
            protectedUntil.Clear();
        }
    }
}

The plugin listens for OnPlayerRecovered and, when a player gets back up, gives them a configurable number of seconds of armour protection. It records the protected player and the expiry time in a dictionary, sends them a chat message through lang, and applies a simple damage scale in OnEntityTakeDamage while the window is active. The protection value and duration come from the config. On expiry a timer removes the entry and notifies the player. Puts and warnings are only called at startup, and the dictionary is cleared in Unload alongside destroying any pending timers so a reload does not leave stale state.

Common use cases

  • Respawn protection after revive

    Give a brief window of reduced damage or immunity right after a player recovers so they are not instantly re-downed by nearby attackers.

  • Recovery logging for moderation

    Record time, position and health of every recovery to a data file so admins can review suspicious cases of players getting up in combat.

  • Reward or feedback on revive

    Send a chat message, play an effect at the player's position or grant a small item to acknowledge the recovery.

Pitfalls

  • Collider is not settled yet

    The hook fires before RefreshColliderSize, so teleporting or spawning entities at the exact position can land wrong. Defer with NextTick if you rely on the collider.

  • Cannot cancel the recovery

    The return value is ignored. If you need to block or intercept the downed state, use CanBeWounded or OnPlayerWound instead.

  • Fires alongside game mode revives

    The active game mode's revive callback runs before this hook. Do not duplicate its logic; assume the player is already flagged as not incapacitated.

Build a plugin with OnPlayerRecovered

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

Prompt: Respawn protection after revive using the OnPlayerRecovered 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 OnPlayerRecovered

Generate