Skip to content
RustPluginGenerator

OnApartmentRoomUpgrade

OnApartmentRoomUpgrade is called when a player attempts to upgrade their current apartment room to a larger size, before the server picks the destination room and moves the player.

Signature
object OnApartmentRoomUpgrade(ApartmentRoom playerApartment, BasePlayer player, ApartmentSize size, ApartmentBuilding apartmentBuilding)

Parameters

Hook parameters
ParameterTypeDescription
playerApartmentApartmentRoomThe ApartmentRoom the player is currently inside and is trying to upgrade to a larger size.
playerBasePlayerThe BasePlayer requesting the room upgrade.
sizeApartmentSizeThe ApartmentSize the room is being upgraded to. Compare against ApartmentSize enum values to gate specific tiers.
apartmentBuildingApartmentBuildingThe ApartmentBuilding instance that owns the room and is running TryUpgradeRoom.

Return value

Returning null lets the original method continue, which fetches the closest unoccupied room of the requested size and proceeds with the upgrade. Returning any non-null value makes TryUpgradeRoom return immediately, so the upgrade is cancelled and the player keeps their current room.

How it works

This hook fires inside ApartmentBuilding.TryUpgradeRoom, right after the server confirms the player has a current room and before it calls FetchClosestUnoccupiedRoom(size) to find the target room. It fires only on the upgrade attempt itself, not on the initial purchase (that path uses OnApartmentRoomPurchase).

The parameters cover the whole context of the request: playerApartment is the room being left, player is the requester, size is the requested destination tier, and apartmentBuilding is the parent building. Use player for permission checks and size to allow or deny specific upgrade tiers. Declaring the parameters with these exact apartment types narrows the hook to apartment upgrades only.

Returning any non-null value aborts the upgrade: the game method returns immediately and no new room is fetched, so the player stays in their current room. This is a natural place for an economy charge, cooldown check, or per-tier permission gate. Because the call happens before the destination room is known, you cannot inspect the target room here.

Example plugin: Gate apartment upgrades behind a permission per size

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

namespace Oxide.Plugins
{
    [Info("Apartment Upgrade Gate", "RustPluginGenerator", "1.0.0")]
    [Description("Requires a permission per apartment size and rate-limits upgrade attempts.")]
    public class ApartmentUpgradeGate : RustPlugin
    {
        private const string PermSmall = "apartmentupgradegate.small";
        private const string PermMedium = "apartmentupgradegate.medium";
        private const string PermLarge = "apartmentupgradegate.large";

        private PluginConfig config;
        private readonly Dictionary<ulong, float> lastAttempt = new Dictionary<ulong, float>();

        private class PluginConfig
        {
            [JsonProperty("Cooldown seconds between attempts")]
            public float CooldownSeconds = 5f;
        }

        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>
            {
                ["NoPermission"] = "You do not have permission to upgrade to this apartment size.",
                ["Cooldown"] = "Please wait {0} more seconds before upgrading again."
            }, 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(PermSmall, this);
            permission.RegisterPermission(PermMedium, this);
            permission.RegisterPermission(PermLarge, this);
        }

        private object OnApartmentRoomUpgrade(ApartmentRoom playerApartment, BasePlayer player, ApartmentSize size, ApartmentBuilding apartmentBuilding)
        {
            if (player == null || playerApartment == null)
                return null;

            float now = Time.realtimeSinceStartup;
            float last;
            if (lastAttempt.TryGetValue(player.userID.Get(), out last))
            {
                float remaining = config.CooldownSeconds - (now - last);
                if (remaining > 0f)
                {
                    player.ChatMessage(Msg("Cooldown", player.UserIDString, Mathf.CeilToInt(remaining)));
                    return false;
                }
            }
            lastAttempt[player.userID.Get()] = now;

            string perm = PermissionForSize(size);
            if (perm != null && !permission.UserHasPermission(player.UserIDString, perm))
            {
                player.ChatMessage(Msg("NoPermission", player.UserIDString));
                return false;
            }

            return null;
        }

        private static string PermissionForSize(ApartmentSize size)
        {
            string name = size.ToString().ToLowerInvariant();
            if (name.Contains("medium") || name.Contains("middle")) return PermMedium;
            if (name.Contains("large") || name.Contains("big")) return PermLarge;
            return PermSmall;
        }

        private void Unload()
        {
            lastAttempt.Clear();
        }
    }
}

The plugin maps each ApartmentSize to a permission (apartmentupgradegate.medium and similar) and registers them on load. When OnApartmentRoomUpgrade fires, it checks whether the player passes a quick cooldown check and holds the permission for the requested size. A missing permission sends a localized chat message telling the player which permission is required and returns a non-null value, which cancels the upgrade before the server reserves a new room. The cooldown dictionary prevents players from spamming the apartment terminal and is cleared on unload.

Common use cases

  • Charge an economy balance per upgrade

    Call into an Economy plugin with the player's ID and the cost for the requested size, and cancel the upgrade when the balance is too low.

  • Restrict large apartments to donors

    Compare the size parameter against the highest tier and block upgrades unless the player holds a VIP permission.

  • Rate-limit upgrades

    Track the last upgrade time per player ID and cancel repeat attempts inside a short window.

Pitfalls

  • Wrong size means no upgrade

    size is the requested destination tier, not the current room's size. Compare it against playerApartment only when you need the delta.

  • No destination room visible yet

    The server picks the new room after this hook, so FetchClosestUnoccupiedRoom has not run. Do not try to read the target room from the parameters.

  • No resource refund on cancel

    Returning non-null simply aborts the method; any cost the game would have applied is skipped, but no cleanup of prior state happens. Handle refunds yourself if you also charge elsewhere.

Build a plugin with OnApartmentRoomUpgrade

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

Prompt: Charge an economy balance per upgrade using the OnApartmentRoomUpgrade 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 OnApartmentRoomUpgrade

Generate