Skip to content
RustPluginGenerator

OnClientCommand

OnClientCommand is called when the server receives a console command string from a connected client, before Rust executes it. Returning a non-null value skips execution of the command for that client.

Signature
object OnClientCommand(Network.Connection connection, string text)

Parameters

Hook parameters
ParameterTypeDescription
connectionNetwork.ConnectionThe Network.Connection of the client that sent the console command. Null or disconnected connections are filtered before the hook fires, but treat it as potentially null and use connection.player as BasePlayer when needed.
textstringThe raw console command string the client sent, for example 'kill' or 'chat.say hello'. Parse it to decide whether to allow, block or rewrite the command.

Return value

Return null to let Rust execute the client's command normally. Return any non-null value (including an empty string) to stop the command from running at all; the return value itself is otherwise ignored because the patched method returns void.

How it works

The hook fires inside ConsoleNetwork.OnClientCommand, right after the packet's command string is read and the connection is confirmed valid and connected. Every console command a client sends goes through this path, including commands typed into the F1 console, bind/input commands such as chat.say and kill, and commands issued by keybinds or client-side scripts. If connection is null or not connected, the method logs a warning and the hook never fires.

connection identifies the sending client (connection.player is the BasePlayer, authLevel is the client's auth level). text is the untouched command line, so you can match substrings, split on spaces, or compare against an allow/deny list. Returning a non-null value (an empty string is fine, anything not null) prevents ConsoleSystem.RunWithResult from running the command. Returning null lets the command proceed untouched.

The hook cannot change the command text; it is an allow/block gate only. Blocking silently is often desired, but you may notify the sender yourself. Because it fires for very frequent keybind and chat traffic, avoid heavy work and never log on every call.

Example plugin: Block dangerous and noisy console commands per player

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

namespace Oxide.Plugins
{
    [Info("Client Command Blocker", "RustPluginGenerator", "1.0.0")]
    [Description("Blocks selected client console commands unless the sender has permission or is an admin")]
    public class ClientCommandBlocker : RustPlugin
    {
        private const string PermBypass = "clientcommandblocker.bypass";

        private PluginConfig config;
        private readonly Dictionary<ulong, float> lastNotice = new Dictionary<ulong, float>();

        private class PluginConfig
        {
            [JsonProperty("Blocked command prefixes")]
            public List<string> Blocked = new List<string> { "global.say", "chat.say" };

            [JsonProperty("Notify blocked players")]
            public bool Notify = true;

            [JsonProperty("Notice cooldown seconds")]
            public float NoticeCooldown = 10f;
        }

        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"] = "The command '{0}' is not allowed here.",
                ["Reloaded"] = "Client Command Blocker configuration reloaded."
            }, 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(PermBypass, this);
        }

        private object OnClientCommand(Network.Connection connection, string text)
        {
            if (connection == null || string.IsNullOrEmpty(text)) return null;

            var player = connection.player as BasePlayer;
            if (player != null && (player.IsAdmin || permission.UserHasPermission(player.UserIDString, PermBypass)))
                return null;

            var command = text.Trim().ToLowerInvariant();
            foreach (var blocked in config.Blocked)
            {
                if (string.IsNullOrEmpty(blocked)) continue;
                if (!command.StartsWith(blocked, StringComparison.Ordinal)) continue;

                if (config.Notify && player != null && player.IsConnected)
                    NotifyPlayer(player, text.Trim());

                return string.Empty;
            }

            return null;
        }

        private void NotifyPlayer(BasePlayer player, string command)
        {
            float now = UnityEngine.Time.realtimeSinceStartup;
            float last;
            if (lastNotice.TryGetValue(player.userID, out last) && now - last < config.NoticeCooldown)
                return;

            lastNotice[player.userID] = now;
            player.ChatMessage(Msg("Blocked", player.UserIDString, command));
        }

        [ChatCommand("ccb")]
        private void CmdCcb(BasePlayer player, string command, string[] args)
        {
            if (player != null && !player.IsAdmin) return;
            LoadConfig();
            if (player != null) player.ChatMessage(Msg("Reloaded", player.UserIDString));
        }

        private void Unload()
        {
            lastNotice.Clear();
        }
    }
}

The plugin keeps a config list of blocked console commands (prefix matches). When a client sends a command, OnClientCommand lowercases the text and compares it against every blocked entry; on a match it checks the sender's permission and auth level. Admins and players holding clientcommandblocker.bypass are ignored, everyone else gets the command dropped and, if Notify is enabled, a chat message listing the blocked command. A short per-player cooldown limits how often the notice is sent so a spammed keybind does not flood chat. The config is loaded on startup and rewritten by the /ccb reload chat command.

Common use cases

  • Block client exploits

    Deny console commands that abusive clients use to gain an edge, such as mass chat.say spam or commands known to desync server state, while leaving normal play untouched.

  • Restrict commands to staff

    Allow specific console commands only for admins or players holding a permission; everyone else has the command silently dropped before Rust executes it.

  • Audit command usage

    Count how many times each command is sent and report the totals to staff on demand, without writing a log line for every single call.

Pitfalls

  • The hook cannot rewrite commands

    You can only allow or block; the original text string is always what runs. To change a command's arguments you must block it and run your own replacement logic.

  • Fires for all client console traffic

    Keybinds and chat go through this path, so DoS-prone work (string splits per blocked entry, file writes, chat messages) should be capped with cooldowns or permission checks.

  • connection.player can be null

    Not every connection resolves to a loaded BasePlayer at the moment the command is sent. Null-check connection.player before reading UserIDString or sending messages.

Build a plugin with OnClientCommand

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

Prompt: Block client exploits using the OnClientCommand 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 OnClientCommand

Generate