Skip to content
RustPluginGenerator

OnPhoneDialFail

OnPhoneDialFail is called when a telephone call fails to connect, right before the game resets the phone to idle and tells the client why the dial failed.

Signature
object OnPhoneDialFail(PhoneController phoneController, Telephone.DialFailReason reason, BasePlayer currentPlayer)

Parameters

Hook parameters
ParameterTypeDescription
phoneControllerPhoneControllerThe PhoneController of the telephone handset that attempted the call. Use it to reach the owning entity via phoneController.baseEntity and to inspect activeCallTo or the dialed number.
reasonTelephone.DialFailReasonA Telephone.DialFailReason value explaining why the call could not be placed, such as no answer, busy, or a blocked/invalid number. Compare it against the enum members to branch on the cause.
currentPlayerBasePlayerThe BasePlayer holding the phone when the dial failed. May be null if the controller has no player owner, so null-check it before using player APIs.

Return value

Returning null lets the game proceed: the phone is set to Idle, the client is told the dial failed with the given reason, the active call is cleared, and timeouts are cancelled. Returning any non-null value skips that entire block, so the phone stays in its current call state and the client receives no failure RPC.

How it works

This hook fires inside PhoneController.OnDialFailed, which the game runs when a dial attempt cannot be completed, for example an unanswered call, a busy line, or a rejected number. It is the single place where a failed call is handled, so it runs once per failed dial.

The phoneController parameter is the controller instance and gives access to baseEntity and activeCallTo. reason is a Telephone.DialFailReason you can compare against the enum members to distinguish causes. currentPlayer is the player who placed the call; it can be null, so check it before reading player data or sending messages.

The hook is dispatched normally, so declaring currentPlayer as a more specific type only narrows calls where the argument is that type. Since the argument is a plain BasePlayer, keep the declared type as-is unless you intentionally want to skip non-matching owners. Return a value to suppress the default failure handling. Because the hook fires rarely, it is safe to log or notify here, but avoid expensive work that could stall the network thread.

Example plugin: Log and notify players when a phone call fails

PhoneDialFailNotifier.cs
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("Phone Dial Fail Notifier", "RustPluginGenerator", "1.0.0")]
    [Description("Sends a localized chat message to a player when their telephone call fails to connect")]
    public class PhoneDialFailNotifier : RustPlugin
    {
        private PluginConfig config;

        public class PluginConfig
        {
            [JsonProperty("Notify the caller on failure")]
            public bool NotifyCaller { get; set; } = true;

            [JsonProperty("Prefix")]
            public string Prefix { get; set; } = "[Phone]";
        }

        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>
            {
                ["Fail.NoAnswer"] = "The call went unanswered.",
                ["Fail.Busy"] = "The line is busy.",
                ["Fail.Blocked"] = "That number cannot be reached.",
                ["Fail.Generic"] = "The call failed to connect ({0}).",
                ["Reply"] = "{0} {1}"
            }, this);
        }

        private string Msg(string key, string userId = null, params object[] args) =>
            string.Format(lang.GetMessage(key, this, userId), args);

        private object OnPhoneDialFail(PhoneController phoneController, Telephone.DialFailReason reason, BasePlayer currentPlayer)
        {
            if (!config.NotifyCaller || currentPlayer == null) return null;

            string text;
            switch (reason.ToString())
            {
                case "NoAnswer":
                case "TimeOut":
                    text = Msg("Fail.NoAnswer", currentPlayer.UserIDString);
                    break;
                case "Busy":
                    text = Msg("Fail.Busy", currentPlayer.UserIDString);
                    break;
                case "Blocked":
                case "InvalidNumber":
                    text = Msg("Fail.Blocked", currentPlayer.UserIDString);
                    break;
                default:
                    text = Msg("Fail.Generic", currentPlayer.UserIDString, reason);
                    break;
            }

            currentPlayer.ChatMessage(Msg("Reply", currentPlayer.UserIDString, config.Prefix, text));
            return null;
        }
    }
}

The plugin listens to OnPhoneDialFail and, when the hook fires, builds a short message from the Telephone.DialFailReason value using a switch statement and localized strings. It checks currentPlayer != null and the NotifyCaller config option before sending the message. The message is prefixed with the configurable Prefix and sent only to the caller via ChatMessage. The hook always returns null so the game continues its normal failure handling; the plugin only adds context on top of the vanilla behavior.

Common use cases

  • Explain why a call failed

    Send the caller a localized chat message that maps the dial fail reason to plain language, such as busy or unreachable.

  • Log phone activity for admins

    Write failed dial attempts to the data folder with the player name, controller ID and reason so admins can review abuse.

  • Custom rate limiting messages

    When your own dial-tracking logic rejects a call and forces a failure, use this hook to tell the player the specific limit they hit.

Pitfalls

  • Returning non-null suppresses reset

    Any non-null return from the hook skips the phone reset and the client failure RPC, leaving the phone stuck in its call state. Only return a value if you deliberately take over recovery.

  • currentPlayer can be null

    Controllers without an owning player hand back null for currentPlayer. Always guard before reading UserIDString or sending chat.

  • Do not assume every failure is player-driven

    The dial can fail for reasons unrelated to the caller's intent, such as line state changes. Branch on reason rather than assuming a specific cause.

Build a plugin with OnPhoneDialFail

Describe what should happen and get a compiled plugin that uses this hook.

Prompt: Explain why a call failed using the OnPhoneDialFail 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 OnPhoneDialFail

Generate