I’ve been using Rocket Guns and made two small changes that make it easier to control for server owners:
- Config-driven allowlist of 5.56 guns
- Config option to require toggling (or always-on mode)
Disclaimer: I am not proficient with C#, so I had help from ChatGPT.
Configurable allowlist of 5.56 guns (by shortname)
Instead of applying to all guns that use 5.56 ammo, the mod can now read a list of allowed gun shortnames from the config:- If the fired gun’s shortname is in the list → it shoots rockets
- If not in the list → it fires normal bullets
Config JSON
"Enabled 5.56 guns (shortnames). Empty list = all 5.56 guns": [
"rifle.ak",
"rifle.lr300"
]Code changes
New config field:
[JsonProperty("Enabled 5.56 guns (shortnames). Empty list = all 5.56 guns")]
public List<string> Enabled556Guns = new List<string>();Allowlist loader & check:private readonly HashSet<string> allowed556Guns =
new HashSet<string>(StringComparer.OrdinalIgnoreCase);
private void RefreshAllowedGuns()
{
allowed556Guns.Clear();
if (config?.Enabled556Guns == null) return;
foreach (var s in config.Enabled556Guns)
{
if (string.IsNullOrWhiteSpace(s)) continue;
allowed556Guns.Add(s.Trim());
}
}
private bool IsAllowedWeapon(BaseProjectile weapon)
{
if (weapon == null) return false;
// Empty list = original behaviour (all 5.56 guns enabled)
if (allowed556Guns.Count == 0) return true;
var shortname = weapon.GetItem()?.info?.shortname;
return !string.IsNullOrEmpty(shortname) && allowed556Guns.Contains(shortname);
}Hook gating (example):
if (IsRocketsEnabledFor(player)
&& ammo.ammoType == Rust.AmmoTypes.RIFLE_556MM
&& IsAllowedWeapon(weapon))
{
...
}
Config option: require toggle OR always-on
Adds a config boolean that controls whether players must run the toggle command:- true (default): original behavior (player must toggle on)
- false: bypass toggle requirement → rockets are always enabled for permitted players
"Require players to toggle rockets on (true) or always enabled for permitted players (false)": trueThis does not remove permissions. The mod still requires rocketguns.use — it just bypasses the toggle requirement if set to false.
Code changesNew config field:
[JsonProperty("Require players to toggle rockets on (true) or always enabled for permitted players (false)")]
public bool RequirePlayersToToggle = true;Centralized “is enabled?” check (handles permission & toggle mode):
private const string PermUse = "rocketguns.use";
private bool IsRocketsEnabledFor(BasePlayer player)
{
if (player == null) return false;
if (!permission.UserHasPermission(player.userID.ToString(), PermUse)) return false;
// Always-on mode
if (!config.RequirePlayersToToggle) return true;
// Toggle-required mode
return ActiveGUNS.Contains(player.userID);
}Toggle command behavior when always-on:if (!config.RequirePlayersToToggle)
{
SendReply(basePlayer, "Rockets are always enabled on this server.");
UpdateIcon(basePlayer);
return;
}Icon behavior
The “ammo icon” UI is now gated the same way as firing rockets:- only shows for allowed 5.56 guns
- only shows if rockets are enabled (toggle-on OR always-on mode)
The full code is below:
using Newtonsoft.Json;
using Oxide.Game.Rust.Cui;
using UnityEngine;
using System;
using System.Collections.Generic;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("Rocket Guns", "Sapnu Puas #3696", "1.2.4")]
[Description("Allow 556 guns to fire rockets based on ammo type")]
public class RocketGuns : RustPlugin
{
List<ulong> ActiveGUNS = new List<ulong>();
private HashSet<string> allowed556Guns = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
private const string PermUse = "rocketguns.use";
#region[Rocket prefabs]
public string Rocket = "assets/prefabs/ammo/rocket/rocket_basic.prefab";
public string Hv = "assets/prefabs/ammo/rocket/rocket_hv.prefab";
public string Fire = "assets/prefabs/ammo/rocket/rocket_fire.prefab";
// public string Mrls = "assets/content/vehicles/mlrs/rocket_mlrs.prefab";
#endregion[Rocket prefabs]
#region GUI
void DestroyCUI(BasePlayer player)
{
CuiHelper.DestroyUi(player, "GunUI");
}
public void CreateAmmoIcon(BasePlayer player, int ammo)
{
DestroyCUI(player);
CuiElementContainer elements = new CuiElementContainer();
string panel = elements.Add(new CuiPanel
{
Image = { Color = "0.5 0.5 0.5 0.0" },
RectTransform = { AnchorMin = config.ImageAnchorMin, AnchorMax = config.ImageAnchorMax }
}, "Hud.Menu", "GunUI");
elements.Add(new CuiElement
{
Parent = panel,
Components =
{
new CuiImageComponent { ItemId = ammo },
new CuiRectTransformComponent {AnchorMin = "0 0", AnchorMax = "1 1"}
}
});
CuiHelper.AddUi(player, elements);
}
#endregion GUI
#region[Commands]
private void ToggleRocketCMD(IPlayer player, string command, string[] args)
{
if (player.IsServer)
return;
BasePlayer basePlayer = player.Object as BasePlayer;
if(basePlayer != null)
{
if (!permission.UserHasPermission(basePlayer.userID.ToString(), PermUse))
{
SendReply(basePlayer, lang.GetMessage("NoPerm", this, basePlayer.userID.ToString()));
return;
}
// Optional: allow server owners to disable per-player toggling.
// When disabled, rockets are always enabled for players with permission.
if (config != null && !config.RequireToggle)
{
SendReply(basePlayer, lang.GetMessage("AlwaysOn", this, basePlayer.userID.ToString()));
UpdateIcon(basePlayer);
return;
}
if (ActiveGUNS.Contains(basePlayer.userID))
{
SendReply(basePlayer, lang.GetMessage("Off", this, basePlayer.userID.ToString()));
ActiveGUNS.Remove(basePlayer.userID);
DestroyCUI(basePlayer);
return;
}
else
{
SendReply(basePlayer, lang.GetMessage("On", this, basePlayer.userID.ToString()));
ActiveGUNS.Add(basePlayer.userID);
UpdateIcon(basePlayer);
return;
}
}
}
#endregion[Commands]
#region[Hooks]
#region[load/unload]
void Unload()
{
foreach (BasePlayer player in BasePlayer.activePlayerList)
{
DestroyCUI(player);
}
ActiveGUNS = null;
}
private void Init()
{
permission.RegisterPermission(PermUse, this);
AddCovalenceCommand(config.Command, nameof(ToggleRocketCMD));
RefreshAllowedGuns();
}
#endregion[load/unload]
#region[gui Hooks]
void OnPlayerDisconnected(BasePlayer player) => DestroyCUI(player);
void OnPlayerDeath(BasePlayer player, HitInfo info) => DestroyCUI(player);
object OnWeaponReload(BaseProjectile weapon, BasePlayer player)
{
if (player != null && player.userID.IsSteamId())
{
if (IsEnabledForPlayer(player))
{
timer.Once(weapon.reloadTime + 0.2f, () =>
{
UpdateIcon(player);
});
}
}
return null;
}
void OnActiveItemChanged(BasePlayer player, Item oldItem, Item newItem)
{
DestroyCUI(player);
var heldEntity = player.GetActiveItem();
if (heldEntity != null)
{
var weapon = heldEntity.GetHeldEntity() as BaseProjectile;
if (weapon != null)
{
if (!IsAllowedWeapon(weapon)) return;
if (IsEnabledForPlayer(player))
{
NextFrame(() =>
{
UpdateIcon(player);
});
}
}
}
}
void OnAmmoUnload(BaseProjectile weapon, Item item, BasePlayer player)
{
if (IsEnabledForPlayer(player))
{
NextFrame(() =>
{
UpdateIcon(player);
});
}
return;
}
#endregion[gui hooks]
void OnWeaponFired(BaseProjectile weapon, BasePlayer player, ItemModProjectile ammo, ProtoBuf.ProjectileShoot projectiles)
{
if (player == null) return;
if (IsEnabledForPlayer(player) && ammo.ammoType == Rust.AmmoTypes.RIFLE_556MM && IsAllowedWeapon(weapon))
{
string rocket = string.Empty;
switch (ammo.name)
{
case "ammo_rifle.item":
rocket = RocketToFire(config.Normal);
break;
case "ammo_rifle_hv.item":
rocket = RocketToFire(config.Hv);
break;
case "ammo_rifle_fire.item":
rocket = RocketToFire(config.Fire);
break;
case "ammo_rifle_explosive.item":
rocket = RocketToFire(config.Explo);
break;
default:
break;
}
if (string.IsNullOrEmpty(rocket))
{
return;
}
FireRockets(player, rocket);
}
else return;
}
#endregion[Hooks]
#region[Methods]
private bool HasUsePermission(BasePlayer player)
{
if (player == null) return false;
return permission.UserHasPermission(player.userID.ToString(), PermUse);
}
private bool IsEnabledForPlayer(BasePlayer player)
{
if (!HasUsePermission(player)) return false;
// If toggling is disabled in config, rockets are always enabled for permitted players.
if (config != null && !config.RequireToggle) return true;
return ActiveGUNS.Contains(player.userID);
}
private void RefreshAllowedGuns()
{
allowed556Guns.Clear();
if (config?.Enabled556Guns == null) return;
foreach (var s in config.Enabled556Guns)
{
if (string.IsNullOrWhiteSpace(s)) continue;
allowed556Guns.Add(s.Trim());
}
}
private bool IsAllowedWeapon(BaseProjectile weapon)
{
if (weapon == null) return false;
// Empty list = keep original behaviour (all 5.56 guns are enabled)
if (allowed556Guns == null || allowed556Guns.Count == 0) return true;
var item = weapon.GetItem();
var shortname = item?.info?.shortname;
if (string.IsNullOrEmpty(shortname)) return false;
return allowed556Guns.Contains(shortname);
}
public string RocketToFire(int id)
{
switch (id)
{
case 1:
return Rocket;
case 2:
return Hv;
case 3:
return Fire;
default:
return string.Empty;
}
}
public int RocketIcon(int id)
{
switch (id)
{
case 1:
return -742865266;
case 2:
return -1841918730;
case 3:
return 1638322904;
default:
return 0;
}
}
public void UpdateIcon(BasePlayer player)
{
DestroyCUI(player);
var heldEntity = player.GetActiveItem();
if (heldEntity != null)
{
var weapon = heldEntity.GetHeldEntity() as BaseProjectile;
if (weapon != null)
{
if (!IsAllowedWeapon(weapon)) return;
var ammodef = weapon.primaryMagazine.ammoType;
ItemDefinition itemDefinition = ItemManager.FindItemDefinition(ammodef.itemid);
ItemModProjectile ammo = itemDefinition.GetComponent<ItemModProjectile>();
if (ammo.ammoType == Rust.AmmoTypes.RIFLE_556MM)
{
int rocketicon = 0;
var ammount = weapon.primaryMagazine.contents;
if (ammount < 1) return;
var ammotype = weapon.primaryMagazine.ammoType;
switch (ammo.name)
{
case "ammo_rifle.item":
rocketicon = RocketIcon(config.Normal);
break;
case "ammo_rifle_hv.item":
rocketicon = RocketIcon(config.Hv);
break;
case "ammo_rifle_fire.item":
rocketicon = RocketIcon(config.Fire);
break;
case "ammo_rifle_explosive.item":
rocketicon = RocketIcon(config.Explo);
break;
default:
break;
}
if (rocketicon == 0)
{
rocketicon = ammotype.itemid;
}
CreateAmmoIcon(player, rocketicon);
}
}
}
}
public void FireRockets(BasePlayer player, string rocketPrefab)
{
if (player == null) return;
var rocket = GameManager.server.CreateEntity(rocketPrefab, player.eyes.position, new Quaternion());
if (rocket != null)
{
if(rocketPrefab != null)
{
float speed = 0;
switch (rocketPrefab)
{
case "assets/prefabs/ammo/rocket/rocket_basic.prefab":
speed = config.NormalSpeed;
break;
case "assets/prefabs/ammo/rocket/rocket_hv.prefab":
speed = config.HvSpeed;
break;
case "assets/prefabs/ammo/rocket/rocket_fire.prefab":
speed = config.FireSpeed;
break;
default:
break;
}
rocket.creatorEntity = player;
rocket.SendMessage("InitializeVelocity", player.eyes.HeadForward() * speed);
rocket.OwnerID = player.userID;
rocket.Spawn();
rocket.ClientRPC(null, "RPCFire");
Interface.CallHook("OnRocketLaunched", player,rocket);
}
}
}
#endregion[Methods]
#region Config
public Configuration config;
public class Configuration
{
[JsonProperty("Toggle command")]
public string Command = "togglegun";
[JsonProperty("Require players to toggle rockets on (true) or always enabled for permitted players (false)")]
public bool RequireToggle = true;
[JsonProperty("1 = normal rocket, 2 = hv rocket , 3 = incendiary rocket , 0 = none")]
public int notused = 0;
[JsonProperty("rocket type to fire when using normall 5.56")]
public int Normal = 1;
[JsonProperty("rocket type to fire when using hv 5.56")]
public int Hv = 2;
[JsonProperty("rocket type to fire when using Incendiary 5.56")]
public int Fire = 3;
[JsonProperty("rocket type to fire when using explosive 5.56")]
public int Explo = 0;
[JsonProperty("Enabled 5.56 guns (shortnames). Empty list = all 5.56 guns")]
public List<string> Enabled556Guns = new List<string>();
//[JsonProperty("Allow Incendiary rockets (may cause server lag if too many fired)")]
// public bool UseFire = false;
[JsonProperty("Hv rocket speed ")]
public float HvSpeed = 200;
[JsonProperty("Normal rocket speed")]
public float NormalSpeed = 100;
[JsonProperty("Incendiary rocket speed")]
public float FireSpeed = 100;
[JsonProperty("Image AnchorMin")]
public string ImageAnchorMin = "0.645 0.023";
[JsonProperty("Image AnchorMax")]
public string ImageAnchorMax = "0.688 0.095";
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
config = Config.ReadObject<Configuration>();
if (config == null) LoadDefaultConfig();
SaveConfig();
RefreshAllowedGuns();
}
catch (Exception e)
{
Debug.LogException(e);
PrintWarning("Creating new config file.");
LoadDefaultConfig();
}
}
protected override void LoadDefaultConfig() => config = new Configuration();
protected override void SaveConfig() => Config.WriteObject(config);
#endregion
#region[Localization]
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
["NoPerm"] = "You dont have permission to use this command",
["Off"] = "Raid gun disengaged",
["On"] = "Raid gun engaged",
["AlwaysOn"] = "Rockets are always enabled on this server."
}, this);
}
#endregion[Localization]
}
}