コード例 #1
0
        public void Start(PurchasesQueryArgs queryArgs)
        {
            SetQueryArgs(queryArgs);
            m_IsInProgress = true;
            m_Timestamp    = DateTime.Now.Ticks;

            if (!m_UnityConnect.isUserLoggedIn)
            {
                OnOperationError(new UIError(UIErrorCode.AssetStoreOperationError, k_UserNotLoggedInErrorMessage));
                return;
            }

            m_Result = new AssetStorePurchases(m_OriginalQueryArgs);
            if ((m_DownloadedAssetsOnly || m_UpdateAvailableOnly) && !m_AdjustedQueryArgs.productIds.Any())
            {
                m_Result.total = 0;
                onOperationSuccess?.Invoke(this);
                FinalizedOperation();
                return;
            }

            // We need to keep a local version of the current timestamp to make sure the callback timestamp is still the original one.
            var localTimestamp = m_Timestamp;

            m_AssetStoreRestAPI.GetPurchases(QueryToString(m_AdjustedQueryArgs), (result) => GetPurchasesCallback(result, localTimestamp), OnOperationError);
        }
コード例 #2
0
        public static string QueryToString(PurchasesQueryArgs queryArgs)
        {
            var stringBuilder = new StringBuilder($"?offset={queryArgs.startIndex}&limit={queryArgs.limit}", 512);
            var status        = queryArgs.status;

            if (!string.IsNullOrEmpty(status))
            {
                stringBuilder.Append($"&status={status}");
            }

            if (!string.IsNullOrEmpty(queryArgs.searchText))
            {
                stringBuilder.Append($"&query={Uri.EscapeDataString(queryArgs.searchText)}");
            }
            if (!string.IsNullOrEmpty(queryArgs.orderBy))
            {
                stringBuilder.Append($"&orderBy={queryArgs.orderBy}");
                stringBuilder.Append(queryArgs.isReverseOrder ? "&order=desc" : "&order=asc");
            }
            if (queryArgs.labels?.Any() ?? false)
            {
                stringBuilder.Append($"&tagging={string.Join(",", queryArgs.labels.Select(label => Uri.EscapeDataString(label)).ToArray())}");
            }
            if (queryArgs.categories?.Any() ?? false)
            {
                stringBuilder.Append($"&categories={string.Join(",", queryArgs.categories.Select(cat => Uri.EscapeDataString(cat)).ToArray())}");
            }
            if (queryArgs.productIds?.Any() ?? false)
            {
                stringBuilder.Append($"&ids={string.Join(",", queryArgs.productIds.ToArray())}");
            }
            return(stringBuilder.ToString());
        }
コード例 #3
0
        private void StartFetchOperation(long productId, bool hidden = false)
        {
            // when the purchase info is not available for a package (either it's not fetched yet or just not available altogether)
            // we'll try to fetch the purchase info first and then call the `FetchInternal`.
            // In the case where a package not purchased, `purchaseInfo` will still be null,
            // but the generated `AssetStorePackage` in the end will contain an error.
            var fetchOperation = new AssetStoreListOperation(m_UnityConnect, m_AssetStoreRestAPI, m_AssetStoreCache);
            var queryArgs      = new PurchasesQueryArgs {
                productIds = new List <string> {
                    productId.ToString()
                }, status = hidden? "hidden" : string.Empty
            };

            fetchOperation.onOperationSuccess += op =>
            {
                var purchaseInfo = fetchOperation.result.list.FirstOrDefault();
                // If we can't find the purchase info the first time, it could be be that the asset is hidden
                // we'll do another check
                if (!hidden && purchaseInfo == null)
                {
                    StartFetchOperation(productId, true);
                    return;
                }

                if (purchaseInfo != null)
                {
                    m_AssetStoreCache.SetPurchaseInfo(purchaseInfo);
                }
                FetchInternal(productId, purchaseInfo);
            };
            fetchOperation.Start(queryArgs);
        }
コード例 #4
0
        public virtual void ListPurchases(PurchasesQueryArgs queryArgs)
        {
            CancelListPurchases();

            RefreshLocalInfos();

            m_ListOperation = m_ListOperation ?? new AssetStoreListOperation(m_UnityConnect, m_AssetStoreRestAPI, m_AssetStoreCache);
            m_ListOperation.onOperationSuccess += op =>
            {
                var result = m_ListOperation.result;
                if (result.list.Count > 0)
                {
                    var updatedPackages = new List <IPackage>();
                    foreach (var purchaseInfo in result.list)
                    {
                        var productIdString = purchaseInfo.productId.ToString();
                        var oldPurchaseInfo = m_AssetStoreCache.GetPurchaseInfo(productIdString);
                        m_AssetStoreCache.SetPurchaseInfo(purchaseInfo);

                        // create a placeholder before fetching data from the cloud for the first time
                        var productInfo = m_AssetStoreCache.GetProductInfo(productIdString);
                        if (productInfo == null)
                        {
                            updatedPackages.Add(new PlaceholderPackage(productIdString, purchaseInfo.displayName, PackageType.AssetStore, PackageTag.Downloadable, PackageProgress.Refreshing));
                        }
                        else if (oldPurchaseInfo != null)
                        {
                            // for now, `tags` is the only component in `purchase info` that can be updated over time, so we only check for changes there
                            var oldTags = oldPurchaseInfo.tags ?? Enumerable.Empty <string>();
                            var newTags = purchaseInfo.tags ?? Enumerable.Empty <string>();
                            if (!oldTags.SequenceEqual(newTags))
                            {
                                updatedPackages.Add(new AssetStorePackage(m_AssetStoreUtils, m_IOProxy, purchaseInfo, productInfo, m_AssetStoreCache.GetLocalInfo(productIdString)));
                            }
                        }
                    }

                    if (updatedPackages.Any())
                    {
                        onPackagesChanged?.Invoke(updatedPackages);
                    }
                }

                foreach (var cat in result.categories)
                {
                    m_AssetStoreCache.SetCategory(cat.name, cat.count);
                }

                onProductListFetched?.Invoke(result);
            };

            onListOperation?.Invoke(m_ListOperation);
            m_ListOperation.Start(queryArgs);
        }
