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
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.
{
"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
| Command | What it does | Permission |
|---|---|---|
pvetraps.status | Prints whether player protection is enabled and how many trap prefabs are configured. | pvetraps.admin |
| Permission | Grants |
|---|---|
pvetraps.admin | Allows the pvetraps.status console command. |
How the code works
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 whenhitInfo.Initiatoris null.Initiator.ShortPrefabNametells you what caused the hit:flameturret,guntrap,shotgun_trapandtrap.fireballby default. The config arrayPlayer Proof Trap Prefabsis loaded into thetrapPrefabshash set, and every entry passes throughNormalizePrefab, which strips a leading path so a full prefab path still matches.Only block damage when the victim is a player
The hook receives a plain
BaseCombatEntity, so the plugin casts it toBasePlayerfirst. 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 intrapPrefabs,CancelDamagezeroes the damage list and the hook returns true to stop further damage handling for that hit.Handle landmines separately
Landmines are checked before the prefab list through
IsLandmine, which compares the attacker's short prefab name totrap.landmine. TheProtect From Landminesconfig key gates that branch. Because the player check already happened above, zeroing the damage types is enough; no radius or ownership lookup is needed.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 checksProtect From Turret Targetingand whethertargis aBasePlayer, then returns false. Anything that is not a player returns null, so the default decision is unchanged.Leave non-player victims untouched
Nothing in the plugin special-cases NPCs or animals. The
entity is BasePlayercast 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.Config, permissions and reload
PluginConfigholds three booleans and astring[], all with[JsonProperty]names.LoadConfigfalls back to defaults and warns when the file is unreadable, then callsSaveConfigandRebuildTrapSetso the prefab set is current. The permissionpvetraps.adminis registered inInitand guards thepvetraps.statusconsole command, which reports the current settings.
Install it on your server
Save PveTraps.cs
Keep the file name exactly as the class name. Oxide matches them.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.Edit the config if you want
On first load the default config is written tooxide/config/PveTraps.json(Carbon:carbon/configs/PveTraps.json). After editing, reload it:oxide.reload PveTraps c.reload PveTraps # CarbonGrant the permission
Give it to every player, or swapdefaultfor a group such asvip: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 versionAnnounce blocked trap damage to the victim
Send a short chat line when a player would have been killed by a trap shot.
Generate this versionExtend 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.
Edit the prompt on the next screen. 2 free plugins a month, no card.
More pve plugins
- Building damage protectionBlocks and deployables only take damage from their owner or players authorized on the covering tool cupboard.OnEntityTakeDamage
- Player corpse loot protectionLocks a dead player's corpse and dropped backpack to the owner and their current team for a configurable number of minutes.OnServerInitializedOnEntitySpawnedCanLootEntity
- Heli and Bradley loot lockTracks damage dealt to the Patrol Helicopter and Bradley APC per player and locks the crates they drop for a configurable time, allowing only theโฆOnServerInitializedOnServerSaveOnEntityTakeDamage
Last updated Oct 26, 2026.
Customize traps that ignore players
Customize