Possible fix
using System;
using Newtonsoft.Json;
using Oxide.Core.Libraries.Covalence;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using WebSocketSharp;

/*
 * This update 1.2.3
 * Max Durability permission fixes
 * other fixes/edits
 *
 * This update 1.3.0
 * Added More Permissions
 * Added More Config Options 
 *
 * This update 1.4.0
 * Partial Re-write
 * Patched New Commands
 * Added infinity ammo no reload required
 * Added Weapon Names
 * Added Drop Weapon on Death toggle/feature
 *
 * this update 1.4.1
 * Fixed admin permission ops
 * fixed inifinity issues
 * fixed Drop Weapon on Death toggle/feature
 *
 * This update 1.4.2
 * Added Skin Id Support on item crafted
 * Added Ammo Type Support on item crafted
 * Added Preloaded Magazine Size support on item crafted
 * Updated Lang file correctly now
 * Fixed command weapon name renaming issue
 * More in the works.
 *
 * This update 1.4.3
 * Patched AmmoType bug when Infinity ammo was set true.
 *
 * This update 1.4.4
 * Corrected return behaviour for CanDropActiveItem
 * Resolves possible plugin conflicts.
 * Fixed Clip size not working per permission set.
 *
 * This update 1.4.5
 * Fixes RPC error when infinity ammo was enabled.
 *
 * This update 1.4.6
 * Added OnRocketLaunched hook to fix multiple rocket launcher not working correctly.
 *
 * This update 1.4.7
 * Fixed Weapon recoil breaking from increasing Max Meg Sizes
 * Replaced NPC Murderer Code check ( FacePunch removed from game completely ) with ScarecrowNPC check.
 *
 * This update 1.4.8
 * Fixed weapon drop toggle.
 *
 * This update 1.4.9
 * Patched Eoka Pistol erroring on weapon reload.
 *
 * This update 1.5.0
 * Updated Oxide hook change is now OnWeaponReload(BasePlayer player, BaseProjectile projectile)
 * Added support for Extended Magazine sizes.
 *
 * This update 1.5.1
 * Fixed Extendo Mag support
 * Made more performant
 *
 * This update 1.5.2
 * Fixed perms failing to register sometimes?
 * Made performance improvements to OnLoseCondition
 *
 * this update 1.5.5
 * Resolved mag issues.
 *
 * This update 1.5.6
 * Patched, will sort out performance optimizations later..
 *
 * This update 1.5.8
 * Fixed Infinity ammo / Condition bug
 * Performance Optmizations
 *
 * This update 1.5.9
 * corrected foreach loop on perm granting/revoking
 *
 * Removed Redundant code From OnPlayerConnect.
*/

namespace Oxide.Plugins
{
    [Info("Firearm Modifier", "Khan", "1.6.0")]
    [Description("Allows you to change Magazine Size + Weapon Condition levels")]
    public class FirearmModifier : CovalencePlugin
    {
        #region Fields

        private string Admin = "firearmmodifier.admin";

        private PluginConfig _config;
        private static FirearmModifier _instance;

        private List<string> Exclude = new List<string>
        {
            "bow.hunting",
            "bow.compound",
            "crossbow",
            "pistol.eoka"
        };

        private class Infinity
        {
            public int MagSize;
            public ItemDefinition AmmoType;
        }

        // Needed for infinity rocket - related projectile weapons ( grenade launcher etc )
        private Hash<int, Dictionary<string, Infinity>> _rocket = new Hash<int, Dictionary<string, Infinity>>();

        // Needed for reloading weapons
        private Hash<int, Dictionary<string, Infinity>> _reloads = new Hash<int, Dictionary<string, Infinity>>();

        // Infinity Ammo for enabled weapons with permission
        private Hash<int, Dictionary<string, Infinity>> _ammo = new Hash<int, Dictionary<string, Infinity>>();

        // Infinity Condition for enabled weapons with permission
        private Hash<int, List<string>> _condition = new Hash<int, List<string>>();

        // Drop on death cache stores the weapon as the itemID & a list of perms that have it enabled only.
        private Hash<int, List<string>> _drop = new Hash<int, List<string>>();

        // Active player cache stores ther ulong id & the highest perm they have. ( which would be the first one in the list if you grant them it 5 is lowest 1 is highest)
        private Hash<ulong, string> _players = new Hash<ulong, string>();

