Skip to content
RustPluginGenerator

CanAffordUpgrade

CanAffordUpgrade is called when a player requests a structure upgrade and the server checks whether that player can pay for it. Returning a bool overrides the affordability result.

Signature
object CanAffordUpgrade(BasePlayer player, BuildingBlock buildingBlock, BuildingGrade.Enum grade, ulong skin)

Parameters

Hook parameters
ParameterTypeDescription
playerBasePlayerThe BasePlayer who is trying to pay for the upgrade. Can be null in edge cases, so guard before reading anything from it.
buildingBlockBuildingBlockThe BuildingBlock being upgraded; use it to read grade, buildingID, position and ownership of the structure.
gradeBuildingGrade.EnumThe BuildingGrade.Enum target grade the player is upgrading to (Twigs, Wood, Stone, Metal, TopTier).
skinulongThe skin ID the resulting upgraded block will use; 0 means the default grade skin.

Return value

Return true to let the player be treated as able to afford the upgrade, or false to block it. Returning null (or any non-bool) leaves the decision to the vanilla check that follows the hook, including the creative free-build path.

How it works

This hook fires inside BuildingBlock.CanAffordUpgrade, the internal check that runs after a player selects an upgrade via the building planner or hammer. It runs before the server actually upgrades anything, so it is the correct place to decide whether the player is allowed to pay and proceed. The player argument identifies who is upgrading; buildingBlock is the structure being changed, which lets you inspect its current grade, building ID, position and owning privilege. grade is the target grade and skin is the skin applied to the new block.

Because Oxide dispatches by parameter type, declaring player as BasePlayer already narrows nothing here (the argument is a BasePlayer), but you can safely null-check and read buildingBlock.buildingID or buildingBlock.GetBuildingPrivilege(). The hook only runs for real upgrade attempts, not every frame, so light work is fine.

Returning a bool forces the affordability answer; returning null lets vanilla logic continue (creative free-build checks, material/currency costs, tool cupboard rules).

Example plugin: Charge a scrap fee before allowing upgrades

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

namespace Oxide.Plugins
{
    [Info("Upgrade Scrap Fee", "RustPluginGenerator", "1.0.0")]
    [Description("Charges a scrap fee before a player is allowed to upgrade a building block.")]
    public class UpgradeScrapFee : RustPlugin
    {
        private const string PermExempt = "upgradescrapfee.exempt";

        private PluginConfig config;

        public class PluginConfig
        {
            [JsonProperty("Scrap fee Wood")]
            public int Wood = 5;

            [JsonProperty("Scrap fee Stone")]
            public int Stone = 15;

            [JsonProperty("Scrap fee Metal")]
            public int Metal = 30;

            [JsonProperty("Scrap fee TopTier")]
            public int TopTier = 60;
        }

        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>
            {
                ["NotEnoughScrap"] = "You need {0} scrap to upgrade to {1}.",
                ["Charged"] = "Upgrade fee: {0} scrap taken."
            }, 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(PermExempt, this);
        }

        private int FeeFor(BuildingGrade.Enum grade)
        {
            switch (grade)
            {
                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 0;
            }
        }

        private object CanAffordUpgrade(BasePlayer player, BuildingBlock buildingBlock, BuildingGrade.Enum grade, ulong skin)
        {
            if (player == null || buildingBlock == null) return null;
            if (permission.UserHasPermission(player.UserIDString, PermExempt)) return null;

            int fee = FeeFor(grade);
            if (fee <= 0) return null;

            var main = player.inventory?.containerMain;
            if (main == null) return false;

            if (main.GetAmount(ItemManager.FindItemDefinition("scrap").itemid) < fee)
            {
                player.ChatMessage(Msg("NotEnoughScrap", player.UserIDString, fee, grade.ToString()));
                return false;
            }

            var collect = new List<Item>();
            player.inventory.Take(collect, ItemManager.FindItemDefinition("scrap").itemid, fee);
            player.ChatMessage(Msg("Charged", player.UserIDString, fee));
            return true;
        }
    }
}

The plugin requires a scrap fee to be present in the player's inventory before allowing any structure upgrade, ignoring the normal vanilla material cost. When CanAffordUpgrade fires, it looks up the configured scrap cost for the target grade, checks the player's main container inventory with GetAmount, and returns false when the player is short. If the player has enough scrap, the plugin takes the scrap with Take and returns true so the upgrade proceeds. A short chat message tells the player what is missing. The fee per grade is stored in the config so admins can tune it without editing code.

Common use cases

  • Scrap or currency upgrade tax

    Take scrap or an Economics balance before letting players upgrade, acting as a server economy sink.

  • Restrict grades by permission

    Return false when the player lacks a permission for metal or top-tier upgrades, so only donators can build armored bases.

  • Raid or combat lockout

    Block upgrades while the player is recently damaged or in combat, preventing mid-fight wall upgrades.

Pitfalls

  • Returning true skips vanilla cost

    If you return true you are replacing the vanilla affordability check, so handle material or currency deductions yourself or players get free upgrades.

  • Charge inside the hook only after you allow

    Deduct items or currency only when you intend to return true; if you take resources and then return false the player loses them for nothing.

  • player can be null

    Guard against a null player before reading inventory or permissions, otherwise the hook can throw on odd upgrade paths.

Build a plugin with CanAffordUpgrade

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

Prompt: Scrap or currency upgrade tax using the CanAffordUpgrade 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 CanAffordUpgrade

Generate