Skip to content
RustPluginGenerator

OnMapMarkerRemove

OnMapMarkerRemove is called when a player deletes one of their own map markers, before the game disposes and removes it from their map state.

Signature
object OnMapMarkerRemove(BasePlayer player, List<ProtoBuf.MapNote> pointsOfInterest, int num)

Parameters

Hook parameters
ParameterTypeDescription
playerBasePlayerThe BasePlayer who is removing a marker from their personal map. Never null when the hook fires from the client RPC.
pointsOfInterestList<ProtoBuf.MapNote>The player's current list of ProtoBuf.MapNote entries (their map markers), before the removal is applied. You can inspect names, colors and positions here.
numintThe zero-based index of the marker the client is removing. The game already validated that it is within range of the list.

Return value

Returning null lets the game proceed: the marker is disposed, removed from the list, and the updated markers are sent to the client. Returning any non-null value cancels the removal, so the marker stays on the player's map and no state is marked dirty.

How it works

The hook fires inside BasePlayer.Server_RemovePointOfInterest, the server handler for the RPC a client sends when it drops a point of interest from its map. Before anything is deleted, the game checks that the marker list exists, that the requested index is valid, and only then calls the hook. At that moment the marker still exists in pointsOfInterest[num], so the ProtoBuf.MapNote you receive describes exactly what is about to disappear.

Use player to know whose map is changing, pointsOfInterest to inspect or count the remaining markers, and num to read the specific entry being removed (its note, colour and worldPosition). Blocking the call leaves the marker in place; the client keeps showing it because the server never sends the updated marker list.

The hook only fires for player-driven removals from the map UI. Marker clears handled through other paths do not reach this hook, so do not treat it as a full audit of map state changes. It is also a good place to enforce marker quotas or protected markers without touching the rest of the player's state.

Example plugin: Protect pinned markers from deletion

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

namespace Oxide.Plugins
{
    [Info("Marker Guard", "RustPluginGenerator", "1.0.0")]
    [Description("Prevents players from removing map markers tagged as protected.")]
    public class MarkerGuard : RustPlugin
    {
        private const string PermBypass = "markerguard.bypass";

        private PluginConfig config;

        private class PluginConfig
        {
            [JsonProperty("Protected name prefix")]
            public string ProtectedPrefix = "[PIN]";

            [JsonProperty("Allow admins to remove protected markers")]
            public bool AllowAdminRemove = 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>
            {
                ["Protected"] = "This marker is pinned and cannot be removed from the map.",
                ["NoPrefix"] = "The protected prefix in the config is empty; marker protection is disabled."
            }, 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);
            if (string.IsNullOrEmpty(config.ProtectedPrefix))
                PrintWarning(Msg("NoPrefix"));
        }

        private object OnMapMarkerRemove(BasePlayer player, List<MapNote> pointsOfInterest, int index)
        {
            if (player == null || pointsOfInterest == null) return null;
            if (index < 0 || index >= pointsOfInterest.Count) return null;
            if (string.IsNullOrEmpty(config.ProtectedPrefix)) return null;

            var note = pointsOfInterest[index];
            if (note == null) return null;

            var text = GetNoteText(note);
            if (string.IsNullOrEmpty(text)) return null;
            if (!text.StartsWith(config.ProtectedPrefix, StringComparison.OrdinalIgnoreCase)) return null;

            if (config.AllowAdminRemove && (player.IsAdmin || permission.UserHasPermission(player.UserIDString, PermBypass)))
                return null;

            player.ChatMessage(Msg("Protected", player.UserIDString));
            return false;
        }

        // The marker label is carried on the ProtoBuf MapNote as the "label" string field.
        private static string GetNoteText(MapNote note)
        {
            return note != null ? note.label : null;
        }
    }
}

Server admins can pin markers by prefixing their name with the configured tag (default [PIN]). When a player tries to delete a marker, OnMapMarkerRemove reads the note at the given index and compares its label to the tag case-insensitively. If the label starts with the tag, the hook sends a localized chat message to the player and returns false, so the removal is stopped and the marker survives. If the label does not match, the player is an admin, or the player has the markerguard.bypass permission while AllowAdminRemove is enabled, the hook returns null and the normal deletion runs. Setting the prefix to an empty string disables protection and logs a warning at startup.

Common use cases

  • Enforce a maximum marker count

    Read pointsOfInterest.Count and reject removals that would drop a player below a minimum (for example, race checkpoints). Useful for event plugins that rely on map notes as progress markers.

  • Protect admin-placed waypoints

    Scan the note text for a reserved prefix or color and return non-null so players cannot delete markers set by staff for navigation or events.

  • Log marker removals for review

    Record the player, note text, color and world position to a data file for moderation or analytics without changing game behavior.

Pitfalls

  • Index can equal the count during the removal cycle

    The game checks Count > num before calling, so pointsOfInterest[num] is valid, but subsequent removals shift the list. Do not cache the index across calls; always read the list supplied to the hook.

  • Blocking is silent to the client

    Returning non-null prevents the server from sending the updated list, so the marker reappears on the next marker sync. Tell the player through chat, otherwise the click looks like it did nothing.

  • Not all removals hit this hook

    Only the client RPC path calls it. Server-side marker clears, disconnects and state resets do not, so a quota enforced here can still be bypassed by other code paths.

Build a plugin with OnMapMarkerRemove

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

Prompt: Enforce a maximum marker count using the OnMapMarkerRemove 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 OnMapMarkerRemove

Generate