        // set perm cache this is only used to speed up permission granting/revoking caching.
        private HashSet<string> _perm = new HashSet<string>();

        #endregion

        #region Config

        protected override void LoadDefaultConfig() => _config = new PluginConfig();

        protected override void LoadConfig()
        {
            base.LoadConfig();

            try
            {
                _config = Config.ReadObject<PluginConfig>();

                if (_config == null)
                {
                    throw new JsonException();
                }

                if (!_config.ToDictionary().Keys.SequenceEqual(Config.ToDictionary(x => x.Key, x => x.Value).Keys))
                {
                    PrintWarning($"Configuration file {Name}.json was Updated");
                    SaveConfig();
                }
            }
            catch
            {
                PrintError("Configuration file is corrupt! Loading Default Config");
                PrintError("Your Configuration file is corrupt! Please verify your config file at https://jsonlint.com/");
                LoadDefaultConfig();
            }
        }

        protected override void SaveConfig() => Config.WriteObject(_config, true);

        private class PluginConfig
        {
            [JsonProperty("Weapon Options")]
            public Dictionary<string, WeaponConfig> WeaponOptions = new Dictionary<string, WeaponConfig>();

            public string ToJson() => 
                JsonConvert.SerializeObject(this);

            public Dictionary<string, object> ToDictionary() =>
                JsonConvert.DeserializeObject<Dictionary<string, object>>(ToJson());
        }

        private class WeaponConfig
        {
            public Dictionary<string, PermissionSetting> PermissionSettings = new Dictionary<string, PermissionSetting>();

            [JsonIgnore]
            public string[] Permissions => PermissionSettings.Keys.ToArray();

            public PermissionSetting FindPermissionSetting(string permission)
            {
                PermissionSetting permissionSetting;
                return PermissionSettings.TryGetValue(permission, out permissionSetting) ? permissionSetting : null;
            }
        }

        public class PermissionSetting
        {
            public ulong SkinId;
            public int MagazineSize;
            public int PreloadSize;
            public float Condition;
            public bool InfiniteCondition;
            public bool InfiniteAmmo;
            public bool DropOnDeath;
            public string WeaponName = "";
            public string AmmoType = "";
            public int ItemID;

            public void SetSkinId(IPlayer player, string displayName, string value)
            {
                ulong id;
                if (!ulong.TryParse(value, out id))
                {
                    player.Message(GetMessage("Syntax", player.Id));
                    return;
                }

                SkinId = id;
                player.Reply(GetMessage("Success", player.Id, displayName, "skin", SkinId));
            }

            public void SetMagazineSize(IPlayer player, string displayName, string value)
            {
                int size;
                if (!int.TryParse(value, out size))
                {
                    player.Message(GetMessage("Syntax", player.Id));
                    return;
                }

                MagazineSize = size;
                player.Reply(GetMessage("Success", player.Id, displayName, "magazinesize", MagazineSize));
            }
            
            public void SetPreloadSize(IPlayer player, string displayName, string value)
            {
                int size;
                if (!int.TryParse(value, out size))
                {
                    player.Message(GetMessage("Syntax", player.Id));
                    return;
                }

                PreloadSize = size;
                player.Reply(GetMessage("Success", player.Id, displayName, "preloadsize", PreloadSize));
            }

            public void SetCondition(IPlayer player, string displayName, string value)
            {
                float size;
                if (!float.TryParse(value, out size))
                {
                    player.Message(GetMessage("Syntax", player.Id));
                    return;
                }

                Condition = size;
                player.Reply(GetMessage("Success", player.Id, displayName, "condition", Condition));
            }

            public void SetMax(IPlayer player, string displayName, string value)
            {
                bool boolean;
                if (!bool.TryParse(value, out boolean))
                {
                    player.Message(GetMessage("Syntax", player.Id));
                    return;
                }

                InfiniteCondition = boolean;
                player.Reply(GetMessage("Success", player.Id, displayName, "max", InfiniteCondition));
            }
            
            public void SetMaxAmmo(IPlayer player, string displayName, string value)
            {
                bool boolean;
                if (!bool.TryParse(value, out boolean))
                {
                    player.Message(GetMessage("Syntax", player.Id));
                    return;
                }

                InfiniteAmmo = boolean;
                player.Reply(GetMessage("Success", player.Id, displayName, "maxammo", InfiniteAmmo));
            }
            
