Skip to content
RustPluginGenerator

OnMixingTableFinished

OnMixingTableFinished is called after a MixingTable completes its mixing cycle, once the ingredients are consumed and the produced items have been created inside the table's output slot.

Signature
void OnMixingTableFinished(MixingTable mixingTable, BasePlayer startingPlayer, Recipe recipe, int quantity)

Parameters

Hook parameters
ParameterTypeDescription
mixingTableMixingTableThe MixingTable entity that finished producing. Use it to read the table's position, owner ID, inventory or flags for notifications and placement effects.
startingPlayerBasePlayerThe BasePlayer recorded as MixStartingPlayer on the table when mixing began. It can be null if no player was stored, so always null-check before using it.
recipeRecipeThe Recipe that was produced. Gives ProducedItem (item definition and amount), ingredients and the table's recipe index are not needed here since quantity is passed separately.
quantityintHow many crafting runs were completed, so the total output is recipe.ProducedItem.amount multiplied by this value.

Return value

The hook's return value is ignored because MixingTable.ProduceItem returns void. Return nothing and let the game continue its normal path; nothing you return can cancel production, which has already happened by the time the hook fires.

How it works

The hook fires inside MixingTable.ProduceItem, after the table has set its pending item id, stopped mixing, consumed the recipe ingredients and created the finished items. That means by the time your method runs, the output already exists in the table's inventory and pendingItemId points at it. It is called once per completed cycle, not per tick, so it is safe for light work.

mixingTable is the entity itself, useful for position, OwnerID or inventory. startingPlayer is the stored MixStartingPlayer and may be null. recipe exposes ProducedItem (an ItemAmount with itemid, amount, itemDef) so you can identify the output, and quantity tells you how many runs finished.

There is only one injection site and the original method returns void, so the return value is ignored. Declaring mixingTable as a more specific type such as BaseEntity has no practical narrowing effect here, but it is still checked during dispatch. Keep the handler short: notifications, statistics or bonus item grants.

Example plugin: Announce finished mixing output to the player

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

namespace Oxide.Plugins
{
    [Info("Mixing Table Notifier", "RustPluginGenerator", "1.0.0")]
    [Description("Notifies the player who started a mixing table when its output is ready.")]
    public class MixingTableNotifier : RustPlugin
    {
        private class PluginConfig
        {
            [JsonProperty("Chat message to starting player")]
            public bool NotifyPlayer = true;

            [JsonProperty("Broadcast to server")]
            public bool Broadcast = false;
        }

        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);

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                ["Ready"] = "Your mixing table finished: {0} x{1}",
                ["Broadcast"] = "{0} finished {1} x{2} at a mixing table"
            }, this);
        }

        private string Msg(string key, string userId = null, params object[] args) =>
            string.Format(lang.GetMessage(key, this, userId), args);

        private void OnMixingTableFinished(MixingTable mixingTable, BasePlayer startingPlayer, Recipe recipe, int quantity)
        {
            if (mixingTable == null || recipe == null || recipe.ProducedItem == null) return;

            var itemDef = recipe.ProducedItem;
            string itemName = itemDef.displayName != null ? itemDef.displayName.english : itemDef.shortname;
            int total = Math.Max(1, recipe.ProducedItemCount) * Math.Max(1, quantity);

            if (config.NotifyPlayer && startingPlayer != null && startingPlayer.IsConnected)
            {
                startingPlayer.ChatMessage(Msg("Ready", startingPlayer.UserIDString, itemName, total));
            }

            if (config.Broadcast)
            {
                string who = startingPlayer != null ? startingPlayer.displayName : "Someone";
                Server.Broadcast(Msg("Broadcast", null, who, itemName, total));
            }
        }
    }
}

The plugin hooks OnMixingTableFinished and returns early if mixingTable, recipe, or recipe.ProducedItem is null. It builds a readable message from recipe.ProducedItem and a total computed as Math.Max(1, recipe.ProducedItemCount) * Math.Max(1, quantity). If NotifyPlayer is enabled and the starting player is connected, it sends a chat message to that player using the Ready language key. If Broadcast is enabled, it sends the Broadcast language key to the whole server, naming the starting player's displayName or Someone if they are null. Both messages go through the language file, so admins can translate them. No data is written and nothing is cancelled.

Common use cases

  • Notify the crafter

    Send a chat line to the player who started mixing so they know the table finished without walking back to check.

  • Log production statistics

    Record how many explosives or other mixed items were produced per player for economy or activity tracking.

  • Grant bonus output

    Give extra items or a small reward to the starting player when a high-value recipe such as explosives completes.

Pitfalls

  • startingPlayer can be null

    The stored MixStartingPlayer is not guaranteed to be set, for example after a server restart. Guard every use of it.

  • Do not try to cancel

    The hook fires after ingredients are consumed and items created, and the return value is ignored. Use OnMixingTableToggle or input hooks if you need to block mixing beforehand.

  • quantity multiplies output

    reporting recipe.ProducedItem.amount alone understates the total. Multiply it by quantity to get the real production count.

Build a plugin with OnMixingTableFinished

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

Prompt: Notify the crafter using the OnMixingTableFinished 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 OnMixingTableFinished

Generate