Skip to content
RustPluginGenerator

OnMaxStackable

OnMaxStackable is called whenever the game asks an item for its maximum stack size via Item.MaxStackable, letting plugins override the value returned to inventory and stacking logic.

Signature
object OnMaxStackable(Item item)

Parameters

Hook parameters
ParameterTypeDescription
itemItemThe Item instance whose maximum stack size is being calculated. Access item.info for the item definition and item.parent for the ItemContainer it currently lives in (may be null).

Return value

Return an int to replace the item's stack limit for that call; the game uses your value directly. Return null (or any non-int) to keep the game's computed default, which is info.stackable adjusted by the parent container's stack size rules.

How it works

This hook fires inside Item.MaxStackable. The game first computes a baseline number from item.info.stackable, then adjusts it by the parent container's maxStackSize (the smaller of the two when allowItemsToIncreaseToMaxStackSize is false, the larger otherwise). Right before returning that baseline, Oxide calls OnMaxStackable with the item. The call happens every time something queries the stack limit, which includes merging items into a container, splitting stacks, moving items, and refreshing nearby loot views, so it can run frequently. Narrowing does not help here because the only parameter is a single Item; instead, branch on item.info.shortname, item.info.itemid, or item.skin inside the hook. Keep the callback cheap: avoid heavy lookups and never log on every call. The container is often null (for example when an item is being created in a vacuum or inspected outside a parent), so guard item.parent before reading container properties.

Example plugin: Raise the stack limit for a configured item shortname

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

namespace Oxide.Plugins
{
    [Info("CustomStackLimit", "RustPluginGenerator", "1.0.0")]
    [Description("Overrides the maximum stack size of a configured item shortname.")]
    public class CustomStackLimit : RustPlugin
    {
        private const string PermReload = "customstacklimit.reload";

        private PluginConfig config;

        private class PluginConfig
        {
            [JsonProperty("Target shortname")]
            public string TargetShortname = "ammo.rifle";

            [JsonProperty("Custom stack limit")]
            public int StackLimit = 128;
        }

        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>
            {
                ["Reloaded"] = "Stack limit for {0} is now {1}.",
                ["Denied"] = "You do not have permission to use this command."
            }, 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(PermReload, this);
        }

        private object OnMaxStackable(Item item)
        {
            if (item == null || item.info == null) return null;
            if (string.IsNullOrEmpty(config.TargetShortname)) return null;
            if (item.info.shortname != config.TargetShortname) return null;

            int limit = Mathf.Max(1, config.StackLimit);
            return limit;
        }

        [ChatCommand("stacklimit")]
        private void CmdStackLimit(BasePlayer player, string command, string[] args)
        {
            if (player == null) return;
            if (!permission.UserHasPermission(player.UserIDString, PermReload))
            {
                player.ChatMessage(Msg("Denied", player.UserIDString));
                return;
            }

            if (args == null || args.Length < 2)
            {
                player.ChatMessage("Usage: /stacklimit <shortname> <amount>");
                return;
            }

            if (!int.TryParse(args[1], out int amount) || amount < 1)
            {
                player.ChatMessage("Amount must be a positive integer.");
                return;
            }

            config.TargetShortname = args[0];
            config.StackLimit = amount;
            SaveConfig();

            player.ChatMessage(Msg("Reloaded", player.UserIDString, config.TargetShortname, config.StackLimit));
        }
    }
}

The plugin stores a shortname plus a desired stack limit in its config. When OnMaxStackable runs, it checks that item and item.info are non-null and that the item's shortname matches the configured one, then returns the configured limit as an int. Every other item falls through by returning null, so the game keeps its normal computed value. Because the hook already receives the item and its parent, no container lookups are needed. A chat command lets admins reload the target shortname at runtime without restarting the server, and the config is validated on load so a missing or malformed file falls back to sensible defaults.

Common use cases

  • Give donors larger stacks

    Return a higher limit for specific shortnames so players can carry more ammo or resources per slot, reducing inventory pressure on busy servers.

  • Cap stack sizes on custom items

    Return a smaller int for plugin-created items to prevent players from hoarding large quantities in a single slot when the economy relies on scarcity.

  • Skin-aware stacking rules

    Branch on item.skin to treat event or reward variants differently from their vanilla counterparts, so special skins stack less or more than normal items.

Pitfalls

  • This hook runs very often

    Item.MaxStackable is queried during nearly every inventory operation. Do not log, allocate collections, or run expensive lookups inside the callback; keep it to a shortname check and a return.

  • Returning 0 or a negative value

    Returning a non-positive int becomes the stack limit and can break merging and splitting logic. Clamp to at least 1 and be aware the item may then refuse to combine.

  • Mismatched type breaks the override

    The game only honors the return value when it is a boxed int. Returning a long, float, or string silently falls back to the default, so always cast to int and return null otherwise.

Build a plugin with OnMaxStackable

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

Prompt: Give donors larger stacks using the OnMaxStackable 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 OnMaxStackable

Generate