            public void SetDropOnDeath(IPlayer player, string displayName, string value)
            {
                bool boolean;
                if (!bool.TryParse(value, out boolean))
                {
                    player.Message(GetMessage("Syntax", player.Id));
                    return;
                }

                DropOnDeath = boolean;
                player.Reply(GetMessage("Success", player.Id, displayName, "drop", DropOnDeath));
            }
            
            public void SetWeaponName(IPlayer player, string displayName, string value)
            {
                if (string.IsNullOrEmpty(value))
                {
                    player.Message(GetMessage("Syntax", player.Id));
                    return;
                }

                WeaponName = value;
                player.Reply(GetMessage("Success", player.Id, displayName, "name", WeaponName));
            }
            
            public void SetAmmoType(IPlayer player, string displayName, string value)
            {
                if (string.IsNullOrEmpty(value))
                {
                    player.Message(GetMessage("Syntax", player.Id));
                    return;
                }

                AmmoType = value;
                player.Reply(GetMessage("Success", player.Id, displayName, "ammotype", AmmoType));
            }
        }

        #endregion

        #region Oxide

        private void Init()
        {
            permission.RegisterPermission(Admin, this);
        }

        private void Loaded()
        {
            _instance = this;
        }

        private void OnServerInitialized()
        {
            StringBuilder sb = new StringBuilder();
            int fix = 0;
            bool drop = false;
            bool infinitycondition = false;
            bool infinityammo = false;
            foreach (var itemDefinition in ItemManager.itemList)
            {
                ItemModEntity itemModEntity = itemDefinition.GetComponent<ItemModEntity>();
                if (itemModEntity == null) continue;

                BaseProjectile baseProjectile = itemModEntity.entityPrefab?.Get()?.GetComponent<BaseProjectile>();
                if (baseProjectile == null) continue;

                if (!Exclude.Contains(itemDefinition.shortname) && _config.WeaponOptions.ContainsKey(itemDefinition.shortname))
                {
                    foreach (var p in _config.WeaponOptions[itemDefinition.shortname].PermissionSettings)
                    {
                        if (p.Value.ItemID == 0)
                            p.Value.ItemID = itemDefinition.itemid;

                        if (!_perm.Contains(p.Key))
                            _perm.Add(p.Key);

                        var ammoType = string.IsNullOrEmpty(p.Value.AmmoType) ? null : ItemManager.FindItemDefinition(p.Value.AmmoType) ?? null;

                        if (!_reloads.ContainsKey(itemDefinition.itemid))
                        {
                            Dictionary<string, Infinity> value = new Dictionary<string, Infinity>();
                            value.Add(p.Key, new Infinity
                            {
                                MagSize = p.Value.MagazineSize, 
                                AmmoType = ammoType
                            });

                            _reloads.Add(itemDefinition.itemid, value);
                        }
                        else if (!_reloads[itemDefinition.itemid].ContainsKey(p.Key))
                            _reloads[itemDefinition.itemid].Add(p.Key, new Infinity
                            {
                                MagSize = p.Value.MagazineSize,
                                AmmoType = ammoType
                            });

                        if (p.Value.InfiniteAmmo)
                        {
                            if (!_ammo.ContainsKey(itemDefinition.itemid))
                            {
                                Dictionary<string, Infinity> value = new Dictionary<string, Infinity>();
                                value.Add(p.Key, new Infinity
                                {
                                    MagSize = p.Value.MagazineSize, 
                                    AmmoType = ammoType
                                });

                                _ammo.Add(itemDefinition.itemid, value);
                            }
                            else if (!_ammo[itemDefinition.itemid].ContainsKey(p.Key))
                                _ammo[itemDefinition.itemid].Add(p.Key, new Infinity
                                {
                                    MagSize = p.Value.MagazineSize,
                                    AmmoType = ammoType
                                });

                            infinityammo = true;
                        }

                        if (p.Value.InfiniteCondition)
                        {
                            if (!_condition.ContainsKey(itemDefinition.itemid))
                                _condition.Add(itemDefinition.itemid, new List<string> { p.Key });
                            else if (!_condition[itemDefinition.itemid].Contains(p.Key))
                                _condition[itemDefinition.itemid].Add(p.Key);

                            infinitycondition = true;
                        }

                        if (!p.Value.AmmoType.IsNullOrEmpty())
                        {
                            var ammo = ItemManager.FindItemDefinition(p.Value.AmmoType);
                            if (ammo == null)
                            {
                                sb.Append($"weapon {itemDefinition.shortname}, {p.Key} AmmoType is invalid! > {p.Value.AmmoType} \n");
                                fix++;
                            }
                        }

                        if (p.Value.DropOnDeath)
                        {
                            if (!_drop.ContainsKey(itemDefinition.itemid))
                                _drop.Add(itemDefinition.itemid, new List<string> { p.Key });
                            else if (!_drop[itemDefinition.itemid].Contains(p.Key))
                                _drop[itemDefinition.itemid].Add(p.Key);

                            drop = true;
                        }
                    }
                }

                if (Exclude.Contains(itemDefinition.shortname) || _config.WeaponOptions.ContainsKey(itemDefinition.shortname)) continue;

                _config.WeaponOptions.Add(itemDefinition.shortname, new WeaponConfig
                {
                    PermissionSettings = new Dictionary<string, PermissionSetting>
                    {
                        {
                            "firearmmodifier.1", 
                            new PermissionSetting
                            {
                                MagazineSize = baseProjectile.primaryMagazine.definition.builtInSize,
                                PreloadSize = baseProjectile.primaryMagazine.contents,
                                Condition = itemDefinition.condition.max,
                                InfiniteCondition = false,
                                InfiniteAmmo = false,
                                DropOnDeath = false,
                                WeaponName = "",
                                AmmoType = "",
                                SkinId = 0,
                                ItemID = itemDefinition.itemid
                            } 
                        },
                        {
                            "firearmmodifier.2", 
                            new PermissionSetting
                            {
                                MagazineSize = baseProjectile.primaryMagazine.definition.builtInSize,
                                PreloadSize = baseProjectile.primaryMagazine.contents,
                                Condition = itemDefinition.condition.max,
                                InfiniteCondition = false,
                                InfiniteAmmo = false,
                                DropOnDeath = false,
                                WeaponName = "",
                                AmmoType = "",
                                SkinId = 0,
                                ItemID = itemDefinition.itemid
                            }
                        },
                        {
                            "firearmmodifier.3", 
                            new PermissionSetting
                            {
                                MagazineSize = baseProjectile.primaryMagazine.definition.builtInSize,
                                PreloadSize = baseProjectile.primaryMagazine.contents,
                                Condition = itemDefinition.condition.max,
                                InfiniteCondition = false,
                                InfiniteAmmo = false,
                                DropOnDeath = false,
                                WeaponName = "",
                                AmmoType = "",
                                SkinId = 0,
                                ItemID = itemDefinition.itemid
                            } 
                        },
                        { 
                            "firearmmodifier.4", 
                            new PermissionSetting
                            {
                                MagazineSize = baseProjectile.primaryMagazine.definition.builtInSize,
                                PreloadSize = baseProjectile.primaryMagazine.contents,
                                Condition = itemDefinition.condition.max,
                                InfiniteCondition = false,
                                InfiniteAmmo = false,
                                DropOnDeath = false,
                                WeaponName = "",
                                AmmoType = "",
                                SkinId = 0,
                                ItemID = itemDefinition.itemid
                            } 
                        },
                        { 
                            "firearmmodifier.5", 
                            new PermissionSetting
                            {
                                MagazineSize = baseProjectile.primaryMagazine.definition.builtInSize,
                                PreloadSize = baseProjectile.primaryMagazine.contents,
                                Condition = itemDefinition.condition.max,
                                InfiniteCondition = false,
                                InfiniteAmmo = false,
                                DropOnDeath = false,
                                WeaponName = "",
                                AmmoType = "",
                                SkinId = 0,
                                ItemID = itemDefinition.itemid
                            } 
                        }
                    }
                });
            }

            SaveConfig();

            if (fix > 0)
            {
                PrintError($"{sb}".ToSentence());
                PrintError($"Config requires {fix} repairs before plugin will be usable");
                server.Command("o.unload FirearmModifier");
            }

            if (!drop)
            {
                Puts("Unsubscribed from CanDropActiveItem to save performance since it's not in use");
                Unsubscribe(nameof(CanDropActiveItem));
            }

            if (!infinitycondition)
            {
                Puts("Unsubscribed from OnLoseCondition to save performance since it's not in use");
                Unsubscribe(nameof(OnLoseCondition));
            }

            if (!infinityammo)
            {
                Puts("Unsubscribed from OnWeaponFired to save performance since it's not in use");
                Unsubscribe(nameof(OnWeaponFired));
            }

            foreach (var items in _config.WeaponOptions.Select(x => x.Value.PermissionSettings.Keys).ToList())
            {
                foreach (var item in items)
                {
                    if (permission.PermissionExists(item, this)) continue; 

                    permission.RegisterPermission(item, this);
                }
            }

            foreach (var p in covalence.Players.Connected)
            {
                if (!p.Id.IsSteamId()) continue;
                foreach (var perm in _perm)
                    if (permission.UserHasPermission(p.Id, perm))
                    {
                        var user = (p.Object as BasePlayer).userID;
                        _players[user] = perm;
                        break;
                    }
            }
        }

