Skip to content
RustPluginGenerator

OnApartmentMasterKeyPurchased

OnApartmentMasterKeyPurchased is called after a player buys an apartment master key from NPCApartmentSecurity, once the key item has already been created and handed to the player's inventory.

Signature
void OnApartmentMasterKeyPurchased(BasePlayer player, Item item)

Parameters

Hook parameters
ParameterTypeDescription
playerBasePlayerThe BasePlayer who bought the master key. Matches the buyer passed into NPCApartmentSecurity.OnPurchaseKey.
itemItemThe Item instance for the master key that was just created and already given to the player through GiveItem. It has item ownership recorded as a vendor sale.

Return value

The return value is ignored. The original method is void and the hook call is the final statement in the purchase branch, so returning null or any other value has no effect on the game.

How it works

This hook fires inside NPCApartmentSecurity.OnPurchaseKey, immediately after the game creates the master key item with ItemManager.Create, records item ownership as a vendor sale, and gives it to the player via GiveItem. Because it is the last statement in the success branch, it only runs when the item creation succeeded.

The hook is observational: the purchase and item transfer are already done. player is the buyer, and item is the live key item that now sits in the buyer's inventory (or on the ground if the inventory was full, since GiveItem drops overflow). You can read item.skin, item.amount, or item.info.itemid to identify the key, and use player.userID or player.UserIDString to key your own data.

Because there is only one injection site, you cannot narrow which calls you receive by declaring a more specific parameter type; both arguments are always the exact player and key item. If you need to react before the key is given, use OnApartmentMasterKeyPurchase or CanAffordApartmentMasterKey instead.

Example plugin: Track and reward apartment master key purchases

ApartmentKeyTracker.cs
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;

namespace Oxide.Plugins
{
    [Info("Apartment Key Tracker", "RustPluginGenerator", "1.0.0")]
    [Description("Tracks apartment master key purchases and rewards repeat buyers.")]
    public class ApartmentKeyTracker : RustPlugin
    {
        private const string PermUse = "apartmentkeytracker.use";

        private PluginConfig config;
        private StoredData data;
        private Timer saveTimer;
        private bool dirty;

        private class PluginConfig
        {
            [JsonProperty("Reward every N purchases (0 disables)")]
            public int RewardEvery { get; set; } = 3;

            [JsonProperty("Reward item shortname")]
            public string RewardShortname { get; set; } = "scrap";

            [JsonProperty("Reward amount")]
            public int RewardAmount { get; set; } = 50;
        }

        private class StoredData
        {
            [JsonProperty("Purchase counts by user id")]
            public Dictionary<string, int> Counts { get; set; } = new Dictionary<string, int>();
        }

        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"] = "Thanks for your purchase! You reached {0} master keys and received {1} x{2}.",
                ["NoPermission"] = "You do not have permission to use apartment keys here."
            }, this);
        }

        private string Msg(string key, string userId = null, params object[] args)
        {
            return string.Format(lang.GetMessage(key, this, userId), args);
        }

        private void Init()
        {
            permission.RegisterPermission(PermUse, this);
            data = Interface.Oxide.DataFileSystem.ReadObject<StoredData>(Name) ?? new StoredData();
        }

        private void Unload()
        {
            saveTimer?.Destroy();
            SaveData();
        }

        private void OnApartmentMasterKeyPurchased(BasePlayer player, Item item)
        {
            if (player == null) return;

            if (!data.Counts.ContainsKey(player.UserIDString))
                data.Counts[player.UserIDString] = 0;

            data.Counts[player.UserIDString]++;
            dirty = true;
            QueueSave();

            if (config.RewardEvery <= 0) return;
            if (data.Counts[player.UserIDString] % config.RewardEvery != 0) return;

            var reward = ItemManager.CreateByName(config.RewardShortname, config.RewardAmount);
            if (reward == null) return;

            player.GiveItem(reward);
            player.ChatMessage(Msg("Rewarded", player.UserIDString,
                data.Counts[player.UserIDString], reward.info.displayName.english, config.RewardAmount));
        }

        private void QueueSave()
        {
            if (saveTimer != null && !saveTimer.Destroyed) return;
            saveTimer = timer.Once(5f, () =>
            {
                saveTimer = null;
                SaveData();
            });
        }

        private void SaveData()
        {
            if (!dirty) return;
            Interface.Oxide.DataFileSystem.WriteObject(Name, data);
            dirty = false;
        }
    }
}

The plugin keeps a per-player purchase count in oxide/data and grants a bonus item every N keys (default 3), giving buyers a small incentive to keep shopping.

OnApartmentMasterKeyPurchased looks up the player's record, increments the counter, and saves via a timer so rapid purchases are batched. When the count hits the configured threshold it gives a reward item with GiveItem and resets the counter, sending a chat message through the language file. A config file controls the threshold, reward shortname, and reward amount. Data is saved on unload, and the plugin null-checks both the hook arguments so unexpected calls cannot throw.

Common use cases

  • Reward repeat buyers

    Count master key purchases per player and hand out an item, currency, or permission after a threshold to encourage apartment use on your server.

  • Audit key sales

    Log each purchase with the buyer's Steam ID and the key's skin to a data file so admins can trace who bought what during an event.

  • Restrict or flag keys by group

    Use the buyer's permission group to post a staff alert when a key is bought outside normal access, or mark the item so a separate system can identify it later.

Pitfalls

  • The key is already delivered

    By the time this hook runs, the item is in the player's inventory or dropped on the ground. Do not try to cancel the purchase here; use the earlier purchase hooks for that.

  • Do not assume the item is in the backpack

    If the buyer's inventory was full, player.GiveItem drops the key at the player's feet. Check item.parent before trying to move or read its slot.

  • Avoid heavy work in the callback

    The hook runs on the main thread during the NPC purchase flow. Keep data writes batched with a timer instead of hitting DataFileSystem synchronously on every purchase.

Build a plugin with OnApartmentMasterKeyPurchased

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

Prompt: Reward repeat buyers using the OnApartmentMasterKeyPurchased 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 OnApartmentMasterKeyPurchased

Generate