private void Craft()
        {
            ItemCollection craftCollection = m_Collections[m_CraftingCollectionIndex];
            ItemBlueprint  blueprint       = ItemDatabase.GetBlueprint(craftCollection.ToArray());

            if (blueprint == null)
            {
                return;
            }

            ItemCollection defaultCollection = m_Collections[m_DefaultCollectionIndex];

            if (defaultCollection.IsFull(blueprint.Output))
            {
                return;
            }
            if (!defaultCollection.IsAllowed(blueprint.Output))
            {
                return;
            }

            craftCollection.Clear(true);

            GameObject    obj  = NetworkController.Instance.Scene.CreateForClient(Identity.OwnerConnection, blueprint.Output.gameObject, Vector3.zero, Quaternion.identity);
            InventoryItem item = obj.GetComponent <InventoryItem>();

            Add(item, defaultCollection);

            NetworkController.Instance.RemoteProcedures.Call(Identity, RPCType.Target, nameof(ClientRpcClearCollection), Identity.OwnerConnection, GetCollectionIndex(craftCollection));
        }
        private void Move(InventoryItem fromItem, int fromSlot, ItemCollection fromCollection, int toSlot, ItemCollection toCollection)
        {
            if (!toCollection.IsAllowed(fromItem, toSlot))
            {
                return;
            }

            if (toCollection != fromCollection && toCollection.IsReferenceCollection && toCollection.Contains(fromItem))
            {
                return;
            }

            InventoryItem toItem = toCollection[toSlot];

            if (toItem != null)
            {
                // From and to reference collections cannot be combined or swapped only replaced and destroyed..
                if (!fromCollection.IsReferenceCollection && !toCollection.IsReferenceCollection)
                {
                    if (toCollection.CanStackInCollection && toItem.ItemID == fromItem.ItemID && toItem.Stack < toItem.MaxStack)
                    {
                        Combine(fromItem, toItem, fromCollection, toCollection);
                        return;
                    }

                    Swap(fromItem, fromCollection, fromSlot, toItem, toCollection, toSlot);
                    return;
                }
            }

            if (!toCollection.IsReferenceCollection && !toCollection.CanStackInCollection && fromItem.Stack > 1)
            {
                fromItem.Stack--;
                NotifyStackChanged(fromItem, fromCollection);

                GameObject inst = NetworkController.Instance.Scene.CreateForClient(
                    Identity.OwnerConnection,
                    m_ItemDatabase.GetItem(fromItem.ItemID).gameObject,
                    Vector3.zero, Quaternion.identity
                    );

                NetworkIdentity identity = inst.GetComponent <NetworkIdentity>();
                NetworkController.Instance.RemoteProcedures.Call(Identity, RPCType.All, nameof(SharedRpcClientClaim), identity.InstanceID);
                SharedRpcClientClaim(identity.InstanceID);
                toItem = identity.GetComponent <InventoryItem>();
                toCollection[toSlot] = toItem;

                ItemMoved?.Invoke(fromCollection, toCollection, fromSlot, toSlot, toItem);
                ItemAdded?.Invoke(toCollection, toItem, toSlot);

                NetworkController.Instance.RemoteProcedures.Call(
                    Identity,
                    RPCType.Target,
                    nameof(ClientRpcMoveItem),
                    Identity.OwnerConnection,
                    toItem.InstanceID,
                    GetCollectionIndex(toCollection), GetCollectionIndex(toCollection),
                    toSlot, toSlot);
                return;
            }

            // You can't move an item out of a reference collection...
            if (fromCollection.IsReferenceCollection && fromCollection != toCollection)
            {
                return;
            }

            bool contains = toCollection.Contains(fromItem);

            // Do not clear the item if it's a reference collection we're dragging to.
            if (fromCollection == toCollection || !toCollection.IsReferenceCollection)
            {
                fromCollection[fromSlot] = null;
            }

            toCollection[toSlot] = fromItem;
            if (!contains)
            {
                ItemAdded?.Invoke(toCollection, fromItem, toSlot);
            }
            else
            {
                ItemMoved?.Invoke(fromCollection, toCollection, fromSlot, toSlot, fromItem);
            }

            // Only need to invoke removal if the item becomes null.
            if (fromCollection[fromSlot] == null && fromCollection != toCollection)
            {
                ItemRemoved?.Invoke(fromCollection, fromItem, fromSlot);
            }

            NetworkController.Instance.RemoteProcedures.Call(
                Identity,
                RPCType.Target,
                nameof(ClientRpcMoveItem),
                Identity.OwnerConnection,
                fromItem.InstanceID,
                GetCollectionIndex(fromCollection),
                GetCollectionIndex(toCollection),
                fromSlot,
                toSlot);
        }
        private void Add(InventoryItem item, ItemCollection collection)
        {
            if (item.Stack <= 0)
            {
                return;
            }

            if (!collection.IsAllowed(item))
            {
                return;
            }

            if (collection.IsFull(item))
            {
                return;
            }

            InventoryItem[] foundItems    = Array.FindAll(collection.ToArray(), x => x != null && x.ItemID == item.ItemID && x.Stack < x.MaxStack);
            bool            amountChanged = false;

            if (foundItems.Length > 0)
            {
                for (int i = 0; i < foundItems.Length; i++)
                {
                    InventoryItem foundItem = foundItems[i];
                    int           count     = foundItem.MaxStack - foundItem.Stack;

                    for (int j = 0; j < count; j++)
                    {
                        foundItem.Stack++;
                        item.Stack--;
                        amountChanged = true;

                        if (item.Stack == 0)
                        {
                            NetworkController.Instance.Scene.Destroy(item.gameObject);
                            NotifyStackChanged(foundItem, collection);
                            return;
                        }
                    }

                    if (amountChanged)
                    {
                        NotifyStackChanged(foundItem, collection);
                    }
                }
            }

            if (amountChanged)
            {
                NotifyStackChanged(item, collection);
            }

            int slot = collection.FirstEmptySlot(item.Category);

            if (slot == -1)
            {
                return;
            }

            collection[slot] = item;
            NetworkController.Instance.Scene.RegisterObjectAuthority(Identity.OwnerConnection, item.Identity);
            ItemAdded?.Invoke(collection, item, slot);

            int collectionIndex = GetCollectionIndex(collection);

            NetworkController.Instance.RemoteProcedures.Call(Identity, RPCType.Target, nameof(ClientRpcMoveItem), Identity.OwnerConnection, item.InstanceID, collectionIndex, collectionIndex, slot, slot);
            NetworkController.Instance.RemoteProcedures.Call(Identity, RPCType.All, nameof(SharedRpcClientClaim), item.InstanceID);
            SharedRpcClientClaim(item.InstanceID);
        }