Найти в Дзене

Секретики Unity3d. Зачем нужен флаг STARTER_ASSETS_PACKAGES_CHECKED в стартовых ассетах

Оглавление

Что за флаг?

Кто устанавливал офицальные ассеты от Unity "Starter Assets - Third Person Character Controller" или "Starter Assets - First Person Character Controller" возможно замечал что в настройках проета (Project settings -> Player -> Other settings -> Script Compilation) появляется флаг STARTER_ASSETS_PACKAGES_CHECKED, но зачем он нужен? Давайте разбираться.

Исследуем скрипты

Для иследования был выбран ассет "Starter Assets - First Person Character Controller". Открываем скрипт "ThirdPersonController" и что мы видим:

...
namespace StarterAssets
{
[RequireComponent(typeof(CharacterController))]
if ENABLE_INPUT_SYSTEM && STARTER_ASSETS_PACKAGES_CHECKED
[RequireComponent(typeof(PlayerInput))]
endif
public class ThirdPersonController : MonoBehaviour
{
...
...
if ENABLE_INPUT_SYSTEM && STARTER_ASSETS_PACKAGES_CHECKED
private PlayerInput _playerInput;
endif
...
...
if ENABLE_INPUT_SYSTEM && STARTER_ASSETS_PACKAGES_CHECKED
_playerInput = GetComponent<PlayerInput>();
else
...

По всюду этот флаг используется в паре с флагом ENABLE_INPUT_SYSTEM, хм... интересно. Очевидно что флаг ENABLE_INPUT_SYSTEM отвечает за новую систему ввода, но вот второй флаг зачем он здесь и кто его устанавливает в настройках проекта? Смотрим дальше. Нашелся еще один флаг в скрипте "StarterAssetsDeployMenu.cs", но уже тут он используется один:

...
if STARTER_ASSETS_PACKAGES_CHECKED
private static void CheckCameras(Transform targetParent, string prefabFolder)
{
CheckMainCamera(prefabFolder);

GameObject vcam = GameObject.Find(CinemachineVirtualCameraName);

...

Из кода становиться понятно что он включает работу с кинемашиной. Интересно, значит получается что этот флаг контролирует подключение кода который в свой очередь находиться в двух пакетах "com.unity.inputsystem" и "com.unity.cinemachine". С этим вроде немного разобрались, но всетаки кто устанавливает этот флаг в настройках проекта?

Исследуем файлы проекта

После тщательного обследования файлов ассета, выявлена подозрительная библиотека Assets\StarterAssets\Editor\PackageChecker\StarterAssetsPackageChecker.dll давайте ее отрефлектим:

Hidden text

И что мы тут видим? Наш флажочек STARTER_ASSETS_PACKAGES_CHECKED)

[Serializable]
private class Settings
{
public string EditorFolderRoot = "Assets/StarterAssets/";
public string[] PackagesToAdd = new string[2]
{
"com.unity.cinemachine",
"com.unity.inputsystem"
};

public string PackageCheckerScriptingDefine => "STARTER_ASSETS_PACKAGES_CHECKED";
}

Так, я чувствую что мы уже близко к истине.

Разбираем потроха StarterAssetsPackageChecker.dll

Изучив код этой библиотеки, я пришол к выводу что это - автоматический инсталятор пакетов Unity. Очень интересно! Давайте расскажу как эта штука работает.

Главный метод запускается каждый раз, при "перезагрузки" редактора, о чем говорит аттрибут[InitializeOnLoadMethod]в этом методе идет поиск файлов с именем "PackageCheckerSettings.json", а затем настройки из этого файла мапятся на PackageChecker._settings.

...
[InitializeOnLoadMethod]
private static void CheckPackage()
{
PackageChecker._settings = new PackageChecker.Settings();
string[] files = Directory.GetFiles(Application.dataPath, "PackageCheckerSettings.json", SearchOption.AllDirectories);
if (files.Length != 0)
JsonUtility.FromJsonOverwrite(File.ReadAllText(files[0]), (object) PackageChecker._settings);
...

Давайте взглянем что находиться в файле "PackageCheckerSettings.json", и тут мы видим опять наши пакеты, а также какой-то "EditorFolderRoot":

{
"EditorFolderRoot": "Assets/StarterAssets/",
"PackagesToAdd": [
"com.unity.cinemachine",
"com.unity.inputsystem"
]
}

Вернемся в нашу dll. Далее по коду идет сравнение версий пакетов и их установка с помощью метода private static AddRequest InstallSelectedPackage. И тут же видим нашу заветную строчку, которая задает флаг STARTER_ASSETS_PACKAGES_CHECKED на уровне проекта:

PackageChecker.SetScriptingDefine(PackageChecker._settings.PackageCheckerScriptingDefine);
...
private static void SetScriptingDefine(string scriptingDefine)
{
BuildTargetGroup buildTargetGroup = EditorUserBuildSettings.selectedBuildTargetGroup;
string defineSymbolsForGroup = PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup);
if (defineSymbolsForGroup.Contains(scriptingDefine))
return;
string defines = defineSymbolsForGroup + ";" + scriptingDefine;
PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, defines);
}

Теперь стало все понятно, этот флаг фиксирует установку пакетов и при дальнейшем вызове метода CheckPackage() идет проверка, что если флаг установлен то установку пакетов уже не производим. Вауля!!!

if (PackageChecker.CheckScriptingDefine(PackageChecker._settings.PackageCheckerScriptingDefine))
return;

А что насчет строчки "EditorFolderRoot": "Assets/StarterAssets/" из конфига? А тут все просто она указывает на папку с ассетами которым нужно сделать реимпорт после установки пакетов

private static void ReimportPackagesByKeyword()
{
AssetDatabase.Refresh();
AssetDatabase.ImportAsset(PackageChecker._settings.EditorFolderRoot, ImportAssetOptions.ImportRecursive
}

Что в итоге?

Мы можем использовать библиотеку StarterAssetsPackageChecker.dll в паре с файлом PackageCheckerSettings.json в своем проекте для автоматической установки пакетов Unity. Просто закидываем их к себе в папку Editor и добавляем необходимые пакеты в файл конфигурации.

Чтобы я улучшил в библиотеке StarterAssetsPackageChecker.dll так это сделал бы свойство public string PackageCheckerScriptingDefine => "STARTER_ASSETS_PACKAGES_CHECKED" доступным для записи, чтобы можно было задавать произвольное имя флага в своих ассетах. Еще бы добавил итерацию по всем файлам PackageCheckerSettings.json находящимся в проекте, чтобы установить все зависимости, а не производить установку только по первому попавшемуся файлу.

Могу предположить что у каманды Unity это своего рода "заготовка" для будущей автоматизации установки пакетов, поэтому будем надеяться и верить что работа с пакетами станет еще проще и удобней. А также пожелаем Unity чтобы она добавила возможность добавлять scope в файлы манифеста с помощью кода.

Присоединяйтесь к моим соц сетям: