Skip to content
RustPluginGenerator

OnXmasStockingFill

OnXmasStockingFill is called when a Christmas stocking is empty and about to be filled with its default loot. Returning a non-null value suppresses the vanilla fill.

Signature
object OnXmasStockingFill(Stocking stocking)

Parameters

Hook parameters
ParameterTypeDescription
stockingStockingThe Stocking entity whose loot is about to be generated. Use its inventory, transform.position, OwnerID and net.ID to inspect or replace the contents.

Return value

Return null (or let the method fall through) to let the vanilla SpawnLoot routine run and fill the stocking with default loot. Return any non-null value to skip the original fill entirely; the returned object is discarded because the patched method returns void.

How it works

The hook fires from Stocking.SpawnLoot, and only when two conditions hold: the stocking's inventory is not null and IsEmpty() returns true. That means it runs when a stocking is first made lootable on a server running the Christmas event, not every time someone opens it. If the container already holds items, the hook is never called.

The only parameter is the Stocking entity itself. Because it derives from StorageContainer, you can read stocking.inventory (an ItemContainer), clear it, or push items into it with ItemManager.CreateByName and MoveToContainer. You can also use OwnerID to find the owner and transform.position for location-based logic.

The hook is called on every empty stocking that attempts a fill, so it can fire many times during the holiday period. Keep the body cheap: no Puts, no per-entity network updates. If you want a specific type of stocking, narrow the parameter to a subclass, but in practice the base Stocking type is what you will always receive here.

Example plugin: Fill Christmas stockings with a configurable custom loot table

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

namespace Oxide.Plugins
{
    [Info("Custom Stocking Loot", "RustPluginGenerator", "1.0.0")]
    [Description("Fills Christmas stockings with a configurable loot table instead of the default one.")]
    public class CustomStockingLoot : RustPlugin
    {
        private class LootEntry
        {
            [JsonProperty("Shortname")]
            public string Shortname = "scrap";

            [JsonProperty("Amount")]
            public int Amount = 25;
        }

        private class PluginConfig
        {
            [JsonProperty("Use custom loot table")]
            public bool Enabled = true;

            [JsonProperty("Loot entries")]
            public List<LootEntry> Loot = new List<LootEntry>
            {
                new LootEntry { Shortname = "scrap", Amount = 50 },
                new LootEntry { Shortname = "xmas.present.small", Amount = 1 },
                new LootEntry { Shortname = "xmas.present.medium", Amount = 1 }
            };
        }

        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 void OnServerInitialized()
        {
            if (!config.Enabled || config.Loot == null) return;

            foreach (var entry in config.Loot)
            {
                if (string.IsNullOrEmpty(entry.Shortname)) continue;
                var def = ItemManager.FindItemDefinition(entry.Shortname);
                if (def == null)
                {
                    PrintWarning($"Unknown item shortname in config: {entry.Shortname}");
                    continue;
                }
                if (entry.Amount > def.stackable)
                {
                    PrintWarning($"{entry.Shortname} amount {entry.Amount} exceeds stack size {def.stackable}");
                }
            }
        }

        private object OnXmasStockingFill(Stocking stocking)
        {
            if (!config.Enabled || stocking == null) return null;
            if (stocking.inventory == null) return null;

            var entries = config.Loot;
            if (entries == null || entries.Count == 0) return null;

            foreach (var entry in entries)
            {
                var def = ItemManager.FindItemDefinition(entry.Shortname);
                if (def == null) continue;

                int remaining = Mathf.Max(1, entry.Amount);
                while (remaining > 0)
                {
                    int amount = Mathf.Min(remaining, def.stackable);
                    var item = ItemManager.CreateByName(entry.Shortname, amount);
                    if (item == null) break;

                    if (!item.MoveToContainer(stocking.inventory))
                    {
                        item.Remove();
                        break;
                    }
                    remaining -= amount;
                }
            }

            stocking.inventory.MarkDirty();
            return true;
        }
    }
}

The plugin defines a config list of shortnames and amounts. When OnXmasStockingFill fires, it checks the stocking's inventory, then inserts each configured item, stacking it if needed and otherwise creating a new item via ItemManager.CreateByName. A stack-size warning is printed at load time for entries that exceed the item's stackable value. The hook returns true so the vanilla loot table never runs, giving admins full control. Reload the plugin after editing the config to apply new entries, and leave the list empty to keep stockings vanilla.

Common use cases

  • Custom loot tables

    Replace the default holiday loot with server-specific items such as scrap, components or event currency. Returning a value stops the vanilla fill.

  • Owner-restricted rewards

    Read stocking.OwnerID to give the stocking's owner a personal reward, for example a gift box tied to their Steam ID.

  • Anti-farm tuning

    Reduce the value of stockings during high-population events by filling them with mostly scrap or low-tier components instead of premium items.

Pitfalls

  • Hook only fires on empty stockings

    SpawnLoot is guarded by IsEmpty(). If anything already put an item in the container, your hook will not run and the vanilla fill is also skipped for that pass.

  • Do not stack over the item limit

    Custom amounts must respect item.info.stackable. Overfilled stacks are clamped or dropped by the container, so split large rewards into several GiveItem/MoveToContainer calls.

  • Return value is not a boolean result

    The patched method returns void, so the object you return only acts as a flag. Returning false still suppresses the vanilla fill because it is non-null. Return null to keep vanilla behavior.

Build a plugin with OnXmasStockingFill

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

Prompt: Custom loot tables using the OnXmasStockingFill 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 OnXmasStockingFill

Generate