コード例 #5
0
        private void SetQueryArgs(PurchasesQueryArgs queryArgs)
        {
            m_OriginalQueryArgs = queryArgs;

            m_DownloadedAssetsOnly = m_OriginalQueryArgs.downloadedOnly;
            m_UpdateAvailableOnly  = m_OriginalQueryArgs.updateAvailableOnly;
            // The GetPurchases API has a limit of maximum 1000 items (to avoid performance issues)
            // therefore we do some adjustments to the original query args enforce that limit and split
            // the original query to multiple batches. We make a clone before when adjusting is needed
            m_AdjustedQueryArgs       = m_OriginalQueryArgs.Clone();
            m_AdjustedQueryArgs.limit = Math.Min(m_OriginalQueryArgs.limit, k_QueryLimit);

            if (m_DownloadedAssetsOnly)
            {
                m_AdjustedQueryArgs.status     = string.Empty;
                m_AdjustedQueryArgs.productIds = m_AssetStoreCache.localInfos.Select(info => info.id).ToList();
            }
            else if (m_UpdateAvailableOnly)
            {
                m_AdjustedQueryArgs.status     = string.Empty;
                m_AdjustedQueryArgs.productIds = m_AssetStoreCache.localInfos.Where(info => info.canUpdate).Select(info => info.id).ToList();
            }
        }
コード例 #6
0
 public AssetStorePurchases(PurchasesQueryArgs queryArgs = null)
 {
     this.queryArgs = queryArgs ?? new PurchasesQueryArgs();
 }
コード例 #7
0
        public virtual void Refresh(RefreshOptions options)
        {
            if ((options & RefreshOptions.UpmAny) != 0)
            {
                var entitlements = m_PackageDatabase.allPackages.Where(package => package.hasEntitlementsError);
                if (entitlements.Any())
                {
                    foreach (var package in entitlements)
                    {
                        package.ClearErrors(error => error.errorCode == UIErrorCode.Forbidden);
                    }
                    TriggerOnSelectionChanged();
                }
            }

            if ((options & RefreshOptions.UpmSearch) != 0)
            {
                m_UpmClient.SearchAll();
                // Since the SearchAll online call now might return error and an empty list, we want to trigger a `SearchOffline` call if
                // we detect that SearchOffline has not been called before. That way we will have some offline result to show to the user instead of nothing
                if (!m_RefreshTimestamps.TryGetValue(RefreshOptions.UpmSearchOffline, out var value) || value == 0)
                {
                    options |= RefreshOptions.UpmSearchOffline;
                }
            }
            if ((options & RefreshOptions.UpmSearchOffline) != 0)
            {
                m_UpmClient.SearchAll(true);
            }
            if ((options & RefreshOptions.UpmList) != 0)
            {
                m_UpmClient.List();
                // Do the same logic for the List operations as the Search operations
                if (!m_RefreshTimestamps.TryGetValue(RefreshOptions.UpmListOffline, out var value) || value == 0)
                {
                    options |= RefreshOptions.UpmListOffline;
                }
            }
            if ((options & RefreshOptions.UpmListOffline) != 0)
            {
                m_UpmClient.List(true);
            }
            if ((options & RefreshOptions.Purchased) != 0)
            {
                var queryArgs = new PurchasesQueryArgs
                {
                    startIndex = 0,
                    limit      = Math.Max(GetCurrentPage().numCurrentItems, m_PackageManagerPrefs.numItemsPerPage ?? k_DefaultPageSize),
                    searchText = m_PackageFiltering.currentSearchText
                };

                IPage page;
                if (m_Pages.TryGetValue(PackageFilterTab.AssetStore, out page))
                {
                    queryArgs.status         = page.filters.status;
                    queryArgs.categories     = page.filters.categories;
                    queryArgs.labels         = page.filters.labels;
                    queryArgs.orderBy        = page.filters.orderBy;
                    queryArgs.isReverseOrder = page.filters.isReverseOrder;
                }

                m_AssetStoreClient.ListPurchases(queryArgs);
            }
            if ((options & RefreshOptions.PurchasedOffline) != 0)
            {
                m_AssetStoreClient.RefreshLocal();
            }
        }