private IEnumerator MoveItemFromStorageRoutine(BasePlayerCharacterEntity playerCharacterEntity, StorageId storageId, short storageItemIndex, short amount, short nonEquipIndex)
        {
            List <CharacterItem> storageItemList     = new List <CharacterItem>();
            ReadStorageItemsJob  readStorageItemsJob = new ReadStorageItemsJob(Database, storageId.storageType, storageId.storageOwnerId);

            readStorageItemsJob.Start();
            yield return(StartCoroutine(readStorageItemsJob.WaitFor()));

            if (readStorageItemsJob.result != null)
            {
                // Set storage items
                storageItemList = readStorageItemsJob.result;
            }
            if (storageItemIndex < 0 || storageItemIndex >= storageItemList.Count)
            {
                // Don't do anything, if storage item index is invalid
            }
            else
            {
                // Prepare storage data
                Storage storage     = GetStorage(storageId);
                bool    isLimitSlot = storage.slotLimit > 0;
                short   slotLimit   = storage.slotLimit;
                // Prepare item data
                CharacterItem movingItem = storageItemList[storageItemIndex].Clone();
                movingItem.amount = amount;
                if (nonEquipIndex < 0 ||
                    nonEquipIndex >= playerCharacterEntity.NonEquipItems.Count ||
                    !playerCharacterEntity.NonEquipItems[nonEquipIndex].NotEmptySlot() ||
                    playerCharacterEntity.NonEquipItems[nonEquipIndex].dataId == movingItem.dataId)
                {
                    // Add to inventory or merge
                    bool isOverwhelming = playerCharacterEntity.IncreasingItemsWillOverwhelming(movingItem.dataId, movingItem.amount);
                    if (!isOverwhelming && playerCharacterEntity.IncreaseItems(movingItem))
                    {
                        // Remove from storage
                        CharacterDataExtension.DecreaseItemsByIndex(storageItemList, storageItemIndex, amount);
                    }
                }
                else
                {
                    // Swapping
                    CharacterItem storageItem  = storageItemList[storageItemIndex];
                    CharacterItem nonEquipItem = playerCharacterEntity.NonEquipItems[nonEquipIndex];

                    storageItemList[storageItemIndex] = nonEquipItem;
                    playerCharacterEntity.NonEquipItems[nonEquipIndex] = storageItem;
                }
                CharacterDataExtension.FillEmptySlots(storageItemList, isLimitSlot, slotLimit);
            }
            // Update storage list immediately
            // TODO: Have to test about race condition while running multiple-server
            UpdateStorageItemsJob updateStorageItemsJob = new UpdateStorageItemsJob(Database, storageId.storageType, storageId.storageOwnerId, storageItemList);

            updateStorageItemsJob.Start();
            yield return(StartCoroutine(updateStorageItemsJob.WaitFor()));

            // Update storage items to characters that open the storage
            UpdateStorageItemsToCharacters(usingStorageCharacters[storageId], storageItemList);
        }
        public override void OpenStorage(BasePlayerCharacterEntity playerCharacterEntity)
        {
            if (!CanAccessStorage(playerCharacterEntity, playerCharacterEntity.CurrentStorageId))
            {
                SendServerGameMessage(playerCharacterEntity.ConnectionId, GameMessage.Type.CannotAccessStorage);
                return;
            }
            if (!storageItems.ContainsKey(playerCharacterEntity.CurrentStorageId))
            {
                storageItems[playerCharacterEntity.CurrentStorageId] = new List <CharacterItem>();
            }
            if (!usingStorageCharacters.ContainsKey(playerCharacterEntity.CurrentStorageId))
            {
                usingStorageCharacters[playerCharacterEntity.CurrentStorageId] = new HashSet <uint>();
            }
            usingStorageCharacters[playerCharacterEntity.CurrentStorageId].Add(playerCharacterEntity.ObjectId);
            // Prepare storage data
            Storage storage     = GetStorage(playerCharacterEntity.CurrentStorageId);
            bool    isLimitSlot = storage.slotLimit > 0;
            short   slotLimit   = storage.slotLimit;

            CharacterDataExtension.FillEmptySlots(storageItems[playerCharacterEntity.CurrentStorageId], isLimitSlot, slotLimit);
            // Update storage items
            playerCharacterEntity.StorageItems = storageItems[playerCharacterEntity.CurrentStorageId];
        }
        public override void MoveItemToStorage(BasePlayerCharacterEntity playerCharacterEntity, StorageId storageId, short nonEquipIndex, short amount, short storageItemIndex)
        {
            if (!CanAccessStorage(playerCharacterEntity, playerCharacterEntity.CurrentStorageId))
            {
                SendServerGameMessage(playerCharacterEntity.ConnectionId, GameMessage.Type.CannotAccessStorage);
                return;
            }
            if (!storageItems.ContainsKey(storageId))
            {
                storageItems[storageId] = new List <CharacterItem>();
            }
            List <CharacterItem> storageItemList = storageItems[storageId];

            if (nonEquipIndex < 0 || nonEquipIndex >= playerCharacterEntity.NonEquipItems.Count)
            {
                // Don't do anything, if non equip item index is invalid
                return;
            }
            // Prepare storage data
            Storage storage       = GetStorage(storageId);
            bool    isLimitWeight = storage.weightLimit > 0;
            bool    isLimitSlot   = storage.slotLimit > 0;
            short   weightLimit   = storage.weightLimit;
            short   slotLimit     = storage.slotLimit;
            // Prepare item data
            CharacterItem movingItem = playerCharacterEntity.NonEquipItems[nonEquipIndex].Clone();

            movingItem.amount = amount;
            if (storageItemIndex < 0 ||
                storageItemIndex >= storageItemList.Count ||
                !storageItemList[storageItemIndex].NotEmptySlot() ||
                storageItemList[storageItemIndex].dataId == movingItem.dataId)
            {
                // Add to storage or merge
                bool isOverwhelming = CharacterDataExtension.IncreasingItemsWillOverwhelming(
                    storageItemList, movingItem.dataId, movingItem.amount, isLimitWeight, weightLimit,
                    CharacterDataExtension.GetTotalItemWeight(storageItemList), isLimitSlot, slotLimit);
                if (!isOverwhelming && CharacterDataExtension.IncreaseItems(storageItemList, movingItem))
                {
                    // Decrease from inventory
                    playerCharacterEntity.DecreaseItemsByIndex(nonEquipIndex, amount);
                }
            }
            else
            {
                // Swapping
                CharacterItem storageItem  = storageItemList[storageItemIndex];
                CharacterItem nonEquipItem = playerCharacterEntity.NonEquipItems[nonEquipIndex];

                storageItemList[storageItemIndex] = nonEquipItem;
                playerCharacterEntity.NonEquipItems[nonEquipIndex] = storageItem;
            }
            CharacterDataExtension.FillEmptySlots(storageItemList, isLimitSlot, slotLimit);
            UpdateStorageItemsToCharacters(usingStorageCharacters[storageId], storageItemList);
        }
        public override float GetTotalWeight(ICharacterData character)
        {
            float result = CharacterDataExtension.GetTotalItemWeight(character.EquipItems) +
                           CharacterDataExtension.GetTotalItemWeight(character.NonEquipItems);

            // Weight from right hand equipment
            if (character.EquipWeapons.rightHand.NotEmptySlot())
            {
                result += character.EquipWeapons.rightHand.GetItem().weight;
            }
            // Weight from left hand equipment
            if (character.EquipWeapons.leftHand.NotEmptySlot())
            {
                result += character.EquipWeapons.leftHand.GetItem().weight;
            }
            return(result);
        }
        private IEnumerator OpenStorageRoutine(BasePlayerCharacterEntity playerCharacterEntity)
        {
            List <CharacterItem> result          = new List <CharacterItem>();
            ReadStorageItemsJob  storageItemsJob = new ReadStorageItemsJob(Database, playerCharacterEntity.CurrentStorageId.storageType, playerCharacterEntity.CurrentStorageId.storageOwnerId);

            storageItemsJob.Start();
            yield return(StartCoroutine(storageItemsJob.WaitFor()));

            if (storageItemsJob.result != null)
            {
                // Set storage items
                result = storageItemsJob.result;
            }
            // Prepare storage data
            Storage storage     = GetStorage(playerCharacterEntity.CurrentStorageId);
            bool    isLimitSlot = storage.slotLimit > 0;
            short   slotLimit   = storage.slotLimit;

            CharacterDataExtension.FillEmptySlots(result, isLimitSlot, slotLimit);
            // Update storage items
            playerCharacterEntity.StorageItems = result;
        }