using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Runtime.InteropServices; using UnityEditor.Rendering.Analytics; using UnityEditor.UIElements; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.HighDefinition; using UnityEngine.UIElements; namespace UnityEditor.Rendering.HighDefinition { partial class HDWizard : EditorWindowWithHelpButton { #region OBJECT_SELECTOR //utility class to show only non scene object selection static class ObjectSelector { static Action> ShowObjectSelector; static Func GetCurrentObject; static Func GetSelectorID; static Action SetSelectorID; const string ObjectSelectorUpdatedCommand = "ObjectSelectorUpdated"; static int id; static int selectorID { get => GetSelectorID(); set => SetSelectorID(value); } public static bool opened => Resources.FindObjectsOfTypeAll(typeof(PlayerSettings).Assembly.GetType("UnityEditor.ObjectSelector")).Length > 0; // Action to be called with the window is closed static Action s_OnClose; static ObjectSelector() { Type playerSettingsType = typeof(PlayerSettings); Type objectSelectorType = playerSettingsType.Assembly.GetType("UnityEditor.ObjectSelector"); var instanceObjectSelectorInfo = objectSelectorType.GetProperty("get", BindingFlags.Static | BindingFlags.Public); #if UNITY_2022_2_OR_NEWER var showInfo = objectSelectorType.GetMethod("Show", BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(UnityEngine.Object), typeof(Type), typeof(UnityEngine.Object), typeof(bool), typeof(List), typeof(Action), typeof(Action), typeof(bool) }, null); #elif UNITY_2020_1_OR_NEWER var showInfo = objectSelectorType.GetMethod("Show", BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(UnityEngine.Object), typeof(Type), typeof(UnityEngine.Object), typeof(bool), typeof(List), typeof(Action), typeof(Action) }, null); #else var showInfo = objectSelectorType.GetMethod("Show", BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(UnityEngine.Object), typeof(Type), typeof(SerializedProperty), typeof(bool), typeof(List), typeof(Action), typeof(Action) }, null); #endif var objectSelectorVariable = Expression.Variable(objectSelectorType, "objectSelector"); var objectParameter = Expression.Parameter(typeof(UnityEngine.Object), "unityObject"); var typeParameter = Expression.Parameter(typeof(Type), "type"); var onClosedParameter = Expression.Parameter(typeof(Action), "onClosed"); var onChangedObjectParameter = Expression.Parameter(typeof(Action), "onChangedObject"); var showObjectSelectorBlock = Expression.Block( new[] { objectSelectorVariable }, Expression.Assign(objectSelectorVariable, Expression.Call(null, instanceObjectSelectorInfo.GetGetMethod())), #if UNITY_2022_2_OR_NEWER Expression.Call(objectSelectorVariable, showInfo, objectParameter, typeParameter, Expression.Constant(null, typeof(UnityEngine.Object)), Expression.Constant(false), Expression.Constant(null, typeof(List)), Expression.Constant(null, typeof(Action)), onChangedObjectParameter, Expression.Constant(true)) #elif UNITY_2020_1_OR_NEWER Expression.Call(objectSelectorVariable, showInfo, objectParameter, typeParameter, Expression.Constant(null, typeof(UnityEngine.Object)), Expression.Constant(false), Expression.Constant(null, typeof(List)), Expression.Constant(null, typeof(Action)), onChangedObjectParameter) #else Expression.Call(objectSelectorVariable, showInfo, objectParameter, typeParameter, Expression.Constant(null, typeof(SerializedProperty)), Expression.Constant(false), Expression.Constant(null, typeof(List)), Expression.Constant(null, typeof(Action)), onChangedObjectParameter) #endif ); var showObjectSelectorLambda = Expression.Lambda>>(showObjectSelectorBlock, objectParameter, typeParameter, onChangedObjectParameter); ShowObjectSelector = showObjectSelectorLambda.Compile(); var instanceCall = Expression.Call(null, instanceObjectSelectorInfo.GetGetMethod()); var objectSelectorIDField = Expression.Field(instanceCall, "objectSelectorID"); var getSelectorIDLambda = Expression.Lambda>(objectSelectorIDField); GetSelectorID = getSelectorIDLambda.Compile(); var inSelectorIDParam = Expression.Parameter(typeof(int), "value"); var setSelectorIDLambda = Expression.Lambda>(Expression.Assign(objectSelectorIDField, inSelectorIDParam), inSelectorIDParam); SetSelectorID = setSelectorIDLambda.Compile(); var getCurrentObjectInfo = objectSelectorType.GetMethod("GetCurrentObject"); var getCurrentObjectLambda = Expression.Lambda>(Expression.Call(null, getCurrentObjectInfo)); GetCurrentObject = getCurrentObjectLambda.Compile(); } public static void Show(UnityEngine.Object obj, Type type, Action onChangedObject, Action onClose) { id = GUIUtility.GetControlID("s_ObjectFieldHash".GetHashCode(), FocusType.Keyboard); GUIUtility.keyboardControl = id; ShowObjectSelector(obj, type, onChangedObject); selectorID = id; ObjectSelector.s_OnClose = onClose; EditorApplication.update += CheckClose; } static void CheckClose() { if (!opened) { ObjectSelector.s_OnClose?.Invoke(); EditorApplication.update -= CheckClose; } } public static void CheckAssignationEvent(Action assignator) where T : UnityEngine.Object { Event evt = Event.current; if (evt.type != EventType.ExecuteCommand) return; string commandName = evt.commandName; if (commandName != ObjectSelectorUpdatedCommand || selectorID != id) return; T current = GetCurrentObject() as T; if (current == null) return; assignator(current); GUI.changed = true; evt.Use(); } } void CreateOrLoad(Action onCancel, Action onObjectChanged) where T : ScriptableObject { string title; string content; UnityEngine.Object target; if (typeof(T) == typeof(HDRenderPipelineAsset)) { title = Style.hdrpAssetDisplayDialogTitle; content = Style.hdrpAssetDisplayDialogContent; target = GraphicsSettings.defaultRenderPipeline as HDRenderPipelineAsset; } else throw new ArgumentException("Unknown type used"); switch (EditorUtility.DisplayDialogComplex(title, content, Style.displayDialogCreate, "Cancel", Style.displayDialogLoad)) { case 0: //create if (!AssetDatabase.IsValidFolder("Assets/" + HDProjectSettings.projectSettingsFolderPath)) AssetDatabase.CreateFolder("Assets", HDProjectSettings.projectSettingsFolderPath); var asset = ScriptableObject.CreateInstance(); asset.name = typeof(T).Name; AssetDatabase.CreateAsset(asset, "Assets/" + HDProjectSettings.projectSettingsFolderPath + "/" + asset.name + ".asset"); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); if (typeof(T) == typeof(HDRenderPipelineAsset)) GraphicsSettings.defaultRenderPipeline = asset as HDRenderPipelineAsset; break; case 1: //cancel onCancel?.Invoke(); break; case 2: //Load { m_Fixer.Pause(); ObjectSelector.Show(target, typeof(T), o => onObjectChanged?.Invoke((T)o), m_Fixer.Unpause); break; } default: throw new ArgumentException("Unrecognized option"); } } #endregion #region UIELEMENT abstract class VisualElementUpdatable : VisualElement { protected Func m_Tester; bool m_HaveFixer; public Result currentStatus { get; private set; } protected VisualElementUpdatable(Func tester, bool haveFixer) { m_Tester = tester; m_HaveFixer = haveFixer; } public virtual void CheckUpdate() { var wellConfigured = m_Tester(); if (wellConfigured != currentStatus) currentStatus = wellConfigured; UpdateDisplay(wellConfigured, m_HaveFixer); } public void Init() => UpdateDisplay(currentStatus, m_HaveFixer); public abstract void UpdateDisplay(Result status, bool haveFixer); } class ConfigInfoLine : VisualElementUpdatable { static class Style { public const int k_IndentStepSize = 15; } readonly bool m_VisibleStatus; readonly bool m_SkipErrorIcon; private Image m_StatusOk; private Image m_StatusKO; private Image m_StatusPending; private Button m_Resolver; private HelpBox m_HelpBox; public ConfigInfoLine(Entry entry) : base(() => entry.check(), entry.fix != null) { m_VisibleStatus = entry.configStyle.messageType == MessageType.Error || entry.forceDisplayCheck; m_SkipErrorIcon = entry.skipErrorIcon; var testLabel = new Label(entry.configStyle.label) { name = "TestLabel", style = { paddingLeft = style.paddingLeft.value.value + entry.indent * Style.k_IndentStepSize } }; var testRow = new VisualElement() { name = "TestRow", style = { marginBottom = 2, } }; testRow.Add(testLabel); m_StatusOk = new Image() { image = CoreEditorStyles.iconComplete, name = "StatusOK", style = { height = 16, width = 16 } }; m_StatusKO = new Image() { image = CoreEditorStyles.iconFail, name = "StatusError", style = { height = 16, width = 16 } }; m_StatusPending = new Image() { image = CoreEditorStyles.iconPending, name = "StatusPending", style = { height = 16, width = 16 } }; testRow.Add(m_StatusOk); testRow.Add(m_StatusKO); testRow.Add(m_StatusPending); Add(testRow); var kind = entry.configStyle.messageType switch { MessageType.Error => HelpBoxMessageType.Error, MessageType.Warning => HelpBoxMessageType.Warning, MessageType.Info => HelpBoxMessageType.Info, _ => HelpBoxMessageType.None, }; string error = entry.configStyle.error; // If it is necessary, append tht name of the current asset. var hdrpAsset = HDRenderPipeline.currentAsset; if (entry.displayAssetName && hdrpAsset != null) { error += " (" + hdrpAsset.name + ")."; } m_HelpBox = new HelpBox(error, kind); m_HelpBox.Q