OnMapMarkerAdd
OnMapMarkerAdd is called when a player places a marker on the in-game map, before the server stores it. Returning a non-null value cancels the placement.
object OnMapMarkerAdd(BasePlayer player, ProtoBuf.MapNote mapNote)Parameters
| Parameter | Type | Description |
|---|---|---|
player | BasePlayer | The BasePlayer whose client sent the marker request. Use it for permission checks, team lookups or per-player limits. |
mapNote | ProtoBuf.MapNote | The ProtoBuf.MapNote being placed, carrying the world position (x, z) and the icon type (note, vending machine, etc.). Read it to inspect or validate the marker before it is stored. |
Return value
Returning null (or nothing) lets the original code continue: the marker is stored unless CanUseMapMarkers is false. Returning any non-null object aborts Server_AddMarker immediately, so the note is never added to State.pointsOfInterest.
How it works
Fires inside BasePlayer.Server_AddMarker, which runs when the server handles the RPC a client sends after the player drops a map note. The method first reads the serialized ProtoBuf.MapNote from the message, calls the hook, and only then checks CanUseMapMarkers and appends the note to State.pointsOfInterest. Because the hook runs before that check, it is the only point where a plugin can inspect the note and refuse it.
mapNote exposes the world position (x, z) and the type field that selects which icon is drawn (MapNote.POI, vending machine, etc.). There is no separate permission requirement on the game side, so this hook is the place to enforce your own rules: a marker limit per player, a block on markers while raiding, a priced marker system, or wiping the position before storage.
The player argument is the sender, not necessarily the map owner in any other sense; it is the player whose account is placing the note. Declaring ProtoBuf.MapNote exactly is required — there is no base type to widen to. Modifying the note object in the hook does not prevent storage, so mutate it only if you intend to change what is kept, and return non-null to stop the placement entirely.
Example plugin: Limit map markers per player with a configurable cap
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("Map Marker Limit", "RustPluginGenerator", "1.0.0")]
[Description("Caps the number of map markers a player can place.")]
public class MapMarkerLimit : RustPlugin
{
private const string PermBypass = "mapmarkerlimit.bypass";
private PluginConfig config;
private class PluginConfig
{
[JsonProperty("Maximum markers per player")]
public int MaxMarkersPerPlayer = 10;
}
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>
{
["MarkerLimitReached"] = "You already have {0} map markers placed. Remove one before adding another."
}, 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 OnMapMarkerAdd(BasePlayer player, ProtoBuf.MapNote mapNote)
{
if (player == null || mapNote == null) return null;
if (permission.UserHasPermission(player.UserIDString, PermBypass)) return null;
int limit = Math.Max(1, config.MaxMarkersPerPlayer);
int current = player.State?.pointsOfInterest?.Count ?? 0;
if (current >= limit)
{
player.ChatMessage(Msg("MarkerLimitReached", player.UserIDString, current));
return true;
}
return null;
}
}
}The plugin keeps a per-player count of placed markers, capped by MaxMarkersPerPlayer in the config and bypassable through the mapmarkerlimit.bypass permission. OnMapMarkerAdd counts the player's current entries in player.State.pointsOfInterest and returns true when the limit is reached, which aborts the placement before the server stores the note. Chat feedback comes from the language file so admins can reword it. Existing markers placed before the plugin was installed are not removed; the count simply starts from whatever the player already has, which keeps behavior consistent across reloads. The permission is registered in Init and checked against the player's UserIDString.
Common use cases
Per-player marker caps
Stop players from littering the map by rejecting placements once they hold more than N notes.
Paid map markers
Charge an economy balance in the hook and reject the note when the player cannot afford it.
Zone restrictions
Read
mapNote.xandmapNote.zto refuse markers placed inside a raid zone, event area or admin-only region.
Pitfalls
Returning a value from elsewhere
Any non-null return aborts the method, so always return null after your checks unless you want to block the note; returning
falsestill cancels the placement.Existing markers are not counted retroactively
State.pointsOfInterestalready contains markers placed before the plugin loaded, so counting it enforces a hard total. If you only want to count new markers, track them in data instead.The note is already deserialized
mapNoteis a live object read from the client. Editing it changes what is stored but does not stop storage; return non-null for that.
Build a plugin with OnMapMarkerAdd
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 OnMapMarkerAdd
Generate