Ще искате да приложите това към всичките си игри

Преглед

Наскоро търсех решение за дистанционно съхраняване на конфигурационните данни на моята предстояща игра поради множество причини:

  1. За да балансирате лесно нещата по време на бета/предварителните версии,
  2. За да актуализирате конфигурацията в често променящи се части,
  3. За „A/B тестване“ на важни части от играта,
  4. Превключване на съдържание за кампании или специални събития,

Между другото, ето ви връзка за присъединяване към ранна бета версия:



Защо ви е необходима отдалечена конфигурация

Нека обясним защо да съхранявате конфигурацията на вашата игра от разстояние в подробности:

За лесно балансиране на нещата по време на бета/предварителни версии или за актуализиране на конфигурацията в често променящи се части на играта, без да пускате нова версия. Това е основно, за да не чакате компилациите да бъдат одобрени от магазините, защото те отделят време, за да прегледат правилно всяка компилация. Това може да отнеме дни или дори седмици в някои случаи. Някои части могат да се променят често

  • Ако искате да актуализирате здравната стойност на определен враг в играта,
  • Регулирайте стойността на атака на вашия главен герой,
  • Или променете цената на надграждане и т.н. няма нужда да преминавате през процеса на освобождаване, ако съхранявате тези конфигурации дистанционно. Това ще бъде удобно, особено ако това са чести промени.

За A/B тестване на важни части от играта чрез предоставяне на различни конфигурации на различни сегменти на играчи и сравняване на резултатите за вземане на информирани решения. Винаги можете да разчитате на писмена или устна обратна връзка от играча, но за да направите фини корекции на конфигурация, трябва да се базирате на някои данни. Това ще бъде полезно особено за голяма база играчи, тъй като данните ще бъдат много по-надеждни с нарастването им. Например,

  • В игра за решаване на пъзели за един играч можете да разделите играчите на две групи, за да дадете различно количество подсказки (напр. 1 подсказка срещу 3 подсказки), за да видите коя група играе играта по-дълго и завършва нивото,
  • Или можете да опитате различен тип RNG алгоритми, за да видите кой от тях осигурява по-приятни моменти в играта.

За да замените съществуващата конфигурация за кампании или специални събития за определен период от време. Например, можете да имате:

  • Отстъпки за определени артикули във вашата игра по време на Черен петък,
  • Увеличени награди за Коледа и др.

Опции за съхраняване на конфигурацията на играта

Има няколко начина за съхраняване на вашата конфигурация:

  1. Клиентска страна → Изисква актуализация на приложението и преглед на магазина (Steam, GooglePlay, iTunes и др.) всеки път.
  2. Персонализиран бекенд → Изисква да внедрите свое собствено бекенд решение — и да го хоствате някъде, за да съхранявате вашата конфигурация. Позволява динамично актуализиране на съдържанието и може да бъде много полезно, ако имате други постоянни данни за съхранение или извършвате някои операции сигурно в отдалечен сървър. Трябва обаче да отделите много време и усилия, за да внедрите свое собствено бекенд решение, което само по себе си може да бъде огромна задача.
  3. PlayFab (или всяка друга облачна услуга) → Изисква минимални усилия за интегриране и използване. През повечето време тези услуги съдържат всичко необходимо, включително съхраняване на конфигурацията от разстояние.

Защо PlayFab

PlayFab позволява дистанционно съхранение на конфигурация безплатно до ~1 милион знака и 1000 двойки ключ-стойност. Това е повече от достатъчно за 99,9% от сценариите, които може да са необходими.

A/B тестването и анализите също са достъпни в PlayFab за отмяна на конфигурацията на играта за определен сегмент от играчи за събиране на данни и вземане на решения за подобряване на времето за игра, процента на реализация и т.н.

Можете да използвате всякакъв вид облачна услуга, но PlayFab предлага всички услуги, от които може да се нуждаете, безплатно с много разумни ограничения. Можете да разгледате всички функции тук: https://learn.microsoft.com/en-us/gaming/playfab/what-is-playfab

Инсталиране на PlayFab SDK

Изтеглете шаблона

Инициализиране на SDK

Изпълнете стъпките в Документи за бърз старт на PlayFab до секцията „Извършване на вашето първо API извикване“, за да инсталирате SDK. Ще направим извикването на API заедно както за влизане, така и за извличане на конфигурацията на играта.

Дефиниране на конфигурацията в PlayFab

Имайте предвид, че има два начина да видите и актуализирате конфигурацията на играта в PlayFab:

  1. Използвайки „Window › PlayFab › Editor Extensions“, за да отворите прозореца на PlayFab, и изберете раздела „Data“.
  2. Влезте в playfab https://developer.playfab.com/en-us/login, отворете вашето заглавие и изберете „Съдържание“ от лявото меню.

