OnRfListenerRemove
OnRfListenerRemove is called when an RF listener is about to be detached from a frequency channel in RFManager.RemoveListener. Returning a non-null value cancels the removal.
object OnRfListenerRemove(IRFObject rfObject, int frequency)Parameters
| Parameter | Type | Description |
|---|---|---|
rfObject | IRFObject | The RF listener entity being detached from the frequency, such as an RF receiver, a powered door, or any other IRFObject implementation. It can be cast to BaseEntity to reach owner, position, and networking members. |
frequency | int | The already-clamped RF frequency channel (int) the object is being removed from. This is the value after RFManager.ClampFrequency runs, so it is always within the valid RF range. |
Return value
Returning null (or nothing, by falling off the end) lets the removal proceed: the listener is removed from the set, RFSignalUpdate(false) runs, and OnRfListenerRemoved fires. Returning any non-null value stops the original code path, so the listener stays attached to the frequency and no further hooks run for that call.
How it works
This hook fires inside RFManager.RemoveListener(int frequency, IRFObject obj), which the game calls whenever an object should stop receiving RF signal on a channel. That covers normal gameplay paths like a player clearing the frequency on an RF receiver, a receiver being picked up or destroyed, a door or trap losing its RF link, or a broadcaster's paired listener being reconfigured. The frequency arrives already clamped, so you never see out-of-range numbers here.
The rfObject parameter is the IRFObject being unlinked; cast it to BaseEntity to read OwnerID, transform.position, or prefab name. Declaring BaseEntity instead of IRFObject is not valid here, so keep the interface type and use as BaseEntity when you need entity data.
Use this hook to veto or log unlinking: block players from removing a listener from a protected channel, keep admin-placed receivers permanently tuned, or record channel changes for auditing. Because it runs for every listener removal on the server, keep work inside it cheap and avoid logging to console. Pair it with OnRfListenerRemoved if you only care about completed removals.
Example plugin: Keep receivers locked to protected RF channels
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Rf Channel Guard", "RustPluginGenerator", "1.0.0")]
[Description("Blocks RF listeners from being removed from protected frequencies unless the player has bypass permission.")]
public class RfChannelGuard : RustPlugin
{
private const string PermBypass = "rfchannelguard.bypass";
private PluginConfig config;
private class PluginConfig
{
[JsonProperty("Protected frequencies")]
public List<int> ProtectedFrequencies = new List<int> { 101, 202 };
[JsonProperty("Notify blocked players in chat")]
public bool NotifyPlayers = true;
}
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"] = "Frequency {0} is protected. A receiver can not be detached from it."
}, 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 OnRfListenerRemove(IRFObject rfObject, int frequency)
{
if (rfObject == null || config.ProtectedFrequencies == null) return null;
if (!config.ProtectedFrequencies.Contains(frequency)) return null;
var entity = rfObject as BaseEntity;
if (entity == null) return null;
var ownerId = entity.OwnerID;
// Server-owned listeners (OwnerID 0) are always protected.
if (ownerId != 0)
{
var ownerIdString = ownerId.ToString();
if (permission.UserHasPermission(ownerIdString, PermBypass)) return null;
if (config.NotifyPlayers)
{
var player = BasePlayer.FindByID(ownerId);
if (player != null && player.IsConnected)
{
player.ChatMessage(Msg("Blocked", ownerIdString, frequency));
}
}
}
return false;
}
}
}The plugin defines a list of protected frequencies in its config, defaulting to 101 and 202. Init registers the admin permission rfchannelguard.bypass. OnRfListenerRemove checks the clamped frequency against the protected set; if it matches, it casts rfObject to BaseEntity and reads OwnerID. Players without the bypass permission and entities not owned by the server (OwnerID 0) get their removal blocked by returning false, while admins and server-owned entities are allowed through. A config option switches on a chat notice so affected players understand why their receiver stayed tuned. OnRfListenerRemoved is not needed here; the guard only intercepts the pending removal.
Common use cases
Lock admin-controlled RF frequencies
Keep event or trap wiring intact by refusing removal on a fixed set of channels, while letting trusted staff with a permission bypass the block.
Protect server-owned receivers
Check the cast
BaseEntity.OwnerIDand block removal only for entity-owned listeners (OwnerID 0), so player-built and player-tuned receivers still behave normally.Audit RF channel changes
Record which listener left which frequency for later review, for example when investigating griefing with remote-controlled doors or traps.
Pitfalls
Fires on every removal path
Destroyed entities, picked-up receivers, and quiet reconfigurations all reach this hook, not just a player clearing the frequency. Do not send chat messages or console output unconditionally.
Blocking can orphan listeners
A non-null return keeps the object in the listener set even when the entity is being destroyed, so the game may retain a stale reference. Restrict blocking to cases where the entity stays alive.
The frequency is already clamped
You receive the post-ClampFrequency value, so comparing against raw player input or config entries outside the valid RF range will silently never match.
Build a plugin with OnRfListenerRemove
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 OnRfListenerRemove
Generate