        private void Unload()
        {
            _perm.Clear();
            _players.Clear();
            _drop.Clear();
            _condition.Clear();
            _ammo.Clear();
            _reloads.Clear();
            _instance = null;
        }

        #endregion

        #region Core

        private WeaponConfig FindWeaponOption(string shortname)
        {
            WeaponConfig weaponConfig;
            return _config.WeaponOptions.TryGetValue(shortname, out weaponConfig) ? weaponConfig : null;
        }

        //OnMagazineReload(BaseProjectile weapon, int desiredAmount, BasePlayer player)
        //OnAmmoSwitch(BaseProjectile weapon, BasePlayer player)

        private void OnWeaponReload(BaseProjectile projectile, BasePlayer player)
        {
            Item item = projectile.GetItem();
            if (item == null || player == null || !player.userID.IsSteamId()) return;
            var i = item.info.itemid;
            if (!_reloads.ContainsKey(i) || !_players.ContainsKey(player.userID)) return;
            if (!_reloads[i].ContainsKey(_players[player.userID])) return;

            var mag = _reloads[i][_players[player.userID]].MagSize;
            if (mag == 0)
                mag = projectile.primaryMagazine.definition.builtInSize;

            bool adjust = projectile.primaryMagazine.definition.builtInSize != projectile.primaryMagazine.capacity;
            if (adjust)
            {
                int num = Mathf.CeilToInt(ProjectileWeaponMod.Mult(projectile, (x => x.magazineCapacity), (y => y.scalar), 1f) * mag);
                mag = num;
            }

            projectile.primaryMagazine.capacity = mag;

            if (_reloads[i][_players[player.userID]].AmmoType != null)
                projectile.primaryMagazine.ammoType = _reloads[i][_players[player.userID]].AmmoType;

            projectile.SendNetworkUpdateImmediate();
        }

