Skip to content
RustPluginGenerator

How to make a Rust staff chat plugin (colored [STAFF] channel)

Adds a permission-gated /a command that forwards a message only to online players holding the staffchat.use permission, prefixed with a colored [STAFF] tag. It uses one ChatCommand method plus permission checks, with all output routed through Oxide lang messages.

Global chat is visible to everyone, so staff discussions get noisy fast. A dedicated staff channel keeps moderation talk private without leaving the game. This plugin registers a single chat command, /a, that only players with the staffchat.use permission can run. When they type /a <text>, the message is wrapped in a [STAFF] prefix and sent to every connected player who also holds that permission. Running /a with no text returns a usage line instead of broadcasting an empty message, and anyone without the permission gets a denial reply. The plugin keeps no data file, timer or UI, so it is stateless and safe to reload at any time. The prefix text, its color, and the all reply strings live in the language file and config, so admins can rename the tag without touching code.

The plugin code

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

namespace Oxide.Plugins
{
    [Info("Staff Chat", "RustPluginGenerator", "1.0.0")]
    [Description("Adds a permission-gated staff chat channel via /a with a colored prefix.")]
    public class StaffChat : RustPlugin
    {
        private const string PermUse = "staffchat.use";

        private PluginConfig config;

        private class PluginConfig
        {
            [JsonProperty("Prefix")]
            public string Prefix = "[STAFF]";
            [JsonProperty("Prefix Color Hex")]
            public string PrefixColorHex = "#66ccff";
        }

        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>
            {
                ["NoPermission"] = "You do not have permission to use staff chat.",
                ["Usage"] = "Usage: /a <message>",
                ["Line"] = "{0} {1}: {2}"
            }, 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(PermUse, this);
        }

        [ChatCommand("a")]
        private void CmdStaffChat(BasePlayer player, string command, string[] args)
        {
            if (player == null) return;
            if (!permission.UserHasPermission(player.UserIDString, PermUse))
            {
                player.ChatMessage(Msg("NoPermission", player.UserIDString));
                return;
            }
            if (args == null || args.Length == 0)
            {
                player.ChatMessage(Msg("Usage", player.UserIDString));
                return;
            }

            string body = string.Join(" ", args).Trim();
            if (string.IsNullOrEmpty(body))
            {
                player.ChatMessage(Msg("Usage", player.UserIDString));
                return;
            }

            string prefix = config.PrefixColorHex.StartsWith("#")
                ? $"<color={config.PrefixColorHex}>{config.Prefix}</color>"
                : config.Prefix;

            foreach (BasePlayer target in BasePlayer.activePlayerList)
            {
                if (target == null || target.IsNpc || !target.IsConnected) continue;
                if (!permission.UserHasPermission(target.UserIDString, PermUse)) continue;
                target.ChatMessage(Msg("Line", target.UserIDString, prefix, player.displayName, body));
            }
        }

        private void Unload()
        {
            // No persistent state or timers to clean up.
        }
    }
}

Config file

Created automatically on first load at oxide/config/StaffChat.json.

StaffChat.json
{
  "Prefix": "[STAFF]",
  "Prefix Color Hex": "#66ccff"
}

Commands and permissions

Chat and console commands
CommandWhat it doesPermission
/a <message>Sends the message to online players with the staffchat.use permission. Without text it shows usage.staffchat.use
Permissions
PermissionGrants
staffchat.useReceive [STAFF] messages and use /a to send them.

