icon

Создание опций в настройках платформы

Можно создать новые опции для двух разделов:

  1. Такие же опции как мы рассматривали ранее. Их можно сделать с флагами активности и без. Это опции, которые содержат разные значения для разных платформ.
  2. Общие настройки, которые размещаются в отдельном разделе. У них будет одинаковое для всех платформ.
    icon

И в первом и во втором случае нужно создать скрипт, файл которого можно назвать как угодно и таких файлов сделать можно сколько угодно и к ним применимы атрибуты: [ApplySettings], [SelectPlatform], [DeletePlatform].

Создание опций
Пример без флага активности.
Создание поля с разными значениями для разных платформ:
namespace YG.Insides
{
    public partial class ProjectSettings
    {
        public string myOption; // Добавление опции
    }
}
Обращение к созданному полю:
YG2.infoYG.platformOptions.myOption

Также создаётся поле общих настроек, только класс другой:

namespace YG.Insides
{
    public partial class CommonOptions
    {
        public string myCommonOption; // Добавление опции
    }
}
Обращение к созданному полю:
YG2.infoYG.common.myCommonOption

Следующий пример — с добавлением флага активности:

namespace YG.Insides
{
    public partial class ProjectSettings // Или CommonOptions
    {
        public string myOption; // Добавление опции

        [ApplySettings]
        public void MyApplySettings()
        {
            // Сработает при применении настроек платформы. Пример:

            // Получаем ссылку на флаги опций
            PlatformToggles toggles = YG2.infoYG.platformToggles;

            // Если флаг активный - применяем опцию
            if (toggles.myOption == true)
                myOption = "apply";
        }

        [SelectPlatform]
        public void MySelectPlatform()
        {
            // Сработает при выборе платформы
        }

        [DeletePlatform]
        public void MyDeletePlatform()
        {
            // Сработает перед удаление платформы из проекта
        }
    }

    // Добавьте флаг активности
    public partial class PlatformToggles
    {
        public bool myOption; // Флаг должен называться также как опция
    }
}

Создание платформы

Для примера возьмём платформу Crazy Games.

  1. Создайте папку с именем платформы в PluginYourGames/Platforms. Название нужно подобрать тщательно, оно много где будет использоваться.
  2. Создайте текстовый документ Version.txt, в нём запишите версию модуля в таком формате: v1.0.
  3. Создайте файл настроек платформы: ЛКМ → Create → YG2 → New Platform. Настройте по желанию.
  4. Создайте папку SDK — она будет игнорироваться для компилятора, если платформа не активна. В данную папку поместите SDK площадки, если таковой имеется. И все скрипты платформы содержите в папке SDK.

icon

Если вы создаёте WebGL платформу, то шаблон нужно назвать также как назвали платформу. Шаблон — это index.html и другие файлы для WebGL билда. Шаблон должен находиться в папке WebGLTemplates. Сделайте по аналогии с YandexGames.

В настройках PluginYG2 переключитесь на созданную платформу.
В SDK можно создать папку ScriptsYG, чтобы обозначить скрипты для PluginYG. В этой папке создайте базовый скрипт, в котором будет логика инициализации. Я назову скрипт CG_BasicAPI. Вставьте в него шаблон:

#if CrazyGamesPlatform_yg
namespace YG
{
    public partial class PlatformYG2 : IPlatformsYG2
    {
        public void InitAwake() { }
        public void InitStart() { }
        public void InitComplete() { }
        public void GameplayStart() { }
        public void GameplayStop() { }
        public void HappyTime() { }
    }
}
#endif
Измените дефайн
CrazyGamesPlatform_yg — это дефайн (директива препроцессора). Его можно встретить в следующих местах:
drawing
Измените его название на то, что указано в настройках платформы. Когда название верное, код внутри #if код #endif не серый. Серый он становится тогда, когда дефайна нет в списке Scripting Define Symbols. Это ещё от IDE (редактор кода) зависит, конечно. Если в списке он есть и название верное, но код серый — перезагрузите IDE.
О интерфейсе и методах
Скрипт выше реализует интерфейс IPlatformsYG2.
Представленные методы переопредиляют стандартную реализацию. Для всех методов в интерфейсе IPlatformsYG2 есть стандартная реализация. У представленных методов реализация пустая (кроме InitAwake, его пока не трогать). По этому их можно удалить или оставить так, ничего не изменится. В примере предоставлены самые важные методы, которые есть в PluginYG без отдельных модулей.

По простому, это работает так:
Например, нам нужно выполнить метод SDK платформы GameplayStart. В одноименном представленном методе внутри фигурных скобок прописываем реализацию:

public void GameplayStart()
{
	CrazySDK.Game.GameplayStart();
}
Можно сократить и прописать так:
public void GameplayStart() => CrazySDK.Game.GameplayStart();
Инициализация
Чаще всего SDK предоставляет асинхронный метод инициализации. После того, как игра загрузилась — SDK ещё не готов и нельзя пользоваться его функциями, надо подождать пока SDK инициализируется.
Давайте рассмотрим два варианта:

