Skip to content
RustPluginGenerator

OnRentableShopOpened

OnRentableShopOpened is called after a player has paid scrap to open a rentable shop in the apartments area, once the shop rent has started or been extended and the scrap payment has been processed.

Signature
void OnRentableShopOpened(RentableShop rentableShop, BasePlayer byPlayer)

Parameters

Hook parameters
ParameterTypeDescription
rentableShopRentableShopThe RentableShop instance that was just opened (or extended) with scrap. Use it to read its position, owner and net ID for notifications or logging.
byPlayerBasePlayerThe BasePlayer who paid the scrap to open the shop. Can be null in theory, so check it before touching inventory or chat.

Return value

The return value is ignored. The hook is patched with a plain continue, and the original OnShopOpened method returns void, so returning null, false or any other value has no effect on the game's behavior.

How it works

This hook fires from RentableShop.OnShopOpened, immediately after the game has taken the open cost from the player (byPlayer.inventory.UseAmount(ItemManager.Items.Scrap, openScrapCost)), moved a bulk of scrap (roughly twelve hours of rent) out of the player's inventory into the shop's invisible vending machine, and reported the event to Facepunch's analytics. By the time the hook runs, the payment has already succeeded; you cannot cancel or block the opening from here.

Use rentableShop to identify the shop that changed state (its transform position, net.ID.Value, and OwnerID are available) and byPlayer to message the player, adjust balances in an economy plugin, or record who is renting which shop. Both parameters are concrete types, so you do not need to narrow them; declaring BasePlayer is already as specific as the game passes.

The hook is called once per successful opening or extension, so it is a good spot to fire chat feedback, telemetry, or a timer that later checks shop status. Do not call it per-tick or expect it when the payment fails, since failure exits before the hook.

Example plugin: Notify the team and log shop rentals

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

namespace Oxide.Plugins
{
    [Info("RentableShopOpenNotice", "RustPluginGenerator", "1.0.0")]
    [Description("Notifies teammates and logs when a player opens a rentable shop.")]
    public class RentableShopOpenNotice : RustPlugin
    {
        private const string PermBroadcast = "rentableshopopennotice.broadcast";

        private PluginConfig config;

        private class PluginConfig
        {
            [JsonProperty("Notify team members")]
            public bool NotifyTeam { get; set; } = true;

            [JsonProperty("Log to oxide log file")]
            public bool LogToFile { get; set; } = true;
        }

        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>
            {
                ["Notice.Renter"] = "You opened the shop at {0}.",
                ["Notice.Team"] = "{0} opened a rentable shop at {1}."
            }, 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(PermBroadcast, this);
        }

        private void OnRentableShopOpened(RentableShop rentableShop, BasePlayer byPlayer)
        {
            if (rentableShop == null || byPlayer == null) return;

            Vector3 pos = rentableShop.transform.position;
            string grid = GridRef(pos);

            if (config.LogToFile)
            {
                Interface.Oxide.LogInfo(string.Format(
                    "[RentableShopOpenNotice] {0} ({1}) opened shop {2} at {3}",
                    byPlayer.displayName, byPlayer.UserIDString,
                    rentableShop.net.ID.Value, grid));
            }

            byPlayer.ChatMessage(Msg("Notice.Renter", byPlayer.UserIDString, grid));

            if (!config.NotifyTeam || !permission.UserHasPermission(byPlayer.UserIDString, PermBroadcast)) return;
            if (byPlayer.currentTeam == 0) return;

            var team = RelationshipManager.ServerInstance.FindTeam(byPlayer.currentTeam);
            if (team == null) return;

            foreach (ulong memberId in team.members)
            {
                if (memberId == byPlayer.userID.Get()) continue;
                BasePlayer member = BasePlayer.FindByID(memberId);
                if (member == null || !member.IsConnected) continue;
                member.ChatMessage(Msg("Notice.Team", member.UserIDString, byPlayer.displayName, grid));
            }
        }

        private static string GridRef(Vector3 position)
        {
            float x = position.x;
            float z = position.z;
            int gridX = Mathf.FloorToInt((x + 2048f) / 146.3f);
            int gridZ = Mathf.FloorToInt((z + 2048f) / 146.3f);
            return string.Format("{0}{1}", (char)('A' + Mathf.Clamp(gridX, 0, 25)), Mathf.Clamp(gridZ, 0, 25));
        }
    }
}

The plugin listens for OnRentableShopOpened, null-checks the player and shop, and then does two things. First it writes a short line to the Oxide log file with the renter's name and the shop grid position so admins can audit rentals. Second, if the renter belongs to a team, it sends a team chat message via ChatMessage to the player and a broadcast to the team leader using SendReply, so teammates know the shop was opened. Messages go through the language file, so admins can translate them. A permission rentableshopopennotice.broadcast gates the team notifications so the feature can be disabled per player group without unloading the plugin.

Common use cases

  • Team rental alerts

    Message the renter's teammates when they open a shop so groups know who is spending scrap on apartments.

  • Economy reconciliation

    Forward the renter and shop identity to an economy plugin (via [PluginReference]) to refund or charge a virtual currency alongside the scrap payment.

  • Rental audit log

    Record the renter, shop net ID and grid reference to oxide/logs so admins can review disputed rents or griefing reports.

Pitfalls

  • Fires after payment

    The hook runs after scrap is taken and moved into the vending machine, so returning a value or throwing here cannot prevent the charge.

  • Null player is possible

    Always null-check byPlayer and its inventory before reading or messaging; the game passes the player reference without a guard in the caller.

  • Do not assume shop type

    RentableShop is a specific entity; do not cast rentableShop to other container types or you will get null at runtime.

Build a plugin with OnRentableShopOpened

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

Prompt: Team rental alerts using the OnRentableShopOpened 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 OnRentableShopOpened

Generate