OnSendCommand
OnSendCommand is called before the server writes a console command packet to a client connection, inside ConsoleNetwork.SendClientCommand. Returning a non-null value cancels the send.
object OnSendCommand(Network.Connection connection, string strCommand, object[] args)Parameters
| Parameter | Type | Description |
|---|---|---|
connection | Network.Connection | The Network.Connection the command is addressed to, or in the list overload a List<Network.Connection> of all recipients. Can be null when the target is unclear, so null-check before using net.connection identity. |
strCommand | string | The console command string being sent to the client, e.g. `chat.add` or an effect command. Compare with string.Equals against the commands you want to intercept. |
args | object[] | The argument array the server will serialize into the outgoing console command. May be null or contain nulls; treat every element defensively. |
Return value
Return null or nothing to let the command be written to the client as usual. Return any non-null object to skip the original send entirely, so the client never receives that console command.
How it works
This hook fires inside ConsoleNetwork.SendClientCommand, right before the packet is built and written to the network. That method is the single funnel for server-to-client console commands, so the hook sees client commands broadly: chat lines, effect calls, UI-related commands and anything else the server pushes to a specific connection or a list of connections. It is not a player input hook; it only concerns data leaving the server.
The first parameter is the target Network.Connection (or a List<Network.Connection> in the multi-recipient overload). Use connection?.connection identity or cn.player style lookups only if you confirm the field exists in your build; comparing against a stored connection reference is the safe path. The strCommand string is the command name, and args holds the serialized arguments in order.
Declaring Network.Connection narrows the first argument to single-recipient sends; declaring List<Network.Connection> captures the broadcast overload instead. Because the hook fires for every outgoing client command, keep the body cheap and return early on a string comparison.
Other signatures
Oxide also calls OnSendCommand from other places in the game with these parameter types. Declare the overload you need, or several:
object OnSendCommand(List<Network.Connection> cn, string strCommand, object[] args)
Example plugin: Hide specific server console commands from clients
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Command Send Filter", "RustPluginGenerator", "1.0.0")]
[Description("Blocks selected server-to-client console commands before they are sent")]
public class CommandSendFilter : RustPlugin
{
private const string PermManage = "commandsendfilter.manage";
private PluginConfig config;
private readonly HashSet<string> blocked = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
private class PluginConfig
{
[JsonProperty("Blocked commands")]
public List<string> BlockedCommands = new List<string>
{
"example.noisycommand"
};
}
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();
}
RebuildLookup();
SaveConfig();
}
protected override void SaveConfig() => Config.WriteObject(config);
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
["Blocked"] = "Command '{0}' is now blocked from being sent to clients",
["Unblocked"] = "Command '{0}' is no longer blocked",
["AlreadyBlocked"] = "Command '{0}' is already blocked",
["NotBlocked"] = "Command '{0}' is not in the block list",
["List"] = "Blocked commands: {0}",
["Usage"] = "Usage: /cmdfilter add <command> | /cmdfilter remove <command> | /cmdfilter list",
["NoPerm"] = "You do not have permission to use this command"
}, 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(PermManage, this);
}
private void RebuildLookup()
{
blocked.Clear();
foreach (var command in config.BlockedCommands)
{
if (!string.IsNullOrEmpty(command)) blocked.Add(command);
}
}
[ChatCommand("cmdfilter")]
private void CmdFilter(BasePlayer player, string command, string[] args)
{
if (player == null) return;
if (!permission.UserHasPermission(player.UserIDString, PermManage))
{
SendReply(player, Msg("NoPerm", player.UserIDString));
return;
}
if (args == null || args.Length == 0)
{
SendReply(player, Msg("Usage", player.UserIDString));
return;
}
string action = args[0].ToLowerInvariant();
if (action == "list")
{
SendReply(player, Msg("List", player.UserIDString, string.Join(", ", config.BlockedCommands)));
return;
}
if (args.Length < 2)
{
SendReply(player, Msg("Usage", player.UserIDString));
return;
}
string target = args[1];
if (action == "add")
{
if (blocked.Contains(target))
{
SendReply(player, Msg("AlreadyBlocked", player.UserIDString, target));
return;
}
config.BlockedCommands.Add(target);
RebuildLookup();
SaveConfig();
SendReply(player, Msg("Blocked", player.UserIDString, target));
}
else if (action == "remove")
{
if (!blocked.Contains(target))
{
SendReply(player, Msg("NotBlocked", player.UserIDString, target));
return;
}
config.BlockedCommands.RemoveAll(c => string.Equals(c, target, StringComparison.OrdinalIgnoreCase));
RebuildLookup();
SaveConfig();
SendReply(player, Msg("Unblocked", player.UserIDString, target));
}
else
{
SendReply(player, Msg("Usage", player.UserIDString));
}
}
private object OnSendCommand(Network.Connection connection, string strCommand, object[] args)
{
if (string.IsNullOrEmpty(strCommand)) return null;
if (!blocked.Contains(strCommand)) return null;
// Non-null return stops the command packet from being written to the client.
return true;
}
}
}The plugin keeps a configurable block list of command names in its config. OnSendCommand receives each outgoing client console command, compares strCommand against the block list with a case-insensitive lookup, and returns a non-null value when it matches, which prevents the packet from being built. Admins can use /cmdfilter add <command> and /cmdfilter list to manage the block list at runtime; changes are written to the config file through SaveConfig. The hook body only performs a dictionary lookup and returns early, so the cost per outgoing command stays minimal. Null parameters are handled before any string work.
Common use cases
Suppress noisy effect commands
Some plugins push effect commands that clients without matching assets handle poorly. Filtering them on the server stops the packet before it reaches anyone.
Hide administrative output
Commands the server pushes to clients that reveal internal state can be dropped per command name, keeping the client console clean without patching each caller.
Audit outgoing traffic during development
Collect the command names seen during a test session and compare them with what your plugins expect to send, then use the same block list mechanism in production.
Pitfalls
Blocking chat or UI commands breaks the game feel
Chat lines and UI updates also travel through client console commands. A broad string match such as
chator an empty prefix filter will silence player-facing output.The list overload needs a separate declaration
Declaring only
Network.Connectionmisses sends addressed to aList<Network.Connection>. Add the list signature if you need to cover those paths.Fires on every outgoing command
Do not log or allocate inside this hook at scale. Use a prebuilt lookup and return early for non-matching commands.
Build a plugin with OnSendCommand
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 OnSendCommand
Generate