How to make a Rust no-decay plugin (per-category multipliers)
Scales or disables decay damage for building blocks by grade, deployables and vehicles using configurable multipliers. It hooks OnEntityTakeDamage, reads the damage type and the entity type, and returns null when decay should be cancelled.
Decay is the slow tax Rust puts on everything you leave standing. Admins who run PvE, modded or seasonal servers usually want to tune it rather than remove it outright: keep twig and wood decay honest, make stone and metal last longer, leave vehicles safe. A single global on/off switch is too blunt, and editing decay rates in the server's decay settings hits every entity at once.
This plugin intercepts damage before it is applied. In OnEntityTakeDamage it checks whether the majority damage type is Rust.DamageType.Decay. If so, it identifies the target: a BuildingBlock (by grade), a deployable BaseCombatEntity without a building block, or a vehicle type. Each category has its own multiplier in the config, so 0 cancels decay, 1 leaves it untouched and 0.25 slows it to a quarter. Anything that is not decay damage is left alone by returning null.
The plugin code
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("No Decay", "RustPluginGenerator", "1.0.0")]
[Description("Cancels or scales decay damage per building grade, deployable and vehicle.")]
public class NoDecay : RustPlugin
{
private const string PermInfo = "nodecay.info";
private PluginConfig config;
private class PluginConfig
{
[JsonProperty("Twig multiplier")]
public float Twig { get; set; } = 1f;
[JsonProperty("Wood multiplier")]
public float Wood { get; set; } = 1f;
[JsonProperty("Stone multiplier")]
public float Stone { get; set; } = 0.5f;
[JsonProperty("Metal multiplier")]
public float Metal { get; set; } = 0f;
[JsonProperty("Top tier multiplier")]
public float TopTier { get; set; } = 0f;
[JsonProperty("Deployable multiplier")]
public float Deployable { get; set; } = 0.5f;
[JsonProperty("Vehicle multiplier")]
public float Vehicle { get; set; } = 0f;
}
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>
{
["Info"] = "Decay multipliers: twig {0}, wood {1}, stone {2}, metal {3}, top tier {4}, deployable {5}, vehicle {6}",
["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(PermInfo, this);
}
private void OnServerInitialized()
{
Puts($"NoDecay active. Multipliers: twig={config.Twig}, wood={config.Wood}, stone={config.Stone}, metal={config.Metal}, top={config.TopTier}, deployable={config.Deployable}, vehicle={config.Vehicle}");
}
private object OnEntityTakeDamage(BaseCombatEntity entity, HitInfo hitInfo)
{
if (entity == null || hitInfo == null) return null;
if (hitInfo.damageTypes == null) return null;
if (hitInfo.damageTypes.GetMajorityDamageType() != Rust.DamageType.Decay) return null;
float multiplier = GetMultiplier(entity);
if (multiplier <= 0f)
{
hitInfo.damageTypes.ScaleAll(0f);
return true;
}
if (multiplier != 1f)
{
hitInfo.damageTypes.ScaleAll(multiplier);
}
return null;
}
private float GetMultiplier(BaseCombatEntity entity)
{
BuildingBlock block = entity as BuildingBlock;
if (block != null)
{
switch (block.grade)
{
case BuildingGrade.Enum.Twigs: return config.Twig;
case BuildingGrade.Enum.Wood: return config.Wood;
case BuildingGrade.Enum.Stone: return config.Stone;
case BuildingGrade.Enum.Metal: return config.Metal;
case BuildingGrade.Enum.TopTier: return config.TopTier;
default: return 1f;
}
}
if (entity is BaseVehicle || entity is BaseHelicopter || entity is ModularCar || entity is BaseBoat)
{
return config.Vehicle;
}
return config.Deployable;
}
[ChatCommand("nodecay")]
private void CmdNoDecay(BasePlayer player, string command, string[] args)
{
if (player == null) return;
if (!permission.UserHasPermission(player.UserIDString, PermInfo))
{
player.ChatMessage(Msg("NoPermission", player.UserIDString));
return;
}
player.ChatMessage(Msg("Info", player.UserIDString,
config.Twig, config.Wood, config.Stone, config.Metal, config.TopTier, config.Deployable, config.Vehicle));
}
}
}Hooks used: OnServerInitialized, OnEntityTakeDamage
Config file
Created automatically on first load at oxide/config/NoDecay.json.
{
"Twig multiplier": 1,
"Wood multiplier": 1,
"Stone multiplier": 0.5,
"Metal multiplier": 0,
"Top tier multiplier": 0,
"Deployable multiplier": 0.5,
"Vehicle multiplier": 0
}Commands and permissions
| Command | What it does | Permission |
|---|---|---|
/nodecay | Prints the current decay multiplier for each category. | nodecay.info |
| Permission | Grants |
|---|---|
nodecay.info | Allows a player to run /nodecay and read the active multipliers. |
How the code works
Detect decay damage first
The hook
object OnEntityTakeDamage(BaseCombatEntity entity, HitInfo hitInfo)fires for every damage event in the game, so the first job is to bail out cheaply. Null-checkentityandhitInfo, then callhitInfo.damageTypes.GetMajorityDamageType(). If it is notRust.DamageType.Decay, returnnullimmediately so vanilla behavior continues untouched. Only decay events go on to the classification step, which keeps the cost per hit near zero.Classify the entity and pick a multiplier
The plugin runs the target through three checks in order. A
BuildingBlockis matched on itsgradevalue (BuildingGrade.Enum.Twigs,Wood,Stone,Metal,TopTier), so each building material has its own[JsonProperty]multiplier. Non-block entities are matched againstBaseVehicle,MiniCopter,BaseHelicopter,ModularCarandBaseBoatfor the vehicle multiplier. Everything else combat-entity is treated as a deployable. The result is a float:0cancels,1passes through.Cancel or scale the damage
When the multiplier is zero the plugin calls
hitInfo.damageTypes.ScaleAll(0f)and returnstrue, which tells Oxide the damage was handled and stops it reaching the entity. For other values it callsScaleAll(multiplier)and returnsnull, letting Rust apply the reduced (or amplified) amount through the normal pipeline, so health bars and the destruction check still work. A multiplier of1is a no-op.Use the config correctly
All knobs live in one nested
PluginConfigclass with[JsonProperty]names like"Twig multiplier"and"Deployable multiplier".LoadDefaultConfigseeds sane defaults (twig and wood full decay, stone half, metal and top tier off, vehicles off),LoadConfigfalls back to defaults with a warning if the file fails to parse, andSaveConfigwrites it back. Admins editoxide/config/NoDecay.jsonand reload withoxide.reload NoDecay.Keep the hot path quiet
OnEntityTakeDamagecan fire hundreds of times per second on a busy server, so the plugin never callsPuts,PrintWarningorlang.GetMessageinside it. Logging only happens at startup inOnServerInitialized, where the plugin prints the loaded multipliers. The/nodecaycommand is the only player-facing surface and it reads cached config values, not the hook path.Tune vehicle types deliberately
Vanilla vehicles take damage from many sources, and only a few of them are
Decay, so the vehicle multiplier mostly matters on cars and boats that Rust slowly rots when idle. The plugin checks vehicle types before the generic deployable fallback, because aMiniCopteris aBaseCombatEntitytoo. If you want vehicles to still be destroyable by bullets and explosions, leave the multiplier at0: the hook only ever touches decay damage.
Install it on your server
Save NoDecay.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/NoDecay.json(Carbon:carbon/configs/NoDecay.json). After editing, reload it:oxide.reload NoDecay c.reload NoDecay # CarbonGrant the permission
Give it to every player, or swapdefaultfor a group such asvip:oxide.grant group default nodecay.info c.grant group default nodecay.info # Carbon
Variations
Each one opens the generator with a ready prompt you can tweak.
Decay only while offline
Skip decay damage for entities whose building privilege owner is offline.
Generate this versionAnnounce decay to owners
Send a chat warning when a building takes decay damage.
Generate this versionFull decay bypass with permission
Grant no decay to specific players via a permission like nodecay.bypass.
Generate this version
FAQ
Does this also stop decay on hovercraft and horse troughs?
Vehicles matched by the plugin are BaseVehicle, MiniCopter, BaseHelicopter, ModularCar and BaseBoat, and most other deployables fall into the generic deployable bucket. Anything the plugin fails to classify is left alone, so if a specific entity still decays you can add a type check in the classification method.
Will setting TopTier to 0 make bases indestructible?
No. The hook only touches events whose majority damage type is Decay. Bullets, explosives, fire and falling damage are untouched and still apply normally.
How do I install it on Oxide or Carbon?
Drop NoDecay.cs into oxide/plugins, run oxide.reload NoDecay from the console, or c.reload NoDecay on Carbon, which loads the same file. The plugin creates oxide/config/NoDecay.json on first load.
Why do stone buildings still take damage with metal set to 0?
Stone and metal are different grades and have separate multipliers. The Stone multiplier controls BuildingGrade.Enum.Stone. If stone should not decay either, set it to 0 as well.
Does this plugin track entities or use data files?
No. It uses no Interface.Oxide.DataFileSystem writes, no timers and no per-entity state, so it is safe to reload at any time and adds no save-file footprint.
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 building plugins
- Auto closing doorsCloses doors a configurable number of seconds after a player opens them, with a per-player /autodoor toggle and a personal delay clamped to serverโฆOnDoorOpened
- Auto code lockAutomatically attaches a code lock with the player's saved personal code to every door or box they place, consuming a code lock from their inventory.OnServerInitializedOnEntityBuilt
- Auto upgrade on buildLets each player pick a building grade with /up 1-4, then upgrades every building block they place to that grade using resources taken from theirโฆOnServerInitializedOnEntityBuilt
Last updated Oct 26, 2026.
Customize no decay
Customize