Skip to content
RustPluginGenerator

OnTrapArm

OnTrapArm is called when a player arms a BearTrap, right before the trap is set armed. Returning a non-null value cancels the arming.

Signature
object OnTrapArm(BearTrap bearTrap, BasePlayer player)

Parameters

Hook parameters
ParameterTypeDescription
bearTrapBearTrapThe BearTrap entity being armed. Use it to read the trap's position, owner, flags or short prefab name, or to arm other logic around it.
playerBasePlayerThe BasePlayer whose client sent the arm RPC. It is the player who interacted with the trap to set it. May be null in edge cases, so always null-check it.

Return value

Return null to allow the trap to be armed normally. Return any non-null value to stop the original Arm() call, leaving the trap unarmed. The returned value is not used as a result by the game method (it returns void), so a sentinel like true or false both simply cancel arming.

How it works

This hook fires from BearTrap.RPC_Arm, the server-side RPC that runs when a player interacts with an unarmed bear trap to set it. It only runs while the trap is not already armed; the original method first checks Armed() and only then calls the hook. Because the call happens before Arm(), your code runs while the trap still has its unarmed state.

The first argument is the trap entity itself, useful for position checks (bearTrap.transform.position), ownership (OwnerID) or distance checks. The second is the BasePlayer who triggered the RPC, appropriate for permission checks, cooldowns or logging who set a trap where.

The return value is what controls behavior. Because the hook accepts any return value type and the original method only checks for null, returning anything non-null blocks Arm() from running. Returning null lets arming continue normally. There is no way to inspect the incoming RPC message payload, only the trap and the player.

You can narrow dispatch by declaring BearTrap specifically (as shown) so you only receive calls for bear traps; other trap types that might use the same hook name in future would be skipped.

Example plugin: Limit bear trap arming to one per player

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

namespace Oxide.Plugins
{
    [Info("Trap Arm Limit", "RustPluginGenerator", "1.0.0")]
    [Description("Limits how many bear traps a single player may arm at once and can block arming in restricted areas.")]
    public class TrapArmLimit : RustPlugin
    {
        private const string PermBypass = "traparmlimit.bypass";

        private class PluginConfig
        {
            [JsonProperty("Max armed bear traps per player")]
            public int MaxArmedTraps = 5;

            [JsonProperty("Maximum arm distance in meters")]
            public float MaxArmDistance = 4f;

            [JsonProperty("Message radius (chat warning only)")]
            public float MessageRadius = 2f;
        }

        private PluginConfig config;

        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>
            {
                ["LimitReached"] = "You already have {0} bear traps armed. Disarm one first.",
                ["TooFar"] = "You are too far from that bear trap to arm it."
            }, 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(PermBypass, this);
        }

        private object OnTrapArm(BearTrap bearTrap, BasePlayer player)
        {
            if (bearTrap == null || player == null) return null;
            if (permission.UserHasPermission(player.UserIDString, PermBypass)) return null;

            if (Vector3.Distance(player.transform.position, bearTrap.transform.position) > config.MaxArmDistance)
            {
                player.ChatMessage(Msg("TooFar", player.UserIDString));
                return true;
            }

            int owned = 0;
            foreach (var entity in BaseNetworkable.serverEntities)
            {
                var trap = entity as BearTrap;
                if (trap == null || trap.IsDestroyed) continue;
                if (trap == bearTrap) continue;
                if (trap.OwnerID != player.userID.Get()) continue;
                if ((trap.HasFlag(BaseEntity.Flags.On) || trap.Armed())) owned++;
            }

            if (owned >= config.MaxArmedTraps)
            {
                player.ChatMessage(Msg("LimitReached", player.UserIDString, config.MaxArmedTraps));
                return true;
            }

            return null;
        }
    }
}

The plugin tracks how many bear traps each player has currently armed, using the trap owner id. When OnTrapArm fires it looks up the player's configured limit from the config, counts existing armed traps owned by that user, and if the count has reached the limit sends a chat message and returns true to block the new arm. It also checks an optional permission bypass and a max distance from the trap to catch odd interactions. A periodic timer clears stale entries for players who disconnect, and armed traps placed via other paths are still counted because the count is recomputed against BaseNetworkable.serverEntities each call rather than cached.

Common use cases

  • Per-player trap limits

    Prevent a single player from arming dozens of bear traps around a base by counting their currently armed traps and cancelling the arm when a configured cap is reached.

  • Restricted zones

    Return non-null when bearTrap.transform.position falls inside a protected area such as a spawn zone, so players cannot set traps near safe areas.

  • Audit logging

    Record which player armed which trap and where, writing the data to a small runtime list to help admins investigate trap-related reports without blocking arming.

Pitfalls

  • Returning false still blocks arming

    The injection compares the returned value to null, not to true. Returning false cancels arming just like returning true. Always return null when you want to let the trap arm.

  • Trap is not armed yet

    The hook runs before Arm() executes, so HasFlag(BaseEntity.Flags.On) is not reliable as an armed indicator at this point. Count existing traps via the entity list or stored state instead of the current trap.

  • Player can be null on some paths

    RPCs normally arrive from a connected client, but null-check player anyway before touching player.UserIDString or sending chat messages to avoid a hook-thrown exception.

Build a plugin with OnTrapArm

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

Prompt: Per-player trap limits using the OnTrapArm 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 OnTrapArm

Generate