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.
object OnStructureUpgrade(BuildingBlock buildingBlock, BasePlayer player, BuildingGrade.Enum type, ulong skin)Parameters
| Parameter | Type | Description |
|---|---|---|
buildingBlock | BuildingBlock | The BuildingBlock entity being upgraded. Use it to read the current grade, building ID and owner, or to check the upgrade location. |
player | BasePlayer | The player who triggered the upgrade. Use it for permission checks, team checks or to send feedback messages. |
type | BuildingGrade.Enum | The target BuildingGrade.Enum (Twigs, Wood, Stone, Metal, TopTier) the block would be upgraded to. |
skin | ulong | The 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
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
OnStructureUpgradedfor 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.
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