OnPhoneAnswer
OnPhoneAnswer is called when a player answers an incoming phone call, right before the call is connected. Returning a non-null value cancels the connection while the ring state on the answering phone is already cleared.
object OnPhoneAnswer(PhoneController phoneController, PhoneController activeCallTo)Parameters
| Parameter | Type | Description |
|---|---|---|
phoneController | PhoneController | The PhoneController of the player who is answering, i.e. the phone entity receiving the AnswerPhone message. Use it to get the answering player via GetOwnerPlayer(). |
activeCallTo | PhoneController | The PhoneController on the other end of the pending call. Null-check it before reading its owner; this is the phone that will start ringing/connecting once the call begins. |
Return value
Return null (or nothing) to let the call connect normally. Any non-null return stops the rest of AnswerPhone, so the call never begins and OnPhoneAnswered does not fire.
How it works
The hook fires inside PhoneController.AnswerPhone, after the answering phone cancels its dial timeout and before UpdateServerPlayer, BeginCall and the paired activeCallTo.BeginCall() run. It only fires when activeCallTo is not null, meaning there is a live incoming call to accept. Use phoneController to identify the answering phone and phoneController.GetOwnerPlayer() for the player; activeCallTo is the caller's phone. This is the last place to block a call after the target has pressed answer, for example to enforce proximity between phones, a phone ban list, or a clan-only rule. Declaring both parameters as PhoneController matches the dispatch exactly. Because the ring state has already been cleared, returning non-null leaves both players without an active call; there is no need to close anything yourself. Pair it with OnPhoneAnswered (fires after the call is actually connected) when you want to react to successful calls only.
Example plugin: Block calls between phones that are far apart
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Phone Proximity", "RustPluginGenerator", "1.0.0")]
[Description("Blocks phone calls between phones that are farther apart than the configured range")]
public class PhoneProximity : RustPlugin
{
private const string PermBypass = "phoneproximity.bypass";
private PluginConfig config;
private class PluginConfig
{
[JsonProperty("Maximum call distance (meters)")]
public float MaxDistance = 150f;
}
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>
{
["TooFar"] = "The other phone is out of range (max {0} m).",
["NoOwner"] = "This phone is not linked to a player."
}, 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 BasePlayer GetPhoneOwner(PhoneController phone)
{
if (phone == null) return null;
BaseEntity entity = phone.GetComponent<BaseEntity>();
if (entity == null || entity.OwnerID == 0) return null;
return BasePlayer.FindByID(entity.OwnerID);
}
private object OnPhoneAnswer(PhoneController phoneController, PhoneController activeCallTo)
{
if (phoneController == null || activeCallTo == null)
return null;
BasePlayer answerer = GetPhoneOwner(phoneController);
if (answerer == null || permission.UserHasPermission(answerer.UserIDString, PermBypass))
return null;
BasePlayer caller = GetPhoneOwner(activeCallTo);
if (caller == null)
return null;
float distance = Vector3.Distance(phoneController.transform.position, activeCallTo.transform.position);
if (distance <= config.MaxDistance)
return null;
answerer.ChatMessage(Msg("TooFar", answerer.UserIDString, Mathf.RoundToInt(config.MaxDistance)));
return true;
}
}
}The plugin rejects phone connections when the two phone entities are farther apart than the configured distance, which curbs distant relay abuse. OnPhoneAnswer reads both PhoneController transforms and compares them with Vector3.Distance. On a violation it returns a non-null value to cancel the connection and sends a localized message to the answering player. The bypass permission phoneproximity.bypass exempts the answering player from the distance check. A config field sets the maximum range, and messages are registered in lang so server owners can translate the warning.
Common use cases
Range limits on calls
Deny connection when the two phones are too far apart, forcing players to use them within a base or region.
Ban list enforcement
Return non-null when either phone's owner is on a call ban list, preventing a muted or jailed player from accepting calls.
Team-only lines
Compare the owners'
currentTeamvalues and cancel the call when they differ, creating private squad-only phone networks.
Pitfalls
The ring already stopped
AnswerPhonecancels the dial timeout before the hook runs. A cancelled call leaves the answering player without the ring, so show a message explaining why.Hooks only fire with a live caller
The injection is inside an
activeCallTo != nullblock, so cancelled or expired calls never reach this hook. Do not rely on it to clean up abandoned calls.Owner may be null
GetOwnerPlayer()can return null if the phone was dropped or its owner disconnected. Null-check both owners before reading player data.
Build a plugin with OnPhoneAnswer
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 OnPhoneAnswer
Generate