OnCoalingTowerStart
OnCoalingTowerStart is called when a player invokes the CoalingTower unload RPC, giving plugins a chance to block the tower from unloading its active wagon.
object OnCoalingTowerStart(CoalingTower coalingTower, BasePlayer player)Parameters
| Parameter | Type | Description |
|---|---|---|
coalingTower | CoalingTower | The CoalingTower entity whose unload RPC was invoked. Use it for its position, net.ID or to read or change the tower's state. |
player | BasePlayer | The BasePlayer who triggered the unload RPC. Can be null when the RPC arrives without an attached connection, so null-check it before use. |
Return value
Return null to let the vanilla unload attempt run as normal. Return any non-null value (a bool works) to skip the original unload path entirely, so no wagon is released and no ActionFailed RPC is sent to the player.
How it works
The hook fires inside CoalingTower.RPC_Unload, the server-side RPC handler for a player requesting that a coaling tower release its active wagon. The RPC carries a player, so player is normally the client that sent the request, but the handler does not guarantee it is non-null, so null-check it. coalingTower is the tower entity that received the RPC; its position, net.ID and ownership are the usual things you need when deciding whether to allow the unload.
Returning a non-null value stops the original unload path, so the tower keeps its wagon and the player is not sent the ActionFailed client RPC. Returning null lets the unload continue and the vanilla error feedback is still sent when the unload attempt fails. Because the injection happens before the actual unload logic, this is a gate, not a notification: you cannot use it to react to a completed unload.
Declaring the player parameter as BasePlayer matches the RPC caller. If you only care about the tower, drop the parameter or replace it with a more specific type only when you can guarantee the argument instance matches, otherwise Oxide will skip your method on calls where the argument is a different type.
Example plugin: Rate-limit coaling tower unloads and log them
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Coaling Tower Guard", "RustPluginGenerator", "1.0.0")]
[Description("Rate-limits coaling tower unload requests and notifies players on cooldown.")]
public class CoalingTowerGuard : RustPlugin
{
private const string PermBypass = "coalingtowerguard.bypass";
private PluginConfig config;
private readonly Dictionary<string, float> lastRequest = new Dictionary<string, float>();
private class PluginConfig
{
[JsonProperty("Cooldown seconds")]
public float CooldownSeconds { get; set; } = 10f;
[JsonProperty("Notify player on cooldown")]
public bool NotifyOnCooldown { 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>
{
["Cooldown"] = "The coaling tower is still busy. Try again in {0}s."
}, 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(PermBypass, this);
}
private object OnCoalingTowerStart(CoalingTower coalingTower, BasePlayer player)
{
if (coalingTower == null || player == null) return null;
if (permission.UserHasPermission(player.UserIDString, PermBypass)) return null;
string userId = player.UserIDString;
float now = UnityEngine.Time.realtimeSinceStartup;
float last;
if (lastRequest.TryGetValue(userId, out last))
{
float elapsed = now - last;
if (elapsed < config.CooldownSeconds)
{
if (config.NotifyOnCooldown)
{
float remaining = Mathf.Ceil(config.CooldownSeconds - elapsed);
player.ChatMessage(Msg("Cooldown", userId, remaining));
}
return true;
}
}
lastRequest[userId] = now;
return null;
}
private void Unload()
{
lastRequest.Clear();
}
}
}The plugin adds a cooldown per player on coaling tower unload requests and stops the vanilla unload when a player spams the RPC. A configurable CooldownSeconds value is compared against a dictionary of last-request times keyed by user ID string. Players with the coalingtowerguard.bypass permission skip the check. On a block, OnCoalingTowerStart sends a localized chat message and returns true, which stops the original unload and suppresses the ActionFailed RPC. Otherwise it records the timestamp, returns null and lets the tower unload normally. The dictionary is cleared on unload so reloads start fresh.
Common use cases
Cooldown on unload requests
Stop players from hammering the unload RPC by returning true while a per-player timestamp is still fresh.
Restrict who can unload a tower
Block the RPC unless the player is authorised on the tower's building privilege or holds a permission, then return true to deny silently.
Audit tower usage
Record tower position and player ID for each unload attempt, since the hook fires on every request the client sends.
Pitfalls
Cancelling hides the failure message
Returning non-null skips the whole original branch, so the player never receives the
ActionFailedRPC. Send your own feedback or they will see nothing happen.The player can be null
The RPC handler only checks the player after the hook. Guard against a null player before reading
UserIDStringor sending chat.Fires per request, not per unload
The hook runs before
TryUnloadActiveWagon, so it fires even when the unload would have failed. Do not treat it as proof the wagon was released.
Build a plugin with OnCoalingTowerStart
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 OnCoalingTowerStart
Generate