Skip to content
RustPluginGenerator

OnDigitalClockRingStop

OnDigitalClockRingStop is called when a DigitalClock's alarm finishes and the clock is about to stop ringing. Returning a non-null value blocks the default stop behavior.

Signature
object OnDigitalClockRingStop(DigitalClock digitalClock)

Parameters

Hook parameters
ParameterTypeDescription
digitalClockDigitalClockThe DigitalClock entity that is about to stop ringing. Use it to read its position, owner, net.ID or IO connections and to send network updates or effects.

Return value

Return null (or nothing) to let the game clear isRinging, send the stop RPC and mark the clock dirty. Returning any non-null value skips that entire block, so the clock stays in its ringing state and clients are not told to stop.

How it works

Oxide fires this hook inside DigitalClock.StopRinging, right before the clock clears its ringing state: it sets isRinging to false, sends the RPC_StopRinging client RPC and marks the entity dirty. This happens when the configured alarm window elapses, not when a player interacts with the clock.

The single digitalClock parameter is the DigitalClock entity itself. From it you can read net.ID.Value, OwnerID, transform.position, IsDestroyed, the attached power/IO state, and any custom data you stored earlier in OnDigitalClockRing.

Oxide matches your hook method by checking that the argument is an instance of the declared parameter type. Declaring DigitalClock (as in the signature) is the only useful option here; declaring a broader type such as BaseEntity would also match but gives no extra calls.

Because the hook only fires on the edge where ringing ends, it is cheap to do work here: send effects, notify the owner, log the event, or cancel the stop entirely by returning a non-null value so the clock keeps ringing. The clock is still ringing at the point the hook runs, so IsDestroyed checks matter if a clock is killed mid-alarm.

Example plugin: Notify the owner when a digital clock alarm ends

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

namespace Oxide.Plugins
{
    [Info("Digital Clock Alarm Notifier", "RustPluginGenerator", "1.0.0")]
    [Description("Notifies the owner in chat when a deployed digital clock stops ringing")]
    public class DigitalClockAlarmNotifier : RustPlugin
    {
        private const string PermNotify = "digitalclockalarmnotifier.notify";

        private PluginConfig config;
        private readonly Dictionary<ulong, float> lastNotify = new Dictionary<ulong, float>();

        private class PluginConfig
        {
            [JsonProperty("Cooldown between notifications (seconds)")]
            public float Cooldown = 15f;

            [JsonProperty("Play sound at the clock")]
            public bool PlaySound = 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>
            {
                ["AlarmStopped"] = "Your digital clock at {0}m from you stopped ringing."
            }, this);
        }

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

        private void Init()
        {
            permission.RegisterPermission(PermNotify, this);
        }

        private object OnDigitalClockRingStop(DigitalClock digitalClock)
        {
            if (digitalClock == null || digitalClock.IsDestroyed) return null;
            if (digitalClock.OwnerID == 0) return null;

            var player = BasePlayer.FindByID(digitalClock.OwnerID);
            if (player == null || !player.IsConnected) return null;
            if (!permission.UserHasPermission(player.UserIDString, PermNotify)) return null;

            float now = UnityEngine.Time.realtimeSinceStartup;
            float last;
            if (lastNotify.TryGetValue(player.userID.Get(), out last) && now - last < config.Cooldown)
                return null;
            lastNotify[player.userID.Get()] = now;

            int distance = Mathf.RoundToInt(Vector3.Distance(player.transform.position, digitalClock.transform.position));
            player.ChatMessage(Msg("AlarmStopped", player.UserIDString, distance));

            if (config.PlaySound)
                Effect.server.Run("assets/bundled/prefabs/fx/notice/loot.drag.grab.fx.prefab", digitalClock.transform.position);

            return null;
        }

        private void Unload()
        {
            lastNotify.Clear();
        }
    }
}

The plugin stores a configurable message and cooldown, then hooks OnDigitalClockRingStop. Each time a clock stops ringing it resolves the owner through OwnerID and BasePlayer.FindByID, checks the cooldown dictionary keyed by player id, and sends the chat message through the language file with the clock's distance from the player. A small sound effect is played at the clock so nearby players hear the alarm end. Cooldowns are pruned by expiry on each call so the dictionary does not grow without bound, and the plugin always returns null so the game still performs its normal stop logic.

Common use cases

  • Alarm end notification

    Chat or console-message the clock's owner when an alarm finishes so they know the timer elapsed without standing next to the clock.

  • Audit and logging

    Record each ringing cycle with the clock's position and owner to data files for troubleshooting base circuits and timer chains.

  • Keep alarms ringing as a punishment

    Return a non-null value to skip the stop block and leave the clock ringing, for example when a raid or event rule forbids silencing alarms.

Pitfalls

  • Returning non-null freezes the clock

    Any non-null return prevents isRinging from being cleared and the RPC from being sent, so the clock keeps ringing indefinitely. Only do this deliberately.

  • The clock may be destroyed mid-alarm

    If the entity was killed while ringing, the hook can still fire. Check digitalClock == null || digitalClock.IsDestroyed before sending effects or network updates.

  • OwnerID is zero for unowned clocks

    Deployed outdoors without a tool cupboard owner, OwnerID can be 0. Guard BasePlayer.FindByID with a zero check to avoid wasted lookups.

Build a plugin with OnDigitalClockRingStop

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

Prompt: Alarm end notification using the OnDigitalClockRingStop 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 OnDigitalClockRingStop

Generate