        private void OnItemCraftFinished(ItemCraftTask task, Item item, ItemCrafter itemCrafter)
        {
            BaseProjectile projectile = item?.GetHeldEntity() as BaseProjectile;
            if (projectile == null) return;

            var player = itemCrafter.owner.userID;
            if (!_players.ContainsKey(player)) return;

            WeaponConfig weaponOptions = FindWeaponOption(item.info.shortname);
            if (weaponOptions == null) return;

            var perm = _players[player];
            item._maxCondition = weaponOptions.PermissionSettings[perm].Condition;
            item.condition = weaponOptions.PermissionSettings[perm].Condition;
            projectile.primaryMagazine.contents = weaponOptions.PermissionSettings[perm].PreloadSize;
            if (!weaponOptions.PermissionSettings[perm].AmmoType.IsNullOrEmpty())
            {
                var ammo = ItemManager.FindItemDefinition(weaponOptions.PermissionSettings[perm].AmmoType);
                projectile.primaryMagazine.ammoType = ammo;
            }
            item.skin = weaponOptions.PermissionSettings[perm].SkinId;
            if (!weaponOptions.PermissionSettings[perm].WeaponName.IsNullOrEmpty())
            {
                item.name = weaponOptions.PermissionSettings[perm].WeaponName;
                item.MarkDirty();
            }
            projectile.SendNetworkUpdateImmediate();
        }

