Skip to content
RustPluginGenerator

OnFishingRodCast

OnFishingRodCast is called when a player requests a cast with a fishing rod, right after the server processes the cast request and before the fishing session begins. It fires inside BaseFishingRod.Server_RequestCast.

Signature
void OnFishingRodCast(BaseFishingRod fishingRod, BasePlayer ownerPlayer, Item currentLure)

Parameters

Hook parameters
ParameterTypeDescription
fishingRodBaseFishingRodThe BaseFishingRod entity the player is trying to cast. Use it for position, owner checks, and to read or modify rod state.
ownerPlayerBasePlayerThe BasePlayer who owns the rod and is executing the cast request. Can be null in edge cases if the rod has no owner, so null-check it.
currentLureItemThe Item currently placed on the rod as a lure (bait). May be null when the rod is cast without bait loaded.

Return value

The hook's return value is ignored: the injection uses plain continue and Server_RequestCast returns void. Returning a value or null has no effect on whether the cast proceeds. To prevent casting you must use a different hook such as CanCastFishingRod.

How it works

The hook fires from BaseFishingRod.Server_RequestCast, the server-side path that runs when a player starts a cast with a fishing rod. The rod has already validated the request and computed its target position by the time Oxide calls your method, so this is a notification stage rather than a gate. Use fishingRod to inspect or adjust the rod entity (for example its position or any custom state you track per rod). ownerPlayer identifies who is fishing; it is the same player the game uses for analytics at this point, and you should still null-check it before touching inventory or permissions. currentLure is the bait item currently loaded on the rod and can be null when the rod casts without bait; its info.shortname and amount are what you usually read. Declaring ownerPlayer as a narrower type such as BasePlayer is already the signature; there is no more specific subtype for fishing players, so type narrowing does not help here. Because the hook fires on every cast and cannot undo it, treat it as a place to count, track, or reward casts, not to block them.

Example plugin: Track casts per player and reward every 10th cast

FishingCastRewards.cs
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;

namespace Oxide.Plugins
{
    [Info("Fishing Cast Rewards", "RustPluginGenerator", "1.0.0")]
    [Description("Counts fishing rod casts per player and rewards a configurable milestone.")]
    public class FishingCastRewards : RustPlugin
    {
        private const string PermReward = "fishingcastrewards.reward";

        private PluginConfig config;
        private Dictionary<string, int> castCounts = new Dictionary<string, int>();
        private Timer saveTimer;

        private class PluginConfig
        {
            [JsonProperty("Casts required for a reward")]
            public int CastsPerReward { get; set; } = 10;

            [JsonProperty("Reward item shortname")]
            public string RewardShortname { get; set; } = "scrap";

            [JsonProperty("Reward item amount")]
            public int RewardAmount { get; set; } = 5;
        }

        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>
            {
                ["Reward"] = "You cast your line {0} times and received {1} x {2}.",
                ["NoPermission"] = "You do not have permission to earn fishing rewards."
            }, 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(PermReward, this);
            castCounts = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<string, int>>(Name) ?? new Dictionary<string, int>();
        }

        private void OnServerInitialized()
        {
            saveTimer = timer.Every(120f, SaveData);
        }

        private void Unload()
        {
            saveTimer?.Destroy();
            SaveData();
        }

        private void SaveData()
        {
            Interface.Oxide.DataFileSystem.WriteObject(Name, castCounts);
        }

        private void OnFishingRodCast(BaseFishingRod fishingRod, BasePlayer ownerPlayer, Item currentLure)
        {
            if (fishingRod == null || ownerPlayer == null) return;
            if (ownerPlayer.IsNpc || !ownerPlayer.IsConnected) return;
            if (!permission.UserHasPermission(ownerPlayer.UserIDString, PermReward)) return;

            string id = ownerPlayer.UserIDString;
            if (!castCounts.TryGetValue(id, out int count)) count = 0;
            count++;
            castCounts[id] = count;

            if (config.CastsPerReward <= 0 || count % config.CastsPerReward != 0) return;

            Item reward = ItemManager.CreateByName(config.RewardShortname, config.RewardAmount);
            if (reward == null) return;
            ownerPlayer.GiveItem(reward);
            ownerPlayer.ChatMessage(Msg("Reward", id, count, config.RewardAmount, reward.info.displayName.english));
        }
    }
}

The plugin listens to OnFishingRodCast, increments a per-player cast counter stored in oxide/data, and saves it on a timer to avoid disk writes on every cast. When a player reaches a configurable milestone (default 10 casts), it grants a configurable reward item by shortname and sends a localized chat message. A permission (fishingcastrewards.reward) restricts who earns rewards. Every hook parameter is null-checked, currentLure is only read for shortname, and the save timer is destroyed in Unload. Because the hook return is ignored, the example never tries to cancel the cast; it simply records and rewards legitimate casts.

Common use cases

  • Cast statistics and leaderboards

    Count casts per player over time and expose totals through a chat command. Useful for fishing-focused servers that want progression metrics.

  • Lure-aware rewards

    Read currentLure.info.shortname to give different rewards or bonuses depending on which bait was loaded at cast time.

  • Anti-afk fishing detection

    Record the time and position of each cast and flag players who cast at an implausible rate or from suspicious spots for staff review.

Pitfalls

  • Cannot cancel the cast here

    The return value is ignored, so returning false does nothing. Use CanCastFishingRod if you need to block a cast before it starts.

  • No bait is not an error

    currentLure is often null when the rod is cast without bait. Guard against it before reading info or amount.

  • Frequent hook, avoid logging spam

    This fires on every cast request for every player. Do not call Puts or PrintWarning inside it; batch or persist data instead.

Build a plugin with OnFishingRodCast

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

Prompt: Cast statistics and leaderboards using the OnFishingRodCast 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 OnFishingRodCast

Generate