Skip to content
RustPluginGenerator

OnLiquidWeaponFired

OnLiquidWeaponFired is called after a LiquidWeapon such as a flamethrower runs StartFiring, which happens when a player triggers the weapon and its cooldown has elapsed.

Signature
void OnLiquidWeaponFired(LiquidWeapon liquidWeapon, BasePlayer player)

Parameters

Hook parameters
ParameterTypeDescription
liquidWeaponLiquidWeaponThe LiquidWeapon entity that just fired, typically a flamethrower. Use it to read position, owner, the attached player and its held item state.
playerBasePlayerThe BasePlayer who pulled the trigger and caused StartFiring. Can be null-checked before applying per-player logic such as cooldowns, permissions or statistics.

Return value

The hook is injected with a plain call and the original method returns void, so any value your hook returns is ignored and the weapon always finishes firing normally. Use OnLiquidWeaponFired for observation only; cancel firing through CanFireLiquidWeapon.

How it works

The hook fires at the end of LiquidWeapon.StartFiring, after the weapon has set its cooldown, sent its network update to clients, and then invoked the hook with the weapon entity and the firing player. StartFiring is the server-side entry point used when a liquid weapon is triggered from input, so the hook runs once per accepted fire attempt, not on every frame the trigger is held. Both arguments are useful: liquidWeapon gives you the entity (position, owner, GetOwnerPlayer(), held item) and player gives you the shooter directly.

Because the method returns void, you cannot cancel the shot from here; there is no return value that stops the game code. Blocking the fire itself belongs in CanFireLiquidWeapon. Declaring a more specific type than LiquidWeapon makes Oxide skip calls for other liquid weapon subclasses. Keep hook bodies cheap: this fires on every trigger pull and is not a place for chat output or logging.

Example plugin: Limit flamethrower shots per player

LiquidWeaponShotLimit.cs
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Plugins;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("Liquid Weapon Shot Limit", "RustPluginGenerator", "1.0.0")]
    [Description("Limits how many liquid weapon shots a player can fire per time window")]
    public class LiquidWeaponShotLimit : RustPlugin
    {
        private const string PermBypass = "liquidweaponshotlimit.bypass";

        private PluginConfig config;
        private readonly Dictionary<ulong, int> shots = new Dictionary<ulong, int>();
        private Timer resetTimer;

        private class PluginConfig
        {
            [JsonProperty("Maximum shots per window")]
            public int MaxShots { get; set; } = 10;

            [JsonProperty("Window length in seconds")]
            public float WindowSeconds { get; set; } = 30f;

            [JsonProperty("Watched liquid weapon shortnames")]
            public List<string> WeaponShortnames { get; set; } = new List<string> { "flamethrower" };
        }

        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 reached the flamethrower shot limit ({0} per {1}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);
            resetTimer = timer.Every(config.WindowSeconds, () => shots.Clear());
        }

        private void Unload()
        {
            resetTimer?.Destroy();
            shots.Clear();
        }

        private bool IsWatched(LiquidWeapon liquidWeapon)
        {
            var shortname = liquidWeapon?.ShortPrefabName;
            if (string.IsNullOrEmpty(shortname)) return false;
            foreach (var name in config.WeaponShortnames)
            {
                if (string.Equals(name, shortname, StringComparison.OrdinalIgnoreCase)) return true;
            }
            return false;
        }

        private object CanFireLiquidWeapon(LiquidWeapon liquidWeapon, BasePlayer player)
        {
            if (player == null || liquidWeapon == null) return null;
            if (!IsWatched(liquidWeapon)) return null;
            if (permission.UserHasPermission(player.UserIDString, PermBypass)) return null;

            int used;
            shots.TryGetValue(player.userID.Get(), out used);
            if (used >= config.MaxShots) return false;
            return null;
        }

        private void OnLiquidWeaponFired(LiquidWeapon liquidWeapon, BasePlayer player)
        {
            if (player == null || liquidWeapon == null) return;
            if (!IsWatched(liquidWeapon)) return;
            if (permission.UserHasPermission(player.UserIDString, PermBypass)) return;

            ulong id = player.userID.Get();
            int used;
            shots.TryGetValue(id, out used);
            shots[id] = used + 1;

            if (shots[id] == config.MaxShots)
            {
                player.ChatMessage(Msg("LimitReached", player.UserIDString, config.MaxShots, config.WindowSeconds));
            }
        }
    }
}

The plugin tracks a fixed-window shot counter per player Steam ID. OnLiquidWeaponFired runs after every accepted flamethrower shot; it ignores any weapon whose shortname is not in the configured list, then increments the counter for the firing player and sends a warning when the limit is reached. Because the hook cannot cancel the shot, the plugin enforces the cap through CanFireLiquidWeapon: once the counter is at the configured maximum the method returns false and the weapon refuses to fire. Counters reset on a timer every configured window (timer.Every), and the timer and player state are cleared in Unload.

Common use cases

  • Shot statistics

    Count flamethrower shots per player or log them to a data file so admins can spot spam or farm abuse.

  • Cooldown enforcement

    Combine the hook with CanFireLiquidWeapon to track recent shots and refuse the next trigger until a custom cooldown elapses.

  • Effect and chat feedback

    Reward or notify the shooter on a milestone shot count, using lang messages so the text stays configurable.

Pitfalls

  • Fires per accepted shot

    The hook runs only when StartFiring executes, after the cooldown check, so it does not fire for shots the game rejected on fire rate.

  • Cannot cancel here

    The injection ignores the return value and the method returns void, so blocking must use CanFireLiquidWeapon instead.

  • Null player

    Always null-check player before reading UserIDString; if the weapon is fired without a player initiator the argument can be null.

Build a plugin with OnLiquidWeaponFired

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

Prompt: Shot statistics using the OnLiquidWeaponFired 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 OnLiquidWeaponFired

Generate