OnItemDeployed
OnItemDeployed is called after a deployable item has been spawned into the world, right after the mod's OnDeployed callback and before the item amount is consumed. It fires for both regular deployments and slot-based placements such as wall-mounted items.
void OnItemDeployed(Deployer deployer, ItemModDeployable modDeployable, BaseEntity entity)Parameters
| Parameter | Type | Description |
|---|---|---|
deployer | Deployer | The Deployer component that performed the placement, usually parented to the item being deployed. It gives access to the owning item and player through its normal members. |
modDeployable | ItemModDeployable | The ItemModDeployable on the item that was used. Its entityPrefab, and the item definition behind it, describe which entity the item spawns. |
entity | BaseEntity | The BaseEntity that was just spawned on the server. This is the placed object (a deployable, a slot-based entity, or another prefab) and is safe to inspect, modify or kill. |
Return value
The return value is ignored on both injection sites; returning null, true or any other value does not change the deployment. The game continues with UseItemAmount(1) regardless.
How it works
The hook fires inside Deployer.DoDeploy_Regular and Deployer.DoDeploy_Slot, after the game has set the entity's skin, owner and position, called Spawn(), and invoked ItemModDeployable.OnDeployed. It runs before UseItemAmount(1) consumes the deployed item, so at call time the item still exists in the player's inventory.
entity is the placed object itself: use it to read OwnerID, skinID, PrefabName or its position, or to adjust or remove it. modDeployable identifies the item type that was used (its entityPrefab and item definition), and deployer is the component that ran the deployment.
Both sites call the same hook name but pass different argument types: the regular path passes (Deployer, ItemModDeployable, BaseEntity) and the slot path passes (Deployer, BaseEntity, BaseEntity). Declare the exact signature you need; Oxide dispatches by argument type, so a method declared with ItemModDeployable will not fire from the slot path. If you only care about the placed entity, a method taking a single BaseEntity is not enough here because the hook passes three arguments, so declare all three.
Because the hook fires per placement, treat it as low frequency but avoid PrintToChat or expensive work inside it.
Other signatures
Oxide also calls OnItemDeployed from other places in the game with these parameter types. Declare the overload you need, or several:
void OnItemDeployed(Deployer deployer, BaseEntity entity, BaseEntity baseEntity2)
Example plugin: Limit deployables per player and block listed prefabs
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Deploy Limit", "RustPluginGenerator", "1.0.0")]
[Description("Blocks configured deployables and caps how many of each prefab a player can place.")]
public class DeployLimit : RustPlugin
{
private const string PermBypass = "deploylimit.bypass";
private class PluginConfig
{
[JsonProperty("Blocked prefabs")]
public List<string> BlockedPrefabs = new List<string> { "wall.external.high", "barricade.metal" };
[JsonProperty("Default limit per player")]
public int DefaultLimit = 5;
[JsonProperty("Limit overrides by prefab")]
public Dictionary<string, int> Limits = new Dictionary<string, int>
{
["wall.external.high.stone"] = 10,
["door.hinged.metal"] = 3
};
}
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>
{
["Blocked"] = "Placing {0} is not allowed on this server.",
["Limit"] = "You already have {0} of {0} and cannot place more.",
["LimitReached"] = "You have reached the limit of {0} for {1}."
}, 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);
}
private void OnItemDeployed(Deployer deployer, ItemModDeployable modDeployable, BaseEntity entity)
{
HandleDeployment(entity);
}
private void OnItemDeployed(Deployer deployer, BaseEntity entity, BaseEntity placed)
{
HandleDeployment(placed);
}
private void HandleDeployment(BaseEntity entity)
{
if (entity == null || entity.IsDestroyed) return;
var player = entity.OwnerID == 0 ? null : BasePlayer.FindByID(entity.OwnerID);
if (player == null) return;
if (permission.UserHasPermission(player.UserIDString, PermBypass)) return;
string prefab = entity.ShortPrefabName;
string display = entity.ShortPrefabName;
if (config.BlockedPrefabs != null && config.BlockedPrefabs.Contains(prefab))
{
entity.Kill();
player.ChatMessage(Msg("Blocked", player.UserIDString, display));
return;
}
int limit = GetLimit(prefab);
if (limit <= 0) return;
int count = CountOwned(player.userID.Get(), prefab);
if (count > limit)
{
entity.Kill();
player.ChatMessage(Msg("LimitReached", player.UserIDString, limit, display));
}
}
private int GetLimit(string prefab)
{
int limit;
if (config.Limits != null && config.Limits.TryGetValue(prefab, out limit)) return limit;
return config.DefaultLimit;
}
private int CountOwned(ulong ownerId, string prefab)
{
int count = 0;
foreach (var networkable in BaseNetworkable.serverEntities)
{
var entity = networkable as BaseEntity;
if (entity == null || entity.IsDestroyed) continue;
if (entity.OwnerID != ownerId) continue;
if (entity.ShortPrefabName != prefab) continue;
count++;
}
return count;
}
}
}The plugin subscribes to OnItemDeployed(Deployer, ItemModDeployable, BaseEntity) and looks up the placed entity's prefab name. If the prefab is on the config blocklist, it destroys the entity with Kill() and sends the owner a localized message; the item is still consumed because the original code path continues, which the example notes to the player. Otherwise it counts how many live entities of the same prefab the owner already has and kills the new one when the per-player limit is reached. Configuration holds the blocklist, the default limit and an optional per-prefab override dictionary. The count walks BaseNetworkable.serverEntities, so it only runs on an actual deployment, not on a timer.
Common use cases
Block specific deployables
Kill the spawned entity when its prefab appears in a config blocklist, for example to stop players placing certain items on PvE or event servers.
Cap deployables per player
Count existing entities owned by the player with the same prefab and remove the new one once a limit is reached, keeping base spam under control.
Tag or modify the placed object
Adjust properties on
entitysuch as health, skin or flags right after spawning, or attach bookkeeping data keyed byentity.net.ID.Value.
Pitfalls
The item is still consumed
The hook fires before
UseItemAmount(1), and the return value is ignored, so killing the entity does not refund the item. Grant a replacement item yourself if you want to compensate the player.Argument types differ between deploy paths
The regular path passes
ItemModDeployableas the second argument while the slot path passes aBaseEntity. A method declared withItemModDeployablenever fires from slot deployments; use theBaseEntity, BaseEntityoverload if you need those.Entity may already be gone
Other plugins or the game can remove the entity in the same tick. Check
entity == null || entity.IsDestroyedbefore touching it, and do not assumeentityis a specific subclass on the slot path.
Plugin recipes that use OnItemDeployed
Build a plugin with OnItemDeployed
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 OnItemDeployed
Generate