Skip to content
RustPluginGenerator

OnEntitySaved

OnEntitySaved is called by Oxide right before an entity is serialized for network transmission, and only when the save targets a specific connection rather than the disk.

Signature
void OnEntitySaved(BaseNetworkable baseNetworkable, BaseNetworkable.SaveInfo saveInfo)

Parameters

Hook parameters
ParameterTypeDescription
baseNetworkableBaseNetworkableThe entity being serialized for the network. Cast it to the concrete type (StorageContainer, BuildingBlock, BasePlayer, etc.) to inspect or adjust it; it can be null.
saveInfoBaseNetworkable.SaveInfoThe save object that holds the network payload plus context such as forConnection. Its Msg is the network message being written, and forConnection identifies which client or snapshot the save is for.

Return value

The game method returns void and the hook result is ignored, so returning a value has no effect. Use the hook to inspect or modify state; you cannot cancel the network save through the return value.

How it works

The hook fires from Oxide's own save routing, not from a patched game method. Whenever an entity is written to a network message for a particular client (the forConnection value is non-null), the hook runs before the payload leaves the server. Saves to disk or to the general broadcast path are skipped because forConnection is null, and so are calls that happen before the server is fully initialized.

baseNetworkable is the entity being saved, so you can cast it to BasePlayer, BuildingBlock, StorageContainer, or another concrete type. saveInfo.forConnection tells you which client will receive the update. Declaring the first parameter as a more specific type makes Oxide skip calls for any other entity, which is useful when you only care about one class.

Because this fires for every network save of an entity, keep the handler cheap: no allocations, no logging. It is a practical place to observe visibility or adjust what a client is about to receive, but not to block the save itself.

Example plugin: Count storage container network saves per owner and report periodically

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

namespace Oxide.Plugins
{
    [Info("EntitySavedAudit", "RustPluginGenerator", "1.0.0")]
    [Description("Counts network saves of storage containers per player and reports them periodically.")]
    public class EntitySavedAudit : RustPlugin
    {
        private PluginConfig config;
        private readonly Dictionary<ulong, int> saveCounts = new Dictionary<ulong, int>();
        private Timer reportTimer;

        private class PluginConfig
        {
            [JsonProperty("Enable auditing")]
            public bool Enabled = true;

            [JsonProperty("Report interval (seconds)")]
            public float Interval = 10f;
        }

        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 void OnServerInitialized()
        {
            if (!config.Enabled) return;
            reportTimer = timer.Every(Mathf.Max(1f, config.Interval), Report);
        }

        private void OnEntitySaved(BaseNetworkable baseNetworkable, BaseNetworkable.SaveInfo saveInfo)
        {
            if (!config.Enabled) return;
            if (baseNetworkable == null) return;
            var container = baseNetworkable as StorageContainer;
            if (container == null) return;
            var ownerId = container.OwnerID;
            if (ownerId == 0) return;
            saveCounts.TryGetValue(ownerId, out var current);
            saveCounts[ownerId] = current + 1;
        }

        private void Report()
        {
            if (saveCounts.Count == 0) return;
            foreach (var kvp in saveCounts)
            {
                Puts($"Container saves for {kvp.Key}: {kvp.Value}");
            }
            saveCounts.Clear();
        }

        private void Unload()
        {
            if (reportTimer != null && !reportTimer.Destroyed) reportTimer.Destroy();
            reportTimer = null;
            saveCounts.Clear();
        }
    }
}

The plugin counts network saves of StorageContainer entities, keyed by container.OwnerID, and ignores entities whose OwnerID is 0. OnEntitySaved receives each BaseNetworkable and SaveInfo, casts the networkable to StorageContainer, and increments a per-owner counter. A timer set to the configured Interval (default 10 seconds, minimum 1 second) writes each owner's total with Puts and clears the counts, so logging happens only on the timer rather than inside the save hook. The Enabled config setting turns auditing on or off, and Unload destroys the timer.

Common use cases

  • Diagnose bandwidth hotspots

    Count savings per entity type to find which prefabs dominate network traffic to a given client. A modded server with many custom entities benefits from this visibility.

  • Verify visibility filtering

    Confirm that containers, doors, or markers are only serialized to the intended connections after you've applied custom rules elsewhere.

  • Instrument a custom entity system

    Track when your own BaseNetworkable subclasses are saved to clients to detect components that are churning too many updates.

Pitfalls

  • Hook does not fire for disk saves

    Saves with a null forConnection are skipped, so the hook is useless for inspecting data file persistence. Use OnServerSave or OnNewSave for that instead.

  • Fires very often

    Every network save of every entity triggers the hook. Logging, LINQ, or string allocation inside the handler will hurt performance on busy servers.

  • Cannot block the payload

    The return value is ignored and the save proceeds. If you need to suppress or alter data, do it earlier in the pipeline rather than relying on this hook.

Build a plugin with OnEntitySaved

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

Prompt: Diagnose bandwidth hotspots using the OnEntitySaved 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 OnEntitySaved

Generate