Skip to content
RustPluginGenerator

OnNewSave

OnNewSave is called by SaveRestore.Load when the save file the server tries to load does not exist, which happens when a server starts with a freshly generated world.

Signature
void OnNewSave(string filename)

Parameters

Hook parameters
ParameterTypeDescription
filenamestringThe save file path the server tried to load, normally World.SaveFolderName + "/" + World.SaveFileName (for example "proceduralmap.4500.123.sav"). Useful for logging or for naming a backup file; by the time your hook runs the file is already known to be missing.

Return value

The return value is ignored. Your reload still proceeds with the original file-existence check, so returning null, true or nothing at all makes no difference to whether the server starts.

How it works

The hook fires inside SaveRestore.Load, right after the server builds the save path from World.SaveFolderName and World.SaveFileName and finds that no file exists at that path. In practice this means the world is new: the map seed generated new terrain and there is no saved state to restore, so the server is about to write a clean save. The single parameter is the filename that failed the existence check.

Because the call happens during server startup and loading, the hook runs before OnServerInitialized and before any player can connect. Do not expect network entities, player data or your own saved data to be meaningful at this point beyond what already exists in oxide/data. Treat the hook as a one-shot signal that this world has never been saved before.

There is only one variant of the signature. Declaring it as private void OnNewSave(string filename) is the normal form; declaring it with no parameters is also accepted by Oxide's dispatch, but then you lose the file path. The return value is ignored, so returning anything has no effect on the load path.

Example plugin: Message the admin and snapshot data on a fresh wipe

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

namespace Oxide.Plugins
{
    [Info("New Save Notifier", "RustPluginGenerator", "1.0.0")]
    [Description("Records when a server starts on a brand new save and notifies staff")]
    public class NewSaveNotifier : RustPlugin
    {
        private const string PermNotify = "newsavenotifier.notify";
        private const string DataFile = "NewSaveNotifier";

        private PluginConfig config;
        private StoredData data;

        private class PluginConfig
        {
            [JsonProperty("Announce in chat to admins")]
            public bool AnnounceToAdmins { get; set; } = true;
        }

        private class StoredData
        {
            [JsonProperty("Last new save filename")]
            public string LastFilename { get; set; } = string.Empty;

            [JsonProperty("Last new save time (UTC)")]
            public string LastTimeUtc { get; set; } = string.Empty;

            [JsonProperty("Announcement sent")]
            public bool AnnouncementSent { 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>
            {
                ["NewSaveDetected"] = "New save detected: {0}",
                ["AdminSummary"] = "This server started on a new save ({0}). Staff have been notified."
            }, 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 OnServerInitialized()
        {
            data = Interface.Oxide.DataFileSystem.ReadObject<StoredData>(DataFile) ?? new StoredData();

            if (string.IsNullOrEmpty(data.LastFilename))
            {
                return;
            }

            PrintWarning(Msg("NewSaveDetected", null, data.LastFilename));

            if (!config.AnnounceToAdmins || data.AnnouncementSent)
            {
                return;
            }

            foreach (BasePlayer player in BasePlayer.activePlayerList)
            {
                if (player == null || !player.IsConnected) continue;
                if (!player.IsAdmin && !permission.UserHasPermission(player.UserIDString, PermNotify)) continue;

                player.ChatMessage(Msg("AdminSummary", player.UserIDString, data.LastFilename));
            }
        }

        private void OnNewSave(string filename)
        {
            data = new StoredData
            {
                LastFilename = filename ?? string.Empty,
                LastTimeUtc = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss"),
                AnnouncementSent = false
            };

            Interface.Oxide.DataFileSystem.WriteObject(DataFile, data);
            PrintWarning("Fresh world detected, save file was missing: " + data.LastFilename);
        }

        private void Unload()
        {
            if (data != null)
            {
                Interface.Oxide.DataFileSystem.WriteObject(DataFile, data);
            }
        }
    }
}

The plugin listens for OnNewSave, stores the reported filename and startup time in a small data file, and immediately writes a message to the server console and to the chat queue so staff know a brand new world was detected. A flag in the data file prevents repeated broadcasts if the world is saved and the server restarted later. OnServerInitialized then prints a short summary and, if a permission is configured, tells connected admins the server started on a new save. The message text lives in the language file so the wording can be translated or edited, and the data file is flushed in Unload.

Common use cases

  • Wipe announcements

    Record the moment a new save is created and broadcast a wipe message once players can actually receive chat, for example from OnServerInitialized instead of directly inside OnNewSave.

  • Reset plugin data per world

    Clear per-wipe counters, leaderboards or event cooldowns stored in oxide/data so a fresh map starts with fresh statistics.

  • Operational logging

    Write the generated save filename and timestamp to a log file or Discord bridge webhook so administrators can track when each server instance was actually wiped.

Pitfalls

  • Not the same as a manual wipe of saved entities

    The hook only fires when the save file is absent at load time. Deleting individual entity data, running a wipe command on a live server, or restoring a backup does not trigger it.

  • Chat will not reach anyone

    No players are connected during startup, so PrintToChat and Server.Broadcast sent from this hook are effectively lost. Defer player-facing messages to OnServerInitialized or OnPlayerConnected.

  • Runs on every server in a cluster

    Each server that starts with a missing save file raises the hook independently, so cluster setups can fire it once per instance. Guard shared data writes with a timestamp or flag.

Plugin recipes that use OnNewSave

Build a plugin with OnNewSave

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

Prompt: Wipe announcements using the OnNewSave 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 OnNewSave

Generate