OnAnimalDungProduce
OnAnimalDungProduce is called when a ridable animal (RidableHorse) runs its dung production step, right before the game spawns the dung item at the animal's position. Returning a non-null value skips the vanilla dung spawn.
object OnAnimalDungProduce(RidableHorse ridableHorse)Parameters
| Parameter | Type | Description |
|---|---|---|
ridableHorse | RidableHorse | The horse or other ridable animal that is about to drop dung. It is a live RidableHorse entity; check whether it is null and whether it still has an owner before acting on it. |
Return value
Return null to let the game continue its normal dung production and spawn the dung item with random velocity. Return any non-null value (for example true) to stop the default code path, so no dung item is created for that animal at that moment.
How it works
The hook fires inside RidableHorse.DoDung, which the game runs on its internal dung production timer for tamed/owned ridable animals such as horses. The decrement of the internal counter has already happened when the hook is called, so your code runs at the exact moment a dung item would be created. The only argument is the animal itself, so you can inspect its position, owner, breed and health. Declaring the parameter as RidableHorse (the exact type) is required; the game passes that object, so a broader BaseEntity parameter would also receive calls but gives you nothing extra. Because DoDung runs per animal on a repeating timer, this hook can fire often on a busy server; keep the callback cheap. Any non-null return value suppresses the default dung spawn, which makes this the natural place to disable dung on specific animals or replace it with your own reward logic.
Example plugin: Auto-collect horse dung into the owner's inventory
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Auto Dung Collector", "RustPluginGenerator", "1.0.0")]
[Description("Gives horse dung directly to the owner instead of dropping it on the ground")]
public class AutoDungCollector : RustPlugin
{
private const string PermToggle = "autodungcollector.toggle";
private PluginConfig config;
private readonly HashSet<ulong> disabled = new HashSet<ulong>();
private class PluginConfig
{
[JsonProperty("Dung item shortname")]
public string DungShortname = "horsedung";
[JsonProperty("Amount per production")]
public int Amount = 1;
[JsonProperty("Respect per-player toggle")]
public bool RespectToggle = true;
}
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>
{
["Collected"] = "Your horse dropped {0}x {1}, collected automatically.",
["ToggledOn"] = "Auto collection enabled for your horses.",
["ToggledOff"] = "Auto collection disabled, your horses drop dung normally.",
["InventoryFull"] = "Your inventory is full, the dung was left on the ground."
}, 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(PermToggle, this);
}
[ChatCommand("autodung")]
private void CmdAutoDung(BasePlayer player, string command, string[] args)
{
if (!permission.UserHasPermission(player.UserIDString, PermToggle))
{
return;
}
if (disabled.Remove(player.userID.Get()))
{
SendReply(player, Msg("ToggledOn", player.UserIDString));
}
else
{
disabled.Add(player.userID.Get());
SendReply(player, Msg("ToggledOff", player.UserIDString));
}
}
private object OnAnimalDungProduce(RidableHorse ridableHorse)
{
if (ridableHorse == null || ridableHorse.IsDestroyed)
{
return null;
}
var owner = BasePlayer.FindByID(ridableHorse.OwnerID);
if (owner == null || !owner.IsConnected)
{
return null;
}
if (config.RespectToggle && disabled.Contains(owner.userID.Get()))
{
return null;
}
var definition = ItemManager.FindItemDefinition(config.DungShortname);
if (definition == null)
{
return null;
}
var item = ItemManager.CreateByName(config.DungShortname, Mathf.Max(1, config.Amount));
if (item == null)
{
return null;
}
if (!owner.inventory.GiveItem(item))
{
item.Drop(ridableHorse.transform.position + Vector3.up * 0.3f, Vector3.zero);
SendReply(owner, Msg("InventoryFull", owner.UserIDString));
}
else
{
SendReply(owner, Msg("Collected", owner.UserIDString, item.amount, item.info.displayName.english));
}
return true;
}
}
}The plugin blocks the vanilla dung drop for owned horses and instead gives the item straight to the owner. OnAnimalDungProduce checks that the horse still exists and has a connected owner, then returns true to suppress the world drop. On the allowed path it creates the dung item with ItemManager.CreateByName using the shortname from the config and calls GiveItem. If the owner's inventory is full, the item is dropped at the horse's position as a fallback. The config sets the dung shortname, the amount per production, and whether the per-player toggle is respected. Players with the autodungcollector.toggle permission can use /autodung to enable or disable auto-collection for their own horses, provided RespectToggle is on.
Common use cases
Disable dung entirely on roleplay servers
Return a non-null value for every horse so no dung items litter the world. This keeps tamed animal areas clean and reduces entity count on large farms.
Reward horse owners for collecting manure
Return non-null to block the drop, then create your own item or currency payout for the owning player, letting you tune quantities with a config value.
Move dung into a nearby container
Skip the ground drop and insert the dung item into a storage container the horse is standing near, so farms can feed the output into a chest automatically.
Pitfalls
Hook fires before the item exists
The dung item is created after the hook returns, so you cannot inspect or modify it from
OnAnimalDungProduce. UseOnAnimalDungProducedinstead if you need to touch the finished item.No owner on wild or unclaimed horses
Not every ridable animal has a connected owner. Call
GetOwnerPlayer()and null-check the result before giving items or sending chat, otherwise your payout logic silently fails.High frequency on big ranches
The hook runs on a per-animal repeating timer. Avoid expensive work such as iterating all players or spawning effects inside it, and cache per-animal state in a dictionary keyed by
net.ID.Value.
Build a plugin with OnAnimalDungProduce
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 OnAnimalDungProduce
Generate