Skip to content
RustPluginGenerator

OnPlayerBanned

OnPlayerBanned is called when a player is added to the server ban list or banned by Easy Anti-Cheat, giving plugins the name, Steam ID, IP address, reason and expiry of the ban.

Signature
void OnPlayerBanned(string playerName, ulong steamId, string Address, string reason, long expiry)

Parameters

Hook parameters
ParameterTypeDescription
playerNamestringName of the banned player as recorded in the ban list. May be an empty string or a steam ID string when the server ban was created without a name.
steamIdulongSteam ID of the banned player as a ulong. Use it for data keys, permission removal or lookups in your own ban tracking.
AddressstringLast known IP address from Covalence's player record, or the literal string "0" when the player is not tracked by the player manager.
reasonstringThe reason text stored with the ban. Empty string when the ban was issued without a reason, as with a plain `banid` console command.
expirylongUnix timestamp when the ban expires. A value of 0 or -1 means a permanent ban. Compare against Facepunch.Math.Epoch.Current to tell temporary bans apart.

Return value

The return value is ignored at every injection site. The original ban code runs regardless of what your hook returns, so the hook is purely an observer and cannot cancel or shorten a ban.

How it works

The hook fires from two different places. RustCore.OnServerUserSet calls it whenever a user is written to the server's user database with the Banned group - that covers console commands like ban and banid, RCON bans and bans written through ServerUsers. It also fires from EAC when a client is permanently or temporarily banned by the anticheat. A third overload OnPlayerBanned(Network.Connection connection, string status) is used for EAC auth responses.

The name/Steam ID form gives you everything you need to act on the ban: steamId as a key, Address for IP correlation, reason for logging and expiry for telling temporary bans from permanent ones. Use playerName only for display - it can be blank for bans created by ID alone.

Oxide dispatches overloads by checking parameter types against the arguments, so the two-argument form receives Network.Connection and a status string, while the five-argument form receives the ban record. Declare the form you need and null-check connection in the short form, since the auth connection may already be torn down. Because the hook comes from RustCore, not a patched game method, it also fires for bans issued while the server is starting up.

Other signatures

Oxide also calls OnPlayerBanned from other places in the game with these parameter types. Declare the overload you need, or several:

  • void OnPlayerBanned(Network.Connection connection, string toString)

Example plugin: Record bans to an oxide/data file and notify admins

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

namespace Oxide.Plugins
{
    [Info("Ban Audit Log", "RustPluginGenerator", "1.0.0")]
    [Description("Records every server and anticheat ban to a data file and lets admins review recent entries")]
    public class BanAuditLog : RustPlugin
    {
        private const string PermAdmin = "banauditlog.admin";
        private const string DataFile = "BanAuditLog";

        private PluginConfig config;
        private StoredData data;

        private class PluginConfig
        {
            [JsonProperty("Warn admins in chat when a ban is recorded")]
            public bool NotifyAdmins = true;
        }

        private class BanEntry
        {
            [JsonProperty("Player name")]
            public string PlayerName;
            [JsonProperty("Steam ID")]
            public string SteamId;
            [JsonProperty("Address")]
            public string Address;
            [JsonProperty("Reason")]
            public string Reason;
            [JsonProperty("Duration")]
            public string Duration;
            [JsonProperty("Banned at (UTC)")]
            public string BannedAt;
        }

        private class StoredData
        {
            [JsonProperty("Recent bans")]
            public List<BanEntry> RecentBans = new List<BanEntry>();
        }

        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>
            {
                ["AdminNotice"] = "Ban recorded: {0} ({1}) - {2}",
                ["NoBans"] = "No bans have been recorded yet.",
                ["ListHeader"] = "Last {0} bans:",
                ["ListEntry"] = "{0} ({1}) - {2} [{3}]"
            }, 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(PermAdmin, this);
        }

        private void OnServerInitialized()
        {
            data = Interface.Oxide.DataFileSystem.ReadObject<StoredData>(DataFile) ?? new StoredData();
        }

