Skip to content
RustPluginGenerator

OnOpenVendingAdmin

OnOpenVendingAdmin is called after a player successfully opens the admin panel of a vending machine, right after the server sends the CLIENT_OpenAdminMenu RPC and opens the 'notCustomerPanel' shop view.

Signature
void OnOpenVendingAdmin(VendingMachine vendingMachine, BasePlayer player)

Parameters

Hook parameters
ParameterTypeDescription
vendingMachineVendingMachineThe VendingMachine entity whose admin UI is being opened. Use it to read the shop name, network ID, owner or position.
playerBasePlayerThe BasePlayer who is opening the admin panel. This is the player who passed the CanPlayerAdmin check (owner or admin).

Return value

The return value is ignored because the injection is a plain call on a void method. Returning anything (or nothing) has no effect on the original code path, the admin panel still opens.

How it works

The hook fires inside VendingMachine.RPC_OpenAdmin, the server RPC a client sends when it asks to manage a shop. The game first resolves msg.player, verifies with CanPlayerAdmin(player) (shop owner, or an admin), then calls OpenShop(player, "notCustomerPanel"), sends CLIENT_OpenAdminMenu to that player, and finally calls the hook. Because it runs only after the permission check, the hook never fires for players who are not allowed to administrate the machine.

Both parameters are useful: vendingMachine identifies the shop entity (its net.ID.Value, OwnerID, position, or attached data such as the shop name), and player is the administrator who just got the panel. This is a good point to start a temporary UI, log staff access to shops, or notify owners that someone is editing their machine.

The hook is void, so it is not a gate. To block the admin panel you must use a hook that fires before the check, such as CanAdministerVending. CanPlayerAdmin itself is not an Oxide hook. If the machine is destroyed during the same frame, guarding vendingMachine and player with null checks is still good practice.

Example plugin: Log staff access to vending machine admin panels

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

namespace Oxide.Plugins
{
    [Info("Vending Admin Audit", "RustPluginGenerator", "1.0.0")]
    [Description("Logs every successful vending machine admin panel open and notifies staff.")]
    public class VendingAdminAudit : RustPlugin
    {
        private const string PermNotify = "vendingadminaudit.notify";

        private PluginConfig config;
        private AuditData data;
        private Timer flushTimer;

        private class PluginConfig
        {
            [JsonProperty("Maximum stored records")]
            public int MaxRecords = 500;

            [JsonProperty("Notify permitted players")]
            public bool NotifyStaff = true;
        }

        private class AuditEntry
        {
            public string AdminName;
            public string AdminId;
            public string ShopName;
            public ulong MachineId;
            public string Position;
            public string Timestamp;
        }

        private class AuditData
        {
            public List<AuditEntry> Entries = new List<AuditEntry>();
        }

        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>
            {
                ["AdminOpened"] = "{0} ({1}) opened the admin panel of '{2}' at {3}.",
                ["NoName"] = "Unnamed shop"
            }, 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(PermNotify, this);
            data = Interface.Oxide.DataFileSystem.ReadObject<AuditData>(Name) ?? new AuditData();
        }

        private void OnServerInitialized()
        {
            flushTimer = timer.Every(60f, SaveData);
        }

        private void OnOpenVendingAdmin(VendingMachine vendingMachine, BasePlayer player)
        {
            if (vendingMachine == null || player == null) return;

            string shopName = string.IsNullOrEmpty(vendingMachine.shopName) ? Msg("NoName") : vendingMachine.shopName;
            string pos = vendingMachine.transform.position.ToString("F0");

            data.Entries.Add(new AuditEntry
            {
                AdminName = player.displayName,
                AdminId = player.UserIDString,
                ShopName = shopName,
                MachineId = vendingMachine.net.ID.Value,
                Position = pos,
                Timestamp = DateTime.UtcNow.ToString("u")
            });

            while (data.Entries.Count > config.MaxRecords)
            {
                data.Entries.RemoveAt(0);
            }

            if (!config.NotifyStaff) return;

            string message = Msg("AdminOpened", null, player.displayName, player.UserIDString, shopName, pos);
            foreach (BasePlayer target in BasePlayer.activePlayerList)
            {
                if (target == null || target == player || !target.IsConnected) continue;
                if (target.IsAdmin || permission.UserHasPermission(target.UserIDString, PermNotify))
                {
                    target.ChatMessage(message);
                }
            }
        }

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

        private void Unload()
        {
            if (flushTimer != null)
            {
                flushTimer.Destroy();
                flushTimer = null;
            }
            SaveData();
        }
    }
}

The plugin writes one line to oxide/data/VendingAdminAudit for every successful admin-panel open and pushes a short notice to staff who have the vendingadminaudit.notify permission. OnOpenVendingAdmin reads the machine's shop name via the public shopName field, falls back to a localized placeholder, and records the admin's display name, Steam ID, machine network ID and world position. Records are trimmed to the configured limit, saved on unload and flushed every 60 seconds with a repeating timer. Because the hook fires after the game's own CanPlayerAdmin check, only real administrators (owner or staff) ever appear in the log.

Common use cases

  • Audit trail for shop edits

    Store who opened which vending machine admin panel and when, so owners can see if a teammate or server staff changed prices in their shops.

  • Staff activity overview

    Broadcast a message to online admins when a moderator opens a player shop, so duplicate edits during an event can be avoided.

  • Owner reminder on admin open

    Send the shop owner a chat or Discord-relayed notice that their machine is being edited, along with the machine name and position.

Pitfalls

  • It cannot block the panel

    The hook runs after CanPlayerAdmin, OpenShop and the admin RPC. Use CanAdministerVending or CanAccessVendingMachine if you need to deny access.

  • Not a purchase event

    This fires for the admin UI only. Customer opens use OnVendingShopOpen / OnVendingShopOpened, and sales use OnBuyVendingItem or OnVendingTransaction.

  • Keep it cheap

    It is a rare hook so light logging is fine, but writing the data file directly on every call causes unnecessary disk I/O. Batch saves with a timer or on unload.

Build a plugin with OnOpenVendingAdmin

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

Prompt: Audit trail for shop edits using the OnOpenVendingAdmin 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 OnOpenVendingAdmin

Generate