CanReceiveCall
CanReceiveCall is called when the server checks whether a placed telephone is able to accept an incoming call, before the power requirement and other built-in checks run. Returning false blocks the call from ringing that phone.
object CanReceiveCall(PhoneController phoneController)Parameters
| Parameter | Type | Description |
|---|---|---|
phoneController | PhoneController | The PhoneController entity being checked, i.e. the telephone that is about to receive an incoming call. Its OwnerID identifies the player who placed the phone, and its position tells you where the phone is physically located. |
Return value
Return null (or nothing in a void-style helper) to let the game continue with its own checks, including the power requirement. Return a bool to override that path entirely: true makes CanReceiveCall report success and false makes it fail, so a false return stops the phone from ringing even if it is powered.
How it works
The hook fires inside PhoneController.CanReceiveCall, the game method that decides if a telephone may ring. The server calls it whenever a call is being routed to a specific phone, so it runs once per receiving phone per dial attempt, before the game checks whether the phone is powered (RequirePower) and before it applies its own vanilla conditions.
The single parameter is the PhoneController for the receiving phone. Read phoneController.OwnerID to find the player who placed it, phoneController.transform.position to know where it stands, or cast it to BaseEntity to inspect flags and building privilege. You can also look up whether the owner is connected, whether they are in a team targeting the caller, or whether the phone is in a restricted zone.
Oxide matches hook methods by parameter type. Declaring BaseEntity or BaseNetworkable instead of PhoneController would still receive the call, but a more specific type such as a hypothetical subclass would not, so keep PhoneController for reliability. The hook is not fired on a timer, only on live call routing, so it stays cheap even on busy servers.
Return true to force acceptance regardless of power, false to reject, or null to defer to vanilla logic.
Example plugin: Block calls to phones in building-blocked zones
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace Oxide.Plugins
{
[Info("Phone Zone Blocker", "RustPluginGenerator", "1.0.0")]
[Description("Blocks incoming phone calls to phones placed inside building-blocked zones unless the owner has bypass permission.")]
public class PhoneZoneBlocker : RustPlugin
{
private const string PermBypass = "phonezoneblocker.bypass";
private PluginConfig config;
private class PluginConfig
{
[JsonProperty("Block calls inside building-blocked zones")]
public bool BlockInBlockedZones { get; set; } = true;
}
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>
{
["Toggled"] = "Phone zone blocking is now {0}.",
["State"] = "Phone zone blocking is currently {0}."
}, 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 CanReceiveCall(PhoneController phoneController)
{
if (phoneController == null || !config.BlockInBlockedZones) return null;
// Find the physical phone entity associated with the controller
var phone = phoneController.GetComponent<BaseEntity>();
if (phone == null) phone = phoneController.GetComponentInParent<BaseEntity>();
if (phone == null || phone.IsDestroyed) return null;
ulong ownerId = phone.OwnerID;
if (ownerId != 0 && permission.UserHasPermission(ownerId.ToString(), PermBypass))
return null;
BasePlayer owner = BasePlayer.FindByID(ownerId);
if (owner != null && owner.IsBuildingBlocked())
return false;
return null;
}
[ChatCommand("phoneblock")]
private void CmdPhoneBlock(BasePlayer player, string command, string[] args)
{
if (player == null || !player.IsAdmin) return;
config.BlockInBlockedZones = !config.BlockInBlockedZones;
SaveConfig();
string state = config.BlockInBlockedZones ? "enabled" : "disabled";
SendReply(player, Msg("Toggled", player.UserIDString, state));
}
}
}The plugin lets admins toggle whether phones whose owner is building-blocked may receive calls. In CanReceiveCall it finds the phone entity from the PhoneController, reads its OwnerID, and if that owner has the bypass permission returns null so vanilla logic runs. Otherwise it resolves the owner with BasePlayer.FindByID and, when the owner is online and IsBuildingBlocked() is true and the feature is enabled, returns false. The flag is stored in config so it survives restarts, and the phoneblock chat command flips it with a language message to confirm. Returning null everywhere else keeps the default power and connection checks intact.
Common use cases
Restrict phones to a whitelist of owners
Only let phones belonging to members of a specific permission group ring, so public telephones placed by other players are silent. Return false for every other owner.
Disable incoming calls during a scheduled event
Track an event flag in plugin state and return false while it is active, then return null once the event ends so normal power checks resume.
Ignore phones whose owner is offline
Use BasePlayer.FindByID on OwnerID, and if the player is not connected return false to prevent ringing an empty base and wasting the caller's dial slot.
Pitfalls
Returning true bypasses power checks
Because the hook runs before the power check, returning true lets an unpowered phone ring. Only return true when you actually want to override the vanilla requirement.
null is not the same as false
Returning null keeps default behavior and lets the power test run. Returning false short-circuits everything, so use it deliberately rather than as a default.
OwnerID is zero on unowned phones
Phones spawned by admins or plugins may have OwnerID 0, so guard lookups and permission checks against that before rejecting or allowing the call.
Build a plugin with CanReceiveCall
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 CanReceiveCall
Generate