OnBradleyApcPatrol
OnBradleyApcPatrol is called from BradleyAPC.UpdateMovement_Patrol when the APC picks its next movement step while it has no active path or has reached its destination. Returning a non-null value keeps the APC from choosing a new random patrol node this update.
object OnBradleyApcPatrol(BradleyAPC bradleyAPC)Parameters
| Parameter | Type | Description |
|---|---|---|
bradleyAPC | BradleyAPC | The Bradley APC entity whose patrol movement is being updated. Use it to read position, health, current target, or to change how the APC navigates. |
Return value
Returning null (or falling through) lets the original code continue and pick a new random interest node along the patrol path. Returning any non-null value causes the method to return immediately, so the APC does not select a new patrol node in that cycle and stays idle until the next patrol timer expires.
How it works
The hook fires inside BradleyAPC.UpdateMovement_Patrol. Before running, the game checks whether a patrol path exists and whether at least 20 seconds have passed since the last patrol step; if either condition fails the method returns early and the hook is not called. When it does run, Oxide is asked for OnBradleyApcPatrol right at the branch that decides whether to continue patrolling. The call happens after nextPatrolTime has already been pushed 20 seconds forward, so each invocation represents one patrol decision cycle.
The only argument is the BradleyAPC instance, which you can use to read transform.position, health, or GetParentEntity(), teleport the APC, change its target, or gate its movement based on zone, player proximity or event state. Because the parameter is typed BradleyAPC, a hook declared with that exact type receives every call; declaring a broader type would still work but gives no benefit. Return nothing (or null) to let the default random-interest-node selection proceed. Note that the game only calls this while the APC has no path or has arrived at its final destination, so it does not run every tick during a long traverse.
Example plugin: Pause Bradley patrol while players are fighting it
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Bradley Patrol Pause", "RustPluginGenerator", "1.0.0")]
[Description("Pauses Bradley APC patrol movement while it engages a nearby player.")]
public class BradleyPatrolPause : RustPlugin
{
private const string PermUse = "bradleypatrolpause.use";
private PluginConfig config;
private bool paused;
private class PluginConfig
{
[JsonProperty("Pause patrol while engaging a player")]
public bool PauseOnEngage { get; set; } = true;
[JsonProperty("Minimum distance to consider engagement (meters)")]
public float EngageDistance { get; set; } = 60f;
}
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>
{
["Paused"] = "Bradley patrol pause: {0}",
["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);
}
[ChatCommand("bradleypatrol.toggle")]
private void CmdToggle(BasePlayer player, string command, string[] args)
{
if (player == null) return;
if (!player.IsAdmin && !permission.UserHasPermission(player.UserIDString, PermUse))
{
SendReply(player, Msg("NoPermission", player.UserIDString));
return;
}
paused = !paused;
SendReply(player, Msg("Paused", player.UserIDString, paused ? "on" : "off"));
}
private object OnBradleyApcPatrol(BradleyAPC bradleyAPC)
{
if (bradleyAPC == null || !config.PauseOnEngage) return null;
if (paused) return true;
// BradleyAPC does not expose its current target publicly; find the closest
// alive player ourselves and pause patrol while one is within engagement range.
BasePlayer closest = null;
float maxDistance = config.EngageDistance;
float bestDistance = float.MaxValue;
foreach (BasePlayer player in BasePlayer.activePlayerList)
{
if (player == null || !player.IsAlive()) continue;
float distance = Vector3.Distance(bradleyAPC.transform.position, player.transform.position);
if (distance > maxDistance) continue;
if (distance < bestDistance)
{
bestDistance = distance;
closest = player;
}
}
if (closest == null) return null;
return true;
}
}
}The plugin hooks OnBradleyApcPatrol and, when PauseOnEngage is enabled, checks whether any alive player is within EngageDistance of the APC. If one is, the hook returns true so the APC skips its random patrol node selection and keeps engaging. If no player qualifies, the hook returns null and vanilla patrol logic runs unchanged. Admins can toggle pausing with the bradleypatrol.toggle chat command; the toggle does not change the config value. The config exposes the pause toggle and engagement distance, and messages go through the language file so feedback is localisable.
Common use cases
Keep the APC focused on nearby players
Return a non-null value while a player is within a chosen radius so the APC does not wander to a random interest node mid-fight. This makes Bradley encounters feel more aggressive without editing its targeting logic.
Route the APC to a custom waypoint
Instead of returning early, teleport the APC toward a custom point or call your own movement logic, then return a non-null value to suppress the default patrol selection for that cycle.
Freeze Bradley during a server event
When a PvP event or boss phase is active, return a non-null value for every patrol call so the APC stays in place. Clear the flag when the event ends to restore normal patrolling.
Pitfalls
The hook does not fire every update
The game only reaches the hook after a minimum 20-second patrol interval and only when the APC has no path or is at its final destination. Do not rely on this hook for per-tick movement logic; use it for decision-level gating.
Returning early does not stop combat
Suppressing the patrol branch prevents a new random patrol node from being chosen. The APC still runs its own targeting, firing and movement code elsewhere, so it can still shoot and pursue the current target.
State leaks across APC instances
If you track per-APC state, key it by
bradleyAPC.net.ID.Valueand clear entries onOnEntityKillorOnEntityDeath, otherwise stale entries survive respawns.
Build a plugin with OnBradleyApcPatrol
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 OnBradleyApcPatrol
Generate