Skip to content
RustPluginGenerator

OnBoatGroupSpawn

OnBoatGroupSpawn is called by BoatGroupSpawner.SpawnBoatGroup just before BoatAI.SpawnBoatGroup arranges the RHIB group, and returning a non-null value cancels the spawn entirely.

Signature
object OnBoatGroupSpawn(BoatGroupSpawner boatGroupSpawner, UnityEngine.Vector2 position, UnityEngine.Quaternion quaternion, HashSet<RHIB> list, bool flag, bool spawnsPT)

Parameters

Hook parameters
ParameterTypeDescription
boatGroupSpawnerBoatGroupSpawnerThe BoatGroupSpawner component that is about to arrange the group; useful for reading its transform or identifying which spawner entity is responsible.
positionUnityEngine.Vector2The XZ world position where the group is centered, passed as a Vector2 (deep sea checks use the same value).
quaternionUnityEngine.QuaternionThe rotation the group will face, built from the forward vector with Y flattened to zero.
listHashSet<RHIB>The set of RHIB entities being collected into the group. The list is passed by reference, so you can inspect it, though the spawn happens after this hook.
flagboolTrue when the spawn position lies inside the deep sea area (set immediately before the hook is called).
spawnsPTboolWhether the group should also spawn patrol/escort boats alongside the RHIBs; passed straight through to BoatAI.SpawnBoatGroup.

Return value

Returning null (or any value when you simply fall through) lets the original BoatAI.SpawnBoatGroup call proceed. Returning any non-null object stops the method before that call, so the RHIB group is never arranged or spawned.

How it works

The hook fires inside BoatGroupSpawner.SpawnBoatGroup, after the spawner has computed the group position and rotation and after the deep sea check has set the flag argument. Immediately after the hook returns, the game hands the data to BoatAI.SpawnBoatGroup(position, quaternion, list, flag, spawnsPT). Because this is the only place the hook is injected, it is the single choke point for player-visible RHIB group spawns driven by a BoatGroupSpawner - typically the ambient/deep sea boat encounters.

Use position and quaternion to filter by location or heading, flag to distinguish deep sea spawns, and spawnsPT to tell whether escort boats are included. The list holds the RHIBs that will be arranged; it is not yet positioned when the hook runs, so read it for counts rather than final coordinates. Declaring boatGroupSpawner as a more specific type would only narrow the hook, and the practical overload is the full signature shown. Since the hook returns an object, only a non-null return has any effect.

Example plugin: Cap concurrent boat groups per deep sea region

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

namespace Oxide.Plugins
{
    [Info("Boat Group Guard", "RustPluginGenerator", "1.0.0")]
    [Description("Caps how many RHIB boat groups can spawn inside a rolling time window.")]
    public class BoatGroupGuard : RustPlugin
    {
        private const string PermAdmin = "boatgroupguard.admin";

        private class PluginConfig
        {
            [JsonProperty("Max groups per window")]
            public int MaxGroups { get; set; } = 6;

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

            [JsonProperty("Only limit deep sea spawns")]
            public bool DeepSeaOnly { get; set; } = false;
        }

        private PluginConfig config;
        private readonly List<float> recentSpawns = new List<float>();
        private Timer cleanupTimer;

        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 do not have permission to use this command.",
                ["Status"] = "Boat groups in the last {0}s: {1} / {2}. Deep sea only: {3}",
                ["Blocked"] = "Boat group spawn blocked: window limit reached."
            }, 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(PermAdmin, this);
        }

        private void OnServerInitialized()
        {
            cleanupTimer = timer.Every(10f, PruneOld);
        }

        private void Unload()
        {
            cleanupTimer?.Destroy();
            cleanupTimer = null;
            foreach (var player in BasePlayer.activePlayerList)
            {
                if (player != null) player.ChatMessage(Msg("Blocked", player.UserIDString));
            }
        }

        private void PruneOld()
        {
            float cutoff = Time.realtimeSinceStartup - config.WindowSeconds;
            recentSpawns.RemoveAll(t => t < cutoff);
        }

        private object OnBoatGroupSpawn(BoatGroupSpawner boatGroupSpawner, Vector2 position, Quaternion quaternion, HashSet<RHIB> list, bool flag, bool spawnsPT)
        {
            if (config.DeepSeaOnly && !flag) return null;

            PruneOld();
            if (recentSpawns.Count >= config.MaxGroups) return false;

            recentSpawns.Add(Time.realtimeSinceStartup);
            return null;
        }

        [ConsoleCommand("boatguard.status")]
        private void CmdStatus(ConsoleSystem.Arg arg)
        {
            if (arg.Player() != null && !permission.UserHasPermission(arg.Player().UserIDString, PermAdmin))
            {
                arg.ReplyWith(Msg("NoPermission", arg.Player().UserIDString));
                return;
            }

            PruneOld();
            arg.ReplyWith(Msg("Status", null, (int)config.WindowSeconds, recentSpawns.Count, config.MaxGroups, config.DeepSeaOnly));
        }
    }
}

The plugin counts spawns inside a rolling window using Time.realtimeSinceStartup, and rejects any new group once the configured limit is reached, returning false to cancel the spawn. It only applies the cap when flag is true (deep sea), so surface encounters are untouched. A timer.Every loop clears stale timestamps so the count decays naturally. Admins can run boatguard.status from the console or F1 to see the recent count and the configured limit; the command player may be null, which the console command handles by replying through arg.ReplyWith.

Common use cases

  • Limit ambient boat spam

    Cancel or throttle RHIB group spawns when too many groups have appeared nearby recently, keeping server performance and player attention in check.

  • Block deep sea groups on custom maps

    Return non-null whenever flag is true to stop deep sea boat encounters on servers that restrict that area.

  • Seasonal encounter control

    Use the position to allow boat groups only in certain map quadrants, for example keeping encounters away from a heavily built coastal zone.

Pitfalls

  • Only non-null cancels

    Because the original method returns void and the patched check is for a non-null hook result, returning null or true/false has to be deliberate - returning any object cancels, so do not return a value from a logging branch.

  • List is not positioned yet

    The RHIBs in list have not been arranged when the hook fires; reading their transform.position gives pre-spawn coordinates, not the group layout.

  • One spawner, one call

    This hook only covers spawns routed through BoatGroupSpawner.SpawnBoatGroup; boats spawned by other code paths or plugins are not affected.

Build a plugin with OnBoatGroupSpawn

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

Prompt: Limit ambient boat spam using the OnBoatGroupSpawn 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 OnBoatGroupSpawn

Generate