Skip to content
RustPluginGenerator

OnSaveLoad

OnSaveLoad is called by SaveRestore.Load after all entities have been spawned from the world save file, and just before the server finishes the load and lets players reconnect.

Signature
object OnSaveLoad(Dictionary<BaseEntity, ProtoBuf.Entity> entities)

Parameters

Hook parameters
ParameterTypeDescription
entitiesDictionary<BaseEntity, ProtoBuf.Entity>Map of every spawned BaseEntity being restored from the save file to its serialized ProtoBuf data. It is populated just before the entities are instantiated, so you can inspect or modify both the entity references and the raw saved proto data.

Return value

Returning a value that is not a bool (including null) lets SaveRestore.Load continue normally with the map-load reporting and player connection setup. Returning a bool replaces the method's own result: true claims the load succeeded, false claims it failed, and either way the remaining vanilla load steps are skipped.

How it works

This hook fires once per world load, at the end of SaveRestore.Load. By that point the terrain, buildings, deployables and other saved entities have already been spawned (item.SpawnAsMapEntity() has run for each one), the dictionary has been filled, and the line Spawning N entities from save is about to be logged. The single parameter is a Dictionary<BaseEntity, ProtoBuf.Entity> mapping the freshly created entity objects to their deserialized proto records. Long-running loads are the main use case: you can count or filter entities, log map statistics, adjust freshly loaded entities (for example set flags, health or ownership), or delay your own setup logic until the world is fully there. Because the entities already exist, IsDestroyed will be false and net.ID is valid. Keep work fast; the server is still in its load phase and blocking here delays the whole map load. Use OnServerInitialized or OnNewSave if you only need init-time logic that does not depend on the entity dictionary.

Example plugin: Report a map load summary of entities

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

namespace Oxide.Plugins
{
    [Info("Save Load Summary", "RustPluginGenerator", "1.0.0")]
    [Description("Logs a short entity summary of the world right after the save file is loaded.")]
    public class SaveLoadSummary : RustPlugin
    {
        private class PluginConfig
        {
            [JsonProperty("Print summary to server log")]
            public bool PrintSummary { get; set; } = true;

            [JsonProperty("Warn when entity count is above")]
            public int WarnAbove { get; set; } = 200000;
        }

        private PluginConfig config;

        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);

        private object OnSaveLoad(Dictionary<BaseEntity, ProtoBuf.Entity> entities)
        {
            if (!config.PrintSummary || entities == null)
            {
                return null;
            }

            int buildings = 0;
            int containers = 0;
            int ovens = 0;
            int doors = 0;
            int players = 0;

            foreach (KeyValuePair<BaseEntity, ProtoBuf.Entity> pair in entities)
            {
                BaseEntity entity = pair.Key;
                if (entity == null || entity.IsDestroyed)
                {
                    continue;
                }

                if (entity is BuildingBlock) buildings++;
                else if (entity is StorageContainer) containers++;
                else if (entity is BaseOven) ovens++;
                else if (entity is Door) doors++;
                else if (entity is BasePlayer) players++;
            }

            string line = string.Format(
                "SaveLoadSummary: {0} entities restored (buildings {1}, containers {2}, ovens {3}, doors {4}, players {5})",
                entities.Count, buildings, containers, ovens, doors, players);

            if (entities.Count > config.WarnAbove)
            {
                PrintWarning(line + " - above configured threshold");
            }
            else
            {
                Puts(line);
            }

            return null;
        }
    }
}

The plugin hooks OnSaveLoad, iterates the entity dictionary and counts a few common categories by checking against BuildingBlock, StorageContainer, BaseOven, Door and BasePlayer with the as operator. It writes the total and per-category counts to the server log so admins see how heavy a freshly restored map is. A config option toggles the summary and lets the admin set a threshold under which a warning is printed instead of a normal log line. All counters are local, so the hook returns nothing and the vanilla load path is untouched.

Common use cases

  • Map health overview after wipe

    Count buildings, containers and deployables right after the save is loaded to spot maps that were restored from a bad backup or a much larger world than expected.

  • Post-load entity adjustment

    Iterate the dictionary and tweak freshly loaded entities, for example resetting flags or ownership, before players reconnect.

  • Deferred setup for plugins

    Some plugins need the full entity list to be present before they index buildings; this hook is the earliest point where that is guaranteed.

Pitfalls

  • Returning a bool breaks the load

    The injection reads a returned bool and returns it to the caller, skipping the reporting and connection setup that follows. Always return null from this hook.

  • The dictionary is not authoritative forever

    It reflects the save state at load time; entities spawned later by other plugins or by map changes are not in it. Rebuild any index when entities change.

  • Slow loops delay player joins

    Heavy processing here blocks the server during map load. Keep it to simple iteration and defer expensive work to a timer after OnServerInitialized.

Build a plugin with OnSaveLoad

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

Prompt: Map health overview after wipe using the OnSaveLoad 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 OnSaveLoad

Generate