        // Used for infinity weapon conditions ( Never Breaks )
        private void OnLoseCondition(Item item)
        {
            BasePlayer player = item.GetOwnerPlayer();
            if (player == null || !player.userID.IsSteamId()) return;
            var i = item.info.itemid;
            if (!_condition.ContainsKey(i) || !_players.ContainsKey(player.userID)) return;
            if (_condition[i].Contains(_players[player.userID]))
                item.condition = item.info.condition.max;
        }

        private void OnRocketLaunched(BasePlayer player, BaseEntity entity)
        {
            if (!_players.ContainsKey(player.userID)) return;

            BaseEntity weapon = player.GetHeldEntity();
             if (weapon == null) return;

             Item item = weapon.GetItem();
             if (item == null) return;

             WeaponConfig weaponOptions = FindWeaponOption(item.info.shortname);
              if (weaponOptions == null) return;

              BaseProjectile projectile = weapon as BaseProjectile;
              if (projectile == null) return;

              var perm = _players[player.userID];
              if (weaponOptions.PermissionSettings[perm].InfiniteAmmo == false) return;
              if (!weaponOptions.PermissionSettings[perm].AmmoType.IsNullOrEmpty())
              {
                  var ammo = ItemManager.FindItemDefinition(weaponOptions.PermissionSettings[perm].AmmoType);
                  if (ammo != null)
                      projectile.primaryMagazine.ammoType = ammo;
              }
              if (projectile.primaryMagazine.contents > 0) return;
              projectile.primaryMagazine.contents = weaponOptions.PermissionSettings[perm].MagazineSize;
              projectile.SendNetworkUpdateImmediate();
        }

        // Needed for infinity weapon ammo crap.
        private void OnWeaponFired(BaseProjectile projectile, BasePlayer player)
        {
            if (projectile.primaryMagazine.contents > 0) return;
            Item item = projectile.GetItem();
            if (item == null || player == null || !player.userID.IsSteamId()) return;
            var i = item.info.itemid;
            if (!_ammo.ContainsKey(i) || !_players.ContainsKey(player.userID)) return;
            if (!_ammo[i].ContainsKey(_players[player.userID])) return;

            projectile.primaryMagazine.contents = _reloads[i][_players[player.userID]].MagSize;

            if (_ammo[i][_players[player.userID]].AmmoType != null)
                projectile.primaryMagazine.ammoType = _ammo[i][_players[player.userID]].AmmoType;

            projectile.SendNetworkUpdateImmediate();
        }

        // I used to support renaming any weapon you pick up but i have disabled this feature due to performance reasons.. ( is now crafting only feature )
        /*private void OnItemAddedToContainer(ItemContainer container, Item item)
        {
            BasePlayer player = item.GetOwnerPlayer();
            if (player == null || player.IsNpc) return;
            
            WeaponConfig weaponOptions = FindWeaponOption(item.info.shortname);
            if (weaponOptions == null) return;
            
            foreach (var perm in weaponOptions.Permissions)
            {
                if (!permission.UserHasPermission(player.UserIDString, perm)) continue;
                if (weaponOptions.PermissionSettings[perm].WeaponName.IsNullOrEmpty()) continue;
                item.name = weaponOptions.PermissionSettings[perm].WeaponName;
                item.MarkDirty();
                break;
            }
        }*/
        private object CanDropActiveItem(BasePlayer player)
        {
            Item item = player.GetActiveItem();
            if (item == null || player == null || !player.userID.IsSteamId()) return null;
            var i = item.info.itemid;
            if (!_drop.ContainsKey(i) || !_players.ContainsKey(player.userID)) return null;
            if (_drop[i].Contains(_players[player.userID])) return false;
            return null;
        }

        #endregion

        #region Permission Tracker

        private void OnPlayerConnected(BasePlayer player)
        {
            foreach (var perm in _perm)
                if (permission.UserHasPermission(player.UserIDString, perm))
                {
                    _players[player.userID] = perm;
                    break;
                }
        }

        private void OnPlayerDisconnected(BasePlayer player, string reason) => _players.Remove(player.userID);

        private void OnPlayerKicked(BasePlayer player, string reason) => _players.Remove(player.userID);

