OnSiegeWeaponFire
OnSiegeWeaponFire is called on the server when a player asks a siege weapon to shoot or attack, before the weapon actually fires. Returning a non-null value cancels that shot.
object OnSiegeWeaponFire(Catapult catapult, BasePlayer player)Parameters
| Parameter | Type | Description |
|---|---|---|
catapult | Catapult | The siege weapon entity requesting the shot. In the base-game call this is a Catapult; the same hook also fires from BatteringRam.SERVER_WantsAttack, so declare the parameter as the type you care about or as BaseCombatEntity to catch all of them. |
player | BasePlayer | The BasePlayer who sent the fire or attack request, i.e. the player operating the siege weapon. Treat it as untrusted input and null-check it. |
Return value
Return null (or nothing else) to let the shot proceed normally. Returning any non-null object stops the original path: the catapult does not call Fire and does not reset its reload progress, and the battering ram returns before sending CLIENT_Attack. The value itself is not used.
How it works
The hook fires inside the server RPC handlers, not when the projectile leaves the weapon. Catapult.SERVER_WantsFire runs it after the player has pressed fire, but only once CanFire() is true, and only then does the code call Fire(player, force) with the current reloadProgress as force before resetting the reload timer. BatteringRam.SERVER_WantsAttack runs it after validating that the sender is the actual driver, CanAttack() is true and the driver is not in a safe zone; if the hook returns non-null the method bails out before the CLIENT_Attack RPC and the melee swing.
Use the catapult parameter to inspect the entity (position, owner, grade, health) and player to check permissions, cooldowns or team status. Because two different weapon classes raise the hook with the same name, either write two hook methods with the specific types (Catapult and BatteringRam) or one method taking BaseCombatEntity to cover both. Oxide dispatches by argument type, so a Catapult parameter is skipped for battering ram calls and vice versa. The hook runs before the weapon's own fire timers are touched, so blocking it leaves reloadProgress intact.
Other signatures
Oxide also calls OnSiegeWeaponFire from other places in the game with these parameter types. Declare the overload you need, or several:
object OnSiegeWeaponFire(BatteringRam batteringRam, BasePlayer player)
Example plugin: Restrict siege weapons to permitted players
using UnityEngine;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("Siege Weapon Permission", "RustPluginGenerator", "1.0.0")]
[Description("Restricts catapult and battering ram firing to permitted players with a cooldown.")]
public class SiegeWeaponPermission : RustPlugin
{
private const string PermUse = "siegeweaponpermission.use";
private PluginConfig config;
private readonly Dictionary<ulong, double> lastShot = new Dictionary<ulong, double>();
private class PluginConfig
{
[JsonProperty("Require permission")]
public bool RequirePermission { get; set; } = true;
[JsonProperty("Minimum seconds between shots")]
public float CooldownSeconds { get; set; } = 3f;
}
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 siege weapons.",
["Cooldown"] = "Wait {0}s before firing this siege weapon 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);
}
private object OnSiegeWeaponFire(Catapult catapult, BasePlayer player)
{
return CheckShot(catapult, player);
}
private object OnSiegeWeaponFire(BatteringRam batteringRam, BasePlayer player)
{
return CheckShot(batteringRam, player);
}
private object CheckShot(BaseCombatEntity weapon, BasePlayer player)
{
if (weapon == null || player == null || !player.IsConnected) return null;
if (config.RequirePermission && !permission.UserHasPermission(player.UserIDString, PermUse))
{
player.ChatMessage(Msg("NoPermission", player.UserIDString));
return true;
}
if (config.CooldownSeconds > 0f)
{
double now = UnityEngine.Time.realtimeSinceStartup;
double last;
if (lastShot.TryGetValue(player.userID, out last) && now - last < config.CooldownSeconds)
{
player.ChatMessage(Msg("Cooldown", player.UserIDString, Math.Ceiling(config.CooldownSeconds - (now - last))));
return true;
}
lastShot[player.userID] = now;
}
return null;
}
private void Unload()
{
lastShot.Clear();
}
}
}The plugin registers a single permission, siegeweaponpermission.use, and implements two typed hook methods so it sees both the catapult and battering ram calls. Each one returns a non-null value when the player is not connected or lacks the permission, which cancels the shot. A per-player cooldown from the config rate-limits how often one player can fire any siege weapon, and a language message tells them why the shot was blocked; it is sent only on a denied attempt, not on every shot. The last-shot timestamps live in memory and are cleared on unload.
Common use cases
Raid-only siege weapons
Allow catapults and battering rams only during a configured window (for example a weekend raid window) by comparing
DateTime.UtcNow.Hourwith the config and returning non-null outside it.Cooldown between shots
Store the last fire time per player in a dictionary and block shots that arrive inside the configured interval, protecting against macros spamming SERVER_WantsFire.
Team and zone checks
Block attacks against siege weapons whose driver is not on the same team as the weapon owner, or refuse firing while the player stands in a safe zone.
Pitfalls
One signature does not catch both weapons
Oxide only calls a hook method when every argument matches the declared parameter type. A method taking
Catapultnever sees battering ram attacks and the reverse is also true, so implement both or useBaseCombatEntity.The player argument can be null
The RPC sender is not guaranteed to be valid by the time the hook runs, especially on the catapult path where the code only null-checks later. Always check
playerandplayer.IsConnectedbefore reading permissions.Blocking does not show feedback
A non-null return silently cancels the shot; the client may not receive any error. Send a chat or console reply yourself, and keep it short so it does not spam the chat on repeated fire input.
Build a plugin with OnSiegeWeaponFire
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 OnSiegeWeaponFire
Generate