CanCombineDroppedItem
CanCombineDroppedItem is called when one dropped item entity lands on another and the game is about to merge their stacks. Returning any non-null value blocks the merge and leaves both entities separate.
object CanCombineDroppedItem(DroppedItem droppedItem, DroppedItem di)Parameters
| Parameter | Type | Description |
|---|---|---|
droppedItem | DroppedItem | The DroppedItem entity that was dropped onto (the target stack on the ground). Its item is the stack that would grow. |
di | DroppedItem | The DroppedItem that was just dropped or moved onto the target. Its item is the stack that would be merged into droppedItem. |
Return value
Returning null (or not implementing the hook) lets the merge continue normally. Returning any non-null value stops OnDroppedOn before the amounts are combined, so both dropped item entities stay separate. The returned object itself is discarded because the original method returns void.
How it works
The hook fires from DroppedItem.OnDroppedOn, which runs when a dropped item is placed on top of another dropped item (for example by physics settling, by a player dropping an item onto an existing stack, or when a stack is moved onto a ground item). The game first checks that both entities still own items, that neither has NeverCombine set and that item.CanStack(di.item) passes, then calls CanCombineDroppedItem before summing di.item.amount + item.amount.
droppedItem is the receiving entity; di is the incoming one. Read droppedItem.item and di.item to inspect shortnames, skins, amounts or GetOwnerPlayer(). Both arguments are already DroppedItem, so the declared types are as specific as Oxide can dispatch on; a null-check is still needed because either entity's item can be null in edge cases.
Use it to keep stacks apart for custom rules: block merging of different skins (the game already refuses different skins in CanStack, but you may want to segment by owner or category), or stop merging entirely on your server. The hook is followed by OnDroppedItemCombined only when the merge proceeds.
Example plugin: Prevent merging of player-dropped stacks by owner
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("No Dropped Stack Merge", "RustPluginGenerator", "1.0.0")]
[Description("Prevents selected players' dropped items from merging with other stacks on the ground")]
public class NoDroppedStackMerge : RustPlugin
{
private const string PermKeep = "nodroppedstackmerge.keep";
private PluginConfig config;
private class PluginConfig
{
[JsonProperty("Block merging for all players")]
public bool BlockForEveryone { get; set; } = false;
}
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>
{
["Status"] = "Dropped stack merging - everyone blocked: {0}. Permission '{1}' holders are always exempt from merging.",
["Granted"] = "You now keep your dropped stacks separate.",
["Revoked"] = "Your dropped stacks can merge again."
}, 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(PermKeep, this);
}
private object CanCombineDroppedItem(DroppedItem droppedItem, DroppedItem di)
{
if (droppedItem == null || di == null) return null;
if (droppedItem.item == null || di.item == null) return null;
if (config.BlockForEveryone) return true;
if (IsProtected(droppedItem.item) || IsProtected(di.item)) return true;
return null;
}
private bool IsProtected(Item item)
{
var owner = item.GetOwnerPlayer();
if (owner == null) return false;
return permission.UserHasPermission(owner.UserIDString, PermKeep);
}
[ChatCommand("mergestatus")]
private void CmdMergeStatus(BasePlayer player, string command, string[] args)
{
if (player == null) return;
SendReply(player, Msg("Status", player.UserIDString, config.BlockForEveryone, PermKeep));
}
[ChatCommand("mergetoggle")]
private void CmdMergeToggle(BasePlayer player, string command, string[] args)
{
if (player == null) return;
if (!player.IsAdmin) return;
bool granted;
if (permission.UserHasPermission(player.UserIDString, PermKeep))
{
permission.RevokeUserPermission(player.UserIDString, PermKeep);
granted = false;
}
else
{
permission.GrantUserPermission(player.UserIDString, PermKeep, this);
granted = true;
}
SendReply(player, Msg(granted ? "Granted" : "Revoked", player.UserIDString));
}
}
}The plugin adds a permission that exempts a player's items from merging with anything else on the ground. CanCombineDroppedItem compares the owner of each stack via item.GetOwnerPlayer(); if either side belongs to a player holding nodroppedstackmerge.keep, it returns true, which blocks the merge. A config toggle lets admins disable merging for every player on the server instead. Because the hook can fire often on busy servers, nothing is logged inside it; the only output is the optional chat warning sent by a /mergestatus command that reports the current mode.
Common use cases
Keep premium skin stacks separate
Block merging when either stack carries a skin ID you want to keep distinct, so collectors' skinned drops never absorb a plain stack.
Stop automatic stack merging server-wide
Return true for every pair when a server wants fully discrete ground loot, for example on scarcity-focused wipes or custom loot economies.
Segment merging by owner
Compare GetOwnerPlayer() on both items and refuse merges across different players so dropped loot keeps its original owner tag for return-on-death rules.
Pitfalls
Null item on either entity
DroppedItem.itemcan be null if the entity's item was already taken or removed. Always check bothdroppedItem?.itemanddi?.itembefore calling intoItemmembers.Return value type does not matter
The original method returns void, so only null versus non-null counts. Returning
falsestill blocks the merge because it is not null.Does not cover inventory merging
This hook only handles dropped item entities bumping into each other. Merging inside containers is controlled by
CanStackItemand container-level logic.
Build a plugin with CanCombineDroppedItem
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 CanCombineDroppedItem
Generate