Skip to content
RustPluginGenerator

OnRecyclerToggle

OnRecyclerToggle is called when a player tries to turn a Recycler on or off from the machine's UI. Returning a non-null value cancels the toggle.

Signature
object OnRecyclerToggle(Recycler recycler, BasePlayer player)

Parameters

Hook parameters
ParameterTypeDescription
recyclerRecyclerThe Recycler entity the player is trying to switch. Its position and network ID identify which recycling machine is involved.
playerBasePlayerThe BasePlayer who sent the switch request. Use it for permission checks, cooldowns or feedback messages.

Return value

Returning null (or nothing) lets the toggle continue through the vanilla checks. Returning any non-null value stops SVSwitch immediately, so the recycler does not change state and no start/stop logic runs.

How it works

The hook fires inside Recycler.SVSwitch, the server method that handles the client's on/off RPC for a recycler. The server first reads the requested state and bails out if the recycler is already in that state, so the hook only runs for a real state change request from a connected player. It runs before any of the vanilla guards: the onlyOneUser loot-source check, the unpowered check and the HasRecyclable() check. Because of that, blocking the hook blocks every toggle regardless of power or contents.

The recycler parameter is the machine; player is the requesting player. You normally do not need to declare either type more specifically, since an entity-backed recycler is already a Recycler and the caller is a real BasePlayer. Declaring the parameter as a narrower subtype such as a custom recycler class would make Oxide skip the call for other recyclers, which is rarely what you want here.

Use it to enforce permissions, per-player cooldowns, restricted zones or a limited number of active recyclers. Keep the hook body fast: it runs on every toggle request and a blocked return simply leaves the recycler in its current state.

Example plugin: Permission-gated recycler with a per-player cooldown

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

namespace Oxide.Plugins
{
    [Info("Recycler Toggle Guard", "RustPluginGenerator", "1.0.0")]
    [Description("Restricts recycler toggling by permission and per-player cooldown.")]
    public class RecyclerToggleGuard : RustPlugin
    {
        private const string PermUse = "recyclertoggleguard.use";

        private PluginConfig config;
        private readonly Dictionary<ulong, float> lastUse = new Dictionary<ulong, float>();
        private Timer cleanupTimer;

        private class PluginConfig
        {
            [JsonProperty("Require permission")]
            public bool RequirePermission { get; set; } = true;

            [JsonProperty("Block while building blocked")]
            public bool BlockWhenBuildingBlocked { get; set; } = true;

            [JsonProperty("Cooldown seconds")]
            public float CooldownSeconds { get; set; } = 15f;
        }

        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>
            {
                ["NoPermission"] = "You are not allowed to use recyclers.",
                ["BuildingBlocked"] = "You cannot use a recycler while building blocked.",
                ["Cooldown"] = "Wait {0} seconds before using a recycler again."
            }, 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(PermUse, this);
            cleanupTimer = timer.Every(60f, CleanupCooldowns);
        }

        private void Unload()
        {
            cleanupTimer?.Destroy();
            lastUse.Clear();
        }

        private void CleanupCooldowns()
        {
            if (config.CooldownSeconds <= 0f || lastUse.Count == 0) return;

            float now = Time.realtimeSinceStartup;
            var stale = new List<ulong>();
            foreach (var entry in lastUse)
            {
                if (now - entry.Value >= config.CooldownSeconds) stale.Add(entry.Key);
            }

            foreach (var id in stale) lastUse.Remove(id);
        }

        private object OnRecyclerToggle(Recycler recycler, BasePlayer player)
        {
            if (recycler == null || player == null || player.IsNpc) return null;

            if (config.RequirePermission && !permission.UserHasPermission(player.UserIDString, PermUse))
            {
                player.ChatMessage(Msg("NoPermission", player.UserIDString));
                return false;
            }

            if (config.BlockWhenBuildingBlocked && player.IsBuildingBlocked())
            {
                player.ChatMessage(Msg("BuildingBlocked", player.UserIDString));
                return false;
            }

            if (config.CooldownSeconds > 0f)
            {
                float now = Time.realtimeSinceStartup;
                if (lastUse.TryGetValue(player.userID, out float last))
                {
                    float remaining = config.CooldownSeconds - (now - last);
                    if (remaining > 0f)
                    {
                        player.ChatMessage(Msg("Cooldown", player.UserIDString, Mathf.CeilToInt(remaining)));
                        return false;
                    }
                }
                lastUse[player.userID] = now;
            }

            return null;
        }
    }
}

The plugin registers a permission recyclertoggleguard.use and a configurable cooldown. When a player toggles a recycler, OnRecyclerToggle rejects the request (by returning false, which is non-null) if the player lacks the permission, is building blocked, or is still inside their cooldown window. Rejections send a localized chat message so the player knows why nothing happened. Accepted toggles record the current time per player ID and let the vanilla recycler logic run. A timer.Every cleans the cooldown dictionary so it cannot grow without bound, and Unload destroys that timer.

Common use cases

  • Restrict recycling to a VIP group

    Check permission.UserHasPermission on the requesting player and return a non-null value for everyone else, keeping recycling a paid or ranked perk.

  • Enforce a cooldown between toggles

    Store the last use time per player ID and block requests inside a configurable window to stop players spamming recyclers for lag.

  • Block recyclers inside raid or PvP zones

    Look up the recycler position against your zone data and cancel the toggle when the machine sits in a no-recycling area.

Pitfalls

  • The hook fires after the same-state check

    If the requested state equals the current state the server returns before calling the hook, so you will not see redundant on/off clicks and cannot use the hook to count UI presses.

  • Returning a value also skips power and contents checks

    Because the hook runs ahead of the unpowered and HasRecyclable() guards, a cancellation is unconditional. Do not assume the vanilla guards already filtered the request.

  • Do not return null by accident in a guard

    Only a non-null return cancels the toggle. Make sure every blocking branch returns false or another non-null object, otherwise the toggle proceeds.

Plugin recipes that use OnRecyclerToggle

Build a plugin with OnRecyclerToggle

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

Prompt: Restrict recycling to a VIP group using the OnRecyclerToggle 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 OnRecyclerToggle

Generate