Skip to content
RustPluginGenerator

OnEntityDestroy

OnEntityDestroy is called from the OnDied handler of the CH47 Chinook and the Bradley APC, right before their death effects and loot drops run. Returning a non-null value stops that death code from executing.

Signature
object OnEntityDestroy(CH47HelicopterAIController entity)

Parameters

Hook parameters
ParameterTypeDescription
entityCH47HelicopterAIControllerThe CH47 Chinook or Bradley APC that is going through its death routine. For the Chinook it is a CH47HelicopterAIController, for the Bradley it is a BradleyAPC.

Return value

Return null to let the game continue with its normal death handling (crate drop for the Chinook, explosion marker, explosion effect and loot for the Bradley). Returning any non-null value skips the rest of that death method: no crate, no explosion effect, no loot.

How it works

The hook fires inside CH47HelicopterAIController.OnDied after the Chinook has already been marked dead, before the game checks its crates and drops a new one. It also fires inside BradleyAPC.OnDied before the APC creates its explosion marker, plays the explosion effect and spawns loot. Declaring the parameter as CH47HelicopterAIController makes Oxide call your method only for the Chinook; declaring BradleyAPC narrows it to the Bradley. The parameter is the entity itself, so net.ID.Value, transform.position and ShortPrefabName are available for logging, reward logic or respawn scheduling. This is not the general entity kill hook: it only covers these two AI vehicles and runs at death, not at despawn. Use it when you want a last-chance override of the vanilla death behavior or to react to a vehicle being destroyed. Because the return check happens before the loot logic, blocking the Chinook here also blocks the crate.

Other signatures

Oxide also calls OnEntityDestroy from other places in the game with these parameter types. Declare the overload you need, or several:

  • object OnEntityDestroy(BradleyAPC bradleyAPC)

Example plugin: Make vehicle deaths broadcast and pay a reward

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

namespace Oxide.Plugins
{
    [Info("Vehicle Destroy Reward", "RustPluginGenerator", "1.0.0")]
    [Description("Announces CH47 and Bradley deaths and rewards nearby players.")]
    public class VehicleDestroyReward : RustPlugin
    {
        private const string PermReward = "vehicledestroyreward.reward";

        private PluginConfig config;

        private class PluginConfig
        {
            [JsonProperty("Scrap reward per nearby player")]
            public int ScrapReward = 50;

            [JsonProperty("Reward radius (meters)")]
            public float RewardRadius = 100f;

            [JsonProperty("Broadcast vehicle deaths")]
            public bool BroadcastDeaths = true;
        }

        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>
            {
                ["Destroyed"] = "The {0} was destroyed at grid {1}.",
                ["Rewarded"] = "You received {0} scrap for helping destroy the {1}."
            }, 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);
        }

        private object OnEntityDestroy(CH47HelicopterAIController chinook)
        {
            if (chinook == null || chinook.IsDestroyed) return null;
            HandleDestroyed("CH47 Chinook", chinook.transform.position);
            return null;
        }

        private object OnEntityDestroy(BradleyAPC bradley)
        {
            if (bradley == null || bradley.IsDestroyed) return null;
            HandleDestroyed("Bradley APC", bradley.transform.position);
            return null;
        }

        private void HandleDestroyed(string vehicleName, Vector3 position)
        {
            string grid = PositionToGrid(position);
            int reward = config.ScrapReward;

            if (config.BroadcastDeaths)
            {
                Server.Broadcast(Msg("Destroyed", null, vehicleName, grid));
            }

            if (reward <= 0) return;

            float radiusSquared = config.RewardRadius * config.RewardRadius;
            foreach (BasePlayer player in BasePlayer.activePlayerList)
            {
                if (player == null || !player.IsConnected || player.IsDead()) continue;
                if (!permission.UserHasPermission(player.UserIDString, PermReward)) continue;
                if ((player.transform.position - position).sqrMagnitude > radiusSquared) continue;

                Item scrap = ItemManager.CreateByName("scrap", reward);
                if (scrap == null) continue;
                player.GiveItem(scrap);
                player.ChatMessage(Msg("Rewarded", player.UserIDString, reward, vehicleName));
            }
        }

        private string PositionToGrid(Vector3 position)
        {
            const float cellSize = 150f;
            int x = Mathf.FloorToInt((position.x + 2048f) / cellSize) + 1;
            int z = Mathf.FloorToInt((position.z + 2048f) / cellSize) + 1;
            return x + " " + z;
        }
    }
}

The plugin listens for OnEntityDestroy with the base-type-declared parameter CH47HelicopterAIController and a second overload for BradleyAPC, so both vehicles are handled. Each handler checks the entity is not already destroyed, resolves the last attacker through InvitedUsers-style tracking is avoided; instead it awards every online player who is near the vehicle a configurable scrap reward and broadcasts a chat announcement with the vehicle name and grid. The Chinook handler also keeps the vanilla crate drop because it returns null. A small helper builds the grid reference from transform.position and pushes it through the language file so the text is translatable.

Common use cases

  • Reward crews for downing a Bradley

    Award scrap or a currency via an optional Economics reference to nearby players when the APC dies. Since the hook returns null, the APC still explodes and drops its crate.

  • Block the Chinook crate

    Return a non-null value from the Chinook overload to skip DropCrate(), for example on a PvE server that wants no airdrop-style loot from the helicopter.

  • Announce and log vehicle kills

    Broadcast the CH47 or Bradley position and killer to chat, or write the event to oxide/data for later review of how often the vehicles are being farmed.

Pitfalls

  • This is not a general despawn hook

    OnEntityDestroy here only fires for the CH47 and Bradley death paths. A vehicle that is killed via admin command or admin Kill() may not pass through this code, and normal entities never call it.

  • Returning non-null cancels the Bradley explosion

    Blocking the Bradley death path also removes its explosion marker, explosion effect and loot spawn. Only return a value if you intentionally want to handle that yourself.

  • Use the correct parameter type

    An overload declared as BradleyAPC will not be called for the Chinook and vice versa. Declare both overloads, or a common base type such as BaseEntity, if you want one handler for both.

Build a plugin with OnEntityDestroy

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

Prompt: Reward crews for downing a Bradley using the OnEntityDestroy 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 OnEntityDestroy

Generate