Skip to content
RustPluginGenerator

OnServerSave

OnServerSave is called by the server right before an automated world save begins, inside SaveRestore.DoAutomatedSave. It gives plugins a moment to run code on the main thread before the save routine kicks off.

Signature
void OnServerSave()

Return value

The return value is ignored. Whatever your hook returns, the server proceeds to create and run the automated save coroutine as normal.

How it works

Rust fires this hook at the top of SaveRestore.DoAutomatedSave, which the server schedules for its periodic automatic save. The hook runs before the save coroutine is created, so it is the last main-thread point before the world state is written to disk. There are no parameters.

Because the injection only covers the automated save path, a manual save triggered by an admin command does not raise OnServerSave through this site. Treat the hook as a periodic tick tied to the save interval rather than a guaranteed "every save" signal.

Practical uses are lightweight housekeeping that should line up with save cadence: flushing in-memory plugin state, writing data files, or broadcasting a short warning that the server is saving. Since it fires on the main thread as part of the server's own work, keep the callback fast. Do not start long loops, spawn entities, or block on anything here; anything slow delays the save and can cause a hitch for connected players. There is no way to cancel or modify the save from this hook.

Example plugin: Persist tracked state and warn players on autosave

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

namespace Oxide.Plugins
{
    [Info("Autosave Notifier", "RustPluginGenerator", "1.0.0")]
    [Description("Counts automated saves, persists the count, and can warn players when the server saves.")]
    public class AutosaveNotifier : RustPlugin
    {
        private const string DataFileName = "AutosaveNotifier";
        private const string PermToggle = "autosavenotifier.toggle";

        private PluginConfig config;
        private StoredData data;

        private class PluginConfig
        {
            [JsonProperty("Notify players on autosave")]
            public bool NotifyPlayers { get; set; } = true;
        }

        private class StoredData
        {
            [JsonProperty("Autosave count")]
            public int AutosaveCount { get; set; }
        }

        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>
            {
                ["SaveNotice"] = "The server is saving the world, expect a brief hitch.",
                ["CountReply"] = "Autosaves recorded so far: {0}"
            }, 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(PermToggle, this);
            data = Interface.Oxide.DataFileSystem.ReadObject<StoredData>(DataFileName) ?? new StoredData();
        }

        private void OnServerSave()
        {
            data.AutosaveCount++;

            try
            {
                Interface.Oxide.DataFileSystem.WriteObject(DataFileName, data);
            }
            catch (Exception ex)
            {
                PrintWarning("Failed to persist autosave count: " + ex.Message);
            }

            if (!config.NotifyPlayers) return;

            string notice = Msg("SaveNotice");
            foreach (var player in BasePlayer.activePlayerList)
            {
                if (player == null || !player.IsConnected) continue;
                player.ChatMessage(notice);
            }
        }

        [ChatCommand("autosaves")]
        private void CmdAutosaves(BasePlayer player, string command, string[] args)
        {
            if (player == null) return;

            if (args.Length > 0 && args[0] == "toggle")
            {
                if (!permission.UserHasPermission(player.UserIDString, PermToggle))
                {
                    player.ChatMessage("You do not have permission to change this setting.");
                    return;
                }

                config.NotifyPlayers = !config.NotifyPlayers;
                SaveConfig();
                player.ChatMessage("Autosave notices are now " + (config.NotifyPlayers ? "on." : "off."));
                return;
            }

            player.ChatMessage(Msg("CountReply", player.UserIDString, data.AutosaveCount));
        }

        private void Unload()
        {
            try
            {
                Interface.Oxide.DataFileSystem.WriteObject(DataFileName, data);
            }
            catch (Exception)
            {
                // ignored on shutdown
            }
        }
    }
}

The plugin keeps a running count of autosaves and writes it to a data file whenever one starts. In OnServerSave it increments the counter, saves via Interface.Oxide.DataFileSystem, and sends a chat notice to every connected player if the config enables it. Init loads the stored counter so it survives restarts. All work is a single file write and a broadcast, keeping the hook fast enough not to delay the save. Config toggles the notice and message text, and the message itself lives in the language file so admins can localize it.

Common use cases

  • Flush plugin data to disk

    Write tracked player stats, cooldowns, or economy snapshots to oxide/data at the same cadence as the world save so a crash loses minimal data.

  • Warn players of the save

    Broadcast a short chat message so players know the server is saving and expect a brief hitch or a lock on building.

  • Rotate periodic maintenance

    Run a cheap scheduled task such as clearing expired entries from an in-memory cache, since this hook fires on a predictable interval.

Pitfalls

  • Not every save hits this hook

    The injection only sits in the automated save path, so manual saves triggered by admin commands may not fire it. Do not rely on it as the only persistence trigger for critical data.

  • Keep it short

    The hook runs on the main thread before the save coroutine starts. Heavy loops, file reads, or entity spawning here delay the save and cause server hitches.

  • Return value does nothing

    Returning a value does not skip or alter the save. There is no way to cancel a save from this hook.

Plugin recipes that use OnServerSave

Build a plugin with OnServerSave

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

Prompt: Flush plugin data to disk using the OnServerSave 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 OnServerSave

Generate