1. Когда SDK при запуске игры сразу готов (как у платформы YandexGames на PluginYG. Она адаптирована под два варианта). В этом случае нужно только удалить метод InitAwake.
2. Второй случай, когда необходимо дождаться инициализации.

Для второго варианта необходимо включить опцию Sync Init SDK в Basic Settings и настроить вытикающие параметры. Почитайте всплывающие подсказки.

Затем, в реализации InitAwake выполните метод SDK для инициализации. По завершению инициализации выполните метод YG2.SyncInitialization(), чтобы сигнализировать PluginYG о том, что SDK готов. Пример:

public void InitAwake()
{
    if (CrazySDK.IsAvailable) // Требования CrazyGames
    {
        CrazySDK.Init(() =>
        {
            YG2.SyncInitialization();
        });
    }
}
Реализация отдельных модулей
Для удобства скрипты под отдельные модули можно поместить в папку Modules.

Например мы делаем реализацию для модуля некого MyModule. Создадим скрипт с названием файла CG_MyModule. И вставим в скрипт тот же код, что был для инициализации удалив все методы.
Но вот что нам ещё нужно сделать для скипта использующего методы модуля — прописать дефайн:

#if CrazyGamesPlatform_yg && MyMethod_yg // + && MyMethod_yg
namespace YG
{
    public partial class PlatformYG2 : IPlatformsYG2
    {
        public void MyMethod()
        {
            // Реализация
        }
    }
}
#endif

Мы добавили дефайн модуля. Дефайн состоит из названия модуля и приписки _yg. Это нужно делать, потому что модуль может отсутствовать в проекте и тогда пойдут ошибки.
Инициализация модулей
Многие модули имеют методы для инициализации. Они выполняются после рассмотренного выше метода InitAwake, когда SDK уже готов. Например, у модуля EnvirData есть метод InitEnvirData — в нём данные вроде device, language из SDK записываются в поля плагина. И для новой платформы тоже нужно передавать таким образом данные. Вот как выглядит готовый скипт CG_EnvirData:
#if CrazyGamesPlatform_yg && EnvirData_yg
using CrazyGames;

namespace YG
{
    public partial class PlatformYG2 : IPlatformsYG2
    {
        public void InitEnirData()
        {
            if (CrazySDK.User.IsUserAccountAvailable) // Требование платформы
            {
                YG2.envir.language = CrazySDK.User.SystemInfo.countryCode.ToLower();
                YG2.envir.browser = CrazySDK.User.SystemInfo.browser.name;
                YG2.envir.platform = CrazySDK.User.SystemInfo.os.name;

                string device = CrazySDK.User.SystemInfo.device.type;
                YG2.envir.deviceType = device;

                switch (device)
                {
                    case "desktop":
                        YG2.envir.isDesktop = true;
                        break;
                    case "tablet":
                        YG2.envir.isTablet = true;
                        break;
                    case "mobile":
                        YG2.envir.isMobile = true;
                        break;
                }
            }
        }

        public void GetEnvirData()
        {
            InitEnirData();
            YG2.GetDataInvoke();
        }
    }
}
#endif

Метод GetEnvirData — обновляет данные в процессе игры. И в конце он выполняет метод YG2.GetDataInvoke, который вызовет событие onGetSDKData если PluginYG уже полностью инициализирован. Данное событие может вызвать некоторые обновления данных плагина на сцене.
Асинхронная инициализация модулей
Бывает такое, что асинхронные методы есть не только для инициализации. Например, для Crazy Games нужно асинхронно инициализировать ещё данные игрока. Все асинхронные инициализации необходимо выполнить в методе InitAwake. По этому в скрипте с базовыми реализациями мы инициализируем и данные игрока, но зададим условие — если импортирован модуль авторизации. Вот так выглядит итоговый скрипт CG_BasicAPI:
#if CrazyGamesPlatform_yg
using CrazyGames;

namespace YG
{
    public partial class PlatformYG2 : IPlatformsYG2
    {
#if Authorization_yg
        public PortalUser User;
#endif
        public void InitAwake()
        {
            if (CrazySDK.IsAvailable)
            {
                CrazySDK.Init(() =>
                {
#if Authorization_yg
                    if (CrazySDK.User.IsUserAccountAvailable)
                    {
                        CrazySDK.User.GetUser(user =>
                        {
                            User = user;
                            YG2.SyncInitialization();
                        });
                    }
                    else
                    {
                        YG2.SyncInitialization();
                    }
#else
                    YG2.SyncInitialization();
#endif
                });
            }
        }
    }
}
#endif

Сохраняем данные в поле User. Используем его для записи данных в методе инициализации модуля. Готовый скрипт CG_Authorization:
#if CrazyGamesPlatform_yg && Authorization_yg
using UnityEngine;
using CrazyGames;

