i dont know where my replaceweapon methos is. Analyze the following scripts by yourself and create the whole fixed script.

using System.Collections.Generic;
using Mirror;
using UnityEngine;
using MarsFPSKit;
using MarsFPSKit.Weapons;

[RequireComponent(typeof(Collider))]
[RequireComponent(typeof(NetworkIdentity))]
public class Kit_WeaponPickup : NetworkBehaviour
{
    [Tooltip("Weapon ID to give players when picked up.")]
    public int weaponID = -1;

    [Tooltip("Attachments attached to the weapon (optional)")]
    public List<int> attachments = new List<int>();

    [Tooltip("Initial bullets left for this weapon on pickup")]
    public int bulletsLeft;

    [Tooltip("Initial bullets left to reload on pickup")]
    public int bulletsLeftToReload;

    [Tooltip("Delay until respawned after pickup (seconds)")]
    public float respawnDelay = 10f;

    [Tooltip("Prefab asset to respawn")]
    public GameObject weaponPickupPrefab;

    private Vector3 spawnPosition;
    private Quaternion spawnRotation;

    void Awake()
    {
        spawnPosition = transform.position;
        spawnRotation = transform.rotation;

        var col = GetComponent<Collider>();
        if (!col)
        {
            col = gameObject.AddComponent<BoxCollider>();
            Debug.Log("[Kit_WeaponPickup] Added missing BoxCollider as trigger");
        }
        col.isTrigger = true;

        if (!TryGetComponent(out NetworkIdentity _))
        {
            Debug.LogError("[Kit_WeaponPickup] Requires a NetworkIdentity component!");
        }

        if (weaponPickupPrefab == null)
        {
            weaponPickupPrefab = gameObject;
            Debug.LogWarning("[Kit_WeaponPickup] weaponPickupPrefab not assigned, defaulting to this GameObject");
        }
    }

    [ServerCallback]
    void OnTriggerEnter(Collider other)
    {
        var player = other.GetComponentInParent<Kit_PlayerBehaviour>();
        if (player == null)
        {
            Debug.Log("[Kit_WeaponPickup] Triggered by non-player or missing Kit_PlayerBehaviour");
            return;
        }

        Debug.Log($"[Kit_WeaponPickup] Player '{player.name}' triggered pickup '{gameObject.name}'");

        var runtimeData = player.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
        var weaponManager = player.weaponManager as Kit_ModernWeaponManager;

        if (runtimeData == null || weaponManager == null)
        {
            Debug.LogWarning($"[Kit_WeaponPickup] Player's weaponManager or runtimeData missing/wrong type. player={player.name}");
            return;
        }

        LogPlayerWeapons(player, runtimeData);

        bool consumed = TryGiveOrRefillWeapon(player, runtimeData, weaponManager);

        if (consumed)
        {
            Debug.Log($"[Kit_WeaponPickup] Pickup '{gameObject.name}' consumed by player '{player.name}'. Scheduling respawn and destroying pickup.");
            Kit_WeaponPickupRespawnManager.Instance.ScheduleRespawn(weaponPickupPrefab, spawnPosition, spawnRotation, respawnDelay);

            if (NetworkServer.active)
            {
                NetworkServer.Destroy(gameObject);
                Debug.Log("[Kit_WeaponPickup] NetworkServer.Destroy called.");
            }
            else
            {
                Debug.LogWarning("[Kit_WeaponPickup] NetworkServer not active, cannot destroy pickup properly!");
            }
        }
        else
        {
            Debug.LogWarning($"[Kit_WeaponPickup] Pickup '{gameObject.name}' NOT consumed by player '{player.name}'. This is unexpected.");
        }
    }

    private void LogPlayerWeapons(Kit_PlayerBehaviour player, Kit_ModernWeaponManagerNetworkData runtimeData)
    {
        Debug.Log($"[Kit_WeaponPickup] Player '{player.name}' current weapons and ammo (slots count: {runtimeData.weaponsInUseDataObjects.Length}):");

        for (int i = 0; i < runtimeData.weaponsInUseDataObjects.Length; i++)
        {
            var wData = runtimeData.weaponsInUseDataObjects[i] as Kit_ModernWeaponScriptRuntimeData;
            if (wData != null)
            {
                string weaponName = "Unknown";
                int id = runtimeData.weaponsInUseDataObjects[i].id;
                var allWeapons = Kit_IngameMain.instance.gameInformation?.allWeapons;

                if (allWeapons != null && id >= 0 && id < allWeapons.Length && allWeapons[id] != null)
                {
                    weaponName = allWeapons[id].weaponName.GetLocalizedString();
                }

                Debug.Log($"  Slot {i}: WeaponID={id} ({weaponName}), bulletsLeft={wData.bulletsLeft}, bulletsLeftToReload={wData.bulletsLeftToReload}");
            }
            else
            {
                Debug.Log($"  Slot {i}: null or wrong runtime data type.");
            }
        }
    }

    [Server]
    bool TryGiveOrRefillWeapon(Kit_PlayerBehaviour player, Kit_ModernWeaponManagerNetworkData runtimeData,
        Kit_ModernWeaponManager weaponManager)
    {
        Debug.Log($"[Kit_WeaponPickup] Attempting pickup for player '{player.name}' with weaponID {weaponID}.");

        if (weaponID < 0 || weaponID >= Kit_IngameMain.instance.gameInformation.allWeapons.Length)
        {
            Debug.LogWarning("[Kit_WeaponPickup] Invalid weaponID in pickup.");
            return false;
        }

        int slot = weaponManager.HasWeapon(player, weaponID);
        Debug.Log($"[Kit_WeaponPickup] Player '{player.name}' has weapon {weaponID} in slot {slot}.");

        if (slot >= 0)
        {
            // Refresh the runtime data from the networked instance
            if (runtimeData.weaponsInUseSync.Count <= slot)
            {
                Debug.LogWarning("[Kit_WeaponPickup] weaponsInUseSync count insufficient.");
                return false;
            }

            if (!NetworkServer.spawned.TryGetValue(runtimeData.weaponsInUseSync[slot], out NetworkIdentity netId) || netId == null)
            {
                Debug.LogWarning($"[Kit_WeaponPickup] Weapon NetworkIdentity missing or destroyed for slot {slot}.");
                return false;
            }

            var wrData = netId.GetComponent<Kit_ModernWeaponScriptRuntimeData>();
            if (wrData == null)
            {
                Debug.LogWarning($"[Kit_WeaponPickup] Weapon runtime data missing for slot {slot}.");
                return false;
            }

            // Update cached references
            runtimeData.weaponsInUseDataObjects[slot] = wrData;

            Debug.Log($"[Kit_WeaponPickup] Current ammo for player '{player.name}' on slot {slot}: bulletsLeft = {wrData.bulletsLeft}, bulletsLeftToReload = {wrData.bulletsLeftToReload}");

            bool didRefill = false;

            if (wrData.bulletsLeft < bulletsLeft)
            {
                Debug.Log($"[Kit_WeaponPickup] Refilling bulletsLeft from {wrData.bulletsLeft} to {bulletsLeft} for player '{player.name}'.");
                wrData.bulletsLeft = bulletsLeft;
                didRefill = true;
            }

            if (wrData.bulletsLeftToReload < bulletsLeftToReload)
            {
                Debug.Log($"[Kit_WeaponPickup] Refilling bulletsLeftToReload from {wrData.bulletsLeftToReload} to {bulletsLeftToReload} for player '{player.name}'.");
                wrData.bulletsLeftToReload = bulletsLeftToReload;
                didRefill = true;
            }

            if (runtimeData.currentWeapon != slot)
            {
                runtimeData.currentWeapon = slot;
                Debug.Log($"[Kit_WeaponPickup] Switched current weapon to slot {slot} for player '{player.name}'.");
            }

            // Always consume the pickup
            Debug.Log($"[Kit_WeaponPickup] Pickup will be consumed by player '{player.name}' (has weapon). Refilled: {didRefill}");

            return true;
        }
        else
        {
            // Player does not have the weapon — assign new one.
            var emptySlots = weaponManager.GetSlotsWithEmptyWeapon(player);

            int targetSlot;
            if (emptySlots.Length > 0)
            {
                targetSlot = emptySlots[0];
                Debug.Log($"[Kit_WeaponPickup] Using empty slot {targetSlot} for player '{player.name}'.");
            }
            else
            {
                targetSlot = runtimeData.currentWeapon;
                Debug.Log($"[Kit_WeaponPickup] No empty slots, replacing weapon at current slot {targetSlot} for player '{player.name}'.");
            }

            Debug.Log($"[Kit_WeaponPickup] Replacing player '{player.name}' weapon in slot {targetSlot} with new weapon ID {weaponID}.");

            player.ReplaceWeapon(targetSlot, weaponID, bulletsLeft, bulletsLeftToReload, attachments.ToArray());

            // Refresh weaponsInUseDataObjects with new weapon reference
            if (runtimeData.weaponsInUseSync.Count > targetSlot)
            {
                if (NetworkServer.spawned.TryGetValue(runtimeData.weaponsInUseSync[targetSlot], out NetworkIdentity newNetId))
                {
                    var newWrData = newNetId.GetComponent<Kit_WeaponRuntimeDataBase>();
                    runtimeData.weaponsInUseDataObjects[targetSlot] = newWrData;

                    Debug.Log($"[Kit_WeaponPickup] Refreshed weaponsInUseDataObjects[{targetSlot}] after replacement.");
                }
                else
                {
                    Debug.LogWarning("[Kit_WeaponPickup] Failed to refresh weaponsInUseDataObjects after replacement.");
                }
            }
            else
            {
                Debug.LogWarning("[Kit_WeaponPickup] weaponsInUseSync count less than target slot after replacement.");
            }

            runtimeData.currentWeapon = targetSlot;

            Debug.Log("[Kit_WeaponPickup] Pickup will be consumed by player (new weapon assigned).");

            return true;
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using Mirror;
using UnityEngine;

public class Kit_WeaponPickupRespawnManager : NetworkBehaviour
{
    public static Kit_WeaponPickupRespawnManager Instance;

    void Awake()
    {
        if (Instance && Instance != this) Destroy(gameObject);
        else
        {
            Instance = this;
            DontDestroyOnLoad(gameObject);
        }
    }

    private struct PickupRespawnData
    {
        public GameObject prefab;
        public Vector3 position;
        public Quaternion rotation;
        public float delay;

        public PickupRespawnData(GameObject p, Vector3 pos, Quaternion rot, float d)
        {
            prefab = p; position = pos; rotation = rot; delay = d;
        }
    }

    private Queue<PickupRespawnData> respawnsQueue = new Queue<PickupRespawnData>();
    private bool isRespawning = false;

    [Server]
    public void ScheduleRespawn(GameObject prefab, Vector3 position, Quaternion rotation, float delay)
    {
        if (!isServer) return;

        respawnsQueue.Enqueue(new PickupRespawnData(prefab, position, rotation, delay));
        if (!isRespawning)
            StartCoroutine(ProcessRespawns());
    }

    [Server]
    private IEnumerator ProcessRespawns()
    {
        isRespawning = true;

        while (respawnsQueue.Count > 0)
        {
            var data = respawnsQueue.Dequeue();
            yield return new WaitForSeconds(data.delay);

            GameObject newPickup = Instantiate(data.prefab, data.position, data.rotation);
            newPickup.SetActive(true);

            // Ensure collider and renderers enabled
            var col = newPickup.GetComponent<Collider>();
            if (col != null) col.enabled = true;

            var renderers = newPickup.GetComponentsInChildren<Renderer>(true);
            foreach (var r in renderers)
                if (!r.enabled) r.enabled = true;

            try
            {
                NetworkServer.Spawn(newPickup);
                Debug.Log("[Kit_WeaponPickupRespawnManager] Spawned pickup on server");

                // Re-enqueue for continuous respawn after pickup is consumed again
                // Note: The respawn itself will schedule the next cycle when consumed again,
                // so no need to re-enqueue here, to avoid duplicates causing overlap.
            }
            catch (System.Exception e)
            {
                Debug.LogError("[Kit_WeaponPickupRespawnManager] Failed to spawn pickup: " + e);
                Destroy(newPickup);
            }
        }

        isRespawning = false;
    }
}
using Mirror;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using UnityEngine;

namespace MarsFPSKit
{
    namespace Weapons
    {
        /// <summary>
        /// Input that is allowed for the given weapon slot
        /// </summary>
        [System.Serializable]
        public class WeaponManagerSlot
        {
            /// <summary>
            /// Can weapons in this slot be equipped?
            /// </summary>
            public bool enableEquipping = true;
            /// <summary>
            /// ID of <see cref="Kit_PlayerInput.weaponSlotUses"/>
            /// </summary>
            public int equippingInputID;
            /// <summary>
            /// Can weapons in this slot be quick used (e.g. quick grenades, quick knife)
            /// </summary>
            public bool enableQuickUse;
            /// <summary>
            /// ID of <see cref="Kit_PlayerInput.weaponSlotUses"/>
            /// </summary>
            public int quickUseInputID;
        }

        public enum DeadDrop { None, Selected, All }

        /// <summary>
        /// This is a modern, generic weapon manager. Weapons are put away and then taken out, like in COD or Battlefield. Supports an "infinite" amount of weapons
        /// </summary>
        [CreateAssetMenu(menuName = ("MarsFPSKit/Weapons/Modern Weapon Manager"))]
        public class Kit_ModernWeaponManager : Kit_WeaponManagerBase
        {
            public WeaponManagerSlot[] slotConfiguration;
            /// <summary>
            /// Main drop prefab!
            /// </summary>
            public GameObject dropPrefab;
            /// <summary>
            /// Layers that will be hit by the pickup raycast
            /// </summary>
            public LayerMask pickupLayers;
            /// <summary>
            /// Distance for the pickup raycast
            /// </summary>
            public float pickupDistance = 3f;
            /// <summary>
            /// Which weapons should be dropped upon death?
            /// </summary>
            public DeadDrop uponDeathDrop;
            /// <summary>
            /// How fast does the weapon position change?
            /// </summary>
            public float weaponPositionChangeSpeed = 5f;
            /// <summary>
            /// Can we switch while we are running?
            /// </summary>
            public bool allowSwitchingWhileRunning;
            /// <summary>
            /// Can we do quick use while running?
            /// </summary>
            public bool allowQuickUseWhileRunning;

            public override void OnWeaponsInUseSyncCallback(Kit_PlayerBehaviour pb, SyncList<uint>.Operation op, int itemIndex, uint item)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;

                switch (op)
                {
                    case SyncList<uint>.Operation.OP_SET:
                        //Cleanup old data first
                        for (int i = 0; i < runtimeData.weaponsInUseDataObjects[itemIndex].instantiatedObjects.Count; i++)
                        {
                            if (runtimeData.weaponsInUseDataObjects[itemIndex].instantiatedObjects[i])
                            {
                                NetworkIdentity nid = runtimeData.weaponsInUseDataObjects[itemIndex].instantiatedObjects[i].GetComponentInChildren<NetworkIdentity>();

                                if (nid)
                                {
                                    if (NetworkServer.active)
                                    {
                                        NetworkServer.Destroy(nid.gameObject);
                                    }
                                }
                                else
                                {
                                    Destroy(runtimeData.weaponsInUseDataObjects[itemIndex].instantiatedObjects[i]);
                                }
                            }
                        }

                        runtimeData.weaponsInUseDataObjects[itemIndex].instantiatedObjects.Clear();

                        //We may need to wait a bit for the network
                        Kit_ScriptableObjectCoroutineHelper.instance.StartCoroutine(Kit_ScriptableObjectCoroutineHelper.instance.NetworkReplaceWeapon(pb, runtimeData, itemIndex, runtimeData.weaponsInUseSync[itemIndex]));
                        break;
                }
            }

            public override void SetupSpawnData(Kit_PlayerBehaviour pb, Loadout loadout, NetworkConnectionToClient sender)
            {
                GameObject data = Instantiate(networkData, Vector3.zero, Quaternion.identity);
                Kit_ModernWeaponManagerNetworkData runtimeData = data.GetComponent<Kit_ModernWeaponManagerNetworkData>();
                pb.weaponManagerNetworkData = runtimeData;

                for (int i = 0; i < loadout.loadoutWeapons.Length; i++)
                {
                    GameObject spawnObject = Kit_IngameMain.instance.gameInformation.allWeapons[loadout.loadoutWeapons[i].weaponID].SetupSpawnData(pb, i, loadout.loadoutWeapons[i]);
                    NetworkServer.Spawn(spawnObject, sender);
                    NetworkIdentity id = spawnObject.GetComponent<NetworkIdentity>();

                    //Add to our weapon list
                    runtimeData.weaponsInUseSync.Add(id.netId);
                }
            }

            public override void SetupSpawnData(Kit_PlayerBehaviour pb, Loadout loadout)
            {
                GameObject data = Instantiate(networkData, Vector3.zero, Quaternion.identity);
                Kit_ModernWeaponManagerNetworkData runtimeData = data.GetComponent<Kit_ModernWeaponManagerNetworkData>();
                pb.weaponManagerNetworkData = runtimeData;

                for (int i = 0; i < loadout.loadoutWeapons.Length; i++)
                {
                    GameObject spawnObject = Kit_IngameMain.instance.gameInformation.allWeapons[loadout.loadoutWeapons[i].weaponID].SetupSpawnData(pb, i, loadout.loadoutWeapons[i]);
                    NetworkServer.Spawn(spawnObject);
                    NetworkIdentity id = spawnObject.GetComponent<NetworkIdentity>();

                    //Add to our weapon list
                    runtimeData.weaponsInUseSync.Add(id.netId);
                }
            }

            public override void InitializeServer(Kit_PlayerBehaviour pb)
            {
                //Is created in SetupSpawnData
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                runtimeData.ownerPlayerNetworkId = pb.netId;
                //Spawn it here
                if (pb.isBot)
                    NetworkServer.Spawn(runtimeData.gameObject);
                else
                    NetworkServer.Spawn(runtimeData.gameObject, pb.gameObject);

                //Setup input IDs
                runtimeData.lastInputIDs = new bool[pb.input.weaponSlotUses.Length];

                //Initially build list
                runtimeData.weaponsInUseDataObjects = new Kit_WeaponRuntimeDataBase[runtimeData.weaponsInUseSync.Count];

                for (int i = 0; i < runtimeData.weaponsInUseSync.Count; i++)
                {
                    NetworkIdentity id = null;

                    if (NetworkServer.active)
                    {
                        id = NetworkServer.spawned[runtimeData.weaponsInUseSync[i]];
                    }
                    else
                    {
                        id = NetworkClient.spawned[runtimeData.weaponsInUseSync[i]];
                    }

                    if (id)
                    {
                        runtimeData.weaponsInUseDataObjects[i] = id.GetComponent<Kit_WeaponRuntimeDataBase>();
                    }
                    else
                    {
                        //Didn't find it. This shouldn't happen!
                        runtimeData.weaponsInUseDataObjects[i] = null;
                    }
                }

                for (int i = 0; i < runtimeData.weaponsInUseDataObjects.Length; i++)
                {
                    int slot = i;
                    int id = runtimeData.weaponsInUseDataObjects[slot].id;
                    //Get their behaviour modules
                    Kit_WeaponBase weaponBehaviour = pb.gameInformation.allWeapons[id];
                    //Assign Behaviour
                    runtimeData.weaponsInUseDataObjects[slot].behaviour = weaponBehaviour;
                    runtimeData.weaponsInUseDataObjects[slot].pb = pb;
                    //Setup FP
                    weaponBehaviour.SetupFirstPerson(pb, runtimeData.weaponsInUseDataObjects[slot]);
                    //Setup TP
                    weaponBehaviour.SetupThirdPerson(pb, runtimeData.weaponsInUseDataObjects[slot]);
                }

                SelectDefaultWeapon(pb, runtimeData);

                //Set time
                runtimeData.switchNextEnd = Time.time + runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.drawTime;
                //Set phase
                runtimeData.switchPhase = 1;
                //Set switching
                runtimeData.switchInProgress = true;
            }

            public override void InitializeClient(Kit_PlayerBehaviour pb)
            {
                if (!pb.weaponManagerNetworkData)
                {
                    //Find ours
                    pb.weaponManagerNetworkData = FindObjectsOfType<Kit_ModernWeaponManagerNetworkData>().Where(x => x.ownerPlayerNetworkId == pb.netId).FirstOrDefault();
                }

                if (pb.isClientOnly)
                {
                    Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;

                    //Setup input IDs
                    runtimeData.lastInputIDs = new bool[pb.input.weaponSlotUses.Length];

                    //Initially build list
                    runtimeData.weaponsInUseDataObjects = new Kit_WeaponRuntimeDataBase[runtimeData.weaponsInUseSync.Count];

                    for (int i = 0; i < runtimeData.weaponsInUseSync.Count; i++)
                    {
                        NetworkIdentity id = null;

                        if (NetworkServer.active)
                        {
                            id = NetworkServer.spawned[runtimeData.weaponsInUseSync[i]];
                        }
                        else
                        {
                            id = NetworkClient.spawned[runtimeData.weaponsInUseSync[i]];
                        }

                        if (id)
                        {
                            runtimeData.weaponsInUseDataObjects[i] = id.GetComponent<Kit_WeaponRuntimeDataBase>();
                        }
                        else
                        {
                            //Didn't find it. This shouldn't happen!
                            runtimeData.weaponsInUseDataObjects[i] = null;
                        }
                    }

                    for (int i = 0; i < runtimeData.weaponsInUseDataObjects.Length; i++)
                    {
                        int slot = i;
                        int id = runtimeData.weaponsInUseDataObjects[slot].id;
                        //Get their behaviour modules
                        Kit_WeaponBase weaponBehaviour = pb.gameInformation.allWeapons[id];
                        //Assign Behaviour
                        runtimeData.weaponsInUseDataObjects[slot].behaviour = weaponBehaviour;
                        runtimeData.weaponsInUseDataObjects[slot].pb = pb;
                        //Setup FP
                        weaponBehaviour.SetupFirstPerson(pb, runtimeData.weaponsInUseDataObjects[slot]);
                        //Setup TP
                        weaponBehaviour.SetupThirdPerson(pb, runtimeData.weaponsInUseDataObjects[slot]);
                    }

                    SelectDefaultWeapon(pb, runtimeData);

                    //Set time
                    runtimeData.switchNextEnd = Time.time + runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.drawTime;
                    //Set phase
                    runtimeData.switchPhase = 1;
                    //Set switching
                    runtimeData.switchInProgress = true;
                }
            }

            /// <summary>
            /// Selects the first weapon
            /// </summary>
            /// <param name="pb"></param>
            /// <param name="runtimeData"></param>
            void SelectDefaultWeapon(Kit_PlayerBehaviour pb, Kit_ModernWeaponManagerNetworkData runtimeData)
            {
                //Select default weapon
                for (int i = 0; i < runtimeData.weaponsInUseDataObjects.Length; i++)
                {
                    if (i < slotConfiguration.Length && slotConfiguration[i].enableEquipping)
                    {
                        if (runtimeData.weaponsInUseDataObjects[i].behaviour.CanBeSelected(pb, runtimeData.weaponsInUseDataObjects[i]))
                        {
                            int id = i;
                            //Select current weapon
                            runtimeData.weaponsInUseDataObjects[i].behaviour.DrawWeapon(pb, runtimeData.weaponsInUseDataObjects[i]);
                            //Play Third person animation
                            pb.thirdPersonPlayerModel.PlayWeaponChangeAnimation(runtimeData.weaponsInUseDataObjects[i].behaviour.thirdPersonAnimType, true, runtimeData.weaponsInUseDataObjects[i].behaviour.drawTime);
                            //Set current weapon
                            runtimeData.desiredWeapon = runtimeData.currentWeapon = id;
                            return;
                        }

                    }
                }
            }

            public override void TakeControl(Kit_PlayerBehaviour pb)
            {
                //Hide crosshair
                Kit_IngameMain.instance.hud.DisplayCrosshair(0f, false);

            }

            public override void ForceUnselectCurrentWeapon(Kit_PlayerBehaviour pb)
            {
                Debug.Log("[Weapon Manager] Forcing unselect of current weapon!");
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                bool foundWeapon = false;
                //Try to find next weapon
                int next = -1;
                for (int i = 0; i < runtimeData.weaponsInUseDataObjects.Length; i++)
                {
                    if (foundWeapon) break;


                    if (!runtimeData.weaponsInUseDataObjects[i].isInjectedFromPlugin)
                    {
                        //Check if this one works!
                        if (runtimeData.weaponsInUseDataObjects[i].behaviour.CanBeSelected(pb, runtimeData.weaponsInUseDataObjects[i]))
                        {
                            int id = i;
                            next = id;
                            //We found one
                            foundWeapon = true;
                            break;
                        }
                    }

                }

                //This should ALWAYS be true!
                if (next >= 0)
                {
                    runtimeData.desiredWeapon = next;
                    //Begin switch and skip putaway
                    runtimeData.switchInProgress = true;
                    //Set time (Because here we cannot use a coroutine)
                    runtimeData.switchNextEnd = 0f;
                    //Set phase
                    runtimeData.switchPhase = 0;
                    if (pb.isFirstPersonActive)
                    {
                        //Hide crosshair
                        Kit_IngameMain.instance.hud.DisplayCrosshair(0f, false);
                    }
                    //Set current one too!
                    runtimeData.currentWeapon = next;
                }
                else
                {
                    Debug.LogError("Could not find next weapon! This is not allowed!");
                }
            }

            public override void AuthorativeInput(Kit_PlayerBehaviour pb, Kit_PlayerInput input, float delta, double revertTime)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;

                if (!runtimeData.isDesiredWeaponLocked)
                {
                    for (int i = 0; i < runtimeData.weaponsInUseDataObjects.Length; i++)
                    {
                        if (!runtimeData.weaponsInUseDataObjects[i].isInjectedFromPlugin)
                        {
                            if (slotConfiguration.Length > i)
                            {
                                if (slotConfiguration[i].enableEquipping && slotConfiguration[i].equippingInputID >= 0 && !runtimeData.quickUseInProgress)
                                {
                                    if (runtimeData.lastInputIDs[slotConfiguration[i].equippingInputID] != input.weaponSlotUses[slotConfiguration[i].equippingInputID])
                                    {
                                        runtimeData.lastInputIDs[slotConfiguration[i].equippingInputID] = input.weaponSlotUses[slotConfiguration[i].equippingInputID];
                                        //Check for input
                                        if (input.weaponSlotUses[slotConfiguration[i].equippingInputID] && (allowSwitchingWhileRunning || !pb.movement.IsRunning(pb)))
                                        {
                                            int id = i;
                                            if (runtimeData.desiredWeapon != id)
                                            {
                                                if (runtimeData.weaponsInUseDataObjects[i].behaviour.CanBeSelected(pb, runtimeData.weaponsInUseDataObjects[i]))
                                                {
                                                    runtimeData.desiredWeapon = id;
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    if (input.nextWeapon)
                    {
                        int nextWeapon = runtimeData.desiredWeapon + 1;
                        if (nextWeapon >= runtimeData.weaponsInUseSync.Count) nextWeapon = 0;
                        while (runtimeData.weaponsInUseDataObjects[nextWeapon].isInjectedFromPlugin || !runtimeData.weaponsInUseDataObjects[nextWeapon].behaviour.CanBeSelected(pb, runtimeData.weaponsInUseDataObjects[nextWeapon]))
                        {
                            nextWeapon++;
                            if (nextWeapon >= runtimeData.weaponsInUseSync.Count) nextWeapon = 0;
                        }

                        runtimeData.desiredWeapon = nextWeapon;
                    }
                    else if (input.previousWeapon)
                    {
                        int previousWeapon = runtimeData.desiredWeapon - 1;
                        if (previousWeapon < 0) previousWeapon = runtimeData.weaponsInUseDataObjects.Length - 1;
                        while (runtimeData.weaponsInUseDataObjects[previousWeapon].isInjectedFromPlugin || !runtimeData.weaponsInUseDataObjects[previousWeapon].behaviour.CanBeSelected(pb, runtimeData.weaponsInUseDataObjects[previousWeapon]))
                        {
                            previousWeapon--;
                            if (previousWeapon < 0) previousWeapon = runtimeData.weaponsInUseDataObjects.Length - 1;
                        }

                        runtimeData.desiredWeapon = previousWeapon;
                    }

                    //Check if we can do a quick use!
                    if (runtimeData.currentWeapon == runtimeData.desiredWeapon && !runtimeData.switchInProgress)
                    {
                        if (!runtimeData.quickUseInProgress)
                        {
                            for (int i = 0; i < runtimeData.weaponsInUseDataObjects.Length; i++)
                            {
                                if (!runtimeData.weaponsInUseDataObjects[i].isInjectedFromPlugin)
                                {
                                    int slot = i;
                                    if (slotConfiguration.Length > slot)
                                    {
                                        if (slotConfiguration[slot].enableQuickUse)
                                        {
                                            if (slotConfiguration[slot].quickUseInputID >= 0)
                                            {
                                                if (runtimeData.lastInputIDs[slotConfiguration[slot].quickUseInputID] != input.weaponSlotUses[slotConfiguration[slot].quickUseInputID])
                                                {
                                                    runtimeData.lastInputIDs[slotConfiguration[slot].quickUseInputID] = input.weaponSlotUses[slotConfiguration[slot].quickUseInputID];
                                                    //Check for input
                                                    if (input.weaponSlotUses[slotConfiguration[slot].quickUseInputID] && (allowQuickUseWhileRunning || !pb.movement.IsRunning(pb)))
                                                    {
                                                        if (runtimeData.weaponsInUseDataObjects[slot].behaviour.SupportsQuickUse(pb, runtimeData.weaponsInUseDataObjects[slot]))
                                                        {
                                                            runtimeData.desiredQuickUse = slot;
                                                            runtimeData.quickUseInProgress = true;
                                                            //Also reset these!
                                                            runtimeData.quickUseState = 0;
                                                            runtimeData.quickUseOverAt = Time.time;
                                                            break;
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        else
                        {
                            if (runtimeData.quickUseState == 2)
                            {
                                //Check if quick use button needs to be released
                                if (runtimeData.weaponsInUseDataObjects[runtimeData.desiredQuickUse].behaviour.WaitForQuickUseButtonRelease(pb, runtimeData.weaponsInUseDataObjects[runtimeData.desiredQuickUse]) && (!pb.input.weaponSlotUses[slotConfiguration[runtimeData.desiredQuickUse].quickUseInputID]))
                                {
                                    runtimeData.quickUseSyncButtonWaitOver = true;
                                }
                            }
                        }
                    }
                }

                if (!runtimeData.switchInProgress && !runtimeData.quickUseInProgress)
                {
                    runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.AuthorativeInput(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon], input, delta, revertTime);
                }
            }

            public override void PredictionInput(Kit_PlayerBehaviour pb, Kit_PlayerInput input, float delta)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;

                AuthorativeInput(pb, input, delta, 0f);


                if (Physics.Raycast(pb.playerCameraTransform.position, pb.playerCameraTransform.forward, out runtimeData.hit, pickupDistance, pickupLayers.value))
                {
                    if (runtimeData.hit.transform.root.GetComponent<Kit_DropBehaviour>())
                    {
                        Kit_DropBehaviour drop = runtimeData.hit.transform.root.GetComponent<Kit_DropBehaviour>();
                        if (pb.isFirstPersonActive)
                        {
                            Kit_IngameMain.instance.hud.DisplayWeaponPickup(true, drop.weaponID);
                            Kit_IngameMain.instance.hud.DisplayInteraction(false);
                        }

                        if (runtimeData.lastInteract != input.interact)
                        {
                            runtimeData.lastInteract = input.interact;
                            if (input.interact && (allowSwitchingWhileRunning || !pb.movement.IsRunning(pb)))
                            {
                                drop.CmdTryPickUp();
                            }
                        }
                    }
                    else if (runtimeData.hit.transform.GetComponentInParent<Kit_InteractableObject>())
                    {
                        Kit_InteractableObject io = runtimeData.hit.transform.GetComponentInParent<Kit_InteractableObject>();

                        if (io.CanInteract(pb))
                        {
                            if (pb.isFirstPersonActive)
                            {
                                Kit_IngameMain.instance.hud.DisplayWeaponPickup(false);
                                Kit_IngameMain.instance.hud.DisplayInteraction(true, io.interactionText);
                            }

                            if (io.IsHold())
                            {
                                if (input.interact)
                                {
                                    //Store object
                                    runtimeData.holdingInteractableObject = io;

                                    //Tell object we want to interact
                                    io.Interact(pb);
                                }
                                else
                                {
                                    if (runtimeData.holdingInteractableObject)
                                    {
                                        runtimeData.holdingInteractableObject.InteractHoldEnd(pb);
                                        runtimeData.holdingInteractableObject = null;
                                    }
                                }
                            }
                            else
                            {
                                if (runtimeData.lastInteract != input.interact)
                                {
                                    runtimeData.lastInteract = input.interact;
                                    if (input.interact)
                                    {
                                        //Tell object we want to interact
                                        io.Interact(pb);
                                    }
                                }
                            }
                        }
                        else
                        {
                            if (pb.isFirstPersonActive)
                            {
                                Kit_IngameMain.instance.hud.DisplayWeaponPickup(false);
                                Kit_IngameMain.instance.hud.DisplayInteraction(false);
                            }

                            if (runtimeData.holdingInteractableObject)
                            {
                                runtimeData.holdingInteractableObject.InteractHoldEnd(pb);
                                runtimeData.holdingInteractableObject = null;
                            }
                        }
                    }
                    else
                    {
                        if (pb.isFirstPersonActive)
                        {
                            Kit_IngameMain.instance.hud.DisplayWeaponPickup(false);
                            Kit_IngameMain.instance.hud.DisplayInteraction(false);
                        }

                        if (runtimeData.holdingInteractableObject)
                        {
                            runtimeData.holdingInteractableObject.InteractHoldEnd(pb);
                            runtimeData.holdingInteractableObject = null;
                        }
                    }
                }
                else
                {
                    if (pb.isFirstPersonActive)
                    {
                        Kit_IngameMain.instance.hud.DisplayWeaponPickup(false);
                        Kit_IngameMain.instance.hud.DisplayInteraction(false);
                    }

                    if (runtimeData.holdingInteractableObject)
                    {
                        runtimeData.holdingInteractableObject.InteractHoldEnd(pb);
                        runtimeData.holdingInteractableObject = null;
                    }
                }
            }

            public override void CustomUpdate(Kit_PlayerBehaviour pb, double revertBy)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;

                //Quick use has priority!
                if ((runtimeData.quickUseInProgress || runtimeData.quickUseState > 0) && runtimeData.desiredQuickUse >= 0)
                {
                    //Update weapon animation
                    runtimeData.weaponsInUseDataObjects[runtimeData.desiredQuickUse].behaviour.AnimateWeapon(pb, runtimeData.weaponsInUseDataObjects[runtimeData.desiredQuickUse], pb.movement.GetCurrentWeaponMoveAnimation(pb), pb.movement.GetCurrentWalkAnimationSpeed(pb));

                    if (Time.time >= runtimeData.quickUseOverAt)
                    {
                        //First, put away current weapon!
                        if (runtimeData.quickUseState == 0)
                        {
                            if (!runtimeData.weaponsInUseDataObjects[runtimeData.desiredQuickUse].behaviour.QuickUseSkipsPutaway(pb, runtimeData.weaponsInUseDataObjects[runtimeData.desiredQuickUse]))
                            {
                                //Set time (Because here we cannot use a coroutine)
                                runtimeData.quickUseOverAt = Time.time + runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.putawayTime;
                                //Set phase
                                runtimeData.quickUseState = 1;
                                //Start putaway
                                runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.PutawayWeapon(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]);
                                //Play Third person animation
                                pb.thirdPersonPlayerModel.PlayWeaponChangeAnimation(runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.thirdPersonAnimType, false, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.putawayTime);
                                if (pb.isFirstPersonActive)
                                {
                                    //Hide crosshair
                                    Kit_IngameMain.instance.hud.DisplayCrosshair(0f, false);
                                }

                                if (pb.isLocalPlayer)
                                {
                                    pb.inputManager.ResetAiming(pb);
                                }
                            }
                            else
                            {
                                //Set phase
                                runtimeData.quickUseState = 1;
                                if (pb.isFirstPersonActive)
                                {
                                    //Hide crosshair
                                    Kit_IngameMain.instance.hud.DisplayCrosshair(0f, false);
                                }
                            }
                        }
                        else if (runtimeData.quickUseState == 1)
                        {
                            //Weapon has been put away, hide weapon
                            runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.PutawayWeaponHide(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]);
                            runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.QuickUseOnOtherWeaponBegin(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]);

                            //Set state
                            runtimeData.quickUseState = 2;

                            //Begin quick use....
                            runtimeData.quickUseOverAt = Time.time + runtimeData.weaponsInUseDataObjects[runtimeData.desiredQuickUse].behaviour.BeginQuickUse(pb, runtimeData.weaponsInUseDataObjects[runtimeData.desiredQuickUse], (float)revertBy);
                        }
                        else if (runtimeData.quickUseState == 2)
                        {
                            //Check if weapon wants to abort quick use
                            if (!runtimeData.weaponsInUseDataObjects[runtimeData.desiredQuickUse].behaviour.SupportsQuickUse(pb, runtimeData.weaponsInUseDataObjects[runtimeData.desiredQuickUse]) ||
                                //Check if we don't need to wait for the button
                                (!runtimeData.weaponsInUseDataObjects[runtimeData.desiredQuickUse].behaviour.WaitForQuickUseButtonRelease(pb, runtimeData.weaponsInUseDataObjects[runtimeData.desiredQuickUse])) ||
                                //Or button was released via sync
                                (runtimeData.quickUseSyncButtonWaitOver))
                            {
                                runtimeData.quickUseSyncButtonWaitOver = true;
                                //Set State
                                runtimeData.quickUseState = 3;
                                //End quick use...
                                runtimeData.quickUseOverAt = Time.time + runtimeData.weaponsInUseDataObjects[runtimeData.desiredQuickUse].behaviour.EndQuickUse(pb, runtimeData.weaponsInUseDataObjects[runtimeData.desiredQuickUse], (float)revertBy);
                            }
                        }
                        else if (runtimeData.quickUseState == 3)
                        {
                            //Hide Quick Use!
                            runtimeData.weaponsInUseDataObjects[runtimeData.desiredQuickUse].behaviour.EndQuickUseAfter(pb, runtimeData.weaponsInUseDataObjects[runtimeData.desiredQuickUse], (float)revertBy);
                            //Check if currently selected  weapon is valid.
                            if (runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.CanBeSelected(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]))
                            {
                                //Set weapon
                                runtimeData.currentWeapon = runtimeData.desiredWeapon;
                            }
                            else
                            {
                                //Its not, find a new one
                                int next = 0;
                                for (int i = 0; i < runtimeData.weaponsInUseDataObjects.Length; i++)
                                {
                                    //Check if this one works!
                                    if (runtimeData.weaponsInUseDataObjects[i].behaviour.CanBeSelected(pb, runtimeData.weaponsInUseDataObjects[i]))
                                    {
                                        int id = i;
                                        next = id;
                                        //We found one
                                        break;
                                    }
                                }

                                //This should ALWAYS be true!
                                if (next >= 0)
                                {
                                    runtimeData.desiredWeapon = next;
                                    //Set current one too!
                                    runtimeData.currentWeapon = next;
                                }
                                else
                                {
                                    Debug.LogError("Could not find next weapon! This is not allowed!");
                                }
                            }

                            //Draw that weapon
                            runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.DrawWeapon(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]);
                            //Play Third person animation
                            pb.thirdPersonPlayerModel.PlayWeaponChangeAnimation(runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.thirdPersonAnimType, true, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.drawTime);
                            //Set phase
                            runtimeData.quickUseState = 4;
                            //Set time
                            runtimeData.quickUseOverAt = Time.time + runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.drawTime;
                            //Done, now wait
                        }
                        else if (runtimeData.quickUseState == 4)
                        {
                            //End quick use
                            runtimeData.quickUseInProgress = false;
                            runtimeData.desiredQuickUse = -1;
                            runtimeData.quickUseSyncButtonWaitOver = false;
                            runtimeData.quickUseState = 0;
                            runtimeData.quickUseOverAt = Time.time;

                            //Also reset switching just to be sure!
                            runtimeData.switchPhase = 0;
                            runtimeData.switchNextEnd = 0f;
                            runtimeData.switchInProgress = false;
                        }
                    }
                }
                else
                {
                    //Update weapon animation
                    runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.AnimateWeapon(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon], pb.movement.GetCurrentWeaponMoveAnimation(pb), pb.movement.GetCurrentWalkAnimationSpeed(pb));

                    if (!runtimeData.switchInProgress)
                    {
                        //If we aren't switching weapons, update weapon behaviour
                        runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.CalculateWeaponUpdate(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]);

                        //Check if we want to select a different weapon
                        if (runtimeData.desiredWeapon != runtimeData.currentWeapon)
                        {
                            //If not, start to switch
                            runtimeData.switchInProgress = true;
                            //Set time (Because here we cannot use a coroutine)
                            runtimeData.switchNextEnd = Time.time + runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.putawayTime;
                            //Set phase
                            runtimeData.switchPhase = 0;
                            //Start putaway
                            runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.PutawayWeapon(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]);
                            //Play Third person animation
                            pb.thirdPersonPlayerModel.PlayWeaponChangeAnimation(runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.thirdPersonAnimType, false, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.putawayTime);
                            if (pb.isFirstPersonActive)
                            {
                                //Hide crosshair
                                Kit_IngameMain.instance.hud.DisplayCrosshair(0f, false);
                            }
                        }
                    }
                    else
                    {
                        //Switching, courtine less
                        #region Switching
                        //Check for time
                        if (Time.time >= runtimeData.switchNextEnd)
                        {
                            //Time is over, check which phase is next
                            if (runtimeData.switchPhase == 0)
                            {
                                //Weapon has been put away, hide weapon
                                runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.PutawayWeaponHide(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]);

                                runtimeData.currentWeapon = runtimeData.desiredWeapon;

                                //Draw that weapon
                                runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.DrawWeapon(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]);
                                //Set phase
                                runtimeData.switchPhase = 1;
                                //Set time
                                runtimeData.switchNextEnd = Time.time + runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.drawTime;
                                //Play Third person animation
                                pb.thirdPersonPlayerModel.PlayWeaponChangeAnimation(runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.thirdPersonAnimType, true, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.drawTime);
                                //Done, now wait
                            }
                            else if (runtimeData.switchPhase == 1)
                            {
                                //Switching is over
                                runtimeData.switchPhase = 0;
                                runtimeData.switchNextEnd = 0f;
                                runtimeData.switchInProgress = false;
                            }
                        }
                        #endregion
                    }
                }

                //Move weapons transform
                pb.weaponsGo.localPosition = Vector3.Lerp(pb.weaponsGo.localPosition, Vector3.zero + pb.looking.GetWeaponOffset(pb), Time.deltaTime * weaponPositionChangeSpeed);

                //Move weapons transform
                pb.weaponsGo.localRotation = Quaternion.Slerp(pb.weaponsGo.localRotation, pb.looking.GetWeaponRotationOffset(pb), Time.deltaTime * weaponPositionChangeSpeed);

                if (pb.isFirstPersonActive)
                {
                    Kit_IngameMain.instance.hud.DisplayWeaponsAndQuickUses(pb, runtimeData);
                }
            }

            public override void CustomLateUpdate(Kit_PlayerBehaviour pb, double revertTime)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;

                //Update weapon animation
                runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.CalculateWeaponLateUpdate(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]);
            }

            public override void CustomFixedUpdate(Kit_PlayerBehaviour pb, double revertTime)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;

                //Update weapon animation
                runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.CalculateWeaponFixedUpdate(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]);
            }

            public override void PlayerDead(Kit_PlayerBehaviour pb)
            {
                if (NetworkServer.active && (Kit_IngameMain.instance.currentPvPGameModeBehaviour && Kit_IngameMain.instance.currentPvPGameModeBehaviour.CanDropWeapons()) || (Kit_IngameMain.instance.currentPvEGameModeBehaviour && Kit_IngameMain.instance.currentPvEGameModeBehaviour.CanDropWeapons()))
                {
                    Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                    if (uponDeathDrop == DeadDrop.Selected)
                    {
                        DropWeaponDead(pb, runtimeData.currentWeapon);
                    }
                    else if (uponDeathDrop == DeadDrop.All)
                    {
                        for (int i = 0; i < runtimeData.weaponsInUseDataObjects.Length; i++)
                        {
                            if (!runtimeData.weaponsInUseDataObjects[i].isInjectedFromPlugin)
                            {
                                DropWeaponDead(pb, i);
                            }
                        }
                    }

                }
            }

            public override void OnAnimatorIKCallback(Kit_PlayerBehaviour pb, Animator anim)
            {
                //Get runtime data
                if (pb.isLocalPlayer)
                {
                    Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                    if (anim)
                    {
                        //Get Weapon IK
                        WeaponIKValues ikv = null;

                        if (runtimeData.quickUseInProgress && runtimeData.quickUseState > 0 && runtimeData.quickUseState < 4)
                        {
                            ikv = runtimeData.weaponsInUseDataObjects[runtimeData.desiredQuickUse].behaviour.GetIK(pb, anim, runtimeData.weaponsInUseDataObjects[runtimeData.desiredQuickUse]);
                        }
                        else
                        {
                            ikv = runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.GetIK(pb, anim, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]);
                        }

                        if (ikv != null)
                        {
                            if (ikv.leftHandIK)
                            {
                                anim.SetIKPosition(AvatarIKGoal.LeftHand, ikv.leftHandIK.position);
                                anim.SetIKRotation(AvatarIKGoal.LeftHand, ikv.leftHandIK.rotation);
                            }
                            if (!runtimeData.switchInProgress && ikv.canUseIK && ikv.leftHandIK)
                            {
                                runtimeData.leftHandIKWeight = Mathf.Lerp(runtimeData.leftHandIKWeight, 1f, Time.deltaTime * 3);
                            }
                            else
                            {
                                runtimeData.leftHandIKWeight = Mathf.Lerp(runtimeData.leftHandIKWeight, 0f, Time.deltaTime * 20);
                            }
                            anim.SetIKPositionWeight(AvatarIKGoal.LeftHand, runtimeData.leftHandIKWeight);
                            anim.SetIKRotationWeight(AvatarIKGoal.LeftHand, runtimeData.leftHandIKWeight);
                        }
                        else
                        {
                            runtimeData.leftHandIKWeight = Mathf.Lerp(runtimeData.leftHandIKWeight, 0f, Time.deltaTime * 20);
                            anim.SetIKPositionWeight(AvatarIKGoal.LeftHand, runtimeData.leftHandIKWeight);
                            anim.SetIKRotationWeight(AvatarIKGoal.LeftHand, runtimeData.leftHandIKWeight);
                        }
                    }

                }
                else
                {
                    Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                    if (anim)
                    {
                        //Get Weapon IK
                        WeaponIKValues ikv = null;

                        if (runtimeData.quickUseInProgress && runtimeData.quickUseState > 0 && runtimeData.quickUseState < 4)
                        {
                            ikv = runtimeData.weaponsInUseDataObjects[runtimeData.desiredQuickUse].behaviour.GetIK(pb, anim, runtimeData.weaponsInUseDataObjects[runtimeData.desiredQuickUse]);
                        }
                        else
                        {
                            ikv = runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.GetIK(pb, anim, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]);
                        }

                        if (ikv != null)
                        {
                            if (ikv.leftHandIK)
                            {
                                anim.SetIKPosition(AvatarIKGoal.LeftHand, ikv.leftHandIK.position);
                                anim.SetIKRotation(AvatarIKGoal.LeftHand, ikv.leftHandIK.rotation);
                            }
                            if (!runtimeData.switchInProgress && ikv.canUseIK && ikv.leftHandIK)
                            {
                                runtimeData.leftHandIKWeight = Mathf.Lerp(runtimeData.leftHandIKWeight, 1f, Time.deltaTime * 3);
                            }
                            else
                            {
                                runtimeData.leftHandIKWeight = Mathf.Lerp(runtimeData.leftHandIKWeight, 0f, Time.deltaTime * 20);
                            }
                            anim.SetIKPositionWeight(AvatarIKGoal.LeftHand, runtimeData.leftHandIKWeight);
                            anim.SetIKRotationWeight(AvatarIKGoal.LeftHand, runtimeData.leftHandIKWeight);
                        }
                        else
                        {
                            runtimeData.leftHandIKWeight = Mathf.Lerp(runtimeData.leftHandIKWeight, 0f, Time.deltaTime * 20);
                            anim.SetIKPositionWeight(AvatarIKGoal.LeftHand, runtimeData.leftHandIKWeight);
                            anim.SetIKRotationWeight(AvatarIKGoal.LeftHand, runtimeData.leftHandIKWeight);
                        }
                    }

                }
            }

            public override void FallDownEffect(Kit_PlayerBehaviour pb, bool wasFallDamageApplied)
            {
                if (pb.isBot) return;
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                if (runtimeData.weaponsInUseDataObjects.Length <= runtimeData.currentWeapon) return;
                if (!runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]) return;
                if (!runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour) return;
                runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.FallDownEffect(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon], wasFallDamageApplied);

            }

            public override void OnControllerColliderHitRelay(Kit_PlayerBehaviour pb, ControllerColliderHit hit)
            {
                if (!pb.weaponManagerNetworkData) return;
                //Get runtime data
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                if (runtimeData.weaponsInUseDataObjects.Length <= runtimeData.currentWeapon) return;
                if (!runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]) return;
                if (!runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour) return;
                runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.OnControllerColliderHitCallback(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon], hit);
            }

            public override void NetworkSemiRPCReceived(Kit_PlayerBehaviour pb)
            {
                if (!pb.weaponManagerNetworkData) return;
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                if (runtimeData.weaponsInUseDataObjects.Length <= runtimeData.currentWeapon) return;
                if (!runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]) return;
                if (!runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour) return;
                //Relay to weapon script
                runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.NetworkSemiRPCReceived(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]);
            }

            public override void NetworkBoltActionRPCReceived(Kit_PlayerBehaviour pb, int state)
            {
                if (!pb.weaponManagerNetworkData) return;
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                if (runtimeData.weaponsInUseDataObjects.Length <= runtimeData.currentWeapon) return;
                if (!runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]) return;
                if (!runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour) return;
                //Relay to weapon script
                runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.NetworkBoltActionRPCReceived(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon], state);
            }

            public override void NetworkBurstRPCReceived(Kit_PlayerBehaviour pb, int burstLength)
            {
                if (!pb.weaponManagerNetworkData) return;
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                if (runtimeData.weaponsInUseDataObjects.Length <= runtimeData.currentWeapon) return;
                if (!runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]) return;
                if (!runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour) return;
                //Relay to weapon script
                runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.NetworkBurstRPCReceived(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon], burstLength);
            }

            public override void NetworkReloadRPCReceived(Kit_PlayerBehaviour pb, bool isEmpty)
            {
                if (!pb.weaponManagerNetworkData) return;
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                if (runtimeData.weaponsInUseDataObjects.Length <= runtimeData.currentWeapon) return;
                if (!runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]) return;
                if (!runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour) return;
                //Relay to weapon script
                runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.NetworkReloadRPCReceived(pb, isEmpty, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]);

            }

            public override void NetworkProceduralReloadRPCReceived(Kit_PlayerBehaviour pb, int stage)
            {
                if (!pb.weaponManagerNetworkData) return;
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                if (runtimeData.weaponsInUseDataObjects.Length <= runtimeData.currentWeapon) return;
                if (!runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]) return;
                if (!runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour) return;
                //Relay to weapon script
                runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.NetworkProceduralReloadRPCReceived(pb, stage, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]);

            }

            public override void NetworkMeleeChargeRPCReceived(Kit_PlayerBehaviour pb, int state, int slot)
            {
                if (!pb.weaponManagerNetworkData) return;
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                if (runtimeData.weaponsInUseDataObjects.Length <= runtimeData.currentWeapon) return;
                if (!runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]) return;
                if (!runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour) return;
                //Relay to weapon script
                runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.NetworkMeleeChargeRPCReceived(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon], state, slot);

            }

            public override void NetworkMeleeHealRPCReceived(Kit_PlayerBehaviour pb, int slot)
            {
                if (!pb.weaponManagerNetworkData) return;
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                if (runtimeData.weaponsInUseDataObjects.Length <= runtimeData.currentWeapon) return;
                if (!runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]) return;
                if (!runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour) return;
                //Relay to weapon script
                runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.NetworkMeleeHealRPCReceived(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon], slot);
            }

            public override void NetworkMeleeStabRPCReceived(Kit_PlayerBehaviour pb, int state, int slot)
            {
                if (!pb.weaponManagerNetworkData) return;
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                if (runtimeData.weaponsInUseDataObjects.Length <= runtimeData.currentWeapon) return;
                if (!runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]) return;
                if (!runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour) return;
                //Relay to weapon script
                runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.NetworkMeleeStabRPCReceived(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon], state, slot);
            }

            public override void NetworkGrenadePullPinRPCReceived(Kit_PlayerBehaviour pb)
            {
                if (!pb.weaponManagerNetworkData) return;
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                if (runtimeData.weaponsInUseDataObjects.Length <= runtimeData.currentWeapon) return;
                if (!runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]) return;
                if (!runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour) return;
                //Relay to weapon script
                runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.NetworkGrenadePullPinRPCReceived(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]);
            }

            public override void NetworkGrenadeThrowRPCReceived(Kit_PlayerBehaviour pb)
            {
                if (!pb.weaponManagerNetworkData) return;
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                if (runtimeData.weaponsInUseDataObjects.Length <= runtimeData.currentWeapon) return;
                if (!runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]) return;
                if (!runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour) return;
                //Relay to weapon script
                runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.NetworkGrenadeThrowRPCReceived(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]);
            }

            public override float GetAimingPercentage(Kit_PlayerBehaviour pb)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                return runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.GetAimingPercentage(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]); //Relay to weapon script
            }

            public override bool IsAiming(Kit_PlayerBehaviour pb)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                return runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.IsWeaponAiming(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]); //Relay to weapon script
            }

            public override float AimInTime(Kit_PlayerBehaviour pb)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                return runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.AimInTime(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]); //Relay to weapon script
            }

            public override bool ForceIntoFirstPerson(Kit_PlayerBehaviour pb)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                return runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.ForceIntoFirstPerson(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]); //Relay to weapon script
            }

            public override bool CanRun(Kit_PlayerBehaviour pb)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                if (allowSwitchingWhileRunning) return true;
                else return !runtimeData.switchInProgress;
            }

            public override float CurrentMovementMultiplier(Kit_PlayerBehaviour pb)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                return runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.SpeedMultiplier(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]); //Relay to weapon script
            }

            public override float CurrentSensitivity(Kit_PlayerBehaviour pb)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                return runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.Sensitivity(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]); //Relay to weapon script
            }

            public override int GetCurrentWeapon(Kit_PlayerBehaviour pb)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                //Just return ID
                return runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].id;
            }

            public override int HasWeapon(Kit_PlayerBehaviour pb, int id)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;

                for (int i = 0; i < runtimeData.weaponsInUseDataObjects.Length; i++)
                {
                    if (runtimeData.weaponsInUseDataObjects[i].id == id)
                    {
                        return i;
                    }
                }

                return -1;
            }

            public override Kit_WeaponRuntimeDataBase GetRuntimeDataOfWeapon(Kit_PlayerBehaviour pb, int slot)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                //Just return ID
                return runtimeData.weaponsInUseDataObjects[slot];
            }

            public override bool CanBuyWeapon(Kit_PlayerBehaviour pb, int id)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;

                for (int i = 0; i < runtimeData.weaponsInUseDataObjects.Length; i++)
                {
                    if (runtimeData.weaponsInUseDataObjects[i].id == id)
                    {
                        //Special case for grenades - let us buy more grenades if we are below that #
                        if (runtimeData.weaponsInUseDataObjects[i] != null && runtimeData.weaponsInUseDataObjects[i].GetType() == typeof(Kit_ModernGrenadeScriptRuntimeData))
                        {
                            Kit_ModernGrenadeScriptRuntimeData gcrd = runtimeData.weaponsInUseDataObjects[i] as Kit_ModernGrenadeScriptRuntimeData;
                            Kit_ModernGrenadeScript grenadeData = runtimeData.weaponsInUseDataObjects[i].behaviour as Kit_ModernGrenadeScript;

                            if (gcrd.amountOfGrenadesLeft < grenadeData.amountOfGrenadesAtStart)
                            {
                                return true;
                            }

                        }

                        return false;
                    }

                }

                //Can buy
                return true;
            }

            public override void NetworkReplaceWeapon(Kit_PlayerBehaviour pb, int slot, int weapon, int bulletsLeft, int bulletsLeftToReload, int[] attachments)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;

                GameObject spawnObject = Kit_IngameMain.instance.gameInformation.allWeapons[weapon].SetupSpawnData(pb, slot, new LoadoutWeapon { weaponID = weapon, attachments = attachments });

                Kit_WeaponRuntimeDataBase wrdb = spawnObject.GetComponent<Kit_WeaponRuntimeDataBase>();

                if (wrdb is Kit_ModernWeaponScriptRuntimeData)
                {
                    Kit_ModernWeaponScriptRuntimeData mwsrd = wrdb as Kit_ModernWeaponScriptRuntimeData;
                    mwsrd.bulletsLeft = bulletsLeft;
                    mwsrd.bulletsLeftToReload = bulletsLeftToReload;
                }

                NetworkServer.Spawn(spawnObject, pb.gameObject);
                NetworkIdentity id = spawnObject.GetComponent<NetworkIdentity>();

                NetworkIdentity oldIdentity = NetworkServer.spawned[runtimeData.weaponsInUseSync[slot]];

                if (oldIdentity)
                {
                    NetworkServer.Destroy(oldIdentity.gameObject);
                }

                runtimeData.weaponsInUseSync[slot] = id.netId;
            }

            public override void NetworkPhysicalBulletFired(Kit_PlayerBehaviour pb, Vector3 pos, Vector3 dir)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                if (runtimeData.weaponsInUseDataObjects.Length > runtimeData.currentWeapon)
                    //Relay to weapon script
                    runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.NetworkPhysicalBulletFired(pb, pos, dir, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]);
            }


            public override void DropWeapon(Kit_PlayerBehaviour pb, int slot)
            {
                if ((Kit_IngameMain.instance.currentPvPGameModeBehaviour && Kit_IngameMain.instance.currentPvPGameModeBehaviour.CanDropWeapons()) || (Kit_IngameMain.instance.currentPvEGameModeBehaviour && Kit_IngameMain.instance.currentPvEGameModeBehaviour.CanDropWeapons()))
                {
                    if (pb.weaponManagerNetworkData != null && pb.weaponManagerNetworkData.GetType() == typeof(Kit_ModernWeaponManagerNetworkData))
                    {
                        //Get the manager's runtime data
                        Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                        if (runtimeData.weaponsInUseDataObjects[slot] != null && runtimeData.weaponsInUseDataObjects[slot].GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                        {
                            //Get the weapon's runtime data
                            Kit_ModernWeaponScriptRuntimeData wepData = runtimeData.weaponsInUseDataObjects[slot] as Kit_ModernWeaponScriptRuntimeData;
                            //Get the Scriptable object
                            Kit_ModernWeaponScript wepScript = runtimeData.weaponsInUseDataObjects[slot].behaviour as Kit_ModernWeaponScript;
                            //Instantiate
                            GameObject go = Instantiate(dropPrefab, pb.playerCameraTransform.position, pb.playerCameraTransform.rotation);
                            Kit_DropBehaviour dp = go.GetComponent<Kit_DropBehaviour>();
                            dp.isSceneOwned = true;
                            dp.weaponID = wepScript.gameGunID;
                            dp.bulletsLeft = wepData.bulletsLeft;
                            dp.bulletsLeftToReload = wepData.bulletsLeftToReload;

                            for (int i = 0; i < wepData.attachments.Count; i++)
                            {
                                dp.attachments.Add(wepData.attachments[i]);
                            }

                            NetworkServer.Spawn(go);
                        }
                        else if (runtimeData.weaponsInUseDataObjects[slot] != null && runtimeData.weaponsInUseDataObjects[slot].GetType() == typeof(Kit_ModernMeleeScriptRuntimeData))
                        {
                            //Get the weapon's runtime data
                            Kit_ModernMeleeScriptRuntimeData wepData = runtimeData.weaponsInUseDataObjects[slot] as Kit_ModernMeleeScriptRuntimeData;
                            //Get the Scriptable object
                            Kit_ModernMeleeScript wepScript = runtimeData.weaponsInUseDataObjects[slot].behaviour as Kit_ModernMeleeScript;
                            //Instantiate
                            GameObject go = Instantiate(dropPrefab, pb.playerCameraTransform.position, pb.playerCameraTransform.rotation);
                            Kit_DropBehaviour dp = go.GetComponent<Kit_DropBehaviour>();
                            dp.isSceneOwned = true;
                            dp.weaponID = wepScript.gameGunID;
                            dp.bulletsLeft = 0;
                            dp.bulletsLeftToReload = 0;

                            for (int i = 0; i < wepData.attachments.Count; i++)
                            {
                                dp.attachments.Add(wepData.attachments[i]);
                            }

                            NetworkServer.Spawn(go);
                        }
                        else if (runtimeData.weaponsInUseDataObjects[slot] != null && runtimeData.weaponsInUseDataObjects[slot].GetType() == typeof(Kit_ModernGrenadeScriptRuntimeData))
                        {
                            //Get the weapon's runtime data
                            Kit_ModernGrenadeScriptRuntimeData wepData = runtimeData.weaponsInUseDataObjects[slot] as Kit_ModernGrenadeScriptRuntimeData;
                            if (wepData.amountOfGrenadesLeft <= 0) return;
                            //Get the Scriptable object
                            Kit_ModernGrenadeScript wepScript = runtimeData.weaponsInUseDataObjects[slot].behaviour as Kit_ModernGrenadeScript;
                            //Instantiate
                            GameObject go = Instantiate(dropPrefab, pb.playerCameraTransform.position, pb.playerCameraTransform.rotation);
                            Kit_DropBehaviour dp = go.GetComponent<Kit_DropBehaviour>();
                            dp.isSceneOwned = true;
                            dp.weaponID = wepScript.gameGunID;
                            dp.bulletsLeft = 0;
                            dp.bulletsLeftToReload = 0;

                            for (int i = 0; i < wepData.attachments.Count; i++)
                            {
                                dp.attachments.Add(wepData.attachments[i]);
                            }

                            NetworkServer.Spawn(go);
                        }
                    }
                }
            }

            /// <summary>
            /// Drops a weapon and applies the ragdoll force!
            /// </summary>
            /// <param name="pb"></param>
            /// <param name="slot"></param>
            public void DropWeaponDead(Kit_PlayerBehaviour pb, int slot)
            {
                if ((Kit_IngameMain.instance.currentPvPGameModeBehaviour && Kit_IngameMain.instance.currentPvPGameModeBehaviour.CanDropWeapons()) || (Kit_IngameMain.instance.currentPvEGameModeBehaviour && Kit_IngameMain.instance.currentPvEGameModeBehaviour.CanDropWeapons()))
                {
                    if (pb.weaponManagerNetworkData != null && pb.weaponManagerNetworkData.GetType() == typeof(Kit_ModernWeaponManagerNetworkData))
                    {
                        //Get the manager's runtime data
                        Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                        if (runtimeData.weaponsInUseDataObjects[slot] != null && runtimeData.weaponsInUseDataObjects[slot].GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                        {
                            //Get the weapon's runtime data
                            Kit_ModernWeaponScriptRuntimeData wepData = runtimeData.weaponsInUseDataObjects[slot] as Kit_ModernWeaponScriptRuntimeData;
                            //Get the Scriptable object
                            Kit_ModernWeaponScript wepScript = runtimeData.weaponsInUseDataObjects[slot].behaviour as Kit_ModernWeaponScript;
                            //Instantiate
                            GameObject go = Instantiate(dropPrefab, pb.playerCameraTransform.position, pb.playerCameraTransform.rotation);
                            Kit_DropBehaviour dp = go.GetComponent<Kit_DropBehaviour>();
                            dp.isSceneOwned = true;
                            dp.weaponID = wepScript.gameGunID;
                            dp.bulletsLeft = wepData.bulletsLeft;
                            dp.bulletsLeftToReload = wepData.bulletsLeftToReload;

                            for (int i = 0; i < wepData.attachments.Count; i++)
                            {
                                dp.attachments.Add(wepData.attachments[i]);
                            }

                            NetworkServer.Spawn(go);
                            Rigidbody body = go.GetComponent<Rigidbody>();
                            if (body)
                            {
                                body.velocity = pb.movement.GetVelocity(pb);
                                body.AddForceNextFrame(pb.ragdollForward * pb.ragdollForce / 10);
                            }
                        }
                        else if (runtimeData.weaponsInUseDataObjects[slot] != null && runtimeData.weaponsInUseDataObjects[slot].GetType() == typeof(Kit_ModernMeleeScriptRuntimeData))
                        {
                            //Get the weapon's runtime data
                            Kit_ModernMeleeScriptRuntimeData wepData = runtimeData.weaponsInUseDataObjects[slot] as Kit_ModernMeleeScriptRuntimeData;
                            //Get the Scriptable object
                            Kit_ModernMeleeScript wepScript = runtimeData.weaponsInUseDataObjects[slot].behaviour as Kit_ModernMeleeScript;
                            //Instantiate
                            GameObject go = Instantiate(dropPrefab, pb.playerCameraTransform.position, pb.playerCameraTransform.rotation);
                            Kit_DropBehaviour dp = go.GetComponent<Kit_DropBehaviour>();
                            dp.isSceneOwned = true;
                            dp.weaponID = wepScript.gameGunID;
                            dp.bulletsLeft = 0;
                            dp.bulletsLeftToReload = 0;

                            for (int i = 0; i < wepData.attachments.Count; i++)
                            {
                                dp.attachments.Add(wepData.attachments[i]);
                            }

                            NetworkServer.Spawn(go);
                            Rigidbody body = go.GetComponent<Rigidbody>();
                            if (body)
                            {
                                body.velocity = pb.movement.GetVelocity(pb);
                                body.AddForceNextFrame(pb.ragdollForward * pb.ragdollForce / 10);
                            }
                        }
                        else if (runtimeData.weaponsInUseDataObjects[slot] != null && runtimeData.weaponsInUseDataObjects[slot].GetType() == typeof(Kit_ModernGrenadeScriptRuntimeData))
                        {
                            //Get the weapon's runtime data
                            Kit_ModernGrenadeScriptRuntimeData wepData = runtimeData.weaponsInUseDataObjects[slot] as Kit_ModernGrenadeScriptRuntimeData;
                            if (wepData.amountOfGrenadesLeft <= 0) return;
                            //Get the Scriptable object
                            Kit_ModernGrenadeScript wepScript = runtimeData.weaponsInUseDataObjects[slot].behaviour as Kit_ModernGrenadeScript;
                            //Instantiate
                            GameObject go = Instantiate(dropPrefab, pb.playerCameraTransform.position, pb.playerCameraTransform.rotation);
                            Kit_DropBehaviour dp = go.GetComponent<Kit_DropBehaviour>();
                            dp.isSceneOwned = true;
                            dp.weaponID = wepScript.gameGunID;
                            dp.bulletsLeft = 0;
                            dp.bulletsLeftToReload = 0;

                            for (int i = 0; i < wepData.attachments.Count; i++)
                            {
                                dp.attachments.Add(wepData.attachments[i]);
                            }

                            NetworkServer.Spawn(go);
                            Rigidbody body = go.GetComponent<Rigidbody>();
                            if (body)
                            {
                                body.velocity = pb.movement.GetVelocity(pb);
                                body.AddForceNextFrame(pb.ragdollForward * pb.ragdollForce / 10);
                            }
                        }
                    }
                }
            }

            public override void DropWeapon(Kit_PlayerBehaviour pb, int slot, Transform replace)
            {
                if (pb.weaponManagerNetworkData != null && pb.weaponManagerNetworkData.GetType() == typeof(Kit_ModernWeaponManagerNetworkData))
                {
                    //Get the manager's runtime data
                    Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                    if (runtimeData.weaponsInUseDataObjects[slot] != null && runtimeData.weaponsInUseDataObjects[slot].GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                    {
                        //Get the weapon's runtime data
                        Kit_ModernWeaponScriptRuntimeData wepData = runtimeData.weaponsInUseDataObjects[slot] as Kit_ModernWeaponScriptRuntimeData;
                        //Get the Scriptable object
                        Kit_ModernWeaponScript wepScript = runtimeData.weaponsInUseDataObjects[slot].behaviour as Kit_ModernWeaponScript;
                        //Instantiate
                        GameObject go = Instantiate(dropPrefab, replace.position, replace.rotation);
                        Kit_DropBehaviour dp = go.GetComponent<Kit_DropBehaviour>();
                        dp.isSceneOwned = true;
                        dp.weaponID = wepScript.gameGunID;
                        dp.bulletsLeft = wepData.bulletsLeft;
                        dp.bulletsLeftToReload = wepData.bulletsLeftToReload;

                        for (int i = 0; i < wepData.attachments.Count; i++)
                        {
                            dp.attachments.Add(wepData.attachments[i]);
                        }

                        NetworkServer.Spawn(go);
                    }
                    else if (runtimeData.weaponsInUseDataObjects[slot] != null && runtimeData.weaponsInUseDataObjects[slot].GetType() == typeof(Kit_ModernMeleeScriptRuntimeData))
                    {
                        //Get the weapon's runtime data
                        Kit_ModernMeleeScriptRuntimeData wepData = runtimeData.weaponsInUseDataObjects[slot] as Kit_ModernMeleeScriptRuntimeData;
                        //Get the Scriptable object
                        Kit_ModernMeleeScript wepScript = runtimeData.weaponsInUseDataObjects[slot].behaviour as Kit_ModernMeleeScript;
                        //Instantiate
                        GameObject go = Instantiate(dropPrefab, replace.position, replace.rotation);
                        Kit_DropBehaviour dp = go.GetComponent<Kit_DropBehaviour>();
                        dp.isSceneOwned = true;
                        dp.weaponID = wepScript.gameGunID;
                        dp.bulletsLeft = 0;
                        dp.bulletsLeftToReload = 0;

                        for (int i = 0; i < wepData.attachments.Count; i++)
                        {
                            dp.attachments.Add(wepData.attachments[i]);
                        }

                        NetworkServer.Spawn(go);
                    }
                    else if (runtimeData.weaponsInUseDataObjects[slot] != null && runtimeData.weaponsInUseDataObjects[slot].GetType() == typeof(Kit_ModernGrenadeScriptRuntimeData))
                    {
                        //Get the weapon's runtime data
                        Kit_ModernGrenadeScriptRuntimeData wepData = runtimeData.weaponsInUseDataObjects[slot] as Kit_ModernGrenadeScriptRuntimeData;
                        if (wepData.amountOfGrenadesLeft <= 0) return;
                        //Get the Scriptable object
                        Kit_ModernGrenadeScript wepScript = runtimeData.weaponsInUseDataObjects[slot].behaviour as Kit_ModernGrenadeScript;
                        //Instantiate
                        GameObject go = Instantiate(dropPrefab, replace.position, replace.rotation);
                        Kit_DropBehaviour dp = go.GetComponent<Kit_DropBehaviour>();
                        dp.isSceneOwned = true;
                        dp.weaponID = wepScript.gameGunID;
                        dp.bulletsLeft = 0;
                        dp.bulletsLeftToReload = 0;

                        for (int i = 0; i < wepData.attachments.Count; i++)
                        {
                            dp.attachments.Add(wepData.attachments[i]);
                        }

                        NetworkServer.Spawn(go);
                    }
                }
            }

            public override int WeaponState(Kit_PlayerBehaviour pb)
            {
                //Get the manager's runtime data
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                return runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.WeaponState(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]);
            }

            public override int WeaponType(Kit_PlayerBehaviour pb)
            {
                //Get the manager's runtime data
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                return runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.GetWeaponType(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]);
            }

            public override void FirstThirdPersonChanged(Kit_PlayerBehaviour pb, Kit_GameInformation.Perspective perspective)
            {
                if (pb.syncSetup)
                {
                    //Forward to currently selected weapon
                    Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                    if (runtimeData.quickUseInProgress && runtimeData.quickUseState > 0 && runtimeData.quickUseState < 4)
                    {
                        runtimeData.weaponsInUseDataObjects[runtimeData.desiredQuickUse].behaviour.FirstThirdPersonChanged(pb, perspective, runtimeData.weaponsInUseDataObjects[runtimeData.desiredQuickUse]);
                    }
                    else
                    {
                        runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.FirstThirdPersonChanged(pb, perspective, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]);
                    }
                }
            }

            public override void OnAmmoPickup(Kit_PlayerBehaviour pb, Kit_AmmoPickup pickup)
            {
                //Forward to currently selected weapon
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.OnAmmoPickup(pb, pickup, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]);
            }

            public override void RestockAmmo(Kit_PlayerBehaviour pb, bool allWeapons)
            {
                if (pb.isServer)
                {
                    if (pb.weaponManagerNetworkData != null && pb.weaponManagerNetworkData.GetType() == typeof(Kit_ModernWeaponManagerNetworkData))
                    {
                        if (allWeapons)
                        {
                            Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                            for (int i = 0; i < runtimeData.weaponsInUseDataObjects.Length; i++)
                            {
                                runtimeData.weaponsInUseDataObjects[i].behaviour.RestockAmmo(pb, runtimeData.weaponsInUseDataObjects[i]);
                            }
                        }
                        else
                        {
                            //Forward to currently selected weapon
                            Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                            runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.RestockAmmo(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]);
                        }
                    }
                }
            }

            public override bool IsCurrentWeaponFull(Kit_PlayerBehaviour pb)
            {
                //Forward to currently selected weapon
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                return runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon].behaviour.IsWeaponFull(pb, runtimeData.weaponsInUseDataObjects[runtimeData.currentWeapon]);
            }

            public override void PluginSelectWeapon(Kit_PlayerBehaviour pb, int slot, bool locked = true)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                //Just set, thats all!
                runtimeData.desiredWeapon = slot;
                runtimeData.isDesiredWeaponLocked = locked;
            }

            public override int GetCurrentlyDesiredWeapon(Kit_PlayerBehaviour pb)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                return runtimeData.desiredWeapon;
            }

            public override int GetCurrentlyDesiredQuickUse(Kit_PlayerBehaviour pb)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                return runtimeData.desiredQuickUse;
            }

            public override int GetCurrentlySelectedWeapon(Kit_PlayerBehaviour pb)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                return runtimeData.currentWeapon;
            }

            public override void SetDesiredWeapon(Kit_PlayerBehaviour pb, int desiredWeapon)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;
                if (runtimeData.weaponsInUseDataObjects[desiredWeapon].behaviour.CanBeSelected(pb, runtimeData.weaponsInUseDataObjects[desiredWeapon]))
                {
                    runtimeData.desiredWeapon = desiredWeapon;

                }
            }

            public override int[] GetSlotsWithEmptyWeapon(Kit_PlayerBehaviour pb)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;

                List<int> emptySlots = new List<int>();

                for (int i = 0; i < runtimeData.weaponsInUseDataObjects.Length; i++)
                {
                    //Check if that slot contains a placehodler weapon
                    if (runtimeData.weaponsInUseDataObjects[i].behaviour.GetType() == typeof(Kit_WeaponUnselectable))
                    {
                        int id = i;
                        //Add it to list of empty slots
                        emptySlots.Add(id);
                    }
                }

                return emptySlots.ToArray();
            }

            public override void BeginSpectating(Kit_PlayerBehaviour pb)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;

                for (int i = 0; i < runtimeData.weaponsInUseDataObjects.Length; i++)
                {
                    //Relay
                    runtimeData.weaponsInUseDataObjects[i].behaviour.BeginSpectating(pb, runtimeData.weaponsInUseDataObjects[i], runtimeData.weaponsInUseDataObjects[i].attachments.ToArray());
                }
            }

            public override void EndSpectating(Kit_PlayerBehaviour pb)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;

                for (int i = 0; i < runtimeData.weaponsInUseDataObjects.Length; i++)
                {
                    //Relay
                    runtimeData.weaponsInUseDataObjects[i].behaviour.EndSpectating(pb, runtimeData.weaponsInUseDataObjects[i]);
                }
            }

            public override void OnTriggerEnterRelay(Kit_PlayerBehaviour pb, Collider col)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;

                for (int i = 0; i < runtimeData.weaponsInUseDataObjects.Length; i++)
                {
                    if (runtimeData.weaponsInUseDataObjects[i].behaviour)
                    {
                        //Relay
                        runtimeData.weaponsInUseDataObjects[i].behaviour.OnTriggerEnterRelay(pb, runtimeData.weaponsInUseDataObjects[i], col);
                    }
                }
            }

            public override void OnTriggerExitRelay(Kit_PlayerBehaviour pb, Collider col)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;

                for (int i = 0; i < runtimeData.weaponsInUseDataObjects.Length; i++)
                {
                    if (runtimeData.weaponsInUseDataObjects[i].behaviour)
                    {
                        //Relay
                        runtimeData.weaponsInUseDataObjects[i].behaviour.OnTriggerExitRelay(pb, runtimeData.weaponsInUseDataObjects[i], col);
                    }
                }
            }

            public override void OnDestroyRelay(Kit_PlayerBehaviour pb)
            {
                Kit_ModernWeaponManagerNetworkData runtimeData = pb.weaponManagerNetworkData as Kit_ModernWeaponManagerNetworkData;

                for (int i = 0; i < runtimeData.weaponsInUseDataObjects.Length; i++)
                {
                    if (runtimeData.weaponsInUseDataObjects[i].behaviour)
                    {
                        //Relay
                        runtimeData.weaponsInUseDataObjects[i].behaviour.OnDestroyRelay(pb, runtimeData.weaponsInUseDataObjects[i]);
                    }
                }
            }
        }
    }
}
using Mirror;
using System;
using System.Collections.Generic;
using UnityEngine;

namespace MarsFPSKit
{
    namespace Weapons
    {
        public class Kit_ModernWeaponManagerNetworkData : Kit_WeaponManagerNetworkBase
        {
            /// <summary>
            /// Our currently selected weapon; [0] = slot; [1] = weapon In Slot
            /// </summary>
            public int currentWeapon;
            [SyncVar]
            /// <summary>
            /// The weapon we want to select
            /// </summary>
            public int desiredWeapon;
            [System.NonSerialized]
            /// <summary>
            /// Desired weapon is locked (by plugin?)
            /// </summary>
            public bool isDesiredWeaponLocked;
            [SyncVar]
            /// <summary>
            /// Is a quick use in progress?
            /// </summary>
            public bool quickUseInProgress;
            [SyncVar]
            /// <summary>
            /// Quick use that we want to do!
            /// </summary>
            public int desiredQuickUse;
            [System.NonSerialized]
            /// <summary>
            /// Current state of quick use.
            /// </summary>
            public int quickUseState;
            [System.NonSerialized]
            /// <summary>
            /// When is the next quick use state over?
            /// </summary>
            public float quickUseOverAt;
            [SyncVar]
            /// <summary>
            /// Sync!
            /// </summary>
            public bool quickUseSyncButtonWaitOver;
            /// <summary>
            /// These are the network ids of our weapon's prefabs that co-exist with out player
            /// </summary>
            public readonly SyncList<uint> weaponsInUseSync = new SyncList<uint>();
            /// <summary>
            /// Stores the objects of our list
            /// </summary>
            public Kit_WeaponRuntimeDataBase[] weaponsInUseDataObjects = new Kit_WeaponRuntimeDataBase[0];
            [System.NonSerialized]
            /// <summary>
            /// Last states for the slot buttons!
            /// </summary>
            public bool[] lastInputIDs;
            [System.NonSerialized]
            /// <summary>
            /// Last state for the drop weapon
            /// </summary>
            public bool lastInteract;
            [System.NonSerialized]
            /// <summary>
            /// Are we currently switching weapons?
            /// </summary>
            public bool switchInProgress;
            [System.NonSerialized]
            /// <summary>
            /// When is the next switching phase over?
            /// </summary>
            public float switchNextEnd; //This is only so we don't have to use a coroutine
            [System.NonSerialized]
            /// <summary>
            /// The current phase of switching
            /// </summary>
            public int switchPhase;
            [System.NonSerialized]
            /// <summary>
            /// Raycast hit for the pickup process
            /// </summary>
            public RaycastHit hit;
            [System.NonSerialized]
            /// <summary>
            /// To fire the interaction end trigger
            /// We store the object we are currently interacting with
            /// </summary>
            public Kit_InteractableObject holdingInteractableObject;

            private void Start()
            {
                weaponsInUseSync.OnChange += OnWeaponsInUseSyncCallback;
            }

            private void OnWeaponsInUseSyncCallback(SyncList<uint>.Operation operation, int index, uint item)
            {
                //Make sure its assigned
                //Shouldn't happen..
                //But just in case, it should fix itself.
                if (!ownerPlayer)
                {
                    if (NetworkServer.active)
                    {
                        if (NetworkServer.spawned.ContainsKey(ownerPlayerNetworkId))
                        {
                            Kit_PlayerBehaviour pb = NetworkServer.spawned[ownerPlayerNetworkId].GetComponent<Kit_PlayerBehaviour>();
                            pb.weaponManagerNetworkData = this;
                            ownerPlayer = pb;
                        }
                    }
                    else
                    {
                        if (NetworkClient.spawned.ContainsKey(ownerPlayerNetworkId))
                        {
                            Kit_PlayerBehaviour pb = NetworkClient.spawned[ownerPlayerNetworkId].GetComponent<Kit_PlayerBehaviour>();
                            pb.weaponManagerNetworkData = this;
                            ownerPlayer = pb;
                        }
                    }
                }

                if (ownerPlayer)
                {
                    ownerPlayer.weaponManager.OnWeaponsInUseSyncCallback(ownerPlayer, operation, index, item);
                }
            }

            public Kit_WeaponRuntimeDataBase GetWeapon(int index)
            {
                if (weaponsInUseDataObjects.Length == 0)
                {
                    weaponsInUseDataObjects = new Kit_WeaponRuntimeDataBase[weaponsInUseSync.Count];

                    //Rebuild list
                    for (int i = 0; i < weaponsInUseSync.Count; i++)
                    {
                        int saved_i = i;
                        NetworkIdentity id = NetworkClient.spawned[weaponsInUseSync[i]];

                        if (id)
                        {
                            weaponsInUseDataObjects[saved_i] = id.GetComponent<Kit_WeaponRuntimeDataBase>();
                        }
                        else
                        {
                            //Didn't find it. This shouldn't happen!
                            weaponsInUseDataObjects[saved_i] = null;
                        }
                    }
                }

                return weaponsInUseDataObjects[index];
            }

            private void OnDestroy()
            {
                if (NetworkServer.active)
                {
                    for (int i = 0; i < weaponsInUseDataObjects.Length; i++)
                    {
                        if (weaponsInUseDataObjects[i])
                        {
                            NetworkServer.Destroy(weaponsInUseDataObjects[i].gameObject);
                        }
                    }
                }
            }

            #region IK
            [System.NonSerialized]
            /// <summary>
            /// Weight of the left hand IK
            /// </summary>
            public float leftHandIKWeight;
            #endregion
        }
    }
}

using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Serialization;

namespace MarsFPSKit
{
    namespace Weapons
    {
        #region enums
        public enum FireMode { Semi, Auto, Burst, BoltAction };
        public enum FireTypeMode { Simple, Pellets }
        public enum BulletMode { Raycast, Physical }
        public enum ReloadMode { Simple, FullEmpty, Chambered, Procedural, ProceduralChambered }
        public enum SpreadMode { Simple, SprayPattern }
        #endregion

        [CreateAssetMenu(menuName = ("MarsFPSKit/Weapons/Modern Weapon Script"))]
        public class Kit_ModernWeaponScript : Kit_WeaponBase
        {
            [Header("Spring")]
            /// <summary>
            /// Config for positional spring
            /// </summary>
            public Kit_Spring.SpringConfig springPosConfig;
            /// <summary>
            /// Config for rotational spring
            /// </summary>
            public Kit_Spring.SpringConfig springRotConfig;

            #region Settings
            [Header("Settings")]
            public FireMode fireMode = FireMode.Semi;
            /// <summary>
            /// How many rounds per minute does this weapon shoot?
            /// </summary>
            public int RPM = 600;
            private float fireRate = 0.1f;
            /// <summary>
            /// How many bullets do we have per mag
            /// </summary>
            public int bulletsPerMag = 30;
            /// <summary>
            /// With how many <see cref="WeaponControllerRuntimeData.bulletsLeftToReload"/> do we start?
            /// </summary>
            public int bulletsToReloadAtStart = 60;
            /// <summary>
            /// How much damage does this weapon deal?
            /// </summary>
            public float baseDamage = 30f;
            /// <summary>
            /// The max. range of this weapon
            /// </summary>
            public float range = 500f;
            /// <summary>
            /// This is the damage drop off relative to <see cref="range"/>. It should be a value between 0 and 1 that multiplies with <see cref="baseDamage"/>
            /// </summary>
            public AnimationCurve damageDropoff = AnimationCurve.Linear(0, 1, 500f, 0.8f);
            /// <summary>
            /// Should we shoot one bullet at a time or pellets?
            /// </summary>
            public FireTypeMode fireTypeMode = FireTypeMode.Simple;
            /// <summary>
            /// If we are firing using burst, how many bullets should be fired in one burst?
            /// </summary>
            public int burstBulletsPerShot = 3;
            /// <summary>
            /// How many seconds need to pass between individual shots in burst fire mode?
            /// </summary>
            public float burstTimeBetweenShots = 0.1f;
            /// <summary>
            /// If we should shoot pellets, how many should we shoot?
            /// </summary>
            public int amountOfPellets = 12;
            /// <summary>
            /// How much should the weapon slow us down (base)?  Other values are multiplier by this.
            /// </summary>
            public float speedMultiplierBase = 1f;
            /// <summary>
            /// How much force is applied to the ragdoll?
            /// </summary>
            public float ragdollForce = 500f;
            #endregion

            #region Attachments
            [FormerlySerializedAs("attachmentSlots")]
            /// <summary>
            /// Attachment slots available on this weapon
            /// </summary>
            public AttachmentSlot[] attachmentSlotsSpecific;

            /// <summary>
            /// If assigned, this list is used instead
            /// </summary>
            public Kit_AttachmentsUniversal attachmentSlotOverride;

            public AttachmentSlot[] attachmentSlots
            {
                get
                {
                    if (attachmentSlotOverride) return attachmentSlotOverride.attachmentSlots;
                    else return attachmentSlotsSpecific;
                }
            }
            #endregion

            #region Animation Settings
            /// <summary>
            /// Should the "empty" bool be set to the animator?
            /// </summary>
            public bool setEmptyBool;
            /// <summary>
            /// Should the "aiming" bool be set to the animator?
            /// </summary>
            public bool setAimingBool;
            /// <summary>
            /// Should the "aiming" bool be set to the animator?
            /// </summary>
            public bool setRunningBool;
            /// <summary>
            /// Should the "aiming" bool be set to the animator?
            /// </summary>
            public bool sendRunningEvents;
            /// <summary>
            /// Set "aiming" float to the animator?
            /// </summary>
            public bool setAimingProgress;
            /// <summary>
            /// Set actual movement direction to the animator? ("hor" / "ver")
            /// </summary>
            public bool setMovementDirection;
            #endregion

            #region Crosshair
            [Header("Crosshair")]
            /// <summary>
            /// Is the crosshair enabled for this weapon?
            /// </summary>
            public bool crosshairEnabled = true;
            /// <summary>
            /// By which factor should we multiply the crosshair's size?
            /// </summary>
            public float crosshairSizeMultiplier = 1f;
            #endregion

            #region Bullets
            [Header("Bullets")]
            /// <summary>
            /// Determines whether we should use raycast or physical bullets
            /// </summary>
            public BulletMode bulletsMode = BulletMode.Raycast;
            /// <summary>
            /// Is bullet penetration enabled?
            /// </summary>
            public bool bulletsPenetrationEnabled = true;
            /// <summary>
            /// This is a value that determines how many objects can be penetrated with this bullet. Think of it as the money you have available to pay the penetration cost here <see cref="Kit_PenetrateableObject.cost"/>
            /// </summary>
            public int bulletsPenetrationForce = 3;
            /// <summary>
            /// If <see cref="bulletsMode"/> is set to <see cref="BulletMode.Physical"/>, this prefab will be instantiated instead of raycast
            /// </summary>
            public GameObject bulletPrefab;
            /// <summary>
            /// Speed of physical bullet in m/s
            /// </summary>
            public float bulletSpeed = 200;
            /// <summary>
            /// How many frames after shooting should the bullet be hidden?
            /// </summary>
            public int bulletHideForFrames = 3;
            /// <summary>
            /// Multiplier of gravity applied to bullet (1 = realistic). Multiplies with <see cref="Physics.gravity"/>
            /// </summary>
            public float bulletGravityMultiplier = 1f;
            /// <summary>
            /// How long will this weapon's bullets exist?
            /// </summary>
            public float bulletLifeTime = 10f;
            /// <summary>
            /// Should the bullet parent itself to its hit thing and stay alive? Useful for things like nails and arrows.
            /// </summary>
            public bool bulletStaysAliveAfterDeath = false;
            /// <summary>
            /// If bullet stays alive after death, this is how long
            /// </summary>
            public float bulletStaysAliveAfterDeathTime = 10f;
            #endregion

            #region Bullet Spread
            [Header("Bullet Spread")]
            /// <summary>
            /// Which spray m ode does this weapon use?
            /// </summary>
            public SpreadMode bulletSpreadMode = SpreadMode.Simple;
            /// <summary>
            /// Base value for hip bullet spread
            /// </summary>
            public float bulletSpreadHipBase = 0.1f;
            /// <summary>
            /// How much spread should be added for our current velocity in reference to <see cref="bulletSpreadHipVelocityReference"/>
            /// </summary>
            public float bulletSpreadHipVelocityAdd = 0.1f;
            /// <summary>
            /// Reference velocity for hip spread
            /// </summary>
            public float bulletSpreadHipVelocityReference = 6f;

            /// <summary>
            /// Base value for aiming bullet spread
            /// </summary>
            public float bulletSpreadAimBase = 0.01f;
            /// <summary>
            /// How much spread should be added for our current velocity in reference to <see cref="bulletSpreadAimVelocityReference"/>
            /// </summary>
            public float bulletSpreadAimVelocityAdd = 0.02f;
            /// <summary>
            /// Reference velocity for aim spread
            /// </summary>
            public float bulletSpreadAimVelocityReference = 6f;

            //SPRAY PATTERN
            /// <summary>
            /// Offset values for the spray pattern mode
            /// </summary>
            public Vector3[] bulletSpreadSprayPattern = new Vector3[30];
            /// <summary>
            /// How fast does the spray pattern recover?
            /// </summary>
            public float bulletSpreadSprayPatternRecoverySpeed = 1f;
            //END
            #endregion

            #region Recoil
            [Header("Recoil")]
            /// <summary>
            /// Minimum amount of recoil per shot
            /// </summary>
            public Vector2 recoilPerShotMin = new Vector2 { x = -0.1f, y = 0.5f };
            /// <summary>
            /// Max amount of recoil per shot
            /// </summary>
            public Vector2 recoilPerShotMax = new Vector2 { x = 0.1f, y = 1f };
            /// <summary>
            /// How fast is our recoil going to be applied
            /// </summary>
            public float recoilApplyTime = 0.1f;
            /// <summary>
            /// How fast are we going to return to our normal position?
            /// </summary>
            public float recoilReturnSpeed = 6f;
            #endregion

            #region Reload
            [Header("Reload")]
            public ReloadMode reloadMode = ReloadMode.Chambered;
            public bool reloadProceduralAddBulletDuringStartEmpty;
            /// <summary>
            /// Reload time for normal reload (simple / full)
            /// </summary>
            public float reloadTimeOne, reloadTimeTwo; //Reload is split up in two parts, first is till bullets are updated, second is till you can shoot again
            /// <summary>
            /// Reload time for empty reload, if <see cref="reloadMode"/> is set to <see cref="ReloadMode.FullEmpty"/> or <see cref="ReloadMode.Chambered"/>
            /// </summary>
            public float reloadEmptyTimeOne, reloadEmptyTimeTwo;
            /// <summary>
            /// How much time does it take to start the procedural reload when the gun is still loaded?
            /// </summary>
            public float reloadProceduralStartTime;
            /// <summary>
            /// How much time does it take to start the reload when the gun is empty (and no bullet is added as set in <see cref="reloadProceduralAddBulletDuringStartEmpty"/>
            /// </summary>
            public float reloadProceduralEmptyStartTime;
            /// <summary>
            /// How much time until the bullet gets added (empty reload start + adding bullet during animation)
            /// </summary>
            public float reloadProceduralEmptyInsertStartTimeOne;
            /// <summary>
            /// How much time left until the loop can start?
            /// </summary>
            public float reloadProceduralEmptyInsertStartTimeTwo;
            /// <summary>
            /// How much time before the bullet gets added?
            /// </summary>
            public float reloadProceduralInsertTimeOne;
            /// <summary>
            /// How much time needs to pass after the bullet was added
            /// </summary>
            public float reloadProceduralInsertTimeTwo;
            /// <summary>
            /// How long does it take to end the procedural reload?
            /// </summary>
            public float reloadProceduralEndTime;

            /// <summary>
            /// Reloading full sound
            /// </summary>
            public AudioClip reloadSound;
            /// <summary>
            /// Reloading empty sound
            /// </summary>
            public AudioClip reloadSoundEmpty;
            /// <summary>
            /// Max sound distance for third person reload
            /// </summary>
            public float reloadSoundThirdPersonMaxRange = 20;
            /// <summary>
            /// Sound rolloff for third person reload
            /// </summary>
            public AnimationCurve reloadSoundThirdPersonRolloff = AnimationCurve.EaseInOut(0f, 1f, 20f, 0f);
            /// <summary>
            /// Sound that plays when the procedural reload starts while there is still ammo left in the gun
            /// </summary>
            public AudioClip reloadProceduralStartSound;
            /// <summary>
            /// Sound that plays when the procedural reload starts while the gun is completely empty
            /// </summary>
            public AudioClip reloadProceduralStartEmptySound;
            /// <summary>
            /// Sound that plays when a bullet is inserted during the procedural reload
            /// </summary>
            public AudioClip reloadProceduralInsertSound;
            /// <summary>
            /// Sound that plays when the procedural reload ends
            /// </summary>
            public AudioClip reloadProceduralEndSound;
            #endregion

            #region Aiming
            /// <summary>
            /// Can we aim?
            /// </summary>
            [Header("Aiming")]
            public bool aimEnabled = true;
            /// <summary>
            /// How fast (in seconds) should we go from idle position to aiming?
            /// </summary>
            public float aimInTime = 0.5f;
            /// <summary>
            /// How fast (in seconds) should we return from aiming back to idle position?
            /// </summary>
            public float aimOutTime = 0.5f;
            /// <summary>
            /// How much should aiming slow us down?
            /// </summary>
            public float aimSpeedMultiplier = 0.8f;
            #endregion

            #region Weapon Delay
            [Header("Weapon Delay")]
            /// <summary>
            /// Base amount for weapon delay
            /// </summary>
            public float weaponDelayBaseAmount = 1f;
            /// <summary>
            /// Max amount for weapon delay
            /// </summary>
            public float weaponDelayMaxAmount = 0.02f;
            /// <summary>
            /// Multiplier that is applied when we are aiming
            /// </summary>
            public float weaponDelayAimingMultiplier = 0.3f;
            /// <summary>
            /// How fast does the weapon delay update?
            /// </summary>
            public float weaponDelaySmooth = 3f;
            #endregion

            #region Weapon Tilt
            /// <summary>
            /// Should the weapon tilt sideways when we are walking sideways?
            /// </summary>
            public bool weaponTiltEnabled = true;
            /// <summary>
            /// Should the weapon also tilt when we are aiming?
            /// </summary>
            public bool weaponTiltEnabledWhileAiming;
            /// <summary>
            /// By how many degrees should the weapon tilt?
            /// </summary>
            public float weaponTiltIntensity = 5f;
            /// <summary>
            /// How fast should it return to 0,0,0 when weapon tilt is disabled?
            /// </summary>
            public float weaponTiltReturnSpeed = 3f;
            #endregion

            #region Weapon Fall
            [Header("Fall Down effect")]
            public float fallDownAmount = 10.0f;
            public float fallDownMinOffset = -6.0f;
            public float fallDownMaxoffset = 6.0f;
            public float fallDownTime = 0.1f;
            public float fallDownReturnSpeed = 1f;
            #endregion

            #region Shell Ejection
            [Header("Shell Ejection")]
            /// <summary>
            /// Our shell ejection prefab
            /// </summary>
            public GameObject shellEjectionPrefab;
            /// <summary>
            /// Should there be a delay between the shot and the shell ejection? Must be lower than <see cref="fireRate"/>.
            /// </summary>
            public float shellEjectionTime = 0f;
            /// <summary>
            /// The minimum force applied (relative to the ejection point)
            /// </summary>
            public Vector3 shellEjectionMinForce;
            /// <summary>
            /// The maximum force applied (relative to the ejection point)
            /// </summary>
            public Vector3 shellEjectionMaxForce;
            /// <summary>
            /// The minimum torque applied (relative to the ejection point)
            /// </summary>
            public Vector3 shellEjectionMinTorque;
            /// <summary>
            /// The maximum torque applied (relative to the ejection point)
            /// </summary>
            public Vector3 shellEjectionMaxTorque;
            #endregion

            #region Running
            [Header("Running")]
            /// <summary>
            /// Time in seconds that you cannot fire after you stopped running
            /// </summary>
            public float timeCannotFireAfterRun = 0.3f;
            #endregion

            #region Sounds
            [Header("Sounds")]
            /// <summary>
            /// Sound used for draw
            /// </summary>
            public AudioClip drawSound;
            /// <summary>
            /// Sound used for putaway
            /// </summary>
            public AudioClip putawaySound;
            /// <summary>
            /// Fire sound used for first person
            /// </summary>
            public AudioClip fireSound;
            /// <summary>
            /// Fire sound used for third person
            /// </summary>
            public AudioClip fireSoundThirdPerson;
            /// <summary>
            /// Delay for <see cref="boltActionSoundNormal"/> if this is a normal shot
            /// </summary>
            public float boltActionDelayNormal;
            /// <summary>
            /// Sound that plays for <see cref="FireMode.BoltAction"/> if this is a normal shot
            /// </summary>
            public AudioClip boltActionSoundNormal;
            /// <summary>
            /// Total time of bolt action if it is a normal shot
            /// </summary>
            public float boltActionTimeNormal = 0.3f;
            /// <summary>
            /// Delay for <see cref="boltActionSoundLast"/> if this is a normal shot
            /// </summary>
            public float boltActionDelayLast;
            /// <summary>
            /// Sound that plays for <see cref="FireMode.BoltAction"/> if this is the last shot
            /// </summary>
            public AudioClip boltActionSoundLast;
            /// <summary>
            /// Total time of bolt action if it is the last shot
            /// </summary>
            public float boltActionTimeLast = 0.3f;
            /// <summary>
            /// Max sound distance for third person bolt sound
            /// </summary>
            public float boltActionSoundThirdPersonMaxRange = 20f;
            /// <summary>
            /// Sound rolloff for third person bolt sound
            /// </summary>
            public AnimationCurve boltActionSoundThirdPersonRolloff = AnimationCurve.EaseInOut(0f, 1f, 20f, 0f);
            /// <summary>
            /// Max sound distance for third person fire
            /// </summary>
            public float fireSoundThirdPersonMaxRange = 300f;
            /// <summary>
            /// Sound rolloff for third person fire
            /// </summary>
            public AnimationCurve fireSoundThirdPersonRolloff = AnimationCurve.EaseInOut(0f, 1f, 300f, 0f);

            /// <summary>
            /// Dry fire sound (Shooting with 0 bullets left)
            /// </summary>
            public AudioClip dryFireSound;
            #endregion

            #region Walk Animations
            /// <summary>
            /// Should the walk animation still play while we are aiming?
            /// </summary>
            [Header("Walking")]
            public bool enableWalkAnimationWhileAiming;
            #endregion

            #region Generic Animations
            [Header("Generic Animations")]
            /// <summary>
            /// This animation controller holds the animations for generic gun movement (Idle, Walk, Run)
            /// </summary>
            public GameObject genericGunAnimatorControllerPrefab;

            /// <summary>
            /// Uses the generic walk anim if true
            /// </summary>
            public bool useGenericWalkAnim = true;

            /// <summary>
            /// Uses the generic run anim if true
            /// </summary>
            public bool useGenericRunAnim = true;
            #endregion


            #region Overriden functions
            public override WeaponDisplayData GetWeaponDisplayData(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData)
            {
                WeaponDisplayData wdd = new WeaponDisplayData();
                wdd.sprite = weaponHudPicture;
                wdd.name = weaponName.GetLocalizedString();
                return wdd;
            }

            public override void SetupFirstPerson(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData)
            {
                //Set RPM
                fireRate = 60f / RPM;

                Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;

                //Setup root for this weapon
                GameObject root = new GameObject("Weapon root");
                root.transform.parent = pb.weaponsGo; //Set root
                root.transform.localPosition = Vector3.zero; //Reset position
                root.transform.localRotation = Quaternion.identity; //Reset rotation
                root.transform.localScale = Vector3.one; //Reset scale

                //Setup generic animations
                GameObject genericAnimations = Instantiate(genericGunAnimatorControllerPrefab);
                genericAnimations.transform.parent = root.transform;
                genericAnimations.transform.localPosition = Vector3.zero; //Reset position
                genericAnimations.transform.localRotation = Quaternion.identity; //Reset rotation
                genericAnimations.transform.localScale = Vector3.one; //Reset scale

                //Get animator
                Animator anim = genericAnimations.GetComponent<Animator>(); ;
                anim.Play("Idle");
                data.genericAnimator = anim;

                //Setup aiming transform
                GameObject aimTrans = new GameObject("Weapon aiming");
                aimTrans.transform.parent = genericAnimations.transform; //Set root
                aimTrans.transform.localPosition = Vector3.zero; //Reset position
                aimTrans.transform.localRotation = Quaternion.identity; //Reset rotation
                aimTrans.transform.localScale = Vector3.one; //Reset scale

                //Assign it
                data.aimingTransform = aimTrans.transform;

                //Delay transform
                GameObject delayTrans = new GameObject("Weapon delay");
                delayTrans.transform.parent = aimTrans.transform; //Set root
                delayTrans.transform.localPosition = Vector3.zero; //Reset position
                delayTrans.transform.localRotation = Quaternion.identity; //Reset rotation
                delayTrans.transform.localScale = Vector3.one; //Reset scale

                //Assign it
                data.weaponDelayTransform = delayTrans.transform;

                //Delay transform
                GameObject fallTrans = new GameObject("Weapon fall");
                fallTrans.transform.parent = delayTrans.transform; //Set root
                fallTrans.transform.localPosition = Vector3.zero; //Reset position
                fallTrans.transform.localRotation = Quaternion.identity; //Reset rotation
                fallTrans.transform.localScale = Vector3.one; //Reset scale

                //Assign it
                data.weaponFallTransform = fallTrans.transform;

                //Get Fire Audio (Needs to be consistent)
                if (pb.weaponsGo.GetComponent<AudioSource>()) data.soundFire = pb.weaponsGo.GetComponent<AudioSource>();
                else data.soundFire = pb.weaponsGo.gameObject.AddComponent<AudioSource>();

                //Setup reload sound
                GameObject soundReload = new GameObject("SoundReload"); //Create
                soundReload.transform.parent = root.transform;
                soundReload.transform.localPosition = Vector3.zero; //Reset position
                soundReload.transform.localRotation = Quaternion.identity; //Reset rotation
                soundReload.transform.localScale = Vector3.one; //Reset scale
                                                                //Add audio source
                data.soundReload = soundReload.AddComponent<AudioSource>();

                //Setup other sound
                GameObject soundOther = new GameObject("SoundOther"); //Create
                soundOther.transform.parent = root.transform;
                soundOther.transform.localPosition = Vector3.zero; //Reset position
                soundOther.transform.localRotation = Quaternion.identity; //Reset rotation
                soundOther.transform.localScale = Vector3.one; //Reset scale
                                                               //Add audio source
                data.soundOther = soundOther.AddComponent<AudioSource>();

                //Copy data first
                data.fireMode = fireMode;
                data.fireRate = 60f / RPM;
                data.bulletsPerMag = bulletsPerMag;
                data.bulletsToReloadAtStart = bulletsToReloadAtStart;
                data.baseDamage = baseDamage;
                data.range = range;
                data.damageDropoff = damageDropoff;
                data.fireTypeMode = fireTypeMode;
                data.burstBulletsPerShot = burstBulletsPerShot;
                data.burstTimeBetweenShots = burstTimeBetweenShots;
                data.amountOfPellets = amountOfPellets;
                data.speedMultiplierBase = speedMultiplierBase;
                data.ragdollForce = ragdollForce;

                data.bulletsMode = bulletsMode;
                data.bulletsPenetrationEnabled = bulletsPenetrationEnabled;
                data.bulletsPenetrationForce = bulletsPenetrationForce;
                data.bulletPrefab = bulletPrefab;
                data.bulletSpeed = bulletSpeed;
                data.bulletHideForFrames = bulletHideForFrames;
                data.bulletGravityMultiplier = bulletGravityMultiplier;
                data.bulletLifeTime = bulletLifeTime;
                data.bulletStaysAliveAfterDeath = bulletStaysAliveAfterDeath;
                data.bulletStaysAliveAfterDeathTime = bulletStaysAliveAfterDeathTime;

                data.bulletSpreadMode = bulletSpreadMode;
                data.bulletSpreadHipBase = bulletSpreadHipBase;
                data.bulletSpreadHipVelocityAdd = bulletSpreadHipVelocityAdd;
                data.bulletSpreadHipVelocityReference = bulletSpreadHipVelocityReference;
                data.bulletSpreadAimBase = bulletSpreadAimBase;
                data.bulletSpreadAimVelocityAdd = bulletSpreadAimVelocityAdd;
                data.bulletSpreadAimVelocityReference = bulletSpreadAimVelocityReference;

                data.bulletSpreadSprayPattern = bulletSpreadSprayPattern;
                data.bulletSpreadSprayPatternRecoverySpeed = bulletSpreadSprayPatternRecoverySpeed;

                data.recoilPerShotMin = recoilPerShotMin;
                data.recoilPerShotMax = recoilPerShotMax;
                data.recoilApplyTime = recoilApplyTime;
                data.recoilReturnSpeed = recoilReturnSpeed;

                //Setup the first person prefab
                GameObject fpRuntime = Instantiate(firstPersonPrefab, fallTrans.transform, false);
                fpRuntime.transform.localScale = Vector3.one; //Reset scale

                //Setup renderer
                data.weaponRenderer = fpRuntime.GetComponent<Kit_WeaponRenderer>();
                //Set Attachments
                data.weaponRenderer.SetAttachments(data.attachments.ToArray(), this, pb, data);

                //Play Dependent arms
                if (data.weaponRenderer.playerModelDependentArmsEnabled && pb.thirdPersonPlayerModel.firstPersonArmsPrefab.Contains(data.weaponRenderer.playerModelDependentArmsKey))
                {
                    //Create Prefab
                    GameObject fpArms = Instantiate(pb.thirdPersonPlayerModel.firstPersonArmsPrefab[data.weaponRenderer.playerModelDependentArmsKey], fallTrans.transform, false);
                    //Get Arms
                    Kit_FirstPersonArms fpa = fpArms.GetComponent<Kit_FirstPersonArms>();

                    if (fpa.cameraBoneOverride)
                    {
                        data.weaponRenderer.cameraAnimationBone = fpa.cameraBoneOverride;
                    }

                    if (fpa.cameraBoneTargetOverride)
                    {
                        data.weaponRenderer.cameraAnimationTarget = fpa.cameraBoneTargetOverride;
                    }

#if INTEGRATION_FPV2
                        //Set shaders
                        FirstPersonView.ShaderMaterialSolution.FPV_SM_Object armsObj = fpArms.GetComponent<FirstPersonView.ShaderMaterialSolution.FPV_SM_Object>();
                        if (armsObj)
                        {
                            //Set as first person object
                            armsObj.SetAsFirstPersonObject();
                        }
                        else
                        {
                            Debug.LogError("FPV2 is enabled but first person prefab does not have FPV_SM_Object assigned!");
                        }

#elif INTEGRATION_FPV3
                        //Set shaders
                        FirstPersonView.FPV_Object armsObj = fpArms.GetComponent<FirstPersonView.FPV_Object>();
                        if (armsObj)
                        {
                            //Set as first person object
                            armsObj.SetAsFirstPersonObject();
                        }
                        else
                        {
                            Debug.LogError("FPV3 is enabled but first person prefab does not have FPV_Object assigned!");
                        }
#endif

                    //Reparent
                    for (int i = 0; i < fpa.reparents.Length; i++)
                    {
                        if (fpa.reparents[i])
                        {
                            fpa.reparents[i].transform.parent = data.weaponRenderer.playerModelDependentArmsRoot;
                        }
                        else
                        {
                            Debug.LogWarning("First Person Arm Renderer at index " + i + " is not assigned", fpa);
                        }
                    }
                    //Merge Array
                    data.weaponRenderer.allWeaponRenderers = data.weaponRenderer.allWeaponRenderers.Concat(fpa.renderers).ToArray();
                    //Rebind so that the animator animates our freshly reparented transforms too!
                    if (data.weaponRenderer.anim)
                    {
                        data.weaponRenderer.anim.Rebind();

                        for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                        {
                            data.weaponRenderer.animAdditionals[i].Rebind();
                        }
                    }
                }

                //Hide
                data.weaponRenderer.visible = false;

#if INTEGRATION_FPV2
                    //Set shaders
                    FirstPersonView.ShaderMaterialSolution.FPV_SM_Object obj = fpRuntime.GetComponent<FirstPersonView.ShaderMaterialSolution.FPV_SM_Object>();
                    if (obj)
                    {
                        //Set as first person object
                        obj.SetAsFirstPersonObject();
                    }
                    else
                    {
                        Debug.LogError("FPV2 is enabled but first person prefab does not have FPV_SM_Object assigned!");
                    }
#elif INTEGRATION_FPV3
                    //Set shaders
                    FirstPersonView.FPV_Object obj = fpRuntime.GetComponent<FirstPersonView.FPV_Object>();
                    if (obj)
                    {
                        //Set as first person object
                        obj.SetAsFirstPersonObject();
                    }
                    else
                    {
                        Debug.LogError("FPV3 is enabled but first person prefab does not have FPV_Object assigned!");
                    }
#endif

                //Add to the list
                data.instantiatedObjects.Add(root);

                //Setup start values
                data.bulletsLeft = data.bulletsPerMag;
                data.bulletsLeftToReload = data.bulletsToReloadAtStart;

                //Object Pool the bullet
                Kit_IngameMain.instance.objectPooling.EnqueueInstantiateable(data.bulletPrefab, 50);
                //And shell
                if (shellEjectionPrefab)
                {
                    Kit_IngameMain.instance.objectPooling.EnqueueInstantiateable(shellEjectionPrefab, 50);
                }
            }

            public override void SetupThirdPerson(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData)
            {
                Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;

                //Setup the third person prefab
                GameObject tpRuntime = Instantiate(thirdPersonPrefab, pb.thirdPersonPlayerModel.weaponsInHandsGo, false);
                //Set Scale
                tpRuntime.transform.localScale = Vector3.one;

                //Setup renderer
                data.tpWeaponRenderer = tpRuntime.GetComponent<Kit_ThirdPersonWeaponRenderer>();
                data.tpWeaponRenderer.visible = false;
                if (pb.isFirstPersonActive)
                {
                    //Make it shadows only
                    data.tpWeaponRenderer.shadowsOnly = true;
                }
                //Setup attachments
                data.tpWeaponRenderer.SetAttachments(data.attachments.ToArray(), this, pb, data);

                //Add to the list
                data.instantiatedObjects.Add(tpRuntime);

                //Object Pool the bullet
                Kit_IngameMain.instance.objectPooling.EnqueueInstantiateable(data.bulletPrefab, 50);
                //And shell
                if (shellEjectionPrefab)
                {
                    Kit_IngameMain.instance.objectPooling.EnqueueInstantiateable(shellEjectionPrefab, 50);
                }
            }

            public override void AuthorativeInput(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData, Kit_PlayerInput input, float delta, double revertTime)
            {
                if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                {
                    Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;


                    //Set this weapon to selected and ready (for other things)
                    data.isSelectedAndReady = true;

                    //If we are not reloading
                    if (!data.reloadInProgress)
                    {
                        //Check if movement and time allows firing
                        if (pb.movement.CanFire(pb) && Time.time - timeCannotFireAfterRun > data.lastRun)
                        {
                            //Fire modes
                            if (data.fireMode == FireMode.Semi)
                            {
                                //We cannot fire full auto, set value
                                data.isFiring = false;
                                //Check for input
                                if (data.lastLmb != input.lmb)
                                {
                                    data.lastLmb = input.lmb;
                                    if (input.lmb)
                                    {
                                        //Compare with fire rate
                                        if (Time.time >= data.lastFire + data.fireRate)
                                        {
                                            if (data.bulletsLeft > 0)
                                            {
                                                FireOneShot(pb, data, delta, (float)revertTime, false);
                                            }
                                            else if (!Kit_IngameMain.instance.gameInformation.enableAutoReload || data.bulletsLeftToReload == 0) //No ammo, dry fire
                                            {
                                                DryFire(pb, data);
                                            }
                                        }
                                    }
                                }
                            }
                            else if (data.fireMode == FireMode.BoltAction)
                            {
                                //We cannot fire full auto, set value
                                data.isFiring = false;
                                //Check for input
                                if (data.lastLmb != input.lmb)
                                {
                                    data.lastLmb = input.lmb;
                                    if (input.lmb)
                                    {
                                        //In bolt action, lastFire already includes bolt time
                                        if (Time.time >= data.lastFire)
                                        {
                                            if (data.bulletsLeft > 0)
                                            {
                                                FireOneShot(pb, data, delta, (float)revertTime, false);
                                            }
                                            else if (!Kit_IngameMain.instance.gameInformation.enableAutoReload || data.bulletsLeftToReload == 0) //No ammo, dry fire
                                            {
                                                DryFire(pb, data);
                                            }
                                        }
                                    }
                                }
                            }
                            else if (data.fireMode == FireMode.Auto)
                            {
                                //Check for input
                                if (input.lmb)
                                {
                                    //Compare with fire rate
                                    if (Time.time >= data.lastFire + data.fireRate)
                                    {
                                        //Compare bullets left
                                        if (data.bulletsLeft > 0)
                                        {
                                            FireOneShot(pb, data, delta, (float)revertTime, false);
                                            //We are firing full auto, set value
                                            data.isFiring = true;
                                        }
                                        else if (!Kit_IngameMain.instance.gameInformation.enableAutoReload || data.bulletsLeftToReload == 0) //No ammo, dry fire
                                        {
                                            DryFire(pb, data);
                                            //We cannot fire, set value
                                            data.isFiring = false;
                                        }
                                    }
                                }
                                else
                                {
                                    //We cannot fire, set value
                                    data.isFiring = false;
                                }
                            }
                            else if (data.fireMode == FireMode.Burst)
                            {
                                //We cannot fire full auto, set value
                                data.isFiring = false;
                                //Check for input
                                if (data.lastLmb != input.lmb)
                                {
                                    data.lastLmb = input.lmb;
                                    if (input.lmb)
                                    {
                                        //Compare with fire rate
                                        if (Time.time >= data.lastFire + data.fireRate)
                                        {
                                            if (data.bulletsLeft > 0)
                                            {
                                                FireBurst(pb, data, delta, (float)revertTime, false);
                                            }
                                            else if (!Kit_IngameMain.instance.gameInformation.enableAutoReload || data.bulletsLeftToReload == 0) //No ammo, dry fire
                                            {
                                                DryFire(pb, data);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        else
                        {
                            //We cannot fire, set value
                            data.isFiring = false;
                        }

                        //Aiming input
                        if (pb.movement.CanFire(pb) && aimEnabled)
                        {
                            //Check for input
                            if (input.aiming)
                            {
                                //Check if we can aim
                                if (data.isSelectedAndReady && !data.reloadInProgress)
                                {
                                    data.isAiming = true;
                                }
                                //Else we cannot aim, set to not aiming
                                else
                                {
                                    data.isAiming = false;
                                }
                            }
                            //Else we cannot aim, set to not aiming
                            else
                            {
                                data.isAiming = false;
                            }
                        }
                        //Else we cannot aim, set to not aiming
                        else
                        {
                            data.isAiming = false;
                        }

                        //Check for input
                        if (data.lastReload != input.reload || Kit_IngameMain.instance.gameInformation.enableAutoReload && data.bulletsLeft == 0 && data.bulletsLeftToReload > 0 && Time.time > data.lastFire + 0.5f)
                        {
                            data.lastReload = input.reload;
                            if (input.reload || Kit_IngameMain.instance.gameInformation.enableAutoReload && data.bulletsLeft == 0 && data.bulletsLeftToReload > 0)
                            {
                                //Check if we can start reload
                                if (data.fireMode != FireMode.BoltAction || data.fireMode == FireMode.BoltAction && Time.time > data.lastFire)
                                {
                                    //Check if we have spare ammo
                                    if (data.bulletsLeftToReload > 0)
                                    {
                                        //Check if the weapon isn't already full (Chambered means we can have one in the chamber)
                                        if ((reloadMode == ReloadMode.Chambered || reloadMode == ReloadMode.ProceduralChambered) && data.bulletsLeft != data.bulletsPerMag + 1 || reloadMode != ReloadMode.Chambered && reloadMode != ReloadMode.ProceduralChambered && data.bulletsLeft != data.bulletsPerMag)
                                        {
                                            if (pb.isLocalPlayer)
                                            {
                                                pb.inputManager.ResetAiming(pb);
                                            }


                                            data.reloadInProgress = true;
                                            //Play reload voice
                                            if (pb.voiceManager)
                                            {
                                                pb.voiceManager.Reloading(pb);
                                            }
                                            //Reset run animation
                                            data.startedRunAnimation = false;
                                            switch (reloadMode)
                                            {
                                                //Set reload time
                                                case ReloadMode.Simple:
                                                    //Simple reload, set time
                                                    data.reloadNextEnd = Time.time + reloadTimeOne;
                                                    data.reloadPhase = 0;
                                                    if (pb.isFirstPersonActive)
                                                    {
                                                        if (data.weaponRenderer.anim)
                                                        {
                                                            //Play animation
                                                            data.weaponRenderer.anim.Play("Reload Full", data.weaponRenderer.animActionLayer, 0f);

                                                            for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                            {
                                                                data.weaponRenderer.animAdditionals[i].Play("Reload Full", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                                            }
                                                        }
                                                        else if (data.weaponRenderer.legacyAnim)
                                                        {
                                                            //Play animation
                                                            data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.reload, 0.15f, PlayMode.StopAll);
                                                        }
                                                        //Play sound
                                                        data.soundReload.PlayOneShot(reloadSound);
                                                    }
                                                    else
                                                    {
                                                        //Set clip
                                                        pb.thirdPersonPlayerModel.soundReload.clip = reloadSound;
                                                        //Set distance
                                                        pb.thirdPersonPlayerModel.soundReload.maxDistance = reloadSoundThirdPersonMaxRange;
                                                        //Set rolloff
                                                        pb.thirdPersonPlayerModel.soundReload.SetCustomCurve(AudioSourceCurveType.CustomRolloff, reloadSoundThirdPersonRolloff);
                                                        //Play
                                                        pb.thirdPersonPlayerModel.soundReload.Play();
                                                    }
                                                    //Call network
                                                    if (pb.isServer) pb.RpcWeaponReloadNetwork(false);
                                                    //Play third person reload anim
                                                    pb.thirdPersonPlayerModel.PlayWeaponReloadAnimation(thirdPersonAnimType, 0);
                                                    break;

                                                case ReloadMode.FullEmpty:
                                                    //Set time for full
                                                    if (data.bulletsLeft > 0)
                                                    {
                                                        //Set time
                                                        data.reloadNextEnd = Time.time + reloadTimeOne;
                                                        data.reloadPhase = 0;
                                                        if (pb.isFirstPersonActive)
                                                        {
                                                            //Play animation
                                                            if (data.weaponRenderer.anim)
                                                            {
                                                                //Play animation
                                                                data.weaponRenderer.anim.Play("Reload Full", data.weaponRenderer.animActionLayer, 0f);

                                                                for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                                {
                                                                    data.weaponRenderer.animAdditionals[i].Play("Reload Full", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                                                }
                                                            }
                                                            else if (data.weaponRenderer.legacyAnim)
                                                            {
                                                                //Play animation
                                                                data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.reload, 0.15f, PlayMode.StopAll);
                                                            }
                                                            //Play sound
                                                            data.soundReload.PlayOneShot(reloadSound);
                                                        }
                                                        else
                                                        {
                                                            //Set clip
                                                            pb.thirdPersonPlayerModel.soundReload.clip = reloadSound;
                                                            //Set distance
                                                            pb.thirdPersonPlayerModel.soundReload.maxDistance = reloadSoundThirdPersonMaxRange;
                                                            //Set rolloff
                                                            pb.thirdPersonPlayerModel.soundReload.SetCustomCurve(AudioSourceCurveType.CustomRolloff, reloadSoundThirdPersonRolloff);
                                                            //Play
                                                            pb.thirdPersonPlayerModel.soundReload.Play();
                                                        }
                                                        //Call network
                                                        if (pb.isServer) pb.RpcWeaponReloadNetwork(false);
                                                        //Play third person reload anim
                                                        pb.thirdPersonPlayerModel.PlayWeaponReloadAnimation(thirdPersonAnimType, 0);
                                                    }
                                                    //Empty
                                                    else
                                                    {
                                                        //Set time
                                                        data.reloadNextEnd = Time.time + reloadEmptyTimeOne;
                                                        data.reloadPhase = 0;
                                                        if (pb.isFirstPersonActive)
                                                        {
                                                            //Play animation
                                                            if (data.weaponRenderer.anim)
                                                            {
                                                                //Play animation
                                                                data.weaponRenderer.anim.Play("Reload Empty", data.weaponRenderer.animActionLayer, 0f);

                                                                for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                                {
                                                                    data.weaponRenderer.animAdditionals[i].Play("Reload Empty", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                                                }
                                                            }
                                                            else if (data.weaponRenderer.legacyAnim)
                                                            {
                                                                //Play animation
                                                                data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.reloadEmpty, 0.15f, PlayMode.StopAll);
                                                            }
                                                            //Play sound
                                                            data.soundReload.PlayOneShot(reloadSoundEmpty);
                                                        }
                                                        else
                                                        {
                                                            //Play reload sound
                                                            //Set clip
                                                            pb.thirdPersonPlayerModel.soundReload.clip = reloadSoundEmpty;
                                                            //Set distance
                                                            pb.thirdPersonPlayerModel.soundReload.maxDistance = reloadSoundThirdPersonMaxRange;
                                                            //Set rolloff
                                                            pb.thirdPersonPlayerModel.soundReload.SetCustomCurve(AudioSourceCurveType.CustomRolloff, reloadSoundThirdPersonRolloff);
                                                            //Play
                                                            pb.thirdPersonPlayerModel.soundReload.Play();
                                                        }
                                                        //Call network
                                                        if (pb.isServer) pb.RpcWeaponReloadNetwork(true);
                                                        //Play third person reload anim
                                                        pb.thirdPersonPlayerModel.PlayWeaponReloadAnimation(thirdPersonAnimType, 0);
                                                    }
                                                    break;
                                                case ReloadMode.Chambered:
                                                    //Set time for full
                                                    if (data.bulletsLeft > 0)
                                                    {
                                                        //Set time
                                                        data.reloadNextEnd = Time.time + reloadTimeOne;
                                                        data.reloadPhase = 0;
                                                        if (pb.isFirstPersonActive)
                                                        {
                                                            //Play animation
                                                            if (data.weaponRenderer.anim)
                                                            {
                                                                //Play animation
                                                                data.weaponRenderer.anim.Play("Reload Full", data.weaponRenderer.animActionLayer, 0f);

                                                                for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                                {
                                                                    data.weaponRenderer.animAdditionals[i].Play("Reload Full", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                                                }
                                                            }
                                                            else if (data.weaponRenderer.legacyAnim)
                                                            {
                                                                //Play animation
                                                                data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.reload, 0.15f, PlayMode.StopAll);
                                                            }
                                                            //Play sound
                                                            data.soundReload.PlayOneShot(reloadSound);
                                                        }
                                                        else
                                                        {
                                                            //Set clip
                                                            pb.thirdPersonPlayerModel.soundReload.clip = reloadSound;
                                                            //Set distance
                                                            pb.thirdPersonPlayerModel.soundReload.maxDistance = reloadSoundThirdPersonMaxRange;
                                                            //Set rolloff
                                                            pb.thirdPersonPlayerModel.soundReload.SetCustomCurve(AudioSourceCurveType.CustomRolloff, reloadSoundThirdPersonRolloff);
                                                            //Play
                                                            pb.thirdPersonPlayerModel.soundReload.Play();
                                                        }
                                                        //Call network
                                                        if (pb.isServer) pb.RpcWeaponReloadNetwork(false);
                                                        //Play third person reload anim
                                                        pb.thirdPersonPlayerModel.PlayWeaponReloadAnimation(thirdPersonAnimType, 0);
                                                    }
                                                    //Empty
                                                    else
                                                    {
                                                        //Set time
                                                        data.reloadNextEnd = Time.time + reloadEmptyTimeOne;
                                                        data.reloadPhase = 0;
                                                        if (pb.isFirstPersonActive)
                                                        {
                                                            //Play animation
                                                            if (data.weaponRenderer.anim)
                                                            {
                                                                //Play animation
                                                                data.weaponRenderer.anim.Play("Reload Empty", data.weaponRenderer.animActionLayer, 0f);

                                                                for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                                {
                                                                    data.weaponRenderer.animAdditionals[i].Play("Reload Empty", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                                                }
                                                            }
                                                            else if (data.weaponRenderer.legacyAnim)
                                                            {
                                                                //Play animation
                                                                data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.reloadEmpty, 0.15f, PlayMode.StopAll);
                                                            }
                                                            //Play sound
                                                            data.soundReload.PlayOneShot(reloadSoundEmpty);
                                                        }
                                                        else
                                                        {
                                                            //Play reload sound
                                                            //Set clip
                                                            pb.thirdPersonPlayerModel.soundReload.clip = reloadSoundEmpty;
                                                            //Set distance
                                                            pb.thirdPersonPlayerModel.soundReload.maxDistance = reloadSoundThirdPersonMaxRange;
                                                            //Set rolloff
                                                            pb.thirdPersonPlayerModel.soundReload.SetCustomCurve(AudioSourceCurveType.CustomRolloff, reloadSoundThirdPersonRolloff);
                                                            //Play
                                                            pb.thirdPersonPlayerModel.soundReload.Play();
                                                        }
                                                        //Call network
                                                        if (pb.isServer) pb.RpcWeaponReloadNetwork(true);
                                                        //Play third person reload anim
                                                        pb.thirdPersonPlayerModel.PlayWeaponReloadAnimation(thirdPersonAnimType, 0);
                                                    }
                                                    break;
                                                case ReloadMode.Procedural:
                                                    if (data.bulletsLeft > 0)
                                                    {
                                                        //Set phase
                                                        data.reloadPhase = 0;
                                                        //Set time
                                                        data.reloadNextEnd = Time.time + reloadProceduralStartTime;
                                                        if (pb.isFirstPersonActive)
                                                        {
                                                            //Play animation
                                                            if (data.weaponRenderer.anim)
                                                            {
                                                                //Play animation
                                                                data.weaponRenderer.anim.Play("Reload Procedural Start", data.weaponRenderer.animActionLayer, 0f);

                                                                for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                                {
                                                                    data.weaponRenderer.animAdditionals[i].Play("Reload Procedural Start", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                                                }
                                                            }
                                                            else if (data.weaponRenderer.legacyAnim)
                                                            {
                                                                //Play animation
                                                                data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.reloadProceduralStart, 0.15f, PlayMode.StopAll);
                                                            }
                                                            //Play sound
                                                            data.soundReload.PlayOneShot(reloadProceduralStartSound);
                                                        }
                                                        else
                                                        {
                                                            //Play reload sound
                                                            //Set clip
                                                            pb.thirdPersonPlayerModel.soundReload.clip = reloadProceduralStartSound;
                                                            //Set distance
                                                            pb.thirdPersonPlayerModel.soundReload.maxDistance = reloadSoundThirdPersonMaxRange;
                                                            //Set rolloff
                                                            pb.thirdPersonPlayerModel.soundReload.SetCustomCurve(AudioSourceCurveType.CustomRolloff, reloadSoundThirdPersonRolloff);
                                                            //Play
                                                            pb.thirdPersonPlayerModel.soundReload.Play();
                                                        }
                                                        //Set cancel state
                                                        data.cancelProceduralReload = false;
                                                        //Call network
                                                        if (pb.isServer) pb.RpcWeaponProceduralReloadNetwork(0);
                                                        //Set cancel state
                                                        data.cancelProceduralReload = false;
                                                    }
                                                    else
                                                    {
                                                        //Set phase
                                                        data.reloadPhase = 0;
                                                        //Set time
                                                        if (reloadProceduralAddBulletDuringStartEmpty && data.bulletsLeft == 0)
                                                        {
                                                            data.reloadNextEnd = Time.time + reloadProceduralEmptyInsertStartTimeOne;
                                                        }
                                                        else
                                                        {
                                                            data.reloadNextEnd = Time.time + reloadProceduralEmptyStartTime;
                                                        }
                                                        if (pb.isFirstPersonActive)
                                                        {
                                                            if (data.weaponRenderer.anim)
                                                            {
                                                                //Play animation
                                                                data.weaponRenderer.anim.Play("Reload Procedural Start Empty", data.weaponRenderer.animActionLayer, 0f);

                                                                for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                                {
                                                                    data.weaponRenderer.animAdditionals[i].Play("Reload Procedural Start Empty", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                                                }
                                                            }
                                                            else if (data.weaponRenderer.legacyAnim)
                                                            {
                                                                //Play animation
                                                                data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.reloadProceduralStartEmpty, 0.15f, PlayMode.StopAll);
                                                            }
                                                            //Play sound
                                                            data.soundReload.PlayOneShot(reloadProceduralStartEmptySound);
                                                        }
                                                        else
                                                        {
                                                            //Play reload sound
                                                            //Set clip
                                                            pb.thirdPersonPlayerModel.soundReload.clip = reloadProceduralStartEmptySound;
                                                            //Set distance
                                                            pb.thirdPersonPlayerModel.soundReload.maxDistance = reloadSoundThirdPersonMaxRange;
                                                            //Set rolloff
                                                            pb.thirdPersonPlayerModel.soundReload.SetCustomCurve(AudioSourceCurveType.CustomRolloff, reloadSoundThirdPersonRolloff);
                                                            //Play
                                                            pb.thirdPersonPlayerModel.soundReload.Play();
                                                        }
                                                        //Set cancel state
                                                        data.cancelProceduralReload = false;
                                                        //Call network
                                                        if (pb.isServer) pb.RpcWeaponProceduralReloadNetwork(1);
                                                    }
                                                    break;
                                                case ReloadMode.ProceduralChambered:
                                                    if (data.bulletsLeft > 0)
                                                    {
                                                        //Set phase
                                                        data.reloadPhase = 0;
                                                        //Set time
                                                        data.reloadNextEnd = Time.time + reloadProceduralStartTime;
                                                        if (pb.isFirstPersonActive)
                                                        {
                                                            //Play animation
                                                            if (data.weaponRenderer.anim)
                                                            {
                                                                //Play animation
                                                                data.weaponRenderer.anim.Play("Reload Procedural Start", data.weaponRenderer.animActionLayer, 0f);

                                                                for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                                {
                                                                    data.weaponRenderer.animAdditionals[i].Play("Reload Procedural Start", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                                                }
                                                            }
                                                            else if (data.weaponRenderer.legacyAnim)
                                                            {
                                                                //Play animation
                                                                data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.reloadProceduralStart, 0.15f, PlayMode.StopAll);
                                                            }
                                                            //Play sound
                                                            data.soundReload.PlayOneShot(reloadProceduralStartSound);
                                                        }
                                                        else
                                                        {
                                                            //Play reload sound
                                                            //Set clip
                                                            pb.thirdPersonPlayerModel.soundReload.clip = reloadProceduralStartSound;
                                                            //Set distance
                                                            pb.thirdPersonPlayerModel.soundReload.maxDistance = reloadSoundThirdPersonMaxRange;
                                                            //Set rolloff
                                                            pb.thirdPersonPlayerModel.soundReload.SetCustomCurve(AudioSourceCurveType.CustomRolloff, reloadSoundThirdPersonRolloff);
                                                            //Play
                                                            pb.thirdPersonPlayerModel.soundReload.Play();
                                                        }
                                                        //Set cancel state
                                                        data.cancelProceduralReload = false;
                                                        //Call network
                                                        if (pb.isServer) pb.RpcWeaponProceduralReloadNetwork(0);
                                                        //Set cancel state
                                                        data.cancelProceduralReload = false;
                                                    }
                                                    else
                                                    {
                                                        //Set phase
                                                        data.reloadPhase = 0;
                                                        //Set time
                                                        if (reloadProceduralAddBulletDuringStartEmpty && data.bulletsLeft == 0)
                                                        {
                                                            data.reloadNextEnd = Time.time + reloadProceduralEmptyInsertStartTimeOne;
                                                        }
                                                        else
                                                        {
                                                            data.reloadNextEnd = Time.time + reloadProceduralEmptyStartTime;
                                                        }
                                                        if (pb.isFirstPersonActive)
                                                        {
                                                            if (data.weaponRenderer.anim)
                                                            {
                                                                //Play animation
                                                                data.weaponRenderer.anim.Play("Reload Procedural Start Empty", data.weaponRenderer.animActionLayer, 0f);

                                                                for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                                {
                                                                    data.weaponRenderer.animAdditionals[i].Play("Reload Procedural Start Empty", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                                                }
                                                            }
                                                            else if (data.weaponRenderer.legacyAnim)
                                                            {
                                                                //Play animation
                                                                data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.reloadProceduralStartEmpty, 0.15f, PlayMode.StopAll);
                                                            }
                                                            //Play sound
                                                            data.soundReload.PlayOneShot(reloadProceduralStartEmptySound);
                                                        }
                                                        else
                                                        {
                                                            //Play reload sound
                                                            //Set clip
                                                            pb.thirdPersonPlayerModel.soundReload.clip = reloadProceduralStartEmptySound;
                                                            //Set distance
                                                            pb.thirdPersonPlayerModel.soundReload.maxDistance = reloadSoundThirdPersonMaxRange;
                                                            //Set rolloff
                                                            pb.thirdPersonPlayerModel.soundReload.SetCustomCurve(AudioSourceCurveType.CustomRolloff, reloadSoundThirdPersonRolloff);
                                                            //Play
                                                            pb.thirdPersonPlayerModel.soundReload.Play();
                                                        }
                                                        //Set cancel state
                                                        data.cancelProceduralReload = false;
                                                        //Call network
                                                        if (pb.isServer) pb.RpcWeaponProceduralReloadNetwork(1);
                                                    }
                                                    break;
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        if (data != null && data.weaponRenderer && data.weaponRenderer.cachedInteractionAttachments != null)
                        {
                            //Attachment interaction, only when we can control.
                            for (int i = 0; i < data.weaponRenderer.cachedInteractionAttachments.Length; i++)
                            {
                                data.weaponRenderer.cachedInteractionAttachments[i].Interaction(pb);
                            }
                        }

                        if (setEmptyBool && pb.isFirstPersonActive && data.weaponRenderer.anim)
                        {
                            //Set empty bool
                            data.weaponRenderer.anim.SetBool("empty", data.bulletsLeft == 0);

                            for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                            {
                                data.weaponRenderer.animAdditionals[i].SetBool("empty", data.bulletsLeft == 0);
                            }
                        }
                    }
                    //Reloading
                    else
                    {
                        //When we are reloading, empty bool will be 'false'
                        if (setEmptyBool && pb.isFirstPersonActive && data.weaponRenderer.anim)
                        {
                            //Set empty bool
                            data.weaponRenderer.anim.SetBool("empty", false);

                            for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                            {
                                data.weaponRenderer.animAdditionals[i].SetBool("empty", false);
                            }
                        }
                        //Reset run animation
                        data.startedRunAnimation = false;
                        //Make sure we are not aiming
                        data.isAiming = false;
                        //Make sure we are not firing either
                        data.isFiring = false;
                        //Check for cancelling
                        if (reloadMode == ReloadMode.Procedural || reloadMode == ReloadMode.ProceduralChambered)
                        {
                            if (data.lastLmb != input.lmb)
                            {
                                data.lastLmb = input.lmb;
                                if (input.lmb && data.bulletsLeft > 0)
                                {
                                    //User wants to cancel
                                    data.cancelProceduralReload = true;
                                    data.reloadPhase = 0;
                                    data.reloadInProgress = false;
                                    FireOneShot(pb, data, delta, (float)revertTime, false);
                                }
                            }
                        }
                        else
                        {
                            data.cancelProceduralReload = false;
                        }

                        //Check if a reload phase is over
                        if (Time.time >= data.reloadNextEnd)
                        {
                            switch (reloadMode)
                            {
                                //Simple reload
                                case ReloadMode.Simple:
                                    if (data.reloadPhase == 0)
                                    {
                                        //Update bullets
                                        if (data.bulletsLeftToReload > data.bulletsPerMag)
                                        {
                                            if (!Kit_IngameMain.instance.gameInformation.debugEnableUnlimitedReloads)
                                                data.bulletsLeftToReload -= data.bulletsPerMag - data.bulletsLeft;
                                            data.bulletsLeft = data.bulletsPerMag;
                                        }
                                        else
                                        {
                                            int wepBullet = Mathf.Clamp(data.bulletsPerMag, data.bulletsLeftToReload, data.bulletsLeft + data.bulletsLeftToReload);
                                            if (!Kit_IngameMain.instance.gameInformation.debugEnableUnlimitedReloads)
                                                data.bulletsLeftToReload -= (wepBullet - data.bulletsLeft);
                                            data.bulletsLeft = wepBullet;
                                        }
                                        //Proceed
                                        data.reloadPhase = 1;
                                        data.reloadNextEnd = Time.time + reloadTimeTwo;
                                    }
                                    else if (data.reloadPhase == 1)
                                    {
                                        //Reload is over
                                        data.reloadInProgress = false;
                                        data.reloadPhase = 0;
                                    }
                                    break;

                                //Reload with different anims / times for full / empty state
                                case ReloadMode.FullEmpty:
                                    if (data.reloadPhase == 0)
                                    {
                                        //Set time
                                        if (data.bulletsLeft > 0)
                                        {
                                            //Full reload
                                            data.reloadNextEnd = Time.time + reloadTimeTwo;
                                        }
                                        else
                                        {
                                            //Empty reload
                                            data.reloadNextEnd = Time.time + reloadEmptyTimeTwo;
                                        }

                                        //Update bullets
                                        if (data.bulletsLeftToReload > data.bulletsPerMag)
                                        {
                                            if (!Kit_IngameMain.instance.gameInformation.debugEnableUnlimitedReloads)
                                                data.bulletsLeftToReload -= data.bulletsPerMag - data.bulletsLeft;
                                            data.bulletsLeft = data.bulletsPerMag;
                                        }
                                        else
                                        {
                                            int wepBullet = Mathf.Clamp(data.bulletsPerMag, data.bulletsLeftToReload, data.bulletsLeft + data.bulletsLeftToReload);
                                            if (!Kit_IngameMain.instance.gameInformation.debugEnableUnlimitedReloads)
                                                data.bulletsLeftToReload -= (wepBullet - data.bulletsLeft);
                                            data.bulletsLeft = wepBullet;
                                        }
                                        //Proceed
                                        data.reloadPhase = 1;
                                    }
                                    else if (data.reloadPhase == 1)
                                    {
                                        //Reload is over
                                        data.reloadInProgress = false;
                                        data.reloadPhase = 0;
                                    }
                                    break;
                                //Reload with different anims / times for full / empty state and a bullet in the chamber
                                case ReloadMode.Chambered:
                                    if (data.reloadPhase == 0)
                                    {
                                        //Set time
                                        if (data.bulletsLeft > 0)
                                        {
                                            //Full reload
                                            data.reloadNextEnd = Time.time + reloadTimeTwo;
                                        }
                                        else
                                        {
                                            //Empty reload
                                            data.reloadNextEnd = Time.time + reloadEmptyTimeTwo;
                                        }

                                        //Update bullets
                                        if (data.bulletsLeftToReload > data.bulletsPerMag)
                                        {
                                            if (data.bulletsLeft > 0)
                                            {
                                                if (!Kit_IngameMain.instance.gameInformation.debugEnableUnlimitedReloads)
                                                    data.bulletsLeftToReload -= (data.bulletsPerMag + 1) - data.bulletsLeft;
                                                data.bulletsLeft = data.bulletsPerMag + 1;
                                            }
                                            else
                                            {
                                                if (!Kit_IngameMain.instance.gameInformation.debugEnableUnlimitedReloads)
                                                    data.bulletsLeftToReload -= data.bulletsPerMag - data.bulletsLeft;
                                                data.bulletsLeft = data.bulletsPerMag;
                                            }
                                        }
                                        else
                                        {
                                            if (data.bulletsLeft > 0)
                                            {
                                                int wepBullet = Mathf.Clamp(data.bulletsPerMag + 1, data.bulletsLeftToReload, data.bulletsLeft + data.bulletsLeftToReload);
                                                if (!Kit_IngameMain.instance.gameInformation.debugEnableUnlimitedReloads)
                                                    data.bulletsLeftToReload -= (wepBullet - data.bulletsLeft);
                                                data.bulletsLeft = wepBullet;
                                            }
                                            else
                                            {
                                                int wepBullet = Mathf.Clamp(data.bulletsPerMag, data.bulletsLeftToReload, data.bulletsLeft + data.bulletsLeftToReload);
                                                if (!Kit_IngameMain.instance.gameInformation.debugEnableUnlimitedReloads)
                                                    data.bulletsLeftToReload -= (wepBullet - data.bulletsLeft);
                                                data.bulletsLeft = wepBullet;
                                            }
                                        }
                                        //Proceed
                                        data.reloadPhase = 1;
                                    }
                                    else if (data.reloadPhase == 1)
                                    {
                                        //Reload is over
                                        data.reloadInProgress = false;
                                        data.reloadPhase = 0;
                                    }
                                    break;
                                case ReloadMode.Procedural:
                                    //Phase 0 = Start
                                    //Phase 1 = End of start (If bullet needs to be added)
                                    //Phase 2 = Loop
                                    //Phase 3 = Loop 2
                                    //Phase 4 = End
                                    if (data.reloadPhase == 0)
                                    {
                                        if (reloadProceduralAddBulletDuringStartEmpty && data.bulletsLeft == 0)
                                        {
                                            //Set phase
                                            data.reloadPhase = 1;
                                            //Set time
                                            data.reloadNextEnd = Time.time + reloadProceduralEmptyInsertStartTimeTwo;
                                            //Add bullet
                                            data.bulletsLeft++;
                                            //Substract
                                            if (!Kit_IngameMain.instance.gameInformation.debugEnableUnlimitedReloads)
                                                data.bulletsLeftToReload--;
                                            //Sounds and animation is already being played, so ignore that
                                        }
                                        else
                                        {
                                            //Go to Phase 2
                                            data.reloadPhase = 2;
                                            //Here we don't need to check if ammo is left because we already did that
                                            //Set time
                                            data.reloadNextEnd = Time.time + reloadProceduralInsertTimeOne;
                                            if (pb.isFirstPersonActive)
                                            {
                                                //Play animation
                                                if (data.weaponRenderer.anim)
                                                {
                                                    //Play animation
                                                    data.weaponRenderer.anim.Play("Reload Procedural Insert", data.weaponRenderer.animActionLayer, 0f);

                                                    for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                    {
                                                        data.weaponRenderer.animAdditionals[i].Play("Reload Procedural Insert", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                                    }
                                                }
                                                else if (data.weaponRenderer.legacyAnim)
                                                {
                                                    //Play animation
                                                    data.weaponRenderer.legacyAnim.Rewind(data.weaponRenderer.legacyAnimData.reloadProceduralInsert);
                                                    data.weaponRenderer.legacyAnim.Play(data.weaponRenderer.legacyAnimData.reloadProceduralInsert, PlayMode.StopAll);
                                                }
                                                //Play sound
                                                data.soundReload.PlayOneShot(reloadProceduralInsertSound);
                                            }
                                            else
                                            {
                                                //Play reload sound
                                                //Set clip
                                                pb.thirdPersonPlayerModel.soundReload.clip = reloadProceduralInsertSound;
                                                //Set distance
                                                pb.thirdPersonPlayerModel.soundReload.maxDistance = reloadSoundThirdPersonMaxRange;
                                                //Set rolloff
                                                pb.thirdPersonPlayerModel.soundReload.SetCustomCurve(AudioSourceCurveType.CustomRolloff, reloadSoundThirdPersonRolloff);
                                                //Play
                                                pb.thirdPersonPlayerModel.soundReload.Play();
                                            }
                                            //Call network
                                            if (pb.isServer) pb.RpcWeaponProceduralReloadNetwork(2);
                                        }
                                    }
                                    else if (data.reloadPhase == 1)
                                    {
                                        //Insert is over, check if we have more bullets to reload
                                        if (data.bulletsLeftToReload > 0 && !data.cancelProceduralReload)
                                        {
                                            //Go to Phase 2
                                            data.reloadPhase = 2;
                                            //Here we don't need to check if ammo is left because we already did that
                                            //Set time
                                            data.reloadNextEnd = Time.time + reloadProceduralInsertTimeOne;
                                            if (pb.isFirstPersonActive)
                                            {
                                                //Play animation
                                                if (data.weaponRenderer.anim)
                                                {
                                                    //Play animation
                                                    data.weaponRenderer.anim.Play("Reload Procedural Insert", data.weaponRenderer.animActionLayer, 0f);

                                                    for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                    {
                                                        data.weaponRenderer.animAdditionals[i].Play("Reload Procedural Insert", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                                    }
                                                }
                                                else if (data.weaponRenderer.legacyAnim)
                                                {
                                                    //Play animation
                                                    data.weaponRenderer.legacyAnim.Rewind(data.weaponRenderer.legacyAnimData.reloadProceduralInsert);
                                                    data.weaponRenderer.legacyAnim.Play(data.weaponRenderer.legacyAnimData.reloadProceduralInsert, PlayMode.StopAll);
                                                }
                                                //Play sound
                                                data.soundReload.PlayOneShot(reloadProceduralInsertSound);
                                            }
                                            else
                                            {
                                                //Play reload sound
                                                //Set clip
                                                pb.thirdPersonPlayerModel.soundReload.clip = reloadProceduralInsertSound;
                                                //Set distance
                                                pb.thirdPersonPlayerModel.soundReload.maxDistance = reloadSoundThirdPersonMaxRange;
                                                //Set rolloff
                                                pb.thirdPersonPlayerModel.soundReload.SetCustomCurve(AudioSourceCurveType.CustomRolloff, reloadSoundThirdPersonRolloff);
                                                //Play
                                                pb.thirdPersonPlayerModel.soundReload.Play();
                                            }
                                            //Call network
                                            if (pb.isServer) pb.RpcWeaponProceduralReloadNetwork(2);
                                        }
                                        else
                                        {
                                            //End
                                            data.reloadPhase = 4;
                                            //Set time
                                            data.reloadNextEnd = Time.time + reloadProceduralEndTime;
                                            if (pb.isFirstPersonActive)
                                            {
                                                //Play animation
                                                if (data.weaponRenderer.anim)
                                                {
                                                    //Play animation
                                                    data.weaponRenderer.anim.Play("Reload Procedural End", data.weaponRenderer.animActionLayer, 0f);

                                                    for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                    {
                                                        data.weaponRenderer.animAdditionals[i].Play("Reload Procedural End", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                                    }
                                                }
                                                else if (data.weaponRenderer.legacyAnim)
                                                {
                                                    //Play animation
                                                    data.weaponRenderer.legacyAnim.Play(data.weaponRenderer.legacyAnimData.reloadProceduralEnd, PlayMode.StopAll);
                                                }
                                                //Play sound
                                                data.soundReload.PlayOneShot(reloadProceduralEndSound);
                                            }
                                            else
                                            {
                                                //Play reload sound
                                                //Set clip
                                                pb.thirdPersonPlayerModel.soundReload.clip = reloadProceduralEndSound;
                                                //Set distance
                                                pb.thirdPersonPlayerModel.soundReload.maxDistance = reloadSoundThirdPersonMaxRange;
                                                //Set rolloff
                                                pb.thirdPersonPlayerModel.soundReload.SetCustomCurve(AudioSourceCurveType.CustomRolloff, reloadSoundThirdPersonRolloff);
                                                //Play
                                                pb.thirdPersonPlayerModel.soundReload.Play();
                                            }
                                            //Call network
                                            if (pb.isServer) pb.RpcWeaponProceduralReloadNetwork(4);
                                        }
                                    }
                                    else if (data.reloadPhase == 2)
                                    {
                                        //End insert
                                        data.bulletsLeft++;
                                        //Substract
                                        if (!Kit_IngameMain.instance.gameInformation.debugEnableUnlimitedReloads)
                                            data.bulletsLeftToReload--;
                                        //Wait
                                        data.reloadPhase = 3;
                                        //Set time
                                        data.reloadNextEnd = Time.time + reloadProceduralInsertTimeTwo;
                                    }
                                    else if (data.reloadPhase == 3)
                                    {
                                        //Insert is over, check if we can insert some more
                                        if (data.bulletsLeftToReload > 0 && data.bulletsLeft < data.bulletsPerMag && !data.cancelProceduralReload)
                                        {
                                            //Go to Phase 2
                                            data.reloadPhase = 2;
                                            //Here we don't need to check if ammo is left because we already did that
                                            //Set time
                                            data.reloadNextEnd = Time.time + reloadProceduralInsertTimeOne;
                                            if (pb.isFirstPersonActive)
                                            {
                                                //Play animation
                                                if (data.weaponRenderer.anim)
                                                {
                                                    //Play animation
                                                    data.weaponRenderer.anim.Play("Reload Procedural Insert", data.weaponRenderer.animActionLayer, 0f);

                                                    for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                    {
                                                        data.weaponRenderer.animAdditionals[i].Play("Reload Procedural Insert", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                                    }
                                                }
                                                else if (data.weaponRenderer.legacyAnim)
                                                {
                                                    //Play animation
                                                    data.weaponRenderer.legacyAnim.Rewind(data.weaponRenderer.legacyAnimData.reloadProceduralInsert);
                                                    data.weaponRenderer.legacyAnim.Play(data.weaponRenderer.legacyAnimData.reloadProceduralInsert, PlayMode.StopAll);
                                                }
                                                //Play sound
                                                data.soundReload.PlayOneShot(reloadProceduralInsertSound);
                                            }
                                            else
                                            {
                                                //Play reload sound
                                                //Set clip
                                                pb.thirdPersonPlayerModel.soundReload.clip = reloadProceduralInsertSound;
                                                //Set distance
                                                pb.thirdPersonPlayerModel.soundReload.maxDistance = reloadSoundThirdPersonMaxRange;
                                                //Set rolloff
                                                pb.thirdPersonPlayerModel.soundReload.SetCustomCurve(AudioSourceCurveType.CustomRolloff, reloadSoundThirdPersonRolloff);
                                                //Play
                                                pb.thirdPersonPlayerModel.soundReload.Play();
                                            }
                                            //Call network
                                            if (pb.isServer) pb.RpcWeaponProceduralReloadNetwork(2);
                                        }
                                        else
                                        {
                                            //End
                                            data.reloadPhase = 4;
                                            //Set time
                                            data.reloadNextEnd = Time.time + reloadProceduralEndTime;
                                            if (pb.isFirstPersonActive)
                                            {
                                                //Play animation
                                                if (data.weaponRenderer.anim)
                                                {
                                                    //Play animation
                                                    data.weaponRenderer.anim.Play("Reload Procedural End", data.weaponRenderer.animActionLayer, 0f);

                                                    for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                    {
                                                        data.weaponRenderer.animAdditionals[i].Play("Reload Procedural End", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                                    }
                                                }
                                                else if (data.weaponRenderer.legacyAnim)
                                                {
                                                    //Play animation
                                                    data.weaponRenderer.legacyAnim.Play(data.weaponRenderer.legacyAnimData.reloadProceduralEnd, PlayMode.StopAll);
                                                }
                                                //Play sound
                                                data.soundReload.PlayOneShot(reloadProceduralEndSound);
                                            }
                                            else
                                            {
                                                //Play reload sound
                                                //Set clip
                                                pb.thirdPersonPlayerModel.soundReload.clip = reloadProceduralEndSound;
                                                //Set distance
                                                pb.thirdPersonPlayerModel.soundReload.maxDistance = reloadSoundThirdPersonMaxRange;
                                                //Set rolloff
                                                pb.thirdPersonPlayerModel.soundReload.SetCustomCurve(AudioSourceCurveType.CustomRolloff, reloadSoundThirdPersonRolloff);
                                                //Play
                                                pb.thirdPersonPlayerModel.soundReload.Play();
                                            }
                                            //Call network
                                            if (pb.isServer) pb.RpcWeaponProceduralReloadNetwork(4);
                                        }
                                    }
                                    else if (data.reloadPhase == 4)
                                    {
                                        //It is over, end reload
                                        data.reloadInProgress = false;
                                        data.reloadPhase = 0;
                                    }
                                    break;
                                case ReloadMode.ProceduralChambered:

                                    //Phase 0 = Start
                                    //Phase 1 = End of start (If bullet needs to be added)
                                    //Phase 2 = Loop
                                    //Phase 3 = Loop 2
                                    //Phase 4 = End
                                    if (data.reloadPhase == 0)
                                    {
                                        if (reloadProceduralAddBulletDuringStartEmpty && data.bulletsLeft == 0)
                                        {
                                            //Set phase
                                            data.reloadPhase = 1;
                                            //Set time
                                            data.reloadNextEnd = Time.time + reloadProceduralEmptyInsertStartTimeTwo;
                                            //Add bullet
                                            data.bulletsLeft++;
                                            //Substract
                                            if (!Kit_IngameMain.instance.gameInformation.debugEnableUnlimitedReloads)
                                                data.bulletsLeftToReload--;
                                            //Sounds and animation is already being played, so ignore that
                                        }
                                        else
                                        {
                                            //Go to Phase 2
                                            data.reloadPhase = 2;
                                            //Here we don't need to check if ammo is left because we already did that
                                            //Set time
                                            data.reloadNextEnd = Time.time + reloadProceduralInsertTimeOne;
                                            if (pb.isFirstPersonActive)
                                            {
                                                //Play animation
                                                if (data.weaponRenderer.anim)
                                                {
                                                    //Play animation
                                                    data.weaponRenderer.anim.Play("Reload Procedural Insert", data.weaponRenderer.animActionLayer, 0f);

                                                    for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                    {
                                                        data.weaponRenderer.animAdditionals[i].Play("Reload Procedural Insert", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                                    }
                                                }
                                                else if (data.weaponRenderer.legacyAnim)
                                                {
                                                    //Play animation
                                                    data.weaponRenderer.legacyAnim.Rewind(data.weaponRenderer.legacyAnimData.reloadProceduralInsert);
                                                    data.weaponRenderer.legacyAnim.Play(data.weaponRenderer.legacyAnimData.reloadProceduralInsert, PlayMode.StopAll);
                                                }
                                                //Play sound
                                                data.soundReload.PlayOneShot(reloadProceduralInsertSound);
                                            }
                                            else
                                            {
                                                //Play reload sound
                                                //Set clip
                                                pb.thirdPersonPlayerModel.soundReload.clip = reloadProceduralInsertSound;
                                                //Set distance
                                                pb.thirdPersonPlayerModel.soundReload.maxDistance = reloadSoundThirdPersonMaxRange;
                                                //Set rolloff
                                                pb.thirdPersonPlayerModel.soundReload.SetCustomCurve(AudioSourceCurveType.CustomRolloff, reloadSoundThirdPersonRolloff);
                                                //Play
                                                pb.thirdPersonPlayerModel.soundReload.Play();
                                            }
                                            //Call network
                                            if (pb.isServer) pb.RpcWeaponProceduralReloadNetwork(2);
                                        }
                                    }
                                    else if (data.reloadPhase == 1)
                                    {
                                        //Insert is over, check if we have more bullets to reload
                                        if (data.bulletsLeftToReload > 0 && !data.cancelProceduralReload)
                                        {
                                            //Go to Phase 2
                                            data.reloadPhase = 2;
                                            //Here we don't need to check if ammo is left because we already did that
                                            //Set time
                                            data.reloadNextEnd = Time.time + reloadProceduralInsertTimeOne;
                                            if (pb.isFirstPersonActive)
                                            {
                                                //Play animation
                                                if (data.weaponRenderer.anim)
                                                {
                                                    //Play animation
                                                    data.weaponRenderer.anim.Play("Reload Procedural Insert", data.weaponRenderer.animActionLayer, 0f);

                                                    for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                    {
                                                        data.weaponRenderer.animAdditionals[i].Play("Reload Procedural Insert", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                                    }
                                                }
                                                else if (data.weaponRenderer.legacyAnim)
                                                {
                                                    //Play animation
                                                    data.weaponRenderer.legacyAnim.Rewind(data.weaponRenderer.legacyAnimData.reloadProceduralInsert);
                                                    data.weaponRenderer.legacyAnim.Play(data.weaponRenderer.legacyAnimData.reloadProceduralInsert, PlayMode.StopAll);
                                                }
                                                //Play sound
                                                data.soundReload.PlayOneShot(reloadProceduralInsertSound);
                                            }
                                            else
                                            {
                                                //Play reload sound
                                                //Set clip
                                                pb.thirdPersonPlayerModel.soundReload.clip = reloadProceduralInsertSound;
                                                //Set distance
                                                pb.thirdPersonPlayerModel.soundReload.maxDistance = reloadSoundThirdPersonMaxRange;
                                                //Set rolloff
                                                pb.thirdPersonPlayerModel.soundReload.SetCustomCurve(AudioSourceCurveType.CustomRolloff, reloadSoundThirdPersonRolloff);
                                                //Play
                                                pb.thirdPersonPlayerModel.soundReload.Play();
                                            }
                                            //Call network
                                            if (pb.isServer) pb.RpcWeaponProceduralReloadNetwork(2);
                                        }
                                        else
                                        {
                                            //End
                                            data.reloadPhase = 4;
                                            //Set time
                                            data.reloadNextEnd = Time.time + reloadProceduralEndTime;
                                            if (pb.isFirstPersonActive)
                                            {
                                                //Play animation
                                                if (data.weaponRenderer.anim)
                                                {
                                                    //Play animation
                                                    data.weaponRenderer.anim.Play("Reload Procedural End", data.weaponRenderer.animActionLayer, 0f);

                                                    for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                    {
                                                        data.weaponRenderer.animAdditionals[i].Play("Reload Procedural End", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                                    }
                                                }
                                                else if (data.weaponRenderer.legacyAnim)
                                                {
                                                    //Play animation
                                                    data.weaponRenderer.legacyAnim.Play(data.weaponRenderer.legacyAnimData.reloadProceduralEnd, PlayMode.StopAll);
                                                }
                                                //Play sound
                                                data.soundReload.PlayOneShot(reloadProceduralEndSound);
                                            }
                                            else
                                            {
                                                //Play reload sound
                                                //Set clip
                                                pb.thirdPersonPlayerModel.soundReload.clip = reloadProceduralEndSound;
                                                //Set distance
                                                pb.thirdPersonPlayerModel.soundReload.maxDistance = reloadSoundThirdPersonMaxRange;
                                                //Set rolloff
                                                pb.thirdPersonPlayerModel.soundReload.SetCustomCurve(AudioSourceCurveType.CustomRolloff, reloadSoundThirdPersonRolloff);
                                                //Play
                                                pb.thirdPersonPlayerModel.soundReload.Play();
                                            }
                                            //Call network
                                            if (pb.isServer) pb.RpcWeaponProceduralReloadNetwork(4);
                                        }
                                    }
                                    else if (data.reloadPhase == 2)
                                    {
                                        //End insert
                                        data.bulletsLeft++;
                                        //Substract
                                        if (!Kit_IngameMain.instance.gameInformation.debugEnableUnlimitedReloads)
                                            data.bulletsLeftToReload--;
                                        //Wait
                                        data.reloadPhase = 3;
                                        //Set time
                                        data.reloadNextEnd = Time.time + reloadProceduralInsertTimeTwo;
                                    }
                                    else if (data.reloadPhase == 3)
                                    {
                                        //Insert is over, check if we can insert some more
                                        if (data.bulletsLeftToReload > 0 && data.bulletsLeft < data.bulletsPerMag + 1 && !data.cancelProceduralReload)
                                        {
                                            //Go to Phase 2
                                            data.reloadPhase = 2;
                                            //Here we don't need to check if ammo is left because we already did that
                                            //Set time
                                            data.reloadNextEnd = Time.time + reloadProceduralInsertTimeOne;
                                            if (pb.isFirstPersonActive)
                                            {
                                                //Play animation
                                                if (data.weaponRenderer.anim)
                                                {
                                                    //Play animation
                                                    data.weaponRenderer.anim.Play("Reload Procedural Insert", data.weaponRenderer.animActionLayer, 0f);

                                                    for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                    {
                                                        data.weaponRenderer.animAdditionals[i].Play("Reload Procedural Insert", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                                    }
                                                }
                                                else if (data.weaponRenderer.legacyAnim)
                                                {
                                                    //Play animation
                                                    data.weaponRenderer.legacyAnim.Rewind(data.weaponRenderer.legacyAnimData.reloadProceduralInsert);
                                                    data.weaponRenderer.legacyAnim.Play(data.weaponRenderer.legacyAnimData.reloadProceduralInsert, PlayMode.StopAll);
                                                }
                                                //Play sound
                                                data.soundReload.PlayOneShot(reloadProceduralInsertSound);
                                            }
                                            else
                                            {
                                                //Play reload sound
                                                //Set clip
                                                pb.thirdPersonPlayerModel.soundReload.clip = reloadProceduralInsertSound;
                                                //Set distance
                                                pb.thirdPersonPlayerModel.soundReload.maxDistance = reloadSoundThirdPersonMaxRange;
                                                //Set rolloff
                                                pb.thirdPersonPlayerModel.soundReload.SetCustomCurve(AudioSourceCurveType.CustomRolloff, reloadSoundThirdPersonRolloff);
                                                //Play
                                                pb.thirdPersonPlayerModel.soundReload.Play();
                                            }
                                            //Call network
                                            if (pb.isServer) pb.RpcWeaponProceduralReloadNetwork(2);
                                        }
                                        else
                                        {
                                            //End
                                            data.reloadPhase = 4;
                                            //Set time
                                            data.reloadNextEnd = Time.time + reloadProceduralEndTime;
                                            if (pb.isFirstPersonActive)
                                            {
                                                //Play animation
                                                if (data.weaponRenderer.anim)
                                                {
                                                    //Play animation
                                                    data.weaponRenderer.anim.Play("Reload Procedural End", data.weaponRenderer.animActionLayer, 0f);

                                                    for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                    {
                                                        data.weaponRenderer.animAdditionals[i].Play("Reload Procedural End", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                                    }
                                                }
                                                else if (data.weaponRenderer.legacyAnim)
                                                {
                                                    //Play animation
                                                    data.weaponRenderer.legacyAnim.Play(data.weaponRenderer.legacyAnimData.reloadProceduralEnd, PlayMode.StopAll);
                                                }
                                                //Play sound
                                                data.soundReload.PlayOneShot(reloadProceduralEndSound);
                                            }
                                            else
                                            {
                                                //Play reload sound
                                                //Set clip
                                                pb.thirdPersonPlayerModel.soundReload.clip = reloadProceduralEndSound;
                                                //Set distance
                                                pb.thirdPersonPlayerModel.soundReload.maxDistance = reloadSoundThirdPersonMaxRange;
                                                //Set rolloff
                                                pb.thirdPersonPlayerModel.soundReload.SetCustomCurve(AudioSourceCurveType.CustomRolloff, reloadSoundThirdPersonRolloff);
                                                //Play
                                                pb.thirdPersonPlayerModel.soundReload.Play();
                                            }
                                            //Call network
                                            if (pb.isServer) pb.RpcWeaponProceduralReloadNetwork(4);
                                        }
                                    }
                                    else if (data.reloadPhase == 4)
                                    {
                                        //It is over, end reload
                                        data.reloadInProgress = false;
                                        data.reloadPhase = 0;
                                    }
                                    break;
                            }
                        }
                    }

                    //Update aiming
                    if (data.isAiming)
                    {
                        //Increase progress
                        if (aimInTime > 0)
                        {
                            if (data.aimingProgress < 1) data.aimingProgress += Time.deltaTime / aimInTime;
                            //Clamp
                            data.aimingProgress = Mathf.Clamp01(data.aimingProgress);
                        }
                        else
                        {
                            //Instant mode
                            data.aimingProgress = 1f;
                        }
                    }
                    else
                    {
                        //Decrease progress
                        if (aimOutTime > 0)
                        {
                            if (data.aimingProgress > 0) data.aimingProgress -= Time.deltaTime / aimOutTime;
                            //Clamp
                            data.aimingProgress = Mathf.Clamp01(data.aimingProgress);
                        }
                        else
                        {
                            //Instant mode
                            data.aimingProgress = 0;
                        }
                    }

                    if (pb.isFirstPersonActive)
                    {
                        if (data.weaponRenderer.cachedUseFullscreenScope)
                        {
                            if (data.isAimedIn)
                            {
                                //We are aimed in, show scope
                                Kit_IngameMain.instance.hud.DisplaySniperScope(true);
                                //Snap fov
                                Kit_IngameMain.instance.mainCamera.fieldOfView = data.weaponRenderer.cachedAimingFov;
                                //Hide weapon
                                if (!data.sniperWeaponHidden)
                                {
                                    data.sniperWeaponHidden = true;
                                    data.weaponRenderer.visible = false;
                                }
                            }
                            else
                            {
                                //We are not aimed in, hide the scope
                                Kit_IngameMain.instance.hud.DisplaySniperScope(false);
                                //Smoothly fade FoV
                                Kit_IngameMain.instance.mainCamera.fieldOfView = Mathf.Lerp(Kit_GameSettings.baseFov, Kit_GameSettings.baseFov - 5f, data.aimingProgress);
                                //Show weapon
                                if (data.sniperWeaponHidden)
                                {
                                    data.sniperWeaponHidden = false;
                                    data.weaponRenderer.visible = true;
                                }
                            }
                        }
                        else
                        {
                            //Sniper scope is not active, just hide it
                            Kit_IngameMain.instance.hud.DisplaySniperScope(false);
                            //Smoothly fade FoV
                            Kit_IngameMain.instance.mainCamera.fieldOfView = Mathf.Lerp(Kit_GameSettings.baseFov, data.weaponRenderer.cachedAimingFov, data.aimingProgress);
                        }

                        //Update position and rotation
                        data.aimingTransform.localPosition = Vector3.Lerp(Vector3.zero, data.weaponRenderer.cachedAimingPos, data.aimingProgress);
                        data.aimingTransform.localRotation = Quaternion.Slerp(Quaternion.identity, Quaternion.Euler(data.weaponRenderer.cachedAimingRot), data.aimingProgress);
                    }

                    if (data.bulletSpreadMode == SpreadMode.SprayPattern && !data.isFiring)
                    {
                        //Spray pattern recovery
                        if (data.sprayPatternState > 0f)
                        {
                            data.sprayPatternState -= Time.deltaTime * data.bulletSpreadSprayPatternRecoverySpeed;
                        }
                        else
                        {
                            data.sprayPatternState = 0f;
                        }
                    }

                    //Shell ejection
                    if (data.shellEjectEnabled) //Check if shell ejection is enabled
                    {
                        //Check if enough time has passed
                        if (Time.time >= data.shellEjectNext || shellEjectionTime <= 0)
                        {
                            //Set ejection bool
                            data.shellEjectEnabled = false;
                            //Eject shell
                            EjectShell(pb, data);
                        }
                    }

                    //Check for bolt action
                    if (data.boltActionState == 1 || data.boltActionState == 2)
                    {
                        //Check if the time has passed
                        if (Time.time > data.boltActionTime)
                        {
                            if (pb.isFirstPersonActive)
                            {
                                //Set values
                                data.soundOther.loop = false;


                                //Set correct clip
                                if (data.boltActionState == 1)
                                {
                                    data.soundOther.clip = boltActionSoundNormal;
                                }
                                else
                                {
                                    data.soundOther.clip = boltActionSoundLast;
                                }

                                //Play
                                data.soundOther.Play();
                            }

                            //Set back to 0
                            data.boltActionState = 0;
                        }
                    }

                    if (pb.isFirstPersonActive)
                    {
                        //Update HUD
                        Kit_IngameMain.instance.hud.DisplayAmmo(data.bulletsLeft, data.bulletsLeftToReload);
                        Kit_IngameMain.instance.hud.DisplayCrosshair(GetCrosshairSize(pb, data), pb.looking.GetPerspective(pb) == Kit_GameInformation.Perspective.ThirdPerson);
                    }
                }
            }

            public override void PredictionInput(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData, Kit_PlayerInput input, float delta)
            {

            }

            public override void CalculateWeaponUpdate(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData)
            {
                Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;

                if (pb.isServer || pb.isLocalPlayer)
                {

                }
                else
                {
                    //Fire Replica
                    if (data.fireMode == FireMode.Auto)
                    {
                        if (data.isFiring)
                        {
                            //Compare with fire rate
                            if (Time.time >= data.lastFire + data.fireRate)
                            {
                                FireOneShot(pb, data, 0, 0, true);
                            }
                        }
                    }
                }
            }

            public override void AnimateWeapon(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData, int id, float speed)
            {
                if (pb.isServer || pb.isOwned)
                {
                    if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                    {
                        Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;

                        //Recoil
                        //Apply to transform
                        pb.recoilApplyRotation = Quaternion.Slerp(pb.recoilApplyRotation, Quaternion.identity, Time.deltaTime * data.recoilReturnSpeed);
                    }
                }

                if (pb.isFirstPersonActive)
                {
                    if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                    {
                        Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;


                        data.weaponRenderer.WeaponUpdate(this, data);

                        //Camera animation
                        if (data.weaponRenderer.cameraAnimationEnabled)
                        {
                            if (data.weaponRenderer.cameraAnimationType == CameraAnimationType.Copy)
                            {
                                if (data.weaponRenderer.cameraAnimationBone) pb.playerCameraAnimationTransform.localRotation = Quaternion.Euler(data.weaponRenderer.cameraAnimationReferenceRotation) * data.weaponRenderer.cameraAnimationBone.localRotation;
                                else pb.playerCameraAnimationTransform.localRotation = Quaternion.Slerp(pb.playerCameraAnimationTransform.localRotation, Quaternion.identity, Time.deltaTime * 5f);
                            }
                            else if (data.weaponRenderer.cameraAnimationType == CameraAnimationType.LookAt)
                            {
                                if (data.weaponRenderer.cameraAnimationBone && data.weaponRenderer.cameraAnimationTarget) pb.playerCameraAnimationTransform.localRotation = Quaternion.Euler(data.weaponRenderer.cameraAnimationReferenceRotation) * Quaternion.LookRotation(data.weaponRenderer.cameraAnimationTarget.localPosition - data.weaponRenderer.cameraAnimationBone.localPosition);
                                else pb.playerCameraAnimationTransform.localRotation = Quaternion.Slerp(pb.playerCameraAnimationTransform.localRotation, Quaternion.identity, Time.deltaTime * 5f);
                            }
                        }
                        else
                        {
                            //Go back to 0,0,0
                            pb.playerCameraAnimationTransform.localRotation = Quaternion.Slerp(pb.playerCameraAnimationTransform.localRotation, Quaternion.identity, Time.deltaTime * 5f);
                        }

                        //Weapon delay calculation
                        data.weaponDelayLastDifference = data.weaponDelayLastRotation * Quaternion.Inverse(pb.mouseLookObject.rotation);
                        Vector3 differenceEulerAngles = data.weaponDelayLastDifference.eulerAngles;
                        float x = differenceEulerAngles.y;
                        float y = differenceEulerAngles.x;

                        if (x > 180) x -= 360f;
                        if (y > 180) y -= 360f;

                        //Get input from the mouse
                        data.weaponDelayCurrentX = x * weaponDelayBaseAmount * Time.deltaTime;
                        data.weaponDelayCurrentY = -y * weaponDelayBaseAmount * Time.deltaTime;

                        data.weaponDelayLastRotation = pb.mouseLookObject.rotation;

                        //Clamp
                        data.weaponDelayCurrentX = Mathf.Clamp(data.weaponDelayCurrentX, -weaponDelayMaxAmount, weaponDelayMaxAmount);
                        data.weaponDelayCurrentY = Mathf.Clamp(data.weaponDelayCurrentY, -weaponDelayMaxAmount, weaponDelayMaxAmount);

                        //Aiming multiplier
                        if (data.isAiming)
                        {
                            data.weaponDelayCurrentX *= weaponDelayAimingMultiplier;
                            data.weaponDelayCurrentY *= weaponDelayAimingMultiplier;
                        }

                        //Update Vector
                        data.weaponDelayCur.x = data.weaponDelayCurrentX;
                        data.weaponDelayCur.y = data.weaponDelayCurrentY;
                        data.weaponDelayCur.z = 0f;

                        //Smooth move towards the target
                        data.weaponDelayTransform.localPosition = Vector3.Lerp(data.weaponDelayTransform.localPosition, data.weaponDelayCur, Time.deltaTime * weaponDelaySmooth);

                        //Weapon tilt
                        if (weaponTiltEnabled)
                        {
                            if (!weaponTiltEnabledWhileAiming && data.isAiming)
                            {
                                data.weaponDelayTransform.localRotation = Quaternion.Slerp(data.weaponDelayTransform.localRotation, Quaternion.identity, Time.deltaTime * weaponTiltReturnSpeed);
                            }
                            else
                            {
                                data.weaponDelayTransform.localRotation = Quaternion.Slerp(data.weaponDelayTransform.localRotation, Quaternion.Euler(0, 0, -pb.movement.GetMovementDirection(pb).x * weaponTiltIntensity), Time.deltaTime * weaponTiltReturnSpeed);
                            }
                        }
                        else
                        {
                            data.weaponDelayTransform.localRotation = Quaternion.Slerp(data.weaponDelayTransform.localRotation, Quaternion.identity, Time.deltaTime * weaponTiltReturnSpeed);
                        }

                        //Weapon Fall
                        data.weaponFallTransform.localRotation = Quaternion.Slerp(data.weaponFallTransform.localRotation, Quaternion.identity, Time.deltaTime * fallDownReturnSpeed);

                        //Set speed
                        if (id != 0)
                        {
                            data.genericAnimator.SetFloat("speed", speed);
                        }
                        //If idle, set speed to 1
                        else
                        {
                            data.genericAnimator.SetFloat("speed", 1f);
                        }

                        //Run position and rotation
                        //Check state and if we can move (Selected, not reloading)
                        if (id == 2 && data.isSelectedAndReady && !data.reloadInProgress && data.weaponRenderer.useRunPosRot)
                        {
                            //Move to run pos
                            data.weaponRenderer.transform.localPosition = Vector3.Lerp(data.weaponRenderer.transform.localPosition, data.weaponRenderer.runPos, Time.deltaTime * data.weaponRenderer.runSmooth);
                            //Move to run rot
                            data.weaponRenderer.transform.localRotation = Quaternion.Slerp(data.weaponRenderer.transform.localRotation, Quaternion.Euler(data.weaponRenderer.runRot), Time.deltaTime * data.weaponRenderer.runSmooth);
                            //Set time
                            data.lastRun = Time.time;
                        }
                        else
                        {
                            //Move back to idle pos
                            data.weaponRenderer.transform.localPosition = Vector3.Lerp(data.weaponRenderer.transform.localPosition, Vector3.zero, Time.deltaTime * data.weaponRenderer.runSmooth * 2f);
                            //Move back to idle rot
                            data.weaponRenderer.transform.localRotation = Quaternion.Slerp(data.weaponRenderer.transform.localRotation, Quaternion.identity, Time.deltaTime * data.weaponRenderer.runSmooth * 2f);
                        }

                        //Make sure idle anim is playing if no anim is playing
                        if (data.weaponRenderer.legacyAnim && !data.weaponRenderer.legacyAnim.isPlaying && data.isSelectedAndReady)
                        {
                            if (data.bulletsLeft == 0)
                            {
                                data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idleEmpty].wrapMode = WrapMode.Loop;
                                data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idleEmpty].speed = data.weaponRenderer.legacyAnimData.idleAnimationSpeed;
                                data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.idleEmpty, 0.3f, PlayMode.StopAll);
                            }
                            else
                            {
                                data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idle].wrapMode = WrapMode.Loop;
                                data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idle].speed = data.weaponRenderer.legacyAnimData.idleAnimationSpeed;
                                data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.idle, 0.3f, PlayMode.StopAll);
                            }
                        }

                        //If we are aiming, force idle animation
                        if (data.isAiming && !enableWalkAnimationWhileAiming)
                        {
                            //Play idle animation
                            data.genericAnimator.CrossFade("Idle", 0.3f);
                            //Also set last id to 0, so it can be updated if we stop aiming
                            data.lastWeaponAnimationID = 0;

                            if (sendRunningEvents)
                            {
                                //End run animation on weapon animator
                                if (data.startedRunAnimation)
                                {
                                    data.startedRunAnimation = false;
                                    if (data.weaponRenderer.anim)
                                    {
                                        data.weaponRenderer.anim.ResetTrigger("Start Run");
                                        data.weaponRenderer.anim.SetTrigger("End Run");

                                        for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                        {
                                            data.weaponRenderer.animAdditionals[i].ResetTrigger("Start Run");
                                            data.weaponRenderer.animAdditionals[i].SetTrigger("End Run");
                                        }
                                    }
                                    else if (data.weaponRenderer.legacyAnim)
                                    {
                                        if (data.bulletsLeft == 0)
                                        {
                                            data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idleEmpty].wrapMode = WrapMode.Loop;
                                            data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idleEmpty].speed = data.weaponRenderer.legacyAnimData.idleAnimationSpeed;
                                            data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.idleEmpty, 0.3f, PlayMode.StopAll);
                                        }
                                        else
                                        {
                                            data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idle].wrapMode = WrapMode.Loop;
                                            data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idle].speed = data.weaponRenderer.legacyAnimData.idleAnimationSpeed;
                                            data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.idle, 0.3f, PlayMode.StopAll);
                                        }
                                    }
                                }
                            }
                        }
                        else
                        {
                            //Check if state changed
                            if (id != data.lastWeaponAnimationID)
                            {
                                //Idle
                                if (id == 0)
                                {
                                    //Play idle animation
                                    data.genericAnimator.CrossFade("Idle", 0.3f);

                                    if (sendRunningEvents)
                                    {
                                        //End run animation on weapon animator
                                        if (data.startedRunAnimation)
                                        {
                                            data.startedRunAnimation = false;
                                            if (data.weaponRenderer.anim)
                                            {
                                                data.weaponRenderer.anim.ResetTrigger("Start Run");
                                                data.weaponRenderer.anim.SetTrigger("End Run");

                                                for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                {
                                                    data.weaponRenderer.animAdditionals[i].ResetTrigger("Start Run");
                                                    data.weaponRenderer.animAdditionals[i].SetTrigger("End Run");
                                                }
                                            }
                                            else if (data.weaponRenderer.legacyAnim)
                                            {
                                                if (data.bulletsLeft == 0)
                                                {
                                                    data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idleEmpty].wrapMode = WrapMode.Loop;
                                                    data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idleEmpty].speed = data.weaponRenderer.legacyAnimData.idleAnimationSpeed;
                                                    data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.idleEmpty, 0.3f, PlayMode.StopAll);
                                                }
                                                else
                                                {
                                                    data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idle].wrapMode = WrapMode.Loop;
                                                    data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idle].speed = data.weaponRenderer.legacyAnimData.idleAnimationSpeed;
                                                    data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.idle, 0.3f, PlayMode.StopAll);
                                                }
                                            }
                                        }
                                    }
                                }
                                //Walk
                                else if (id == 1 && (!data.isAiming || enableWalkAnimationWhileAiming))
                                {
                                    //Check if we should use generic anim
                                    if (useGenericWalkAnim)
                                    {
                                        //Play run animation
                                        data.genericAnimator.CrossFade("Walk", 0.2f);
                                    }
                                    //If not continue to play Idle
                                    else
                                    {
                                        //Play idle animation
                                        data.genericAnimator.CrossFade("Idle", 0.3f);
                                    }

                                    if (sendRunningEvents)
                                    {
                                        //End run animation on weapon animator
                                        if (data.startedRunAnimation)
                                        {
                                            data.startedRunAnimation = false;
                                            if (data.weaponRenderer.anim)
                                            {
                                                data.weaponRenderer.anim.ResetTrigger("Start Run");
                                                data.weaponRenderer.anim.SetTrigger("End Run");

                                                for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                {
                                                    data.weaponRenderer.animAdditionals[i].ResetTrigger("Start Run");
                                                    data.weaponRenderer.animAdditionals[i].SetTrigger("End Run");
                                                }
                                            }
                                            else if (data.weaponRenderer.legacyAnim)
                                            {
                                                if (data.bulletsLeft == 0)
                                                {
                                                    data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idleEmpty].wrapMode = WrapMode.Loop;
                                                    data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idleEmpty].speed = data.weaponRenderer.legacyAnimData.idleAnimationSpeed;
                                                    data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.idleEmpty, 0.3f, PlayMode.StopAll);
                                                }
                                                else
                                                {
                                                    data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idle].wrapMode = WrapMode.Loop;
                                                    data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idle].speed = data.weaponRenderer.legacyAnimData.idleAnimationSpeed;
                                                    data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.idle, 0.3f, PlayMode.StopAll);
                                                }
                                            }
                                        }
                                    }
                                }
                                //Run
                                else if (id == 2 && (!data.isAiming || enableWalkAnimationWhileAiming))
                                {
                                    //Check if we should use generic anim
                                    if (useGenericRunAnim)
                                    {
                                        //Play run animation
                                        data.genericAnimator.CrossFade("Run", 0.2f);
                                    }
                                    //If not continue to play Idle
                                    else if (sendRunningEvents)
                                    {
                                        //Play idle animation
                                        data.genericAnimator.CrossFade("Idle", 0.3f);
                                        //Start run animation on weapon animator
                                        if (!data.startedRunAnimation && !data.reloadInProgress && data.isSelectedAndReady)
                                        {
                                            data.startedRunAnimation = true;
                                            if (data.weaponRenderer.anim)
                                            {
                                                data.weaponRenderer.anim.ResetTrigger("End Run");
                                                data.weaponRenderer.anim.SetTrigger("Start Run");

                                                for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                {
                                                    data.weaponRenderer.animAdditionals[i].ResetTrigger("End Run");
                                                    data.weaponRenderer.animAdditionals[i].SetTrigger("Start Run");
                                                }
                                            }
                                            else if (data.weaponRenderer.legacyAnim)
                                            {
                                                if (data.bulletsLeft == 0)
                                                {
                                                    data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.runEmpty].wrapMode = WrapMode.Loop;
                                                    data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.runEmpty, 0.3f, PlayMode.StopAll);
                                                }
                                                else
                                                {
                                                    data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.run].wrapMode = WrapMode.Loop;
                                                    data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.run, 0.3f, PlayMode.StopAll);
                                                }
                                            }
                                        }
                                    }
                                }
                                else
                                {
                                    //End run animation on weapon animator
                                    if (data.startedRunAnimation)
                                    {
                                        data.startedRunAnimation = false;
                                        if (data.weaponRenderer.anim)
                                        {
                                            data.weaponRenderer.anim.ResetTrigger("Start Run");
                                            data.weaponRenderer.anim.SetTrigger("End Run");

                                            for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                            {
                                                data.weaponRenderer.animAdditionals[i].ResetTrigger("Start Run");
                                                data.weaponRenderer.animAdditionals[i].SetTrigger("End Run");
                                            }
                                        }
                                        else if (data.weaponRenderer.legacyAnim)
                                        {
                                            if (data.bulletsLeft == 0)
                                            {
                                                data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idleEmpty].wrapMode = WrapMode.Loop;
                                                data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idleEmpty].speed = data.weaponRenderer.legacyAnimData.idleAnimationSpeed;
                                                data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.idleEmpty, 0.3f, PlayMode.StopAll);
                                            }
                                            else
                                            {
                                                data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idle].wrapMode = WrapMode.Loop;
                                                data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idle].speed = data.weaponRenderer.legacyAnimData.idleAnimationSpeed;
                                                data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.idle, 0.3f, PlayMode.StopAll);
                                            }
                                        }
                                    }
                                }
                                //Update last state
                                data.lastWeaponAnimationID = id;
                            }
                            else
                            {
                                if (sendRunningEvents)
                                {
                                    //Idle
                                    if (id == 0)
                                    {
                                        //End run animation on weapon animator
                                        if (data.startedRunAnimation)
                                        {
                                            data.startedRunAnimation = false;
                                            if (data.weaponRenderer.anim)
                                            {
                                                data.weaponRenderer.anim.ResetTrigger("Start Run");
                                                data.weaponRenderer.anim.SetTrigger("End Run");

                                                for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                {
                                                    data.weaponRenderer.animAdditionals[i].ResetTrigger("Start Run");
                                                    data.weaponRenderer.animAdditionals[i].SetTrigger("End Run");
                                                }
                                            }
                                            else if (data.weaponRenderer.legacyAnim)
                                            {
                                                if (data.bulletsLeft == 0)
                                                {
                                                    data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idleEmpty].wrapMode = WrapMode.Loop;
                                                    data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idleEmpty].speed = data.weaponRenderer.legacyAnimData.idleAnimationSpeed;
                                                    data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.idleEmpty, 0.3f, PlayMode.StopAll);
                                                }
                                                else
                                                {
                                                    data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idle].wrapMode = WrapMode.Loop;
                                                    data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idle].speed = data.weaponRenderer.legacyAnimData.idleAnimationSpeed;
                                                    data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.idle, 0.3f, PlayMode.StopAll);
                                                }
                                            }
                                        }
                                    }
                                    //Walk
                                    else if (id == 1 && (!data.isAiming || enableWalkAnimationWhileAiming))
                                    {
                                        //End run animation on weapon animator
                                        if (data.startedRunAnimation)
                                        {
                                            data.startedRunAnimation = false;
                                            if (data.weaponRenderer.anim)
                                            {
                                                data.weaponRenderer.anim.ResetTrigger("Start Run");
                                                data.weaponRenderer.anim.SetTrigger("End Run");

                                                for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                {
                                                    data.weaponRenderer.animAdditionals[i].ResetTrigger("Start Run");
                                                    data.weaponRenderer.animAdditionals[i].SetTrigger("End Run");
                                                }
                                            }
                                            else if (data.weaponRenderer.legacyAnim)
                                            {
                                                if (data.bulletsLeft == 0)
                                                {
                                                    data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idleEmpty].wrapMode = WrapMode.Loop;
                                                    data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idleEmpty].speed = data.weaponRenderer.legacyAnimData.idleAnimationSpeed;
                                                    data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.idleEmpty, 0.3f, PlayMode.StopAll);
                                                }
                                                else
                                                {
                                                    data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idle].wrapMode = WrapMode.Loop;
                                                    data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idle].speed = data.weaponRenderer.legacyAnimData.idleAnimationSpeed;
                                                    data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.idle, 0.3f, PlayMode.StopAll);
                                                }
                                            }
                                        }
                                    }
                                    //Run
                                    else if (id == 2 && !data.isAiming)
                                    {
                                        //Start run animation on weapon animator
                                        if (!data.startedRunAnimation && !data.reloadInProgress && data.isSelectedAndReady)
                                        {
                                            data.startedRunAnimation = true;
                                            if (data.weaponRenderer.anim)
                                            {
                                                data.weaponRenderer.anim.ResetTrigger("End Run");
                                                data.weaponRenderer.anim.SetTrigger("Start Run");

                                                for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                {
                                                    data.weaponRenderer.animAdditionals[i].ResetTrigger("End Run");
                                                    data.weaponRenderer.animAdditionals[i].SetTrigger("Start Run");
                                                }
                                            }
                                            else if (data.weaponRenderer.legacyAnim)
                                            {
                                                if (data.bulletsLeft == 0)
                                                {
                                                    data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.runEmpty].wrapMode = WrapMode.Loop;
                                                    data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.runEmpty, 0.3f, PlayMode.StopAll);
                                                }
                                                else
                                                {
                                                    data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.run].wrapMode = WrapMode.Loop;
                                                    data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.run, 0.3f, PlayMode.StopAll);
                                                }
                                            }
                                        }
                                    }
                                    else
                                    {
                                        //End run animation on weapon animator
                                        if (data.startedRunAnimation)
                                        {
                                            data.startedRunAnimation = false;
                                            if (data.weaponRenderer.anim)
                                            {
                                                data.weaponRenderer.anim.ResetTrigger("Start Run");
                                                data.weaponRenderer.anim.SetTrigger("End Run");

                                                for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                                {
                                                    data.weaponRenderer.animAdditionals[i].ResetTrigger("Start Run");
                                                    data.weaponRenderer.animAdditionals[i].SetTrigger("End Run");
                                                }
                                            }
                                            else if (data.weaponRenderer.legacyAnim)
                                            {
                                                if (data.bulletsLeft == 0)
                                                {
                                                    data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idleEmpty].wrapMode = WrapMode.Loop;
                                                    data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idleEmpty].speed = data.weaponRenderer.legacyAnimData.idleAnimationSpeed;
                                                    data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.idleEmpty, 0.3f, PlayMode.StopAll);
                                                }
                                                else
                                                {
                                                    data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idle].wrapMode = WrapMode.Loop;
                                                    data.weaponRenderer.legacyAnim[data.weaponRenderer.legacyAnimData.idle].speed = data.weaponRenderer.legacyAnimData.idleAnimationSpeed;
                                                    data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.idle, 0.3f, PlayMode.StopAll);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        if (setRunningBool && pb.isFirstPersonActive && data.weaponRenderer.anim)
                        {
                            //Set empty bool 
                            data.weaponRenderer.anim.SetBool("running", id == 2 && !data.reloadInProgress);

                            for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                            {
                                data.weaponRenderer.animAdditionals[i].SetBool("running", id == 2 && !data.reloadInProgress);
                            }
                        }

                        if (setAimingProgress && pb.isFirstPersonActive && data.weaponRenderer.anim)
                        {
                            //Set empty bool
                            data.weaponRenderer.anim.SetFloat("aimingProgress", data.aimingProgress);

                            for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                            {
                                data.weaponRenderer.animAdditionals[i].SetFloat("aimingProgress", data.aimingProgress);
                            }
                        }

                        if (setAimingBool && pb.isFirstPersonActive && data.weaponRenderer.anim)
                        {
                            //Set empty bool
                            data.weaponRenderer.anim.SetBool("aiming", data.isAiming);

                            for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                            {
                                data.weaponRenderer.animAdditionals[i].SetBool("aiming", data.isAiming);
                            }
                        }

                        if (setMovementDirection && pb.isFirstPersonActive && data.weaponRenderer.anim)
                        {
                            Vector3 dir = pb.movement.GetMovementDirection(pb);
                            //Set empty bool
                            data.weaponRenderer.anim.SetFloat("ver", dir.z, 0.1f, Time.deltaTime);
                            data.weaponRenderer.anim.SetFloat("hor", dir.x, 0.1f, Time.deltaTime);
                            data.weaponRenderer.anim.SetFloat("walkSpeed", pb.movement.GetVelocity(pb).magnitude);

                            for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                            {
                                data.weaponRenderer.animAdditionals[i].SetFloat("ver", dir.z, 0.1f, Time.deltaTime);
                                data.weaponRenderer.animAdditionals[i].SetFloat("hor", dir.x, 0.1f, Time.deltaTime);
                                data.weaponRenderer.animAdditionals[i].SetFloat("walkSpeed", pb.movement.GetVelocity(pb).magnitude);
                            }
                        }
                    }
                }
            }

            public override void FallDownEffect(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData, bool wasFallDamageApplied)
            {
                if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                {
                    Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;
                    if (wasFallDamageApplied)
                    {
                        Kit_ScriptableObjectCoroutineHelper.instance.StartCoroutine(Kit_ScriptableObjectCoroutineHelper.instance.Kick(data.weaponFallTransform, new Vector3(fallDownAmount, Random.Range(fallDownMinOffset, fallDownMaxoffset), 0), fallDownTime));
                    }
                    else
                    {
                        Kit_ScriptableObjectCoroutineHelper.instance.StartCoroutine(Kit_ScriptableObjectCoroutineHelper.instance.Kick(data.weaponFallTransform, new Vector3(fallDownAmount / 3, Random.Range(fallDownMinOffset, fallDownMaxoffset) / 2, 0), fallDownTime));
                    }
                }
            }

            public override void DrawWeapon(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData)
            {
                if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                {
                    Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;

                    //Reset firing
                    data.isFiring = false;
                    //Set selected
                    data.isSelected = true;
                    if (pb.isFirstPersonActive)
                    {
                        //Reset pos & rot of the renderer
                        data.weaponRenderer.transform.localPosition = Vector3.zero;
                        data.weaponRenderer.transform.localRotation = Quaternion.identity;
                        //Reset fov
                        Kit_IngameMain.instance.mainCamera.fieldOfView = Kit_GameSettings.baseFov;
                        //Reset delay
                        data.weaponDelayCur = Vector3.zero;
                        //Call renderer
                        data.weaponRenderer.WeaponDraw();
                    }
                    //Reset aiming
                    data.aimingProgress = 0f;
                    if (pb.isFirstPersonActive)
                    {
                        data.aimingTransform.localPosition = Vector3.zero;
                        data.aimingTransform.localRotation = Quaternion.identity;
                    }
                    data.isAiming = false;
                    //Set default values
                    data.reloadInProgress = false;
                    //Reset spray pattern
                    data.sprayPatternState = 0f;
                    if (pb.isFirstPersonActive)
                    {
                        //Enable anim
                        if (data.weaponRenderer.anim)
                        {
                            //Disable anim
                            data.weaponRenderer.anim.enabled = true;
                            //Play animation
                            data.weaponRenderer.anim.Play("Draw", data.weaponRenderer.animActionLayer, 0f);

                            for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                            {
                                data.weaponRenderer.animAdditionals[i].enabled = true;
                                data.weaponRenderer.animAdditionals[i].Play("Draw", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                            }

                            if (setEmptyBool)
                            {
                                //Set empty bool
                                data.weaponRenderer.anim.SetBool("empty", data.bulletsLeft == 0);

                                for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                {
                                    data.weaponRenderer.animAdditionals[i].SetBool("empty", data.bulletsLeft == 0);
                                }
                            }
                        }
                        else if (data.weaponRenderer.legacyAnim)
                        {
                            data.weaponRenderer.legacyAnim.enabled = true;
                            if (data.bulletsLeft == 0)
                            {
                                //Play animation
                                data.weaponRenderer.legacyAnim.Play(data.weaponRenderer.legacyAnimData.drawEmpty, PlayMode.StopAll);
                            }
                            else
                            {
                                //Play animation
                                data.weaponRenderer.legacyAnim.Play(data.weaponRenderer.legacyAnimData.draw, PlayMode.StopAll);
                            }
                        }
                        //Reset shell ejection
                        data.shellEjectEnabled = false;
                        data.shellEjectNext = 0f;
                    }
                    //Reset bolt
                    data.boltActionState = 0;
                    data.boltActionTime = 0f;
                    if (pb.isFirstPersonActive)
                    {
                        //Play sound if it is assigned
                        if (drawSound) data.soundOther.PlayOneShot(drawSound);
                        if (pb.looking.GetPerspective(pb) == Kit_GameInformation.Perspective.FirstPerson)
                        {
                            //Show weapon
                            data.weaponRenderer.visible = true;
                        }
                        else
                        {
                            data.weaponRenderer.visible = false;
                        }
                    }
                    if (pb.looking.GetPerspective(pb) == Kit_GameInformation.Perspective.FirstPerson && pb.isFirstPersonActive)
                    {
                        //Show tp weapon and hide
                        data.tpWeaponRenderer.visible = true;
                        data.tpWeaponRenderer.shadowsOnly = true;
                    }
                    else
                    {
                        //Show tp weapon and show
                        data.tpWeaponRenderer.visible = true;
                        data.tpWeaponRenderer.shadowsOnly = false;
                    }
                    //Make sure it is not ready yet
                    data.isSelectedAndReady = false;
                    //Reset run animation
                    data.startedRunAnimation = false;
                    //Set third person anim type
                    pb.thirdPersonPlayerModel.SetAnimType(thirdPersonAnimType);
                    //Stop third person anims
                    pb.thirdPersonPlayerModel.AbortWeaponAnimations();
                }
            }

            public override void PutawayWeapon(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData)
            {
                if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                {
                    Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;

                    //Reset firing
                    data.isFiring = false;
                    //Reset aiming
                    data.aimingProgress = 0f;
                    //Reset reload
                    data.reloadInProgress = false;
                    if (pb.isFirstPersonActive)
                    {
                        data.aimingTransform.localPosition = Vector3.zero;
                        data.aimingTransform.localRotation = Quaternion.identity;
                        //Call renderer
                        data.weaponRenderer.WeaponPutaway();
                    }
                    data.isAiming = false;
                    if (pb.isFirstPersonActive)
                    {
                        //Check if we need to hide scope
                        if (data.weaponRenderer.cachedUseFullscreenScope)
                        {
                            //Hide
                            Kit_IngameMain.instance.hud.DisplaySniperScope(false);
                        }
                        //Reset fov
                        Kit_IngameMain.instance.mainCamera.fieldOfView = Kit_GameSettings.baseFov;
                        //Enable anim
                        if (data.weaponRenderer.anim)
                        {
                            //Disable anim
                            data.weaponRenderer.anim.enabled = true;

                            for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                            {
                                data.weaponRenderer.animAdditionals[i].enabled = true;
                            }
                        }
                        else if (data.weaponRenderer.legacyAnim)
                        {
                            data.weaponRenderer.legacyAnim.enabled = true;
                        }
                        if (setEmptyBool)
                        {
                            //Set empty bool
                            data.weaponRenderer.anim.SetBool("empty", data.bulletsLeft == 0);

                            for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                            {
                                data.weaponRenderer.animAdditionals[i].SetBool("empty", data.bulletsLeft == 0);
                            }
                        }
                        //Play animation
                        if (data.weaponRenderer.anim)
                        {
                            //Play animation
                            data.weaponRenderer.anim.Play("Putaway", data.weaponRenderer.animActionLayer, 0f);

                            for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                            {
                                data.weaponRenderer.animAdditionals[i].Play("Putaway", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                            }
                        }
                        else if (data.weaponRenderer.legacyAnim)
                        {
                            //Play animation
                            if (data.bulletsLeft == 0)
                            {
                                data.weaponRenderer.legacyAnim.Play(data.weaponRenderer.legacyAnimData.putawayEmpty, PlayMode.StopAll);
                            }
                            else
                            {
                                data.weaponRenderer.legacyAnim.Play(data.weaponRenderer.legacyAnimData.putaway, PlayMode.StopAll);
                            }
                        }
                        //Stop reload sound
                        data.soundReload.Stop();
                        //Play sound if it is assigned
                        if (putawaySound) data.soundOther.PlayOneShot(putawaySound);
                        if (pb.looking.GetPerspective(pb) == Kit_GameInformation.Perspective.FirstPerson)
                        {
                            //Show weapon
                            data.weaponRenderer.visible = true;
                        }
                        else
                        {
                            //Hide
                            data.weaponRenderer.visible = false;
                        }
                    }
                    if (pb.looking.GetPerspective(pb) == Kit_GameInformation.Perspective.FirstPerson && pb.isFirstPersonActive)
                    {
                        //Show tp weapon
                        data.tpWeaponRenderer.visible = true;
                        data.tpWeaponRenderer.shadowsOnly = true;
                    }
                    else
                    {
                        data.tpWeaponRenderer.visible = true;
                        data.tpWeaponRenderer.shadowsOnly = false;
                    }
                    //Make sure it is not ready yet
                    data.isSelectedAndReady = false;
                    //Stop third person anims
                    pb.thirdPersonPlayerModel.AbortWeaponAnimations();
                }
            }

            public override void PutawayWeaponHide(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData)
            {
                if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                {
                    Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;

                    //Set selected
                    data.isSelected = false;
                    //Reset run animation
                    data.startedRunAnimation = false;
                    //Reset firing
                    data.isFiring = false;
                    //Reset aiming
                    data.aimingProgress = 0f;
                    if (pb.isFirstPersonActive)
                    {
                        data.aimingTransform.localPosition = Vector3.zero;
                        data.aimingTransform.localRotation = Quaternion.identity;
                        //Call renderer
                        data.weaponRenderer.WeaponPutawayHide();
                    }
                    data.isAiming = false;
                    if (pb.isFirstPersonActive)
                    {
                        //Check if we need to hide scope
                        if (data.weaponRenderer.cachedUseFullscreenScope)
                        {
                            //Hide
                            Kit_IngameMain.instance.hud.DisplaySniperScope(false);
                        }
                        //Reset fov
                        Kit_IngameMain.instance.mainCamera.fieldOfView = Kit_GameSettings.baseFov;
                        //Hide weapon
                        data.weaponRenderer.visible = false;
                        if (data.weaponRenderer.anim)
                        {
                            //Disable anim
                            data.weaponRenderer.anim.enabled = false;

                            for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                            {
                                data.weaponRenderer.animAdditionals[i].enabled = false;
                            }
                        }
                        else if (data.weaponRenderer.legacyAnim)
                        {
                            data.weaponRenderer.legacyAnim.enabled = false;
                        }
                        //Reset pos & rot of the renderer
                        data.weaponRenderer.transform.localPosition = Vector3.zero;
                        data.weaponRenderer.transform.localRotation = Quaternion.identity;
                        //Reset delay
                        data.weaponDelayCur = Vector3.zero;
                    }
                    //Hide tp weapon
                    data.tpWeaponRenderer.visible = false;
                    //Make sure it is not ready
                    data.isSelectedAndReady = false;
                    //Stop third person anims
                    pb.thirdPersonPlayerModel.AbortWeaponAnimations();
                }
            }

            public override void QuickUseOnOtherWeaponBegin(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData)
            {
                if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                {
                    Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;

                    if (pb.isFirstPersonActive)
                    {
                        data.soundReload.Stop();
                        data.soundOther.Stop();
                    }

                    pb.thirdPersonPlayerModel.soundReload.Stop();
                    pb.thirdPersonPlayerModel.soundOther.Stop();
                }
            }

            public override void NetworkSemiRPCReceived(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData)
            {
                if (!pb.isLocalPlayer && !pb.isServer)
                {
                    if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                    {
                        Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;
                        FireOneShot(pb, data, 0, 0, true);
                    }
                }
            }

            public override void NetworkBoltActionRPCReceived(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData, int state)
            {
                if (!pb.isLocalPlayer && !pb.isServer)
                {
                    if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                    {
                        Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;
                        FireOneShot(pb, data, 0, 0, true);
                    }
                }
            }

            public override void NetworkBurstRPCReceived(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData, int burstLength)
            {
                if (!pb.isLocalPlayer && !pb.isServer)
                {
                    if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                    {
                        Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;
                        FireBurst(pb, data, 0, 0, true);
                    }
                }
            }

            public override void NetworkReloadRPCReceived(Kit_PlayerBehaviour pb, bool isEmpty, Kit_WeaponRuntimeDataBase runtimeData)
            {
                if (!pb.isLocalPlayer && !pb.isServer)
                {
                    if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                    {
                        Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;

                        //Play third person reload animation
                        pb.thirdPersonPlayerModel.PlayWeaponReloadAnimation(thirdPersonAnimType, isEmpty ? 1 : 0);
                        //Play reload sound
                        if (isEmpty)
                        {
                            if (pb.isFirstPersonActive)
                            {
                                //Set clip
                                data.soundReload.clip = reloadSoundEmpty;
                                //Play
                                data.soundReload.Play();

                                if (data.weaponRenderer.anim)
                                {
                                    //Play animation
                                    data.weaponRenderer.anim.Play("Reload Empty", data.weaponRenderer.animActionLayer, 0f);

                                    for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                    {
                                        data.weaponRenderer.animAdditionals[i].Play("Reload Empty", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                    }
                                }
                                else if (data.weaponRenderer.legacyAnim)
                                {
                                    //Play animation
                                    data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.reloadEmpty, 0.15f, PlayMode.StopAll);
                                }
                            }
                            else
                            {
                                //Set clip
                                pb.thirdPersonPlayerModel.soundReload.clip = reloadSoundEmpty;
                                //Set distance
                                pb.thirdPersonPlayerModel.soundReload.maxDistance = reloadSoundThirdPersonMaxRange;
                                //Set rolloff
                                pb.thirdPersonPlayerModel.soundReload.SetCustomCurve(AudioSourceCurveType.CustomRolloff, reloadSoundThirdPersonRolloff);
                                //Play
                                pb.thirdPersonPlayerModel.soundReload.Play();
                            }
                        }
                        else
                        {
                            if (pb.isFirstPersonActive)
                            {
                                //Set clip
                                data.soundReload.clip = reloadSound;
                                //Play
                                data.soundReload.Play();

                                if (data.weaponRenderer.anim)
                                {
                                    //Play animation
                                    data.weaponRenderer.anim.Play("Reload Full", data.weaponRenderer.animActionLayer, 0f);

                                    for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                    {
                                        data.weaponRenderer.animAdditionals[i].Play("Reload Full", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                    }
                                }
                                else if (data.weaponRenderer.legacyAnim)
                                {
                                    //Play animation
                                    data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.reload, 0.15f, PlayMode.StopAll);
                                }
                            }
                            else
                            {
                                //Set clip
                                pb.thirdPersonPlayerModel.soundReload.clip = reloadSound;
                                //Set distance
                                pb.thirdPersonPlayerModel.soundReload.maxDistance = reloadSoundThirdPersonMaxRange;
                                //Set rolloff
                                pb.thirdPersonPlayerModel.soundReload.SetCustomCurve(AudioSourceCurveType.CustomRolloff, reloadSoundThirdPersonRolloff);
                                //Play
                                pb.thirdPersonPlayerModel.soundReload.Play();
                            }
                        }
                    }
                }
            }

            public override void NetworkProceduralReloadRPCReceived(Kit_PlayerBehaviour pb, int stage, Kit_WeaponRuntimeDataBase runtimeData)
            {
                if (!pb.isLocalPlayer && !pb.isServer)
                {
                    if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                    {
                        Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;

                        //Play sounds
                        //0 = Start
                        if (stage == 0)
                        {
                            if (pb.isFirstPersonActive)
                            {
                                if (data.weaponRenderer.anim)
                                {
                                    //Play animation
                                    data.weaponRenderer.anim.Play("Reload Procedural Start", data.weaponRenderer.animActionLayer, 0f);

                                    for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                    {
                                        data.weaponRenderer.animAdditionals[i].Play("Reload Procedural Start", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                    }
                                }
                                else if (data.weaponRenderer.legacyAnim)
                                {
                                    //Play animation
                                    data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.reloadProceduralStart, 0.15f, PlayMode.StopAll);
                                }
                                //Play sound
                                data.soundReload.PlayOneShot(reloadProceduralStartSound);
                            }
                            else
                            {
                                //Set clip
                                pb.thirdPersonPlayerModel.soundReload.clip = reloadProceduralStartSound;
                                //Set distance
                                pb.thirdPersonPlayerModel.soundReload.maxDistance = reloadSoundThirdPersonMaxRange;
                                //Set rolloff
                                pb.thirdPersonPlayerModel.soundReload.SetCustomCurve(AudioSourceCurveType.CustomRolloff, reloadSoundThirdPersonRolloff);
                                //Play
                                pb.thirdPersonPlayerModel.soundReload.Play();
                            }
                        }
                        else if (stage == 1)
                        {
                            if (pb.isFirstPersonActive)
                            {
                                if (data.weaponRenderer.anim)
                                {
                                    //Play animation
                                    data.weaponRenderer.anim.Play("Reload Procedural Start Empty", data.weaponRenderer.animActionLayer, 0f);

                                    for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                    {
                                        data.weaponRenderer.animAdditionals[i].Play("Reload Procedural Start Empty", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                    }
                                }
                                else if (data.weaponRenderer.legacyAnim)
                                {
                                    //Play animation
                                    data.weaponRenderer.legacyAnim.CrossFade(data.weaponRenderer.legacyAnimData.reloadProceduralStartEmpty, 0.15f, PlayMode.StopAll);
                                }
                                //Play sound
                                data.soundReload.PlayOneShot(reloadProceduralStartEmptySound);
                            }
                            else
                            {
                                //Set clip
                                pb.thirdPersonPlayerModel.soundReload.clip = reloadProceduralStartEmptySound;
                                //Set distance
                                pb.thirdPersonPlayerModel.soundReload.maxDistance = reloadSoundThirdPersonMaxRange;
                                //Set rolloff
                                pb.thirdPersonPlayerModel.soundReload.SetCustomCurve(AudioSourceCurveType.CustomRolloff, reloadSoundThirdPersonRolloff);
                                //Play
                                pb.thirdPersonPlayerModel.soundReload.Play();
                            }
                        }
                        else if (stage == 2)
                        {
                            if (pb.isFirstPersonActive)
                            {
                                //Play animation
                                if (data.weaponRenderer.anim)
                                {
                                    //Play animation
                                    data.weaponRenderer.anim.Play("Reload Procedural Insert", data.weaponRenderer.animActionLayer, 0f);

                                    for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                    {
                                        data.weaponRenderer.animAdditionals[i].Play("Reload Procedural Insert", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                    }
                                }
                                else if (data.weaponRenderer.legacyAnim)
                                {
                                    //Play animation
                                    data.weaponRenderer.legacyAnim.Rewind(data.weaponRenderer.legacyAnimData.reloadProceduralInsert);
                                    data.weaponRenderer.legacyAnim.Play(data.weaponRenderer.legacyAnimData.reloadProceduralInsert, PlayMode.StopAll);
                                }
                                //Play sound
                                data.soundReload.PlayOneShot(reloadProceduralInsertSound);
                            }
                            else
                            {
                                //Set clip
                                pb.thirdPersonPlayerModel.soundReload.clip = reloadProceduralInsertSound;
                                //Set distance
                                pb.thirdPersonPlayerModel.soundReload.maxDistance = reloadSoundThirdPersonMaxRange;
                                //Set rolloff
                                pb.thirdPersonPlayerModel.soundReload.SetCustomCurve(AudioSourceCurveType.CustomRolloff, reloadSoundThirdPersonRolloff);
                                //Play
                                pb.thirdPersonPlayerModel.soundReload.Play();
                            }
                        }
                        else if (stage == 4)
                        {
                            if (pb.isFirstPersonActive)
                            {
                                //Play animation
                                if (data.weaponRenderer.anim)
                                {
                                    //Play animation
                                    data.weaponRenderer.anim.Play("Reload Procedural End", data.weaponRenderer.animActionLayer, 0f);

                                    for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                    {
                                        data.weaponRenderer.animAdditionals[i].Play("Reload Procedural End", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                    }
                                }
                                else if (data.weaponRenderer.legacyAnim)
                                {
                                    //Play animation
                                    data.weaponRenderer.legacyAnim.Play(data.weaponRenderer.legacyAnimData.reloadProceduralEnd, PlayMode.StopAll);
                                }
                                //Play sound
                                data.soundReload.PlayOneShot(reloadProceduralEndSound);
                            }
                            else
                            {
                                //Set clip
                                pb.thirdPersonPlayerModel.soundReload.clip = reloadProceduralEndSound;
                                //Set distance
                                pb.thirdPersonPlayerModel.soundReload.maxDistance = reloadSoundThirdPersonMaxRange;
                                //Set rolloff
                                pb.thirdPersonPlayerModel.soundReload.SetCustomCurve(AudioSourceCurveType.CustomRolloff, reloadSoundThirdPersonRolloff);
                                //Play
                                pb.thirdPersonPlayerModel.soundReload.Play();
                            }
                        }
                    }
                }
            }

            public override WeaponIKValues GetIK(Kit_PlayerBehaviour pb, Animator anim, Kit_WeaponRuntimeDataBase runtimeData)
            {
                WeaponIKValues toReturn = new WeaponIKValues();
                if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                {
                    Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;

                    if (data.tpWeaponRenderer.leftHandIK.Length > 0)
                    {
                        toReturn.leftHandIK = data.tpWeaponRenderer.leftHandIK[Mathf.Clamp(pb.thirdPersonPlayerModel.inverseKinematicID, 0, data.tpWeaponRenderer.leftHandIK.Length - 1)];

                        //Check if third person reload animation is being played
                        if (anim.GetCurrentAnimatorStateInfo(1).IsName(thirdPersonAnimType + " Reload") || anim.GetCurrentAnimatorStateInfo(1).IsName(thirdPersonAnimType + " Reload Empty"))
                        {
                            toReturn.canUseIK = false;
                        }
                        else
                        {
                            toReturn.canUseIK = true;
                        }
                    }
                    else
                    {
                        //Can't use ik if none is assigned
                        toReturn.canUseIK = false;
                    }
                }
                return toReturn;
            }

            public override WeaponStats GetStats()
            {
                WeaponStats toReturn = new WeaponStats();
                //Set damage
                toReturn.damage = baseDamage;
                //Set Fire Rate
                toReturn.fireRate = RPM;
                //Set reach
                toReturn.reach = range;
                //Set recoil
                toReturn.recoil = ((Mathf.Abs(recoilPerShotMax.x) + Mathf.Abs(recoilPerShotMax.y) + Mathf.Abs(recoilPerShotMin.x) + Mathf.Abs(recoilPerShotMax.y)) / (float)recoilReturnSpeed);
                return toReturn;
            }

            public override float Sensitivity(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData)
            {
                if (pb.isBot) return 1f;

                if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                {
                    Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;

                    if (data.isAimedIn)
                    {
                        if (data.weaponRenderer.cachedUseFullscreenScope)
                        {
                            return Kit_GameSettings.fullScreenAimSensitivity;
                        }
                        else
                        {
                            return Kit_GameSettings.aimSensitivity;
                        }
                    }
                    else
                    {
                        return Kit_GameSettings.hipSensitivity;
                    }
                }
                return 1f;

            }

            public override int WeaponState(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData)
            {
                if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                {
                    Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;

                    if (data.bulletsLeft > 0) return 0;
                    else if (data.bulletsLeftToReload > 0) return 1;
                    else return 2;
                }
                return 0;
            }

            public override int GetWeaponType(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData)
            {
                if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                {
                    Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;

                    if (data.fireMode == FireMode.Auto)
                    {
                        return 0;
                    }
                    else if (data.fireMode == FireMode.Semi)
                    {
                        if (data.fireTypeMode == FireTypeMode.Simple) return 1;
                        else return 2;
                    }
                    else if (data.fireMode == FireMode.BoltAction)
                    {
                        if (data.fireTypeMode == FireTypeMode.Simple) return 1;
                        else return 2;
                    }
                }
                return 1;
            }

            public override void FirstThirdPersonChanged(Kit_PlayerBehaviour pb, Kit_GameInformation.Perspective perspective, Kit_WeaponRuntimeDataBase runtimeData)
            {
                if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                {
                    //Get runtime data
                    Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;

                    //Activate or deactivate based on bool
                    if (perspective == Kit_GameInformation.Perspective.ThirdPerson)
                    {
                        if (data.weaponRenderer)
                        {
                            data.weaponRenderer.visible = false;
                        }
                        if (data.tpWeaponRenderer)
                        {
                            data.tpWeaponRenderer.visible = true;
                            data.tpWeaponRenderer.shadowsOnly = false;
                        }
                    }
                    else
                    {
                        if (data.weaponRenderer && !data.sniperWeaponHidden)
                        {
                            data.weaponRenderer.visible = true;
                        }
                        if (data.tpWeaponRenderer)
                        {
                            data.tpWeaponRenderer.visible = true;
                            data.tpWeaponRenderer.shadowsOnly = true;
                        }
                    }
                }
            }
            #endregion

            #region Unique functions
            /// <summary>
            /// Fires one shot locally
            /// </summary>
            /// <param name="pb"></param>
            /// <param name="data"></param>
            public void FireOneShot(Kit_PlayerBehaviour pb, Kit_ModernWeaponScriptRuntimeData data, float delta, float revertBy, bool rpc)
            {
                //Update spawn protection
                if (pb.spawnProtection)
                {
                    pb.spawnProtection.GunFired(pb);
                }

                if (pb.isServer && !rpc)
                {
                    //Call network (if semi fire)
                    if (data.fireMode == FireMode.Semi)
                    {
                        if (pb.isServer) pb.RpcWeaponSemiFireNetwork();
                    }
                    else if (data.fireMode == FireMode.BoltAction)
                    {
                        if (pb.isServer) pb.RpcWeaponBoltActionFireNetwork((data.bulletsLeft == 1 ? 2 : 1));//2 = Last, 1 = Normal; 0 would be none
                    }
                }

                //Set bolt action data
                if (data.fireMode == FireMode.BoltAction)
                {
                    if (data.bulletsLeft == 1)
                    {
                        //Set delay
                        data.boltActionTime = Time.time + boltActionDelayLast;
                        //Set state
                        data.boltActionState = 2;
                        //Set fire rate
                        data.lastFire = Time.time + boltActionTimeLast;
                    }
                    else
                    {
                        //Set delay
                        data.boltActionTime = Time.time + boltActionDelayNormal;
                        //Set state
                        data.boltActionState = 1;
                        //Set fire rate
                        data.lastFire = Time.time + boltActionTimeNormal;
                    }
                }
                else
                {
                    //Set firerate
                    data.lastFire = Time.time;
                }

                if (pb.isFirstPersonActive && pb.looking.GetPerspective(pb) == Kit_GameInformation.Perspective.FirstPerson)
                {
                    //Play sound
                    data.soundFire.PlayOneShot(data.weaponRenderer.cachedFireSound);
                    //Play fire animation
                    if (data.bulletsLeft == 1)
                    {
                        //Last fire
                        if (data.weaponRenderer.anim)
                        {
                            //Play animation
                            data.weaponRenderer.anim.Play("Fire Last", data.weaponRenderer.animActionLayer, 0f);

                            for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                            {
                                data.weaponRenderer.animAdditionals[i].Play("Fire Last", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                            }
                        }
                        else if (data.weaponRenderer.legacyAnim)
                        {
                            //Play animation
                            data.weaponRenderer.legacyAnim.Rewind(data.weaponRenderer.legacyAnimData.fireLast);
                            data.weaponRenderer.legacyAnim.Play(data.weaponRenderer.legacyAnimData.fireLast, PlayMode.StopAll);
                        }
                    }
                    else
                    {
                        if (data.isAiming)
                        {
                            //Normal fire (in aiming mode)
                            if (data.weaponRenderer.anim)
                            {
                                //Play animation
                                data.weaponRenderer.anim.Play("Fire Aim", data.weaponRenderer.animActionLayer, 0f);

                                for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                {
                                    data.weaponRenderer.animAdditionals[i].Play("Fire Aim", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                }
                            }
                            else if (data.weaponRenderer.legacyAnim)
                            {
                                //Play animation
                                data.weaponRenderer.legacyAnim.Rewind(data.weaponRenderer.legacyAnimData.fireAim);
                                data.weaponRenderer.legacyAnim.Play(data.weaponRenderer.legacyAnimData.fireAim, PlayMode.StopAll);
                            }
                        }
                        else
                        {
                            //Normal fire
                            if (data.weaponRenderer.anim)
                            {
                                //Play animation
                                data.weaponRenderer.anim.Play("Fire", data.weaponRenderer.animActionLayer, 0f);

                                for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                                {
                                    data.weaponRenderer.animAdditionals[i].Play("Fire", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                                }
                            }
                            else if (data.weaponRenderer.legacyAnim)
                            {
                                //Play animation
                                data.weaponRenderer.legacyAnim.Rewind(data.weaponRenderer.legacyAnimData.fire);
                                data.weaponRenderer.legacyAnim.Play(data.weaponRenderer.legacyAnimData.fire, PlayMode.StopAll);
                            }
                        }
                    }

                    //Play Muzzle Flash Particle System, if assigned
                    if (data.weaponRenderer.muzzleFlash && data.weaponRenderer.cachedMuzzleFlashEnabled)
                    {
                        data.weaponRenderer.muzzleFlash.Play(true);
                    }
                }
                else
                {
                    //Set clip
                    pb.thirdPersonPlayerModel.soundFire.clip = data.tpWeaponRenderer.cachedFireSoundThirdPerson;
                    //Update range
                    pb.thirdPersonPlayerModel.soundFire.maxDistance = data.tpWeaponRenderer.cachedFireSoundThirdPersonMaxRange;
                    //Update sound rolloff
                    pb.thirdPersonPlayerModel.soundFire.SetCustomCurve(AudioSourceCurveType.CustomRolloff, data.tpWeaponRenderer.cachedFireSoundThirdPersonRolloff);
                    //Play
                    pb.thirdPersonPlayerModel.soundFire.PlayOneShot(data.tpWeaponRenderer.cachedFireSoundThirdPerson);

                    //Play Muzzle Flash Particle System, if assigned
                    if (data.tpWeaponRenderer.muzzleFlash && data.tpWeaponRenderer.cachedMuzzleFlashEnabled)
                    {
                        data.tpWeaponRenderer.muzzleFlash.Play(true);
                    }
                }

                //Play third person fire animation
                pb.thirdPersonPlayerModel.PlayWeaponFireAnimation(thirdPersonAnimType);

                //Set shell ejection
                if (shellEjectionPrefab && pb.isFirstPersonActive)
                {
                    data.shellEjectEnabled = true;
                    data.shellEjectNext = Time.time + shellEjectionTime;
                    //The actual ejection is in the CustomUpdate part, so it is coroutine less
                }

                //Subtract bullets
                if (!Kit_IngameMain.instance.gameInformation.debugEnableUnlimitedBullets)
                    data.bulletsLeft--;

                //Simple fire
                if (data.fireTypeMode == FireTypeMode.Simple)
                {
                    if (data.bulletsMode == BulletMode.Raycast)
                    {
                        //Fire Raycast
                        FireRaycast(pb, data, delta, revertBy);
                    }
                    else if (data.bulletsMode == BulletMode.Physical)
                    {
                        //Fire Physical Bullet
                        FirePhysicalBullet(pb, data, rpc);
                    }
                }
                //Pellet fire
                else if (data.fireTypeMode == FireTypeMode.Pellets)
                {
                    //Count how many have been shot
                    int pelletsShot = 0;
                    while (pelletsShot < data.amountOfPellets)
                    {
                        //Increase amount of shot ones
                        pelletsShot++;
                        if (data.bulletsMode == BulletMode.Raycast)
                        {
                            //Fire Raycast
                            FireRaycast(pb, data, delta, revertBy);
                        }
                        else if (data.bulletsMode == BulletMode.Physical)
                        {
                            //Fire Physical Bullet
                            FirePhysicalBullet(pb, data, rpc);
                        }
                    }
                }

                //Increase spray pattern
                if (data.bulletSpreadMode == SpreadMode.SprayPattern)
                {
                    data.sprayPatternState++;
                }

                //Apply recoil using coroutine helper
                Kit_ScriptableObjectCoroutineHelper.instance.StartCoroutine(Kit_ScriptableObjectCoroutineHelper.instance.WeaponApplyRecoil(this, data, pb, RandomExtensions.RandomBetweenVector2(data.recoilPerShotMin, data.recoilPerShotMax), data.recoilApplyTime));
            }

            /// <summary>
            /// Fire one burst (local)
            /// </summary>
            /// <param name="pb"></param>
            /// <param name="data"></param>
            void FireBurst(Kit_PlayerBehaviour pb, Kit_ModernWeaponScriptRuntimeData data, float delta, float revertBy, bool rpc)
            {
                //Update spawn protection
                if (pb.spawnProtection)
                {
                    pb.spawnProtection.GunFired(pb);
                }

                if (pb.isServer && !rpc)
                {
                    //Call network and already tell how many shots are going to be fired
                    if (pb.isServer) pb.RpcWeaponBurstFireNetwork(Mathf.Clamp(data.bulletsLeft, 0, data.burstBulletsPerShot));
                }

                //Start Coroutine
                Kit_ScriptableObjectCoroutineHelper.instance.StartCoroutine(Kit_ScriptableObjectCoroutineHelper.instance.WeaponBurstFire(this, data, pb, delta, revertBy, rpc));
            }

            public void FireRaycast(Kit_PlayerBehaviour pb, Kit_ModernWeaponScriptRuntimeData data, float delta, float revertBy)
            {
                if (pb.isLocalPlayer || pb.isServer)
                {
                    if (data.bulletsPenetrationEnabled)
                    {
                        //Will be set to true again if bullet penetrated through something
                        bool continueLoop = true;

                        //Bullet penetration ability
                        int bulletLifeLeft = data.bulletsPenetrationForce;

                        //So that we may not damage the same player twice
                        List<Kit_PlayerBehaviour> damagedPlayers = new List<Kit_PlayerBehaviour>();


                        RaycastHit hit;
                        Vector3 dir = pb.playerCameraTransform.forward + GetSpread(pb, data);
                        Vector3 pos = pb.playerCameraTransform.position;

                        if (Vector3.Distance(pb.playerCameraTransform.position, pb.input.clientCamPos) < 1)
                        {
                            dir = pb.input.clientCamForward + GetSpread(pb, data);
                            pos = pb.input.clientCamPos;
                        }

                        /*
                        //Override if third person is active
                        if (pb.isFirstPersonActive && Kit_IngameMain.instance.gameInformation.thirdPersonCameraShooting && pb.looking.GetPerspective(pb) == Kit_GameInformation.Perspective.ThirdPerson)
                        {
                            dir = Kit_IngameMain.instance.mainCamera.transform.forward + GetSpread(pb, data);
                            pos = Kit_IngameMain.instance.mainCamera.transform.position;
                        }
                        */

                        RaycastHit[] hits = Physics.RaycastAll(pos, dir, data.range, pb.gameInformation.weaponHitLayers.value).OrderBy(h => h.distance).ToArray();
                        for (int i = 0; i < hits.Length && continueLoop; i++)
                        {
                            hit = hits[i];
                            //Check if we hit ourselves
                            if (hit.collider.gameObject.transform.root != pb.transform.root)
                            {
                                //Set Loop to false
                                continueLoop = false;
                                #region Damage
                                //Check if we hit a player
                                if (hit.collider.GetComponent<Kit_PlayerDamageMultiplier>() && Kit_IngameMain.instance.currentGameModeType == 2)
                                {
                                    if (pb.isLocalPlayer || pb.isServer && pb.isBot)
                                    {
                                        Kit_PlayerDamageMultiplier pdm = hit.collider.GetComponent<Kit_PlayerDamageMultiplier>();
                                        if (hit.collider.transform.root.GetComponent<Kit_PlayerBehaviour>())
                                        {
                                            Kit_PlayerBehaviour hitPb = hit.transform.root.GetComponent<Kit_PlayerBehaviour>();
                                            //Check if we damaged this player already
                                            if (!damagedPlayers.Contains(hitPb))
                                            {
                                                //Add player
                                                damagedPlayers.Add(hitPb);
                                                if (pb.isBot)
                                                {
                                                    hitPb.ServerDamage(GetDamage(data, Vector3.Distance(pb.playerCameraTransform.position, hit.point)) * pdm.damageMultiplier, gameGunID, pb.transform.position, dir, ragdollForce, hit.point, pdm.ragdollId, pb.isBot, pb.id);
                                                }
                                                else
                                                {
                                                    //Tell server
                                                    data.FiredWeapon(hitPb, pdm.ragdollId, pos, hit.point);
                                                }
                                            }
                                        }
                                    }

                                    if (pb.isServer)
                                    {
                                        //Tell other players we hit something
                                        pb.ClientImpactProcess(hit.point, hit.normal, hit.collider.tag);
                                    }
                                }
                                #endregion
                                #region Particles and Interface
                                else
                                {
                                    if (pb.isServer)
                                    {
                                        //Tell other players we hit something
                                        pb.ClientImpactProcess(hit.point, hit.normal, hit.collider.tag);
                                    }

                                    if (hit.collider.GetComponentInParent<IKitDamageable>() != null)
                                    {
                                        if (hit.collider.GetComponentInParent<IKitDamageable>().LocalDamage(GetDamage(data, Vector3.Distance(pb.playerCameraTransform.position, hit.point)), gameGunID, pb.transform.position, dir, data.ragdollForce, hit.point, pb.isBot, pb.id))
                                        {
                                            if (pb.isServer)
                                            {
                                                //Since we hit a player, show the hitmarker
                                                if (!pb.isBot) pb.TargetHitMarker(0);
                                            }
                                        }
                                    }
                                }
                                #endregion
                                #region Bullet Penetration
                                //Check if this object can be penetrated
                                if (hit.collider.GetComponent<Kit_PenetrateableObject>())
                                {
                                    Kit_PenetrateableObject penetration = hit.collider.GetComponent<Kit_PenetrateableObject>();
                                    if (bulletLifeLeft >= penetration.cost)
                                    {
                                        //We penetrated, subtract cost
                                        bulletLifeLeft -= penetration.cost;
                                        //Set bool
                                        continueLoop = true;
                                    }
                                }

                                //Abort loop if nothing was penetrated
                                if (!continueLoop) break;
                                #endregion
                            }
                        }

                    }
                    else
                    {
                        RaycastHit hit;
                        Vector3 dir = pb.playerCameraTransform.forward + GetSpread(pb, data);
                        Vector3 pos = pb.playerCameraTransform.position;

                        if (Vector3.Distance(pb.playerCameraTransform.position, pb.input.clientCamPos) < 1)
                        {
                            dir = pb.input.clientCamForward + GetSpread(pb, data);
                            pos = pb.input.clientCamPos;
                        }

                        /*
                        //Override if third person is active
                        if (pb.isFirstPersonActive && Kit_IngameMain.instance.gameInformation.thirdPersonCameraShooting && pb.looking.GetPerspective(pb) == Kit_GameInformation.Perspective.ThirdPerson)
                        {
                            dir = Kit_IngameMain.instance.mainCamera.transform.forward + GetSpread(pb, data);
                            pos = Kit_IngameMain.instance.mainCamera.transform.position;
                        }
                        */

                        RaycastHit[] hits = Physics.RaycastAll(pos, dir, data.range, pb.gameInformation.weaponHitLayers.value).OrderBy(h => h.distance).ToArray();
                        for (int i = 0; i < hits.Length; i++)
                        {
                            hit = hits[i];
                            Debug.Log(hit.collider.gameObject.name, hit.collider);
                            //Check if we hit ourselves
                            if (hit.collider.gameObject.transform.root != pb.transform.root)
                            {
                                //Check if we hit a player
                                if (hit.transform.GetComponent<Kit_PlayerDamageMultiplier>())
                                {
                                    if (pb.isLocalPlayer || pb.isServer && pb.isBot)
                                    {
                                        Kit_PlayerDamageMultiplier pdm = hit.transform.GetComponent<Kit_PlayerDamageMultiplier>();
                                        if (hit.transform.root.GetComponent<Kit_PlayerBehaviour>())
                                        {
                                            Kit_PlayerBehaviour hitPb = hit.transform.root.GetComponent<Kit_PlayerBehaviour>();
                                            if (pb.isBot)
                                            {
                                                hitPb.ServerDamage(GetDamage(data, Vector3.Distance(pb.playerCameraTransform.position, hit.point)) * pdm.damageMultiplier, gameGunID, pb.transform.position, dir, ragdollForce, hit.point, pdm.ragdollId, pb.isBot, pb.id);
                                            }
                                            else
                                            {
                                                //Tell server
                                                data.FiredWeapon(hitPb, pdm.ragdollId, pos, hit.point);
                                            }
                                            break;
                                        }
                                    }

                                    if (pb.isServer)
                                    {
                                        //Tell other players we hit something
                                        pb.ClientImpactProcess(hit.point, hit.normal, hit.collider.tag);
                                    }
                                }
                                else
                                {
                                    if (pb.isServer)
                                    {
                                        //Tell other players we hit something
                                        pb.ClientImpactProcess(hit.point, hit.normal, hit.collider.tag);
                                    }

                                    if (hits[i].collider.GetComponentInParent<IKitDamageable>() != null)
                                    {
                                        if (hits[i].collider.GetComponentInParent<IKitDamageable>().LocalDamage(GetDamage(data, Vector3.Distance(pb.playerCameraTransform.position, hit.point)), gameGunID, pb.transform.position, dir, data.ragdollForce, hit.point, pb.isBot, pb.id))
                                        {

                                            if (pb.isServer)
                                            {
                                                //Since we hit a player, show the hitmarker
                                                if (!pb.isBot) pb.TargetHitMarker(0);
                                            }
                                        }
                                    }
                                    break;
                                }
                            }
                        }
                    }

                    //Because these are calculated on the master client, we need to call shoot here too
                    if (Kit_IngameMain.instance.minimap)
                    {
                        Kit_IngameMain.instance.minimap.PlayerShoots(pb, data.tpWeaponRenderer.isWeaponSilenced);
                    }
                }
            }

            public override void NetworkPhysicalBulletFired(Kit_PlayerBehaviour pb, Vector3 pos, Vector3 dir, Kit_WeaponRuntimeDataBase runtimeData)
            {
                if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                {
                    //Get runtime data
                    Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;

                    //Instantiate Game Object
                    GameObject bullet = Kit_IngameMain.instance.objectPooling.GetInstantiateable(data.bulletPrefab, pos, Quaternion.LookRotation(dir));
                    //Call setup
                    bullet.GetComponent<Kit_BulletBase>().Setup(this, data, pb, dir);
                }
            }

            public void FirePhysicalBullet(Kit_PlayerBehaviour pb, Kit_ModernWeaponScriptRuntimeData data, bool rpc)
            {
                if (/*Kit_IngameMain.instance.gameInformation.fireShotsLocally ||*/ pb.isServer)
                {
                    Vector3 dir = pb.playerCameraTransform.forward + GetSpread(pb, data);
                    Vector3 pos = pb.playerCameraTransform.position;

                    if (Vector3.Distance(pb.playerCameraTransform.position, pb.input.clientCamPos) < 1)
                    {
                        dir = pb.input.clientCamForward + GetSpread(pb, data);
                        pos = pb.input.clientCamPos;
                    }

                    /*
                    //Override if third person is active
                    if (pb.isFirstPersonActive && Kit_IngameMain.instance.gameInformation.thirdPersonCameraShooting && pb.looking.GetPerspective(pb) == Kit_GameInformation.Perspective.ThirdPerson)
                    {
                        dir = Kit_IngameMain.instance.mainCamera.transform.forward + GetSpread(pb, data);
                        pos = Kit_IngameMain.instance.mainCamera.transform.position;
                    }
                    */

                    if (pb.isServer && !rpc)
                    {
                        //Send RPC
                        if (pb.isServer) pb.RpcWeaponFirePhysicalBulletOthers(pos, dir);
                    }

                    //Instantiate Game Object
                    GameObject bullet = Kit_IngameMain.instance.objectPooling.GetInstantiateable(data.bulletPrefab, pos, Quaternion.LookRotation(dir));

                    //Call setup
                    bullet.GetComponent<Kit_BulletBase>().Setup(this, data, pb, dir);

                    //Because these are calculated on the master client, we need to call shoot here too
                    if (Kit_IngameMain.instance.minimap)
                    {
                        Kit_IngameMain.instance.minimap.PlayerShoots(pb, data.tpWeaponRenderer.isWeaponSilenced);
                    }
                }
            }

            /// <summary>
            /// Returns the damage for given distance
            /// </summary>
            /// <param name="distance"></param>
            /// <returns></returns>
            public float GetDamage(Kit_ModernWeaponScriptRuntimeData data, float distance)
            {
                return data.baseDamage * data.damageDropoff.Evaluate(distance);
            }

            /// <summary>
            /// Returns a direction (for offset) based on data and this behaviour's stats
            /// </summary>
            /// <param name="pb"></param>
            /// <param name="data"></param>
            Vector3 GetSpread(Kit_PlayerBehaviour pb, Kit_ModernWeaponScriptRuntimeData data)
            {
                float velocity = pb.movement.GetVelocity(pb).magnitude;

                #region Hip Spread
                Vector3 spreadHip = Vector3.zero;
                spreadHip.x = Random.Range(-data.bulletSpreadHipBase, data.bulletSpreadHipBase);
                spreadHip.y = Random.Range(-data.bulletSpreadHipBase, data.bulletSpreadHipBase);
                spreadHip.z = Random.Range(-data.bulletSpreadHipBase, data.bulletSpreadHipBase);

                //Velocity add
                if (velocity > 0)
                {
                    spreadHip.x += RandomExtensions.RandomPosNeg() * data.bulletSpreadHipVelocityAdd * (velocity / data.bulletSpreadHipVelocityReference);
                    spreadHip.y += RandomExtensions.RandomPosNeg() * data.bulletSpreadHipVelocityAdd * (velocity / data.bulletSpreadHipVelocityReference);
                    spreadHip.z += RandomExtensions.RandomPosNeg() * data.bulletSpreadHipVelocityAdd * (velocity / data.bulletSpreadHipVelocityReference);
                }
                #endregion

                #region Aim Spread
                Vector3 spreadAim = Vector3.zero;
                spreadAim.x = Random.Range(-data.bulletSpreadAimBase, data.bulletSpreadAimBase);
                spreadAim.y = Random.Range(-data.bulletSpreadAimBase, data.bulletSpreadAimBase);
                spreadAim.z = Random.Range(-data.bulletSpreadAimBase, data.bulletSpreadAimBase);

                //Velocity add
                if (velocity > 0)
                {
                    spreadAim.x += RandomExtensions.RandomPosNeg() * data.bulletSpreadAimVelocityAdd * (velocity / data.bulletSpreadAimVelocityReference);
                    spreadAim.y += RandomExtensions.RandomPosNeg() * data.bulletSpreadAimVelocityAdd * (velocity / data.bulletSpreadAimVelocityReference);
                    spreadAim.z += RandomExtensions.RandomPosNeg() * data.bulletSpreadAimVelocityAdd * (velocity / data.bulletSpreadAimVelocityReference);
                }
                #endregion

                if (data.bulletSpreadMode == SpreadMode.Simple)
                {
                    //Interpolate between both based on aiming progress
                    return Vector3.Lerp(spreadHip, spreadAim, data.aimingProgress);
                }
                else if (data.bulletSpreadMode == SpreadMode.SprayPattern && data.bulletSpreadSprayPattern.Length > 0)
                {
                    //Interpolate between both based on aiming progress and add spray pattern
                    return Vector3.Lerp(spreadHip, spreadAim, data.aimingProgress) + data.bulletSpreadSprayPattern[Mathf.Clamp(Mathf.RoundToInt(data.sprayPatternState), 0, data.bulletSpreadSprayPattern.Length - 1)];
                }
                else
                {
                    //Interpolate between both based on aiming progress
                    return Vector3.Lerp(spreadHip, spreadAim, data.aimingProgress);
                }
            }

            float GetCrosshairSize(Kit_PlayerBehaviour pb, Kit_ModernWeaponScriptRuntimeData data)
            {
                if (crosshairEnabled)
                {
                    //This is essentially the bullet spread part without the random factors.
                    float velocity = pb.movement.GetVelocity(pb).magnitude;
                    float spreadHip = data.bulletSpreadHipBase;

                    //Velocity add
                    if (velocity > 0)
                    {
                        spreadHip += data.bulletSpreadHipVelocityAdd * (velocity / data.bulletSpreadHipVelocityReference);
                    }

                    return Mathf.Lerp(spreadHip, 0f, data.aimingProgress) * crosshairSizeMultiplier;
                }
                //If crosshair is not enablewd
                else
                {
                    //Return size of 0 which will disable the crosshair
                    return 0f;
                }
            }

            void DryFire(Kit_PlayerBehaviour pb, Kit_ModernWeaponScriptRuntimeData data)
            {
                if (pb.isFirstPersonActive)
                {
                    //Play sound (on Other channel so fire sound can still play)
                    data.soundOther.PlayOneShot(dryFireSound);
                    //Play Dry Fire animation
                    if (data.weaponRenderer.anim)
                    {
                        //Play animation
                        data.weaponRenderer.anim.Play("Dry Fire", data.weaponRenderer.animActionLayer, 0f);

                        for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                        {
                            data.weaponRenderer.animAdditionals[i].Play("Dry Fire", data.weaponRenderer.animAdditionalsActionLayer[i], 0f);
                        }
                    }
                    else if (data.weaponRenderer.legacyAnim && data.weaponRenderer.legacyAnimData.dryFire != "")
                    {
                        //Play animation
                        data.weaponRenderer.legacyAnim.Rewind(data.weaponRenderer.legacyAnimData.dryFire);
                        data.weaponRenderer.legacyAnim.Play(data.weaponRenderer.legacyAnimData.dryFire, PlayMode.StopAll);
                    }
                }
                //Set firerate
                data.lastFire = Time.time + 1f; //+1 so you don't dry fire too quick
            }

            /// <summary>
            /// Ejects a single shell
            /// </summary>
            /// <param name="pb"></param>
            /// <param name="data"></param>
            void EjectShell(Kit_PlayerBehaviour pb, Kit_ModernWeaponScriptRuntimeData data)
            {
                if (shellEjectionPrefab & data.weaponRenderer.shellEjectTransform)
                {
                    GameObject shellObj = null;
                    if (pb.looking.GetPerspective(pb) == Kit_GameInformation.Perspective.FirstPerson)
                    {
                        shellObj = Kit_IngameMain.instance.objectPooling.GetInstantiateable(shellEjectionPrefab, data.weaponRenderer.shellEjectTransform.position, data.weaponRenderer.shellEjectTransform.rotation);
                    }
                    else
                    {
                        shellObj = Kit_IngameMain.instance.objectPooling.GetInstantiateable(shellEjectionPrefab, data.tpWeaponRenderer.shellEjectTransform.position, data.weaponRenderer.shellEjectTransform.rotation);
                    }
                    if (!shellObj) return;
                    //Apply force
                    Rigidbody rb = shellObj.GetComponent<Rigidbody>();
                    rb.isKinematic = false;
                    rb.velocity = pb.movement.GetVelocity(pb);
                    //Add force
                    rb.AddRelativeForce(RandomExtensions.RandomBetweenVector3(shellEjectionMinForce, shellEjectionMaxForce));
                    //Add torque
                    rb.AddRelativeTorque(RandomExtensions.RandomBetweenVector3(shellEjectionMinTorque, shellEjectionMaxTorque));
                }
            }

            public override bool IsWeaponAiming(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData)
            {
                if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                {
                    Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;

                    return data.isAiming; //Just relay
                }
                return false;
            }

            public override float GetAimingPercentage(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData)
            {
                if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                {
                    Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;

                    return data.aimingProgress;
                }
                return base.GetAimingPercentage(pb, runtimeData);
            }

            public override bool ForceIntoFirstPerson(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData)
            {
                if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                {
                    Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;

                    if (data.weaponRenderer)
                        return data.isAiming && data.weaponRenderer.cachedUseFullscreenScope; //Just relay
                }
                return false;
            }

            public override float AimInTime(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData)
            {
                return aimInTime;
            }

            public override float SpeedMultiplier(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData)
            {
                if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                {
                    Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;

                    //Lerp from base multiplier to base multiplier multiplied with the aim speed multiplier
                    return Mathf.Lerp(data.speedMultiplierBase, data.speedMultiplierBase * aimSpeedMultiplier, data.aimingProgress);
                }
                return 1f;
            }

            public override void OnAmmoPickup(Kit_PlayerBehaviour pb, Kit_AmmoPickup pickup, Kit_WeaponRuntimeDataBase runtimeData)
            {
                if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                {
                    Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;

                    //Add to bullets
                    data.bulletsLeftToReload += pickup.amountOfClipsToPickup * data.bulletsPerMag;
                }
            }

            public override bool IsWeaponFull(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData)
            {
                if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                {
                    Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;

                    return data.bulletsLeftToReload >= data.bulletsToReloadAtStart;
                }

                return base.IsWeaponFull(pb, runtimeData);
            }

            public override void RestockAmmo(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData)
            {
                if (runtimeData != null && runtimeData.GetType() == typeof(Kit_ModernWeaponScriptRuntimeData))
                {
                    Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;

                    //Reset ammo
                    data.bulletsLeftToReload = data.bulletsToReloadAtStart;
                }
            }
            #endregion

            public override void BeginSpectating(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData, int[] attachments)
            {
                Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;

                //Create First Person renderer if it doesn't exist already
                if (!data.weaponRenderer)
                {
                    //Setup root for this weapon
                    GameObject root = new GameObject("Weapon root");
                    root.transform.parent = pb.weaponsGo; //Set root
                    root.transform.localPosition = Vector3.zero; //Reset position
                    root.transform.localRotation = Quaternion.identity; //Reset rotation
                    root.transform.localScale = Vector3.one; //Reset scale

                    //Setup generic animations
                    GameObject genericAnimations = Instantiate(genericGunAnimatorControllerPrefab);
                    genericAnimations.transform.parent = root.transform;
                    genericAnimations.transform.localPosition = Vector3.zero; //Reset position
                    genericAnimations.transform.localRotation = Quaternion.identity; //Reset rotation
                    genericAnimations.transform.localScale = Vector3.one; //Reset scale

                    //Get animator
                    Animator anim = genericAnimations.GetComponent<Animator>(); ;
                    anim.Play("Idle");
                    data.genericAnimator = anim;

                    //Setup aiming transform
                    GameObject aimTrans = new GameObject("Weapon aiming");
                    aimTrans.transform.parent = genericAnimations.transform; //Set root
                    aimTrans.transform.localPosition = Vector3.zero; //Reset position
                    aimTrans.transform.localRotation = Quaternion.identity; //Reset rotation
                    aimTrans.transform.localScale = Vector3.one; //Reset scale

                    //Assign it
                    data.aimingTransform = aimTrans.transform;

                    //Delay transform
                    GameObject delayTrans = new GameObject("Weapon delay");
                    delayTrans.transform.parent = aimTrans.transform; //Set root
                    delayTrans.transform.localPosition = Vector3.zero; //Reset position
                    delayTrans.transform.localRotation = Quaternion.identity; //Reset rotation
                    delayTrans.transform.localScale = Vector3.one; //Reset scale

                    //Assign it
                    data.weaponDelayTransform = delayTrans.transform;

                    //Delay transform
                    GameObject fallTrans = new GameObject("Weapon fall");
                    fallTrans.transform.parent = delayTrans.transform; //Set root
                    fallTrans.transform.localPosition = Vector3.zero; //Reset position
                    fallTrans.transform.localRotation = Quaternion.identity; //Reset rotation
                    fallTrans.transform.localScale = Vector3.one; //Reset scale

                    //Assign it
                    data.weaponFallTransform = fallTrans.transform;

                    //Get Fire Audio (Needs to be consistent)
                    if (pb.weaponsGo.GetComponent<AudioSource>()) data.soundFire = pb.weaponsGo.GetComponent<AudioSource>();
                    else data.soundFire = pb.weaponsGo.gameObject.AddComponent<AudioSource>();

                    //Setup reload sound
                    GameObject soundReload = new GameObject("SoundReload"); //Create
                    soundReload.transform.parent = root.transform;
                    soundReload.transform.localPosition = Vector3.zero; //Reset position
                    soundReload.transform.localRotation = Quaternion.identity; //Reset rotation
                    soundReload.transform.localScale = Vector3.one; //Reset scale
                                                                    //Add audio source
                    data.soundReload = soundReload.AddComponent<AudioSource>();

                    //Setup other sound
                    GameObject soundOther = new GameObject("SoundOther"); //Create
                    soundOther.transform.parent = root.transform;
                    soundOther.transform.localPosition = Vector3.zero; //Reset position
                    soundOther.transform.localRotation = Quaternion.identity; //Reset rotation
                    soundOther.transform.localScale = Vector3.one; //Reset scale
                                                                   //Add audio source
                    data.soundOther = soundOther.AddComponent<AudioSource>();

                    //Setup the first person prefab
                    GameObject fpRuntime = Instantiate(firstPersonPrefab, fallTrans.transform, false);
                    fpRuntime.transform.localScale = Vector3.one; //Reset scale

                    //Setup renderer
                    data.weaponRenderer = fpRuntime.GetComponent<Kit_WeaponRenderer>();
                    //Set Attachments
                    data.weaponRenderer.SetAttachments(attachments, this, pb, null);

                    //Play Dependent arms
                    if (data.weaponRenderer.playerModelDependentArmsEnabled && pb.thirdPersonPlayerModel.firstPersonArmsPrefab.Contains(data.weaponRenderer.playerModelDependentArmsKey))
                    {
                        //Create Prefab
                        GameObject fpArms = Instantiate(pb.thirdPersonPlayerModel.firstPersonArmsPrefab[data.weaponRenderer.playerModelDependentArmsKey], fallTrans.transform, false);
                        //Get Arms
                        Kit_FirstPersonArms fpa = fpArms.GetComponent<Kit_FirstPersonArms>();

#if INTEGRATION_FPV2
                        //Set shaders
                        FirstPersonView.ShaderMaterialSolution.FPV_SM_Object armsObj = fpArms.GetComponent<FirstPersonView.ShaderMaterialSolution.FPV_SM_Object>();
                        if (armsObj)
                        {
                            //Set as first person object
                            armsObj.SetAsFirstPersonObject();
                        }
                        else
                        {
                            Debug.LogError("FPV2 is enabled but first person prefab does not have FPV_SM_Object assigned!");
                        }
#elif INTEGRATION_FPV3
                        //Set shaders
                        FirstPersonView.FPV_Object armsObj = fpArms.GetComponent<FirstPersonView.FPV_Object>();
                        if (armsObj)
                        {
                            //Set as first person object
                            armsObj.SetAsFirstPersonObject();
                        }
                        else
                        {
                            Debug.LogError("FPV3 is enabled but first person prefab does not have FPV_Object assigned!");
                        }
#endif

                        //Reparent
                        for (int i = 0; i < fpa.reparents.Length; i++)
                        {
                            if (fpa.reparents[i])
                            {
                                fpa.reparents[i].transform.parent = data.weaponRenderer.playerModelDependentArmsRoot;
                            }
                            else
                            {
                                Debug.LogWarning("First Person Arm Renderer at index " + i + " is not assigned", fpa);
                            }
                        }
                        //Merge Array
                        data.weaponRenderer.allWeaponRenderers = data.weaponRenderer.allWeaponRenderers.Concat(fpa.renderers).ToArray();
                        //Rebind so that the animator animates our freshly reparented transforms too!
                        if (data.weaponRenderer.anim)
                        {
                            data.weaponRenderer.anim.Rebind();
                        }

                        for (int i = 0; i < data.weaponRenderer.animAdditionals.Length; i++)
                        {
                            data.weaponRenderer.animAdditionals[i].Rebind();
                        }
                    }

                    //Hide
                    data.weaponRenderer.visible = false;

#if INTEGRATION_FPV2
                    //Set shaders
                    FirstPersonView.ShaderMaterialSolution.FPV_SM_Object obj = fpRuntime.GetComponent<FirstPersonView.ShaderMaterialSolution.FPV_SM_Object>();
                    if (obj)
                    {
                        //Set as first person object
                        obj.SetAsFirstPersonObject();
                    }
                    else
                    {
                        Debug.LogError("FPV2 is enabled but first person prefab does not have FPV_SM_Object assigned!");
                    }
#elif INTEGRATION_FPV3
                    //Set shaders
                    FirstPersonView.FPV_Object obj = fpRuntime.GetComponent<FirstPersonView.FPV_Object>();
                    if (obj)
                    {
                        //Set as first person object
                        obj.SetAsFirstPersonObject();
                    }
                    else
                    {
                        Debug.LogError("FPV3 is enabled but first person prefab does not have FPV_Object assigned!");
                    }
#endif


                    //Add to the list
                    data.instantiatedObjects.Add(root);
                }

                if (pb.looking.GetPerspective(pb) == Kit_GameInformation.Perspective.FirstPerson)
                {
                    //Show if selected
                    data.weaponRenderer.visible = data.isSelected;

                    //Hide tp
                    data.tpWeaponRenderer.shadowsOnly = true;
                }
                else
                {
                    //FP is definitely hidden, TP is already in the state that it should be in
                    data.weaponRenderer.visible = false;
                }
            }

            public override void EndSpectating(Kit_PlayerBehaviour pb, Kit_WeaponRuntimeDataBase runtimeData)
            {
                //Get data
                Kit_ModernWeaponScriptRuntimeData data = runtimeData as Kit_ModernWeaponScriptRuntimeData;

                //Hide weapon renderer if present
                if (data.weaponRenderer)
                {
                    data.weaponRenderer.visible = false;
                }

                data.tpWeaponRenderer.shadowsOnly = false;
            }
        }
    }
}
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;

namespace MarsFPSKit
{
    namespace Weapons
    {
        [CustomEditor(typeof(Kit_ModernWeaponScript))]
        public class Kit_ModernWeaponScriptEditor : UnityEditor.Editor
        {
            static bool prefabsFoldout;
            static bool settingsFoldout;
            static bool attachmentsFoldout;
            static bool animationSettingsFoldout;
            static bool damageFoldout;
            static bool crosshairFoldout;
            static bool bulletFoldout;
            static bool bulletSpreadFoldout;
            static bool recoilFoldout;
            static bool reloadFoldout;
            static bool aimingFoldout;
            static bool weaponDelayFoldout;
            static bool weaponTiltFoldout;
            static bool weaponFallFoldout;
            static bool shellEjectionFoldout;
            static bool walkFoldout;
            static bool genericAnimationsFoldout;
            static bool springFoldout;

            Kit_GameInformation information = null;

            SerializedProperty slotsProperty;
            SerializedProperty weaponNameProperty;
            SerializedProperty weaponCatProperty;
            SerializedProperty weaponSubCatProperty;
            SerializedProperty attachmentsPropery;

            void OnEnable()
            {
                // Fetch the objects from the MyScript script to display in the inspector
                slotsProperty = serializedObject.FindProperty("canFitIntoSlots");
                attachmentsPropery = serializedObject.FindProperty("attachments");
                weaponNameProperty = serializedObject.FindProperty("weaponName");
                weaponNameProperty = serializedObject.FindProperty("weaponName");
                weaponCatProperty = serializedObject.FindProperty("weaponType");
                weaponSubCatProperty = serializedObject.FindProperty("weaponLoadoutSubCategory");
            }

            public override void OnInspectorGUI()
            {
                serializedObject.Update();

                EditorGUI.BeginChangeCheck();
                Kit_ModernWeaponScript script = target as Kit_ModernWeaponScript;

                if (!information)
                {
                    information = Resources.Load<Kit_GameInformation>("Game");
                }

                prefabsFoldout = EditorGUILayout.Foldout(prefabsFoldout, "Prefabs");
                if (prefabsFoldout)
                {
                    EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                    script.firstPersonPrefab = EditorGUILayout.ObjectField("First Person Prefab", script.firstPersonPrefab, typeof(GameObject), false) as GameObject;
                    script.thirdPersonPrefab = EditorGUILayout.ObjectField("Third Person Prefab", script.thirdPersonPrefab, typeof(GameObject), false) as GameObject;
                    script.dropPrefab = EditorGUILayout.ObjectField("Drop Prefab", script.dropPrefab, typeof(GameObject), false) as GameObject;
                    script.runtimeDataPrefab = EditorGUILayout.ObjectField("Runtime Data Prefab", script.runtimeDataPrefab, typeof(GameObject), false) as GameObject;

                    if (script.firstPersonPrefab)
                    {
                        if (!script.firstPersonPrefab.GetComponent<Kit_WeaponRenderer>())
                        {
                            EditorGUILayout.HelpBox("First Person Prefab does not have the weapon renderer assigned!", MessageType.Error);
                        }
                    }
                    if (script.thirdPersonPrefab)
                    {
                        if (!script.thirdPersonPrefab.GetComponent<Kit_ThirdPersonWeaponRenderer>())
                        {
                            EditorGUILayout.HelpBox("Third Person Prefab does not have the third person weapon renderer assigned!", MessageType.Error);
                        }
                    }
                    if (script.dropPrefab)
                    {
                        if (!script.dropPrefab.GetComponent<Kit_DropRenderer>())
                        {
                            EditorGUILayout.HelpBox("Drop Prefab does not have drop renderer assigned!", MessageType.Error);
                        }
                    }
                    if (script.firstPersonPrefab && script.thirdPersonPrefab && script.dropPrefab)
                    {
                        if (script.firstPersonPrefab.GetComponent<Kit_WeaponRenderer>() && script.thirdPersonPrefab.GetComponent<Kit_ThirdPersonWeaponRenderer>() && script.dropPrefab.GetComponent<Kit_DropRenderer>())
                        {
                            Kit_WeaponRenderer wr = script.firstPersonPrefab.GetComponent<Kit_WeaponRenderer>();
                            Kit_ThirdPersonWeaponRenderer wrtp = script.thirdPersonPrefab.GetComponent<Kit_ThirdPersonWeaponRenderer>();
                            Kit_DropRenderer wrd = script.dropPrefab.GetComponent<Kit_DropRenderer>();
                            if (wr.attachmentAndSkinSockets.Length == wrtp.attachmentAndSkinSockets.Length && wrtp.attachmentAndSkinSockets.Length == wrd.attachmentAndSkinSockets.Length) { }
                            else
                            {
                                EditorGUILayout.HelpBox("Attachment Slots on the prefabs do not match.", MessageType.Error);
                            }
                        }
                    }
                    EditorGUILayout.EndVertical();
                }
                settingsFoldout = EditorGUILayout.Foldout(settingsFoldout, "Settings");
                if (settingsFoldout)
                {
                    EditorGUILayout.BeginVertical(EditorStyles.helpBox);

                    EditorGUILayout.PropertyField(weaponNameProperty, true);

                    script.weaponPicture = EditorGUILayout.ObjectField("Weapon Picture", script.weaponPicture, typeof(Sprite), false) as Sprite;
                    script.weaponHudPicture = EditorGUILayout.ObjectField("Weapon HUD Picture", script.weaponHudPicture, typeof(Sprite), false) as Sprite;
                    script.weaponKillfeedImage = EditorGUILayout.ObjectField("Killfeed image", script.weaponKillfeedImage, typeof(Sprite), false) as Sprite;
                    EditorGUI.BeginChangeCheck();
                    EditorGUILayout.PropertyField(slotsProperty, true);
                    if (EditorGUI.EndChangeCheck())
                    {
                        serializedObject.ApplyModifiedProperties();
                        Repaint();
                    }

                    EditorGUI.BeginChangeCheck();
                    EditorGUILayout.PropertyField(weaponCatProperty, true);
                    if (EditorGUI.EndChangeCheck())
                    {
                        serializedObject.ApplyModifiedProperties();
                        Repaint();
                    }

                    EditorGUI.BeginChangeCheck();
                    EditorGUILayout.PropertyField(weaponSubCatProperty, true);
                    if (EditorGUI.EndChangeCheck())
                    {
                        serializedObject.ApplyModifiedProperties();
                        Repaint();
                    }

                    if (information && information.leveling)
                    {
                        script.levelToUnlockAt = EditorGUILayout.IntSlider("Unlocks at level", script.levelToUnlockAt, -1, information.leveling.GetMaxLevel());
                        script.unlockImage = EditorGUILayout.ObjectField("Unlock Picture", script.unlockImage, typeof(Sprite), false) as Sprite;
                    }
                    else
                    {
                        script.levelToUnlockAt = EditorGUILayout.IntField("Level to unlock at", script.levelToUnlockAt);
                        script.unlockImage = EditorGUILayout.ObjectField("Unlock Picture", script.unlockImage, typeof(Sprite), false) as Sprite;
                    }
                    script.drawTime = EditorGUILayout.FloatField("Draw Time", script.drawTime);
                    script.drawSound = EditorGUILayout.ObjectField("Draw Sound", script.drawSound, typeof(AudioClip), false) as AudioClip;
                    script.putawayTime = EditorGUILayout.FloatField("Putaway Time", script.putawayTime);
                    script.putawaySound = EditorGUILayout.ObjectField("Draw Sound", script.putawaySound, typeof(AudioClip), false) as AudioClip;
                    script.deathSoundCategory = EditorGUILayout.IntField("Death Sound Category", script.deathSoundCategory);
                    if (information)
                    {
                        if (information.allAnimatorAnimationSets.Length > 0)
                        {
                            List<string> displayedList = new List<string>();
                            for (int i = 0; i < information.allAnimatorAnimationSets.Length; i++)
                            {
                                displayedList.Add(information.allAnimatorAnimationSets[i].prefix);
                            }
                            int currentIndex = displayedList.IndexOf(script.thirdPersonAnimType);
                            if (currentIndex < 0) currentIndex = 0;
                            string[] toDisplay = displayedList.ToArray();
                            int index = EditorGUILayout.Popup("Third Person Animation Type", currentIndex, toDisplay);
                            script.thirdPersonAnimType = toDisplay[index];
                        }
                        else
                        {
                            EditorGUILayout.HelpBox("Add some animator sets to the game information file!", MessageType.Error);
                        }
                    }
                    else
                    {
                        EditorGUILayout.HelpBox("Game file not found in resources", MessageType.Warning);
                        script.thirdPersonAnimType = EditorGUILayout.TextField("Third Person Animation Type", script.thirdPersonAnimType);
                    }
                    if (script.fireMode != FireMode.BoltAction)
                        script.RPM = EditorGUILayout.IntField("RPM", script.RPM);
                    if (script.fireMode == FireMode.Burst)
                    {
                        script.burstBulletsPerShot = EditorGUILayout.IntField("Shots per burst", script.burstBulletsPerShot);
                        script.burstTimeBetweenShots = EditorGUILayout.FloatField("Time between Burst Shots", script.burstTimeBetweenShots);
                    }
                    script.fireMode = (FireMode)EditorGUILayout.EnumPopup("Fire Mode", script.fireMode);
                    script.fireSound = EditorGUILayout.ObjectField("Fire sound", script.fireSound, typeof(AudioClip), false) as AudioClip;
                    script.fireSoundThirdPerson = EditorGUILayout.ObjectField("Fire sound Third Person", script.fireSoundThirdPerson, typeof(AudioClip), false) as AudioClip;
                    script.dryFireSound = EditorGUILayout.ObjectField("Dry Fire sound", script.dryFireSound, typeof(AudioClip), false) as AudioClip;
                    script.fireSoundThirdPersonMaxRange = EditorGUILayout.FloatField("Fire sound third person max range", script.fireSoundThirdPersonMaxRange);
                    script.fireSoundThirdPersonRolloff = EditorGUILayout.CurveField("Fire sound third person rolloff", script.fireSoundThirdPersonRolloff);
                    if (script.fireMode == FireMode.BoltAction)
                    {
                        script.boltActionTimeNormal = EditorGUILayout.FloatField("Bolt action time", script.boltActionTimeNormal);
                        script.boltActionDelayNormal = EditorGUILayout.FloatField("Bolt action sound delay", script.boltActionDelayNormal);
                        script.boltActionSoundNormal = EditorGUILayout.ObjectField("Bolt action sound", script.boltActionSoundNormal, typeof(AudioClip), false) as AudioClip;
                        script.boltActionTimeLast = EditorGUILayout.FloatField("Bolt action time last", script.boltActionTimeLast);
                        script.boltActionDelayLast = EditorGUILayout.FloatField("Bolt action sound last delay", script.boltActionDelayLast);
                        script.boltActionSoundLast = EditorGUILayout.ObjectField("Bolt action sound last", script.boltActionSoundLast, typeof(AudioClip), false) as AudioClip;
                        script.boltActionSoundThirdPersonMaxRange = EditorGUILayout.FloatField("Bolt action sound third person max range", script.boltActionSoundThirdPersonMaxRange);
                        script.boltActionSoundThirdPersonRolloff = EditorGUILayout.CurveField("Bolt action sound third person rolloff", script.boltActionSoundThirdPersonRolloff);
                    }
                    script.bulletsPerMag = EditorGUILayout.IntField("Bullets Per Mag", script.bulletsPerMag);
                    script.bulletsToReloadAtStart = EditorGUILayout.IntField("Bullets To Reload At Start", script.bulletsToReloadAtStart);
                    script.speedMultiplierBase = EditorGUILayout.FloatField("Speed Multiplier", script.speedMultiplierBase);
                    script.ragdollForce = EditorGUILayout.FloatField("Ragdoll Force", script.ragdollForce);
                    script.timeCannotFireAfterRun = EditorGUILayout.FloatField("Weapon unusable after run in seconds", script.timeCannotFireAfterRun);
                    EditorGUILayout.EndVertical();
                }
                attachmentsFoldout = EditorGUILayout.Foldout(attachmentsFoldout, "Attachments");
                if (attachmentsFoldout)
                {
                    if (!script.attachmentSlotOverride)
                    {
                        EditorGUILayout.PropertyField(attachmentsPropery, true);
                        EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                        EditorGUILayout.HelpBox("You can copy weapon specific attachments over from another weapon by dragging that weapon into this slot:", MessageType.Info);
                        Kit_ModernWeaponScript copyFrom = null;
                        copyFrom = EditorGUILayout.ObjectField("Copy Attachments from weapon", copyFrom, typeof(Kit_ModernWeaponScript), false) as Kit_ModernWeaponScript;

                        if (copyFrom)
                        {
                            Undo.RecordObject(target, "Attachment Copy");
                            script.attachmentSlotsSpecific = new AttachmentSlot[copyFrom.attachmentSlotsSpecific.Length];

                            for (int i = 0; i < script.attachmentSlotsSpecific.Length; i++)
                            {
                                int id = i;
                                script.attachmentSlotsSpecific[id] = copyFrom.attachmentSlotsSpecific[id].Clone();
                            }
                            copyFrom = null;
                        }
                        EditorGUILayout.EndVertical();
                    }
                    else
                    {
                        EditorGUILayout.HelpBox("A universal override file is used", MessageType.Warning);
                    }

                    script.attachmentSlotOverride = EditorGUILayout.ObjectField("Attachments override", script.attachmentSlotOverride, typeof(Kit_AttachmentsUniversal), false) as Kit_AttachmentsUniversal;
                }
                springFoldout = EditorGUILayout.Foldout(springFoldout, "Spring Settings");
                if (springFoldout)
                {
                    EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                    EditorGUILayout.HelpBox("These springs are used for procedural animations", MessageType.Info);
                    script.springPosConfig.damping = EditorGUILayout.Vector3Field("Positional Damping", script.springPosConfig.damping);
                    script.springPosConfig.stiffness = EditorGUILayout.Vector3Field("Positional Stiffness", script.springPosConfig.stiffness);
                    script.springPosConfig.lerpSpeed = EditorGUILayout.FloatField("Positional Lerp Speed", script.springPosConfig.lerpSpeed);

                    script.springRotConfig.damping = EditorGUILayout.Vector3Field("Rotational Damping", script.springRotConfig.damping);
                    script.springRotConfig.stiffness = EditorGUILayout.Vector3Field("Rotational Stiffness", script.springRotConfig.stiffness);
                    script.springRotConfig.lerpSpeed = EditorGUILayout.FloatField("Rotational Lerp Speed", script.springRotConfig.lerpSpeed);

                    EditorGUILayout.EndVertical();
                }
                animationSettingsFoldout = EditorGUILayout.Foldout(animationSettingsFoldout, "Animator Settings");
                if (animationSettingsFoldout)
                {
                    EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                    script.setEmptyBool = GUILayout.Toggle(script.setEmptyBool, "Set Empty Bool");
                    script.setRunningBool = GUILayout.Toggle(script.setRunningBool, "Set Running Bool");
                    script.sendRunningEvents = GUILayout.Toggle(script.sendRunningEvents, "Send Running Events");
                    script.setAimingBool = GUILayout.Toggle(script.setAimingBool, "Set Aiming Bool");
                    script.setAimingProgress = GUILayout.Toggle(script.setAimingProgress, "Set Aiming float value");
                    script.setMovementDirection = GUILayout.Toggle(script.setMovementDirection, "Set movement direction");
                    EditorGUILayout.EndVertical();
                }
                damageFoldout = EditorGUILayout.Foldout(damageFoldout, "Damage");
                if (damageFoldout)
                {
                    EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                    script.baseDamage = EditorGUILayout.FloatField("Base Damage", script.baseDamage);
                    script.range = EditorGUILayout.FloatField("Max Range", script.range);
                    script.damageDropoff = EditorGUILayout.CurveField("Damage Dropoff", script.damageDropoff);
                    script.fireTypeMode = (FireTypeMode)EditorGUILayout.EnumPopup("Fire Type", script.fireTypeMode);
                    if (script.fireTypeMode == FireTypeMode.Pellets)
                    {
                        script.amountOfPellets = EditorGUILayout.IntField("Pellets", script.amountOfPellets);
                    }
                    EditorGUILayout.EndVertical();
                }
                crosshairFoldout = EditorGUILayout.Foldout(crosshairFoldout, "Crosshair");
                if (crosshairFoldout)
                {
                    EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                    script.crosshairEnabled = GUILayout.Toggle(script.crosshairEnabled, "Enabled");
                    if (script.crosshairEnabled)
                    {
                        script.crosshairSizeMultiplier = EditorGUILayout.FloatField("Size Multiplier", script.crosshairSizeMultiplier);
                    }
                    EditorGUILayout.EndVertical();
                }
                bulletFoldout = EditorGUILayout.Foldout(bulletFoldout, "Bullets");
                if (bulletFoldout)
                {
                    EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                    script.bulletsMode = (BulletMode)EditorGUILayout.EnumPopup("Bullet Mode", script.bulletsMode);
                    if (script.bulletsMode == BulletMode.Physical)
                    {
                        script.bulletPrefab = EditorGUILayout.ObjectField("Bullet Prefab", script.bulletPrefab, typeof(GameObject), false) as GameObject;
                        script.bulletSpeed = EditorGUILayout.FloatField("Bullet Speed (m/s)", script.bulletSpeed);
                        script.bulletHideForFrames = EditorGUILayout.IntField("Bullet Hide for frames after existance", script.bulletHideForFrames);
                        script.bulletGravityMultiplier = EditorGUILayout.FloatField("Bullet gravity modifier (current= " + (Physics.gravity.y * script.bulletGravityMultiplier).ToString() + " m/s²)", script.bulletGravityMultiplier);
                        script.bulletLifeTime = EditorGUILayout.FloatField("Bullet Life time (s)", script.bulletLifeTime);
                        script.bulletStaysAliveAfterDeath = EditorGUILayout.Toggle("Bullet Stays Alive after death", script.bulletStaysAliveAfterDeath);
                        if (script.bulletStaysAliveAfterDeath)
                        {
                            script.bulletStaysAliveAfterDeathTime = EditorGUILayout.FloatField("Time it stays alive after death", script.bulletStaysAliveAfterDeathTime);
                        }
                    }
                    script.bulletsPenetrationEnabled = EditorGUILayout.Toggle("Bullet Penetration Enabled", script.bulletsPenetrationEnabled);
                    if (script.bulletsPenetrationEnabled)
                    {
                        script.bulletsPenetrationForce = EditorGUILayout.IntField("Bullet Penetration Force", script.bulletsPenetrationForce);
                    }
                    EditorGUILayout.EndVertical();
                }
                bulletSpreadFoldout = EditorGUILayout.Foldout(bulletSpreadFoldout, "Bullet Spread");
                if (bulletSpreadFoldout)
                {
                    EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                    script.bulletSpreadMode = (SpreadMode)EditorGUILayout.EnumPopup("Spread Mode", script.bulletSpreadMode);

                    script.bulletSpreadHipBase = EditorGUILayout.FloatField("Hip base ", script.bulletSpreadHipBase);
                    script.bulletSpreadHipVelocityAdd = EditorGUILayout.FloatField("Hip velocity add max", script.bulletSpreadHipVelocityAdd);
                    script.bulletSpreadHipVelocityReference = EditorGUILayout.FloatField("Hip velocity reference speed", script.bulletSpreadHipVelocityReference);

                    script.bulletSpreadAimBase = EditorGUILayout.FloatField("Aim base ", script.bulletSpreadAimBase);
                    script.bulletSpreadAimVelocityAdd = EditorGUILayout.FloatField("Aim velocity add max", script.bulletSpreadAimVelocityAdd);
                    script.bulletSpreadAimVelocityReference = EditorGUILayout.FloatField("Aim velocity reference speed", script.bulletSpreadAimVelocityReference);

                    if (script.bulletSpreadMode == SpreadMode.SprayPattern)
                    {
                        SerializedProperty pattern = serializedObject.FindProperty("bulletSpreadSprayPattern");
                        EditorGUILayout.PropertyField(pattern, true);
                        script.bulletSpreadSprayPatternRecoverySpeed = EditorGUILayout.FloatField("Spray Pattern Recovery speed", script.bulletSpreadSprayPatternRecoverySpeed);
                    }
                    EditorGUILayout.EndVertical();
                }
                recoilFoldout = EditorGUILayout.Foldout(recoilFoldout, "Recoil");
                if (recoilFoldout)
                {
                    EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                    script.recoilPerShotMin = EditorGUILayout.Vector2Field("Min recoil", script.recoilPerShotMin);
                    script.recoilPerShotMax = EditorGUILayout.Vector2Field("Max recoil", script.recoilPerShotMax);
                    script.recoilApplyTime = EditorGUILayout.FloatField("Apply time", script.recoilApplyTime);
                    script.recoilReturnSpeed = EditorGUILayout.FloatField("Return speed", script.recoilReturnSpeed);
                    EditorGUILayout.EndVertical();
                }
                reloadFoldout = EditorGUILayout.Foldout(reloadFoldout, "Reloading");
                if (reloadFoldout)
                {
                    EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                    script.reloadMode = (ReloadMode)EditorGUILayout.EnumPopup("Reload mode", script.reloadMode);
                    if (script.reloadMode == ReloadMode.Simple || script.reloadMode == ReloadMode.Chambered || script.reloadMode == ReloadMode.FullEmpty)
                    {
                        GUILayout.Label("Reload normal");
                        script.reloadTimeOne = EditorGUILayout.FloatField("Reload time one", script.reloadTimeOne);
                        script.reloadTimeTwo = EditorGUILayout.FloatField("Reload time two", script.reloadTimeTwo);
                        script.reloadSound = EditorGUILayout.ObjectField("Reload sound", script.reloadSound, typeof(AudioClip), false) as AudioClip;
                    }
                    if (script.reloadMode == ReloadMode.FullEmpty || script.reloadMode == ReloadMode.Chambered)
                    {
                        GUILayout.Label("Reload Empty");
                        script.reloadEmptyTimeOne = EditorGUILayout.FloatField("Reload empty time one", script.reloadEmptyTimeOne);
                        script.reloadEmptyTimeTwo = EditorGUILayout.FloatField("Reload empty time two", script.reloadEmptyTimeTwo);
                        script.reloadSoundEmpty = EditorGUILayout.ObjectField("Reload sound empty", script.reloadSoundEmpty, typeof(AudioClip), false) as AudioClip;
                    }

                    if (script.reloadMode == ReloadMode.Procedural || script.reloadMode == ReloadMode.ProceduralChambered)
                    {
                        GUILayout.Label("Start");
                        script.reloadProceduralStartTime = EditorGUILayout.FloatField("Reload procedural start time", script.reloadProceduralStartTime);
                        script.reloadProceduralStartSound = EditorGUILayout.ObjectField("Reload procedural start sound", script.reloadProceduralStartSound, typeof(AudioClip), false) as AudioClip;
                        GUILayout.Label("Start Empty");
                        script.reloadProceduralAddBulletDuringStartEmpty = GUILayout.Toggle(script.reloadProceduralAddBulletDuringStartEmpty, "Reload procedural add bullet during empty start");
                        if (script.reloadProceduralAddBulletDuringStartEmpty)
                        {
                            script.reloadProceduralEmptyInsertStartTimeOne = EditorGUILayout.FloatField("Reload procedural empty time one", script.reloadProceduralEmptyInsertStartTimeOne);
                            script.reloadProceduralEmptyInsertStartTimeTwo = EditorGUILayout.FloatField("Reload procedural empty time two", script.reloadProceduralEmptyInsertStartTimeTwo);
                        }
                        else
                        {
                            script.reloadProceduralEmptyStartTime = EditorGUILayout.FloatField("Reload procedural empty time", script.reloadProceduralEmptyStartTime);
                        }
                        script.reloadProceduralStartEmptySound = EditorGUILayout.ObjectField("Reload procedural start empty sound", script.reloadProceduralStartEmptySound, typeof(AudioClip), false) as AudioClip;
                        GUILayout.Label("Insert");
                        script.reloadProceduralInsertTimeOne = EditorGUILayout.FloatField("Reload procedural insert time one", script.reloadProceduralInsertTimeOne);
                        script.reloadProceduralInsertTimeTwo = EditorGUILayout.FloatField("Reload procedural insert time two", script.reloadProceduralInsertTimeTwo);
                        script.reloadProceduralInsertSound = EditorGUILayout.ObjectField("Reload procedural insert sound", script.reloadProceduralInsertSound, typeof(AudioClip), false) as AudioClip;
                        GUILayout.Label("End");
                        script.reloadProceduralEndTime = EditorGUILayout.FloatField("Reload procedural end time", script.reloadProceduralEndTime);
                        script.reloadProceduralEndSound = EditorGUILayout.ObjectField("Reload procedural end sound", script.reloadProceduralEndSound, typeof(AudioClip), false) as AudioClip;
                    }

                    script.reloadSoundThirdPersonMaxRange = EditorGUILayout.FloatField("Reload sound third person max range", script.reloadSoundThirdPersonMaxRange);
                    script.reloadSoundThirdPersonRolloff = EditorGUILayout.CurveField("Reload sound third person rolloff", script.reloadSoundThirdPersonRolloff);
                    EditorGUILayout.EndVertical();
                }
                aimingFoldout = EditorGUILayout.Foldout(aimingFoldout, "Aiming");
                if (aimingFoldout)
                {
                    EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                    script.aimEnabled = EditorGUILayout.Toggle("Aim enabled", script.aimEnabled);
                    script.aimInTime = EditorGUILayout.FloatField("Aim in time", script.aimInTime);
                    script.aimOutTime = EditorGUILayout.FloatField("Aim out time", script.aimOutTime);
                    script.aimSpeedMultiplier = EditorGUILayout.FloatField("Aim speed in %", script.aimSpeedMultiplier);
                    EditorGUILayout.EndVertical();
                }
                weaponDelayFoldout = EditorGUILayout.Foldout(weaponDelayFoldout, "Weapon Delay");
                if (weaponDelayFoldout)
                {
                    EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                    script.weaponDelayBaseAmount = EditorGUILayout.FloatField("Base amount", script.weaponDelayBaseAmount);
                    script.weaponDelayMaxAmount = EditorGUILayout.FloatField("Max amount", script.weaponDelayMaxAmount);
                    script.weaponDelayAimingMultiplier = EditorGUILayout.FloatField("Aiming multiplier", script.weaponDelayAimingMultiplier);
                    script.weaponDelaySmooth = EditorGUILayout.FloatField("Smooth", script.weaponDelaySmooth);
                    EditorGUILayout.EndVertical();
                }
                weaponTiltFoldout = EditorGUILayout.Foldout(weaponTiltFoldout, "Weapon Tilt");
                if (weaponTiltFoldout)
                {
                    EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                    script.weaponTiltEnabled = EditorGUILayout.Toggle("Enabled", script.weaponTiltEnabled);
                    if (script.weaponTiltEnabled)
                    {
                        script.weaponTiltIntensity = EditorGUILayout.FloatField("Intensity", script.weaponTiltIntensity);
                        script.weaponTiltEnabledWhileAiming = EditorGUILayout.Toggle("Enabled while aiming", script.weaponTiltEnabledWhileAiming);
                        script.weaponTiltReturnSpeed = EditorGUILayout.FloatField("Return Speed", script.weaponTiltReturnSpeed);
                    }
                    EditorGUILayout.EndVertical();
                }
                weaponFallFoldout = EditorGUILayout.Foldout(weaponFallFoldout, "Weapon Fall");
                if (weaponFallFoldout)
                {
                    EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                    script.fallDownAmount = EditorGUILayout.FloatField("Amount", script.fallDownAmount);
                    script.fallDownMinOffset = EditorGUILayout.FloatField("Min Offset", script.fallDownMinOffset);
                    script.fallDownMaxoffset = EditorGUILayout.FloatField("Max Offset", script.fallDownMaxoffset);
                    script.fallDownTime = EditorGUILayout.FloatField("Time", script.fallDownTime);
                    script.fallDownReturnSpeed = EditorGUILayout.FloatField("Return speed", script.fallDownReturnSpeed);
                    EditorGUILayout.EndVertical();
                }
                shellEjectionFoldout = EditorGUILayout.Foldout(shellEjectionFoldout, "Shell Ejection");
                if (shellEjectionFoldout)
                {
                    EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                    script.shellEjectionPrefab = EditorGUILayout.ObjectField("Shell prefab", script.shellEjectionPrefab, typeof(GameObject), false) as GameObject;
                    if (script.shellEjectionPrefab)
                    {
                        script.shellEjectionTime = Mathf.Clamp(EditorGUILayout.FloatField("Ejection delay", script.shellEjectionTime), 0f, float.MaxValue);
                        script.shellEjectionMinForce = EditorGUILayout.Vector3Field("Min force", script.shellEjectionMinForce);
                        script.shellEjectionMaxForce = EditorGUILayout.Vector3Field("Max force", script.shellEjectionMaxForce);
                        script.shellEjectionMinTorque = EditorGUILayout.Vector3Field("Min torque", script.shellEjectionMinTorque);
                        script.shellEjectionMaxTorque = EditorGUILayout.Vector3Field("Max torque", script.shellEjectionMaxTorque);
                    }
                    EditorGUILayout.EndVertical();
                }
                walkFoldout = EditorGUILayout.Foldout(walkFoldout, "Walk Animation");
                if (walkFoldout)
                {
                    EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                    script.enableWalkAnimationWhileAiming = GUILayout.Toggle(script.enableWalkAnimationWhileAiming, "Enable walk animation while aiming");
                    EditorGUILayout.EndVertical();
                }
                genericAnimationsFoldout = EditorGUILayout.Foldout(genericAnimationsFoldout, "Generic Animations");
                if (genericAnimationsFoldout)
                {
                    EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                    script.genericGunAnimatorControllerPrefab = EditorGUILayout.ObjectField("Animator prefab", script.genericGunAnimatorControllerPrefab, typeof(GameObject), false) as GameObject;
                    script.useGenericWalkAnim = GUILayout.Toggle(script.useGenericWalkAnim, "Use generic walk animation");
                    script.useGenericRunAnim = GUILayout.Toggle(script.useGenericRunAnim, "Use generic run animation");
                    EditorGUILayout.EndVertical();
                }

                if (EditorGUI.EndChangeCheck())
                {
                    Undo.RecordObject(target, "Weapon script modification");
                    serializedObject.ApplyModifiedProperties();
                    EditorUtility.SetDirty(target);
                }

                /*
                if (GUI.changed)
                {
                    Undo.RecordObject(target, "Weapon script modification");
                    serializedObject.ApplyModifiedProperties();
                }
                */
            }
        }
    }
}
using System.Collections.Generic;
using Mirror;
using UnityEngine;
using static System.Net.WebRequestMethods;

namespace MarsFPSKit
{
    namespace Weapons
    {
        public class Kit_ModernWeaponScriptRuntimeData : Kit_WeaponRuntimeDataBase
        {
            [SyncVar]
            /// <summary>
            /// Is this weapon out and ready to shoot?
            /// </summary>
            public bool isSelectedAndReady = false;
            [SyncVar]
            /// <summary>
            /// Is the weapon selected?
            /// </summary>
            public bool isSelected;
            [SyncVar]
            /// <summary>
            /// How many bullets are left in the magazine?
            /// </summary>
            public int bulletsLeft;
            [SyncVar]
            /// <summary>
            /// How many bullets do we have left to reload
            /// </summary>
            public int bulletsLeftToReload;

            [SyncVar]
            /// <summary>
            /// Are we currently reloading?
            /// </summary>
            public bool reloadInProgress;

            public Kit_WeaponRenderer weaponRenderer;
            public Kit_ThirdPersonWeaponRenderer tpWeaponRenderer;

            public Animator genericAnimator;

            #region Stats
            [SyncVar]
            /// <summary>
            /// Are we currently firing full auto?
            /// </summary>
            public bool isFiring;
            /// <summary>
            /// When did we fire for the last time? Compare with <see cref="Time.time"/>
            /// </summary>
            public float lastFire;

            /// <summary>
            /// When did we ran the last time (using this weapon)
            /// </summary>
            public float lastRun;
            #endregion

            #region Reload
            /// <summary>
            /// When is the next reloading phase over?
            /// </summary>
            public float reloadNextEnd; //This is only so we don't have to use a coroutine
            /// <summary>
            /// The current phase of reloading
            /// </summary>
            public int reloadPhase;
            #endregion

            #region Procedural Reload
            /// <summary>
            /// Set to true if the player attemps to fire during the reload
            /// </summary>
            public bool cancelProceduralReload = false;
            #endregion

            #region Aiming
            /// <summary>
            /// Are we currently aiming?
            /// </summary>
            public bool isAiming;

            /// <summary>
            /// So we can see if it changed, based on bools only
            /// </summary>
            public bool lastIsAiming;

            /// <summary>
            /// Float between 0 and 1 that indicates how far we have aimed in
            /// </summary>
            public float aimingProgress;

            /// <summary>
            /// Are we aimed in?
            /// </summary>
            public bool isAimedIn
            {
                get
                {
                    return Mathf.Approximately(aimingProgress, 1f);
                }
            }

            /// <summary>
            /// If we are using the sniper scope, this helps us to only hide the weapon once
            /// </summary>
            public bool sniperWeaponHidden;

            /// <summary>
            /// Transform used to move the weapon to aiming position
            /// </summary>
            public Transform aimingTransform;
            #endregion

            #region Weapon Delay
            /// <summary>
            /// The transform to apply our delay effect to
            /// </summary>
            public Transform weaponDelayTransform;
            /// <summary>
            /// Current weapon delay target
            /// </summary>
            public Vector3 weaponDelayCur;
            /// <summary>
            /// Current Mouse X input for weapon delay
            /// </summary>
            public float weaponDelayCurrentX;
            /// <summary>
            /// Current Mouse Y input for weapon delay
            /// </summary>
            public float weaponDelayCurrentY;
            /// <summary>
            /// This is the difference from last frame
            /// </summary>
            public Quaternion weaponDelayLastDifference;
            /// <summary>
            /// To get difference, we use quaternion of look root
            /// </summary>
            public Quaternion weaponDelayLastRotation;
            #endregion

            #region Weapon Fall
            public Transform weaponFallTransform;
            #endregion

            #region Shell Ejection
            /// <summary>
            /// Should we check if we should eject a shell?
            /// </summary>
            public bool shellEjectEnabled = false;
            /// <summary>
            /// At which point in time are we going to eject the shell?
            /// </summary>
            public float shellEjectNext;
            #endregion

            #region  Bolt Action
            /// <summary>
            /// 0 = Nothing; 1 = Eject next; 2 = Eject next (last shot)
            /// </summary>
            public int boltActionState;
            /// <summary>
            /// When is the eject definied in <see cref="boltActionState"/> going to happen?
            /// </summary>
            public float boltActionTime;
            #endregion

            /// <summary>
            /// Which animation was played the last time? Used to only call CrossFade once so it transitions correctly.
            /// </summary>
            public int lastWeaponAnimationID;

            #region Spray Pattern
            /// <summary>
            /// Current state of the spray pattern
            /// </summary>
            public float sprayPatternState = 0f;
            #endregion

            #region Run Animation
            /// <summary>
            /// Is the running animation (using non generic mecanim) currently playing?
            /// </summary>
            public bool startedRunAnimation;
            #endregion

            #region Sound
            /// <summary>
            /// Audio source used for fire sounds
            /// </summary>
            public AudioSource soundFire;

            /// <summary>
            /// Audio Source used for reload sounds
            /// </summary>
            public AudioSource soundReload;

            /// <summary>
            /// Audio Source used for other sounds
            /// </summary>
            public AudioSource soundOther;
            #endregion

            #region Input
            public bool lastLmb;
            public bool lastRmb;
            public bool lastReload;
            #endregion

            #region Spring
            /// <summary>
            /// Positional spring
            /// </summary>
            public Kit_Spring springPos;
            /// <summary>
            /// Rotational spring
            /// </summary>
            public Kit_Spring springRot;
            #endregion

            //In order to modify the stats, we copy them here first
            #region Modifyable stats
            #region Settings
            [Header("Settings")]
            public FireMode fireMode = FireMode.Semi;
            public float fireRate = 0.1f;
            /// <summary>
            /// How many bullets do we have per mag
            /// </summary>
            public int bulletsPerMag = 30;
            /// <summary>
            /// With how many <see cref="WeaponControllerRuntimeData.bulletsLeftToReload"/> do we start?
            /// </summary>
            public int bulletsToReloadAtStart = 60;
            /// <summary>
            /// How much damage does this weapon deal?
            /// </summary>
            public float baseDamage = 30f;
            /// <summary>
            /// The max. range of this weapon
            /// </summary>
            public float range = 500f;
            /// <summary>
            /// This is the damage drop off relative to <see cref="range"/>. It should be a value between 0 and 1 that multiplies with <see cref="baseDamage"/>
            /// </summary>
            public AnimationCurve damageDropoff = AnimationCurve.Linear(0, 1, 500f, 0.8f);
            /// <summary>
            /// Should we shoot one bullet at a time or pellets?
            /// </summary>
            public FireTypeMode fireTypeMode = FireTypeMode.Simple;
            /// <summary>
            /// If we are firing using burst, how many bullets should be fired in one burst?
            /// </summary>
            public int burstBulletsPerShot = 3;
            /// <summary>
            /// How many seconds need to pass between individual shots in burst fire mode?
            /// </summary>
            public float burstTimeBetweenShots = 0.1f;
            /// <summary>
            /// If we should shoot pellets, how many should we shoot?
            /// </summary>
            public int amountOfPellets = 12;
            /// <summary>
            /// How much should the weapon slow us down (base)?  Other values are multiplier by this.
            /// </summary>
            public float speedMultiplierBase = 1f;
            /// <summary>
            /// How much force is applied to the ragdoll?
            /// </summary>
            public float ragdollForce = 500f;
            #endregion

            #region Bullets
            /// <summary>
            /// Determines whether we should use raycast or physical bullets
            /// </summary>
            public BulletMode bulletsMode = BulletMode.Raycast;
            /// <summary>
            /// Is bullet penetration enabled?
            /// </summary>
            public bool bulletsPenetrationEnabled = true;
            /// <summary>
            /// This is a value that determines how many objects can be penetrated with this bullet. Think of it as the money you have available to pay the penetration cost here <see cref="Kit_PenetrateableObject.cost"/>
            /// </summary>
            public int bulletsPenetrationForce = 3;
            /// <summary>
            /// If <see cref="bulletsMode"/> is set to <see cref="BulletMode.Physical"/>, this prefab will be instantiated instead of raycast
            /// </summary>
            public GameObject bulletPrefab;
            /// <summary>
            /// Speed of physical bullet in m/s
            /// </summary>
            public float bulletSpeed = 200;
            /// <summary>
            /// How many frames after shooting should the bullet be hidden?
            /// </summary>
            public int bulletHideForFrames = 3;
            /// <summary>
            /// Multiplier of gravity applied to bullet (1 = realistic). Multiplies with <see cref="Physics.gravity"/>
            /// </summary>
            public float bulletGravityMultiplier = 1f;
            /// <summary>
            /// How long will this weapon's bullets exist?
            /// </summary>
            public float bulletLifeTime = 10f;
            /// <summary>
            /// Should the bullet parent itself to its hit thing and stay alive? Useful for things like nails and arrows.
            /// </summary>
            public bool bulletStaysAliveAfterDeath = false;
            /// <summary>
            /// If bullet stays alive after death, this is how long
            /// </summary>
            public float bulletStaysAliveAfterDeathTime = 10f;
            #endregion

            #region Bullet Spread
            /// <summary>
            /// Which spray m ode does this weapon use?
            /// </summary>
            public SpreadMode bulletSpreadMode = SpreadMode.Simple;
            /// <summary>
            /// Base value for hip bullet spread
            /// </summary>
            public float bulletSpreadHipBase = 0.1f;
            /// <summary>
            /// How much spread should be added for our current velocity in reference to <see cref="bulletSpreadHipVelocityReference"/>
            /// </summary>
            public float bulletSpreadHipVelocityAdd = 0.1f;
            /// <summary>
            /// Reference velocity for hip spread
            /// </summary>
            public float bulletSpreadHipVelocityReference = 6f;

            /// <summary>
            /// Base value for aiming bullet spread
            /// </summary>
            public float bulletSpreadAimBase = 0.01f;
            /// <summary>
            /// How much spread should be added for our current velocity in reference to <see cref="bulletSpreadAimVelocityReference"/>
            /// </summary>
            public float bulletSpreadAimVelocityAdd = 0.02f;
            /// <summary>
            /// Reference velocity for aim spread
            /// </summary>
            public float bulletSpreadAimVelocityReference = 6f;

            //SPRAY PATTERN
            /// <summary>
            /// Offset values for the spray pattern mode
            /// </summary>
            public Vector3[] bulletSpreadSprayPattern = new Vector3[30];
            /// <summary>
            /// How fast does the spray pattern recover?
            /// </summary>
            public float bulletSpreadSprayPatternRecoverySpeed = 1f;
            //END
            #endregion

            #region Recoil
            /// <summary>
            /// Minimum amount of recoil per shot
            /// </summary>
            public Vector2 recoilPerShotMin = new Vector2 { x = -0.1f, y = 0.5f };
            /// <summary>
            /// Max amount of recoil per shot
            /// </summary>
            public Vector2 recoilPerShotMax = new Vector2 { x = 0.1f, y = 1f };
            /// <summary>
            /// How fast is our recoil going to be applied
            /// </summary>
            public float recoilApplyTime = 0.1f;
            /// <summary>
            /// How fast are we going to return to our normal position?
            /// </summary>
            public float recoilReturnSpeed = 6f;
            #endregion
            #endregion

            public void FiredWeapon(Kit_PlayerBehaviour target, int damageIndex, Vector3 originPoint, Vector3 hitPoint)
            {
                if (!pb.isBot)
                {
                    CmdFiredWeapon(target, damageIndex, originPoint, hitPoint);
                }
            }

            [Command]
            public void CmdFiredWeapon(Kit_PlayerBehaviour target, int damageIndex, Vector3 originPoint, Vector3 hitPoint)
            {
                FiredWeaponInternal(target, damageIndex, originPoint, hitPoint);
            }

            private void FiredWeaponInternal(Kit_PlayerBehaviour target, int damageIndex, Vector3 originPoint, Vector3 hitPoint)
            {
                if (!pb.isBot)
                {
                    if (target)
                    {
                        // 'this' fired at 'target'.
                        // we need to grab 'target's LagCompensator to find out where it was.
                        LagCompensator compensator = target.GetComponent<LagCompensator>();

                        if (compensator)
                        {
                            RaycastHit hit;

                            Vector3 dir = (hitPoint - originPoint).normalized;

                            // next, we can use either of the compensator's 'Check...' functions.
                            // viewer is the one who fired, so it's 'this' object.
                            // Lag Compensator checks 'this' object's latency and then rewinds 'target's history by that time.
                            if (compensator.RaycastCheck(this.connectionToClient, originPoint, hitPoint, pb.gameInformation.lagCompensationTolerancePercent, target.gameInformation.weaponHitLayersNoPlayers, out hit))
                            {
                                List<Kit_PlayerBehaviour> damagedPlayers = new List<Kit_PlayerBehaviour>();
                                #region Damage
                                //Check if we hit a player
                                //if (hit.collider.GetComponent<Kit_PlayerDamageMultiplier>() && Kit_IngameMain.instance.currentGameModeType == 2)
                                {
                                    Kit_PlayerDamageMultiplier pdm = target.thirdPersonPlayerModel.damageMultipliers[damageIndex];
                                    //if (hit.collider.transform.root.GetComponent<Kit_PlayerBehaviour>())
                                    {
                                        //First check if we can actually damage that player
                                        if (Kit_IngameMain.instance.currentPvPGameModeBehaviour.ArePlayersEnemies(pb, target))
                                        {
                                            //Check if he has spawn protection
                                            if (!target.spawnProtection || target.spawnProtection.CanTakeDamage(target))
                                            {
                                                //Apply local damage, sample damage dropoff via distance
                                                if (pb.isServer)
                                                {
                                                    target.ServerDamage((behaviour as Kit_ModernWeaponScript).GetDamage(this, Vector3.Distance(pb.playerCameraTransform.position, hit.point)) * pdm.damageMultiplier, id, pb.transform.position, dir, ragdollForce, hit.point, /*pdm.ragdollId*/ 0, pb.isBot, pb.id);
                                                    if (!pb.isBot) pb.TargetHitMarker(0);
                                                }
                                            }
                                            else if (pb.isServer)
                                            {
                                                //We hit a player but his spawn protection is active
                                                if (!pb.isBot) pb.TargetHitMarker(1);
                                            }
                                        }
                                    }
                                }
                                #endregion
                            }
                        }
                    }
                }
            }


            public void FiredWeapon(LagCompensator target, Vector3 originPoint, Vector3 hitPoint)
            {
                if (!pb.isBot)
                {
                    CmdFiredWeapon(target, originPoint, hitPoint);
                }
            }

            [Command]
            public void CmdFiredWeapon(LagCompensator target, Vector3 originPoint, Vector3 hitPoint)
            {
                FiredWeaponInternal(target, originPoint, hitPoint);
            }

            private void FiredWeaponInternal(LagCompensator target, Vector3 originPoint, Vector3 hitPoint)
            {
                if (!pb.isBot)
                {
                    if (target)
                    {
                        // 'this' fired at 'target'.
                        // we need to grab 'target's LagCompensator to find out where it was.
                        LagCompensator compensator = target.GetComponent<LagCompensator>();

                        if (compensator)
                        {
                            RaycastHit hit;

                            Vector3 dir = (hitPoint - originPoint).normalized;

                            // next, we can use either of the compensator's 'Check...' functions.
                            // viewer is the one who fired, so it's 'this' object.
                            // Lag Compensator checks 'this' object's latency and then rewinds 'target's history by that time.
                            if (compensator.RaycastCheck(this.connectionToClient, originPoint, hitPoint, pb.gameInformation.lagCompensationTolerancePercent, pb.gameInformation.weaponHitLayersNoPlayers, out hit))
                            {
                                //Apply local damage, sample damage dropoff via distance
                                if (pb.isServer)
                                {
                                    var dmg = target.GetComponentInChildren<IKitDamageable>();
                                    if (dmg != null)
                                    {
                                        float damage = (behaviour as Kit_ModernWeaponScript).GetDamage(this, Vector3.Distance(pb.playerCameraTransform.position, hit.point));
                                        dmg.ServerDamage(damage, id, pb.playerCameraTransform.position, dir, ragdollForce, hit.point, pb.isBot, pb.id);
                                        //Show hitmarker
                                        pb.TargetHitMarker(0);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Mirror;
using MarsFPSKit.Networking;
using System.Linq;

namespace MarsFPSKit
{
    /// <summary>
    /// All input for the player (e.g. LMB, W,A,S,D, etc) should be stored here, so that bots may use the same scripts.
    /// </summary>
    public class Kit_PlayerInput
    {
        public float hor;
        public float ver;
        public bool crouch;
        public bool sprint;
        public bool jump;
        public bool interact;
        public bool lmb;
        public bool rmb;
        public bool aiming;
        public bool reload;
        public float mouseX;
        public float mouseY;
        public bool leanLeft;
        public bool leanRight;
        public bool thirdPerson;
        public bool flashlight;
        public bool laser;
        public bool[] weaponSlotUses;

        public bool nextWeapon;
        public bool previousWeapon;

        public Vector3 clientCamPos;
        public Vector3 clientCamForward;
    }

    public class Kit_PlayerBehaviour : NetworkBehaviour
    {
        #region Game Information
        [Header("Internal Game Information")]
        [Tooltip("This object contains all game information such as Maps, Game Modes and Weapons")]
        public Kit_GameInformation gameInformation;
        #endregion

        //This section contains everything for the local camera control
        #region Camera Control
        [Header("Camera Control")]
        public Transform playerCameraTransform;
        /// <summary>
        /// Transform that should be used for camera animations from weapons
        /// </summary>
        public Transform playerCameraAnimationTransform;
        /// <summary>
        /// Fall effects should be applied here
        /// </summary>
        public Transform playerCameraFallDownTransform;
        /// <summary>
        /// Hit reactions for camera should be applied here
        /// </summary>
        public Transform playerCameraHitReactionsTransform;
        #endregion

        //This section contains everything for the movement
        #region Movement
        [Header("Movement")]
        public Kit_MovementBase movement; //The system used for movement
        [System.NonSerialized]
        /// <summary>
        /// Unsynced data for movement module.
        /// </summary>
        public Kit_MovementNetworkBase movementNetworkData;

        /// <summary>
        /// Our Character Controller, assign it here
        /// </summary>
        public CharacterController cc;
        /// <summary>
        /// Our footstep audio source
        /// </summary>
        public AudioSource footstepSource;
        /// <summary>
        /// An audio source to play sounds from movement
        /// </summary>
        public AudioSource movementSoundSource;
        #endregion

        //This section contains everything for the Mouse Look
        #region Looking
        [Header("Mouse Look")]
        public Kit_MouseLookBase looking; //The system used for looking
        public Transform mouseLookObject; //The transform used for looking around
        [HideInInspector]
        /// <summary>
        /// This is used by the mouse looking script to apply the recoil and by the weapon script to set the recoil
        /// </summary>
        public Quaternion recoilApplyRotation = Quaternion.identity;
        [HideInInspector]
        public Kit_MouseLookNetworkBase customMouseLookData; //Used to store custom mouse look data
        #endregion

        //This section contains everything for the weapons
        #region Weapons
        [Header("Weapons")]
        public Weapons.Kit_WeaponManagerBase weaponManager; //The system used for weapon management
        [System.NonSerialized]
        /// <summary>
        /// Synced data for weapon manager
        /// </summary>
        public Kit_WeaponManagerNetworkBase weaponManagerNetworkData;
        public Transform weaponsGo;
        /// <summary>
        /// Hit reactions for weapons should be applied here
        /// </summary>
        public Transform weaponsHitReactions;
        #endregion

        #region Player Vitals
        [Header("Player Vitals")]
        public Kit_VitalsBase vitalsManager;
        [System.NonSerialized]
        /// <summary>
        /// Network Data of vitals module
        /// </summary>
        public Kit_VitalsNetworkBase vitalsNetworkData;
        #endregion

        #region Player Name UI
        [Header("Player Name UI")]
        public Kit_PlayerNameUIBase nameManager;
        public object customNameData;
        #endregion

        #region Spawn Protection
        [Header("Spawn Protection")]
        public Kit_SpawnProtectionBase spawnProtection;
        public object customSpawnProtectionData;
        #endregion

        #region Bots
        [Header("Bot Controls")]
        /// <summary>
        /// This module will control the behaviour of the bot
        /// </summary>
        public Kit_PlayerBotControlBase botControls;
        /// <summary>
        /// Use this to store runtime data for bot control
        /// </summary>
        public Kit_PlayerBotControlDataBase botControlsRuntimeData;
        #endregion

        #region Voice
        [Header("Voice Manager")]
        /// <summary>
        /// If this is assigned, your characters can talk!
        /// </summary>
        public Kit_VoiceManagerBase voiceManager;

        /// <summary>
        /// use this  to store runtime data for the voice manager
        /// </summary>
        public object voiceManagerData;
        #endregion

        #region Input Manager
        [Header("Input Manager")]
        public Kit_InputManagerBase inputManager;
        /// <summary>
        /// Use this to store input manager runtime data
        /// </summary>
        public object inputManagerData;
        #endregion

        //This section contains internal variables
        #region Internal Variables
        [SyncVar]
        //Team
        public int myTeam = -1;

        /// <summary>
        /// True if first person view is active on this player. Does not mean that this is our local player. To determine actual perspective call looking.GetPerspective()
        /// </summary>
        public bool isFirstPersonActive
        {
            get
            {
                if (isLocalPlayer || isBeingSpectated)
                {
                    return true;
                }

                return false;
            }
        }

        /// <summary>
        /// Is input enabled?
        /// </summary>
        public bool enableInput
        {
            get
            {
                if (isOwned || isServer && isBot)
                {
                    if (isBot)
                    {
                        return canControlPlayer;
                    }
                    else
                    {
                        return MarsScreen.lockCursor && canControlPlayer;
                    }
                }
                else
                {
                    return false;
                }
            }
        }

        /// <summary>
        /// Runtime data from the game mode can be stored here
        /// </summary>
        public object gameModeCustomRuntimeData;

        /// <summary>
        /// Input for the player, only assigned if we are controlling this player or we are the master client
        /// </summary>
        public Kit_PlayerInput input;
        [SyncVar]
        /// <summary>
        /// Is this player being controlled by AI?
        /// </summary>
        public bool isBot;
        [SyncVar]
        /// <summary>
        /// This is either the player or bot id, depending on <see cref="isBot"/>
        /// </summary>
        public uint id;
        /// <summary>
        /// User name fetched in sync setup
        /// </summary>
        public string userName;

        [HideInInspector]
        //Position and rotation are synced by photon transform view
        public bool syncSetup;

        //We cache this value to avoid to calculate it many times
        [HideInInspector]
        public bool canControlPlayer = true;

        /// <summary>
        /// Currently active third person model
        /// </summary>
        public Kit_ThirdPersonPlayerModel thirdPersonPlayerModel;
        [SyncVar]
        /// <summary>
        /// Id of the player model we are currently using! Only assigned in PvP game modes.
        /// </summary>
        public int thirdPersonPlayerModelID;
        /// <summary>
        /// Active customizations
        /// </summary>
        public readonly SyncList<int> thirdPersonPlayerModelCustomizations = new SyncList<int>();
        [SyncVar]
        /// <summary>
        /// Last forward vector from where we were shot
        /// </summary>
        public Vector3 ragdollForward;
        [SyncVar]
        /// <summary>
        /// Last force which we were shot with
        /// </summary>
        public float ragdollForce;
        [SyncVar]
        /// <summary>
        /// Last point from where we were shot
        /// </summary>
        public Vector3 ragdollPoint;
        [SyncVar]
        /// <summary>
        /// Which collider should the force be applied to?
        /// </summary>
        public int ragdollId;
        [HideInInspector]
        /// <summary>
        /// The category to play
        /// </summary>
        public int deathSoundCategory;
        [HideInInspector]
        /// <summary>
        /// The specific sound to play
        /// </summary>
        public int deathSoundID;
        [HideInInspector]
        /// <summary>
        /// Who damaged us? For the assist manager.
        /// </summary>
        public List<AssistedKillData> damagedBy = new List<AssistedKillData>();
        [HideInInspector]
        /// <summary>
        /// Are we  currently being spectated?
        /// </summary>
        public bool isBeingSpectated;
        /// <summary>
        /// Cached mirror variable for use after destroy
        /// </summary>
        private bool wasLocalPlayer;
        #endregion

        public IEnumerator LocalPlayerRoutine()
        {
            while (!thirdPersonPlayerModel) yield return null;

            //Make sure we're not spectating anymore
            if (Kit_IngameMain.instance.spectatorManager)
            {
                if (Kit_IngameMain.instance.spectatorManager.IsCurrentlySpectating())
                {
                    Kit_IngameMain.instance.spectatorManager.EndSpectating();
                }
            }

            Kit_IngameMain.instance.hud.PlayerStart(this);
            //Disable our own name hitbox
            thirdPersonPlayerModel.enemyNameAboveHeadTrigger.enabled = false;
            // Setup voice
            if (voiceManager)
            {
                voiceManager.SetupOwner(this);
            }

            //Setup marker
            if (nameManager)
            {
                nameManager.LocalPlayerGainedControl(this);
            }

            //Assign ourselves
            Kit_IngameMain.instance.myPlayer = this;

            //Lock the cursor
            MarsScreen.lockCursor = true;
            //Close pause menu
            Kit_IngameMain.isPauseMenuOpen = false;
            Kit_IngameMain.instance.SwitchMenu(Kit_IngameMain.instance.ingameFadeId, true);
            yield return new WaitForSeconds(Kit_IngameMain.instance.menuScreens[Kit_IngameMain.instance.currentScreen].fadeOutLength);
            //Move camera to the right position
            Kit_IngameMain.instance.activeCameraTransform = playerCameraTransform;
            //Setup third person model
            thirdPersonPlayerModel.FirstPerson();
            //Tell Minimap we spawned
            if (Kit_IngameMain.instance.minimap)
            {
                Kit_IngameMain.instance.minimap.LocalPlayerSpawned(this);
            }
            //Tell touchscreen
            if (Kit_IngameMain.instance.touchScreenCurrent)
            {
                Kit_IngameMain.instance.touchScreenCurrent.LocalPlayerSpawned(this);
            }
            //Auto spawn system callack
            if (Kit_IngameMain.instance.autoSpawnSystem && Kit_IngameMain.instance.currentPvPGameModeBehaviour)
            {
                Kit_IngameMain.instance.autoSpawnSystem.LocalPlayerSpawned();
            }
            if (Kit_IngameMain.instance.currentPvPGameModeBehaviour)
            {
                //Tell Game Mode
                Kit_IngameMain.instance.currentPvPGameModeBehaviour.OnLocalPlayerSpawned(this);
            }
            else if (Kit_IngameMain.instance.currentPvEGameModeBehaviour)
            {
                //Tell Game Mode
                Kit_IngameMain.instance.currentPvEGameModeBehaviour.OnLocalPlayerSpawned(this);
            }
            //Show HUD
            Kit_IngameMain.instance.hud.SetVisibility(true);
            Kit_IngameMain.instance.pluginOnForceClose.Invoke();
            //Call Plugin
            for (int i = 0; i < gameInformation.plugins.Length; i++)
            {
                gameInformation.plugins[i].LocalPlayerSpawned(this);
            }

            //Call loadout
            Kit_IngameMain.instance.loadoutMenu.LocalPlayerSpawned(this);

            //Take control in modules
            looking.TakeControl(this);
            weaponManager.TakeControl(this);

            double waitCur = 0f;
            double waitTarget = Time.fixedDeltaTime;

            while (true)
            {
                //Fetch input
                inputManager.WriteToPlayerInput(this);
                waitCur += Time.deltaTime;

                if (waitCur >= waitTarget)
                {
                    if (NetworkClient.ready)
                        CmdInput(input, NetworkTime.rtt * 0.75f);

                    waitCur = 0f;
                }

                PredictionInput(input);

                //Send CMD every frame to server with all inputs.
                yield return null;
            }
        }

        IEnumerator ServerRoutine()
        {
            var wait = new WaitForFixedUpdate();

            while (true)
            {
                if (isBot)
                {
                    botControls.WriteToPlayerInput(this);
                }

                if (isServer && !isLocalPlayer && input != null)
                {
                    //We are only executing in this coroutine so that if we receive more commands than expected, it doesn't matter. Execution rate will stay the same.
                    try
                    {
                        movement.AuthorativeInput(this, input, Time.fixedDeltaTime, lastRevertTime);
                        looking.AuthorativeInput(this, input, Time.fixedDeltaTime, lastRevertTime);
                        weaponManager.AuthorativeInput(this, input, Time.fixedDeltaTime, lastRevertTime);
                    }
                    catch (System.Exception e)
                    {
                        Debug.Log("Input execution exception: " + e.ToString());
                    }
                }
                yield return wait;
            }
        }

        #region Mirror Calls
        private bool localOnlyCallsDone;
        void LocalOnlyCalls()
        {
            if (!localOnlyCallsDone)
            {
                if (Kit_IngameMain.instance.currentGameModeType == 2)
                {
                    //Start Spawn Protection
                    if (spawnProtection)
                    {
                        spawnProtection.CustomStart(this);
                    }
                }
                else
                {
                    //Spawn protection not used in SP / Coop
                    spawnProtection = null;
                }

                //Setup marker
                if (nameManager)
                {
                    nameManager.StartRelay(this);
                }

                // Setup voice
                if (voiceManager)
                {
                    voiceManager.SetupOthers(this);
                }

                //Tell Minimap we spawned
                if (Kit_IngameMain.instance.minimap)
                {
                    Kit_IngameMain.instance.minimap.PlayerSpawned(this);
                }

                //Call Plugin
                for (int i = 0; i < gameInformation.plugins.Length; i++)
                {
                    gameInformation.plugins[i].PlayerSpawned(this);
                }

                if (Kit_IngameMain.instance.currentPvPGameModeBehaviour)
                {
                    //Tell Game Mode
                    Kit_IngameMain.instance.currentPvPGameModeBehaviour.OnPlayerSpawned(this);
                }
                else if (Kit_IngameMain.instance.currentPvEGameModeBehaviour)
                {
                    //Tell Game Mode
                    Kit_IngameMain.instance.currentPvEGameModeBehaviour.OnPlayerSpawned(this);
                }

                //Call event system
                Kit_Events.onPlayerSpawned.Invoke(this);

                //Spectator call. Do this last so that this player is completely setup.
                if (Kit_IngameMain.instance.spectatorManager)
                {
                    Kit_IngameMain.instance.spectatorManager.PlayerWasSpawned(this);
                }

                localOnlyCallsDone = true;
            }
        }

        public override void OnStartServer()
        {
            if (isBot)
            {
                //Fetch bot's username
                userName = Kit_IngameMain.instance.currentBotManager.GetBotWithID(id).name;
            }
            else
            {
                //Fetch player's username
                userName = Kit_NetworkPlayerManager.instance.GetPlayerById(id).name;
            }

            //Set name
            gameObject.name = userName;

            if (isBot)
            {
                //Check for game mode override
                if (Kit_IngameMain.instance.currentPvEGameModeBehaviour && Kit_IngameMain.instance.currentPvEGameModeBehaviour.botControlOverride)
                {
                    botControls = Kit_IngameMain.instance.currentPvEGameModeBehaviour.botControlOverride;
                }
                if (Kit_IngameMain.instance.currentPvPGameModeBehaviour && Kit_IngameMain.instance.currentPvPGameModeBehaviour.botControlOverride)
                {
                    botControls = Kit_IngameMain.instance.currentPvPGameModeBehaviour.botControlOverride;
                }
                input = new Kit_PlayerInput();
                Kit_BotManager manager = FindAnyObjectByType<Kit_BotManager>();
                manager.AddActiveBot(this);
                //Initialize bot input
                botControls.InitializeControls(this);
            }

            if (!thirdPersonPlayerModel) CreatePlayerModel();

            //Add us to player list
            if (!Kit_IngameMain.instance.allActivePlayers.Contains(this)) Kit_IngameMain.instance.allActivePlayers.Add(this);

            //Initialize input module
            input = new Kit_PlayerInput();
            inputManager.InitializeServer(this);
            //Initialize looking
            looking.InitializeServer(this);
            //Initialize movement
            movement.InitializeServer(this);
            //Setup Vitals
            vitalsManager.InitializeServer(this);
            //Setup weapon manager
            weaponManager.InitializeServer(this);

            LocalOnlyCalls();

            syncSetup = true;

            StartCoroutine(ServerRoutine());
        }

        public override void OnStartClient()
        {
            StartCoroutine(OnStartClientWaitForModules());
        }

        IEnumerator OnStartClientWaitForModules()
        {
            while (!Kit_IngameMain.instance) yield return null;

            //Wait for these modules to arrive before we try to setup our client. The server spawns them simultaneously(-ish) with the player, they may arrive out of order or one frame later
            while (!movementNetworkData || !vitalsNetworkData || !weaponManagerNetworkData)
            {
                if (!movementNetworkData) movementNetworkData = FindObjectsOfType<Kit_MovementNetworkBase>().Where(x => x.ownerPlayerNetworkId == netId).FirstOrDefault();
                if (!customMouseLookData) customMouseLookData = FindObjectsOfType<Kit_MouseLookNetworkBase>().Where(x => x.ownerPlayerNetworkId == netId).FirstOrDefault();
                if (!vitalsNetworkData) vitalsNetworkData = FindObjectsOfType<Kit_VitalsNetworkBase>().Where(x => x.ownerPlayerNetworkId == netId).FirstOrDefault();
                if (!weaponManagerNetworkData)
                {
                    weaponManagerNetworkData = FindObjectsOfType<Kit_WeaponManagerNetworkBase>().Where(x => x.ownerPlayerNetworkId == netId).FirstOrDefault();

                    if (weaponManagerNetworkData)
                    {
                        weaponManagerNetworkData.ownerPlayer = this;
                    }
                }

                yield return null;
            }

            if (isBot)
            {
                while (!Kit_IngameMain.instance.currentBotManager) yield return null;
                while (Kit_IngameMain.instance.currentBotManager.GetBotWithID(id) == null) yield return null;

                //Fetch bot's username
                userName = Kit_IngameMain.instance.currentBotManager.GetBotWithID(id).name;
            }
            else
            {
                //Fetch player's username
                userName = Kit_NetworkPlayerManager.instance.GetPlayerById(id).name;
            }

            //Set name
            gameObject.name = userName;

            if (!thirdPersonPlayerModel) CreatePlayerModel();

            //Add us to player list
            if (!Kit_IngameMain.instance.allActivePlayers.Contains(this)) Kit_IngameMain.instance.allActivePlayers.Add(this);

            //Initialize input module
            input = new Kit_PlayerInput();
            inputManager.InitializeClient(this);
            //Initialize looking
            looking.InitializeClient(this);
            //Movement
            movement.InitializeClient(this);
            //Setup Vitals
            vitalsManager.InitializeClient(this);
            //Setup weapon manager
            weaponManager.InitializeClient(this);

            LocalOnlyCalls();

            syncSetup = true;
        }

        public override void OnStartLocalPlayer()
        {
            StartCoroutine(LocalPlayerRoutine());

            wasLocalPlayer = true;
        }

        public override void OnStopLocalPlayer()
        {
            base.OnStopLocalPlayer();
        }
        #endregion

        #region Authorative Gameplay
        public void PredictionInput(Kit_PlayerInput input)
        {
            movement.PredictionInput(this, input, Time.deltaTime);
            looking.PredictionInput(this, input, Time.deltaTime);
            weaponManager.PredictionInput(this, input, Time.deltaTime);
        }

        private double lastRevertTime;

        [Command]
        public void CmdInput(Kit_PlayerInput input, double revertTime, NetworkConnectionToClient sender = null)
        {
            /*
            var revertTime = connectionToClient.remoteTimeline - connectionToClient.remoteTimeStamp;

            if (!isOwned)
                Debug.Log(revertTime);

            if (revertTime < 0) revertTime = 0;
            */

            this.input = input;
            lastRevertTime = revertTime;
        }
        #endregion

        #region Unity Calls
        void Start()
        {

        }

        private bool wasOnDestroyCalled;

        void OnDestroy()
        {
            wasOnDestroyCalled = true;

            if (Kit_IngameMain.executeDestroyActions)
            {
                //Clean up our additional data
                if (isServer)
                {
                    if (movementNetworkData) NetworkServer.Destroy(movementNetworkData.gameObject);
                    if (weaponManagerNetworkData) NetworkServer.Destroy(weaponManagerNetworkData.gameObject);
                    if (vitalsNetworkData) NetworkServer.Destroy(vitalsNetworkData.gameObject);
                    if (customMouseLookData) NetworkServer.Destroy(customMouseLookData.gameObject);
                    if (isBot) botControls.OnDestroyRelay(this);
                }

                //Hide HUD if we were killed
                if (isLocalPlayer)
                {
                    Kit_IngameMain.instance.hud.SetVisibility(false);
                }

                //Release marker
                if (nameManager)
                {
                    nameManager.OnDestroyRelay(this);
                }

                if (botControlsRuntimeData)
                {
                    Destroy(botControlsRuntimeData.gameObject);
                }

                if (wasLocalPlayer)
                {
                    //Tell minimap
                    if (Kit_IngameMain.instance.minimap)
                    {
                        Kit_IngameMain.instance.minimap.LocalPlayerDied(this);
                    }
                    //Tell touchscreen
                    if (Kit_IngameMain.instance.touchScreenCurrent)
                    {
                        Kit_IngameMain.instance.touchScreenCurrent.LocalPlayerDied(this);
                    }
                    //Auto spawn system callack
                    if (Kit_IngameMain.instance.autoSpawnSystem && Kit_IngameMain.instance.currentPvPGameModeBehaviour)
                    {
                        Kit_IngameMain.instance.autoSpawnSystem.LocalPlayerDied();
                    }
                    if (Kit_IngameMain.instance.currentPvPGameModeBehaviour)
                    {
                        //Tell Game Mode
                        Kit_IngameMain.instance.currentPvPGameModeBehaviour.OnLocalPlayerDestroyed(this);
                    }
                    else if (Kit_IngameMain.instance.currentPvEGameModeBehaviour)
                    {
                        //Tell Game Mode
                        Kit_IngameMain.instance.currentPvEGameModeBehaviour.OnLocalPlayerDestroyed(this);
                    }
                    //Tell HUD
                    Kit_IngameMain.instance.hud.PlayerEnd(this);
                    //Call Plugin
                    for (int i = 0; i < gameInformation.plugins.Length; i++)
                    {
                        gameInformation.plugins[i].LocalPlayerDied(this);
                    }
                }
                else
                {
                    //Tell minimap
                    if (Kit_IngameMain.instance.minimap)
                    {
                        Kit_IngameMain.instance.minimap.PlayerDied(this);
                    }
                    if (Kit_IngameMain.instance.currentPvPGameModeBehaviour)
                    {
                        //Tell Game Mode
                        Kit_IngameMain.instance.currentPvPGameModeBehaviour.OnPlayerDestroyed(this);
                    }
                    else if (Kit_IngameMain.instance.currentPvEGameModeBehaviour)
                    {
                        //Tell Game Mode
                        Kit_IngameMain.instance.currentPvEGameModeBehaviour.OnPlayerDestroyed(this);
                    }
                    //Call Plugin
                    for (int i = 0; i < gameInformation.plugins.Length; i++)
                    {
                        gameInformation.plugins[i].PlayerDied(this);
                    }
                }

                //Spectator call
                if (Kit_IngameMain.instance.spectatorManager)
                {
                    Kit_IngameMain.instance.spectatorManager.PlayerWasKilled(this);
                }

                //Make sure the camera never gets destroyed
                if (Kit_IngameMain.instance.activeCameraTransform == playerCameraTransform)
                {
                    Kit_IngameMain.instance.activeCameraTransform = Kit_IngameMain.instance.spawnCameraPosition;
                    //Set Fov
                    Kit_IngameMain.instance.mainCamera.fieldOfView = Kit_GameSettings.baseFov;
                }

                if (canControlPlayer)
                {
                    if (thirdPersonPlayerModel)
                    {
                        //Unparent sounds
                        thirdPersonPlayerModel.soundFire.transform.parent = null;
                        if (thirdPersonPlayerModel.soundFire.clip)
                        {
                            Destroy(thirdPersonPlayerModel.soundFire.gameObject, thirdPersonPlayerModel.soundFire.clip.length);
                        }
                        else
                        {
                            Destroy(thirdPersonPlayerModel.soundFire.gameObject, 1f);
                        }

                        //Setup ragdoll
                        thirdPersonPlayerModel.CreateRagdoll();
                    }
                }

                //Call event system
                Kit_Events.onPlayerDied.Invoke(this);

                //Remove us from list
                Kit_IngameMain.instance.allActivePlayers.Remove(this);
            }
        }

        void Update()
        {
            if (syncSetup && thirdPersonPlayerModel)
            {
                //Everyone update dcalls
                //Weapon manager update
                weaponManager.CustomUpdate(this, lastRevertTime);
                //looking.CalculateLookUpdate(this);
                //movement.CalculateMovementUpdate(this);
                vitalsManager.CustomUpdate(this);


                //Not controller update calls
                if (!isServer && !isLocalPlayer)
                {
                    movement.NotControllerUpdate(this);
                    looking.NotControllerUpdate(this);
                }
                else
                {

                }

                movement.CalculateFootstepsUpdate(this);

                if (isLocalPlayer)
                {
                    //Call Plugin
                    for (int i = 0; i < gameInformation.plugins.Length; i++)
                    {
                        gameInformation.plugins[i].LocalPlayerUpdate(this);
                    }

                    Kit_IngameMain.instance.hud.PlayerUpdate(this);
                }

                //Call Plugin
                for (int i = 0; i < gameInformation.plugins.Length; i++)
                {
                    gameInformation.plugins[i].PlayerUpdate(this);
                }

                if (isFirstPersonActive)
                {
                    movement.Visuals(this);
                    looking.Visuals(this);
                }

                if (isOwned || isServer)
                {
                    if (Kit_IngameMain.instance.currentPvPGameModeBehaviour)
                    {
                        //Update control value
                        canControlPlayer = Kit_IngameMain.instance.currentPvPGameModeBehaviour.CanControlPlayer();
                    }
                    else if (Kit_IngameMain.instance.currentPvEGameModeBehaviour)
                    {
                        //Update control value
                        canControlPlayer = Kit_IngameMain.instance.currentPvEGameModeBehaviour.CanControlPlayer();
                    }
                }

                if (isServer || isFirstPersonActive)
                {
                    //Update spawn protection
                    if (spawnProtection)
                    {
                        spawnProtection.CustomUpdate(this);
                    }
                }

                if (isServer)
                {
                    //Update voice scanner
                    if (voiceManager)
                    {
                        voiceManager.ScanForEnemies(this);
                    }
                }
            }
        }

        void LateUpdate()
        {
            if (syncSetup)
            {
                //Weapon manager update
                weaponManager.CustomLateUpdate(this, lastRevertTime);

                if (!isFirstPersonActive)
                {
                    if (Kit_IngameMain.instance.currentGameModeType == 2 && Kit_IngameMain.instance.currentPvPGameModeBehaviour.AreWeEnemies(isBot, id))
                    {
                        if (nameManager)
                        {
                            nameManager.UpdateEnemy(this);
                        }
                    }
                    else
                    {
                        if (nameManager)
                        {
                            nameManager.UpdateFriendly(this);
                        }
                        if (Kit_IngameMain.instance.minimap)
                        {
                            Kit_IngameMain.instance.minimap.PlayerFriendlyUpdate(this);
                        }
                    }
                }
            }

            //If we are the controller, update everything
            if (isServer || isLocalPlayer)
            {
                looking.CalculateLookLateUpdate(this);
            }
        }

        private void FixedUpdate()
        {
            if (isLocalPlayer && !isServer)
            {
                movement.CreateSnapshot(this);
            }

            if (syncSetup)
            {
                //Weapon manager update
                weaponManager.CustomFixedUpdate(this, lastRevertTime);
                movement.OnFixedUpdate(this);
            }
        }

        void OnControllerColliderHit(ControllerColliderHit hit)
        {
            //Relay to movement script
            movement.OnControllerColliderHitRelay(this, hit);
            //Relay to mouse look script
            looking.OnControllerColliderHitRelay(this, hit);
            //Relay to weapon manager
            weaponManager.OnControllerColliderHitRelay(this, hit);
        }

        void OnTriggerEnter(Collider col)
        {
            if (syncSetup)
            {
                if (isServer)
                {
                    //Check for amo
                    if (col.transform.root.GetComponent<Kit_AmmoPickup>())
                    {
                        Kit_AmmoPickup pickup = col.transform.root.GetComponent<Kit_AmmoPickup>();
                        //Relay to weapon manager
                        weaponManager.OnAmmoPickup(this, pickup);
                        //Destroy
                        pickup.PickedUp();
                    }
                    else if (col.transform.root.GetComponent<Kit_HealthPickup>())
                    {
                        Kit_HealthPickup pickup = col.transform.root.GetComponent<Kit_HealthPickup>();
                        //Relay to health
                        vitalsManager.ApplyHeal(this, pickup.healthRestored);
                        //Destroy
                        pickup.PickedUp();
                    }
                }

                //Relay to weapon manager
                weaponManager.OnTriggerEnterRelay(this, col);

                //Relay to movement
                movement.OnTriggerEnterRelay(this, col);
            }
        }

        void OnTriggerExit(Collider col)
        {
            if (syncSetup)
            {
                //Relay to weapon manager
                weaponManager.OnTriggerExitRelay(this, col);

                //Relay to movement
                movement.OnTriggerExitRelay(this, col);
            }
        }
        #endregion

        #region Custom Calls
        private void CreatePlayerModel()
        {
            if (!thirdPersonPlayerModel)
            {
                int[] playerModelCustomizations = new int[0];
                GameObject go = null;

                switch (Kit_IngameMain.instance.currentGameModeType)
                {
                    case 0:
                        //Get player model
                        PlayerModelConfig pmcSp = Kit_IngameMain.instance.currentPvEGameModeBehaviour.GetPlayerModel(this);
                        playerModelCustomizations = pmcSp.customization;

                        //Set up player model
                        //Instantiate one random player model for chosen team
                        go = Instantiate(pmcSp.information.prefab, transform, false);
                        //Assign
                        thirdPersonPlayerModel = go.GetComponent<Kit_ThirdPersonPlayerModel>();
                        //Set information
                        thirdPersonPlayerModel.information = pmcSp.information;
                        break;
                    case 1:
                        //Get player model
                        PlayerModelConfig pmcCoop = Kit_IngameMain.instance.currentPvEGameModeBehaviour.GetPlayerModel(this);
                        playerModelCustomizations = pmcCoop.customization;

                        //Set up player model
                        //Instantiate one random player model for chosen team
                        go = Instantiate(pmcCoop.information.prefab, transform, false);
                        //Assign
                        thirdPersonPlayerModel = go.GetComponent<Kit_ThirdPersonPlayerModel>();
                        //Set information
                        thirdPersonPlayerModel.information = pmcCoop.information;
                        break;
                    case 2:
                        //Set up player model
                        //Instantiate one random player model for chosen team
                        go = Instantiate(Kit_IngameMain.instance.gameInformation.allPvpTeams[myTeam].playerModels[thirdPersonPlayerModelID].prefab, transform, false);
                        //Assign
                        thirdPersonPlayerModel = go.GetComponent<Kit_ThirdPersonPlayerModel>();
                        //And cache information
                        thirdPersonPlayerModel.information = Kit_IngameMain.instance.gameInformation.allPvpTeams[myTeam].playerModels[thirdPersonPlayerModelID];
                        break;
                }

                //Reset scale
                go.transform.localScale = Vector3.one;
                //Setup
                thirdPersonPlayerModel.SetupModel(this);
                //Setup Customization
                thirdPersonPlayerModel.SetCustomizations(playerModelCustomizations, this);
                //Make it third person initially
                thirdPersonPlayerModel.ThirdPerson();

                if (thirdPersonPlayerModel.firstPersonArmsPrefab.Count == 0)
                {
                    Debug.LogWarning("WARNING: Player Model does not have ANY first person arms prefabs assigned! Game might be broken! To fix, assign first person arms prefabs to this player model with your key (Default Key: Kit)", thirdPersonPlayerModel.gameObject);
                }
            }
        }

        public void ServerDamage(float dmg, int gunID, Vector3 shotPos, Vector3 forward, float force, Vector3 hitPos, int id, bool botShot, uint idWhoShot)
        {
            //Damage is server authorative now
            if (isServer)
            {
                if (Kit_IngameMain.instance.assistManager)
                {
                    Kit_IngameMain.instance.assistManager.PlayerDamaged(botShot, idWhoShot, this, dmg);
                }

                ragdollForce = force;
                ragdollForward = forward;
                ragdollPoint = hitPos;
                ragdollId = id;
                deathSoundCategory = gameInformation.allWeapons[gunID].deathSoundCategory;
                if (voiceManager)
                {
                    deathSoundID = voiceManager.GetDeathSoundID(this, deathSoundCategory);
                }

                //Relay to the assigned manager
                vitalsManager.ApplyDamage(this, dmg, botShot, idWhoShot, gunID, shotPos);

                RpcDamageVisuals(dmg, shotPos);
            }
        }

        public void ServerDamage(float dmg, string deathCause, Vector3 shotPos, Vector3 forward, float force, Vector3 hitPos, int id, bool botShot, uint idWhoShot)
        {
            if (isServer)
            {
                if (Kit_IngameMain.instance.assistManager)
                {
                    Kit_IngameMain.instance.assistManager.PlayerDamaged(botShot, idWhoShot, this, dmg);
                }

                //Apply damage
                vitalsManager.ApplyDamage(this, dmg, botShot, idWhoShot, deathCause, shotPos);

                ragdollForce = force;
                ragdollForward = forward;
                ragdollId = id;
                ragdollPoint = hitPos;
                deathSoundCategory = gameInformation.allWeapons[0].deathSoundCategory;

                RpcDamageVisuals(dmg, shotPos);
            }
        }

        public void ServerBlind(float time, int gunID, Vector3 shotPos, bool botShot, uint idWhoShot)
        {
            if (isFirstPersonActive)
            {
                RpcBlind(time, gunID, shotPos, botShot, idWhoShot);
            }
        }

        public void ApplyFallDamage(float dmg)
        {
            if (isServer)
            {
                vitalsManager.ApplyFallDamage(this, dmg);
            }
        }

        [Command]
        public void CmdSuicide()
        {
            if (isServer)
            {
                vitalsManager.Suicide(this);
            }
        }

        /// <summary>
        /// Kill the player by cause.
        /// </summary>
        /// <param name="cause"></param>
        public void Die(int cause)
        {
            if (isServer || isLocalPlayer)
            {
                //Tell weapon manager
                weaponManager.PlayerDead(this);
            }

            if (isServer)
            {
                //Tell clients for the killfeed
                Kit_IngameMain.instance.ServerDeathInfo(isBot, id, isBot, id, cause, thirdPersonPlayerModelID, ragdollId);
                Kit_IngameMain.instance.RpcDeathInfo(isBot, id, isBot, id, cause, thirdPersonPlayerModelID, ragdollId);

                if (Kit_IngameMain.instance.assistManager)
                {
                    Kit_IngameMain.instance.assistManager.PlayerKilled(isBot, id, this);
                }

                NetworkServer.Destroy(gameObject);
            }
        }

        public void Die(bool botShot, uint killer, int gunID)
        {
            if (isServer || isLocalPlayer)
            {
                //Tell weapon manager
                weaponManager.PlayerDead(this);
            }

            if (isServer)
            {
                //Tell clients for the killfeed
                Kit_IngameMain.instance.ServerDeathInfo(botShot, killer, isBot, id, gunID, thirdPersonPlayerModelID, ragdollId);
                Kit_IngameMain.instance.RpcDeathInfo(botShot, killer, isBot, id, gunID, thirdPersonPlayerModelID, ragdollId);

                if (Kit_IngameMain.instance.assistManager)
                {
                    Kit_IngameMain.instance.assistManager.PlayerKilled(botShot, killer, this);
                }

                NetworkServer.Destroy(gameObject);
            }
        }

        public void Die(bool botShot, uint killer, string cause)
        {
            if (isServer || isLocalPlayer)
            {
                //Tell weapon manager
                weaponManager.PlayerDead(this);
            }

            if (isServer)
            {
                //Tell clients for the killfeed
                Kit_IngameMain.instance.ServerDeathInfo(botShot, killer, isBot, id, cause, thirdPersonPlayerModelID, ragdollId);
                Kit_IngameMain.instance.RpcDeathInfo(botShot, killer, isBot, id, cause, thirdPersonPlayerModelID, ragdollId);

                if (Kit_IngameMain.instance.assistManager)
                {
                    Kit_IngameMain.instance.assistManager.PlayerKilled(botShot, killer, this);
                }

                NetworkServer.Destroy(gameObject);
            }
        }
        #endregion

        #region Server Calls
        /// <summary>
        /// Server tells us that we hit something.
        /// 0 = Normal, 1 = Spawn protection
        /// Chose byte so you can add more types.
        /// </summary>
        /// <param name="type"></param>
        [TargetRpc]
        public void TargetHitMarker(byte type)
        {
            if (isFirstPersonActive)
            {
                switch (type)
                {
                    case 0:
                        Kit_IngameMain.instance.hud.DisplayHitmarker();
                        break;
                    case 1:
                        Kit_IngameMain.instance.hud.DisplayHitmarkerSpawnProtected();
                        break;
                }
            }
        }

        [ClientRpc(includeOwner = true)]
        public void ClientImpactProcess(Vector3 pos, Vector3 normal, string material)
        {
            //Relay to impact processor
            Kit_IngameMain.instance.impactProcessor.ProcessImpact(pos, normal, material);
        }
        #endregion

        #region RPCs
        [ClientRpc] //Client RPC for spectating purposes
        public void RpcBlind(float time, int gunID, Vector3 shotPos, bool botShot, uint idWhoShot)
        {
            if (isFirstPersonActive)
            {
                Kit_IngameMain.instance.hud.DisplayBlind(time);
                //Tell HUD
                Kit_IngameMain.instance.hud.DisplayShot(shotPos);
            }
        }

        [ClientRpc] //Client RPC for spectating purposes
        public void RpcDamageVisuals(float dmg, Vector3 shotPos)
        {
            if (isFirstPersonActive)
            {
                //Tell HUD
                Kit_IngameMain.instance.hud.DisplayShot(shotPos);
            }
        }

        //If we fire using a semi auto weapon, this is called

        [ClientRpc]
        public void RpcWeaponSemiFireNetwork()
        {
            //Relay to weapon manager
            weaponManager.NetworkSemiRPCReceived(this);
        }

        [ClientRpc]
        //If we fire using a bolt action weapon, this is called
        public void RpcWeaponBoltActionFireNetwork(int state)
        {
            //Relay to weapon manager
            weaponManager.NetworkBoltActionRPCReceived(this, state);
        }

        [ClientRpc]
        public void RpcWeaponBurstFireNetwork(int burstLength)
        {
            //Relay to weapon manager
            weaponManager.NetworkBurstRPCReceived(this, burstLength);
        }

        [ClientRpc]
        public void RpcWeaponFirePhysicalBulletOthers(Vector3 pos, Vector3 dir)
        {
            //Relay to weapon manager
            weaponManager.NetworkPhysicalBulletFired(this, pos, dir);
        }

        //When we reload, this is called
        [ClientRpc]
        public void RpcWeaponReloadNetwork(bool empty)
        {
            //Reload to weapon manager
            weaponManager.NetworkReloadRPCReceived(this, empty);
        }

        //When a procedural reload occurs, this will be called with the correct stage
        [ClientRpc]
        public void RpcWeaponProceduralReloadNetwork(int stage)
        {
            //Relay to weapon manager
            weaponManager.NetworkProceduralReloadRPCReceived(this, stage);
        }

        [ClientRpc]
        public void RpcMeleeStabNetwork(int state, int slot)
        {
            //Send to player model
            thirdPersonPlayerModel.PlayMeleeAnimation(0, state);
            //Weapon Manager
            weaponManager.NetworkMeleeStabRPCReceived(this, state, slot);
        }

        [ClientRpc]
        public void RpcMeleeChargeNetwork(int id, int slot)
        {
            //Send to player model
            thirdPersonPlayerModel.PlayMeleeAnimation(1, id);
            //Weapon Manager
            weaponManager.NetworkMeleeChargeRPCReceived(this, id, slot);
        }

        [ClientRpc]
        public void RpcMeleeHealNetwork(int id)
        {
            //Send to playyer model
            thirdPersonPlayerModel.PlayMeleeAnimation(2, id);
            //Weapon Manager
            weaponManager.NetworkMeleeHealRPCReceived(this, id);
        }

        [ClientRpc]
        public void RpcGrenadePullPinNetwork()
        {
            //Relay
            weaponManager.NetworkGrenadePullPinRPCReceived(this);
        }

        [ClientRpc]
        public void RpcGrenadeThrowNetwork()
        {
            //Relay
            weaponManager.NetworkGrenadeThrowRPCReceived(this);
        }

        public void WeaponRestockAll(bool allWeapons)
        {
            if (isServer)
            {
                //Relay
                weaponManager.RestockAmmo(this, allWeapons);
            }
        }


        public void ReplaceWeapon(int slot, int weapon, int bulletsLeft, int bulletsLeftToReload, int[] attachments)
        {
            if (isServer)
            {
                //Relay to weapon manager
                weaponManager.NetworkReplaceWeapon(this, slot, weapon, bulletsLeft, bulletsLeftToReload, attachments);
            }
            else
            {
                Debug.LogError("Server only function called on non-server!");
            }
        }


        [ClientRpc]
        public void RpcPlayVoiceLine(int catId, int id)
        {
            if (voiceManager)
            {
                voiceManager.PlayVoiceRpcReceived(this, catId, id);
            }
        }


        [ClientRpc]
        public void RpcPlayVoiceLine(int catId, int id, int idTwo)
        {
            if (voiceManager)
            {
                voiceManager.PlayVoiceRpcReceived(this, catId, id, idTwo);
            }
        }

        [ClientRpc]
        public void RpcMovementPlaySound(int id, int id2, int arrayID)
        {
            //Relay to movement
            movement.PlaySound(this, id, id2, arrayID);
        }

        [ClientRpc]
        public void RpcMovementPlayAnimation(int id, int id2)
        {
            //Relay to movement
            movement.PlayAnimation(this, id, id2);
        }
        #endregion

        #region Spectating
        /// <summary>
        /// Begin spectating this player
        /// </summary>
        public void OnSpectatingStart()
        {
            //Move camera to the right position
            Kit_IngameMain.instance.activeCameraTransform = playerCameraTransform;
            //Set bool
            isBeingSpectated = true;

            if (looking.GetPerspective(this) == Kit_GameInformation.Perspective.FirstPerson)
            {
                //Hide third person object
                thirdPersonPlayerModel.FirstPerson();
            }
            else
            {

            }

            if (nameManager)
            {
                nameManager.OnDestroyRelay(this);
            }

            //Call Weapon Manager
            weaponManager.BeginSpectating(this);

            //HUD
            Kit_IngameMain.instance.hud.SetVisibility(true);

            //Minimap
            if (Kit_IngameMain.instance.minimap)
            {
                Kit_IngameMain.instance.minimap.LocalPlayerSpawned(this);
            }
        }

        /// <summary>
        /// End spectating this player
        /// </summary>
        public void OnSpectatingEnd()
        {
            //Set bool
            isBeingSpectated = false;
            //Third Person
            thirdPersonPlayerModel.ThirdPerson();

            //Weapon Manager
            weaponManager.EndSpectating(this);

            if (nameManager && !wasOnDestroyCalled)
            {
                nameManager.StartRelay(this);
            }

            //HUD
            Kit_IngameMain.instance.hud.SetVisibility(false);

            //Minimap
            if (Kit_IngameMain.instance.minimap)
            {
                Kit_IngameMain.instance.minimap.LocalPlayerDied(this);
            }
        }
        #endregion
    }
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace MarsFPSKit
{
    /// <summary>
    /// Use this class to implement your own bot controls
    /// </summary>
    public abstract class Kit_PlayerBotControlBase : ScriptableObject
    {
        /// <summary>
        /// This is called for everyone when this bot is created
        /// </summary>
        /// <param name="pb"></param>
        public abstract void InitializeControls(Kit_PlayerBehaviour pb);

        /// <summary>
        /// This is the Update of the player controls. Only called on server.
        /// </summary>
        /// <param name="pb"></param>
        public abstract void WriteToPlayerInput(Kit_PlayerBehaviour pb);


        /// <summary>
        /// A relay of the OnDestroy function. Only called on server.
        /// </summary>
        /// <param name="pb"></param>
        public virtual void OnDestroyRelay(Kit_PlayerBehaviour pb) { }
    }
}

using UnityEngine;

namespace MarsFPSKit
{
    /// <summary>
    /// Use this class to implement your own bot controls
    /// </summary>
    public abstract class Kit_PlayerBotControlDataBase : MonoBehaviour
    {

    }
}

The weapon respawns when the player picks it up first time, but when he shots meanwhile and the weapon respawns he should be able to refill his ammo and the weapon should disappaer. Use the sripts above to fix everyhting and deliver the whole fixed script