Skip to content
RustPluginGenerator

OnMapImageUpdated

OnMapImageUpdated is called after a MapEntity (a paper map or a map-carrying item) repaints its map image and refreshes its networked image data. It fires on the server assembly inside MapEntity.ImageUpdate, which runs when the map's image is regenerated and pushed to clients.

Signature
void OnMapImageUpdated()

Return value

The hook is patched with continue, so the return value is ignored entirely. Returning null, a value, or nothing has no effect on MapEntity.ImageUpdate; the original method always finishes normally after the hook is called.

How it works

The hook fires at the end of MapEntity.ImageUpdate, after the game has written the newly generated map pixels into the map's cached image array and invalidated the network cache so clients receive the new image. It is a server-side, no-argument hook: you get no entity reference, no owner and no map reference, so anything you need to inspect must be looked up yourself (for example by iterating map entities or storing state you captured earlier).

Because the signature has no parameters, there is no way to narrow dispatch by parameter type. The hook fires whenever any map image updates, which in practice means when a player paints/regenerates a map. Treat it as a change notification, not a per-entity event, and keep the work inside it cheap. Announcements, cache invalidation in your own plugin data or scheduling a deferred scan with NextTick or timer.Once are appropriate; heavy per-player loops on every map update are not.

Example plugin: Notify the map's owner when a paper map is repainted

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

namespace Oxide.Plugins
{
    [Info("Map Update Notifier", "RustPluginGenerator", "1.0.0")]
    [Description("Notifies players when a paper map they carry is repainted.")]
    public class MapUpdateNotifier : RustPlugin
    {
        private const string PermNotify = "mapupdatenotifier.notify";

        private PluginConfig config;
        private readonly Dictionary<ulong, float> lastNotice = new Dictionary<ulong, float>();

        private class PluginConfig
        {
            [JsonProperty("Cooldown seconds between notices per player")]
            public float CooldownSeconds { get; set; } = 30f;

            [JsonProperty("Only notify players holding the map")]
            public bool RequireHeld { get; set; } = false;
        }

        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>
            {
                ["MapUpdated"] = "One of your paper maps was just repainted.",
                ["NoPermission"] = "You do not have permission to receive map notices."
            }, 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(PermNotify, this);
        }

        private void OnMapImageUpdated()
        {
            // The hook has no arguments, so inspect players on the next tick.
            NextTick(ScanPlayers);
        }

        private void ScanPlayers()
        {
            foreach (var player in BasePlayer.activePlayerList)
            {
                if (player == null || !player.IsConnected || player.IsDead()) continue;
                if (!permission.UserHasPermission(player.UserIDString, PermNotify)) continue;

                if (!HoldsMap(player)) continue;

                ulong id = player.userID.Get();
                float now = Time.realtimeSinceStartup;
                float last;
                if (lastNotice.TryGetValue(id, out last) && now - last < config.CooldownSeconds) continue;

                lastNotice[id] = now;
                player.ChatMessage(Msg("MapUpdated", player.UserIDString));
            }
        }

        private bool HoldsMap(BasePlayer player)
        {
            if (player.inventory == null) return false;

            if (HasMapItem(player.inventory.containerBelt)) return true;
            if (config.RequireHeld) return false;
            return HasMapItem(player.inventory.containerMain);
        }

        private static bool HasMapItem(ItemContainer container)
        {
            if (container == null) return false;
            foreach (var item in container.itemList)
            {
                if (item?.info == null) continue;
                if (item.info.shortname == "map") return true;
            }
            return false;
        }

        private void Unload()
        {
            lastNotice.Clear();
        }
    }
}

The plugin reacts to OnMapImageUpdated by finding the players affected by a map repaint. Since the hook passes no arguments, the plugin schedules a deferred scan on the next tick and walks BasePlayer.activePlayerList, checking each player's belt and main inventory for items whose info.shortname is map that are held or carried. When a map is found and the player has the configured permission, the plugin sends a localized chat message telling them their map was updated. The check is guarded by a simple cooldown timestamp so a burst of image updates does not spam players; the message text lives in the language file and can be edited in oxide/lang without recompiling.

Common use cases

  • Announce map repaints

    Tell players that a paper map has been regenerated so they know their drawn markers or revealed areas changed. Useful on servers where map items are a meaningful gameplay resource.

  • Invalidate plugin-side caches

    If your plugin caches map-related data (custom markers, region ownership), treat this hook as a signal to refresh or drop stale entries rather than polling on a timer.

  • Audit map activity

    Schedule a deferred scan and record which maps were updated, then expose the result through an admin command. Keep the scan lightweight because the hook can fire repeatedly.

Pitfalls

  • No arguments to identify the map

    The hook gives you nothing: no entity, no owner, no position. If you need to know which map changed, you must capture state elsewhere or scan for map entities yourself, which is expensive if done on every call.

  • Fires in bursts

    Image generation can trigger several updates in quick succession. Add a cooldown or debounce (for example a timestamp per player) before sending chat messages or running loops.

  • Do not mutate the image here

    The hook runs after the image has been written and the network cache invalidated. Changing map state at this point will not be reflected in the update that just happened; use a follow-up update or a deferred action instead.

Build a plugin with OnMapImageUpdated

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

Prompt: Announce map repaints using the OnMapImageUpdated 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 OnMapImageUpdated

Generate