OnApartmentRoomUpgraded
OnApartmentRoomUpgraded is called after a player successfully upgrades an apartment room to a larger size, once the room has already been changed and the player chat message has been sent.
void OnApartmentRoomUpgraded(ApartmentRoom apartmentRoom, BasePlayer player, ApartmentSize size, ApartmentBuilding apartmentBuilding)Parameters
| Parameter | Type | Description |
|---|---|---|
apartmentRoom | ApartmentRoom | The ApartmentRoom instance that was just upgraded. Use it to read RoomNumber and identify which room the player paid to upgrade. |
player | BasePlayer | The BasePlayer who performed the upgrade and paid the cost. This is the player to reward, notify or bill. |
size | ApartmentSize | The ApartmentSize the room was upgraded to. Compare or switch on it to apply size-specific logic. |
apartmentBuilding | ApartmentBuilding | The ApartmentBuilding that contains the room. Use it if you need to look at the building as a whole or its other rooms. |
Return value
The return value is ignored; the game method continues normally after the hook call. Returning null or any other value has no effect on the upgrade, and there is no way to undo or block the upgrade from this hook.
How it works
The hook fires inside ApartmentBuilding.TryUpgradeRoom, after the upgrade cost has been charged, the room has been resized, the player has been sent the "You have upgraded to room" chat message and the Azure analytics event has been emitted. It is therefore a pure post-success hook: everything that could fail has already been resolved. Use apartmentRoom.RoomNumber to identify the room, player to reward or notify the buyer, size to branch on the new apartment size, and apartmentBuilding when you need context about the whole building. Because the declared parameter types are matched exactly by Oxide's dispatch, declare ApartmentRoom, BasePlayer, ApartmentSize and ApartmentBuilding as given; narrowing any of them (for example using BaseEntity for the building) would work, but widening or swapping types would stop the hook from being called. This hook is not a cancellation point: the upgrade has already been applied, so it cannot be used to block or refund the purchase. Keep the body cheap because it runs inline with the game method.
Example plugin: Reward players who upgrade apartment rooms
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace Oxide.Plugins
{
[Info("Apartment Upgrade Reward", "RustPluginGenerator", "1.0.0")]
[Description("Gives players a configurable item reward when they upgrade an apartment room.")]
public class ApartmentUpgradeReward : RustPlugin
{
private const string PermUse = "apartmentupgradereward.use";
private PluginConfig config;
private readonly Dictionary<ulong, DateTime> lastReward = new Dictionary<ulong, DateTime>();
private class PluginConfig
{
[JsonProperty("Reward item shortname")]
public string RewardShortname = "scrap";
[JsonProperty("Reward amount")]
public int RewardAmount = 25;
[JsonProperty("Cooldown seconds")]
public int CooldownSeconds = 300;
}
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>
{
["Rewarded"] = "Room {0} upgraded. You received {1} x {2}.",
["Cooldown"] = "Room {0} upgraded, but your reward is on cooldown."
}, 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(PermUse, this);
}
private void OnApartmentRoomUpgraded(ApartmentRoom apartmentRoom, BasePlayer player, ApartmentSize size, ApartmentBuilding apartmentBuilding)
{
if (apartmentRoom == null || player == null || !player.IsConnected)
return;
if (!permission.UserHasPermission(player.UserIDString, PermUse))
return;
var roomNumber = apartmentRoom.RoomNumber;
DateTime last;
if (lastReward.TryGetValue(player.userID.Get(), out last) && (DateTime.UtcNow - last).TotalSeconds < config.CooldownSeconds)
{
player.ChatMessage(Msg("Cooldown", player.UserIDString, roomNumber));
return;
}
var item = ItemManager.CreateByName(config.RewardShortname, config.RewardAmount);
if (item == null)
{
PrintWarning($"Unknown reward shortname '{config.RewardShortname}', no reward given");
return;
}
var itemName = item.info != null ? item.info.displayName.english : config.RewardShortname;
player.GiveItem(item);
lastReward[player.userID.Get()] = DateTime.UtcNow;
player.ChatMessage(Msg("Rewarded", player.UserIDString, roomNumber, config.RewardAmount, itemName));
}
private void Unload()
{
lastReward.Clear();
}
}
}The plugin listens for OnApartmentRoomUpgraded and pays the buyer a configurable item reward each time they upgrade a room. On load it reads the reward shortname, amount and a cooldown from the config file. When the hook fires it checks the player is connected, confirms ItemManager.CreateByName returns a real item and applies a per-player cooldown so the reward cannot be farmed by upgrading repeatedly in a short window. The item is given with player.GiveItem and the player receives a localised chat message naming the room. All player-facing text lives in the language file, and the Unload method clears the cooldown dictionary.
Common use cases
Give a bonus item on every upgrade
Reward the buyer with scrap, resources or a custom item to encourage repeat apartment upgrades. Read the shortname and amount from config so admins can tune it.
Track apartment economy statistics
Count upgrades per player or per building and write the totals to a data file for leaderboards or admin reports.
Notify staff of large upgrades
Broadcast or log a message when a player upgrades a room to a high tier, giving admins visibility into apartment activity on the server.
Pitfalls
The upgrade already happened
Do not treat this as a validation hook. The cost has been charged and the room resized before the call, so returning a value or throwing will not prevent anything.
Null player or connection
Although the player is usually connected, always guard with
player == null,player.IsConnectedandplayer.net.connectionbefore sending chat or giving items.Farming rewards
Upgrades can be repeated, so apply a cooldown or a per-player cap if you hand out items, otherwise players can spam cheap upgrades to farm the reward.
Build a plugin with OnApartmentRoomUpgraded
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 OnApartmentRoomUpgraded
Generate