OnExcavatorSuppliesRequested
OnExcavatorSuppliesRequested is called after the excavator signal computer spawns a supply drop for a player request, before the charge is deducted and the panel flags are updated.
void OnExcavatorSuppliesRequested(ExcavatorSignalComputer excavatorSignalComputer, BasePlayer player, BaseEntity entity)Parameters
| Parameter | Type | Description |
|---|---|---|
excavatorSignalComputer | ExcavatorSignalComputer | The ExcavatorSignalComputer entity (the signal panel at the excavator) that received the supply request. Use it to read its position or charge state, e.g. excavatorSignalComputer.transform.position. |
player | BasePlayer | The BasePlayer who pressed the button and triggered the request, taken from the RPC call. Can be null if the RPC arrived without a connection, so null-check before using it. |
entity | BaseEntity | The supply drop entity that was just created, positioned and spawned at the chosen drop point. You can inspect it (type, position, net ID) or kill it to cancel the drop. |
Return value
The hook's return value is ignored. Returning anything (or nothing) does not stop the original code path, so the charge is still deducted and the panel flags still update afterwards.
How it works
This hook fires inside ExcavatorSignalComputer.RequestSupplies, after the game has picked a random drop point, sent InitDropPosition to the newly created supply entity and spawned it. Only the signal computer's button interaction path reaches it, so it fires when a player pays the required charge at the excavator panel to call in supplies. The call happens before chargePower is reduced and before the panel's reserved flags are toggled, so the hook sees the pre-request power state.
The parameters give you the panel (excavatorSignalComputer), the requesting player (from the RPC) and the already-spawned drop entity. Use player for permission checks, logging or messages; use entity.transform.position to know where the drop landed; use the panel to read its health or nearby context.
Narrowing the parameter type is possible only in the sense of subclass checks: declaring BasePlayer as in the signature is already specific. If you declare a parameter type that the argument does not match, Oxide skips your method for that call, so keep the given types.
Practical use: gate or count supply calls, log who called them, relocate or kill the drop, or refund/adjust nothing else — the method body continues regardless.
Example plugin: Count and limit excavator supply calls
using UnityEngine;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("Excavator Supply Limit", "RustPluginGenerator", "1.0.0")]
[Description("Limits how many excavator supply drops a player can request per time window.")]
public class ExcavatorSupplyLimit : RustPlugin
{
private class PluginConfig
{
[JsonProperty("Max requests per window")]
public int MaxRequests { get; set; } = 2;
[JsonProperty("Window length (seconds)")]
public float WindowSeconds { get; set; } = 600f;
}
private PluginConfig config;
private readonly Dictionary<ulong, List<float>> requestTimes = new Dictionary<ulong, List<float>>();
private Timer cleanupTimer;
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>
{
["LimitReached"] = "You have used all {0} excavator supply requests for the next {1} minutes. The drop was cancelled.",
["RequestLogged"] = "Supply request {0}/{1} registered."
}, this);
}
private string Msg(string key, string userId = null, params object[] args) =>
string.Format(lang.GetMessage(key, this, userId), args);
private void OnServerInitialized()
{
cleanupTimer = timer.Every(60f, CleanupStaleEntries);
}
private void Unload()
{
cleanupTimer?.Destroy();
}
private void OnExcavatorSuppliesRequested(ExcavatorSignalComputer excavatorSignalComputer, BasePlayer player, BaseEntity entity)
{
if (player == null || entity == null) return;
ulong userId = player.userID.Get();
float now = UnityEngine.Time.realtimeSinceStartup;
List<float> times;
if (!requestTimes.TryGetValue(userId, out times))
{
times = new List<float>();
requestTimes[userId] = times;
}
times.RemoveAll(t => now - t > config.WindowSeconds);
times.Add(now);
if (times.Count > config.MaxRequests)
{
entity.Kill();
player.ChatMessage(Msg("LimitReached", player.UserIDString, config.MaxRequests, Math.Round(config.WindowSeconds / 60f, 1)));
return;
}
player.ChatMessage(Msg("RequestLogged", player.UserIDString, times.Count, config.MaxRequests));
}
private void CleanupStaleEntries()
{
float now = UnityEngine.Time.realtimeSinceStartup;
foreach (var entry in requestTimes)
{
entry.Value.RemoveAll(t => now - t > config.WindowSeconds);
}
}
}
}The plugin tracks how many supply calls each player makes within a configurable window. On OnExcavatorSuppliesRequested it null-checks the player and the spawned entity, records the timestamp, and prunes old entries. If the player exceeds MaxRequests in WindowSeconds, it kills the just-spawned drop entity and sends a localized chat message. Otherwise nothing is changed, since the return value cannot cancel the request; killing the drop is the practical way to void the delivery. Config holds the window and limit, messages live in the language file, and the timer reference is destroyed on unload.
Common use cases
Rate-limit supply drops
Track per-player call timestamps and kill the spawned supply entity when a player calls too many drops in a short time, then warn them in chat.
Log supply activity
Record who called supplies, at what time, and the drop position taken from the spawned entity for admin review or analytics files in oxide/data.
Reward the caller
Grant a small bonus (permission-gated item, economy deposit via plugin reference) to players who request supplies, since the hook fires exactly on a successful request.
Pitfalls
Returning a value does not cancel
The injection ignores the return value, so you cannot block a supply request from this hook. Kill the spawned entity or undo effects yourself if you need to prevent the delivery.
Player can be null
The player argument comes from the RPC call and may be null in edge cases. Always null-check before reading UserIDString or sending messages.
Charge is deducted afterwards
chargePoweris reduced after the hook runs. If you kill the entity to deny the drop, consider whether the player still pays the charge and compensate if that matters on your server.
Build a plugin with OnExcavatorSuppliesRequested
Describe what should happen and get a compiled plugin that uses this hook.
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 OnExcavatorSuppliesRequested
Generate