Skip to content
RustPluginGenerator

OnExcavatorResourceSet

OnExcavatorResourceSet is called when a player uses the giant excavator terminal and requests a resource type to mine, before the excavator arm applies that choice.

Signature
object OnExcavatorResourceSet(ExcavatorArm excavatorArm, string resource, BasePlayer player)

Parameters

Hook parameters
ParameterTypeDescription
excavatorArmExcavatorArmThe ExcavatorArm entity that received the resource-target RPC, useful for distance checks and for identifying which excavator site the player is operating.
resourcestringThe resource identifier string sent by the client, such as "HQM", "Stone", "Sulfur" or "Metal"; it selects which resource the arm will mine.
playerBasePlayerThe BasePlayer who sent the RPC, i.e. the player sitting at the excavator control terminal.

Return value

Returning null lets the excavator switch to the requested resource normally. Returning any non-null value stops the original method body, so the arm's resource index is never updated and the player's selection is ignored.

How it works

The hook fires inside ExcavatorArm.RPC_SetResourceTarget, the server RPC the client sends when a player picks a resource at the excavator control cabin. It runs after the requested resource string has been read from the message and before the arm's switch statement sets the internal mining index, so blocking the call leaves the excavator mining whatever it was set to previously.

excavatorArm is the arm entity itself; use excavatorArm.net.ID.Value for logging or per-site rules and excavatorArm.transform.position for range checks. resource is the raw string from the client and is worth validating against an allow-list rather than trusting it blindly. player is the operator; it can be null in unusual cases, so guard it before calling player APIs. Note that player is the RPC sender, not necessarily the person currently seated, so compare against excavatorArm mount data if seat integrity matters.

Returning a non-null value stops the original code path, which is the only way to reject a resource selection. Declaring the first parameter as a narrower type is not useful here since the argument is always an ExcavatorArm.

Example plugin: Restrict excavator resources by permission

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

namespace Oxide.Plugins
{
    [Info("Excavator Resource Limiter", "RustPluginGenerator", "1.0.0")]
    [Description("Restricts which resources players can select at the giant excavator terminal")]
    public class ExcavatorResourceLimiter : RustPlugin
    {
        private const string PermAll = "excavatorresourcelimiter.all";

        private PluginConfig config;

        private class PluginConfig
        {
            [JsonProperty("Require permission for all resources")]
            public bool RequirePermissionForAllResources = true;

            [JsonProperty("Resource permissions (resource string -> permission suffix)")]
            public Dictionary<string, string> ResourcePermissions = new Dictionary<string, string>
            {
                ["HQM"] = "hqm",
                ["Sulfur"] = "sulfur",
                ["Metal"] = "metal",
                ["Stone"] = "stone"
            };
        }

        protected override void LoadDefaultConfig() => config = new PluginConfig();

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                config = Config.ReadObject<PluginConfig>();
                if (config == null || config.ResourcePermissions == 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>
            {
                ["Denied"] = "You are not allowed to set the excavator to {0}.",
                ["UnknownResource"] = "That resource is not available on this excavator."
            }, 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(PermAll, this);
            foreach (var entry in config.ResourcePermissions)
            {
                permission.RegisterPermission("excavatorresourcelimiter." + entry.Value, this);
            }
        }

        private object OnExcavatorResourceSet(ExcavatorArm excavatorArm, string resource, BasePlayer player)
        {
            if (excavatorArm == null || player == null || string.IsNullOrEmpty(resource)) return null;
            if (!config.RequirePermissionForAllResources) return null;

            string suffix;
            if (!config.ResourcePermissions.TryGetValue(resource, out suffix))
            {
                SendReply(player, Msg("UnknownResource", player.UserIDString));
                return false;
            }

            if (permission.UserHasPermission(player.UserIDString, PermAll)) return null;
            if (permission.UserHasPermission(player.UserIDString, "excavatorresourcelimiter." + suffix)) return null;

            SendReply(player, Msg("Denied", player.UserIDString, resource));
            return false;
        }

        private void SendReply(BasePlayer player, string message)
        {
            if (player == null || !player.IsConnected) return;
            player.ChatMessage(message);
        }
    }
}

The plugin keeps a per-resource permission list: excavatorresourcelimiter.hqm, excavatorresourcelimiter.sulfur and so on, plus one override permission that allows every resource. When a player sends a resource target RPC, the hook looks up the requested string in the configured map of resource names to permission suffixes, checks permission.UserHasPermission, and returns a non-null value to reject the change when the player lacks access. A throttled chat message tells the player which resource was denied. Unknown resource strings are rejected by default, and the hook is disabled entirely if the config flag RequirePermissionForAllResources is turned off, in which case the hook returns null immediately.

Common use cases

  • Rank-gated HQM mining

    Allow only VIP or high-rank players to switch the excavator to HQM while leaving stone and metal open to everyone.

  • Raid-window restrictions

    Combine with a time check so sulfur cannot be selected outside configured raid hours, keeping the arm on its previous resource.

  • Event overlays

    Temporarily lock resource selection during a server event by returning a value from the hook for all players except event admins.

Pitfalls

  • Blocking does not reset the arm

    Returning a value only skips the new selection; the excavator keeps mining the resource it already had, which may still be the one you meant to deny.

  • The player may not be seated

    The RPC carries the sending connection, which in edge cases is not the mounted operator. Verify with the arm's mount data if seat authenticity matters on your server.

  • Unvalidated resource strings

    The string comes straight from the client. Reject anything not on your known list instead of passing unknown values through to the game's switch.

Build a plugin with OnExcavatorResourceSet

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

Prompt: Rank-gated HQM mining using the OnExcavatorResourceSet 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 OnExcavatorResourceSet

Generate