Using IExternalValueProvider at Initialization | Game Foundation | 0.8.0-preview
docs.unity.cn
    Show / Hide Table of Contents

    Using IExternalValueProvider at Initialization

    When initializing Game Foundation using a MemoryDataLayer class or PersistenceDataLayer class, you typically set the CatalogAsset class with fixed data. While having fixed data for your catalog at initialization works in most situations, there may be cases where it's useful to have catalog data with different values available under specific conditions, or determined for a select group of players. Some examaples of this being useful is when:

    • A/B testing
    • Randomizing the catalog
    • Handling different catalog configurations

    Game Foundation lets you override fixed catalog data at initialization using the External Value Provider, in particular, implementing your own IExternalValueProvider interface. In other words, by binding to a CatalogAsset class, Game Foundation requests the IExternalValueProvider implementation for overriding a specified list of catalog data by providing a catalogItemFieldName/catalogItemKey key pair.

    • catalogItemFieldName is an identifier of the catalog item field to get a value for. Refer to ExternalValueProviderNames to see exact set of existing identifiers.
    • catalogItemKey is the key of the catalog item for which the override is requested.

    Note that external value providers don't require a value for all given identifier pairs. If no value is provided for an identifier pair, the value from the catalog will be used.

    Important: The IExternalValueProvider.TryGetValue method must be synchronous! If you need to initialize it and fetch data from a server, do it before binding it to the CatalogAsset class.

    List of externalizable values to override catalog data

    All fields of a CatalogItemAsset and its inherited classes, wrapped into an ExternalizableValue are overridable. Here is a description of each class and the respective variables that can be overriden using IExternalValueProvider.

    For the CatalogItemAsset class:

    • displayName: The name of a catalog item.
    • staticProperties: A set of user-defined properties for catalog items. Only the values are overridable, the structure and the types cannot be overriden.

    For the CurrencyAsset class:

    • initialBalance: The balance provided to a new player.
    • maximumBalance: The maximum balance a player can have.
    • currencyType: The type of currency (Soft or Hard).

    For the InventoryItemDefinitionAsset class:

    • initialAllocation: The amount of items made from this definition provided to a new player.
    • mutableProperties: A set of user-defined properties for items made from this definition. Only the default values are overridable, the structure and the types cannot be overriden.
    • initialQuantityPerStack: Only for stackable items - the quantity of items for each stack provided to a new player.

    For the IAPTransactionAsset class:

    • googleId: The product ID for the Google Play Store.
    • appleId: The product ID for the Apple App Store.

    For the RewardAsset class:

    • cooldownSeconds: The amount of time (in seconds) a player needs to wait after claiming a reward item before they can claim the next reward item in the sequence.
    • expirationSeconds: The amount of time (in seconds) to claim a reward item before it becomes no longer available to the player. When a reward item is not claimed in time, it expires.
    • resetIfExpired: A flag to determine the behaviour if the current reward item expires. If true, the whole reward is reset to the first valid item in sequence, otherwise it passes to the next valid item.

    Code sample implementation of IExternalValueProvider

    There are many applications of customizing the External Value Provider to create your own implementations of setting catalog data with different values.

    The following code sample is a simple implementation of the IExternalValueProvider interface that allows you to randomize the initial balance for currencies. This is just one example that you can easily use and adapt to implement your own value provider for another scenario.

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.GameFoundation;
    using UnityEngine.GameFoundation.DefaultCatalog;
    using UnityEngine.GameFoundation.DefaultLayers;
    using UnityEngine.Promise;
    
    [Serializable]
    public class CatalogItemRandomRange
    { 
        public string CatalogItemKey;
    
        [Min(0)]
        public long MinimumValue;
    
        [Min(0)]
        public long MaximumValue;
    }
    
    [Serializable]
    public class CurrencyInitialBalanceRandomizer : IExternalValueProvider
    {
        public List<CatalogItemRandomRange> InitialBalanceRanges;
    
        public bool TryGetValue(string catalogItemFieldName, string catalogItemKey, out Property value)
        {
            // Let's start by checking the given catalogItemFieldName to make sure it is handled by our value provider.
            // Remember to use the static class ExternalValueProviderNames to identify
            // what kind of catalogItemFieldName you are currently dealing with.
            // This example handles only one type of field but you can handle multiple field types in
            // the same value provider by using a more advanced matchup table than InitialBalanceRanges.
            if (catalogItemFieldName != ExternalValueProviderNames.initialBalance)
            {
                value = default;
    
                return default;
            }
    
            // Now that the kind of catalog field is confirmed, let's verify if the given catalogItemKey is handled.
            foreach (CatalogItemRandomRange range in InitialBalanceRanges)
            {
                if (range.CatalogItemKey != catalogItemKey)
                {
                    continue;
                }
    
                // Randomize the value.
                value = UnityEngine.Random.Range(range.MinimumValue, range.MaximumValue);
    
                // Make sure the value is positive.
                value = Mathf.Max(0, value);
    
                return true;
            }
    
            // No match found.
            value = default;
    
            return default;
        }
    }
    
    public class Initializer : MonoBehaviour
    {
        public CurrencyInitialBalanceRandomizer ValueProvider;
    
        IEnumerator Start()
        {
            // Get the catalog to give to Game Foundation.
            // Here we use CatalogSettings.catalogAsset for simplicity but you can use any other CatalogAsset.
            CatalogAsset catalog = CatalogSettings.catalogAsset;
    
            // Bind the value provider to the catalog.
            catalog.SetValueProvider(ValueProvider);
    
            // Create the data layer with the setup catalog.
            MemoryDataLayer dataLayer = new MemoryDataLayer(catalog);
    
            // Initialize Game Foundation.
            using (Deferred initialization = GameFoundationSdk.Initialize(dataLayer))
            {
                // Wait for the initialization to be over.
                if (!initialization.isDone)
                {
                    yield return initialization.Wait();
                }
    
                // Make sure the initialization succeeded.
                if (!initialization.isFulfilled)
                {
                    Debug.LogError(initialization.error);
    
                    yield break;
                }
    
                // Get the randomized currency and log its current balance.
                const string key = "coins";
                var coins = GameFoundationSdk.catalog.Find<Currency>(key);
                Debug.Log($"{coins.displayName}'s initial balance is {coins.quantity.ToString()}.");
            }
        }
    }
    

    < table of contents

    Back to top Copyright © 2020 Unity Technologies
    Generated by DocFX
    on 23 November 2020