using System; using System.Linq; using UnityEditor; using UnityEditor.UIElements; using UnityEngine; using UnityEngine.UIElements; namespace Unity.RenderStreaming.Editor { /// /// Render Streaming inspector. /// [CustomEditor(typeof(SignalingManager))] internal class SignalingManagerEditor : UnityEditor.Editor { const string DefaultSignalingSettingsSavePath = "Assets/SignalingSettings.asset"; const string DefaultSignalingSettingsLoadPath = "Packages/com.unity.renderstreaming/Runtime/SignalingSettings.asset"; VisualElement root; Button openProjectSettingsButton; PopupField signalingSettingsPopupField; PropertyField signalingSettingsField; public override VisualElement CreateInspectorGUI() { root = new VisualElement(); bool useDefault = serializedObject.FindProperty("m_useDefault").boolValue; var useDefaultField = new PropertyField(serializedObject.FindProperty("m_useDefault"), "Use Default Settings in Project Settings"); useDefaultField.RegisterValueChangeCallback(OnChangeUseDefault); openProjectSettingsButton = new Button { text = "Open Project Setings" }; openProjectSettingsButton.clicked += OnClickedOpenProjectSettingsButton; signalingSettingsPopupField = CreatePopUpSignalingType(serializedObject.FindProperty("signalingSettingsObject"), "Signaling Settings Asset"); signalingSettingsPopupField.RegisterValueChangedCallback(OnValueChangeSignalingSettingsObject); signalingSettingsField = new PropertyField(serializedObject.FindProperty("signalingSettings"), "Signaling Settings"); signalingSettingsField.RegisterValueChangeCallback(OnValueChangeSignalingSettings); root.Add(useDefaultField); root.Add(openProjectSettingsButton); root.Add(signalingSettingsPopupField); root.Add(signalingSettingsField); if (useDefault) { signalingSettingsPopupField.style.display = DisplayStyle.None; signalingSettingsField.style.display = DisplayStyle.None; } else { openProjectSettingsButton.style.display = DisplayStyle.None; } root.Add(new ReorderableListField(serializedObject.FindProperty("handlers"), "Signaling Handler List")); root.Add(new PropertyField(serializedObject.FindProperty("runOnAwake"), "Run On Awake")); root.Add(new PropertyField(serializedObject.FindProperty("evaluateCommandlineArguments"), "Evaluate Commandline Arguments")); EditorApplication.projectChanged += OnProjectChanged; // Disable UI when running in Playmode EditorApplication.playModeStateChanged += OnPlayModeStateChanged; if (EditorApplication.isPlaying) root.SetEnabled(false); return root; } PopupField CreatePopUpSignalingType(SerializedProperty property, string label) { var asset = property.objectReferenceValue as SignalingSettingsObject; var paths = GetAvailableSignalingSettingsPath(); var field = new PopupField(label: label); field.formatSelectedValueCallback = v => AssetDatabase.GetAssetPath(v); field.formatListItemCallback = v => AssetDatabase.GetAssetPath(v); if (paths.Length == 0) return field; var availableObjects = paths.Select(path => AssetDatabase.LoadAssetAtPath(path)).ToArray(); var defaultIndex = ArrayHelpers.IndexOf(availableObjects, asset); field.choices = availableObjects.ToList(); field.index = defaultIndex < 0 ? 0 : defaultIndex; return field; } static string[] GetAvailableSignalingSettingsPath() { var guids = AssetDatabase.FindAssets("t:SignalingSettingsObject"); return guids.Select(AssetDatabase.GUIDToAssetPath).Where(_ => _.StartsWith("Assets")).ToArray(); } static bool IsValidSignalingSettingsObject(SignalingSettingsObject asset) { if (asset == null) return false; if (AssetDatabase.GetAssetPath(asset).IndexOf("Assets", StringComparison.Ordinal) != 0) return false; return true; } void CreateDefaultSignalingSettings() { // Create Default SignalingSettings in Assets folder when the useDefault flag is turned off first time. SignalingSettingsObject asset = AssetDatabase.LoadAssetAtPath(DefaultSignalingSettingsSavePath); if (asset == null) { if (!AssetDatabase.CopyAsset(DefaultSignalingSettingsLoadPath, DefaultSignalingSettingsSavePath)) { Debug.LogError("CopyAssets is failed."); return; } asset = AssetDatabase.LoadAssetAtPath(DefaultSignalingSettingsSavePath); } var handler = serializedObject.targetObject as SignalingManager; handler.signalingSettingsObject = asset; handler.SetSignalingSettings(handler.signalingSettingsObject.settings); } private void OnPlayModeStateChanged(PlayModeStateChange e) { switch (e) { case PlayModeStateChange.EnteredPlayMode: root.SetEnabled(false); break; case PlayModeStateChange.ExitingPlayMode: root.SetEnabled(true); break; } } private void OnProjectChanged() { var paths = GetAvailableSignalingSettingsPath(); // Force to use default settings if there are no available settings in project folder. if (paths.Length == 0) { serializedObject.FindProperty("m_useDefault").boolValue = true; serializedObject.ApplyModifiedProperties(); return; } var asset = serializedObject.FindProperty("signalingSettingsObject").objectReferenceValue; var availableObjects = paths.Select(path => AssetDatabase.LoadAssetAtPath(path)).ToArray(); var defaultIndex = ArrayHelpers.IndexOf(availableObjects, asset); if (defaultIndex < 0) { defaultIndex = 0; using var e = ChangeEvent.GetPooled(null, availableObjects[defaultIndex]); e.target = signalingSettingsPopupField; root.SendEvent(e); } signalingSettingsPopupField.choices = availableObjects.ToList(); signalingSettingsPopupField.index = defaultIndex; } private void OnClickedOpenProjectSettingsButton() { SettingsService.OpenProjectSettings("Project/Render Streaming"); } private void OnChangeUseDefault(SerializedPropertyChangeEvent e) { bool useDefault = e.changedProperty.boolValue; if (useDefault) { signalingSettingsPopupField.style.display = DisplayStyle.None; signalingSettingsField.style.display = DisplayStyle.None; openProjectSettingsButton.style.display = DisplayStyle.Flex; } else { signalingSettingsPopupField.style.display = DisplayStyle.Flex; signalingSettingsField.style.display = DisplayStyle.Flex; openProjectSettingsButton.style.display = DisplayStyle.None; var property = serializedObject.FindProperty("signalingSettingsObject"); if (!IsValidSignalingSettingsObject(property.objectReferenceValue as SignalingSettingsObject)) { CreateDefaultSignalingSettings(); } } } private void OnValueChangeSignalingSettingsObject(ChangeEvent e) { var asset = e.newValue; if (asset == null) { Debug.LogError("Setting None is not allowed for this parameter. Reverted."); return; } if (AssetDatabase.GetAssetPath(asset).IndexOf("Assets", StringComparison.Ordinal) != 0) { Debug.LogError("Setting an asset not placed under Assets folder is not allowed for this parameter. Reverted."); return; } var property = serializedObject.FindProperty("signalingSettingsObject"); property.objectReferenceValue = asset; serializedObject.ApplyModifiedProperties(); var handler = serializedObject.targetObject as SignalingManager; handler.SetSignalingSettings(asset.settings); // Send event to repaint SignalingSettingsDrawer. using SerializedPropertyChangeEvent changeEvent = SerializedPropertyChangeEvent.GetPooled(); changeEvent.changedProperty = property; changeEvent.target = signalingSettingsField.Children().First(); root.SendEvent(changeEvent); } private void OnValueChangeSignalingSettings(SerializedPropertyChangeEvent e) { // Update SignalingSettings in ScriptableObject. var handler = serializedObject.targetObject as SignalingManager; if (handler.signalingSettingsObject != null) handler.signalingSettingsObject.settings = handler.GetSignalingSettings(); } } }