OnInventoryItemsFind
OnInventoryItemsFind is called when PlayerInventory.FindItemsByItemID is invoked to collect every item of a given item ID from a player's inventory. Returning a non-null value cancels the game's own collection for that call.
object OnInventoryItemsFind(PlayerInventory playerInventory, int id, List<Item> list)Parameters
| Parameter | Type | Description |
|---|---|---|
playerInventory | PlayerInventory | The PlayerInventory instance the search is running on. Use it to identify the owner via playerInventory.baseEntity and to inspect the main, belt and wear containers. |
id | int | The item ID being searched for (ItemDefinition.itemid), not a slot index. Compare it against item.info.itemid to know which item type the game is collecting. |
list | List<Item> | The result List<Item> the game is filling with matching items. You can add, remove or reorder entries here to change what the caller receives. |
Return value
Returning null lets the game run its normal scan of the main, belt and wear containers and add matches to list. Returning any non-null object stops the original method immediately, so the game adds nothing and the caller sees only whatever you placed in list yourself.
How it works
This hook fires inside PlayerInventory.FindItemsByItemID, the method the game uses to gather all items matching an item ID from a player's inventory. It runs once per call, before the main container is scanned, and only covers that first step: the vanilla code that follows checks containerMain, then its belt and wear containers, adding matches to the passed list.
playerInventory is the inventory being searched; playerInventory.baseEntity is the owning BasePlayer when one exists. id is the item ID (for example the ID of scrap or a specific ammo type), which you can resolve with ItemManager.FindItemDefinition on the shortname side. list is the accumulator the game writes into, so you can observe it, prune entries or append your own items.
Because PlayerInventory is the most specific type in the signature, you cannot narrow this hook further by declaring a derived parameter - there is nothing more specific to switch to. The hook runs whenever game code calls the search, so it can fire often; keep the body cheap and avoid logging or chat output.
This is useful when you want to gate or extend what the game considers "found" items, for example virtual or custom items that should count toward a search, or filtering out protected items before another system consumes the list.
Example plugin: Count a protected item as hidden from searches
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("Hide Protected Items On Search", "RustPluginGenerator", "1.0.0")]
[Description("Removes configured protected items from PlayerInventory.FindItemsByItemID search results.")]
public class HideProtectedItemsOnSearch : RustPlugin
{
private const string PermBypass = "hideprotecteditemsonsearch.bypass";
private PluginConfig config;
private class PluginConfig
{
[JsonProperty("Protected item shortnames")]
public List<string> ProtectedShortnames = new List<string> { "scrap" };
}
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>
{
["Protected"] = "Protected from searches: {0}"
}, 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(PermBypass, this);
}
[ChatCommand("protecteditems")]
private void CmdProtectedItems(BasePlayer player, string command, string[] args)
{
if (player == null || !player.IsAdmin) return;
SendReply(player, Msg("Protected", player.UserIDString, string.Join(", ", config.ProtectedShortnames)));
}
private object OnInventoryItemsFind(PlayerInventory playerInventory, int id, List<Item> list)
{
if (playerInventory == null || list == null) return null;
BasePlayer owner = playerInventory.baseEntity as BasePlayer;
if (owner == null || permission.UserHasPermission(owner.UserIDString, PermBypass)) return null;
ItemDefinition def = ItemManager.FindItemDefinition(id);
if (def == null || !config.ProtectedShortnames.Contains(def.shortname)) return null;
for (int i = list.Count - 1; i >= 0; i--)
{
Item item = list[i];
if (item?.info != null && item.info.itemid == id) list.RemoveAt(i);
}
return list;
}
}
}The plugin keeps a configurable set of item shortnames that should be invisible to FindItemsByItemID searches when the owner is holding them in the main container. When the hook fires, it checks that a player owns the inventory and that the searched id matches a protected shortname. If so it removes any matching entries already in list, working from the end of the list so indices stay valid, and then returns list. Returning that non-null object stops the game's own scan, so belt and wear results for that item ID are also skipped. A short permission check lets staff bypass the filter, and a chat command reports the current protected list to admins.
Common use cases
Hide protected currencies from searches
Remove a server currency item from search results so other plugins using FindItemsByItemID do not treat it as available loot or ammo.
Inject virtual inventory items
Add Item objects created with ItemManager.CreateByName into the list so external systems see virtual items that are not stored in any container.
Cap the result set for hot paths
Trim the list to a maximum count so downstream code iterating every match does less work on inventories with many stacks.
Pitfalls
Returning a value skips the entire vanilla scan
The stop happens before containerMain, belt and wear are scanned. If you return non-null you must reproduce any additions yourself, or results will silently be missing.
This hook fires frequently
FindItemsByItemID is called by ammo checks and many plugin systems. Never print warnings or send chat messages from the hook body; gate any output behind an explicit admin command.
The list is shared with the caller
Mutating list changes what the calling code sees. Remove entries from the end backwards so index-based removal does not skip items.
Build a plugin with OnInventoryItemsFind
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 OnInventoryItemsFind
Generate