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.
object OnBoatGroupSpawn(BoatGroupSpawner boatGroupSpawner, UnityEngine.Vector2 position, UnityEngine.Quaternion quaternion, HashSet<RHIB> list, bool flag, bool spawnsPT)Parameters
| Parameter | Type | Description |
|---|---|---|
boatGroupSpawner | BoatGroupSpawner | The BoatGroupSpawner component that is about to arrange the group; useful for reading its transform or identifying which spawner entity is responsible. |
position | UnityEngine.Vector2 | The XZ world position where the group is centered, passed as a Vector2 (deep sea checks use the same value). |
quaternion | UnityEngine.Quaternion | The rotation the group will face, built from the forward vector with Y flattened to zero. |
list | HashSet<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. |
flag | bool | True when the spawn position lies inside the deep sea area (set immediately before the hook is called). |
spawnsPT | bool | Whether 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
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
flagis 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
nullortrue/falsehas 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
listhave not been arranged when the hook fires; reading theirtransform.positiongives 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.
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