Skip to content
RustPluginGenerator

OnRfFrequencyChanged

OnRfFrequencyChanged is called after an RF device (broadcaster, receiver, detonator or pager) has already applied a new frequency set by a player.

Signature
void OnRfFrequencyChanged(RFBroadcaster rFBroadcaster, int num, BasePlayer player)

Parameters

Hook parameters
ParameterTypeDescription
rFBroadcasterRFBroadcasterThe RFBroadcaster entity whose frequency was just set. Cast to BaseEntity for position checks, or to Detonator, RFReceiver or PagerEntity when the same hook fires from those devices.
numintThe new frequency value, already clamped by RFManager.ClampFrequency for receivers and broadcasters, as typed in on the RF device.
playerBasePlayerThe BasePlayer who changed the frequency. May be null in unusual cases, so null-check before using it.

Return value

The return value is ignored. The game code has already applied the new frequency before the hook is called, so returning a value or null has no effect on the device.

How it works

This hook fires at the end of ServerSetFrequency on RFBroadcaster, RFReceiver, Detonator and PagerEntity. By the time it runs, the game has already called SetFrequency(num) and, for broadcasters, applied the 1% decay damage. A paired OnRfFrequencyChange hook fires before that and can cancel the change; this one cannot, so use it for observation, logging, or follow-up effects.

The first parameter is the device itself. Declare the specific type you care about (RFBroadcaster, RFReceiver, Detonator, PagerEntity) to only receive calls from that device class, or declare BaseEntity to catch all four. num is the frequency value the device now holds, clamped through RFManager. player is the person who sent the change; it is normally the entity owner interacting with the device UI.

Because the frequency is already committed, this hook is the right place to react: announce a hijacked broadcaster, cancel scripts that depend on the old frequency, or apply a cost/cooldown. It does not fire when the server sets a frequency directly without a player message.

Other signatures

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

  • void OnRfFrequencyChanged(RFReceiver rFReceiver, int num, BasePlayer player)
  • void OnRfFrequencyChanged(Detonator detonator, int freq, BasePlayer player)
  • void OnRfFrequencyChanged(PagerEntity pagerEntity, int num, BasePlayer player)

Example plugin: Announce frequency changes on player-owned broadcasters

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

namespace Oxide.Plugins
{
    [Info("RfFrequencyAnnouncer", "RustPluginGenerator", "1.0.0")]
    [Description("Announces RF broadcaster frequency changes to the owner and to opted-in players")]
    public class RfFrequencyAnnouncer : RustPlugin
    {
        private const string PermAnnounce = "rffrequencyannouncer.announce";

        private PluginConfig config;
        private readonly Dictionary<ulong, int> lastFrequency = new Dictionary<ulong, int>();

        private class PluginConfig
        {
            [JsonProperty("Announce to owner only")]
            public bool OwnerOnly { get; set; } = true;

            [JsonProperty("Chat prefix")]
            public string Prefix { get; set; } = "<color=#ce422b>[RF]</color>";
        }

        protected override void LoadDefaultConfig() => config = new PluginConfig();

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                config = Config.ReadObject<PluginConfig>();
                if (config == null) throw new System.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>
            {
                ["Changed"] = "Broadcaster frequency changed: {0} -> {1}",
                ["ChangedOwn"] = "You retuned a broadcaster from {0} to {1}"
            }, 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(PermAnnounce, this);
        }

        private void OnRfFrequencyChanged(RFBroadcaster rFBroadcaster, int num, BasePlayer player)
        {
            if (rFBroadcaster == null || player == null) return;

            ulong deviceId = rFBroadcaster.net.ID.Value;
            int previous;
            if (!lastFrequency.TryGetValue(deviceId, out previous))
            {
                lastFrequency[deviceId] = num;
                return;
            }
            if (previous == num) return;
            lastFrequency[deviceId] = num;

            BasePlayer owner = BasePlayer.FindByID(rFBroadcaster.OwnerID);
            if (owner == null) return;

            string message = Msg("Changed", player.UserIDString, previous, num);
            if (config.OwnerOnly)
            {
                owner.ChatMessage(config.Prefix + " " + message);
                return;
            }

            foreach (BasePlayer target in BasePlayer.activePlayerList)
            {
                if (target == null || !target.IsConnected) continue;
                if (target == owner || permission.UserHasPermission(target.UserIDString, PermAnnounce))
                {
                    target.ChatMessage(config.Prefix + " " + Msg("ChangedOwn", target.UserIDString, previous, num));
                }
            }
        }

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

The plugin listens only to broadcaster frequency changes by declaring the RFBroadcaster parameter type, so receiver, detonator and pager calls are skipped by Oxide dispatch. On each change it resolves the device's OwnerID, looks up the owning player and sends a chat message showing the old and new frequency. It keeps a per-device map of the previous frequency in memory and refreshes it each time, and ignores NPC or unowned devices. Server admins can toggle the feature with a config flag, and the radio.announce permission lets non-admins opt in. Data is not persisted because the map is only used for the delta message.

Common use cases

  • Audit broadcaster hijacks

    Log every frequency change on a player-owned broadcaster with the owner and the new value so admins can trace griefing after the fact.

  • Charge for retuning detonators

    Use the Detonator overload with a referenced Economics plugin to deduct a small fee each time a player changes a detonator's frequency.

  • Sync server-side devices

    When a receiver is retuned, update a linked broadcaster or pager so paired trap setups stay on matching frequencies.

Pitfalls

  • Hook does not fire on cancel

    If another plugin returns non-null from OnRfFrequencyChange, the frequency is never applied and OnRfFrequencyChanged is skipped. Do not assume every attempt lands here.

  • player can be null

    Server-driven changes may come through without a player. Null-check the parameter before using UserIDString or sending chat.

  • Four device types share the name

    If you declare BaseEntity you receive calls from broadcasters, receivers, detonators and pagers alike. Cast with as or declare the specific type to avoid handling the wrong device.

Build a plugin with OnRfFrequencyChanged

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

Prompt: Audit broadcaster hijacks using the OnRfFrequencyChanged 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 OnRfFrequencyChanged

Generate