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.
object CanAffordUpgrade(BasePlayer player, BuildingBlock buildingBlock, BuildingGrade.Enum grade, ulong skin)Parameters
| Parameter | Type | Description |
|---|---|---|
player | BasePlayer | The BasePlayer who is trying to pay for the upgrade. Can be null in edge cases, so guard before reading anything from it. |
buildingBlock | BuildingBlock | The BuildingBlock being upgraded; use it to read grade, buildingID, position and ownership of the structure. |
grade | BuildingGrade.Enum | The BuildingGrade.Enum target grade the player is upgrading to (Twigs, Wood, Stone, Metal, TopTier). |
skin | ulong | The 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
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.
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