Skip to content
RustPluginGenerator

OnStructureUpgrade

OnStructureUpgrade is called when a player attempts to upgrade a building block to a new grade, before the upgrade cost is checked and applied. Returning a non-null value cancels the upgrade.

Signature
object OnStructureUpgrade(BuildingBlock buildingBlock, BasePlayer player, BuildingGrade.Enum type, ulong skin)

Parameters

Hook parameters
ParameterTypeDescription
buildingBlockBuildingBlockThe BuildingBlock entity being upgraded. Use it to read the current grade, building ID and owner, or to check the upgrade location.
playerBasePlayerThe player who triggered the upgrade. Use it for permission checks, team checks or to send feedback messages.
typeBuildingGrade.EnumThe target BuildingGrade.Enum (Twigs, Wood, Stone, Metal, TopTier) the block would be upgraded to.
skinulongThe skin ID of the target grade. Non-zero when a skinned building skin is being applied.

Return value

Returning null (or nothing) lets the upgrade continue to the affordability and attack-timer checks. Returning any non-null value stops DoUpgradeToGrade immediately, so the upgrade is cancelled with no cost and no change to the block.

How it works

The hook fires inside BuildingBlock.DoUpgradeToGrade, which runs when a player uses a building plan (or a building skin) on a placed block and requests a grade change. It runs before the server checks whether the player can afford the upgrade, before the recent-attack timer check, and before any grade, health or skin change happens. Because of that, blocking the hook means the player is never charged and the block stays exactly as it was.

All four arguments map to the upgrade request: buildingBlock is the target block, player is the requester, type is the destination grade and skin is the requested skin. There is no need to narrow the block type by declaring a more specific parameter, since only BuildingBlock instances are passed. You can still use the parameters to run permission checks, enforce grade restrictions per building privilege or per team, or implement custom upgrade costs.

Cancelling produces no chat message by default; send your own reply through the language system if the player needs to know why the upgrade was refused. Use OnStructureUpgraded for post-upgrade effects such as effects, logging or rewards.

Example plugin: Restrict structure upgrades to allowed grades per permission

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

namespace Oxide.Plugins
{
    [Info("UpgradeGradeLimiter", "RustPluginGenerator", "1.0.0")]
    [Description("Restricts which building grades players may upgrade to based on permissions")]
    public class UpgradeGradeLimiter : RustPlugin
    {
        private const string PermBypass = "upgradegradelimiter.bypass";

        private PluginConfig config;

        private class PluginConfig
        {
            [JsonProperty("Allowed grades without permissions")]
            public List<string> AllowedGrades { get; set; } = new List<string> { "Twigs", "Wood" };
        }

        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>
            {
                ["NotAllowed"] = "You are not allowed to upgrade to {0}.",
                ["AllowedList"] = "Allowed grades: {0}"
            }, 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);
            foreach (var grade in Enum.GetNames(typeof(BuildingGrade.Enum)))
            {
                if (grade == "None") continue;
                if (config.AllowedGrades.Contains(grade)) continue;
                permission.RegisterPermission(PermPrefix + grade.ToLower(), this);
            }
        }

        private const string PermPrefix = "upgradegradelimiter.";

        private object OnStructureUpgrade(BuildingBlock buildingBlock, BasePlayer player, BuildingGrade.Enum type, ulong skin)
        {
            if (buildingBlock == null || player == null) return null;
            if (type == BuildingGrade.Enum.None) return null;
            if (player.IsAdmin || permission.UserHasPermission(player.UserIDString, PermBypass)) return null;

            string gradeName = type.ToString();
            if (config.AllowedGrades.Contains(gradeName)) return null;

            string perm = PermPrefix + gradeName.ToLower();
            if (permission.UserHasPermission(player.UserIDString, perm)) return null;

            player.ChatMessage(Msg("NotAllowed", player.UserIDString, gradeName));
            return true;
        }
    }
}

The plugin reads a list of permitted grades from its config and registers one permission per allowed grade plus a bypass permission. When OnStructureUpgrade fires, admins and players with the bypass permission pass straight through. Otherwise the target grade is mapped to its permission string, and if the player lacks that permission the hook returns a non-null value to cancel the upgrade, then sends a localized message explaining which grades they may use. Messages go through the language system, and the grade list is rebuilt from config on plugin load so admins can adjust it without recompiling.

Common use cases

  • Paid or permission tiers for upgrades

    Require a permission or an economy balance before allowing a player to upgrade to Metal or TopTier, giving server owners a soft progression gate on building.

  • Stop downgrades on raided bases

    Reject requests that would set a block to a lower grade than it currently has, preventing players from cheaply resetting upkeep or repair costs after a raid.

  • Raid protection windows

    Cancel upgrades on blocks inside a building privilege that is under active raid protection, so defenders cannot reinforce walls while being attacked.

Pitfalls

  • Cancelling without feedback

    Returning non-null silently stops the upgrade; the client shows no reason. Always send a chat or console reply when you block so players are not confused.

  • Assuming the upgrade succeeded

    The hook runs before the affordability and attack-timer checks, so a null return does not guarantee the upgrade happens. Use OnStructureUpgraded for confirmation.

  • Ignoring the skin argument

    Building skins use the same upgrade path with a non-zero skin. If you gate by grade only, skinned upgrades may bypass rules you expect to apply.

Plugin recipes that use OnStructureUpgrade

Build a plugin with OnStructureUpgrade

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

Prompt: Paid or permission tiers for upgrades using the OnStructureUpgrade 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 OnStructureUpgrade

Generate