OnBookmarkDelete
OnBookmarkDelete is called when a computer station is about to remove a control bookmark, before the entry is deleted from its bookmark list.
object OnBookmarkDelete(ComputerStation computerStation, BasePlayer mountedPlayer, string identifier)Parameters
| Parameter | Type | Description |
|---|---|---|
computerStation | ComputerStation | The ComputerStation (the computer/table entity) the bookmark belongs to. Use it to read the station's net.ID or position when reporting or auditing. |
mountedPlayer | BasePlayer | The 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). |
identifier | string | The 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
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.
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