И двата подхода могат да се използват и зависи от вас да изберете. Но обичам да разчитам на уебсайта за актуализиране на съдържанието, а не на разширенията на прозореца на редактора. Нека оставим този раздел отворен и превключим към Unity.

Заглавни обекти и заглавни данни в PlayFab

Както „Обекти за заглавие“, така и „Данни за заглавие“ могат да се използват в PlayFab за съхраняване на конфигурация. Разликата е, че Title Data позволява двойки ключ-стойност (общо до 1MB ~ 1 милион знака) и замени на стойността, докато Title Objects очаква обекти (общо до 20KB ~ 20k знака). Поради предимствата му ще използваме двойки ключ-стойност на данните за заглавието като източник на конфигурация.

Или използвайте прозореца на редактора на PlayFab, или уебсайта, за да добавите следните двойки ключ-стойност като наши данни за заглавие:

  • IntValue: 24
  • BoolValue: вярно
  • StringValue: отдалечени данни
  • ComplexValue: {“InnerIntValue”:2424,”InnerBoolValue”:true}

Как да извлечете конфигурация (известна още като данни за заглавие) от PlayFab

Ако сте изтеглили Празния шаблон на проект и следвате този урок, ще забележите, че има три класа под папката Скриптове. Ако не искате да изтеглите проекта, а просто искате да проверите файловете, вижте страницата на проекта GitHub.

  • ContentData: Тестова конфигурация за задържане на данните по подразбиране (локални) или изтеглени. Това ще съдържа всички двойки ключ-стойност, които дефинираме в PlayFab.
  • ContentView: Опростен UI клас за показване на локални или изтеглени данни за съдържание.
  • ContentUpdater: Това е основният клас, който ще използваме, за да се свържем с PlayFab, да изтеглим данните за играта и да ги предадем на ContentView.

⚠️ Преди да продължите,уверете се, че сте влезли в PlayFab от прозореца на редактора и изберете валидно студио и заглавие от неговите настройки

Настройките на PlayFab трябва да изглеждат подобно на това:

Нека направим първото си обаждане до сървърите на PlayFab, като променим съответно ContentUpdater:

public void LoadRemoteData()
{
    this.HideButtonsAndShowLoadingBar();
    this.FetchTitleData();
}

private void FetchTitleData()
{
    SetLoadingMessage("Fetching content");

    // Request ALL title data key-value pairs as Dictionary<string, string>
    var request = new PlayFab.ClientModels.GetTitleDataRequest();

    PlayFab.PlayFabClientAPI.GetTitleData(
        request,
        result =>
        {
            // TODO: Process the result
            SetLoadingMessage("Processing the result");
        },
        error => contentView.ShowMessage($"Error:\n {error.ErrorMessage}"));
}

Използваме метод PlayFab.PlayFabClientAPI.GetTitleData с PlayFab.ClientModels.GetTitleDataRequest, за да извлечем всички двойки ключ-стойност в данните за заглавието. Този метод ще върне Dictionary<string, string> като резултат.

Ако искате да извлечете определени двойки ключ-стойност, вместо това използвайте следната заявка: (Игнорирайте това, ако просто искате да следвате този урок)

var request = new PlayFab.ClientModels.GetTitleDataRequest
{
    Keys = new List<string> { "desired-key" },
};

Ако се върнете към Unity, за да стартирате проекта, и щракнете върху бутона „Зареждане на дистанционно“, ще очаквате да извлече данните за заглавието. Въпреки това, той ще хвърли и изключение:

