Skip to content
RustPluginGenerator

OnBookmarkDelete

OnBookmarkDelete is called when a computer station is about to remove a control bookmark, before the entry is deleted from its bookmark list.

Signature
object OnBookmarkDelete(ComputerStation computerStation, BasePlayer mountedPlayer, string identifier)

Parameters

Hook parameters
ParameterTypeDescription
computerStationComputerStationThe ComputerStation (the computer/table entity) the bookmark belongs to. Use it to read the station's net.ID or position when reporting or auditing.
mountedPlayerBasePlayerThe player currently mounted on the computer station and requesting the deletion, or null when the removal is not triggered by a mounted player (for example a server-side call).
identifierstringThe string key of the control bookmark being removed, as stored in the station's control bookmarks list.

Return value

Returning null lets the game continue and the bookmark is removed. Returning any non-null value stops the original method before removal, so the bookmark stays in the station's control list and the mounted player is not notified of a change.

How it works

The hook fires inside ComputerStation.RemoveBookmark, after the identifier passes the game's own validation: the string must be a valid identifier and must currently exist in the station's control bookmarks. It runs before the bookmark is actually removed and before the station notifies the mounted player, so at this point the bookmark still exists.

computerStation is the station being edited, which lets you tie the deletion to an owner, privilege check, or logging entry. mountedPlayer is the player driving the removal and is null when nothing is mounted, so always null-check it before sending chat or building messages. identifier is the raw bookmark key, useful for matching against your own stored data.

The hook fires with exactly these types; declaring a more specific type for mountedPlayer is not useful because the game passes whatever player is mounted or null. Keep the handler cheap: it can fire every time a player cleans up a station, possibly in quick succession. Do not call Puts or PrintWarning here.

Cancelling at this point leaves the station state untouched, which is the right place to enforce a per-player bookmark limit or to protect bookmarks flagged as locked in your own data.

Example plugin: Lock bookmarks so they cannot be deleted

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

namespace Oxide.Plugins
{
    [Info("Bookmark Protection", "RustPluginGenerator", "1.0.0")]
    [Description("Lets admins lock control bookmarks on computer stations so they cannot be deleted")]
    public class BookmarkProtection : RustPlugin
    {
        private const string PermUse = "bookmarkprotection.use";

        private PluginConfig config;
        private StoredData data;

        private class PluginConfig
        {
            [JsonProperty("Send chat message when a locked bookmark is deleted")]
            public bool NotifyOnBlock { get; set; } = true;
        }

        private class StoredData
        {
            [JsonProperty("Locked bookmarks by station id")]
            public Dictionary<ulong, List<string>> Locked { get; set; } = new Dictionary<ulong, List<string>>();
        }

        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>
            {
                ["Locked"] = "That bookmark is locked and cannot be removed",
                ["Toggled"] = "Bookmark '{0}' protection is now {1}",
                ["NotStation"] = "You must be mounted on a computer station"
            }, 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);
            data = Interface.Oxide.DataFileSystem.ReadObject<StoredData>(Name) ?? new StoredData();
        }

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

        [ChatCommand("bookmark")]
        private void CmdBookmark(BasePlayer player, string command, string[] args)
        {
            if (player == null || !permission.UserHasPermission(player.UserIDString, PermUse)) return;
            if (args.Length == 0) return;

            var station = player.GetMounted() as ComputerStation;
            if (station == null)
            {
                player.ChatMessage(Msg("NotStation", player.UserIDString));
                return;
            }

            ulong id = station.net.ID.Value;
            if (!data.Locked.TryGetValue(id, out var list))
            {
                list = new List<string>();
                data.Locked[id] = list;
            }

            bool nowLocked;
            if (list.Contains(args[0]))
            {
                list.Remove(args[0]);
                nowLocked = false;
            }
            else
            {
                list.Add(args[0]);
                nowLocked = true;
            }

            player.ChatMessage(Msg("Toggled", player.UserIDString, args[0], nowLocked ? "on" : "off"));
            Interface.Oxide.DataFileSystem.WriteObject(Name, data);
        }

        private object OnBookmarkDelete(ComputerStation computerStation, BasePlayer mountedPlayer, string identifier)
        {
            if (computerStation == null || string.IsNullOrEmpty(identifier)) return null;
            if (!data.Locked.TryGetValue(computerStation.net.ID.Value, out var list)) return null;
            if (!list.Contains(identifier)) return null;

            if (config.NotifyOnBlock && mountedPlayer != null && mountedPlayer.IsConnected)
                mountedPlayer.ChatMessage(Msg("Locked", mountedPlayer.UserIDString));

            return true;
        }
    }
}

The plugin keeps a per-station data file of protected bookmark identifiers. A bookmark.protect chat command (admin only) toggles the bookmark under the player's cursor by name, and OnBookmarkDelete checks the list for the station's net.ID before allowing removal. If the identifier is locked, the hook returns a non-null value to cancel the deletion and informs the mounted player through the language file. Data is written with Interface.Oxide.DataFileSystem on toggle and again in Unload, so protection survives restarts. Limitations: mountedPlayer can be null, and admins with the permission can unlock an entry the same way in order to remove it.

Common use cases

  • Protect station bookmarks from accidental deletion

    Store a list of protected identifiers per station and cancel deletion for those entries while informing the mounted player.

  • Enforce a minimum bookmark count

    Block removal when a station is below a configured number of control bookmarks, which keeps shared computers usable.

  • Audit bookmark edits

    Record who deleted which bookmark on which station to a data file for staff review, without blocking the action.

Pitfalls

  • mountedPlayer can be null

    Server-side or console removal passes no player. Use a null-safe player message helper and guard every access to mountedPlayer.

  • The bookmark still exists here

    The removal happens after the hook returns, so reading the station's bookmark list inside the hook shows the entry you are about to delete.

  • Blocking bricks station cleanup

    If you cancel deletion permanently, players cannot clean stale bookmarks. Always provide an unlock path such as a permission-gated command.

Build a plugin with OnBookmarkDelete

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

Prompt: Protect station bookmarks from accidental deletion using the OnBookmarkDelete 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 OnBookmarkDelete

Generate