OnPlayerRecover
OnPlayerRecover is called when a player is about to recover from the wounded (crawling) state, before the game assigns their post-recovery health.
object OnPlayerRecover(BasePlayer player)Parameters
| Parameter | Type | Description |
|---|---|---|
player | BasePlayer | The BasePlayer who is recovering from the wounded (crawling) state. Check IsConnected or IsNpc before applying player-specific logic. |
Return value
Returning null (or nothing) lets the game continue and roll the normal recovery health. Returning any non-null value (a common Oxidism is returning true from a plugin intended to block) stops the original recovery logic, so the game skips its own state change; you are then responsible for any health or state handling you want.
How it works
The hook fires inside BasePlayer.RecoverFromWounded, the private method the server runs when a wounded player finishes recovering instead of dying. That path is reached when the player's wound timer expires or they are otherwise revived out of the crawling state. The only argument is the BasePlayer being recovered.
Because the call happens before the game writes the recovery health (the crawling case rolls Random.Range(2f, 6f) plus any healing accumulated while crawling), this is the place to adjust what happens to that player at the moment they stand back up: heal them further, strip items, teleport them, or notify them. You cannot narrow the hook by parameter type in a useful way here — there is only one signature and one player argument.
Returning a non-null value blocks the game's own recovery handling for that call, so the player leaves the crawling state without the normal health assignment. Only do that when you set health yourself, otherwise the player can end up with unexpected or stale health values. The hook does not fire for players who die from their wounds.
Example plugin: Grant a short damage-resistance window after recovering
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Recover Shield", "RustPluginGenerator", "1.0.0")]
[Description("Gives players a short damage-reduction window after they recover from the wounded state")]
public class RecoverShield : RustPlugin
{
private const string PermUse = "recovershield.use";
private PluginConfig config;
private readonly Dictionary<ulong, float> shieldUntil = new Dictionary<ulong, float>();
private readonly Dictionary<ulong, Timer> shieldTimers = new Dictionary<ulong, Timer>();
private class PluginConfig
{
[JsonProperty("Shield duration (seconds)")]
public float Duration { get; set; } = 8f;
[JsonProperty("Damage multiplier while shielded")]
public float DamageMultiplier { get; set; } = 0.25f;
[JsonProperty("Give free bandage on recover")]
public bool GiveBandage { get; set; } = 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>
{
["Shielded"] = "You are shielded for {0} seconds after recovering.",
["ShieldEnded"] = "Your recovery shield has expired."
}, 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 OnPlayerRecover(BasePlayer player)
{
if (player == null || player.IsNpc || !permission.UserHasPermission(player.UserIDString, PermUse))
return;
if (shieldTimers.TryGetValue(player.userID.Get(), out Timer oldTimer) && oldTimer != null)
oldTimer.Destroy();
shieldUntil[player.userID.Get()] = UnityEngine.Time.realtimeSinceStartup + config.Duration;
if (config.GiveBandage)
{
Item kit = ItemManager.CreateByName("bandage", 3, 0);
if (kit != null)
player.GiveItem(kit);
}
player.ChatMessage(Msg("Shielded", player.UserIDString, config.Duration));
shieldTimers[player.userID.Get()] = timer.Once(config.Duration, () =>
{
shieldUntil.Remove(player.userID.Get());
shieldTimers.Remove(player.userID.Get());
if (player != null && player.IsConnected)
player.ChatMessage(Msg("ShieldEnded", player.UserIDString));
});
}
private void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info)
{
BasePlayer player = entity as BasePlayer;
if (player == null || info == null)
return;
if (!shieldUntil.TryGetValue(player.userID.Get(), out float until))
return;
if (UnityEngine.Time.realtimeSinceStartup > until)
return;
if (info.damageTypes != null)
info.damageTypes.ScaleAll(config.DamageMultiplier);
}
private void Unload()
{
foreach (Timer t in shieldTimers.Values)
{
if (t != null) t.Destroy();
}
shieldTimers.Clear();
shieldUntil.Clear();
}
}
}The plugin listens for OnPlayerRecover and, if the shield is enabled in config, sends the player a chat notice and places a physical shield kit in their belt. A per-player expiry timestamp is stored in a dictionary, and OnEntityTakeDamage scales incoming damage down for anyone still inside the window. Timers strip the kit back out when it ends. The shield duration and damage multiplier live in a nested config class with [JsonProperty] fields, and the chat text is routed through the language file so it can be edited without recompiling. The hook never blocks recovery because blocking would skip the game's own health assignment.
Common use cases
Spawn protection after recovery
Give players a few seconds of reduced incoming damage after they pull themselves out of the crawling state, so they are not instantly downed again by the attacker standing over them.
Recovery notifications
Send the player a chat message or sound effect confirming they recovered, which is useful on servers with custom near-death gameplay.
Penalty on recover
Apply a small item or hunger penalty when a player survives a wound, for example removing one bandage or reducing calories, to make wounding a meaningful consequence.
Pitfalls
Returning a value skips the game's health roll
A non-null return stops the original recovery code from running. If you block it and do not set health yourself, the player leaves the crawling state with whatever health they had, which can look like a bug.
Only fires for survivors
Players who bleed out or are finished while wounded go through the death path instead, so
OnPlayerRecovernever runs for them. UseOnPlayerDeathfor anything that must cover both outcomes.Do not log here
Recovery can happen often enough on busy servers that console output becomes noise. Send player-facing text through the language file instead of
Puts.
Build a plugin with OnPlayerRecover
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 OnPlayerRecover
Generate