PlayFabException: Must be logged in to call this method
PlayFab.PlayFabClientAPI.GetTitleData (PlayFab.ClientModels.GetTitleDataRequest request, System.Action`1[T] resultCallback, System.Action`1[T] errorCallback, System.Object customData, System.Collections.Generic.Dictionary`2[TKey,TValue] extraHeaders) (at Assets/PlayFabSDK/Client/PlayFabClientAPI.cs:941)

Това съобщение за грешка е доста очевидно: това, което трябва да направим, е просто да влезем, преди да направим заявка за данни за заглавието.

Нека модифицираме ContentUpdater отново (като оставим имплементацията FetchTitleData такава, каквато е), за да добавим метод LoginToPlayFab:

public void LoadRemoteData()
{
    this.HideButtonsAndShowLoadingBar();
    LoginToPlayFab(FetchTitleData);
}

private void LoginToPlayFab(Action onLoggedIn)
{
    SetLoadingMessage("Logging in");

    var request = new PlayFab.ClientModels.LoginWithCustomIDRequest
    {
        CustomId = SystemInfo.deviceUniqueIdentifier,
        CreateAccount = true,
    };

    PlayFab.PlayFabClientAPI.LoginWithCustomID(
        request,
        _ => onLoggedIn?.Invoke(),
        error => contentView.ShowMessage($"Error:\n {error.ErrorMessage}"));
}

Обработка на изтеглените данни

Ако сте следвали урока досега, ще забележите, че сега няма да има грешки, но екранът ще виси след съобщението „Обработване на резултата“.

Това е така, защото все още имаме // TODO: Process the result, с който трябва да се справим. Нека модифицираме метода ContentUpdater.FetchTitleData, за да заменим коментара TODO с имплементация за отпечатване на резултата.

PlayFab.PlayFabClientAPI.GetTitleData(
    request,
    result =>
    {
        SetLoadingMessage("Processing the result");

        var downloadedData = new ContentData
        {
            IntValue = int.Parse(result.Data["IntValue"]),
            BoolValue = bool.Parse(result.Data["BoolValue"]),
            StringValue = result.Data["StringValue"],
        };

        contentView.ShowWithData(downloadedData);
    },
    error => contentView.ShowMessage($"Error:\n {error.ErrorMessage}"));

Ако се върнете към Unity и се опитате да покажете изтеглено съдържание, на екрана ще се отпечата следното:

🎉 Имаме изтеглена отдалечена конфигурация и готова за използване. 🎉

Но какво да кажем за ComplexValue? Защо е нула и как може да бъде анализиран?

Разбор на ComplexValue

Тъй като е сложен тип и се съхранява като сериализиран JSON, имаме нужда от JSON инструмент, за да го десериализираме в C# обект. Ако използвате целевата версия на Unity на този урок (2021.3.3f1), вече трябва да имате библиотеката Json.NET на Newtonsoft, импортирана в проекта.

Всичко, което трябва да направим, е да импортираме пространството от имена (using Newtonsoft.Json;) в проекта и да използваме JsonConvert, за да десериализираме низа в нашия сложен тип:

var downloadedData = new ContentData
{
    IntValue = int.Parse(result.Data["IntValue"]),
    BoolValue = bool.Parse(result.Data["BoolValue"]),
    StringValue = result.Data["StringValue"],
    ComplexValue = JsonConvert.DeserializeObject<ContentData.ComplexData>(result.Data["ComplexValue"]),
};

Сега, когато зареждаме отдалечените данни, трябва също така да имаме нашата сложна стойност десериализирана и готова за използване:

Заключение

Това приключва част 1 от тази серия. Ако сте следвали урока, вашите файлове трябва да изглеждат така, след като направите промените: Част-1 Изтегляне и анализиране на данните.

Как да използвате изтегленото съдържание

Има няколко начина за използване на изтегленото съдържание. Разбира се, зависи от ситуацията, но някои от тях са:

  • Директно преминаване около екземпляра ContentData
  • Създаване на „singleton“ ContentDataManager клас, който да съдържа екземпляр на ContentData и да го направи достъпен за други класове чрез неговото свойство public static Instance.
  • Използване на „инжектиране на зависимост“, напр. с Zenject, VContainer и т.н., за да свържете ContentDataProvider клас, за да осигурите ContentData с желаната изолация.

Неща, които трябва да имате предвид

  • Ако връзката или изтеглянето се провалят поради някаква причина (напр. стартиране на приложението в офлайн режим), винаги можете да се върнете към ContentData.Default, за да използвате конфигурацията по подразбиране в приложението. Една друга алтернатива може да бъде кеширане на изтеглените данни и използване на това като резервен вариант, ако съществува, в противен случай ContentData.Default може да се използва като последна мярка.
  • През повечето време е по-добре да работите с класа ContentData със силен тип, а не с Dictionary<string, string>, за да уловите възможните проблеми по време на компилиране. Въпреки това може да искате да промените дефиницията на вашия клас по време на разработката или след издаването. Така че може да е добра идея да въведете версии във вашите заглавни данни, за да маркирате очакваната (минимална) версия на клиента.

Следващи стъпки

Въпреки че този подход работи добре засега, той не е много стабилен или гъвкав поради картографирането на всеки елемент от речника към свойствата на класа. Ако искаме максимална гъвкавост с този строго типизиран клас данни, една опция е да използваме силата на Json.NET, за да преобразуваме Dictionary<string, string> в нашия ContentData клас. С персонализиран Json конвертор нашият клас може да поддържа атрибути като [JsonIgnore], [JsonProperty] и т.н. и обратни извиквания за десериализация, за да го направи много гъвкав и съвместим с backwark.

В част 2 от тази поредица ще видим как такова нещо може лесно да се приложи.

Тази публикация първоначално е написана в моя блог. Ако ви е харесало, не се колебайте да го разгледате и подобни публикации: https://www.gokhand.com/blog/using-playfab-to-store-config-remotely-part1