Skip to content
RustPluginGenerator

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.

Signature
object OnPhoneAnswer(PhoneController phoneController, PhoneController activeCallTo)

Parameters

Hook parameters
ParameterTypeDescription
phoneControllerPhoneControllerThe 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().
activeCallToPhoneControllerThe 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

PhoneProximity.cs
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' currentTeam values and cancel the call when they differ, creating private squad-only phone networks.

Pitfalls

  • The ring already stopped

    AnswerPhone cancels 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 != null block, 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.

Prompt: Range limits on calls using the OnPhoneAnswer 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 OnPhoneAnswer

Generate