namespace YG
{
    public partial class PlatformYG2 : IPlatformsYG2
    {
        public void InitAuth()
        {
            if (CrazySDK.User.IsUserAccountAvailable)
            {
                YG2.player.auth = true;
                YG2.player.name = User.username;
                YG2.player.photo = User.profilePictureUrl;
            }
        }

        public void GetAuth()
        {
            if (CrazySDK.User.IsUserAccountAvailable)
            {
                CrazySDK.User.GetUser(user =>
                {
                    User = user;
                    YG2.GetDataInvoke();
                });
            }
        }

        public void OpenAuthDialog()
        {
            CrazySDK.User.ShowAuthPrompt((error, user) =>
            {
                if (error != null)
                {
                    Debug.LogError("Show auth prompt error: " + error);
                    return;
                }

                User = user;
                InitAuth();
                YG2.GetDataInvoke();
            });
        }
    }
}
#endif
Подытожим:

  1. Все реализации происходят в одном классе PlatformYG2.
  2. Для реализации нужно переопределить существующий метод.
  3. Сначала выполняется метод InitAwake, потом методы инициализации модулей. Потом метод InitStart, за ним InitComplete.
  4. Если требуется, в методе InitAwake производим асинхронные инициализации. Если нужно, сохраняем некоторые данные для модулей.
  5. Переопредиляем реализации для модулей.

Реализация рекламы

Все методы в интерфейсе для модуля можно найти в папке модуля → Scripts. Скрипты интерфейсы помечены подписью interface. Там же можно посмотреть и стандартную реализацию.
Вместе со всеми модулями идёт реализация для стандартной платформы YandexGames. Содержится в скриптах с подписью yandexPlatform.
В скриптах с подписью yg содержится логика самого модуля. В info опции из настроек PluginYG.
icon

Рассмотрим реализацию для Interstitial Adv:

#if CrazyGamesPlatform_yg && InterstitialAdv_yg
using CrazyGames;
using YG.Insides;

namespace YG
{
    public partial class PlatformYG2 : IPlatformsYG2
    {
        public void InterstitialAdvShow()
        {
            CrazySDK.Ad.RequestAd(CrazyAdType.Midgame, () =>
            {
                YGInsides.OpenInterAdv();
            }, (error) =>
            {
                YGInsides.ErrorInterAdv();
                YGInsides.CloseInterAdv();
            }, () =>
            {
                YGInsides.CloseInterAdv();
            });
        }

        public void FirstInterAdvShow()
        {
            OptionalPlatform.FirstInterAdvShow_RealizationSkip();
        }

        public void OtherInterAdvShow() { }
    }
}
#endif
Здесь мы переопредиляем реализацию для метода InterstitialAdvShow. CrazyGames предоставляет коллбеки открытия, закрыти и т.д. рекламы.

В соответствующих коллбеках выполняются методы из внутреннего класса YGInsides, в нём содержится всё скрытое. Так мы выполняем, например, метод закрытия рекламы: YGInsides.CloseInterAdv();

А в OptionalPlatform содержатся готовые реализации для опциональных методов. О них сказано выше.

Реализация локализации

Создайте метод GetLanguage, который должен вернуть язык. Пример:

#if CrazyGamesPlatform_yg && Localization_yg
using CrazyGames;

namespace YG
{
    public partial class PlatformYG2 : IPlatformsYG2
    {
        public string GetLanguage()
        {
            if (CrazySDK.User.IsUserAccountAvailable)
            {
                return CrazySDK.User.SystemInfo.countryCode.ToLower();
            }
            return "en";
        }
    }
}
#endif

Реализация облачных сохранений

Метод LoadCloud должен загружать сохранения. Для этого нужно передавать их в json строке методу YGInsides.SetLoadSaves. Стандартное значение указываем Null. Если передаваемое значение будет нулевым или это будет пустая строка, то сохранения сбросятся.
Метод SaveCloud должен сохранять. Сохраняем поле YG2.saves. Пример:

#if CrazyGamesPlatform_yg && Storage_yg
using UnityEngine;
using YG.Insides;
#if NJSON_STORAGE_YG2
using Newtonsoft.Json;
#endif
using CrazyGames;

namespace YG
{
    public partial class PlatformYG2 : IPlatformsYG2
    {
        private const string KEY_SAVE = "CG_SavesYG";

        public void LoadCloud()
        {
            string jsonSaves = CrazySDK.Data.GetString(KEY_SAVE, null);
            YGInsides.SetLoadSaves(jsonSaves);
        }

        public void SaveCloud()
        {
#if NJSON_STORAGE_YG2
            CrazySDK.Data.SetString(KEY_SAVE, JsonConvert.SerializeObject(YG2.saves));
#else
            CrazySDK.Data.SetString(KEY_SAVE, JsonUtility.ToJson(YG2.saves));
#endif
        }
    }
}
#endif
Локальные сохранения и сохранения для смуляции в Unity Editor уже реализованы в логике самого модуля.

Создали модуль? Напишите разработчику плагина 😀