Skip to content
RustPluginGenerator

How to make a Rust PvE traps plugin (traps ignore players)

Makes auto turrets, flame turrets, shotgun traps and landmines skip players entirely: turrets drop the player as a target and any trap damage aimed at a player is cancelled. Uses OnTurretTarget and OnEntityTakeDamage.

On a PvE server, base defenses built to stop raiders mostly shoot your own players. Auto turrets lock onto teammates who walk past the compound, flame turrets cook anyone near the gate, and a landmine in a doorway kills the owner. Players end up either not building defenses or peeking at each trap's auth list.

This plugin solves it with two hooks. OnTurretTarget returns false when the candidate is a player, so auto turrets keep scanning for other targets. OnEntityTakeDamage checks the attacker's short prefab name: any damage whose initiator matches a configured trap prefab is cancelled when the victim is a player, and trap.landmine is handled as its own toggle.

The config lists the trap prefabs that count as player-proof and separate switches for landmines, turret targeting and flame turrets.

The plugin code

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

namespace Oxide.Plugins
{
    [Info("PveTraps", "RustPluginGenerator", "1.0.0")]
    [Description("Stops auto turrets, flame turrets, shotgun traps and landmines from damaging players.")]
    public class PveTraps : RustPlugin
    {
        private const string PermAdmin = "pvetraps.admin";

        private PluginConfig config;
        private readonly HashSet<string> trapPrefabs = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

        private class PluginConfig
        {
            [JsonProperty("Player Proof Trap Prefabs")]
            public string[] TrapPrefabs =
            {
                "flameturret",
                "guntrap",
                "shotgun_trap",
                "trap.fireball"
            };

            [JsonProperty("Landmine Prefab")]
            public string LandminePrefab = "trap.landmine";

            [JsonProperty("Protect From Landmines")]
            public bool ProtectFromLandmines = true;

            [JsonProperty("Protect From Turret Targeting")]
            public bool ProtectFromTurretTargeting = true;

            [JsonProperty("Protect From Flame Turrets")]
            public bool ProtectFromFlameTurrets = 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();
            RebuildTrapSet();
        }

        protected override void SaveConfig() => Config.WriteObject(config);

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                ["Status"] = "PvE traps: landmines {0}, turret targeting {1}, flame turrets {2}, {3} trap prefabs configured.",
                ["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(PermAdmin, this);
            LoadDefaultMessages();
            RebuildTrapSet();
        }

        private void RebuildTrapSet()
        {
            trapPrefabs.Clear();
            if (config?.TrapPrefabs == null) return;
            foreach (var prefab in config.TrapPrefabs)
            {
                if (string.IsNullOrEmpty(prefab)) continue;
                trapPrefabs.Add(NormalizePrefab(prefab));
            }
        }

        private static string NormalizePrefab(string prefab)
        {
            if (string.IsNullOrEmpty(prefab)) return string.Empty;
            int slash = prefab.LastIndexOf('/');
            if (slash >= 0 && slash < prefab.Length - 1) prefab = prefab.Substring(slash + 1);
            return prefab.Trim();
        }

        private bool IsLandmine(string prefab)
        {
            if (string.IsNullOrEmpty(prefab)) return false;
            string configured = NormalizePrefab(config?.LandminePrefab ?? "trap.landmine");
            return prefab.Equals(configured, StringComparison.OrdinalIgnoreCase);
        }

        private object OnEntityTakeDamage(BaseCombatEntity entity, HitInfo hitInfo)
        {
            if (entity == null || hitInfo == null) return null;
            if (!(entity is BasePlayer)) return null;
            if (hitInfo.Initiator == null) return null;

            var attacker = hitInfo.Initiator.ShortPrefabName;
            if (string.IsNullOrEmpty(attacker)) return null;

            if (config.ProtectFromLandmines && IsLandmine(attacker))
            {
                CancelDamage(hitInfo);
                return true;
            }

            if (!trapPrefabs.Contains(attacker)) return null;

            if (!config.ProtectFromFlameTurrets &&
                attacker.Equals("flameturret", StringComparison.OrdinalIgnoreCase))
                return null;

            CancelDamage(hitInfo);
            return true;
        }

        private static void CancelDamage(HitInfo hitInfo)
        {
            if (hitInfo.damageTypes != null) hitInfo.damageTypes.ScaleAll(0f);
            hitInfo.damageTypes = new Rust.DamageTypeList();
        }

        private object OnTurretTarget(AutoTurret autoTurret, BaseCombatEntity targ)
        {
            if (autoTurret == null || targ == null) return null;
            if (!config.ProtectFromTurretTargeting) return null;
            if (!(targ is BasePlayer)) return null;
            return false;
        }

        [ConsoleCommand("pvetraps.status")]
        private void CcmdStatus(ConsoleSystem.Arg arg)
        {
            if (arg == null) return;
            var player = arg.Player();
            if (player != null && !permission.UserHasPermission(player.UserIDString, PermAdmin))
            {
                arg.ReplyWith(Msg("NoPermission", player.UserIDString));
                return;
            }

            arg.ReplyWith(Msg("Status", player?.UserIDString,
                config.ProtectFromLandmines ? "on" : "off",
                config.ProtectFromTurretTargeting ? "on" : "off",
                config.ProtectFromFlameTurrets ? "on" : "off",
                trapPrefabs.Count));
        }
    }
}

Hooks used: OnEntityTakeDamage, OnTurretTarget

Config file

Created automatically on first load at oxide/config/PveTraps.json.

