using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using UnityEditor.PackageManager;
using UnityEditor.PackageManager.UI;
using UnityEngine.UIElements;
using PackageInfo = UnityEditor.PackageManager.PackageInfo;
namespace LocalPackageManager
{
///
/// UPM Local Package Manager Extention.
///
[InitializeOnLoad]
internal sealed class UpmLocalPackageManageExtention : VisualElement, IPackageManagerExtension
{
//################################
// Private Members.
//################################
private bool _initialized;
private PackageInfo _packageInfo;
private Button openLocalPackageManagerButton;
[InitializeOnLoadMethod]
private static void InitializeOnLoadMethod()
{
// Register extension.
var ext = new UpmLocalPackageManageExtention();
PackageManagerExtensions.RegisterExtension(ext as IPackageManagerExtension);
}
//################################
// IPackageManagerExtension Members.
//################################
VisualElement IPackageManagerExtension.CreateExtensionUI()
{
_initialized = false;
return this;
}
void IPackageManagerExtension.OnPackageAddedOrUpdated(PackageInfo packageInfo)
{
if (packageInfo == null) return;
if (packageInfo.source == PackageSource.Local)
{
LocalPackageManageWindow.Open(packageInfo);
}
}
void IPackageManagerExtension.OnPackageRemoved(PackageInfo packageInfo)
{
}
void IPackageManagerExtension.OnPackageSelectionChange(PackageInfo packageInfo)
{
// Debug.Log("[UpmLPM] OnPackageSelectionChange");
Initialize();
if (packageInfo == null)
{
openLocalPackageManagerButton.style.display = DisplayStyle.None;
return;
}
// Debug.Log($"[UpmLPM] UPM package info: name=" + packageInfo.name);
// Debug.Log($"[UpmLPM] UPM package info: source=" + packageInfo.source);
// Debug.Log($"[UpmLPM] UPM package info: packageId=" + packageInfo.packageId);
// Debug.Log($"[UpmLPM] UPM package info: resolvedPath=" + packageInfo.resolvedPath);
// Debug.Log($"[UpmLPM] UPM package info: assetPath=" + packageInfo.assetPath);
_packageInfo = packageInfo; //? 暫定処置
if (packageInfo.source == PackageSource.Local)
{
// Debug.Log($"[UpmLPM] {packageInfo.displayName} is local package.");
openLocalPackageManagerButton.style.display = DisplayStyle.Flex;
}
else
{
openLocalPackageManagerButton.style.display = DisplayStyle.None;
}
}
///
/// Initialize.
///
private void Initialize()
{
if (_initialized) return;
CreateLocalPackageManageButton();
_initialized = true;
}
///
/// UPM でローカルパッケージを選択したときに追加のUIを作成する
///
private void CreateLocalPackageManageButton()
{
// Find root element.
VisualElement root = this;
while (root != null && root.parent != null)
{
root = root.parent;
}
// Add open local package manager button.
// Debug.Log($"[UpmLPM] _packageInfo.source: {_packageInfo.source}");
openLocalPackageManagerButton = new(() => { LocalPackageManageWindow.Open(_packageInfo); });
openLocalPackageManagerButton.text = "Open LPM"; //* 仮ラベル
openLocalPackageManagerButton.name = "PackageOpenLocalPackageManagerButton";
// Display property is none by default. (It set to flex when the package is local.)
openLocalPackageManagerButton.style.display = DisplayStyle.None;
// builtInActions はUPM のパッケージ詳細画面の右上にあるボタン群をまとめたVisualElement
if (FindElement(root, x => x.name == "builtInActions") is VisualElement builtInActions)
{
builtInActions.Insert(0, openLocalPackageManagerButton);
}
}
///
/// Execute VisualElementExtention.FindElements method.
///
///
/// 検索対象の VisualElement
/// 検索条件。検索対象のVisualElementを引数として受け取った際にtrueを返す関数
/// 条件に該当する VisualElement のリスト
private static List FindElements(VisualElement element, Func predicate)
{
string engineAssemblyPath = InternalEditorUtility.GetEngineAssemblyPath();
string engineAssemblyDirectoryName = Path.GetDirectoryName(engineAssemblyPath).Replace("\\", "/");
Assembly assembly = Assembly.LoadFile($@"{engineAssemblyDirectoryName}/UnityEditor.UIBuilderModule.dll");
Type type = assembly.GetType("Unity.UI.Builder.VisualElementExtensions");
if (type == null)
{
Debug.LogError("[UpmLPM] Unity.UI.Builder.VisualElementExtention is not found.");
return null;
}
MethodInfo findElementsMethod = type.GetMethod("FindElements", BindingFlags.Static | BindingFlags.Public);
if (findElementsMethod == null)
{
Debug.LogError("[UpmLPM] Unity.UI.Builder.VisualElementExtention.FindElements() is not found.");
return null;
}
List result =
(List)(findElementsMethod?.Invoke(null, new object[] { element, predicate }));
return result;
}
///
/// 条件に合ったVisualElementを取得する
///
/// 検索対象の VisualElement
/// 検索条件。検索対象のVisualElementを引数として受け取った際にtrueを返す関数
/// 一番最初に条件に該当した VisualElement
private static VisualElement FindElement(VisualElement element, Func predicate)
{
List result = FindElements(element, predicate);
if (result == null || result.Count == 0) return null;
return result[0];
}
}
}