Skip to content
RustPluginGenerator

OnBookmarkAdd

OnBookmarkAdd is called when a player submits a new bookmark name to a ComputerStation, before the station stores it. Returning a non-null value cancels the add.

Signature
object OnBookmarkAdd(ComputerStation computerStation, BasePlayer player, string text)

Parameters

Hook parameters
ParameterTypeDescription
computerStationComputerStationThe ComputerStation entity the player is interacting with. Use it to check position, ownership or the station's current state.
playerBasePlayerThe BasePlayer who is adding the bookmark. Check IsAdmin, permissions or team membership here.
textstringThe raw bookmark label the client sent, read from the RPC message. Can be empty, whitespace, very long or contain control characters.

Return value

Returning null lets the station store the bookmark and re-send the list to the client. Returning any non-null object stops the original code path: ForceAddBookmark is not called and SendControlBookmarks is not sent, so the client keeps its previous list.

How it works

The hook fires inside ComputerStation.AddBookmark, right after the station reads the incoming RPC string and before it calls ForceAddBookmark and re-sends the bookmark list to the client. The station's own throttle and bookmark-count limit checks run earlier, so this hook only sees requests that already passed those gates.

computerStation is the entity being edited — useful for position checks (e.g. only allow edits inside a base), ownership checks, or keying per-station state. player is the requesting player; use it for permission checks or to send feedback. text is the exact label the client sent: trim it, length-limit it, or compare it against a blocklist.

The hook receives the concrete ComputerStation type, so declaring the parameter as BaseNetworkable or BaseEntity would match every station type; keep it as ComputerStation unless you also want to catch calls on subclasses. It is a per-request hook, so it fires only on player action, not on a timer — safe to log or send a message from, though avoid heavy work here.

Because the return value is checked with a type test, returning any non-null object cancels the original add path, including the client refresh.

Example plugin: Filter bookmark names on computer stations

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

namespace Oxide.Plugins
{
    [Info("Bookmark Name Filter", "RustPluginGenerator", "1.0.0")]
    [Description("Validates and filters bookmark names added on computer stations")]
    public class BookmarkNameFilter : RustPlugin
    {
        private const string PermBypass = "bookmarknamefilter.bypass";

        private PluginConfig config;

        private class PluginConfig
        {
            [JsonProperty("Minimum length")]
            public int MinLength = 2;

            [JsonProperty("Maximum length")]
            public int MaxLength = 16;

            [JsonProperty("Blocked words (case-insensitive)")]
            public List<string> BlockedWords = new List<string> { "admin", "server", "http" };
        }

        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>
            {
                ["TooShort"] = "Bookmark name must be at least {0} characters.",
                ["TooLong"] = "Bookmark name must be at most {0} characters.",
                ["Blocked"] = "That bookmark name is not allowed."
            }, 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(PermBypass, this);
        }

        private object OnBookmarkAdd(ComputerStation computerStation, BasePlayer player, string text)
        {
            if (computerStation == null || player == null || text == null) return null;
            if (permission.UserHasPermission(player.UserIDString, PermBypass)) return null;

            string name = text.Trim();

            if (name.Length < config.MinLength)
            {
                player.ChatMessage(Msg("TooShort", player.UserIDString, config.MinLength));
                return true;
            }

            if (name.Length > config.MaxLength)
            {
                player.ChatMessage(Msg("TooLong", player.UserIDString, config.MaxLength));
                return true;
            }

            foreach (string word in config.BlockedWords)
            {
                if (string.IsNullOrEmpty(word)) continue;
                if (name.IndexOf(word, StringComparison.OrdinalIgnoreCase) >= 0)
                {
                    player.ChatMessage(Msg("Blocked", player.UserIDString));
                    return true;
                }
            }

            return null;
        }
    }
}

The plugin reads its rules from the config: a list of forbidden words, a maximum length and a minimum length. In OnBookmarkAdd it trims whitespace off the incoming label and compares it case-insensitively against the blocklist, then checks the length limits. A rejected name is reported to the player through a localized chat message and the hook returns a non-null value, which stops the station from adding the bookmark. Accepted names return null so the vanilla add path runs unchanged. The station is also checked so that only vanilla ComputerStation entities are filtered, keeping the filter predictable.

Common use cases

  • Block offensive or advertising bookmark names

    Compare the incoming text against a configurable word list and reject matches so shared stations keep readable labels.

  • Limit label length and formatting

    Trim whitespace and reject overly long or empty labels before the station stores them.

  • Restrict edits outside authorized areas

    Check that the station sits within a building privilege or owned area using its position and the player's building authorization.

Pitfalls

  • Not returning a value rejects silently

    Returning non-null skips SendControlBookmarks, so the client keeps its old list. Send a chat message explaining the rejection or players will assume the station is broken.

  • The text is unsanitized client input

    The string comes straight from the RPC and may contain control characters or be extremely long. Trim and length-check it in code, not only in the config.

Build a plugin with OnBookmarkAdd

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

Prompt: Block offensive or advertising bookmark names using the OnBookmarkAdd 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 OnBookmarkAdd

Generate