Rooster Fight is in development.

Today’s development focused on refining the inventory system. We have successfully implemented the ability to pick up, hold, and drop items seamlessly. This brings us one step closer to a fully functional and dynamic inventory experience.

With these new mechanics in place, players can now interact with pickups, store them in their inventory, and drop them at will. The system ensures smooth transitions between these states, making item management more intuitive and responsive.

Looking ahead, we will continue to optimize item interactions, improve UI feedback, and refine network synchronization to enhance the overall gameplay experience.

Here the full Class

PlayerInventory.cs

using Cockfite.Enums;
using Cockfite.Interfaces;
using Cockfite.Management;
using Cockfite.Weapons;
using Fusion;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using Cockfite.Player.AvatarManagement;
using System.Collections;
using Cockfite.Interactions;
namespace Cockfite.Player.Inventory
{
    public class PlayerInventory : NetworkBehaviour
    {
        #region Fields & Properties #########################################################################
        // private
        private IEngine m_engine => Engine.Instance;
        [SerializeField] private Weapon[] m_weaponPrefabs;
        [SerializeField] private GameObject[] m_dummyPrefabs;
        [SerializeField] private NetworkObject m_dummyInventoryItem;
        [Networked, Capacity(5)] private NetworkArray<NetworkObject> m_itemSlots {get;}
        private sbyte m_localActiveSlot = 0;
        private bool m_isSlotSwitchInProg = false;
        private Dictionary<int, GameObject> tempDummys = new Dictionary<int, GameObject>();
        // protected
        [Networked] protected sbyte m_activeSlot { get; set; } = -1;
        // properties
        public NetworkArray<NetworkObject> ItemSlots => m_itemSlots;
        public sbyte ActiveSlot { get => m_activeSlot; set => m_activeSlot = value; }
        public sbyte LocalActiveSlot 
        {
            get => m_localActiveSlot; set
            {
                RPC_ChangeActiveInventorySlot(value);
            } 
        }
        #endregion
        #region NetworkBehaviours ###########################################################################
        public override void Spawned()
        {
            if (!HasStateAuthority)
                return;
            m_activeSlot = 0;
            m_itemSlots.Set(0, m_dummyInventoryItem.GetComponent<NetworkObject>());
            m_itemSlots.Set(1, m_dummyInventoryItem.GetComponent<NetworkObject>());
            m_itemSlots.Set(2, m_dummyInventoryItem.GetComponent<NetworkObject>());
            m_itemSlots.Set(3, m_dummyInventoryItem.GetComponent<NetworkObject>());
            m_itemSlots.Set(4, m_dummyInventoryItem.GetComponent<NetworkObject>());
        }
        public override void FixedUpdateNetwork()
        {
            if (!HasStateAuthority)
                return;
            foreach (var item in m_itemSlots)
            {
                if(item != null)
                {
                    var iitem = item.GetComponent<IInventoryItem>();
                    if(iitem.InventoyItemType == InventoyItemType.Weapon)
                    {
                        if (iitem.InventoryItemSlot == m_activeSlot && !iitem.IsArmed)
                            iitem.ArmItem();
                        else if(iitem.InventoryItemSlot != m_activeSlot && iitem.IsArmed)
                            iitem.UnarmItem();
                    }
                }
            }
            m_activeSlot = m_localActiveSlot;
        }
        #endregion
        #region Private Methodes ######################################################################
        [Rpc(sources: RpcSources.All, targets: RpcTargets.All, Channel = RpcChannel.Reliable)]
        private void RPC_ChangeActiveInventorySlot(sbyte _slot)
        {
            m_localActiveSlot = _slot;
        }
        [Rpc(RpcSources.InputAuthority, RpcTargets.StateAuthority, Channel = RpcChannel.Reliable)]
        private void RPC_DropItemsInSlot(sbyte _slotIndex, int localDummyId)
        {
            if (!HasStateAuthority)
                return;
            NetworkObject item = m_itemSlots[_slotIndex];
            m_itemSlots.Set(_slotIndex, m_dummyInventoryItem);
            IInventoryItem iitem = item.GetComponent<IInventoryItem>();
            iitem.Uninitalize();
            Vector3 spawnpos = GetDropPosition(iitem.DropOffsetSettings);
            NetworkObject staticPickup = Runner.Spawn(iitem.PickupPrefab, spawnpos, Quaternion.Euler(Vector3.zero), PlayerRef.None, BeforePickupSpawned);
            void BeforePickupSpawned(NetworkRunner runner, NetworkObject obj)
            {
                obj.GetComponent<IInventoryItem>().DropPickup(iitem.CurrentAmmo);
            }
            RPC_MergeDummyWithRealItem(item.InputAuthority, localDummyId);
            /*StartCoroutine(WaitForSpawned(staticPickup, item.InputAuthority));                     now i thing it works without this delay
            IEnumerator WaitForSpawned(NetworkObject _staticPickup, PlayerRef _pref)
            {
                while (_staticPickup == null || !_staticPickup.IsValid)
                {
                    yield return null;
                }
                yield return new WaitForSeconds(.3f);
                RPC_MergeDummyWithRealItem(_pref, localDummyId);
            }*/
            Runner.Despawn(item);
        }
        [Rpc(RpcSources.StateAuthority, RpcTargets.All, Channel = RpcChannel.Reliable)]
        private void RPC_MergeDummyWithRealItem([RpcTarget] PlayerRef player, int localDummyId)
        {
            GameObject localDummyDrop = FindObjectByInstanceID(localDummyId);
            if (localDummyDrop != null)
            {
                Destroy(localDummyDrop);
            }
        }
        [Rpc(RpcSources.All, RpcTargets.StateAuthority, Channel = RpcChannel.Reliable)]
        private void RPC_SwitchInventorySlot(sbyte _slotA, sbyte _slotB)
        {
            m_isSlotSwitchInProg = true;
            IInventoryItem itemA = m_itemSlots[_slotA]?.GetComponent<IInventoryItem>();
            IInventoryItem itemB = m_itemSlots[_slotB]?.GetComponent<IInventoryItem>();
            if (itemA != null && itemB != null)
            {
                itemA.InventoryItemSlot = _slotB;
                itemB.InventoryItemSlot = _slotA;
            }
            // switch places in list
            var temp = m_itemSlots.Get(_slotA);
            m_itemSlots.Set(_slotA, m_itemSlots.Get(_slotB));
            m_itemSlots.Set(_slotB, temp);
            UpdateSlot(_slotA, m_itemSlots.Get(_slotA));
            UpdateSlot(_slotB, m_itemSlots.Get(_slotB));
            m_activeSlot = _slotB;
            m_localActiveSlot = _slotB;
            m_isSlotSwitchInProg = false;
        }
        private Vector3 GetDropPosition(DropOffsetSettings settings)
        {
            // Compute drop direction relative to the player's current rotation
            Vector3 dropDirection = transform.rotation * Quaternion.Euler(0, settings.DropOffsetAngle, 0) * -Vector3.forward;
            // Calculate final drop position
            Vector3 spawnPosition = transform.position + dropDirection * settings.DropOffsetRadius;
            spawnPosition.y += settings.DropOffsetHeight; // Adjust height
            return spawnPosition;
        }
        private GameObject FindObjectByInstanceID(int instanceId)
        {
            if (tempDummys.TryGetValue(instanceId, out GameObject obj))
            {
                tempDummys.Remove(instanceId);
                return obj;
            }
            return null;
        }
        // Updates the corresponding Networked slot based on index
        private void UpdateSlot(int index, NetworkObject item)
        {
            if (index < m_itemSlots.Length)
            {
                m_itemSlots.Set(index, item);
            }
        }
        #endregion
        #region Public Methodes #####################################################################
        public void SwitchInventorySlot(sbyte _slotA, sbyte _slotB)
        {
            RPC_SwitchInventorySlot(_slotA, _slotB);
        }
        // this method is called only on host.
        public bool AddItemToInventory(IInventoryItem _inventoryItem)
        {
            short rest = -1;
            bool hasAmmoAdded = false;
            for (int i = 0; i < m_itemSlots.Length; i++)
            {
                var iitem = m_itemSlots[i].GetComponent<IInventoryItem>();
                if (iitem.ItemId.Equals(_inventoryItem.ItemId)) // we have already a item of this type
                {
                    switch (iitem.InventoyItemType)
                    {
                        case InventoyItemType.Free:
                            break;
                        case InventoyItemType.Weapon:
                            IInventoryItem inventoryItem = iitem;
                            var item = Runner.FindObject(inventoryItem.ItemNetworkId); //inventoryItem as NetworkBehaviour;
                            if (item.gameObject.GetComponent<Weapon>().AddAmmo(_inventoryItem.CurrentAmmo, out short _rest))
                            {
                                hasAmmoAdded = true;
                                rest = _rest;
                                if (_rest == 0)
                                    return true;
                                else
                                    break;
                            }
                            else 
                            {
                                if(_rest > 0)
                                rest = _rest;
                                break;
                            }
                        case InventoyItemType.FirearmWeapon:
                            break;
                        case InventoyItemType.Shield:
                            break;
                        case InventoyItemType.Ammo:
                            break;
                        default:
                            break;
                    }
                }
            }
            
            // If no matching item exists, search for an empty slot
            for (int i = 0; i < m_itemSlots.Length; i++)
            {
                var iitem = m_itemSlots[i].GetComponent<IInventoryItem>();
                if (string.IsNullOrEmpty(iitem.ItemId.ToString())) // we have a free slot
                {
                    switch (_inventoryItem.InventoyItemType)
                    {
                        case InventoyItemType.Free:
                            break;
                        case InventoyItemType.Weapon:
                            var spawn = m_weaponPrefabs.First(w => w.ItemId.Equals(_inventoryItem.ItemId));
                            var weapon = Runner.Spawn(spawn, null, null, GetComponent<CF_Avatar>().PlayerRef, (_rnr, _no) =>
                            {
                                _no.gameObject.GetComponent<IInventoryItem>()
                                    .Initalize(GetComponent<CF_Avatar>().GetSpawnPointTransform(_inventoryItem.SpawnTransform),
                                (sbyte)i,
                                GetComponent<CF_Avatar>().PlayerRef,
                                (rest == -1 && !hasAmmoAdded) ? _inventoryItem.CurrentAmmo : rest); 
                            });
                            UpdateSlot(i, m_itemSlots.Set(i, weapon.GetComponent<NetworkObject>()));
                            break;
                        case InventoyItemType.FirearmWeapon:
                            break;
                        case InventoyItemType.Shield:
                            break;
                        case InventoyItemType.Ammo:
                            break;
                        default:
                            break;
                    }
                    return true;
                }
            }
            // if ammo has addet return true and remove the weapon
            if(hasAmmoAdded)
                return true;
            // we can eather take ammo nor the weapon
            return false;
        }
        public void DropItemsInSlot(sbyte _slotIndex)
        {
            NetworkObject item = m_itemSlots[_slotIndex];
            var iitem = item.GetComponent<IInventoryItem>();
            Vector3 spawnpos = GetDropPosition(iitem.DropOffsetSettings);
            GameObject localDummyDrop = Instantiate(
                iitem.PickupPrefabDummy,
                spawnpos,
                Quaternion.identity
            );
            tempDummys.Add(localDummyDrop.GetInstanceID(), localDummyDrop);
            iitem.UninitalizeLocal();
            m_engine.GUI_Inventory.InventorySlots[_slotIndex].ItemIcon.sprite = m_dummyInventoryItem.GetComponent<IInventoryItem>().InventoryIcon;
            m_engine.GUI_Inventory.InventorySlots[_slotIndex].ItemCount.text = "0";
            RPC_DropItemsInSlot(_slotIndex, localDummyDrop.GetInstanceID());
        }
        #endregion
    }
}

Schreibe einen Kommentar