        private void OnGroupPermissionGranted(string name, string perm) => UpdateGroup(name, perm);

        private void OnGroupPermissionRevoked(string name, string perm) => UpdateGroup(name, perm);

        private void OnUserPermissionGranted(string id, string permName) => UpdatePerms(id, permName);

        private void OnUserPermissionRevoked(string id, string permName) => UpdatePerms(id, permName);

        private void UpdateGroup(string name, string perm)
        {
            if (!_perm.Contains(perm)) return;
            foreach (BasePlayer player in BasePlayer.activePlayerList.Where(p => permission.UserHasGroup(p.UserIDString, name)))
                UpdatePerms(player.UserIDString, name);
        }
        private void UpdatePerms(string id, string perm)
        {
            if (!_perm.Contains(perm)) return;
            var dingus = Convert.ToUInt64(id);
            _players.Remove(dingus);
            foreach (var p in _perm)
            {
                if (!permission.UserHasPermission(id, p)) continue;
                _players[dingus] = p;
                break;
            }
        }

        #endregion

        #region Commands

        [Command("modify")]
        private void Cmdmodify(IPlayer player, string command, string[] args)
        {
            if (!player.HasPermission("firearmmodifier.admin"))
            {
                player.Message(GetMessage("NoPerm", player.Id));
                return;
            }

            if (args.Length < 3)
            {
                player.Reply(GetMessage("Syntax", player.Id));
                return;
            }

            WeaponConfig weaponoption = FindWeaponOption(args[0].ToLower());
            if (weaponoption == null)
            {
                player.Reply(GetMessage("InvalidSelection", player.Id));
                return;
            }

            ItemDefinition itemDefinition = ItemManager.FindItemDefinition(args[0]);
            if (itemDefinition == null)
            {
                player.Reply(GetMessage("InvalidItem", player.Id));
                return;
            }

            PermissionSetting permissionSetting = weaponoption.FindPermissionSetting(args[1]);
            if (permissionSetting == null)
            {
                player.Reply(GetMessage("InvalidPermission", player.Id));
                return;
            }

            switch (args[2].ToLower())
            {
                case "magazinesize":
                    permissionSetting.SetMagazineSize(player, itemDefinition.displayName.english, args[3]);
                    SaveConfig();
                    break;
                case "preloadsize":
                    permissionSetting.SetPreloadSize(player, itemDefinition.displayName.english, args[3]);
                    SaveConfig();
                    break;
                case "skin":
                    permissionSetting.SetSkinId(player, itemDefinition.displayName.english, args[3]);
                    SaveConfig();
                    break;
                case "condition":
                    permissionSetting.SetCondition(player, itemDefinition.displayName.english, args[3]);
                    SaveConfig();
                    break;
                case "max":
                    permissionSetting.SetMax(player, itemDefinition.displayName.english, args[3]);
                    SaveConfig();
                    break;
                case "maxammo":
                    permissionSetting.SetMaxAmmo(player, itemDefinition.displayName.english, args[3]);
                    SaveConfig();
                    break;
                case "drop":
                    permissionSetting.SetDropOnDeath(player, itemDefinition.displayName.english, args[3]);
                    break;
                case "name":
                    permissionSetting.SetWeaponName(player, itemDefinition.displayName.english, string.Join(" ",args[3]));
                    SaveConfig();
                    break;
                case "ammotype":
                    permissionSetting.SetAmmoType(player, itemDefinition.displayName.english, string.Join(" ",args[3]));
                    SaveConfig();
                    break;
                default:
                    player.Message(GetMessage("Syntax", player.Id));
                    break;
            }
        }

        #endregion

        #region lang

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                {"InvalidSelection", "You've selected an invalid weapon to modify please type a valid weapon shortname"},
                {"Syntax", "Invalid Params please do /modify shortname permission setting value"},
                {"InvalidPermission", "Invalid Permission Selected please check config for current permission names"},
                {"InvalidItem", "Invalid item. Please provide a valid item name"},
                {"NoPerm", "Unknown Command: modify"},
                {"Success", "You've successfully set {0} {1} to {2}"}
            }, this);
        }

        private static string GetMessage(string key, string userId = null, params object[] args) => string.Format(_instance.lang.GetMessage(key, _instance, userId), args);

        #endregion
    }
}