OnRfBroadcasterAdded
OnRfBroadcasterAdded is called when an RF object is registered as a broadcaster on a frequency, right after it is added to that frequency's broadcaster set and before listeners are notified. It fires once per successful addition, not on every broadcast.
void OnRfBroadcasterAdded(IRFObject obj, int frequency)Parameters
| Parameter | Type | Description |
|---|---|---|
obj | IRFObject | The RF broadcaster being registered, as an IRFObject. Cast it to the concrete type (BaseEntity, IOEntity, an RF receiver or transmitter component's entity) to read its position, owner or net ID. |
frequency | int | The RF channel the broadcaster was added to, an integer in the RF range (0-9999). Use it to track which channel became active and who is emitting on it. |
Return value
The return value is ignored. Returning null or any other value has no effect on the registration, the broadcaster is added and listeners are updated as usual.
How it works
The hook fires inside RFManager.AddBroadcaster, immediately after the new object is inserted into the broadcaster set for that frequency. This happens when an RF-emitting entity (a transmitter, an IO entity wired to an RF output, a boombox or similar device) first starts emitting on a channel, not on each transmission tick. Because the call sits after broadcasterSet.Add(obj) succeeds, duplicate additions of the same object to the same frequency do not fire the hook again.
Use frequency to log or meter which channels are active, and obj to identify the emitter. IRFObject is an interface; if you need entity data such as position, owner or net ID, cast to the concrete type you expect and null-check the result. Declaring obj as a more specific type is not useful here because the game passes the interface reference, so cast inside the method instead. The hook fires after the manager has registered the broadcaster but before UpdateListenersForFrequency runs for a newly active channel, so it is safe to read state but do not expect listener updates to have happened yet. Keep the handler cheap: it can fire for every device on a busy server, so avoid logging every call.
Example plugin: Warn when too many broadcasters share one channel
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("RfChannelWatcher", "RustPluginGenerator", "1.0.0")]
[Description("Counts RF broadcasters per frequency and warns when a channel gets crowded")]
public class RfChannelWatcher : RustPlugin
{
private const string PermUse = "rfchannelwatcher.count";
private PluginConfig config;
private readonly Dictionary<int, HashSet<ulong>> broadcasters = new Dictionary<int, HashSet<ulong>>();
private readonly HashSet<int> warned = new HashSet<int>();
private class PluginConfig
{
[JsonProperty("Broadcaster warning threshold")]
public int Threshold = 4;
}
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>
{
["NoChannel"] = "Usage: /rfcount <frequency>",
["Count"] = "Frequency {0}: {1} broadcaster(s) registered.",
["Denied"] = "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(PermUse, this);
}
[ChatCommand("rfcount")]
private void CmdRfCount(BasePlayer player, string command, string[] args)
{
if (player == null) return;
if (!permission.UserHasPermission(player.UserIDString, PermUse))
{
player.ChatMessage(Msg("Denied", player.UserIDString));
return;
}
int frequency;
if (args.Length < 1 || !int.TryParse(args[0], out frequency))
{
player.ChatMessage(Msg("NoChannel", player.UserIDString));
return;
}
HashSet<ulong> set;
int count = broadcasters.TryGetValue(frequency, out set) ? set.Count : 0;
player.ChatMessage(Msg("Count", player.UserIDString, frequency, count));
}
private void OnRfBroadcasterAdded(IRFObject obj, int frequency)
{
if (obj == null) return;
BaseEntity entity = obj as BaseEntity;
if (entity == null || entity.net == null) return;
HashSet<ulong> set;
if (!broadcasters.TryGetValue(frequency, out set))
{
set = new HashSet<ulong>();
broadcasters[frequency] = set;
}
if (!set.Add(entity.net.ID.Value)) return;
if (set.Count > config.Threshold && warned.Add(frequency))
{
PrintWarning(string.Format("Frequency {0} now has {1} RF broadcasters registered (threshold {2}).", frequency, set.Count, config.Threshold));
}
}
private void OnRfBroadcasterRemoved(IRFObject obj, int frequency)
{
if (obj == null) return;
BaseEntity entity = obj as BaseEntity;
if (entity == null || entity.net == null) return;
HashSet<ulong> set;
if (!broadcasters.TryGetValue(frequency, out set)) return;
set.Remove(entity.net.ID.Value);
if (set.Count == 0)
{
broadcasters.Remove(frequency);
warned.Remove(frequency);
}
}
private void Unload()
{
broadcasters.Clear();
warned.Clear();
}
}
}The plugin keeps a count of active broadcasters per frequency. Each time OnRfBroadcasterAdded fires it records the entity's network ID in a tracked set for that channel, which filters out repeat notifications for the same object. Deploy the watcher with the rfchannelwatcher.count permission and run /rfcount to print the current number of emitters per frequency to chat. When a channel goes over the configured threshold for the first time, the plugin logs a warning with the frequency and count so admins can spot a group stacking transmitters or a misconfigured IO circuit. Counts are dropped when a broadcaster is removed via OnRfBroadcasterRemoved, keeping the table accurate without polling.
Common use cases
Detect channel crowding
Track how many devices emit on each RF frequency and warn when a single channel exceeds a configured limit, which usually points at a wiring mistake or an attempt to jam a channel.
Owner-based RF auditing
Cast the IRFObject to a BaseEntity, read OwnerID and store a per-player record of which frequencies they transmit on, useful for investigating griefing with remote-controlled traps.
Activate channel telemetry
Mark a frequency as live the first time a broadcaster is added, then show active channels on an admin panel or relay the change to a Discord webhook plugin.
Pitfalls
IRFObject is not always a BaseEntity
Some RF objects are not entities, so an
as BaseEntitycast can return null. Always null-check before reading OwnerID or transform.Fires on registration, not on transmit
The hook runs once when the device is added to the frequency's broadcaster set. Do not use it as a per-burst trigger, and do not expect it for every RF pulse.
Duplicate adds are silent
Because the game only calls the hook when the object is newly inserted into the set, re-adding the same object to the same frequency produces no call. Track removals to keep your own counts correct.
Build a plugin with OnRfBroadcasterAdded
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 OnRfBroadcasterAdded
Generate