fix the script. The weapon respawns only once, and it changes the players weapon, but when the time in the inspector passes and it respawns again, the player should be able to walk through the weapon and refill the ammo of this weapon ID and than the weapon prefab should get destroyed again and than respawn again after given time in the inspector. This should work continously the same way.

Here are the scripts for you to check. Deliver the full fixed working scripts, ready to copy and paste. Do not remove prior code and comments,  just input the fix.
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");
            }
            catch (System.Exception e)
            {
                Debug.LogError("[Kit_WeaponPickupRespawnManager] Failed to spawn pickup: " + e);
                Destroy(newPickup);
            }
        }

        isRespawning = false;
    }
}
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>();
        col.isTrigger = true;

        if (!TryGetComponent(out NetworkIdentity _))
            Debug.LogError("Kit_WeaponPickup requires a NetworkIdentity.");

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

    [ServerCallback]
    void OnTriggerEnter(Collider other)
    {
        var player = other.GetComponentInParent<Kit_PlayerBehaviour>();
        if (player == null) 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 or wrong type.");
            return;
        }

        LogPlayerWeapons(player, runtimeData);

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

        if (consumed)
        {
            Debug.Log($"[Kit_WeaponPickup] Pickup consumed by player {player.name}: scheduling respawn and destroying pickup");
            Kit_WeaponPickupRespawnManager.Instance.ScheduleRespawn(weaponPickupPrefab, spawnPosition, spawnRotation, respawnDelay);
            NetworkServer.Destroy(gameObject);
        }
        else
        {
            Debug.Log($"[Kit_WeaponPickup] Pickup NOT consumed by player {player.name}: no ammo refill or weapon add");
        }
    }

    private void LogPlayerWeapons(Kit_PlayerBehaviour player, Kit_ModernWeaponManagerNetworkData runtimeData)
    {
        Debug.Log($"[Kit_WeaponPickup] Player {player.name} weapons:");
        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");
            }
        }
    }

    [Server]
    bool TryGiveOrRefillWeapon(Kit_PlayerBehaviour player, Kit_ModernWeaponManagerNetworkData runtimeData,
        Kit_ModernWeaponManager weaponManager)
    {
        if (weaponID < 0 || weaponID >= Kit_IngameMain.instance.gameInformation.allWeapons.Length)
        {
            Debug.LogWarning("[Kit_WeaponPickup] Invalid weaponID.");
            return false;
        }

        int slot = weaponManager.HasWeapon(player, weaponID);

        if (slot >= 0)
        {
            // Player has the weapon; refill ammo
            var wrData = runtimeData.weaponsInUseDataObjects[slot] as Kit_ModernWeaponScriptRuntimeData;
            if (wrData == null)
            {
                Debug.LogWarning($"[Kit_WeaponPickup] Runtime weapon data null or wrong type for slot {slot}");
                return false;
            }

            bool didRefill = false;

            if (wrData.bulletsLeft < bulletsLeft)
            {
                int old = wrData.bulletsLeft;
                wrData.bulletsLeft = bulletsLeft;
                Debug.Log($"[Kit_WeaponPickup] Refilled bulletsLeft: {old} → {bulletsLeft} for player {player.name} slot {slot}");
                didRefill = true;
            }

            if (wrData.bulletsLeftToReload < bulletsLeftToReload)
            {
                int old = wrData.bulletsLeftToReload;
                wrData.bulletsLeftToReload = bulletsLeftToReload;
                Debug.Log($"[Kit_WeaponPickup] Refilled bulletsLeftToReload: {old} → {bulletsLeftToReload} for player {player.name} slot {slot}");
                didRefill = true;
            }

            // Switch to the refilled weapon if not current (optional)
            if (runtimeData.currentWeapon != slot)
            {
                runtimeData.currentWeapon = slot;
                Debug.Log($"[Kit_WeaponPickup] Switched current weapon to slot {slot} for player {player.name}");
            }

            return didRefill;
        }
        else
        {
            var emptySlots = weaponManager.GetSlotsWithEmptyWeapon(player);

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

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

            Debug.Log($"[Kit_WeaponPickup] Gave weapon {weaponID} to player {player.name} in slot {targetSlot}");

            return true;
        }
    }
}
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 Mirror;
using UnityEngine;

namespace MarsFPSKit
{
    /// <summary>
    /// Upon entering, this will be picked up
    /// </summary>
    public class Kit_AmmoPickup : NetworkBehaviour
    {
        /// <summary>
        /// How many clips will be picked up
        /// </summary>
        public int amountOfClipsToPickup = 2;
        /// <summary>
        /// Rigidbody
        /// </summary>
        public Rigidbody body;
        /// <summary>
        /// Root object of renderer to hide before destroyed
        /// </summary>
        public GameObject renderRoot;
        
        public void PickedUp()
        {
            if (isServer)
            {
                NetworkServer.Destroy(gameObject);
            }
        }
    }
}
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
        }
    }
}