OnMlrsFiringEnded
OnMlrsFiringEnded is called when an MLRS finishes its firing sequence, right after the vehicle's internal MLRS.EndFiring method clears its broken/firing flags and sends a network update.
void OnMlrsFiringEnded(MLRS mLRS)Parameters
| Parameter | Type | Description |
|---|---|---|
mLRS | MLRS | The MLRS vehicle entity whose firing sequence just ended. It is the same BaseEntity instance spawned in the world, so you can read its net.ID, position, OwnerID and mounted occupants. |
Return value
The return value is ignored. The hook is patched with continue behavior and MLRS.EndFiring returns void, so returning null, true or any other value has no effect on the firing sequence.
How it works
The hook fires once per firing cycle, at the end of MLRS.EndFiring. That method runs when the launcher has finished launching its salvo and is transitioning back to a usable state; the injected call sits after the flags Reserved6 and Broken are cleared, timeSinceBroken is reset to zero and the flags are networked to clients. Because it fires after the state change, the vehicle you receive is already back in its idle configuration, so reading HasFlag(BaseEntity.Flags.Broken) or Flags.Reserved6 here returns the post-firing values.
The only argument is the MLRS entity itself. Use mLRS.net.ID.Value as a stable key for tracking, mLRS.transform.position for the launch site, mLRS.OwnerID to identify the placing player, and mLRS.GetMounted() if you need to know whether an operator is still seated. You do not need to narrow the parameter type; declaring MLRS is already specific, and declaring a broader type such as BaseEntity would not change which calls arrive because the game always passes an MLRS instance.
The hook is a good place for cooldown bookkeeping, admin logging of salvo completions, or map markers, since it fires once per sequence rather than per rocket.
Example plugin: Enforce a per-player MLRS salvo cooldown
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace Oxide.Plugins
{
[Info("Mlrs Salvo Cooldown", "RustPluginGenerator", "1.0.0")]
[Description("Tracks when a player's MLRS finishes a salvo and reports the next allowed launch time.")]
public class MlrsSalvoCooldown : RustPlugin
{
private const string PermUse = "mlrssalvocooldown.use";
private PluginConfig config;
private readonly Dictionary<ulong, DateTime> lastSalvo = new Dictionary<ulong, DateTime>();
private class PluginConfig
{
[JsonProperty("Salvo cooldown in seconds")]
public int CooldownSeconds { get; set; } = 600;
}
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>
{
["SalvoEnded"] = "Your MLRS salvo ended. Next salvo allowed in {0} seconds.",
["Ready"] = "Your MLRS is ready to fire.",
["OnCooldown"] = "Your MLRS is on cooldown for another {0} seconds.",
["NoPermission"] = "You do not have permission to use this command."
}, 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 OnMlrsFiringEnded(MLRS mLRS)
{
if (mLRS == null) return;
ulong ownerId = mLRS.OwnerID;
if (ownerId == 0) return;
lastSalvo[ownerId] = DateTime.UtcNow;
var player = BasePlayer.FindAwakeOrSleeping(ownerId.ToString());
if (player != null && player.IsConnected)
{
player.ChatMessage(Msg("SalvoEnded", player.UserIDString, config.CooldownSeconds));
}
}
[ChatCommand("canfire")]
private void CmdCanFire(BasePlayer player, string command, string[] args)
{
if (player == null) return;
if (!permission.UserHasPermission(player.UserIDString, PermUse))
{
player.ChatMessage(Msg("NoPermission", player.UserIDString));
return;
}
int remaining = GetRemainingSeconds(player.userID.Get());
if (remaining <= 0)
{
player.ChatMessage(Msg("Ready", player.UserIDString));
return;
}
player.ChatMessage(Msg("OnCooldown", player.UserIDString, remaining));
}
private int GetRemainingSeconds(ulong ownerId)
{
DateTime last;
if (!lastSalvo.TryGetValue(ownerId, out last)) return 0;
double elapsed = (DateTime.UtcNow - last).TotalSeconds;
double left = config.CooldownSeconds - elapsed;
return left > 0 ? (int)Math.Ceiling(left) : 0;
}
private void Unload()
{
lastSalvo.Clear();
}
}
}The plugin records the time each player last finished an MLRS salvo, keyed by OwnerID. When the salvo ends, it stamps the current time and, if the owner is online, messages them how many seconds remain before the next allowed salvo. A canfire chat command checks the stored timestamp against the configured cooldown and tells the player whether they can launch again, including the remaining time. Data lives in memory only and is cleared on unload, which is enough for a soft advisory cooldown; combine it with a weapon or entity restriction elsewhere if you need hard enforcement. The config exposes the cooldown length in seconds.
Common use cases
Post-salvo admin audit
Record owner, position and timestamp each time a salvo finishes and write it to a data file, giving staff a history of MLRS usage without hooking every rocket.
Cooldown or usage limits
Track the last completion per owner or team and deny further launches (through a separate restriction hook) until the configured interval has passed.
Map and team notifications
Broadcast a chat notice to the owning team when their launcher finishes firing, or drop a temporary marker at
mLRS.transform.position.
Pitfalls
Fires after the state reset
The call sits after
Flags.BrokenandFlags.Reserved6are cleared, so checking those flags inside the hook will not tell you the launcher was just firing. Track state yourself if you need to know a sequence started.OwnerID may be stale or zero
If the launcher was placed via admin command or its building was destroyed,
OwnerIDcan be 0 or point to a player who is offline. Resolve withBasePlayer.FindAwakeOrSleeping(ownerId.ToString())before messaging.One call per sequence, not per rocket
Use the
OnMlrsRocketFiredfamily if you need a callback for each individual launch; this hook only marks the end of the whole salvo.
Build a plugin with OnMlrsFiringEnded
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 OnMlrsFiringEnded
Generate