OnWorldProjectileCreate
OnWorldProjectileCreate is called from BasePlayer.CreateWorldProjectile right before Rust spawns a visible projectile entity for a player, such as an arrow, rocket or thrown item.
object OnWorldProjectileCreate(HitInfo info, Item item)Parameters
| Parameter | Type | Description |
|---|---|---|
info | HitInfo | HitInfo describing the projectile about to be spawned: its position, ProjectileVelocity, weapon entity, projectile prefab and hit state. Use it to identify the weapon and where the shot originated. |
item | Item | The Item that represents the projectile in the world (for example the rocket or arrow item). It may be a recycled existing item or a newly created one; check item.info for its shortname. |
Return value
Return null (or nothing) to let Rust spawn the projectile normally. Any non-null value stops the original method immediately, so the projectile entity is never created — the weapon still plays, but nothing is launched into the world.
How it works
The hook fires inside BasePlayer.CreateWorldProjectile, after the game has resolved the projectile's velocity and built the Item that backs it in the world, but before the projectile entity itself is created. Typical triggers are a player firing a bow or crossbow, launching a rocket or grenade launcher round, or any weapon that produces a world projectile rather than a hitscan bullet. info carries the shot context: ProjectileVelocity, Weapon, WeaponPrefab and the position fields, which is enough to tell a rocket from a flame round from an arrow via the item's shortname in item.info. The item is useful if you want to inspect skin, amount or definition before the projectile exists. A non-null return from the hook halts the rest of the method, so no projectile entity is spawned and no shot appears. The hook only applies to projectiles the player creates; server-side explosions made by other code do not pass through it.
Example plugin: Cancel and charge for rockets at night
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Rocket Night Block", "RustPluginGenerator", "1.0.0")]
[Description("Prevents selected projectiles from spawning during a configurable time window")]
public class RocketNightBlock : RustPlugin
{
private const string PermBypass = "rocketnightblock.bypass";
private PluginConfig config;
private class PluginConfig
{
[JsonProperty("Blocked projectile shortnames")]
public List<string> BlockedShortnames = new List<string> { "ammo.rocket.basic", "ammo.rocket.hv" };
[JsonProperty("Block start hour (0-24)")]
public float BlockStartHour = 22f;
[JsonProperty("Block end hour (0-24)")]
public float BlockEndHour = 6f;
[JsonProperty("Message cooldown seconds")]
public float MessageCooldown = 5f;
}
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"] = "Explosive projectiles are disabled between {0}:00 and {1}:00."
}, 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 object OnWorldProjectileCreate(HitInfo info, Item item)
{
if (info == null || item?.info == null) return null;
if (!config.BlockedShortnames.Contains(item.info.shortname)) return null;
var player = info.InitiatorPlayer;
if (player == null || player.IsNpc) return null;
if (permission.UserHasPermission(player.UserIDString, PermBypass)) return null;
if (!IsBlockedHour()) return null;
player.ChatMessage(Msg("Blocked", player.UserIDString, config.BlockStartHour, config.BlockEndHour));
return true;
}
private bool IsBlockedHour()
{
var sky = TOD_Sky.Instance;
if (sky == null) return false;
float hour = sky.Cycle.Hour;
float start = config.BlockStartHour;
float end = config.BlockEndHour;
if (start <= end) return hour >= start && hour < end;
return hour >= start || hour < end;
}
}
}The plugin blocks launches of specific projectile shortnames (rockets by default) during a configurable in-game hour window. OnWorldProjectileCreate looks up the shooter from info.InitiatorPlayer, reads the projectile shortname from item.info.shortname, and checks the configured block list against the current in-game time from TOD_Sky.Instance.Cycle.Hour. When a blocked projectile is a match, the owner gets a localized chat warning and the hook returns a non-null value, which prevents the rocket entity from spawning. Admins with the permission bypass the check. Config exposes the hour window and the shortname list, and messages come from the language file.
Common use cases
Night-time explosive restrictions
Block rocket or grenade launches during a raiding-free window and warn the shooter, keeping the rest of the weapon handling untouched.
Projectile cost or cooldown system
Since the backing Item is passed in, deduct a currency or consume inventory items when the projectile is created, then cancel the shot if the player cannot pay.
Weapon-specific event triggers
Detect specific projectile shortnames to broadcast alerts, fire arena events or record shot telemetry without touching the weapon's actual firing pipeline.
Pitfalls
Item may be a recycled instance
The item is sometimes reused from an existing recycled item rather than freshly created, so never rely on it being unique or connected to the player's inventory in any particular way.
Cancelling skips the projectile, not the input
Returning a value stops the entity spawn but the player's trigger pull has already been processed; you may want to send a message so the shooter knows why nothing came out.
Scope to player-created projectiles
The hook lives in the player path, but always use
info.InitiatorPlayerand null-check it; NPCs or turrets can end up here with no player to message or charge.
Build a plugin with OnWorldProjectileCreate
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 OnWorldProjectileCreate
Generate