PveTraps.json
{
  "Player Proof Trap Prefabs": [
    "flameturret",
    "guntrap",
    "shotgun_trap",
    "trap.fireball"
  ],
  "Landmine Prefab": "trap.landmine",
  "Protect From Landmines": true,
  "Protect From Turret Targeting": true,
  "Protect From Flame Turrets": true
}

Commands and permissions

Chat and console commands
CommandWhat it doesPermission
pvetraps.statusPrints whether player protection is enabled and how many trap prefabs are configured.pvetraps.admin
Permissions
PermissionGrants
pvetraps.adminAllows the pvetraps.status console command.

How the code works

  1. Classify trap damage by attacker prefab

    OnEntityTakeDamage(BaseCombatEntity entity, HitInfo hitInfo) fires for every damage event, so the first thing to do is bail out when hitInfo.Initiator is null. Initiator.ShortPrefabName tells you what caused the hit: flameturret, guntrap, shotgun_trap and trap.fireball by default. The config array Player Proof Trap Prefabs is loaded into the trapPrefabs hash set, and every entry passes through NormalizePrefab, which strips a leading path so a full prefab path still matches.

  2. Only block damage when the victim is a player

    The hook receives a plain BaseCombatEntity, so the plugin casts it to BasePlayer first. If the cast fails, the target is something else and the method returns null to keep vanilla behavior. When the cast succeeds and the attacker's short prefab name is in trapPrefabs, CancelDamage zeroes the damage list and the hook returns true to stop further damage handling for that hit.

  3. Handle landmines separately

    Landmines are checked before the prefab list through IsLandmine, which compares the attacker's short prefab name to trap.landmine. The Protect From Landmines config key gates that branch. Because the player check already happened above, zeroing the damage types is enough; no radius or ownership lookup is needed.

  4. Keep auto turrets from acquiring players

    object OnTurretTarget(AutoTurret autoTurret, BaseCombatEntity targ) is asked before an auto turret commits to a target. Returning false makes it discard that candidate and continue scanning. The plugin checks Protect From Turret Targeting and whether targ is a BasePlayer, then returns false. Anything that is not a player returns null, so the default decision is unchanged.

  5. Leave non-player victims untouched

    Nothing in the plugin special-cases NPCs or animals. The entity is BasePlayer cast simply fails for them, so the hit passes through unchanged and a base turret still shoots them normally. The only behavior change is the player branch, which keeps the plugin compatible with PvE and expanded NPC content.

  6. Config, permissions and reload

    PluginConfig holds three booleans and a string[], all with [JsonProperty] names. LoadConfig falls back to defaults and warns when the file is unreadable, then calls SaveConfig and RebuildTrapSet so the prefab set is current. The permission pvetraps.admin is registered in Init and guards the pvetraps.status console command, which reports the current settings.

Install it on your server

  1. Save PveTraps.cs

    Keep the file name exactly as the class name. Oxide matches them.
  2. Upload it to the plugins folder

    Oxide: oxide/plugins/. Carbon: carbon/plugins/. The server compiles and loads it within a few seconds, no restart needed.
  3. Edit the config if you want

    On first load the default config is written to oxide/config/PveTraps.json (Carbon: carbon/configs/PveTraps.json). After editing, reload it:oxide.reload PveTraps c.reload PveTraps # Carbon
  4. Grant the permission

    Give it to every player, or swap default for a group such as vip:oxide.grant group default pvetraps.admin c.grant group default pvetraps.admin # Carbon

Variations

Each one opens the generator with a ready prompt you can tweak.

  • Allow damage from player-placed landmines to other players

    Turn landmine protection into an opt-in per prefab so admins can keep mines lethal for everyone except the placer.

    Generate this version
  • Announce blocked trap damage to the victim

    Send a short chat line when a player would have been killed by a trap shot.

    Generate this version
  • Extend protection to fireballs and flame from other sources

    Cover rocket fire and thrown firebombs in addition to turret-mounted flame.

    Generate this version

FAQ

Do shotgun traps count as turrets for `OnTurretTarget`?

No. OnTurretTarget only fires for AutoTurret entities. Shotgun traps keep their normal target logic, so the plugin instead cancels their damage in OnEntityTakeDamage by matching the guntrap shortname. Players may still get shot at, but take no damage.

Will this stop turrets from shooting NPCs?

No. The turret hook only returns false when the candidate is a BasePlayer. For every other entity it returns null, so the turret makes its own decision and keeps firing. Only player targets are discarded.

Does it work on Oxide and Carbon?

Yes. The file is a standard Oxide plugin with no external dependencies. Drop it in oxide/plugins and reload; Carbon loads the same file from the same folder. Keep the file name matching the class name PveTraps.

How do I add a custom trap on my server?

Open oxide/config/PveTraps.json and add the entity's short prefab name to Player Proof Trap Prefabs. Reload the plugin. Run pvetraps.status from the server console to confirm the count changed.

Does it protect players from decay or bleeding?

No. Only damage whose attacker matches a configured trap prefab, or a landmine when enabled, is cancelled. Decay, bleeding, fall and radiation use different initiators or none at all, so they still apply.

Customize it for your server

Change the reward, add a cooldown, restrict it to VIPs. Start from this prompt and edit anything.

Prompt: Create a Rust Oxide plugin named PveTraps that makes auto turrets, flame turrets, shotgun traps and landmines never damage players while still damaging NPCs and animals, with a config list of trap prefabs.
Customize for my server

Edit the prompt on the next screen. 2 free plugins a month, no card.

Last updated Oct 26, 2026.

Customize traps that ignore players

Customize