Skip to content
RustPluginGenerator

CanHelicopterTarget

CanHelicopterTarget is called from PatrolHelicopterAI.PlayerVisible when the patrol helicopter checks whether it can see a specific player. Returning a bool overrides the game's line-of-sight result for that check.

Signature
object CanHelicopterTarget(PatrolHelicopterAI patrolHelicopterAI, BasePlayer ply)

Parameters

Hook parameters
ParameterTypeDescription
patrolHelicopterAIPatrolHelicopterAIThe PatrolHelicopterAI instance that is evaluating whether it can see and target a player. Use it to read the helicopter's position, health or identity if you need per-helicopter rules.
plyBasePlayerThe BasePlayer being tested for visibility. This is the player the helicopter is considering as a target, not necessarily the attacker.

Return value

Return a bool to override the visibility result: true makes the AI treat the player as visible and eligible to target, false makes it treat the player as not visible. Return null, or anything that is not a bool, to let the game's normal line-of-sight check run unchanged.

How it works

The hook fires inside PatrolHelicopterAI.PlayerVisible(BasePlayer ply), which the helicopter AI calls while scanning for and confirming targets. Every visibility test for a player goes through this method, so the hook can run frequently while a helicopter is active and players are near it. Use ply to inspect the candidate target (team, position, mounted state, permissions) and patrolHelicopterAI to key rules to a specific helicopter.

Because the original method returns bool, Oxide accepts a returned bool as the visibility result: true tells the AI the player is visible (so it may target and shoot), false tells it the player is not visible. Any other return value or null lets the normal line-of-sight check run. Declaring ply as a more specific type such as BasePlayer is already the given signature; there is no narrower player subtype to exploit here, but you can still filter inside the method (for example skip NPCs, sleeping players or players inside safe zones).

Practical uses are safe zones, event arenas, VIP immunity, and temporary truces. Keep the method cheap: it may be called repeatedly per helicopter and per nearby player, so avoid allocations, raycasts or lookups that could run every tick.

Example plugin: Keep players safe inside safe zones from the patrol helicopter

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

namespace Oxide.Plugins
{
    [Info("HelicopterSafeZone", "RustPluginGenerator", "1.0.0")]
    [Description("Prevents the patrol helicopter from targeting players inside configured safe zones")]
    public class HelicopterSafeZone : RustPlugin
    {
        private const string PermSafe = "helicoptersafezone.safe";

        private PluginConfig config;

        private class PluginConfig
        {
            [JsonProperty("Use permission")]
            public bool UsePermission = true;

            [JsonProperty("Safe zone centres")]
            public List<Zone> Zones = new List<Zone>
            {
                new Zone { X = 0f, Y = 0f, Z = 0f, Radius = 50f }
            };
        }

        private class Zone
        {
            [JsonProperty("X")]
            public float X;

            [JsonProperty("Y")]
            public float Y;

            [JsonProperty("Z")]
            public float Z;

            [JsonProperty("Radius")]
            public float Radius;
        }

        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>
            {
                ["ZoneReloaded"] = "Helicopter safe zones reloaded. Zones: {0}"
            }, 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(PermSafe, this);
        }

        [ChatCommand("hszreload")]
        private void CmdReload(BasePlayer player, string command, string[] args)
        {
            if (player != null && !player.IsAdmin) return;

            LoadConfig();
            string text = Msg("ZoneReloaded", player?.UserIDString, config.Zones.Count);
            if (player != null) SendReply(player, text);
            else Puts(text);
        }

        private object CanHelicopterTarget(PatrolHelicopterAI patrolHelicopterAI, BasePlayer ply)
        {
            if (patrolHelicopterAI == null || ply == null || !ply.IsConnected) return null;
            if (ply.IsDead() || ply.IsSleeping()) return null;

            if (config.UsePermission && !permission.UserHasPermission(ply.UserIDString, PermSafe)) return null;

            Vector3 position = ply.transform.position;
            for (int i = 0; i < config.Zones.Count; i++)
            {
                Zone zone = config.Zones[i];
                Vector3 centre = new Vector3(zone.X, zone.Y, zone.Z);
                if (Vector3.Distance(position, centre) <= zone.Radius) return false;
            }

            return null;
        }
    }
}

The plugin hooks CanHelicopterTarget and, before any game line-of-sight check runs, decides whether the candidate is protected. It checks that the player is valid and connected, then confirms the player has the configured permission and is standing inside a defined safe-zone sphere. Protected players return false, so the helicopter treats them as invisible and will not target them. Everyone else returns null, which keeps the default visibility logic. Safe-zone centres, radius and the permission toggle live in the config, and a chat command lets admins reload settings at runtime without restarting the server.

Common use cases

  • Safe-zone protection

    Make players standing in designated safe areas invisible to the patrol helicopter so it never targets them while they trade or bank loot.

  • Event arenas

    During a custom event, deny helicopter targeting for everyone outside the arena bounds so the helicopter only engages participants.

  • VIP immunity

    Grant a permission that makes a player temporarily untargetable by the helicopter, for example as a donor perk or as part of a revive timer.

Pitfalls

  • Runs often

    The hook is invoked each time the helicopter evaluates a player, which can be many times per second while players are nearby. Keep the logic allocation-free and avoid heavy lookups or printing to console.

  • Returning a bool always overrides

    If you return true or false unconditionally you replace the game's real line-of-sight check, which can make the helicopter target through walls or ignore players it should see. Return null when your rule does not apply.

  • Final targets are chosen elsewhere

    Returning false only makes the player invisible to this check. The helicopter can still be pushed toward targets by other AI paths and hooks such as OnHelicopterTarget, so test the full engagement loop on a live server.

Build a plugin with CanHelicopterTarget

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

Prompt: Safe-zone protection using the CanHelicopterTarget 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 CanHelicopterTarget

Generate