How the code works

  1. Register the permission

    In Init the plugin calls permission.RegisterPermission(PermUse, this) with PermUse set to staffchat.use. The prefix must match the lowercase class name, so the const is staffchat.use. Grant it with oxide.grant user <name> staffchat.use or to a whole group with oxide.grant group admin staffchat.use. Players without it both fail to send and never receive channel output.

  2. Handle the chat command

    The [ChatCommand("a")] attribute binds a private method CmdStaffChat(BasePlayer player, string command, string[] args). It null-checks player, verifies permission.UserHasPermission(player.UserIDString, PermUse), and if it fails sends the NoPermission message. If args is null or empty it sends the Usage line. Otherwise it joins args with string.Join(" ", args) and trims the result, so the text the player typed is rebuilt exactly.

  3. Broadcast to staff only

    The method loops over BasePlayer.activePlayerList, skips NPCs with IsNpc, skips disconnected players with IsConnected, and skips anyone without the permission. For each remaining player it calls ChatMessage with the Line message formatted as <prefix> <displayName>: <message>. Because the channel shows the sender's name inline, recipients know who is speaking even though the command itself does not echo back to the sender separately.

  4. Colored prefix from config and lang

    The prefix text is the config key Prefix (default [STAFF]) and the color is Prefix Color Hex (default #66ccff). The send method wraps the tag in a Unity rich-text <color=...> tag when the hex string starts with #, otherwise it sends the tag plainly. The three reply strings live in LoadDefaultMessages under NoPermission, Usage and Line. Oxide chat renders <color> tags, so the tag appears colored in the chat box.

  5. Formatting and null safety

    Every argument is validated before use: player is checked at the top, args can be null when the command is typed alone, and target players are filtered by IsConnected and IsNpc. The helper Msg(key, userId, args) calls lang.GetMessage(key, this, userId) then string.Format. Passing the target's UserIDString lets language selection follow each recipient's client language when more than one language file is installed.

  6. Config loading and reload behavior

    LoadConfig reads the config through Config.ReadObject<PluginConfig>(); if that returns null or throws, it prints a warning, falls back to LoadDefaultConfig and saves again. SaveConfig writes the object back, so editing oxide/config/StaffChat.json and running oxide.reload StaffChat applies a new prefix or color. There are no timers or UI panels, so Unload is empty.

Install it on your server

  1. Save StaffChat.cs

    Keep the file name exactly as the class name. Oxide matches them.
  2. Upload it to the plugins folder

    Oxide: oxide/plugins/. Carbon: carbon/plugins/. The server compiles and loads it within a few seconds, no restart needed.
  3. Edit the config if you want

    On first load the default config is written to oxide/config/StaffChat.json (Carbon: carbon/configs/StaffChat.json). After editing, reload it:oxide.reload StaffChat c.reload StaffChat # Carbon
  4. Grant the permission

    Give it to every player, or swap default for a group such as vip:oxide.grant group default staffchat.use c.grant group default staffchat.use # Carbon

Variations

Each one opens the generator with a ready prompt you can tweak.

FAQ

Why don't non-staff players see the message?

The broadcast loop filters by permission.UserHasPermission(player.UserIDString, "staffchat.use") in addition to checking IsConnected and skipping NPCs. Anyone without the permission is skipped entirely, so the message never reaches their chat. Grant the permission to any group that should see the channel.

Can I rename the [STAFF] tag or change its color?

Yes. The tag text is the Prefix config key and the color is Prefix Color Hex in oxide/config/StaffChat.json. Change them, save, and run oxide.reload StaffChat. Because the tag goes through Oxide chat, Unity rich-text works, so you can also use <b> and <i> around the text if you edit the string.

Does this work on Carbon?

Yes. Carbon loads standard Oxide plugins, and this file only uses ChatCommand, permission, lang, Config and BasePlayer members that both frameworks support. Drop it in oxide/plugins and it will compile; Carbon picks it up from the same folder.

How do I install it?

Save the file as StaffChat.cs in oxide/plugins, wait for compilation, then grant the permission with oxide.grant group admin staffchat.use. Type /a test in chat as an admin to confirm delivery. Check oxide/config/StaffChat.json for the default prefix values.

Can I stop one staff member from sending while still receiving?

Not with this version: sending and receiving use one permission. Split it by adding a second const such as staffchat.see for reception and checking staffchat.use only for the send path. The CmdStaffChat method already has the send check in place, so you only adjust which permission the receive loop tests.

Customize it for your server

Change the reward, add a cooldown, restrict it to VIPs. Start from this prompt and edit anything.

Prompt: Create a Rust Oxide staff chat plugin: /a <message> permission staffchat.use, colored [STAFF] prefix, usage when empty, lang messages. Keep the prefix, general staffchat.use permission, and default config file.
Customize for my server

Edit the prompt on the next screen. 2 free plugins a month, no card.

Last updated Oct 26, 2026.

Customize staff chat

Customize