OnImpactEffectCreate
OnImpactEffectCreate is called from Effect.ImpactEffect before the server decides whether to play the material impact effect for a hit, letting a plugin suppress it by returning a non-null value.
object OnImpactEffectCreate(HitInfo info, string customEffect)Parameters
| Parameter | Type | Description |
|---|---|---|
info | HitInfo | The HitInfo describing the impact: the entity that was hit, the initiator and InitiatorPlayer, the damage type, the hit position and the hit material. Use it to identify who fired at what. |
customEffect | string | The effect prefab name the caller passed as an override for the impact effect, or null when the game would pick a default effect from the hit material. |
Return value
Returning null (or any non-null value, including false) does not suppress anything — only a non-null return cancels the call. When your hook returns a non-null object, Effect.ImpactEffect returns immediately and the original impact effect is never played.
How it works
The hook fires inside Effect.ImpactEffect, the shared entry point that plays the material-based impact effect (bullet sparks, dust puffs) when something is struck. It runs very early in the method: before the DoHitEffects and CanPlayImpactEffect checks, before the hit material is looked up with StringPool.Get(info.HitMaterial), and before the effect name is assembled.
info carries the whole hit context: HitEntity, Initiator, InitiatorPlayer (null for environmental hits), damageTypes, HitPositionWorld and IsProjectile(). That is enough to distinguish a player shooting a wall from a fall, an explosion or an NPC attack. customEffect is only non-null when the caller explicitly overrides the effect.
The hook also fires for hits where the game would have skipped the effect anyway (no hit effects enabled, the effect cannot be played, or a networking-limited player is involved), so you may be called for impacts that would never have produced a visible effect. The fire rate is high on an active combat server; keep the method cheap, avoid allocations and never log from it. Declaring a narrower type is not applicable here because info is already the concrete HitInfo type.
Example plugin: Mute impact effects on a no-decals server
using System.Collections.Generic;
using System;
using Newtonsoft.Json;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("Impact Effect Filter", "RustPluginGenerator", "1.0.0")]
[Description("Suppresses material impact effects globally or for players with a permission.")]
public class ImpactEffectFilter : RustPlugin
{
private const string PermSilent = "impacteffectfilter.silent";
private PluginConfig config;
private class PluginConfig
{
[JsonProperty("Suppress all impact effects")]
public bool SuppressAll { get; set; } = false;
[JsonProperty("Allow permission based suppression")]
public bool PermissionSuppression { get; set; } = 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 System.Collections.Generic.Dictionary<string, string>
{
["ToggleOn"] = "Impact effect suppression is now enabled for everyone.",
["ToggleOff"] = "Impact effect suppression is now disabled for everyone."
}, 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(PermSilent, this);
}
private object OnImpactEffectCreate(HitInfo info, string customEffect)
{
if (info == null) return null;
if (config.SuppressAll) return true;
if (!config.PermissionSuppression) return null;
var player = info.InitiatorPlayer;
if (player == null || player.IsNpc) return null;
if (permission.UserHasPermission(player.UserIDString, PermSilent)) return true;
return null;
}
[ChatCommand("impacteffects")]
private void CmdImpactEffects(BasePlayer player, string command, string[] args)
{
if (player == null || !player.IsAdmin) return;
config.SuppressAll = !config.SuppressAll;
SaveConfig();
SendReply(player, Msg(config.SuppressAll ? "ToggleOn" : "ToggleOff", player.UserIDString));
}
}
}The plugin keeps a permission, impacteffectfilter.silent, and, when enabled in the config, suppresses impact effects for every hit. OnImpactEffectCreate first checks that config flag and that info is not null, then reads info.InitiatorPlayer. If there is no player initiator the hook returns null and the game handles the impact normally. If there is a player, it checks the permission on that player's UserIDString: permitted players get impact effects suppressed by returning true, everyone else falls through with null. Returning true is only a signal — the game never uses the value, it just sees that the hook produced something and skips the effect. A chat command toggles the config value and saves it.
Common use cases
Reduce visual noise in large fights
Suppress material impact effects for all hits when dozens of players are shooting at once, cutting network traffic for clients on weak connections.
Per-permission effect opt-out
Give players a permission that mutes impact effects on their own hits, useful for players who find bullet sparks distracting in PvE or building-focused play.
Silence effects for specific hit types
Inspect
info.damageTypesand suppress impacts from heat, explosion or decay damage while leaving bullet impacts intact.
Pitfalls
Non-null means suppress, not allow
The hook is an inverted filter: returning null keeps the default effect, returning anything else cancels it. Returning
falsethinking it means 'allow' silently removes every impact effect.It fires for hits with no visible effect
The hook runs before the DoHitEffects and CanPlayImpactEffect checks, so you will be called for impacts the game would have skipped anyway. Do not treat every call as proof that an effect was about to play.
Very high call frequency
Every projectile, melee hit and explosion can reach this hook. Avoid string building, list allocation and logging inside it; cache permission results if you query them per hit.
Build a plugin with OnImpactEffectCreate
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 OnImpactEffectCreate
Generate