        private void Unload()
        {
            SaveData();
        }

        private void SaveData()
        {
            if (data != null) Interface.Oxide.DataFileSystem.WriteObject(DataFile, data);
        }

        private void OnPlayerBanned(string playerName, ulong steamId, string Address, string reason, long expiry)
        {
            if (data == null) return;

            long now = Facepunch.Math.Epoch.Current;
            string duration;
            if (expiry <= 0) duration = "permanent";
            else if (expiry > now) duration = Mathf.CeilToInt((float)(expiry - now) / 60f) + " minutes";
            else duration = "expired";

            string name = string.IsNullOrEmpty(playerName) ? steamId.ToString() : playerName;

            data.RecentBans.Insert(0, new BanEntry
            {
                PlayerName = name,
                SteamId = steamId.ToString(),
                Address = string.IsNullOrEmpty(Address) ? "0" : Address,
                Reason = string.IsNullOrEmpty(reason) ? "no reason given" : reason,
                Duration = duration,
                BannedAt = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss")
            });

            while (data.RecentBans.Count > 200) data.RecentBans.RemoveAt(data.RecentBans.Count - 1);
            SaveData();

            if (!config.NotifyAdmins) return;
            string notice = Msg("AdminNotice", null, name, steamId, duration);
            foreach (var admin in BasePlayer.activePlayerList)
            {
                if (admin == null || admin.IsNpc || !permission.UserHasPermission(admin.UserIDString, PermAdmin)) continue;
                admin.ChatMessage(notice);
            }
        }

        [ConsoleCommand("banauditlog.list")]
        private void CmdList(ConsoleSystem.Arg arg)
        {
            if (data == null || data.RecentBans.Count == 0)
            {
                arg.ReplyWith(Msg("NoBans"));
                return;
            }

            int count = Mathf.Clamp(arg.GetInt(0, 10), 1, 50);
            arg.ReplyWith(Msg("ListHeader", null, count));
            for (int i = 0; i < count && i < data.RecentBans.Count; i++)
            {
                var entry = data.RecentBans[i];
                arg.ReplyWith(Msg("ListEntry", null, entry.PlayerName, entry.SteamId, entry.Reason, entry.Duration));
            }
        }
    }
}

The plugin keeps a rolling log of the last 200 bans in oxide/data/BanAuditLog.json. OnPlayerBanned converts the expiry timestamp into a readable duration or the word permanent, builds a single line with the name, Steam ID, IP and reason, and prepends it to the stored list. The updated file is written straight away so the record survives a restart even if no other save happens. Admins are told about the new entry on chat only when at least one admin is connected, using the banauditlog.admin permission, and the banauditlog.list console command prints the most recent entries so RCON can read them without opening the file.

Common use cases

  • Discord or file audit trail

    Persist every ban into a data file or hand it to an external logger so staff can review who banned whom and why after the fact.

  • Clean up player data on ban

    Remove permissions, team membership records or per-player saved data using the Steam ID, since the hook fires for console and RCON bans too.

  • Notify staff of EAC bans

    The hook also fires for anticheat bans, so you can alert online admins immediately when a player is removed by EAC rather than waiting for them to check the logs.

Pitfalls

  • Address can be the string "0"

    When Covalence has no player record for the ID, the address passed in is the literal string "0". Do not treat it as a valid IP or store it as one without checking.

  • Expiry is not a duration

    The last parameter is a Unix timestamp, and permanent bans use 0 or -1. Subtract Facepunch.Math.Epoch.Current instead of printing the raw number as seconds remaining.

  • Do not run heavy work inline

    The hook fires during the ban write path. Keep the handler to a few string operations and a data write, and defer anything expensive to a NextTick or timer.Once.

Build a plugin with OnPlayerBanned

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

Prompt: Discord or file audit trail using the OnPlayerBanned 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 OnPlayerBanned

Generate