Skip to content
RustPluginGenerator

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

NoDecay.cs
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.

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

Chat and console commands
CommandWhat it doesPermission
/nodecayPrints the current decay multiplier for each category.nodecay.info
Permissions
PermissionGrants
nodecay.infoAllows a player to run /nodecay and read the active multipliers.

How the code works

  1. 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-check entity and hitInfo, then call hitInfo.damageTypes.GetMajorityDamageType(). If it is not Rust.DamageType.Decay, return null immediately so vanilla behavior continues untouched. Only decay events go on to the classification step, which keeps the cost per hit near zero.

  2. Classify the entity and pick a multiplier

    The plugin runs the target through three checks in order. A BuildingBlock is matched on its grade value (BuildingGrade.Enum.Twigs, Wood, Stone, Metal, TopTier), so each building material has its own [JsonProperty] multiplier. Non-block entities are matched against BaseVehicle, MiniCopter, BaseHelicopter, ModularCar and BaseBoat for the vehicle multiplier. Everything else combat-entity is treated as a deployable. The result is a float: 0 cancels, 1 passes through.

  3. Cancel or scale the damage

    When the multiplier is zero the plugin calls hitInfo.damageTypes.ScaleAll(0f) and returns true, which tells Oxide the damage was handled and stops it reaching the entity. For other values it calls ScaleAll(multiplier) and returns null, letting Rust apply the reduced (or amplified) amount through the normal pipeline, so health bars and the destruction check still work. A multiplier of 1 is a no-op.

  4. Use the config correctly

    All knobs live in one nested PluginConfig class with [JsonProperty] names like "Twig multiplier" and "Deployable multiplier". LoadDefaultConfig seeds sane defaults (twig and wood full decay, stone half, metal and top tier off, vehicles off), LoadConfig falls back to defaults with a warning if the file fails to parse, and SaveConfig writes it back. Admins edit oxide/config/NoDecay.json and reload with oxide.reload NoDecay.

  5. Keep the hot path quiet

    OnEntityTakeDamage can fire hundreds of times per second on a busy server, so the plugin never calls Puts, PrintWarning or lang.GetMessage inside it. Logging only happens at startup in OnServerInitialized, where the plugin prints the loaded multipliers. The /nodecay command is the only player-facing surface and it reads cached config values, not the hook path.

  6. 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 a MiniCopter is a BaseCombatEntity too. If you want vehicles to still be destroyable by bullets and explosions, leave the multiplier at 0: the hook only ever touches decay damage.

Install it on your server

  1. Save NoDecay.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/NoDecay.json (Carbon: carbon/configs/NoDecay.json). After editing, reload it:oxide.reload NoDecay c.reload NoDecay # Carbon
  4. Grant the permission

    Give it to every player, or swap default for a group such as vip: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 version
  • Announce decay to owners

    Send a chat warning when a building takes decay damage.

    Generate this version
  • Full 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.

Prompt: Write an Oxide Rust plugin named NoDecay that cancels or scales decay damage per category, with JSON multipliers for twig, wood, stone, metal, top tier, deployables and vehicles.
Customize for my server

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

Last updated Oct 26, 2026.

Customize no decay

Customize