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.
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
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
- How to make a Rust daily rewards plugin (Oxide C#)Adds a /daily command that lets each player claim one reward from a configurable weighted list every 24 hours, with a streak bonus that scales while claims stay within 48 hours of each other. Claims and streaks are persisted to oxide/data with the Oxide data file API.
- How to make a Rust heli and Bradley loot lock plugin (PvE ownership)Tracks damage dealt to the Patrol Helicopter and Bradley APC per player and locks the crates they drop for a configurable time, allowing only the top damager and their team to loot. Uses OnEntityTakeDamage, OnEntityDeath, OnEntitySpawned and CanLootEntity.
- How to make a Rust leaderboard UI plugin (CUI top 10)Tracks kills, deaths and K/D per player in oxide/data and renders a CUI top-10 board with /top. Uses OnEntityDeath to record kills/deaths and OnServerSave to flush data.
- How to make a Rust playtime group promotion plugin (Oxide/Carbon)Tracks each player's connected playtime in oxide/data and moves them into stacked Oxide groups when they cross configured hour thresholds. Uses OnPlayerConnected and OnPlayerDisconnected to start and stop counting.
- How to make a Rust PvP toggle plugin (Oxide/Carbon)Adds a /pvp command that switches each player between PvP and PvE mode with a per-player cooldown, stores the choice in oxide/data, and blocks player-versus-player damage unless both sides have PvP enabled. It uses OnEntityTakeDamage(BasePlayer, HitInfo) to cancel damage.
- How to make a Rust server currency plugin (Oxide balances + /pay)A wallet plugin that stores per-player balances in a data file, exposes /balance, /pay and admin give/take console commands, saves on OnServerSave, and publishes GetBalance/Deposit/Withdraw for other plugins.
- How to make a Rust team switch cooldown plugin (leave/kick lockout)Blocks a player from joining a team for N hours after leaving or being kicked, using OnTeamLeave, OnTeamKick and OnTeamAcceptInvite with per-player UTC timestamps saved in oxide/data.
- How to make a Rust team teleport plugin (/tpteam)Adds a /tpteam <name> command that teleports a player to a teammate after a warmup, with a per-player cooldown and an opt-out toggle via /tpteam off. It compares Player.currentTeam on both players and drives the warmup with Oxide timers.
Build a plugin with OnServerSave
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 OnServerSave
Generate