OnPlayerDisconnected
OnPlayerDisconnected is called by ServerMgr.OnDisconnected just before Rust tears down the disconnecting player, giving plugins a last chance to read that player's state.
void OnPlayerDisconnected(BasePlayer player, string reason)Parameters
| Parameter | Type | Description |
|---|---|---|
player | BasePlayer | The BasePlayer whose connection is being closed. Still valid in this call: net identity, inventory, position and team are all readable, but the player is already leaving and will be destroyed shortly after. |
reason | string | The disconnect reason string passed to ServerMgr.OnDisconnected, typically something like a timeout, kick or network error message. It can be empty or a generic string for clean client-side quits. |
Return value
The return value is ignored: the hook is called for its side effects only, and the original method proceeds to basePlayer.OnDisconnected() and the rest of the logout sequence regardless of what you return. Do not return a value expecting to cancel the disconnect; there is no way to keep a player from leaving through this hook.
How it works
This hook fires from ServerMgr.OnDisconnected after EAC has processed the leave and after the connection's player has been resolved, but before basePlayer.OnDisconnected() runs. That means the player object is still intact when your code executes: you can read position, inventory contents, team id, health and permissions, then record or act on them. Because it sits inside the disconnection path, it fires for every kind of departure the server processes: clean quits, timeouts, kicks and network drops all funnel through this method. The reason argument is whatever string the server passed into the disconnect routine and should be treated as informational only, not as a reliable enum. Declaring the first parameter as BasePlayer is the natural choice; narrowing to a subclass is pointless here since real players are never NPCs. Anything you do in this hook must be fast, because the original code continues to run right after it returns. Persist data now, do not schedule work that depends on the player still being connected.
Example plugin: Record last known position on disconnect
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("DisconnectLogger", "RustPluginGenerator", "1.0.0")]
[Description("Records the last known position and reason for every player disconnect")]
public class DisconnectLogger : RustPlugin
{
private const string PermView = "disconnectlogger.view";
private const string DataFile = "DisconnectLogger";
private StoredData data;
private class PluginConfig
{
[JsonProperty("Log to console")]
public bool LogToConsole { get; set; } = true;
[JsonProperty("Keep at most this many records per player")]
public int MaxRecordsPerPlayer { get; set; } = 5;
}
private class Record
{
public string Name;
public string Reason;
public string Position;
public string Timestamp;
}
private class StoredData
{
public Dictionary<string, List<Record>> Records = new Dictionary<string, List<Record>>();
}
private PluginConfig config;
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);
private void Init()
{
permission.RegisterPermission(PermView, this);
}
private void Load()
{
data = Interface.Oxide.DataFileSystem.ReadObject<StoredData>(DataFile) ?? new StoredData();
if (data.Records == null) data.Records = new Dictionary<string, List<Record>>();
}
private void Unload()
{
SaveData();
}
private void SaveData()
{
Interface.Oxide.DataFileSystem.WriteObject(DataFile, data);
}
private void OnPlayerDisconnected(BasePlayer player, string reason)
{
if (player == null || player.net == null) return;
string id = player.UserIDString;
if (string.IsNullOrEmpty(id)) return;
var record = new Record
{
Name = player.displayName ?? "unknown",
Reason = string.IsNullOrEmpty(reason) ? "none" : reason,
Position = player.transform.position.ToString(),
Timestamp = DateTime.UtcNow.ToString("u")
};
if (!data.Records.TryGetValue(id, out List<Record> list))
{
list = new List<Record>();
data.Records[id] = list;
}
list.Add(record);
int max = Mathf.Max(1, config.MaxRecordsPerPlayer);
while (list.Count > max) list.RemoveAt(0);
SaveData();
if (config.LogToConsole)
{
Puts($"{record.Name} ({id}) disconnected at {record.Position}. Reason: {record.Reason}");
}
}
[ChatCommand("dcinfo")]
private void CmdDcInfo(BasePlayer player, string command, string[] args)
{
if (player == null) return;
if (!permission.UserHasPermission(player.UserIDString, PermView))
{
player.ChatMessage("You do not have permission to use this command.");
return;
}
if (args == null || args.Length == 0)
{
player.ChatMessage("Usage: /dcinfo <steamId>");
return;
}
if (!data.Records.TryGetValue(args[0], out List<Record> list) || list.Count == 0)
{
player.ChatMessage("No disconnect records for that Steam ID.");
return;
}
foreach (Record record in list)
{
player.ChatMessage($"{record.Timestamp} {record.Name}: {record.Position} ({record.Reason})");
}
}
}
}The plugin keeps a small data file in oxide/data/DisconnectLogger keyed by Steam ID, storing the display name, disconnect reason, position and timestamp each time a player drops. OnPlayerDisconnected null-checks the player and its net identity, builds a record from live values, and writes it through Interface.Oxide.DataFileSystem. An optional chat command, gated by the disconnectlogger.admin permission, prints the stored entry for a given Steam ID so administrators can check where and when a player left. The data object is loaded in Load and saved in Unload, keeping disk writes out of the disconnect path except for the final WriteObject call, which is cheap for a flat dictionary.
Common use cases
Freeze combat logouts
Compare the player's stored login position or last damage timestamp with their position at disconnect and log suspicious teleports to a file for staff review.
Persist per-player session stats
Flush accumulated playtime, kills or gathered resources for the session into your data file at disconnect so nothing is lost when the player never returns.
Clean up external state
Remove the player from custom vote timers, raid alerts, spectate lists or party bookkeeping that would otherwise hold a stale reference.
Pitfalls
Cannot block the disconnect
The hook's return value is discarded and the original logout path always continues, so bans, kicks or custom rejection logic must run elsewhere, such as an earlier authentication hook.
Do not assume reason is meaningful
The string comes straight from the disconnect call and varies by cause; parse it for display only and never drive permission or punishment logic from its contents.
Keep the hook fast
Heavy work such as scanning all entities or sending network messages delays the disconnection routine. Persist a minimal record and defer any cleanup to a timer.
Plugin recipes that use OnPlayerDisconnected
- How to make a Rust backpack plugin (Oxide/Carbon personal storage)Adds a /backpack command that opens a per-player StorageContainer sized by permission, with contents persisted to oxide/data and optionally dropped on death. Contents are saved in OnPlayerLootEnd and restored on open.
- How to make a Rust chat mentions plugin (@name pings)Detects @name tokens in chat and sends the mentioned online player a private notice plus a notification sound, with a per-sender cooldown. Uses OnPlayerChat.
- How to make a Rust command alias plugin (Oxide chat shortcuts)This plugin maps short chat commands like /h and /k to longer ones such as /home and /kit, defined entirely in its config file, using the OnPlayerCommand hook to intercept and reroute the alias.
- How to make a Rust duels plugin (1v1 challenge system)Adds a player-vs-player duel system where /duel <player> sends a challenge, /duel accept starts it, and damage outside the duel pair is blocked. Uses OnEntityTakeDamage, OnEntityDeath and OnPlayerDisconnected.
- How to make a Rust friendly fire plugin (team damage blocker)Blocks damage between members of the same Rust team using OnEntityTakeDamage, with a permission whitelist and a /ff toggle for team leaders that persists per team across restarts.
- How to make a Rust god mode plugin (damage immunity + full needs)Adds a permission-gated /god toggle that blocks all damage through OnEntityTakeDamage and keeps health, food and water topped up from a repeating timer. State is dropped in OnPlayerDisconnected.
- How to make a Rust high ping kick plugin (Oxide timer and permission)Checks every online player's average network ping on a repeating timer and kicks anyone who stays above the configured limit for three checks in a row. A permission exempts chosen players, and a chat warning is sent before the kick.
- How to make a Rust home teleport plugin (warmup, cooldown, damage cancel)Adds /sethome, /home, /delhome and /homes with per-permission home limits, a warmup timer that is cancelled when the player takes damage, and a teleport cooldown. It uses OnEntityTakeDamage to break the warmup and a per-tick timer for the countdown.
- How to make a Rust join and leave messages plugin (Oxide/Carbon)Broadcasts a configurable chat message when a player connects to the server and when a player disconnects, including the disconnect reason. Uses the OnPlayerConnected and OnPlayerDisconnected hooks and hides players with a permission from announcements.
- How to make a Rust kill streak plugin (Oxide/Carbon)Tracks consecutive player kills per user, announces configurable milestones in global chat and grants item rewards, then resets the streak when the player dies or disconnects. Uses OnEntityDeath and OnPlayerDisconnected.
- How to make a Rust last seen plugin (Oxide /seen command)Records a timestamp for every player on disconnect and answers /seen <name> with a relative time such as '2 hours ago' or 'online now'. Uses OnPlayerDisconnected, OnPlayerConnected and a data file in oxide/data.
- How to make a Rust NPC kill rewards plugin (economy payouts)Pays a configurable item or Economics reward when a player lands the killing blow on a scientist, animal, Bradley APC or patrol helicopter, using OnEntityDeath with a prefab-name reward table.
- How to make a Rust offline raid protection plugin (cupboard based)Scales damage to building blocks and deployables when every player authorized on the covering tool cupboard has been offline for a configurable delay. Uses OnEntityTakeDamage and OnPlayerDisconnected, with a repeating timer that turns protection on and off.
- How to make a Rust outpost and bandit teleport plugin (/outpost, /bandit)Adds /outpost and /bandit chat commands that warm up, then teleport the player to the Outpost or Bandit Camp monument found by name in TerrainMeta.Path.Monuments, with configurable warmup, cooldown and a permission bypass.
- How to make a Rust playtime group promotion plugin (Oxide/Carbon)Tracks each player's connected playtime in oxide/data and moves them into stacked Oxide groups when they cross configured hour thresholds. Uses OnPlayerConnected and OnPlayerDisconnected to start and stop counting.
- How to make a Rust playtime rewards plugin (AFK-safe, Oxide)Pays players configured items every N minutes of active play, skips anyone who has not moved during the interval, and applies a permission-based multiplier for VIPs. Built on OnPlayerConnected, OnPlayerDisconnected and a repeating Oxide timer.
- How to make a Rust playtime tracker plugin (total and wipe time)Records session start time on connect and adds elapsed connected time on disconnect, persisted per player ID in oxide/data, with a /playtime command that reports hours and minutes. Uses OnPlayerConnected, OnPlayerDisconnected and OnNewSave.
- How to make a Rust private messages plugin (with /ignore)A private messaging plugin that adds /pm, /r and /ignore with a per-player cooldown and a configurable message length limit. It uses the OnPlayerDisconnected hook to clear reply targets and cooldown timers.
- How to make a Rust raid block plugin (block tpr/home after explosives)Places a temporary raid block on attackers and on the owner of a building that takes explosive damage, blocking configured chat commands such as /home and /tpr and printing the remaining time. Uses OnEntityTakeDamage to start the block and OnPlayerCommand to enforce it.
- How to make a Rust random teleport plugin (/rtp)Adds a /rtp chat command that teleports a player to a random land position that is not water, not inside a building blocked zone and not near a structure, with a per-permission cooldown.
- How to make a Rust safe PvE zones plugin (spherical, no damage)Creates configurable spherical safe zones where damage between players and to buildings is cancelled, with entry and exit chat notices checked on a repeating timer. It uses OnEntityTakeDamage plus a timer loop.
- How to make a Rust server HUD plugin (CUI)Builds a small persistent CUI panel with the server name, online player count and in-game clock, updated from an Oxide timer for every connected player. Visibility is saved per Steam ID with OnPlayerConnected and OnPlayerDisconnected plus the /hud toggle.
- How to make a Rust sleeper protection plugin (timed spawn protection)Gives sleeping players a configurable grace period after disconnect during which other players cannot damage them, and optionally blocks looting their body. It uses OnPlayerDisconnected to start the timer, OnEntityTakeDamage to block hits, and CanLootPlayer to deny looting.
- How to make a Rust teleport requests plugin (TPR/TPA)A complete Oxide plugin that implements /tpr player-to-player teleport requests with /tpa, /tpc, request timeouts, a warmup before the move, a per-player cooldown and blocks for wounded, dead, mounted or swimming players. It uses OnPlayerTick and OnEntityTakeDamage to guard the warmup.
- How to make a Rust top players command plugin (stat leaderboard)Tracks kills, deaths and playtime per player and prints a top 10 leaderboard in chat through /top kills|deaths|playtime. Uses OnEntityDeath and OnPlayerDisconnected.
- How to make a Rust vanish plugin (admin invisibility)Adds a /vanish command that hides an admin from other players by stopping their network visibility, makes them immune to damage while hidden, draws a small CUI banner, and restores them on toggle off or disconnect. It uses OnEntityTakeDamage to block damage and OnPlayerDisconnected to clean up.
- How to make a Rust warp points plugin (named warps)Adds admin-created named warp points that save to oxide/data, with a /warp and /warps command set, an optional per-warp permission and a shared cooldown. It uses OnServerInitialized for loading, OnPlayerDisconnected to clear cooldown state and a short timer for the countdown.
- How to make a Rust welcome panel plugin (CUI on spawn)Shows a configurable CUI welcome panel with a title, message lines and server links when a player wakes up, closing on a button click or after a timeout. Uses OnPlayerSleepEnded and OnPlayerDisconnected.
Build a plugin with OnPlayerDisconnected
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 OnPlayerDisconnected
Generate