Skip to content
RustPluginGenerator

OnExperimentStarted

OnExperimentStarted is called on the server as soon as a player begins an experiment at a Workbench, after the bench locks its inventory and schedules the completion timer.

Signature
void OnExperimentStarted(Workbench workbench, BasePlayer player)

Parameters

Hook parameters
ParameterTypeDescription
workbenchWorkbenchThe Workbench entity where the experiment was started. Use it for its position, net.ID (to key data) or to read the bench tier from its prefab name.
playerBasePlayerThe BasePlayer who triggered the experiment. Null-check it before use; access permissions, team lookups and chat through it.

Return value

The return value is ignored. The injection uses the continue behavior, so returning null, true or any other value does not stop, cancel or alter the experiment; the workbench still completes after its five second timer.

How it works

The hook fires inside Workbench.RPC_BeginExperiment, after the workbench sets its On flag, locks its inventory, cancels any pending experiment and schedules ExperimentComplete five seconds later. It fires once per experiment attempt, so it covers both blueprint research and item recycling done through the experiment UI.

workbench is the entity running the experiment; player is the initiator. Both are valid at this point because the RPC was sent by a connected player, but still guard against player being null if you store references across ticks.

The parameter types here are already the widest useful ones, so declaring a different type does not narrow dispatch. You can check inside the hook whether the bench belongs to the player's base, whether they hold a permission, or whether it is their own workbench.

The hook runs on the main thread before the completion timer fires. It is not a place for heavy work; the five second window is short and the method returns void, so it cannot block the experiment itself.

Example plugin: Restrict experiments to a permission

ExperimentGate.cs
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;

namespace Oxide.Plugins
{
    [Info("Experiment Gate", "RustPluginGenerator", "1.0.0")]
    [Description("Tracks workbench experiments and warns players who lack the experiment permission.")]
    public class ExperimentGate : RustPlugin
    {
        private const string PermUse = "experimentgate.use";

        private PluginConfig config;
        private readonly HashSet<ulong> pendingWarnings = new HashSet<ulong>();

        private class PluginConfig
        {
            [JsonProperty("Enable plugin")]
            public bool Enable { get; set; } = true;

            [JsonProperty("Warn players without permission")]
            public bool WarnPlayers { get; set; } = 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>
            {
                ["NoPermission"] = "Experiments at this workbench are restricted to permitted players.",
                ["Warning"] = "You started an experiment without the {0} permission. Ask an admin about access."
            }, 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);
        }

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

        private void OnExperimentStarted(Workbench workbench, BasePlayer player)
        {
            if (!config.Enable || player == null || workbench == null) return;
            if (permission.UserHasPermission(player.UserIDString, PermUse)) return;

            if (config.WarnPlayers)
            {
                ulong userId = player.userID.Get();
                pendingWarnings.Add(userId);
                timer.Once(6f, () =>
                {
                    if (!pendingWarnings.Remove(userId)) return;
                    if (player.IsConnected)
                        player.ChatMessage(Msg("Warning", player.UserIDString, PermUse));
                });
            }

            player.ChatMessage(Msg("NoPermission", player.UserIDString));
        }

        private void OnExperimentEnd(Workbench workbench, BasePlayer player)
        {
            if (player == null) return;
            pendingWarnings.Remove(player.userID.Get());
        }
    }
}

The plugin registers a single permission, experimentgate.use, and only players holding it should start experiments. In OnExperimentStarted it checks that permission; players without it get a chat message explaining the restriction. The hook cannot cancel the experiment, so the plugin records blocked players in a short-lived set and fires a timer that warns them once the result has been produced. OnExperimentEnd clears the set so no stale entries linger. The toggle Enable lives in oxide/config, and the permission is registered once in Init.

Common use cases

  • Permission-gated experiment benches

    Allow only PvP-flagged or VIP players to use workbenches as experiment stations by checking a permission inside the hook.

  • Log suspicious experiment spam

    Track how many experiments a player starts per minute and warn admins when a single account hammers RPC_BeginExperiment from a script or macro.

  • Scope experiments to base-owned benches

    Notify players when they start experimenting on a bench that is not inside their own base by comparing building privilege ownership.

Pitfalls

  • The hook cannot cancel the experiment

    Returning any value is ignored and the bench completes five seconds later. To actually prevent use, remove the workbench, block the player, or handle it in an earlier hook such as CanLootEntity or OnExperimentStart.

  • player can become stale

    If you keep a reference to the player after the hook returns, the connection may already have dropped. Check player.IsConnected before messaging them from a timer.

  • Heavy work blocks the RPC

    Doing file I/O or looping over all entities here delays the experiment RPC for everyone. Keep the hook cheap and defer any heavy work with a timer.

Build a plugin with OnExperimentStarted

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

Prompt: Permission-gated experiment benches using the OnExperimentStarted 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 OnExperimentStarted

Generate