OnPlayerUnvanish
OnPlayerUnvanish is called when an invisible player is about to be made visible again through the debugging `invis` convar. Returning a non-null value cancels the unvanish.
object OnPlayerUnvanish(BasePlayer player)Parameters
| Parameter | Type | Description |
|---|---|---|
player | BasePlayer | The BasePlayer who is about to become visible again. This is the player whose invisibility state is being cleared by the debugging invis convar. |
Return value
Returning null lets the unvanish proceed: isInvisible is set to false, the player is removed from BasePlayer.invisPlayers, and the query is rebuilt. Returning any non-null object stops the original method immediately, leaving the player invisible.
How it works
The hook fires inside ConVar.Debugging.invis, which is the console command that toggles a player's invisibility. When the command is used on a player who is currently invisible (!flag && basePlayer.isInvisible), Oxide calls OnPlayerUnvanish with that player before the server clears the flag, removes them from BasePlayer.invisPlayers, and re-adds them to the entity query. Because the hook runs just before those steps, you can observe the state or block the transition.
The single argument is the BasePlayer being unvanished. It is not narrowed by subtype here, so this hook only receives BasePlayer instances. The hook fires per call of the convar, so it is not a per-tick hook, but it can still be spammed by admins or players with access to the convar.
Note that this is triggered by the debugging invis command, not by every gameplay action that could reveal a player. Pair it with OnPlayerVanish/OnPlayerVanished to track the full invisibility cycle.
Example plugin: Flag players who try to unvanish and log it
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Unvanish Guard", "RustPluginGenerator", "1.0.0")]
[Description("Restricts and logs the debugging invis unvanish command.")]
public class UnvanishGuard : RustPlugin
{
private class PluginConfig
{
[Newtonsoft.Json.JsonProperty("Allow admins to unvanish")]
public bool AllowAdmins { get; set; } = true;
}
private const string PermBypass = "unvanishguard.bypass";
private PluginConfig config;
private readonly List<string> log = new List<string>();
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 unvanish on this server.",
["Logged"] = "Unvanish attempt by {0} ({1})."
}, this);
}
private void Init()
{
permission.RegisterPermission(PermBypass, this);
}
private string Msg(string key, string userId = null, params object[] args)
{
return string.Format(lang.GetMessage(key, this, userId), args);
}
private object OnPlayerUnvanish(BasePlayer player)
{
if (player == null) return null;
bool allowed = config.AllowAdmins && player.IsAdmin;
if (!allowed && permission.UserHasPermission(player.UserIDString, PermBypass))
allowed = true;
if (allowed) return null;
log.Add(string.Format("{0} {1}", DateTime.UtcNow.ToString("u"), player.displayName));
if (log.Count > 50) log.RemoveAt(0);
player.ChatMessage(Msg("Blocked", player.UserIDString));
return true;
}
[ConsoleCommand("unvanishguard.log")]
private void CmdLog(ConsoleSystem.Arg arg)
{
if (arg == null || !arg.IsAdmin) return;
if (log.Count == 0)
{
arg.ReplyWith("No unvanish attempts recorded.");
return;
}
foreach (string entry in log)
arg.ReplyWith(entry);
}
private void Unload()
{
log.Clear();
}
}
}The plugin listens to OnPlayerUnvanish and, for players who are not admins, returns a non-null value to cancel the unvanish so they stay invisible until an admin intervenes. It also records the event in a timestamped list so staff can review who attempted the command. Admin players are allowed through, and the hook only writes to an in-memory list to avoid disk churn. The list is exposed through a console command that prints the last few attempts, and everything is cleared on unload.
Common use cases
Enforce staff-only visibility changes
Block the unvanish for anyone who is not on an allowed permission so only moderators can reveal themselves, keeping cheaters in the invisible state.
Audit invis toggles
Record who fired the invis command and when, so admins can review abuse of the debugging convar.
Reapply custom invisibility rules
Cancel the unvanish and issue your own effect or notification if a plugin-managed cloak should stay active.
Pitfalls
Blocking admins with no escape
If you always return non-null, admins cannot undo their own invisibility; gate the return on a permission or role check.
Logging too much on a spammy command
The hook fires on every convar call, so writing files or chats inside it can flood logs; buffer the data and flush rarely.
Build a plugin with OnPlayerUnvanish
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 OnPlayerUnvanish
Generate